Reputation: 57
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?
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
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;
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
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