Un modèle d'objet JSON rapide et économe en mémoire, avec le support pour l'analyse et l'écriture efficaces au format conforme à JSON.
Cette bibliothèque ne dépend que du référentiel Neslib. Il est inclus sous forme de sous-module avec ce référentiel.
Le point d'entrée principal de cette bibliothèque est l'interface IJsonDocument . Il est utilisé pour l'analyse, le chargement et l'enregistrement des documents JSON et donne accès au modèle d'objet JSON. Vous pouvez analyser une chaîne JSON comme suit:
var
Doc: IJsonDocument;
begin
Doc := TJsonDocument.Parse( ' { "Answer" : 42 } ' );
end ;Notez que, contrairement à la spécification JSON officielle, cette bibliothèque ne nécessite pas de citations autour des clés de dictionnaire (tant que la clé ne contient pas d'espaces ou d'autres caractères non identifiants). Ainsi, ce qui suit est également valide:
Doc := TJsonDocument.Parse( ' { Answer : 42 } ' ); Vous pouvez également utiliser la méthode Load pour charger à partir d'un fichier ou d'un flux.
Du côté de la sortie, vous utilisez Save pour enregistrer dans un fichier ou un flux, ou ToJson pour sortir sur une chaîne JSON.
Vous pouvez également créer de nouveaux documents JSON à partir de zéro en utilisant les méthodes CreateArray ou CreateDictionary :
var
Doc: IJsonDocument;
begin
Doc := TJsonDocument.CreateArray;
Doc.Root.Add( 42 );
end ;Comme vous pouvez le voir dans cet exemple, vous accédez au modèle d'objet de document JSON via la propriété racine.
Au cœur du modèle d'objet JSON se trouve le type TJsonValue . Il s'agit d'un enregistrement qui peut contenir n'importe quel type de valeur JSON.
Il fournit divers opérateurs de conversion implicites pour convertir un TJsonValue en un autre type (Delphi). De plus, il existe différentes méthodes To* qui essaient de convertir une TJsonValue mais renvoient une valeur par défaut fournie si la conversion échoue.
Vous (pouvez) ne jamais créer vous-même TJsonValue ; La seule façon de créer un TJsonValue est d'ajouter une valeur à JSON TABLE ou Dictionary:
var
Doc: IJsonDocument;
begin
Doc := TJsonDocument.CreateArray;
Doc.Root.Add( 42 );
end ; Cet exemple ajoute un TJsonValue (avec valeur 42) à un tableau JSON. Pour créer un nouveau tableau de dictionnaire, vous utilisez plutôt les méthodes AddArray ou AddDictionary :
var
Doc: IJsonDocument;
Dict: TJsonValue;
begin
Doc := TJsonDocument.CreateArray;
Dict := Doc.Root.AddDictionary;
Dict.AddOrSetValue( ' answer ' , 42 );
end ;Cela crée un nouveau dictionnaire et l'ajoute au tableau racine. Ensuite, la valeur 42 est ajoutée à ce dictionnaire sous le nom de «réponse».
Pour vérifier le type d'une valeur, utilisez la propriété TJsonValue.ValueType ou l'une des méthodes TJsonValue.Is* .
Lorsque vous essayez d'utiliser des méthodes comme Add (ou AddOrSetValue ) sur des valeurs qui ne sont pas des tableaux (ou des dictionnaires), une exception sera élevée.
Cependant, l'accès aux éléments dans un tableau (en utilisant la propriété Items ) ou les valeurs d'un dictionnaire (en utilisant la propriété Values ) ne se traduira jamais par une exception, même si l'indice du tableau est hors limites. Cela permet de chaîner plusieurs accès à tableau / dictionnaire sans avoir à vérifier la validité de chaque étape intermédiaire. Par exemple:
I := Doc.Root.Items[ 3 ].Values[ ' foo ' ].Values[ ' bar ' ].Items[ 4 ].ToInteger( 0 );Cela réussira toujours, mais renvoyez 0 si l'une des valeurs intermédiaires n'est pas disponible.
L'interface IJsonDocument facilite la lecture et l'écriture de JSON dans un modèle d'objet de document.
Cependant, vous pouvez également choisir de lire ou d'écrire JSON manuellement si vous préférez (par exemple pour éviter d'avoir à charger un modèle d'objet en mémoire). Vous pouvez le faire avec les interfaces IJsonReader et IJsonWriter dans l'unité Neslib.Json.IO .
Ces interfaces sont complètement indépendantes de toute implémentation DOM et ne nécessitent même pas l'unité Neslib.Json . L'utilisation de ces interfaces est un peu plus compliquée et nécessite cependant un peu plus de travail. Voir l'unité Neslib.Json.IO pour plus d'informations.
Il existe également une implémentation JSONPATH de type XPath que vous pouvez utiliser pour interroger les documents JSON.
Il n'y a pas de spécification officielle JSONPATH, mais la version la plus utilisée semble être développée par Stefan Goessner.
Un jsonpath ressemble:
$.store.book[0].titleou
$['store']['book'][0]['title'] Les deux représentations sont identiques: vous pouvez utiliser le point ( . ) Ou le support ( [] ) pour désigner les enfants d'un dictionnaire. Les supports peuvent également être utilisés avec des indices numériques pour désigner les enfants d'un tableau par index.
JSONPATH n'utilise que des citations simples (') entre crochets. Nous permettons également des citations doubles (") car celles-ci sont plus faciles à utiliser dans les chaînes de Delphi.
En bref:
$ indiquant la racine, suivi de zéro ou plus d'opérateurs d'enfants . ou [] ). Un $ correspond à lui-même tout le document.* ou '*' ) pour correspondre à tous les enfants. Par exemple, $.store.book[*].author correspond aux auteurs de tous les livres du magasin.. ), Un double point ( .. ) peut être utilisé pour rechercher des descendants au lieu d'enfants immédiats. Par exemple, $..author correspond à tous les auteurs, quelle que soit la profondeur. C'est ce qu'on appelle la descente récursive.$.store.book[0,2,3] correspond aux premiers, troisième et quatrième livres.[Start:End:Step] pour correspondre à une tranche (plage) d'enfants. Cela correspond à tous les enfants du Start de l'index jusqu'à (mais à l'exception) End , en utilisant une taille Step donnée (généralement 1). Tous sont facultatifs, mais au moins une valeur (et un côlon) doit être donnée:Start est omis, il est impliqué d'être 0. Une valeur négative indique un décalage de la fin du tableau.End est omise, la tranche extrait à travers la fin du tableau. Une valeur négative indique et décalage de la fin du tableau.Step est omise, il est impliqué comme 1.List[2:] correspond au troisième et à tous les éléments suivants.List[-2:] correspond aux deux derniers éléments.List[:2] correspond aux deux premiers éléments.List[:-2] correspond à tous les deux éléments sauf les deux derniers.List[2:-2] correspond à tous les éléments mais les deux premiers et deux premiers.List[-4:-2] correspond aux 3e et 4e éléments de la fin.List[::2] correspond à tous les éléments avec un index uniforme.JSONPath dispose également d'un opérateur @ permettre des expressions de script personnalisées. Nous ne soutenons pas cet opérateur.
Exemple de document:
{ "store" : {
"book" : [
{ "category" : " reference " ,
"author" : " Nigel Rees " ,
"title" : " Sayings of the Century " ,
"price" : 8.95
},
{ "category" : " fiction " ,
"author" : " J. R. R. Tolkien " ,
"title" : " The Lord of the Rings " ,
"isbn" : " 0-395-19395-8 " ,
"price" : 22.99
}
],
"bicycle" : {
"color" : " red " ,
"price" : 19.95
}
}
}Exemples de chemins:
| Expression | Résultat |
|---|---|
$ | Correspond au document racine (une seule valeur) |
$..* | Correspond à tous les membres du document (beaucoup de valeurs) |
$.store.book[*].author | Les auteurs de tous les livres du magasin |
$..author | Tous les auteurs |
$.store.* | Toutes choses en magasin (2 livres et un vélo) |
$.store..price | Le prix de tout dans le magasin |
$..book[2] | Le troisième livre |
$..book[-1:] | Le dernier livre dans l'ordre |
$..book[:2] | Les deux premiers livres |
L'API JSONPATH est courte et simple. Il se compose d'un record TJsonPath avec seulement quelques méthodes.
Pour une correspondance unique, utilisez la méthode Match statique:
var
Doc: IJsonDocument;
Matches: TArray<TJsonValue>;
begin
Doc := TJsonDocument.Load(...);
Matches := TJsonPath.Match(Doc, ' $.store.book[*].author ' );
end ;Si vous prévoyez d'utiliser le même chemin sur plusieurs (sub) documents, il est plus rapide d'analyser le chemin une fois, puis de l'appliquer plusieurs fois:
var
Doc1, Doc2: IJsonDocument;
Path: TJsonPath;
Matches1, Matches2: TArray<TJsonValue>;
begin
Doc1 := TJsonDocument.Load(...);
Doc2 := TJsonDocument.Load(...);
Path := TJsonPath.Create( ' $.store.book[*].author ' );
Matches1 := Path.Match(Doc1);
Matches2 := Path.Match(Doc2);
end ;Vous pouvez également exécuter le chemin sur des sous-arbres:
var
Doc: IJsonDocument;
Store: TJsonValue;
Matches: TArray<TJsonValue>;
begin
Doc := TJsonDocument.Load(...);
Store := Doc.Root.Values[ ' store ' ];
Matches := TJsonPath.Match(Store, ' $.book[*].author ' );
end ; Si vous êtes uniquement intéressé par une seule (ou la première) match, vous pouvez utiliser MatchSingle à la place:
var
Doc: IJsonDocument;
Match: TJsonValue;
begin
Doc := TJsonDocument.Load(...);
if (TJsonPath.MatchSingle(Store, ' $.book[*] ' , Match)) then
...
end ; Toute la gestion de la mémoire dans cette bibliothèque JSON est automatique. Une interface IJsonDocument possède tous les TJsonValue et les détruit lorsque le document est détruit (sort de la portée).
La seule chose dont vous devez être consciente, c'est que vous ne devez plus utiliser de dossiers TJSONValue après la détruire du document. Cela entraînera un comportement non défini et peut-être des plantages.
Vous pouvez personnaliser un certain comportement en utilisant ces définies conditionnelles:
JSON_UTF8 : Pour utiliser UTF8String au lieu de String partout. Toutes les chaînes seront traitées comme des cordes UTF-8 8 bits au lieu de chaînes Unicode 16 bits. Cela réduit la consommation de mémoire et accélère un peu d'analyse. Cependant, cela signifie que vous devrez également utiliser cette bibliothèque JSON avec UTF8Strings, sinon Delphi convertira implicitement entre Unicode Strings et UTF8Strings, ce qui peut nuire aux performances.JSON_STRING_INTERNING : Activer l'entretage de chaîne pour les touches de dictionnaire. Cela réduit la consommation de mémoire dans le cas où la même clé est utilisée beaucoup de fois (ce qui est courant lorsque JSON est exporté à partir d'une base de données), mais est un peu plus lent. L'unité Neslib.json déclare le type JsonString en tant que String ou UTF8String , selon la définition JSON_UTF8 . Cependant, cela ne signifie pas que vous devez également utiliser JsonString . Si vous ne vous souciez pas de la définition JSON_UTF8 , vous pouvez simplement utiliser des chaînes régulières avec cette bibliothèque.
Neslib.json est autorisé sous la licence BSD simplifiée.
Voir Licence.txt pour plus de détails.