Ein Delphi / Lazarus / C ++ Builder Einfache und kleine Klasse für schnelle JSON -Parsen.
Einige Punkte von Interesse:
McJSON ), nur eine Klasse ( 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 ; Produziert 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);
} Bitte beachten Sie, wie Sie im test eine vollständige Liste der McJSON -Anwendungsfälle haben.
Verwenden Sie einfach das AsJSON -Eigentum
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 ; Wenn Sie überprüfen möchten, ob eine JSON -Zeichenfolge gültig ist:
Answer := N.Check( ' {"i":[123} ' ); // Answer will be false Die Check -Methode erhöht keine Ausnahme. Das obige Beispiel wird den Error while parsing text: "expected , got }" at pos "10" -Ausnahme. Wenn Sie Ausnahmen fangen und verwalten müssen, verwenden Sie CheckException wie:
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 ermöglicht eine einfache Möglichkeit, über Pfade auf Artikel zugreifen zu können. Wir können '/', '' oder 'verwenden.' als Pfadabscheider.
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
// access and change second object's value
N.Path( ' o.k2 ' ).AsString := ' value2 ' ;Führt zu:
{
"o" : {
"k1" : " v1 " ,
"k2" : " value2 "
}
} Beachten Sie, dass Path() die Indizes wie folgt noch nicht akzeptiert:
N.AsJSON := ' {"o": [{"k1":"v1"}, {"k2":"v2"}] ' ;
N.Path( ' o[1].k2 ' ).AsString := ' value2 ' ; Seit Version 1.0.4 ermöglicht McJSON die Verwendung von Eigenschaftskürzern wie in Andreas Hausladens JSON -Datenobjekten.
// 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 ;Führt zu:
{
"foo" : " bar " ,
"bar" : " foo " ,
"array" :[
10 ,
20 ,
{
"value" : 12.3 ,
"subarray" :[
100 ,
200
]
}
]
}Hier erfahren Sie, wie Sie auf alle Elemente (Kinder) eines JSON -Objekts zugreifen und ihren Werttyp und seinen Inhalt ändern können.
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 ; Führt zu:
{
"o" : {
"k1" : 1 ,
"k2" : 2
}
} Wir können die Eigenschaften Items[index] und Values['key'] verwenden, um in Objekten und Arrays auf Elemente zuzugreifen. Seit Version 0.9.5 können wir den At(index, 'key') oder At('key', index) als Shortener verwenden.
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 Und es gibt andere Verwendungen ohne den 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 keyMit Delphi Enumerator können Sie die Objekt Kinder und Werte des Elements durchsuchen.
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.AsStringÄndern Sie alle Werte eines Objekts mit mehreren Elementen. Nicht so häufig da draußen.
N.AsJSON := ' {"o": {"k1":"v1", "k2":"v2"}} ' ;
N[ ' o ' ].AsString := ' str ' ;Führt zu:
{
"o" : {
"k1" : " str " ,
"k2" : " str "
}
} Und wenn es notwendig ist, die Art von o zu ändern:
N[ ' o ' ].ItemType := jitValue;
N[ ' o ' ].AsString := ' str ' ;Führt zu:
{
"o" : " str "
}Konvertieren Sie von Array in Objekttyp und umgekehrt. Auch da draußen nicht so häufig.
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 Führt zu:
{
"k1" : {
"0" : " 1 " ,
"1" : " 2 "
},
"k2" : [
" a " ,
" b "
]
}Fügen Sie einige Elemente mit Schlüsseln und Position ein.
P.Insert( ' c ' , 0 ).AsInteger := 3 ;
P.Insert( ' b ' , 0 ).AsInteger := 2 ;
P.Insert( ' a ' , 0 ).AsInteger := 1 ;Führt zu:
{
"a" : 1 ,
"b" : 2 ,
"c" : 3
}Außerdem ist es möglich, Objekte in Arrays einzufügen.
Q.AsJSON := ' {"x":0} ' ;
P.ItemType := jitArray;
P.Insert(Q, 1 );Führt zu:
[
1 ,
{
"x" : 0
},
2 ,
3
] WICHTIG : Seit Version 0.9.3, Add() und Insert() klonen Argumente vom Typ TMcJsonItem . Wir müssen also auch für Q den Speicher freigeben:
P.Free;
Q.Free; Da Version 1.0.5 Saiten mit McJsonEscapeString() Helfer -Funktion entkommen können:
N.AsJSON := ' {"path": ' + McJsonEscapeString( ' dirsubdir ' ) + ' } ' ; Führt zu:
{
"path" : " \ dir \ subdir "
} In Version 1.0.6 wurde der TJEscapeType Enum eingeführt, der in McJsonEscapeString() mit diesen Fluchtpegeln verwendet wurde:
jetNormal : Es entkommt #8 #9 #10 #12 #13 " .jetStrict : Normal + / .jetUnicode : strict + uXXXX .jetNone : Abwärtskompatibilität. Diese Ebenen sind von Lazarus 'Helferfunktion StringToJSONString() aus der Bibliothek FPJSON inspiriert.
Lassen Sie uns sehen, wie alle inneren Datenstruktur, Typen und Werte eines TMcJsonItem -Objekts untersucht werden.
// ---------------------------------------------------------------------------
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);
}
// --------------------------------------------------------------------------- Und verwenden ein Beispiel wie testInspect.json :
{
"foo" : " bar " ,
"array" : [
100 ,
20
],
"arrayObj" : [
{
"key1" : 1.0
},
{
"key2" : 2.0
}
],
"Msg" : [
" #1 UTF8 example: motivação " ,
" #2 Scapes: btnfr\ uFFFF "\ "
]
} Calling Inspect() mit einem Json -Objekt mit testInspect.json :
TMcJsonItem* Json = new TMcJsonItem();
if (Json)
{
Json-> LoadFromFile ( " testInspect.json " );
Inspect (Json);
delete (Json);
}Führt zu:
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"\"
Seit Version 0.9.0 werden leere Tasten mit Fehlern analysiert und überprüft:
N.AsJSON := ' {"": "value"} ' ; Und ToString() erzeugt ein gültiges JSON -Objekt:
{
"" : " value "
}Intern werden die konstante Zeichenfolge c_empy_key als Inhalt des Fkey -Feldes verwendet.
Seit Version 0.9.2 werden Saiten mit nicht entkommenen Linienbrüchen mit Fehlern analysiert:
N.AsJSON := ' {"key": "value ' + # 13 + ' "} ' ;Wird Ausnahme ausschöpfen:
Error while parsing text: "line break" at pos "14"
McJSON kann aus ASCII- und UTF-8-Dateien (mit oder ohne BOM) laden. Siehe LoadFromFile -Methode. Die SaveToFile -Methode schreibt mit der UTF-8-Codierung. HINWEIS : Seit der Veration 1.0.4 wurde der Quellcode des Testprojekts in Lazarus in UTF-8 konvertiert, sodass der asUTF8 Parameter auf false eingestellt wurde.
Die Welt ist nicht perfekt und auch nicht. Hier sind einige bekannte Themen:
TMcJsonItem -Objekte in hierarchischer Struktur mithilfe von Listen fChild instanziiert werden, besteht ein Problem, Felder zu erstellen, die sich automatisch zwischen Elementen ausbreiten. Eine untersuchte Lösung versucht, eine neue übergeordnete Klasse TMcJson zu erstellen, die Objekte wie Wurzeln ähneln und als ihre Kinder TMcJsonItem -Objekte aufweisen werden. Ein Leistungstest wurde mit den ursprünglichen Einheiten von myJSON , LkJson , JsonTools und uJSON durchgeführt. Hier ist eine Zusammenfassung der Tests.
{... {"keyi":"valuei"}... }Und über den Compiler und die verwendete Maschine:
Die nächste Tabelle fasst die Ergebnisse 1 zusammen: 1:
| Bibliothek | Erzeugen | Speichern | Analysieren | Laden | Zugang | Gesamt |
|---|---|---|---|---|---|---|
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 .dynamic_cast , die den Code wörtlich machen.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 , aber die Colection of Klassen erzwingt auch das Casting mit dynamic_cast .uJSON scheint es ein Leistungsproblem im Zusammenhang mit toString() zu geben.Json->put("key", "value") .JsonP = new TJSONObject(Json->toString()) .SaveToFile existiert nicht, so dass es TStringList->SaveToFile() verwendet hat, nachdem Text mit Json->toString() ausgefüllt wurde. Metrik: Durchschnittliche Zeit in Sekunden (en) für 5 aufeinanderfolgende Hinrichtungen. Summe ist der Durchschnitt der Teilprüfungen. Einige Ergebnisse wurden in Minuten (min) umgewandelt. ↩
Version 1.0.5. Verbesserter Test JSON 0.9.0 Projekt, das in Kürze veröffentlicht wird. ↩ ↩ 2