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 |
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.
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;
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;
|
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
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 TJSONBoolean
Constructor Create(AValue : Boolean);
|
- Pour la classe TJSONString
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);
|
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;
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;
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.
Le code suivant est le code de l'unité contenant les données du programme :
| Creation de données JSON |
unit Unit2;
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.


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.