Utiliser JSON sous Free Pascal avec la librairie FCL-JSON

Date de publication : 23/05/2010

Par Darryl Kpizingui (Mon site perso)
 

JSON est un format d'échange de données tout comme le XML. Il présente l'avantage d'être très léger comparé à ce dernier, ce qui fait qu'il est surtout présent dans les applications web. Dans cet article, vous trouverez les bases nécessaires pour comprendre JSON et aussi pour apprendre à utiliser la librairie FCL-JSON pour manipuler ce format d'échange de données sous Free Pascal.
Commentez

       Version hors-ligne (Miroir)
Viadeo Twitter Google Bookmarks ! Facebook Digg del.icio.us MySpace Yahoo MyWeb Blinklist Netvouz Reddit Simpy StumbleUpon Bookmarks Windows Live Favorites      



I. Introduction
II. Présentation de JSON
III. Utilisation de JSON avec la librairie FCL-JSON
III-A. Constituants de la librairie FCL-JSON
III-B. Les types de données JSON
III-B-1. La classe TJSONData
III-B-2. La classe TJSONNumber
III-B-3. Les classes TJSONNull, TJSONBoolean et TJSONString
III-B-4. La classe TJSONArray
III-B-5. La classe TJSONObject
IV. Parser des données JSON
IV-A. Exemple de traitement d'un fichier contenant des données JSON
V. Quelques exemples
V-A. Parcours des données JSON
V-B. Création d'un objet JSON
VI. Conclusion et remerciements
VI-A. Conclusion
VI-B. Remerciements


I. Introduction

Cet article présente le format d'échange de données JSON et montre comment utiliser la librairie FCL-JSON pour parser et manipuler ce format sous Free Pascal. La librairie FCL-JSON fait en effet partie des librairies standard distribuées avec Free Pascal; vous n'aurez donc pas besoin d'une librairie externe pour compiler les codes fournis dans cet article.

Les codes et les exemples de cet article sont réalisés et testés avec la version 0.9.28.2 de Lazarus utilisant Free Pascal 2.2.4. Une connaissance du Pascal Objet est nécessaire pour la compréhension de cet article.

Consulter le site officiel de JSON pour plus d'information sur ce format : fr le site officiel de JSON


II. Présentation de JSON

JSON (JavaScript Object Notation - Notation Objet issue de JavaScript) est un format léger d'échange de données. Tout comme XML, il est facile à manipuler mais requièrt moins de ressources pour l'écriture ou l'analyse des donnés. JSON est un format indépendant de tout langage de programmation et utilise des concepts qu'on retrouve dans la plupart de ces langages.

JSON est un format complètement textuel et se base sur deux structures principales :

  • Une collection : Une collection est composée de couples nom/valeur que nous pouvons identifier avec les champs d'un type record ou d'un Objet.
    Si nous considérons la variable suivante :
Var collection : record
  Nom : String ;
  Age : Integer ; 
End;
//puis ... 
Collection.nom:='darrylsite';
Collection.age := 10;
						
La représentation en collection pourrait être :
{"nom" : "darrylsite",  "age" : 10 }
  • Une liste de valeurs ordonnées : En pascal, cette liste pourrait être un tableau (Array), ou une liste chainée.
En JSON, ces structures prennent la forme suivante :

Un objet JSON est un ensemble non ordonné et constitué de couples nom/valeur contenus entre une paire d'accolades {} et séparés par des virgules. La nom est une chaîne de caractères et doit être suivie des deux points (:). La valeur est soit une chaîne de caractère (String), un nombre (Number), un objet (object), un tableau (Array), un booléen (true, false) ou null.

Une chaîne de caractères est une suite de caractères délimitée par des guillemets (" "). Un tableau est un ensemble ordonné de valeurs contenues dans une paire de crochets ([]).

Un exemple d'objet JSON :
{
   "langage " : "pascal",
   "annee_creation" :1969,
   "compilateurs" :[
                                  {"nom" : "MIDlet Pascal", "plateforme" : "Windows"},
                                  {"nom" : "Lazarus", "plateforme" : "Windows, linux, macOs"}
                   ]
}
Cet objet JSON peut être codé en Pascal de la manière suivante :
Type
         TCompilateur = record
                                       Nom : String ;
                                       plateforme : String
                                     End ;

         TLangage= record
                               nom  : String;    
                               annee_creation :  integer;
                               compilateurs : Array of compilateurs   ;
                             end;

var pascal : TLangage;
Pour plus de d'informations sur JSON vous pouvez consulter le lien suivant : Le site officiel de JSON


III. Utilisation de JSON avec la librairie FCL-JSON


III-A. Constituants de la librairie FCL-JSON

La librairie FCL-JSON que nous allons utiliser est celle distribuée avec la version 2.2.4 de Free Pascal et qu'on retrouve dans la version 0.9.28.2 de Lazarus.
Les principales unités de cette librairie sont les suivantes :

  • l'unité fpjson contient la définition des classes représentant les différents types supportés par JSON,
  • l'unité jsonparser, dans laquelle est définie un parseur permettant de parser des flux de données,
  • l'unité jsonconf contient la classe permettant de créer et d'utiliser des fichiers de configuration au format JSON.
Dans la suite, nous allons uniquement travailler avec les unités fpjson et jsonparser.


III-B. Les types de données JSON

Les différents types supportés par JSON sont définis dans l'unité fpjson comme élément du type énuméré TJSONtype.
TJSONtype = (jtUnknown, jtNumber, jtString, jtBoolean, jtNull, jtArray, jtObject);
Pour chaque type de données JSON, l'unité définit une classe qui modélise ce type de données. La hiérarchie des classes disponibles est la suivante :


III-B-1. La classe TJSONData

La classe TJSONData est une classe abstraite et mère de toutes les autres classes représentant les types de données JSON. Les principales méthodes et propriétés définies dans cette classe sont résumées dans le tableau suivant:

Méthodes ou propriétés rôle
Class function JSONType: TJSONType Donne le type JSON de l'objet
Procedure Clear Efface toutes les données de l'objet
property Value: variant ; Donne la valeur de l'objet dépendant de la valeur de la fonction JSONType
Property AsString : TJSONStringType ; Convertit un type donné en TJSONStringType
property Count : Integer ; Donne le nombre d'éléments disponibles pour les types TJSONrray et TJSONObject
Property AsFloat : TJSONFloat ; Convertit une un type donné en TJSONFloat
Property AsInteger : Integer ; Convertit une un type donné en Integer
Property AsBoolean : Boolean ; Convertit une un type donné en Boolean
Property IsNull : Boolean ; Indique si l'objet est NULL
Property AsJSON : String ; Donne la représentation JSON de l'objet

Pour les conversions entre les types, l'exception EJSON est lancée quand celle-ci échoue.


III-B-2. La classe TJSONNumber

La classe TJSONNumber est utilisée pour représenter les données numériques JSON. Pour des contrôles plus accrus, sont définies les classes TJSONIntegerNumber et TJSONFloatNumber dérivant de TJSONNUmber qui est une classe abstraite.

La nouvelle méthode partagée par ces deux classes est :
class function NumberType : TJSONNumberType
Indiquant ainsi le type du nombre où TJSONNumberType est défini comme suit :
TJSONNumberType = (ntFloat,ntInteger)
Les constructeurs de ces classes sont :

  • Pour la classe TJSONIntegerNumber
Constructor Create(AValue : Integer);
  • Pour la classe TJSONFloatNumber
// TJSONFloat = Extended;
Constructor Create(AValue : TJSONFloat);  
		

III-B-3. Les classes TJSONNull, TJSONBoolean et TJSONString

Les classes TJSONNull, TJSONBoolean et TJSONString ne définissent pas de nouvelles méthodes par rapport à la classe TJSONData.

Leurs constructeurs sont définis comme suit :

  • Pour la classe TJSONNull
Constructor Create;
  • Pour la classe TJSONBoolean
Constructor Create(AValue : Boolean); 
		
  • Pour la classe TJSONString
// TJSONStringType = AnsiString;
Constructor Create(AValue : TJSONStringType);
		

III-B-4. La classe TJSONArray

La classe TJSONArray représente les tableaux utilisés en JSON. Les méthodes de cette classe permettent principalement de manipuler les éléments du tableau (ajouter, supprimer des éléments) et d'accéder à ces différents éléments.

Les constructeurs de cette classe sont :
Constructor Create;
    Constructor Create(const Elements : Array of Const);
La série des méthodes add(...) permettent d'ajouter des éléments dans le tableau et l'index de l'élément est retourné par celles-ci.
    function Add(Item : TJSONData): Integer;
    function Add(I : Integer): Integer;
    function Add(S : String): Integer;
    function Add: Integer;
    function Add(F : TJSONFloat): Integer;
    function Add(B : Boolean): Integer;
    function Add(AnArray : TJSONArray): Integer;
    function Add(AnObject: TJSONObject): Integer;
		
Il existe aussi les méthodes delete et remove qui permettent d'enlever un élément dans le tableau en connaissant soit l'index de ce dernier, soit l'objet à enlever. La méthode clear enlève tous les éléments du tableau.
Procedure Delete(Index : Integer);
    Procedure Remove(Item : TJSONData);
    Procedure Clear;
		
Pour explorer et utiliser les éléments du tableau, nous disposons des propriétés suivantes disponibles en lecture/écriture, permettant d'accéder à un élément dudit tableau en fonction de son type.
    Property Nulls[Index : Integer] : Boolean ;
    Property Integers[Index : Integer] : Integer ;
    Property Strings[Index : Integer] : TJSONStringType;
    Property Floats[Index : Integer] : TJSONFloat;
    Property Booleans[Index : Integer] : Boolean;
    Property Arrays[Index : Integer] : TJSONArray;
    Property Objects[Index : Integer] : TJSONObject;
        
Il nous aît bien sûr possible de connaitre le type d'un élément ou de rechercher si un objet donné se trouve dans le tableau avec les méthodes suivantes :
Property Types[Index : Integer] : TJSONType;
function IndexOf(obj: TJSONData): Integer;
         
La méthode IndexOf retourne -1 si aucun élément n'a été trouvé. L'indice du premier élément du tableau est 0.


III-B-5. La classe TJSONObject

La dernière classe TJSONObject contient les méthodes et attributs permettant d'utiliser les objets JSON. Vous noterez sans doute une ressemblance avec la classe TJSONArray. En effet, on peut voir les objets JSON comme des tableaux associatifs : on utilise des noms pour identifier les éléments au lieu d'indices numériques.

Les constructeurs de cette classe sont :
constructor Create;
    Constructor Create(const Elements : Array of Const); 
		
Les méthodes permettant la manipulation des données sont :
function Add(const AName: TJSONStringType; AValue: TJSONData): Integer;
    function Add(const AName: TJSONStringType; AValue: Boolean): Integer; 
    function Add(const AName: TJSONStringType; AValue: TJSONFloat): Integer;
    function Add(const AName: TJSONStringType; AValue: TJSONStringType): Integer;
    function Add(const AName: TJSONStringType; Avalue: Integer): Integer; 
    function Add(const AName: TJSONStringType): Integer;
    function Add(const AName: TJSONStringType; AValue : TJSONArray): Integer; 
    procedure Delete(Index : Integer);
    procedure Remove(Item : TJSONData);
    Procedure Clear;  override;
De même que pour les tableaux, la classe dispose des méthodes d'accès suivantes :
Property Types[AName : String] : TJSONType;
    Property Nulls[AName : String] : Boolean;
    Property Floats[AName : String] : TJSONFloat;
    Property Integers[AName : String] : Integer;
    Property Strings[AName : String] : TJSONStringType;
    Property Booleans[AName : String] : Boolean;
    Property Arrays[AName : String] : TJSONArray;
    Property Objects[AName : String] : TJSONObject;   
En plus de ces méthodes, la classe contient les méthodes regroupées dans le tableau suivant :

Méthodes ou propriétés Rôle
function IndexOf(Item: TJSONData): Integer; Donne l'indice d'un élément dans le tableau associatif
Function IndexOfName(const AName: TJSONStringType): Integer; Donne l'indice correspondant à une clé donnée
property Names[Index : Integer] : TJSONStringType Donne la clé correspondant à un indice donné
property Elements[AName: string] : TJSONData Donne un élément correspondant à une clé donnée

Il convient de s'attarder un peu sur le constructeur de cette classe prenant en paramètre un tableau variable. Examinons le code suivant :
Var monObjet  : TJSONObject;
Begin
  monObjet := TJSONObjet.create(['game', 'Killer Instinct', 'niveau' , 5, 'nitendo 64', true ]);
End;
Le nombre d'éléments du tableau est toujours en nombre pair représentant ainsi, le couple nom/valeur de la collection. L'objet précédemment crée correspond dans la notation JSON à
{
     "game" : "Killer Instinct",
      "Niveau" : 5,
      "Nitendo 64" : true
   }

IV. Parser des données JSON

Pour parser des flux de données, nous disposons de la classe TJSONParser définie dans l'unité jsonparser.

Pour utiliser des données JSON disponibles dans un flux, nous commencerons toujours par créer une instance du parseur pour ce flux. Selon que le flux est un fichier ou une chaîne de caractères, nous pouvons utiliser l'une des formes suivantes du constructeur Create :
    Constructor Create(Source : TStream); 
    Constructor Create(Source : TJSONStringType);  //TJSONStringType=AnsiString
 
Une fois l'objet créé, la méthode Parse permet d'avoir les données contenues dans le flux.
function Parse: TJSONData;

IV-A. Exemple de traitement d'un fichier contenant des données JSON

Considérons que nous ayons le fichier json.dat contenant les données suivantes :
json.dat
{
   "langage " : "pascal",
   "annee_creation" :1969,
   "compilateurs" :[
                                  {"nom" : "MIDlet Pascal", "plateforme" : "Windows"},
                                  {"nom" : "Lazarus", "plateforme" : "Windows, linux, macOs"}
                               ]
}
Nous pouvons parser le fichier avec le code suivant :
Parser un document json
program parsedemo;
{$mode objfpc}{$H+}
uses
  Classes, SysUtils, fpjson,jsonparser;

Procedure DoParse(Parseur : TJSONParser);
Var
  js : TJSONData;
begin
  Try
    js:=parseur.Parse;
    Try
      If Assigned(js) then
        begin
         Writeln(js.AsJSON)
        end
      else
        Writeln('Pas de données disponibles');
    Finally
      FreeAndNil(js);
    end;
  except
    On E : Exception do
      Writeln('Une erreur est survenue lors du traitement du fichier : ',E.Message);
  end;
end;

Procedure ParseFile (FileName : String);
Var
  flux : TFileStream;
  Parseur : TJSONParser;
begin
  flux:=TFileStream.Create(FileName, fmopenRead);
  try
    parseur:=TJSONParser.Create(flux);
    try
      DoParse(parseur);
    finally
      FreeAndNil(parseur);
    end;
  finally
    flux.Destroy;
  end;
end;

begin
  If FileExists('json.dat') then
    ParseFile('json.dat')
  else
    writeln('Le fichier est introuvable');
  readln;
end.
La procédure ParseFile crée un parseur pour le fichier json.dat, et appelle la procédure doParse qui parse le fichier et affiche les données JSON contenues dans celui-ci.


V. Quelques exemples


V-A. Parcours des données JSON

Le code qui suit permet de parser et afficher les données JSON contenues dans le fichier json.dat suivant :
json.dat
{
   "langage " : "pascal",
   "annee_creation" :1969,
   "compilateurs" :[
                                  {"nom" : "MIDlet Pascal", "plateforme" : "Windows"},
                                  {"nom" : "Lazarus", "plateforme" : "Windows, linux, macOs"}
                               ]
}
Le traitement de quelques exceptions n'a pas été fait afin d'alléger le code.
Parcours des données JSON
program parsedemo;
{$mode objfpc}{$H+}
uses
         Classes, SysUtils, fpjson,jsonparser;

procedure displayData(data : TJSONData);
 var lang, comp : TJSONObject;
     tab : TJSONArray;
     i : byte;
begin
  lang :=TJSONObject(data);
  writeln('Les caracteristique du langage : '+lang.Strings['langage']);
  writeln('Date de creation : ',lang.Integers['annee_creation']);
  writeln('------------- Les compilateurs disponibles ---------------- ');
  tab:=lang.Arrays['compilateurs'];
  for i:=0 to tab.Count-1 do
  begin
   comp:= tab.Objects[i];
   write('Nom : '+comp.Strings['nom']);
   write(' / ');
   writeln('Plateforme : '+comp.Strings['plateforme']);
  end;
  writeln('------------------------------------------ ---------------- ');

end;

Procedure DoParse(Parseur : TJSONParser);
Var
  js : TJSONData;
begin
  js:=parseur.Parse;
  displayData(js);
end;

Procedure ParseFile (FileName : String);
Var
  flux : TFileStream;
  Parseur : TJSONParser;
begin
  flux:=TFileStream.Create(FileName, fmopenRead);
  try
    parseur:=TJSONParser.Create(flux);
    try
      DoParse(parseur);
    finally
      FreeAndNil(parseur);
    end;
  finally
    flux.Destroy;
  end;
end;

begin
  ParseFile('json.dat')
  readln;
end.
Ce qui nous donne en sortie :
aperçu de la console
Les caracteristique du langage : pascal
Date de creation : 1969
------------- Les compilateurs disponibles ----------------
Nom : MIDlet Pascal / Plateforme : Windows
Nom : Lazarus / Plateforme : Windows, linux, macOs
---------------------------------------------------------------------

V-B. Création d'un objet JSON

Nous allons, dans cet exemple, créer par programme un document JSON dans le format ci-dessous représentant un petit carnet d'adresse :
carnet d'adresse au format JSON
{
 "personal" :
  [
   {"nom" : "Nabster", "email" :"nabster@darrylsite.tk"},
   {"nom" :"annis", "email" : "annis@darrylsite.tk"}
  ],
 "professional" :
  [
   {"nom" : "julius cesarius", "email" : "jcesarius@comesaf.com"},
   {"nom" : "nabistar", "email" : "nabistar@darrylsite.tk"}
  ]
}
J'ai écrit un bout code sous Lazarus avec une interface graphique permettant d'ajouter et supprimer des contacts.

Carnet d'adresse

Le code suivant est le code de l'unité contenant les données du programme :
Creation de données JSON
unit Unit2;
{$mode objfpc}{$H+}
interface

uses
     Classes, SysUtils, fpjson;

  Type
       ContactType =(personal, professional);

       TContact = class

                   public
                    constructor init();
                    procedure addContact(nom : String; email :String; tp : ContactType);
                    procedure removeContact(nom : String; email :String; tp : ContactType);
                    function getJSONData() : String;
                    destructor destroyed;
                    datas : TJSONObject;
                  end;

implementation

 constructor TContact.init();
 begin
  datas := TJSONObject.create();
  datas.add('personal', TJSONArray.Create);
  datas.add('professional', TJSONArray.Create);
 end;

 procedure TContact.addContact(nom : String; email : String; tp : ContactType);
  var cont : TJSONObject;
 begin
   cont := TJSONObject.Create(['nom', nom, 'email', email]);
  if (tp=personal) then
    datas.Arrays['personal'].Add(cont)
   else
    datas.Arrays['professional'].Add(cont);
 end;

 procedure TContact.removeContact(nom : String; email : String; tp : ContactType);
  var arr : TJSONArray;
      cont : TJSONObject;
      i : integer;
      trouve : boolean;
 begin
  if(tp=personal) then
    arr:=datas.Arrays['personal']
  else
    arr:=datas.Arrays['professional'];
  trouve := false;
  i:=0;
   while (not trouve) and (i<arr.Count) do
   begin
    cont := arr.Objects[i];
    if(cont.Strings['nom']=nom) and (cont.Strings['email']=email)then
     begin
      arr.Remove(cont);
      trouve:=true;
     end;
   end;
 end;

 function TContact.getJSONData() : AnsiString;
 begin
  result := datas.AsJSON;
 end;

 destructor TContact.destroyed;
 begin
  FreeAndNil(datas);
 end;

end.

VI. Conclusion et remerciements


VI-A. Conclusion

Nous avons donc exploré les bases du format d'échange de données JSON et de la librairie FCL-JSON. Si vous voulez plus de détails concernant l'utilisation de cette librairie, je vous recommande de consulter le code source de celle-ci, vu qu'il n'y a pas beaucoup de ressources disponibles sur le sujet sur le net.


VI-B. Remerciements

J'adresse tous mes remerciements à krachik et Alcatîz pour le temps qu'ils ont bien voulu passer à la correction et à l'amélioration de cet article.



               Version hors-ligne (Miroir)

Valid XHTML 1.0 TransitionalValid CSS!

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2010 Kpizingui Darryl. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée.

 
 
 
 
Partenaires

Hébergement Web