Un constructeur Delphi / Lazarus / C ++ Simple and Small Class pour l'analyse JSON rapide.
Quelques points d'intérêt:
McJSON ), une seule classe ( TMcJsonItem ). uses
McJSON;
...
function Test99 (out Msg: string): Boolean;
var
Json: TMcJsonItem;
i: Integer;
begin
Msg := ' Test: Github readme.md content ' ;
Json := TMcJsonItem.Create();
try
try
// add some pairs.
Json.Add( ' key1 ' ).AsInteger := 1 ;
Json.Add( ' key2 ' ).AsBoolean := True;
Json.Add( ' key3 ' ).AsNumber := 1.234 ;
Json.Add( ' key4 ' ).AsString := ' value 1 ' ;
// add an array
Json.Add( ' array ' , jitArray);
for i := 1 to 3 do
Json[ ' array ' ].Add.AsInteger := i;
// save a backup to file
if (Json[ ' array ' ].Count = 3 ) then
Json.SaveToFile( ' test99.json ' );
// remove an item
Json.Delete( ' array ' );
// oops, load the backup
if (Json.Count = 4 ) then
Json.LoadFromFile( ' test99.json ' );
// test final result
Result := (Json.AsJSON = ' {"key1":1,"key2":true,"key3":1.234,"key4":"value 1","array":[1,2,3]} ' );
except
Result := False;
end ;
finally
Json.Free;
end ;
end ; Produira testtest99.json :
{
"key1" : 1 ,
"key2" : true ,
"key3" : 1.234 ,
"key4" : " value 1 " ,
"array" : [
1 ,
2 ,
3
]
}# include " McJson.hpp "
...
bool Test99 (AnsiString& Msg)
{
bool Result;
TMcJsonItem* Json = NULL ;
Msg = " Test: Github readme.md content " ;
Json = new TMcJsonItem ();
try
{
try
{ // add some pairs.
Json-> Add ( " key1 " )-> AsInteger = 1 ;
Json-> Add ( " key2 " )-> AsBoolean = true ;
Json-> Add ( " key3 " )-> AsNumber = 1.234 ;
Json-> Add ( " key4 " )-> AsString = " value 1 " ;
// add an array
Json-> Add ( " array " , jitArray);
for ( int i = 1 ; i <= 3 ; i++)
Json-> Values [ " array " ]-> Add ()-> AsInteger = i;
// save a backup to file
if (Json-> Values [ " array " ]-> Count == 3 )
Json-> SaveToFile ( " test99.json " );
// remove an item
Json-> Delete ( " array " );
// oops, load the backup
if (Json-> Count == 4 )
Json-> LoadFromFile ( " test99.json " );
// test final result
Result = (Json-> AsJSON ==
" { " key1 " :1, " key2 " :true, " key3 " :1.234, " key4 " : " value 1 " , " array " :[1,2,3]} " );
}
catch (...)
{
Result = false ;
}
}
__finally
{
if (Json) delete (Json);
}
return (Result);
} Veuillez considérer les tests unitaires lire dans le dossier test pour une liste complète des cas d'utilisation McJSON .
Utilisez simplement la propriété AsJSON
var
N: TMcJsonItem;
begin
N := TMcJsonItem.Create;
N.AsJSON := ' {"i": 123, "f": 123.456, "s": "abc", "b": true, "n": null} ' ;
// use N here
N.Free;
end ; Si vous souhaitez vérifier si une chaîne JSON est valide:
Answer := N.Check( ' {"i":[123} ' ); // Answer will be false La méthode Check ne soulèvera aucune exception. L'exemple ci-dessus attrapera et masquera l' Error while parsing text: "expected , got }" at pos "10" . Si vous devez attraper et gérer les exceptions, utilisez CheckException comme:
try
Answer := N.CheckException( ' {"k":1, "k":2} ' ); // Answer will be false
except
on E: Exception do
begin
// Error while parsing text: "duplicated key k" at pos "11"
end ;
end ; McJSON permet un moyen simple d'accéder aux articles par des chemins. Nous pouvons utiliser '/', '' ou '.' comme séparateurs de chemin.
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
// access and change second object's value
N.Path( ' o.k2 ' ).AsString := ' value2 ' ;Résultats:
{
"o" : {
"k1" : " v1 " ,
"k2" : " value2 "
}
} Notez que Path() n'accepte pas encore les index, comme ceci:
N.AsJSON := ' {"o": [{"k1":"v1"}, {"k2":"v2"}] ' ;
N.Path( ' o[1].k2 ' ).AsString := ' value2 ' ; Étant donné que la version 1.0.4 McJSON permet d'utiliser des raccourcisseurs de propriétés comme dans les objets de données JSON d'Andreas Hausladen.
// access (automatic creation as in JDO)
Obj.S[ ' foo ' ] := ' bar ' ;
Obj.S[ ' bar ' ] := ' foo ' ;
// array creation, Obj is the owner of 'array'
Obj.A[ ' array ' ].Add.AsInteger := 10 ;
Obj.A[ ' array ' ].Add.AsInteger := 20 ;
// object creation, 'array' is the owner of ChildObj
ChildObj := Obj[ ' array ' ].Add(jitObject);
ChildObj.D[ ' value ' ] := 12.3 ;
// array creation, ChildObj is the owner of 'subarray'
ChildObj.A[ ' subarray ' ].Add.AsInteger := 100 ;
ChildObj.A[ ' subarray ' ].Add.AsInteger := 200 ;Résultats:
{
"foo" : " bar " ,
"bar" : " foo " ,
"array" :[
10 ,
20 ,
{
"value" : 12.3 ,
"subarray" :[
100 ,
200
]
}
]
}Voici comment accéder à tous les éléments (enfants) d'un objet JSON et modifier leur type de valeur et leur contenu.
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
// type and value: from string to integer
for i := 0 to N[ ' o ' ].Count- 1 do
N[ ' o ' ].Items[i].AsInteger := i+ 1 ; Résultats:
{
"o" : {
"k1" : 1 ,
"k2" : 2
}
} Nous pouvons utiliser les propriétés Items[index] et Values['key'] pour accéder aux éléments à l'intérieur d'objets et de tableaux. Depuis la version 0.9.5 , nous pouvons utiliser l' At(index, 'key') ou At('key', index) comme raccourcisseurs.
N.AsJSON := ' {"a": [{"k1":1,"k2":2},{"k1":10,"k2":20}]} ' ;
// how to access k2 of second object.
i := N[ ' a ' ].Items[ 1 ].Values[ ' k2 ' ].AsInteger; // i will be equal to 20
i := N[ ' a ' ].Items[ 1 ][ ' k2 ' ].AsInteger; // uses the Values[] as default property
i := N[ ' a ' ].At( 1 , ' k2 ' ).AsInteger; // shortener: index, key
i := N.At( ' a ' , 1 )[ ' k2 ' ].AsInteger; // shortener: key, index Et il y a d'autres utilisations sans le paramètre key :
N.AsJSON := ' {"k1":1,"k2":2,"k3":3,"k4":4} ' ;
i := N.Items[ 2 ].AsInteger; // i will be equal to 3
i := N.At( 2 ).AsInteger; // shortener: just index
i := N.At( ' k3 ' ).AsInteger; // shortener: just keyÀ l'aide de Delphi Enumerator, vous pouvez parcourir les enfants et les valeurs de l'objet de l'élément.
var
N, item: TMcJsonItem;
begin
N := TMcJsonItem.Create;
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
for item in N[ ' o ' ] do
// use item here, e.g. item.Key, item.Value, item.AsStringModifiez toutes les valeurs d'un objet avec plusieurs éléments. Pas si courant là-bas.
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
N[ ' o ' ].AsString := ' str ' ;Résultats:
{
"o" : {
"k1" : " str " ,
"k2" : " str "
}
} Et s'il est nécessaire de modifier le type de o :
N[ ' o ' ].ItemType := jitValue;
N[ ' o ' ].AsString := ' str ' ;Résultats:
{
"o" : " str "
}Convertir du tableau en type d'objet et vice-versa. Aussi, pas si courant là-bas.
N.AsJSON := ' { "k1": ["1", "2"], "k2": {"1": "a", "2": "b"} } ' ;
N[ ' k1 ' ].ItemType := jitObject; // convert array to object with items
N[ ' k2 ' ].ItemType := jitArray ; // convert object with items to array Résultats:
{
"k1" : {
"0" : " 1 " ,
"1" : " 2 "
},
"k2" : [
" a " ,
" b "
]
}Insérez certains éléments à l'aide de clés et de position.
P.Insert( ' c ' , 0 ).AsInteger := 3 ;
P.Insert( ' b ' , 0 ).AsInteger := 2 ;
P.Insert( ' a ' , 0 ).AsInteger := 1 ;Résultats:
{
"a" : 1 ,
"b" : 2 ,
"c" : 3
}De plus, il est possible d'insérer des objets dans les tableaux.
Q.AsJSON := ' {"x":0} ' ;
P.ItemType := jitArray;
P.Insert(Q, 1 );Résultats:
[
1 ,
{
"x" : 0
},
2 ,
3
] IMPORTANT : Depuis la version 0.9.3, Add() et Insert() cloneront les arguments de type TMcJsonItem . Donc, nous devons également libérer de la mémoire pour Q :
P.Free;
Q.Free; Étant donné que les chaînes de version 1.0.5 peuvent être échappées avec la fonction d'assistance McJsonEscapeString() :
N.AsJSON := ' {"path": ' + McJsonEscapeString( ' dirsubdir ' ) + ' } ' ; Résultats:
{
"path" : " \ dir \ subdir "
} Dans la version 1.0.6, a été introduit, l'énume TJEscapeType utilisé dans McJsonEscapeString() avec ces niveaux d'évasion:
jetNormal : s'échappe #8 #9 #10 #12 #13 " .jetStrict : normal + / .jetUnicode : strict + uXXXX .jetNone : Compatibilité vers l'arrière. Ces niveaux sont inspirés par la fonction d'assistance de Lazarus StringToJSONString() de la bibliothèque fpjson.
Voyons comment inspecter toutes les structures, types et valeurs de données internes d'un objet TMcJsonItem .
// ---------------------------------------------------------------------------
void
TFormMain::Inspect (TMcJsonItem* AMcJItem, AnsiString Ident)
{
if (!AMcJItem) return ;
// log current
MyLog ( Ident + ItemToStr (AMcJItem) );
// log child
if ( AMcJItem-> HasChild )
{
Ident = " " + Ident;
for ( int i= 0 ; i < AMcJItem-> Count ; i++)
{ // use Value not Child because are note using Key[].
Inspect ( AMcJItem-> Items [i], Ident );
}
}
}
// ---------------------------------------------------------------------------
String
TFormMain::ItemToStr (TMcJsonItem* AMcJItem) const
{
String Ans = " " ;
if (AMcJItem)
Ans = AMcJItem-> GetTypeStr () +
" ; " + AMcJItem-> GetValueStr () +
" ; Key= " + AMcJItem-> Key +
" ; Value= " + AMcJItem-> Value +
" ; JSON= " + AMcJItem-> AsJSON ;
return (Ans);
}
// --------------------------------------------------------------------------- Et en utilisant un exemple comme testInspect.json :
{
"foo" : " bar " ,
"array" : [
100 ,
20
],
"arrayObj" : [
{
"key1" : 1.0
},
{
"key2" : 2.0
}
],
"Msg" : [
" #1 UTF8 example: motivação " ,
" #2 Scapes: btnfr\ uFFFF "\ "
]
} Appeler Inspect() avec un objet Json chargé de testInspect.json :
TMcJsonItem* Json = new TMcJsonItem();
if (Json)
{
Json-> LoadFromFile ( " testInspect.json " );
Inspect (Json);
delete (Json);
}Résultats:
object; string; Key=; Value=; JSON={"foo":"bar","array":[100,20],"arrayObj":[{"key1":1.0},{"key2":2.0}],"Msg":["#1 UTF8 example: motivação","#2 Scapes: btnfru"\"]}
value; string; Key=foo; Value=bar; JSON="foo":"bar"
array; string; Key=array; Value=; JSON="array":[100,20]
value; number; Key=; Value=100; JSON=100
value; number; Key=; Value=20; JSON=20
array; string; Key=arrayObj; Value=; JSON="arrayObj":[{"key1":1.0},{"key2":2.0}]
object; string; Key=; Value=; JSON={"key1":1.0}
value; number; Key=key1; Value=1.0; JSON="key1":1.0
object; string; Key=; Value=; JSON={"key2":2.0}
value; number; Key=key2; Value=2.0; JSON="key2":2.0
array; string; Key=Msg; Value=; JSON="Msg":["#1 UTF8 example: motivação","#2 Scapes: btnfruFFFF"\"]
value; string; Key=; Value=#1 UTF8 example: motivação; JSON="#1 UTF8 example: motivação"
value; string; Key=; Value=#2 Scapes: btnfruFFFF"\; JSON="#2 Scapes: btnfruFFFF"\"
Depuis la version 0.9.0 , les clés vides seront analysées et vérifiées avec des erreurs:
N.AsJSON := ' {"": "value"} ' ; Et ToString() produira un objet JSON valide:
{
"" : " value "
}En interne, il utilisera la chaîne constante C_EMPTY_KEY comme contenu du champ FKEY.
Depuis la version 0.9.2 , les chaînes avec des pauses de ligne non échappées seront analysées avec des erreurs:
N.AsJSON := ' {"key": "value ' + # 13 + ' "} ' ;Soulera une exception:
Error while parsing text: "line break" at pos "14"
McJSON peut se charger à partir des fichiers ASCII et UTF-8 (avec ou sans bom). Voir la méthode LoadFromFile . La méthode SaveToFile écrira en utilisant le codage UTF-8. Remarque : Depuis Vertion 1.0.4, le code source du projet de test à Lazarus a été converti en UTF-8, de sorte que le paramètre asUTF8 a été défini sur false .
Le monde n'est pas parfait et je ne le suis pas non plus. Voici quelques problèmes connus:
TMcJsonItem sont instanciés dans la structure hiérarchique à l'aide de listes fChild , il y a un problème pour créer des champs qui se propagent automatiquement entre les éléments. Une solution à l'étude essaie de créer une nouvelle classe parent TMcJson qui sera comme des racines et aura des objets TMcJsonItem comme enfants. Un test de performance a été effectué avec les unités d'origine myJSON , LkJson , JsonTools et uJSON . Voici un résumé des tests.
{... {"keyi":"valuei"}... }Et à propos du compilateur et de la machine utilisés:
Le tableau suivant résume les résultats 1 :
| Bibliothèque | Générer | Sauvegarder | Analyse | Charger | Accéder | Total |
|---|---|---|---|---|---|---|
McJSON 2 | .11 s | .07 s | .12 S | .09 s | .83 s | 1,25 s |
LkJson 2 | .30 S | .11 s | .47 s | .36 s | .01 S | 1,24 s |
JsonTools | 48.00 s | .70 S | 39,00 s | 40.00 s | .48 s | 1,2 min |
myJSON | 50,00 s | .07 s | 5,1 min | 7,7 min | 1,60 s | 13.1 min |
uJSON | 18,6 min | 20,1 min | 17,5 min | 4.31 s | 53,02 s | 57,6 min |
McJSONJson->Add("key")->AsString = "value" .JsonP->AsJSON = Json->AsJSON .LkJsonTlkBalTree de la recherche équilibrée".dynamic_cast en faisant la verbosie du code.Json->Add("key", "value") .JsonP = dynamic_cast<TlkJSONObject*>(TlkJSON::ParseText(NULL, TlkJSON::GenerateText(NULL, Json))) .JsonToolsJson->Add("key", "value") .JsonP->Value = Json->AsJson .myJSONJson->Item["key"]->setStr("value") .JsonP->Code = Json->getJSON() .uJSONLkJson , mais la colection des classes obligera également le casting avec dynamic_cast .uJSON , il semble y avoir un problème de performance lié à toString() .Json->put("key", "value") .JsonP = new TJSONObject(Json->toString()) .SaveToFile n'existe pas, il a donc utilisé TStringList->SaveToFile() après avoir rempli Text avec Json->toString() . Métrique: temps moyen en secondes (s) pour 5 exécutions consécutives. Le total est la moyenne des tests partiels. Certains résultats se sont convertis en minutes (min). ↩
Version 1.0.5. Amélioration du projet JSON 0.9.0 Test qui sera publié bientôt. ↩ ↩ 2