Delphi.cz

Český portál Delphi

Základy JSON v Delphi

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).

Datum: 2010-10-19 22:34:00 Tagy: JSON, komponenty

Praxe