Ody Light
Ody Light

Reputation: 57

How to fill TListView with TJSONIterator.Next?

I have an app with a TListView and I want to populate data from JSON inside its Items by using TJSONIterator.Next(). The code I use displays the results I want, except for the first one.

How can I parse these JSON objects correctly, what am I doing wrong?

image

Data: Data.json

{
  "event":"subscribe-status",
  "status":"ok",
  "success":[
    {
      "symbol":"EUR/USD",
      "exchange":"PHYSICAL CURRENCY",
      "mic_code":"PHYSICAL CURRENCY",
      "country":"",
      "type":"Physical Currency"
    },
    {
      "symbol":"USD/JPY",
      "exchange":"PHYSICAL CURRENCY",
      "mic_code":"PHYSICAL CURRENCY",
      "country":"",
      "type":"Physical Currency"
    },
    {
      "symbol":"BTC/USD",
      "exchange":"Coinbase Pro",
      "mic_code":"Coinbase Pro",
      "country":"",
      "type":"Digital Currency"
    },
    {
      "symbol":"ETH/BTC",
      "exchange":"Huobi",
      "mic_code":"Huobi",
      "country":"",
      "type":"Digital Currency"
    }
  ],
  "fails":null
}

Code app:

LStringReader := TStreamReader.Create('../../Data.json', TEncoding.UTF8, True);
LJsonTextReader := TJsonTextReader.Create(LStringReader);
LIterator := TJSONIterator.Create(LJsonTextReader);
NObjJSON := LIterator.AsInteger;
    
ListView1.Items.Clear;
ListView1.BeginUpdate;
try
  while True do
  begin
    while LIterator.Next do
    begin
      if LIterator.&Type in [TJsonToken.StartObject, TJsonToken.StartArray] then
      begin
        LIterator.Recurse;
        LIterator.Next;
        oItem := ListView1.Items.Add;
        for NObjJSON := 0 to ListView1.ItemCount -1 do
        begin
          oItem.Text := 'Object #' + NObjJSON.ToString + ' ' + LIterator.AsValue.ToString;
          oItem.Detail := 'Key:' +LIterator.Key;
        end
      end;
    end;
    if LIterator.InRecurse then
      LIterator.Return
    else
      Break;
  end;
finally
  ListView1.EndUpdate;
  LIterator.Free;
  LJsonTextReader.Free;
  lStringReader.Free;
  Memo1.Lines.Text := NObjJSON.ToString;
end;

Upvotes: 3

Views: 258

Answers (2)

Ody Light
Ody Light

Reputation: 57

After all, i found the correct solution:*

var
  LIterator: TJSONIterator;
  LJsonTextReader: TJsonTextReader;
  LStringReader: TStreamReader;
  NObjJSON: Integer;
begin
  LStringReader := TStreamReader.Create('../../Data.json', TEncoding.UTF8, True);
  LJsonTextReader := TJsonTextReader.Create(LStringReader);
  LIterator := TJSONIterator.Create(LJsonTextReader);
  NObjJSON := LIterator.AsInteger;

  ListView1.Items.Clear;
  ListView1.BeginUpdate;
  try
    while True do
    begin
      while LIterator.Next do
      begin
        if LIterator.&Type in [TJsonToken.StartObject, TJsonToken.StartArray] then
        begin
          Memo1.Lines.Add(LIterator.Key);
          LIterator.Recurse;
        end
        else if LIterator.Path = 'success['+NObjJSON.ToString+'].symbol' then
        begin
            Memo1.Lines.Add(LIterator.AsValue.ToString);
            oItem := ListView1.Items.Add;
            for NObjJSON := 0 to ListView1.ItemCount -1 do
              oItem.Text := 'Object #' + NObjJSON.ToString + ' ' + LIterator.AsValue.ToString;
        end
      end;
      if LIterator.InRecurse then
        LIterator.Return
      else
        Break;
    end;
  finally
    ListView1.EndUpdate;
    LIterator.Free;
    LJsonTextReader.Free;
    LStringReader.Free;
  end;
end;

enter image description here enter image description here

NObjJSON is used to count the number of objects inside array and it returns 4. You can use a simple integer (I) and replace "for NObjJSON := 0 to ListView1.ItemCount -1 do" by for I := 0 to ListView1.ItemCount -1 do but the number of objects will return 0.

Upvotes: 0

Haifisch
Haifisch

Reputation: 909

Add this recurse / next at beginning of your loop to prepare to enter array :

while LIterator.Next do
begin
  if LIterator.&Type = TJsonToken.StartArray then
  begin
    LIterator.Recurse;
    LIterator.Next;
  end;

You can check this exemple in the doc : https://docwiki.embarcadero.com/CodeExamples/Sydney/en/RTL.JSONIterator

The code below is easier to read :

procedure TFormX.LoadJSON;
const
  cValue = 'symbol';
var
  LValue: TJSONValue;
  LArray: TJSONArray;
  i: integer;
  oItem: TListViewItem;
begin
  LValue := TJSONObject.ParseJSONValue('{json}');

  LArray := LValue.FindValue('success') as TJSONArray;

  if Assigned(LArray) then
  begin
    for i := 0 to LArray.Count - 1 do
    begin
      oItem := ListView1.Items.Add;

      oItem.Text := 'Object #' + i.ToString + ' ' + LArray.Items[i].GetValue<string>(cValue);
      oItem.Detail := 'Key:' + cValue;
    end;
  end;
end;

Upvotes: 3

Related Questions