IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Composants FMX Delphi Discussion :

Récupérer un tableau d'une API via REST Client et ClientDataSet [Android]


Sujet :

Composants FMX Delphi

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 99
    Points : 98
    Points
    98
    Par défaut Récupérer un tableau d'une API via REST Client et ClientDataSet
    Bonjour à tous,

    je développe sous delphi 10.2 tokyo une application mobile android. J'interroge une API (format json) via les compos RestClient, RestRequest, RestResponse et Restresponsedatasetadapter lié via un DataSource à un ClientDataSet pour lire le résultat dans un Tgrid lié via livebinding.

    Les paramètres retour de l'API sont les suivants :

    Nom : parametre_retour_salon.png
Affichages : 1308
Taille : 12,0 Ko

    initialement, j'ai créé dans le Restresponsedatasetadapter.FieldDefs les éléments suivants :
    - success ftboolean
    - error ftstring
    - salons ftarray size 7
    et dans ChildDefs de salons :
    - id ftinteger
    - nom ftstring
    - adresse ftstring
    - cp ftstring
    - ville ftstring
    - tel ftstring
    - facebook ftstring

    à l'appel de l'API, la connexion est ok et le retour est ok : j'ai vérifié le content de RestResponse et j'ai bien mon JSON complet. mais l'affectation des données dans le clientdataset ne fonctionne pas correctement. En bidouillant suite aux remarques du forum https://stackoverflow.com/questions/...cts-and-arrays, j'ai supprimé du childdefs les 7 éléments du tableau (de id jusqu'à facebook) pour les mettre au même niveau dans Restresponsedatasetadapter.FieldDefs que j'ai mis à jour pour réactualiser les fielddefs du clientdataset et j'ai rajouté dans Restresponsedatasetadapter.RootElement la valeur "salons".

    mais résultat, le fielddefs du clientdataset est différent : j'ai tous les champs au même niveau sauf le id qui reste dans le childdef du salons avec un name à "salons[0]"

    et si je jette un oeil au concepteur livebinding, mon clientdataset dupplique les elements du champ salons :

    Nom : concepteurlivebinding_salon.png
Affichages : 1127
Taille : 10,6 Ko

    au final, j'arrive à voir la liste des nom adresse cp ville tel facebook dans le grid et le listbox mais je n'ai pas le id ni le success et error, et j'ai des colonnes vides en trop (salons[0] jusqu'à[6]).

    je crois que je n'ai pas tout paramétré correctement

    un petit coup de main n'est pas de refus

    merci beaucoup.

    delaio.

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 021
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 021
    Points : 40 935
    Points
    40 935
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    quelle API ?

    " via un DataSource à un ClientDataSet "
    il y a peut être une autre manière de faire s'il s'agit de JSON ... à tester voir cette petite vidéo https://youtu.be/O8yM44efjQU (en faisant abstraction de la partie TMSComponent) et voir comment ça se passe ....
    mais avec livebindings, 2 niveaux il me semble que c'est un niveau de trop
    if faut certainement quelque chose d'intermédiaire
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 99
    Points : 98
    Points
    98
    Par défaut
    merci pour la réponse rapide !!!

    c'est une API propriétaire développée par un prestataire. j'ai regardé le tuto... quand j'appelle une autre API (du même prestataire) qui ne retourne pas de tableau et l'affectation dans le clientdataset fonctionne très bien...

    "mais avec livebindings, 2 niveaux il me semble que c'est un niveau de trop "
    effectivement c'est possible mais je ne maitrise pas suffisamment livebinding pour répondre à cette question. Est ce que 2 clientdataset serait la solution ? l'un pour le premier niveau et l'autre pour le 2ème niveau !?!!

    je vais tester... si tu as d'autres idées n'hésites pas

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 99
    Points : 98
    Points
    98
    Par défaut
    ah j'ai oublié de demander : c'est quoi root element et comment ça se paramètre !?!! je suppose que c'est ce qui permet de "ventiler" le tableau salons car dans la doc ils disent :

    Nom : parametre_root_element_salon.png
Affichages : 981
Taille : 10,0 Ko

    ça explique peut être pourquoi success et error ne s'affichent pas dans le clientdataset !?!! et comment ça marche si plusieurs tableaux dans le paramètre retour !?!!

    en tout cas, quand j'enlève l'affectation à cette propriété, ça plante direct :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    valeur incorrecte pour le champ 'salons'

  5. #5
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 021
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 021
    Points : 40 935
    Points
    40 935
    Billets dans le blog
    62
    Par défaut
    Bonsoir,

    peux-tu me fournir un petit jeu d'essai (fichier JSON) ? des idées avec livebindings j'en ai plein mais je tatonne encore beaucoup !
    peut être une liaison intermédiaire avec un TProtypeBinSource mais ...
    en tout cas rootelement me parait la bonne piste à suivre mais ce serait pas "response.salons" la valeur de la propriété ?
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 99
    Points : 98
    Points
    98
    Par défaut
    bonsoir,

    voici un petit jeu d'essai JSON :

    json_salons.txt

    Concernant rootelement, je n'ai toujours pas compris comment ça fonctionne mais ta proposition renvoie une erreur (j'ai peut être pas fait comme tu m'as dit aussi... )

    Quoi qu'il en soit, j'ai donc intégré 2 clientdataset pour gérer les 2 niveaux et ça donne ceci (copie d'écran du data module) :

    Nom : 2017-11-17_19h50_10.png
Affichages : 1025
Taille : 7,1 Ko

    salon1_restrepdata :
    - rootelement vide
    - fielddefs : 0-success + 1-error
    - mettre a jour l'ensemble des données : remplissage auto de salon1_cds
    - résultat de salon1_cds.fielddefs : 0-success + 1-error

    salon2_restrepdata :
    - rootelement : salons (d'autres syntaxes ne fonctionnent pas [réf "salon_restrep.salons" proposé]
    - fielddefs : 0-salons (array size 0) + 1-id + 2-nom + 3-adresse + ...
    - restrepdata.salons.childdefs : 0-id
    - mettre a jour l'ensemble des données : remplissage auto de salon2_cds
    - résultat de salon2_cds.fielddefs : 0-id + 1-nom + 2-adresse + ...

    je ne sais pas si c'est clair...

    je lie ensuite dans le concepteur livebindings grid.* avec salon2_cds.*

    ma méthode fonctionne mais ce n'est pas très propre :
    - quand clic droit sur le request et "Exécuter..." à la conception : la grid est propre mais à la compil, ça donne ceci :

    Nom : resultat_grid_salon2.png
Affichages : 1019
Taille : 8,3 Ko

    - j'ai 2 colonnes salons et salons[0] vides qui ne servent pas à grand chose mais je n'ai pas pu faire autrement car si je ne rajoute pas dans salon2_restrepdata.fielddefs['salons'].childdefs un élément 0-id alors le remplissage automatique du salon2_cds.fielddefs ne m'intégre pas à la liste 0-id qui forcément n'apparaitra pas à la compil dans ma grid !!!

    et même si mon bidouillage fonctionne, je ne pense pas pouvoir m'accommoder de cette solution... je vais bientôt avoir une nouvelle api à traiter avec cette fois ci 3 niveaux (un array dans un array).

    concernant ta proposition d'utiliser TProtypeBinSource, perso, je suis novice en la matière... il faudrait m'en dire plus...

    autre question : c'est bien array comme DataType qu'il faut que j'utilise ? parce qu'il y en a pleins d'autres (http://docwiki.embarcadero.com/Libra....DB.TFieldType) mais je ne suis pas arrivée à faire autrement.

    je ne suis quand même pas la seule personne à devoir traiter des tableaux imbriqués en JSON !?!!

  7. #7
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 021
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 021
    Points : 40 935
    Points
    40 935
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    merci pour le jeu d'essai,
    Super je vais pouvoir "m'amuser" ce matin !

    [Edit] fin de "l'amusement", en fait je n'ai pas pu passer sans serveur. du coup après des recherches sur comment faire je suis "tomber" sur ce lien encode-json-to-a-firedac-memory-table-without-rest-request qui devrait donner quelques pistes
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 99
    Points : 98
    Points
    98
    Par défaut
    bonjour,

    Tu es trop fort ! c'est exactement ce qu'il me fallait et le résultat est bien plus propre que mes 2 clientdataset !

    donc, pour ceux qui rencontrent le même pb que moi et pour traduire rapidement le lien de SergioMaster, voici ce que ça donne :

    De nombreux services REST ne respectent pas les bonnes pratiques. Au lieu de cela, ils peuvent renvoyer des données JSON imbriquées ou un objet conteneur autour du tableau de données. Ce type de données ne peut pas être géré par le composant TRESTDatasetAdapter.
    J'ai résolu ce problème en créant mon propre composant équivalent personnalisé à TRESTDatasetAdapter que j'ai nommé TJSONDatasetAdapter.
    - j'ai donc installé son composant dans Delphi.
    (ATTENTION : au préalable, j'ai appliqué son correctif concernant un bug de sensibilité à la casse et j'ai affecté un datatype à ftMemo pour ne pas tronquer les adresses supérieures à 255 caractères :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    //Change line 105 of jsonadapt.pas from:
    n := Lowercase(Trim(p.JsonString.ToString));
    to
    n := p.JsonString.ToString;
     
     
    // ligne 121 du jsonadapter.pas
    if (FieldDef.DataType=TFieldType.ftUnknown) then begin
      // FieldDef.DataType := TFieldType.ftString;
      FieldDef.DataType := TFieldType.ftMemo;
    - j'ai posé tous mes composants dans mon projet de test.

    Nom : solution.png
Affichages : 1152
Taille : 52,7 Ko

    paramétrage des compos :

    - RESTResponseDataSetAdapter1.dataset : clientdataset1
    - RESTResponseDataSetAdapter1.tfielddefs : success (ftboolean) + error (ftstring) + salons (ftmemo)
    - liaison des 2 stringgrid via le livebindings
    - j'ai fait l'affectation du jsondatasetadapter.JSON dans un bouton :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      RESTRequest1.Execute;
      JSONDatasetAdapter1.JSON.Text := ClientDataSet1.FieldByName('salons').AsWideString;
      JSONDatasetAdapter1.Dataset := FDMemTable1;
      FDMemTable1.Active := true;
    end;
    et ça marche !!! je n'ai plus qu'à tester sur 3 niveaux pour ma prochaine API à intégrer au projet...

    Mille mercis Sergio pour le coup de main !

    bon dev à tous.

    delaio.

  9. #9
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 021
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 021
    Points : 40 935
    Points
    40 935
    Billets dans le blog
    62
    Par défaut
    Bonjour,
    Citation Envoyé par delaio Voir le message
    Tu es trop fort ! c'est exactement ce qu'il me fallait et le résultat est bien plus propre que mes 2 clientdataset !
    Oui je sais c'est mes chevilles qui vont en prendre un coup !

    Citation Envoyé par delaio Voir le message
    Mille mercis Sergio pour le coup de main !
    En tout cas content que ce lien réponde à la question

    Non, plus sérieusement, je poursuis la discussion car en allant vérifier mes packages via Getit (ce qui m'arrive de temps en temps) il y a peut être aussi les composants REST DataAware Datasnap qui correspondrait aussi au besoin (le lien renvoi sur un forum brésilien donc n'explique pas vraiment l'objectif), inconvénient si l'on peut dire, l'installation de la JCL est nécessaire. S'il m'arrive de lire le portugais je n'en suis pas encore à l'écrire donc je n'ai pas fait de recherche plus avant sur le besoin de cette JCL pour savoir si c'était une obligation ou pas.
    Il peut aussi être intéressant de suivre ce webinaire

    Je laisse la main aux testeurs potentiels
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 99
    Points : 98
    Points
    98
    Par défaut
    Bonjour,

    désolée pour tes chevilles Sergio, et merci pour les news complémentaires...

    Ce compo me va bien jusqu'à ce que... j'importe ma petite démo de test dans mon vrai projet :

    - le compo n'était pas compilé multi plateforme
    (je bidouille un peu... je mets des requires en commentaire... c'est peut être pas très clean ce que j'ai fait mais ça passe pour android )
    - les accents eux, ne passent pas du tout par contre !
    (sous windows, ils disparaissent et sous android, ils sont mal interprétés : Foug?res à la place de Fougères par exemple).

    Bien entendu, j'ai vérifié mes affectations et si j'affiche dans un showmessage mon compojson.json.text tous les accents sont là !

    je pense que c'est au niveau du remplissage du fdmemtable dans le fichier jsonadapter.pas mais là, c'est la misère ! j'ai beau cherché, je ne trouve pas comment faire

    une idée ? je suis à 90% proche de la solution...

  11. #11
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 021
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 021
    Points : 40 935
    Points
    40 935
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    cela me paraît être un problème d'encodage, problème que les anglo-saxons ignorent. Je crains que tu rencontres également ce problème avec les nombres flottant et le point décimal.
    De là à dire s'il faut corriger le problème en amont (Le document que tu as envoyé semble être encodé ANSI et non UTF8) , au niveau des composants (FallBackCharsetEncoding de restClient , contentencoding de restreponse ? en bref tout ce qui concerne l'encodage des REST) ou dans l'unité je suis bien en peine de donner une réponse.

    AMHA à l'amont l'encodage devrait être en UTF8 pour une diffusion standard (internationalisation) c'est peut être le cas ?
    Citation Envoyé par Norme JSON
    JSON text SHALL be encoded in UTF-8, UTF-16, or UTF-32. The default
    encoding is UTF-8, and JSON texts that are encoded in UTF-8 are
    interoperable in the sense that they will be read successfully by the
    maximum number of implementations; there are many implementations
    that cannot successfully read texts in other encodings (such as
    UTF-16 and UTF-32).
    Bien entendu, j'ai vérifié mes affectations et si j'affiche dans un showmessage mon compojson.json.text tous les accents sont là !
    évidement ce contrôle laisse à penser que finalement cela pourrait venir de l'unité. Tu noteras que dans les commentaires du lien sur le source le point des accentuation a été abordé et qu'aucune réponse n'a été donné par Graig Chapman (du moins dans ce blog)

    [Edit] une piste dans le source peut être à la ligne 202, seule à faire appel à une conversion ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    unit jsonadapter;
     
    interface
    uses
      System.SysUtils,
      System.Classes,
      System.Json,
      Data.DB;
     
    type
      EDataTypeCoersion = class(Exception); //- Can't alter data-type for existing field definition.
      EDataTypeUnsupported = class(Exception); //- Can't support data-type from json data. (objects and arrays)
      EUnknownDataType = class(Exception); //- Unable to determine data type from json data.
     
    type
      TJSONDatasetAdapter = class(TComponent)
      private
        fJSON: TStrings;
        fDatasetRef: TDataset;
        procedure SetDatasetRef(const Value: TDataset);
        procedure setJSON(const Value: TStrings);
        procedure SetFieldDefs(a: TJSONArray);
        procedure InsertData(a: TJSONArray);
      public
        constructor Create( aOwner: TComponent ); override;
        destructor Destroy; override;
      public
        procedure UpdateDataset;
      published
        property JSON: TStrings read fJSON write setJSON;
        property Dataset: TDataset read fDatasetRef write SetDatasetRef;
      end;
     
    procedure Register;
     
    implementation
     
    procedure Register;
    begin
      RegisterComponents('REST Client', [TJSONDatasetAdapter]);
    end;
     
    { TJSONDatasetAdapter }
     
    constructor TJSONDatasetAdapter.Create(aOwner: TComponent);
    begin
      inherited Create( aOwner );
      fJSON := TStringList.Create;
      fJSON.Text := '[]';
      fDatasetRef := nil;
    end;
     
    destructor TJSONDatasetAdapter.Destroy;
    begin
      fJSON.DisposeOf;
      fDatasetRef := nil;
      inherited Destroy;
    end;
     
    procedure TJSONDatasetAdapter.SetDatasetRef(const Value: TDataset);
    begin
      fDatasetRef := Value;
      UpdateDataset;
    end;
     
    procedure TJSONDatasetAdapter.setJSON(const Value: TStrings);
    begin
      if not assigned(value) then begin
        fJSON.Clear;
        exit;
      end;
      fJSON.Assign(Value);
      UpdateDataset;
    end;
     
    procedure TJSONDatasetAdapter.SetFieldDefs( a: TJSONArray );
    var
      o: TJSONObject;
      e: TJSONPairEnumerator;
      p: TJSONPair;
      v: TJSONValue;
      n: string;
      idx: uint32;
      FieldDef: TFieldDef;
    begin
      if a.Count<1 then begin
        exit;
      end;
      //- Loop through data to determine data-types.
      for idx := 0 to pred(a.Count) do begin
        v := a.Items[idx];
        if not (v is TJSONObject) then begin
          exit;
        end;
        o := v as TJSONObject;
        try
          e := o.GetEnumerator;
          if not e.MoveNext then begin
            exit;
          end;
          repeat
            p := e.GetCurrent;
            if not assigned(p) then continue;
            //- Get the name of the field, and ensure we have a field def.
            n := Lowercase(Trim(p.JsonString.ToString));
            n := StringReplace(n,'"','',[rfReplaceAll]);
            FieldDef := nil;
            if fDatasetRef.FieldDefs.IndexOf(n)>=0 then begin
              FieldDef := fDatasetRef.FieldDefs.Find(n);
            end;
            if not assigned(FieldDef) then begin
              FieldDef := fDatasetRef.FieldDefs.AddFieldDef;
              FieldDef.Name := n;
            end;
            //- Determine the type of field.
            v := p.JsonValue;
            if v is TJSONString then begin
              if (FieldDef.DataType=TFieldType.ftUnknown) then begin
                FieldDef.DataType := TFieldType.ftString;
              end;
            end else if v is TJSONNumber then begin
              if (FieldDef.DataType=TFieldType.ftUnknown) then begin
                FieldDef.DataType := TFieldType.ftFloat;
              end else if (FieldDef.DataType <> TFieldType.ftFloat) then begin
                raise EDataTypeCoersion.Create('');
              end;
            end else if v is TJSONBool then begin
              if (FieldDef.DataType=TFieldType.ftUnknown) then begin
                FieldDef.DataType := TFieldType.ftBoolean;
              end else if (FieldDef.DataType<>ftBoolean) then begin
                raise EDataTypeCoersion.Create('');
              end;
            end else if v is TJSONNull then begin
              //- Do nothing, another record may indicate data type.
            end else if v is TJSONObject then begin
              raise EDataTypeUnsupported.Create('');
            end else if v is TJSONArray then begin
              raise EDataTypeUnsupported.Create('');
            end;
          until not e.MoveNext;
        finally
          o := nil;
        end;
      end;
     //- Ensure that all field defs have known data types.
     if fDatasetRef.FieldDefs.Count<1 then begin
       exit;
     end;
     for idx := 0 to pred(fDatasetRef.FieldDefs.Count) do begin
       if fDatasetRef.FieldDefs[idx].DataType=TFieldType.ftUnknown then begin
         raise EUnknownDataType.Create('field: '+fDatasetRef.FieldDefs[idx].Name);
       end;
     end;
    end;
     
    procedure TJSONDatasetAdapter.InsertData( a: TJSONArray );
    var
      idx: uint32;
      idy: uint32;
      v: TJSONValue;
      o: TJSONObject;
      FieldName: string;
    begin
      if fDatasetRef.FieldDefs.Count<1 then begin
        exit;
      end;
      if a.Count<1 then begin
        exit;
      end;
      for idx := 0 to pred(a.Count) do begin
        v := a.Items[idx];
        if not (v is TJSONObject) then continue; //[ Exception here? ]
        o := v as TJSONObject;
        fDatasetRef.Insert;
        for idy := 0 to pred(fDatasetRef.FieldDefs.Count) do begin
          FieldName := fDatasetRef.FieldDefs[idy].Name;
          v := o.GetValue(FieldName);
          if assigned(v) then begin
            if v is TJSONString then begin
              fDatasetRef.FieldByName(FieldName).AsString := TJSONString(v).Value;
            end else begin
              fDatasetRef.FieldByName(FieldName).AsString := v.ToJSON;
            end;
          end;
        end;
        fDatasetRef.Post;
      end;
    end;
     
    procedure TJSONDatasetAdapter.UpdateDataset;
    var
      o: TJSONObject;
      a: TJSONArray;
      v: TJSONValue;
    begin
      if not assigned(fDatasetRef) then begin
        exit;
      end;
      fDatasetRef.Active := False;
      fDatasetRef.FieldDefs.Clear;
      try
     //   o := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes('{ "data": '+fJSON.Text+'}'),0) as TJSONObject;
        o := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes('{ "data": '+fJSON.Text+'}'),0) as TJSONObject;  // à tester
      except
        on E: Exception do begin
         exit;
        end;
      end;
      if not assigned(o) then begin
        exit;
      end;
      v := o.GetValue('data');
      if not assigned(v) then begin
        exit;
      end;
      if not (v is TJSONArray) then begin
        exit;
      end;
      a := v as TJSONArray;
      if a.Count=0 then begin
        exit;
      end;
      SetFieldDefs(a);
      fDatasetRef.Active := True;
      InsertData(a);
    end;
     
    end.
    Ou encore, option que tu n'as pas envisagée, une intervention Firedac (là il y a trop d'options pour que j'indique où ce matin )

    Du coup je m’aperçois que j'ai fait une "réponse de normand" mais si les premiers points soulevés sont vérifiés alors cela sautera aux yeux

    pour info j'ai mis du cyrillique dans une des adresses du fichier JSON que tu as joint ("17 rue \u041f\u043e\u0438\u0441\u043a \u043f\u043e \u0444\u0430\u043c\u0438\u043b\u0438\u0438, \u0438\u043c\u0435\u043d\u0438 (\u043e\u0442\u0447\u0435\u0441\u0442\u0432\u0443" au leiu de "17 rue Barnabe") et utilisé le petit programme JSONViewer du webinaire déjà indiqué. Sous cette forme cela fonctionne (P.S. non, je ne lis pas le Cyrillique c'est juste pour frimer ).
    Par contre j'ai tenté de modifié Barnabe en Barnabé avec le bloc note avec Notepad++ en sauvegardant en UTF8 (à moins que j'ai mal manipulé Notepad++) par contre mettre \u00e9 à la place de é
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  12. #12
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 99
    Points : 98
    Points
    98
    Par défaut
    Bonjour,

    alors en plus d'être matinal le week end, désolée pour tes chevilles mais je confirme que je pouvais te faire confiance pour trouver la solution !!! c'est effectivement la ligne 202 avec l'encodage ASCII à UTF8 (j'ai d'ailleurs un peu honte d'être passée à côté )

    donc voici le code corrigé avec les 3 corrections intégrées pour ceux intéressés :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    unit jsonadapter;
     
    interface
    uses
      System.SysUtils,
      System.Classes,
      System.Json,
      Data.DB;
     
    type
      EDataTypeCoersion = class(Exception); //- Can't alter data-type for existing field definition.
      EDataTypeUnsupported = class(Exception); //- Can't support data-type from json data. (objects and arrays)
      EUnknownDataType = class(Exception); //- Unable to determine data type from json data.
     
    type
      TJSONDatasetAdapter = class(TComponent)
      private
        fJSON: TStrings;
        fDatasetRef: TDataset;
        procedure SetDatasetRef(const Value: TDataset);
        procedure setJSON(const Value: TStrings);
        procedure SetFieldDefs(a: TJSONArray);
        procedure InsertData(a: TJSONArray);
      public
        constructor Create( aOwner: TComponent ); override;
        destructor Destroy; override;
      public
        procedure UpdateDataset;
      published
        property JSON: TStrings read fJSON write setJSON;
        property Dataset: TDataset read fDatasetRef write SetDatasetRef;
      end;
     
    procedure Register;
     
    implementation
     
    procedure Register;
    begin
      RegisterComponents('REST Client', [TJSONDatasetAdapter]);
    end;
     
    { TJSONDatasetAdapter }
     
    constructor TJSONDatasetAdapter.Create(aOwner: TComponent);
    begin
      inherited Create( aOwner );
      fJSON := TStringList.Create;
      fJSON.Text := '[]';
      fDatasetRef := nil;
    end;
     
    destructor TJSONDatasetAdapter.Destroy;
    begin
      fJSON.DisposeOf;
      fDatasetRef := nil;
      inherited Destroy;
    end;
     
    procedure TJSONDatasetAdapter.SetDatasetRef(const Value: TDataset);
    begin
      fDatasetRef := Value;
      UpdateDataset;
    end;
     
    procedure TJSONDatasetAdapter.setJSON(const Value: TStrings);
    begin
      if not assigned(value) then begin
        fJSON.Clear;
        exit;
      end;
      fJSON.Assign(Value);
      UpdateDataset;
    end;
     
    procedure TJSONDatasetAdapter.SetFieldDefs( a: TJSONArray );
    var
      o: TJSONObject;
      e: TJSONPairEnumerator;
      p: TJSONPair;
      v: TJSONValue;
      n: string;
      idx: uint32;
      FieldDef: TFieldDef;
    begin
      if a.Count<1 then begin
        exit;
      end;
      //- Loop through data to determine data-types.
      for idx := 0 to pred(a.Count) do begin
        v := a.Items[idx];
        if not (v is TJSONObject) then begin
          exit;
        end;
        o := v as TJSONObject;
        try
          e := o.GetEnumerator;
          if not e.MoveNext then begin
            exit;
          end;
          repeat
            p := e.GetCurrent;
            if not assigned(p) then continue;
            //- Get the name of the field, and ensure we have a field def.
    // il y a un bug de sensibilité à la casse
    //        n := Lowercase(Trim(p.JsonString.ToString));
            n := p.JsonString.ToString;
            n := StringReplace(n,'"','',[rfReplaceAll]);
            FieldDef := nil;
            if fDatasetRef.FieldDefs.IndexOf(n)>=0 then begin
              FieldDef := fDatasetRef.FieldDefs.Find(n);
            end;
            if not assigned(FieldDef) then begin
              FieldDef := fDatasetRef.FieldDefs.AddFieldDef;
              FieldDef.Name := n;
            end;
            //- Determine the type of field.
            v := p.JsonValue;
            if v is TJSONString then begin
    // bascule le datatype string en memo pour eviter de tronquer les adresses superieures a 255 caracteres
              if (FieldDef.DataType=TFieldType.ftUnknown) then begin
    //            FieldDef.DataType := TFieldType.ftString;
                FieldDef.DataType := TFieldType.ftMemo;
              end;
            end else if v is TJSONNumber then begin
              if (FieldDef.DataType=TFieldType.ftUnknown) then begin
                FieldDef.DataType := TFieldType.ftFloat;
              end else if (FieldDef.DataType <> TFieldType.ftFloat) then begin
                raise EDataTypeCoersion.Create('');
              end;
            end else if v is TJSONBool then begin
              if (FieldDef.DataType=TFieldType.ftUnknown) then begin
                FieldDef.DataType := TFieldType.ftBoolean;
              end else if (FieldDef.DataType<>ftBoolean) then begin
                raise EDataTypeCoersion.Create('');
              end;
            end else if v is TJSONNull then begin
              //- Do nothing, another record may indicate data type.
            end else if v is TJSONObject then begin
              raise EDataTypeUnsupported.Create('');
            end else if v is TJSONArray then begin
              raise EDataTypeUnsupported.Create('');
            end;
          until not e.MoveNext;
        finally
          o := nil;
        end;
      end;
     //- Ensure that all field defs have known data types.
     if fDatasetRef.FieldDefs.Count<1 then begin
       exit;
     end;
     for idx := 0 to pred(fDatasetRef.FieldDefs.Count) do begin
       if fDatasetRef.FieldDefs[idx].DataType=TFieldType.ftUnknown then begin
         raise EUnknownDataType.Create('field: '+fDatasetRef.FieldDefs[idx].Name);
       end;
     end;
    end;
     
    procedure TJSONDatasetAdapter.InsertData( a: TJSONArray );
    var
      idx: uint32;
      idy: uint32;
      v: TJSONValue;
      o: TJSONObject;
      FieldName: string;
    begin
      if fDatasetRef.FieldDefs.Count<1 then begin
        exit;
      end;
      if a.Count<1 then begin
        exit;
      end;
      for idx := 0 to pred(a.Count) do begin
        v := a.Items[idx];
        if not (v is TJSONObject) then continue; //[ Exception here? ]
        o := v as TJSONObject;
        fDatasetRef.Insert;
        for idy := 0 to pred(fDatasetRef.FieldDefs.Count) do begin
          FieldName := fDatasetRef.FieldDefs[idy].Name;
          v := o.GetValue(FieldName);
          if assigned(v) then begin
            if v is TJSONString then begin
              fDatasetRef.FieldByName(FieldName).AsString := TJSONString(v).Value;
            end else begin
              fDatasetRef.FieldByName(FieldName).AsString := v.ToJSON;
            end;
          end;
        end;
        fDatasetRef.Post;
      end;
    end;
     
    procedure TJSONDatasetAdapter.UpdateDataset;
    var
      o: TJSONObject;
      a: TJSONArray;
      v: TJSONValue;
    begin
      if not assigned(fDatasetRef) then begin
        exit;
      end;
      fDatasetRef.Active := False;
      fDatasetRef.FieldDefs.Clear;
      try
    //    o := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes('{ "data": '+fJSON.Text+'}'),0) as TJSONObject;
    // afin de gerer les accents
        o := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes('{ "data": '+fJSON.Text+'}'),0) as TJSONObject;
      except
        on E: Exception do begin
         exit;
        end;
      end;
      if not assigned(o) then begin
        exit;
      end;
      v := o.GetValue('data');
      if not assigned(v) then begin
        exit;
      end;
      if not (v is TJSONArray) then begin
        exit;
      end;
      a := v as TJSONArray;
      if a.Count=0 then begin
        exit;
      end;
      SetFieldDefs(a);
      fDatasetRef.Active := True;
      InsertData(a);
    end;
     
    end.
    Tu noteras que dans les commentaires du lien sur le source le point des accentuation a été abordé et qu'aucune réponse n'a été donné par Graig Chapman (du moins dans ce blog)
    c'est moi qui ait laissé le commentaire... il vient juste de répondre à mon post : je lui ai donné ta solution.

    un grand merci Sergio !

    à bientôt

    delaio.

  13. #13
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 021
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 021
    Points : 40 935
    Points
    40 935
    Billets dans le blog
    62
    Par défaut
    Re,

    il te reste, je pense, à régler le problème du point décimal si toutefois tu as des données de ce type
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  14. #14
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 99
    Points : 98
    Points
    98
    Par défaut
    oui, effectivement j'ai des float à gérer. je n'ai pas encore développé cette partie. si pb/solution, je complèterai cette discussion...

  15. #15
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 021
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 021
    Points : 40 935
    Points
    40 935
    Billets dans le blog
    62
    Par défaut
    je te rassure, rien qu'un TFormatSettings ne puisse régler
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  16. #16
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 021
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 021
    Points : 40 935
    Points
    40 935
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    une autre piste de réflexion. Je viens de visionner une autre conférence de CodeRage XII : Creating JSON Wrapper Classes. Elle devrait fortement t’intéresser ! bien qu'en anglais parlé par un russe avec une qualité de son parfois médiocre il présente l'utilisation rapide de l'outil REST Debugger (je me demandais à quoi il pouvait bien servir celui là !) mais aussi un outil hyper pratique téléchargeable sur GitHub qui permet de créer toutes tes classes à partir du fichier JSON (dans une unité à part SVP) et avec des méthodes pour accéder à tout ça ( génial !) AMHA un "must have" pour les gens qui travaillent avec JSON
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  17. #17
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 99
    Points : 98
    Points
    98
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    Bonjour,

    une autre piste de réflexion. Je viens de visionner une autre conférence de CodeRage XII : Creating JSON Wrapper Classes. Elle devrait fortement t’intéresser ! bien qu'en anglais parlé par un russe avec une qualité de son parfois médiocre il présente l'utilisation rapide de l'outil REST Debugger (je me demandais à quoi il pouvait bien servir celui là !) mais aussi un outil hyper pratique téléchargeable sur GitHub qui permet de créer toutes tes classes à partir du fichier JSON (dans une unité à part SVP) et avec des méthodes pour accéder à tout ça ( génial !) AMHA un "must have" pour les gens qui travaillent avec JSON
    Génial un grand merci pour tes recherches... mes dev pour cette appli sont déjà terminés sur la partie traitement JSON mais j'ai hâte de pouvoir tester ta découverte dans un prochain projet...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Récupérer un tableau d'une page
    Par axanta dans le forum Langage
    Réponses: 5
    Dernier message: 08/12/2008, 11h32
  2. Réponses: 7
    Dernier message: 04/02/2008, 19h52
  3. Comment récupérer la taille d'une image via un lien ?
    Par MaTHieU_ dans le forum Web & réseau
    Réponses: 5
    Dernier message: 17/09/2007, 15h37
  4. Réponses: 6
    Dernier message: 12/09/2007, 16h58
  5. [Tableaux] récupérer un tableau sur une autre page
    Par samsso2005 dans le forum Langage
    Réponses: 3
    Dernier message: 27/01/2006, 23h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo