Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 Получить подчинённый узел в JSON  [new]
X11
Member

Откуда: Kharkiv, Ukraine
Сообщений: 13352
Напишу сразу, чтобы не было флуда, использую стандартный TJSONObject. Просьба не тратить время на написание примеров, советов для других библиотек. Ну т.е. тот JSONObject использую, что идёт искаропки в Delphi Tokyo.
Да, я знаю, что в других библиотеках может быть проще. А может быть и в стандартной так можно, как я хочу.

Итак. Есть JSON строка, как на картинке для наглядности.
На данный момент, у меня получается говнокод, который сперва получаю TJsonValue, потом TJSONObject для всей строки, т.е. общий JSON-объект, потом всякие проверки. Затем то же самое узла "result", потом всякие проверки. Потом то же самое нужно сделать для узла "ad_parameters" ну и дальше уже цикл по массиву. Могу показать, но страшно )))

А нельзя ли это всё превратить в одну строку типа

const 
 sJSON = 'здесь JSON-строка';
var
 JSONParamsVal: TJSONValue;
 JSONArray: TJSONArray;
begin
  JSONParamsVal := TJSONObject.ParseJSONValue(sJSON).Get('result').Get('ad_parameters');

  if JSONParamsVal is TJSONArray then
    JSONArray := TJSONArray(JSONParamsVal);

...
...


К сообщению приложен файл. Размер - 10Kb
6 авг 19, 13:17    [21942864]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
ёёёёё
Member

Откуда:
Сообщений: 1295
X11,

сразу же советую переходить на superobject, дальше все одной строкой делается.
6 авг 19, 13:58    [21942938]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11257
var
  LStr: string;
  LVal: TJSONValue;
  LData: TJSONArray;
begin
  LStr := '{"result":{"ad_parameters": [1, 2, 3]}}';
  LVal := TJSONObject.ParseJSONValue(LStr, True, True);
  try
    LData := LVal.GetValue<TJSONArray>('result.ad_parameters');
  finally
    LVal.Free;
  end;
end;
6 авг 19, 15:50    [21943051]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
X11
Member

Откуда: Kharkiv, Ukraine
Сообщений: 13352
_Vasilisk_, Картинка с другого сайта. просто супер. Спасиб!
6 авг 19, 16:18    [21943081]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
X11
Member

Откуда: Kharkiv, Ukraine
Сообщений: 13352
Странно, что я никогда в примерах и справках не видел, что так реально можно.Картинка с другого сайта.
6 авг 19, 16:24    [21943083]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11257
X11
Странно, что я никогда в примерах и справках не видел, что так реально можно.Картинка с другого сайта.
Я тоже. Но я исходил из теории, что так можно. Открыл исходники и посмотрел. Зацепился за имя параметра APath у GetValue. Прочитал в хелпе его формат
6 авг 19, 16:46    [21943103]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
X11
Member

Откуда: Kharkiv, Ukraine
Сообщений: 13352
Что не так?
 LData: TJSONArray;
 JSONPair: TJSONPair;
begin

  for JSONPair in LData do


Incompatible types: 'TJSONPair' and 'TJSONValue'


Как правильно сделать цикл по TJSONArray?
7 авг 19, 11:50    [21943608]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
X11
Member

Откуда: Kharkiv, Ukraine
Сообщений: 13352
Нужно объявить JSONPair как TJSONValue
7 авг 19, 11:56    [21943620]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
s62
Member

Откуда: Жуковский
Сообщений: 1010
X11,
Дерево и его узлы - это в XML. В JSON (JavaScript Object Notation) - объекты и их свойства, массивы и их элементы. В том числе, само собой - вложенные объекты. Мне кажется, если это понимать, то какие-то вопросы решаются. Объект состояит из пар - имя-значение.
JSON
Объект - неупорядоченный набор пар ключ/значение. Объект начинается с {открывающей фигурной скобки и заканчивается }закрывающей фигурной скобкой.

https://www.json.org/json-ru.html
Массив - из элементов.
JSON
Массив - упорядоченная коллекция значений. Массив начинается с [открывающей квадратной скобки и заканчивается ]закрывающей квадратной скобкой.

Чем является этот элемент массива или значение пары в объекте - объектом, массивом или чем-то еще - это уже другое дело.
Исходя из этого, получается и ответ на ваш вопрос.
7 авг 19, 13:14    [21943746]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
s62
Member

Откуда: Жуковский
Сообщений: 1010
s62,
я написал, что массив состоит из элементов, для вопроса "Как правильно сделать цикл по TJSONArray? " важней наверное, что каждый элемент это значение (а не пара), как написано в процитированном мной определении с сайта JSON.
7 авг 19, 13:22    [21943749]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
X11
Member

Откуда: Kharkiv, Ukraine
Сообщений: 13352
значения

К сообщению приложен файл. Размер - 6Kb
7 авг 19, 13:30    [21943760]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
X11
Member

Откуда: Kharkiv, Ukraine
Сообщений: 13352
А почему Delphi не разрешает проверить тип?
Var
 LVal, JSONPair: TJSONValue;
 LData, lData2: TJSONArray;
begin

  if JSONPair is TJSONPair then
    result := TJSONPair(JSONPair).JsonString.Value;


Incompatible types: 'TJSONValue' and 'TJSONPair'
7 авг 19, 15:04    [21943856]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
Cobalt747
Member

Откуда:
Сообщений: 2128
X11
А почему Delphi не разрешает проверить тип?
Incompatible types: 'TJSONValue' and 'TJSONPair'
Эти классы не являются потомками один другого. и значит заведомо не могут быть совместимы.
можно TObject проверять на любой класс, ибо он предок для всех.
аналогично как с
var
 q: TList;
begin
  if q is TStringList then

объявляй JSONPair как предок обоих классов, т.е. TJSONAncestor
7 авг 19, 16:06    [21943936]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
s62
Member

Откуда: Жуковский
Сообщений: 1010
X11
значения

Картинка с другого сайта.
Правильно, как я и написал, каждый элемент массива является значением, а не парой имя:значение. Поэтому и нужно
 LData: TJSONArray;
 JSONValue: TJSONValue;
begin

  for JSONValue in LData do

а не использовать TJSONPair, как было сначала у вас. А вот это значение уже в свою очередь может быть числом, строкой, true, false, null, объектом или массивом. В вашем случае по этой схеме мне не совсем понятно, то ли объекты, то ли массивы.
7 авг 19, 18:26    [21944075]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
X11
Member

Откуда: Kharkiv, Ukraine
Сообщений: 13352
_Vasilisk_, а можно как-то добраться таким описанным тобою способом до элемента "p" и получить его значение?
Или только полным перебором всех элементов?

К сообщению приложен файл. Размер - 6Kb
8 авг 19, 11:35    [21944501]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
X11
Member

Откуда: Kharkiv, Ukraine
Сообщений: 13352
Можно ли этого монстра упростить/оптимизировать или всё правильно?

Задача: получить значение элемента "vl", но только если значение элемента "p" соответствует какому-то определённому значению, в данном случае "area". У других элементов этого списка (ad_parameters) - другие значения. Грубо говоря, нужно найти город.


Function GetADParamFromRendered(const sJSON, path, param_name: string): string;
Var
 LVal, JSONPair: TJSONValue;
 ad_param: TJSONObject;
 LData: TJSONArray;
 i: integer;
begin

  LVal := TJSONObject.ParseJSONValue(sJSON);
  try
    LData := LVal.GetValue<TJSONArray>(path);// 'result.ad_parameters'

    if LData is TJSONArray then
    begin
      for JSONPair in LData do
      begin
        if JSONPair is TJSONObject then
        begin

          ad_param := JSONPair as TJSONObject;// pl, vl, p или v

          for i := 0 to pred(ad_param.Count) do
          begin
            // получаем значение пары "vl"
            if ad_param.Pairs[i].JsonString.Value = 'vl' then
              result := ad_param.Pairs[i].JsonValue.Value;

            // если пара с именем "p" имеет искомое значение param_name, то и значение элемента "vl" правильное
            if (ad_param.Pairs[i].JsonString.Value = 'p') and
               (ad_param.Pairs[i].JsonValue.Value = param_name) // нашли нужный элемент category или region
            then
              exit;// нашли, в result будет нужное значение

          end;//for 
        end;// if 
      end;// for
    end;// if

  finally
    LVal.Free;
  end;

end;


К сообщению приложен файл. Размер - 7Kb
8 авг 19, 11:52    [21944524]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
X11
Member

Откуда: Kharkiv, Ukraine
Сообщений: 13352
количество элементов в массиве ad_parameters может быть разное и неизвестно заранее, в каком индексе живёт тот или иной элемент.
8 авг 19, 11:56    [21944529]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
Василий 2
Member

Откуда:
Сообщений: 799
проверки не заворачивать во вложенные блоки, а делать Exit после негативного результата.
А зачем перебор параметров, если они у тебя четко определенные?
if JSONPair.Get('p') = param_value then Exit(JSONPair.Get('v1'))


Ну а в целом нужно что-то вроде xpath, наверняка можно добавить функцию с поиском через хелперы, чтобы писать так
Get('result.ad_parameters').Find('[].p='+param_value).Get('v1')
8 авг 19, 15:05    [21944859]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
X11
Member

Откуда: Kharkiv, Ukraine
Сообщений: 13352
Василий 2
А зачем перебор параметров, если они у тебя четко определенные?


спасибо
9 авг 19, 08:51    [21945298]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
X11
Member

Откуда: Kharkiv, Ukraine
Сообщений: 13352
Но у JSONPair отсутствует метод Get
9 авг 19, 11:45    [21945457]     Ответить | Цитировать Сообщить модератору
 Re: Получить подчинённый узел в JSON  [new]
X11
Member

Откуда: Kharkiv, Ukraine
Сообщений: 13352
В общем, сократил до
Function GetADParamFromRendered(const sJSON, path, p_param_name: string): string;
Var
 LVal, JSONPair: TJSONValue;
 ad_param: TJSONObject;
 LData: TJSONArray;
 i: integer;
 s, v: string;
begin

  LVal := TJSONObject.ParseJSONValue(sJSON);
  try
    LData := LVal.GetValue<TJSONArray>(path);// 'result.ad_parameters'

    if LData is TJSONArray then
    begin
      for JSONPair in LData do
      begin
        if JSONPair is TJSONObject then
        begin
          ad_param := JSONPair as TJSONObject;

          if JSONPair.GetValue<TJSONString>('p').Value = p_param_name then
            exit(JSONPair.GetValue<TJSONString>('vl').Value);

        end;// if
      end;// for
    end;// if

  finally
    LVal.Free;
  end;

end;


ещё раз спасибо
9 авг 19, 11:57    [21945467]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить