Delphi JSON parser

delphi

My current code:

procedure TForm1.Button10Click(Sender: TObject);
var
  IdHTTP: TIdHTTP;
  IdSSL: TIdSSLIOHandlerSocketOpenSSL;
  JSON: string;
  jsonObiekt: TJSONObject;
  streams: TJSONValue;
  liczbaStrumieni: integer;
  i: integer;
begin
  IdHTTP := TIdHTTP.Create;
  try
    IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
    IdHTTP.IOHandler := IdSSL;
    IdHTTP.Request.CustomHeaders.AddValue('Accept', 'application/vnd.twitchtv.v3+json');
    IdHTTP.Request.CustomHeaders.AddValue('Client-ID', 'smb61nyd0vxmqdn9d3k735qbx41cdyg');
    JSON := IdHTTP.Get('https://api.twitch.tv/kraken/streams?game=StarCraft:%20Brood%20War');
  finally
    IdHTTP.Free;
  end;
  jsonObiekt := nil;
  try
    jsonObiekt := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(JSON), 0) as TJSONObject;
    streams := jsonObiekt.Get('streams').JsonValue;
    liczbaStrumieni := TJSONArray(streams).Size;
    for i := 0 to liczbaStrumieni - 1 do
    begin
      Memo6.Lines.Add(TJSONObject(TJSONArray(streams).Get(i)).Get('viewers').JsonValue.Value);
    end;
  finally
    jsonObiekt.Free;
  end;
end;

With this code i am able to get viewers for every entries in "streams"
enter image description here

My goal is to get "status" from "channel", but thats too hard for me. Tried learn from this How to parse nested JSON object in Delphi XE2? but no result, still dont understand it well. Thanks for help.

Best Solution

It helps to break up the subobjects into their own variables, don't try to do everything in a single statement. Try this:

procedure TForm1.Button10Click(Sender: TObject);
var
  IdHTTP: TIdHTTP;
  IdSSL: TIdSSLIOHandlerSocketOpenSSL;
  JSON: string;
  jsonObiekt: TJSONObject;
  streams: TJSONArray;
  stream: TJSONObject;
  channel: TJSONObject;
  status: TJSONString;
  liczbaStrumieni: integer;
  i: integer;
begin
  IdHTTP := TIdHTTP.Create;
  try
    IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
    IdHTTP.IOHandler := IdSSL;
    IdHTTP.Request.Accept := 'application/vnd.twitchtv.v3+json';
    IdHTTP.Request.CustomHeaders.AddValue('Client-ID', 'smb61nyd0vxmqdn9d3k735qbx41cdyg');
    JSON := IdHTTP.Get('https://api.twitch.tv/kraken/streams?game=StarCraft:%20Brood%20War');
  finally
    IdHTTP.Free;
  end;
  jsonObiekt := TJSONObject.ParseJSONValue(JSON) as TJSONObject;
  try
    streams := jsonObiekt.Get('streams').JsonValue as TJSONArray;
    liczbaStrumieni := streams.Size;
    for i := 0 to liczbaStrumieni - 1 do
    begin
      stream := streams.Get(i) as TJSONObject;
      channel := stream.Get('channel').JsonValue as TJSONObject;
      status := channel.Get('status').JsonValue as TJSONString;
      Memo6.Lines.Add(status.Value);
    end;
  finally
    jsonObiekt.Free;
  end;
end;

Alternatively, download the JSON as bytes so TIdHTTP will not decode them to UTF-16, and thus TJSONObject can parse the original bytes as-is:

procedure TForm1.Button10Click(Sender: TObject);
var
  IdHTTP: TIdHTTP;
  IdSSL: TIdSSLIOHandlerSocketOpenSSL;
  JSON: TBytesStream;
  jsonObiekt: TJSONObject;
  streams: TJSONArray;
  stream: TJSONObject;
  channel: TJSONObject;
  status: TJSONString;
  liczbaStrumieni: integer;
  i: integer;
begin
  jsonObiekt := nil;
  try
    JSON := TBytesStream.Create;
    try
      IdHTTP := TIdHTTP.Create;
      try
        IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
        IdHTTP.IOHandler := IdSSL;
        IdHTTP.Request.Accept := 'application/vnd.twitchtv.v3+json';
        IdHTTP.Request.CustomHeaders.AddValue('Client-ID', 'smb61nyd0vxmqdn9d3k735qbx41cdyg');
        IdHTTP.Get('https://api.twitch.tv/kraken/streams?game=StarCraft:%20Brood%20War', JSON);
      finally
        IdHTTP.Free;
      end;
      jsonObiekt := TJSONObject.ParseJSONValue(JSON.Bytes, 0, JSON.Size) as TJSONObject;
    finally
      JSON.Free;
    end;
    streams := jsonObiekt.Get('streams').JsonValue as TJSONArray;
    liczbaStrumieni := streams.Size;
    for i := 0 to liczbaStrumieni - 1 do
    begin
      stream := streams.Get(i) as TJSONObject;
      channel := stream.Get('channel').JsonValue as TJSONObject;
      status := channel.Get('status').JsonValue as TJSONString;
      Memo6.Lines.Add(status.Value);
   end;
  finally
    jsonObiekt.Free;
  end;
end;
Related Question