Jak v Delphi pracovat s JSON

24. 9. 2019, Vladimír Klaus, přečteno 61x

Delphi

Při získávání dat z webů nebo webových služeb můžete často volit mezi XML nebo JSON. Díky velmi pěkné implementaci JSON v Delphi je možné data získávat pohodlně. Navíc zápis je velmi příjemný a pokud víte, co a kde hledáte, pak se k údaji dostanete opravdu velmi rychle.

Mějme například takovýto JSON text. Je to reálný příklad, protože přesně toto dostanete ze služeb Google Maps Platform, jako jsou Directions, Distance Matrix apod.

{
   "destination_addresses" : [ "Jičíněves, Czechia" ],
   "origin_addresses" : [ "Terezínská 701/4, 190 00 Praha-Letňany, Czechia" ],
   "rows" : [
      {
         "elements" : [
            {
               "distance" : {
                  "text" : "85.5 km",
                  "value" : 85467
               },
               "duration" : {
                  "text" : "1 hour 30 mins",
                  "value" : 5427
               },
               "status" : "OK"
            }
         ]
      }
   ],
   "status" : "OK"
}

Předpokládejme (pro jednoduchost), že potřebujete pouze zjistit vzdálenost. Z výše uvedeného víte jak přesně JSON soubor (obecně text) vypadá a že tedy můžete jít na jisto. Samozřejmě je vhodné vše před přístupem ověřovat, protože si nemůžete být nikdy jisti, že formát a hodnoty budou vypadat přesně tak, jako v době, kdy to programujete.

Obrovskou výhodou tohoto jednoduchého příkladu je přímý přístup k daným datům pomocí tečkové notace.

uses JSON;

procedure ZpracujJsonDistanceMatrix(aJsonText: string);
var
  jv, jv2: TJSONValue;
  s: string;
  r: double;

begin
  //jv je vlastně root celého JSONu
  jv:=TJSONObject.ParseJSONValue(aJsonText);
  try
    if jv<>nil then begin
      jv2:=jv.FindValue('status'); //v rootu, ne někde zanořený
      if jv2<>nil then begin
        s:=jv2.Value;
        if s='OK' then begin
          //z rootu hledám přesně tuto cestu
          jv2:=jv.FindValue('rows[0].elements[0].distance.text');
          if jv2<>nil then begin
            s:=jv2.Value;
            s:=StringReplace(s, 'km', '', [rfIgnoreCase]);
            s:=StringReplace(s, '.', ',', []);
            //získám vzdálenost v kilometrech a jako reálné číslo
            if TryStrToFloat(s, r) then . . .  
          end;
        end;
      end;
    end;

  finally
    FreeAndNil(jv);
  end;
end;

Pokud by JSON obsahoval více údajů, pak se už musí pracovat s poli (TJSONArray) a vše je nepatrně složitější.

procedure ZpracujJsonDirections(aJsonText: string);
var
  jv, jv2, jv3: TJSONValue;
  jarr: TJSONArray;
  s: string;
  r: double;
  i: integer;

begin
  jv:=TJSONObject.ParseJSONValue(aJsonText);
  try
    if jv<>nil then begin
      jv2:=jv.FindValue('status');
      if jv2<>nil then begin
        s:=jv2.Value;
        if s='OK' then begin
          //z rootu hledám sadu cest
          jarr:=jv.FindValue('routes') as TJSONArray;
          if jarr<>nil then begin
            for i:=0 to jarr.Count-1 do begin
              jv3:=jarr.Items[i].FindValue('legs[0].distance.text');
              if jv3<>nil then begin
                s:=jv3.Value;
                s:=StringReplace(s, 'km', '', [rfIgnoreCase]);
                s:=StringReplace(s, '.', ',', []);
                if TryStrToFloat(s, r) then . . .
              end;
            end;
          end;
        end;
      end;
    end;

  finally
    FreeAndNil(jv);
  end;
end;

Zdroje: