V tomto článku popíši základy použití JSON v Delphi.
Článek mi byl zaslán a autor chce zůstat jen pod nickem <z>.
Několik základních faktů o JSON
- JSON je jednoduchý formát určený a vyvinutý přímo pro výměnu dat.
- JSON je alternativa ke XML, vhodnost jednoho nebo druhého je individuální.
- Úspora v zapsání stejných dat v JSON oproti XML může být až 40% (je to dáno zřejmě tím, že se nevyužívájí párové tagy).
- JSON je velmi stabilní formát, tj. neexituje verze 1, 2, …
- Data v JSON jsou ukládána pomocí Unicode (UTF-8), a proto odpadá problém při využití různých kódování.
- Data v JSON mohou obsahovat jak páry (název a k tomu hodnota), tak i samotné hodnoty (pole hodnot).
malá ukázka struktury JSON:
{
"name": "Henri Gourvest", /* this is a comment */
"vip": true,
"telephones": ["000000000", "111111111111"],
"age": 33,
"size": 1.83,
"adresses": [
{
"adress": "blabla",
"city": "Metz",
"pc": 57000
},
{
"adress": "blabla",
"city": "Nantes",
"pc": 44000
}
]
}
Více o JSON a o struktuře lze nalézt na json.org (včetně možných datových typů), nebo v dříve odkazovaném článku co napsal o JSON Paweł Głowacki.
V Delphi je možné využít více knihoven k práci s JSON (viz. předchozí článek o JSON).
Zde představím jen lkJSON a SuperObject.
Obě knihovny lze použít ve všemožných verzích Delphi i FPC, jsou volně ke stažení i se zdrojovým kódem.
lkJSON
V balíku lkJSON jsou dodány jednoduché příklady. Zde jsou komentované základy.
var
js:TlkJSONobject;
i:Integer;
begin
// vytvoreni objektu
//js := TlkJSONobject.Create; // jednoduche vytvoreni
js:=TlkJSON.ParseText('{}') as TlkJSONobject; // vytvoreni parsovanim
// kontrola
if js=nil then
Exit;
try
// pridavani polozek, nazev je string, hodnota může vzít různé typy
js.Add('jmeno','hodnota-1');
// pridat dalsi polozku se stejnym jmenem u lkJSON jde
// hodnotu uz ale vzit asi nejde
js.Add('jmeno','hodnota-2');
// pridani polozky, ktera jako hodnotu obsahuje dalsi objekt {}
js.Add('objekt',TlkJSONobject.Create);
// pridani polozky do pod-objektu
(js.Field['objekt'] as TlkJSONobject).Add('jmeno-objekt','hodnota-3');
js.Add('pole',TlkJSONlist.Create); // vytvoreni pole []
(js.Field['pole'] as TlkJSONlist).Add(20); // pridani polozky do pole
// cteni polozek
ShowMessage('Podle indexu: '+js.getString(0)); // podle indexu
// pomoci .Field a indexu
ShowMessage('Pomoci field: '+(js.FieldByIndex[1] as TlkJSONstring).Value);
ShowMessage('Podle nazvu: '+js.getString('jmeno')); // pomoci nazvu
// cteni z podobjektu
ShowMessage('Podobjekt: '+
(js.Field['objekt'] as TlkJSONobject).getString('jmeno-objekt'));
// prochazeni struktury JSON
// asi lze vyuzit "for … in … do" jako u SuperObject, ale to jsem netestoval
for i := 0 to js.Count - 1 do
case js.FieldByIndex[i].SelfType of
jsString: ShowMessage('Prochazeni: '
+VarToStr((js.FieldByIndex[i] as TlkJSONstring).Value));
// …
end;
// generovani JSON datove struktury pro prenos
//Memo1.Lines.Text:=TlkJSON.GenerateText(js); // jen text
i:=0;
Memo1.Lines.Text:=GenerateReadableText(js,i); // strukturovany text
finally
//js.Free;
FreeAndNil(js);
end;
end;
SuperObject
Použití SuperObject je o něco jednodušší. Více informací lze zjistit zde: code.google.com/p/superobject/wiki/first_steps
var
json: ISuperObject;
// promenne pro prochazeni
item1: ISuperObject;
item2: TSuperAvlEntry;
item3: TSuperObjectIter;
begin
// vytvoreni
json := SO(); // v zavorce lze parsovat JSON
if json=nil then
Exit; // jen pro jistotu, ze objekt byl vytvoren
// jeste pro jistotu, ze to je objekt {}
// pri parsovani prazdneho textu neni a nefungovalo by to spravně
// jeste to muze byt pripadne pole []
if not json.IsType(stObject) then
begin
json:=nil;
Exit;
end;
try
// pridavani a cteni polozek
// S[] - string
// I[] - integer
// B[] - boolean …
// specialni vyznam v nazvu maji tecka, (), [], mozna neco dalsiho
// json.ForcePath('nazev-prvku'); //zaruci existenci prvku
json.S['jmeno-str']:='hodnota-1';
json.I['jmeno-int']:=11;
// prace se strukturou, slozitejsi metoda
json.O['objekt']:=SO; // vytvoreni objektu, stejne jako ForcePath
json.O['objekt'].S['jmeno-sub']:='hodnota-2'; // pridani polozky
// zkraceny zapis pro vytvareni i cteni
// tecka znaci praci s hodnotou, ktera je v podobjektu
// hranate zavorky slouzi k praci s hodnotami pole
// kulate zavorky jsou pro volani metod - zde je mozne se vyuzit hodnot v JSON
// knihovna ohlida a vytvori potrebnou strukturu
json.S['objekt-2.jmeno-sub-1']:='hodnota-3'; // vytvori objekt i polozku
json.S['pole[]']:='polozka pole'; // vytvoreni a pridani polozky do pole
json.S['pole[2]']:='polozka dalsi'; // vytvoreni a pridani polozky na pozici
// cteni polozky podle indexu
// (nevim o jinym jednodussim reseni)
ShowMessage(json.AsObject.GetValues.AsArray[3].AsString);
// prochazeni vsech polozek - moznost 1
// POZN.: Array ma polozku Length, Object ma Count
for item1 in json do
case item1.DataType of
// superobject dovoluje cist integer jako string
stString, stInt: ShowMessage('Prochazeni 1: '+item1.AsString);
//…
end;
// prochazeni - moznost 2
for item2 in json.AsObject do
begin
case item2.Value.DataType of
stString, stInt: ShowMessage('Prochazeni 2: '+item2.Name+' : '
+item2.Value.AsString);
// …
end;
end;
// prochazeni - moznost 3
if ObjectFindFirst(json, item3) then
repeat
case item3.val.DataType of
stString, stInt: ShowMessage('Prochazeni 3: '+item3.key+' : '+
item3.val.AsString);
// …
end;
until not ObjectFindNext(item3);
ObjectFindClose(item3);
// v zavorce - strukturovany / nestrukturovany vystup
Memo1.Lines.Text:=json.AsJSon(True);
finally
// uvolneni
json:=nil;
end;
end;
Osobně využívám SuperObject. Výhodou je jednodušší přístup k jednotlivým prvkům, podobjektům, polím, kde není potřeba se o nic starat.
SuperObject si take poradi s parsováním některých ne-validních sturktur a umožňuje parsovat i XML a převést do JSON.
Malou vyhodou lkJSON je jednodussi vyber polozek pomoci indexu (.Field), na to se ale v JSON spolehat neda.
Rychlost práce obou knihoven je přibližně stejná. JSON používám namísto INI k ukládání dat.
Pro srovnání, udělal jsem si test pro zápis tisíců hodnot a načtení x-té položky:
- INI 3 sekundy!!
- lkJSON 32 ms
- SuperObject 16ms
Pokud potřebujete průběžně ukládat velké množství dat, JSON se určitě vyplatí využít. Je potřeba si dávat pozor při procházení podobjektů, jestli v dané struktuře existují.
Jestli někdo potřebuje nějakou pomoc, stačí napsat a další informace doplním.
<z>
Pozn.: Moc díky za článek. Pokud máte odvahu napsat podobný článek s tématikou Delphi, rád ho uveřejním a myslím, že to ocení všichni čtenáři Delphi.cz (a není jich málo).