Как заполнить TListView с помощью TJSONIterator.Next?

У меня есть приложение с TListView, и я хочу заполнить данные из JSON внутри его Items с помощью TJSONIterator.Next(). Код, который я использую, отображает нужные мне результаты, за исключением первого.

Как я могу правильно разобрать эти объекты JSON, что я делаю неправильно?

Данные: 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
}

Код приложения:

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;
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
110
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Добавьте этот recurse/next в начале цикла, чтобы подготовиться к вводу массива:

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

Вы можете проверить этот пример в документе: https://docwiki.embarcadero.com/CodeExamples/Sydney/en/RTL.JSONIterator

Код ниже легче читать:

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;

Использование TJSONObject проще, да! Но вопрос про TJSONIterator.

Ody Light 01.01.2023 20:21

Вот почему я сначала ответил TJSONIterator

Bosshoss 01.01.2023 21:05

Извините за долгую задержку, @Bosshoss, я пытался, у меня не работает, может быть, я что-то пропустил!

Ody Light 06.01.2023 11:27

Да, я думаю, ты что-то пропустил

Bosshoss 06.01.2023 11:32
Ответ принят как подходящий

Ведь я нашел правильное решение:*

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 используется для подсчета количества объектов внутри массива и возвращает 4. Вы можете использовать простое целое число (I) и заменить «для NObjJSON := 0 на ListView1.ItemCount -1 do» на for I := 0 to ListView1.ItemCount -1 do, но количество объектов вернет 0.

Другие вопросы по теме

Похожие вопросы

Как условно отформатировать поле ReportBuilder в полосе «Подробности» в зависимости от других полей в полосе «Подробности»?
Хранение файлов в таблице SQL Server (столбец varbinary(max)) с использованием компонента ADOQuery
Почему я получаю нарушение прав доступа при создании формы внутри класса, если экземпляр класса не является переменной, определенной в вызывающей процедуре
Вызов функции x64 DLL в Delphi
Delphi Generics: можно ли использовать типы массивов в качестве ограничений типов?
Приложение Delphi FMX для Mac не подключается к Интернету, если оно настроено для «Магазина приложений» с использованием Indy
Получить следующий результат поиска с помощью сочетания клавиш
Delphi: операция [int] в [массиве] не работает
Delphi, когда загружается модуль данных, мне нравится предотвращать подключение TFDConnector, если я по ошибке установил активацию true
Как сделать тест с анонимом в Delphi и TestInsight?