Delphi: доступ к объектам JSON в массиве JSON

У меня есть объект JSON, назовем его jObject, который выглядит так:

{
  "id": 0,
  "data": "[{DAT_INCL: \"08/03/2012 10:07:08\", NUM_ORDE: 1, NUM_ATND: 1, NUM_ACAO: 2, NUM_RESU: 3},
            {DAT_INCL: \"08/03/2012 10:07:09\", NUM_ORDE: 2, NUM_ATND: 1, NUM_ACAO: 4, NUM_RESU: 5},
            {DAT_INCL: \"08/03/2012 10:07:09\", NUM_ORDE: 3, NUM_ATND: 1, NUM_ACAO: 8, NUM_RESU: NULL}]"
}

Как вы можете видеть, он содержит две пары, одна из которых представляет собой массив с тремя объектами в этом случае (количество объектов является динамическим) с несколькими «ключ: значения» (они не меняются, это всегда одни и те же 5 полей ), которую я хочу вставить в базу данных SQL, где «ключ» — столбец, «значение» — поле. Вопрос в том, как мне получить доступ к каждому объекту по отдельности?

С точки зрения кода я извлек пару, содержащую этот массив, поместив ее в jPair.

jPair := OriginalObject.Get(1); 

а затем захватил массив

jArray:= TJSONArray(jPair.JsonValue);

(Кроме того, в качестве бонуса, когда я оцениваю jArray.Size, результат равен 6226004. Что?)


person bpromas    schedule 07.03.2012    source источник
comment
Я использую XE2 с DBXJSON и DBXJSONReflect.   -  person bpromas    schedule 08.03.2012
comment
Изначально у меня был другой JSONObject, поэтому в основном с точки зрения кода я извлек пару, содержащую этот массив, поместив ее в jPair (dtPair := OriginalObject.Get(1);), а затем захватил массив (jArray:= TJSONArray (jPair.JsonValue);) (Должен ли я поместить этот код в исходный пост?)   -  person bpromas    schedule 08.03.2012


Ответы (2)


Если у вас есть массив из DBXJSON, то это TJSONArray. Вызовите его метод Get, чтобы получить элемент массива.

var
  Value: TJSONValue;

Value := jArray.Get(0);

Вы также можете пройтись по всему массиву с помощью цикла for:

for Value in jArray do

Но если вы проверите свойство Size и получите 6226004 вместо 3, это говорит о том, что здесь что-то еще не так. Я предполагаю, что то, что вы считаете TJSONArray, на самом деле не является таким типом. Используйте as для приведения проверенного типа:

jArray := jPair.JsonValue as TJSONArray;

Вы получите исключение EInvalidCast, если это не удастся.

person Rob Kennedy    schedule 07.03.2012
comment
Действительно, я получил исключение EInvalidCast. Означает ли это, что массив, который у меня есть в моем JsonObject, на самом деле не является массивом? Работа с JSON становится все более и более тяжелой битвой. - person bpromas; 08.03.2012
comment
Это означает, что это не TJSONArray. Отладчик должен быть в состоянии сказать вам, что это такое на самом деле. Если отладчик не сообщает об этом во всплывающей подсказке, отобразите результат вызова jPair.JsonValue.ClassName. - person Rob Kennedy; 08.03.2012
comment
Да, это TJSONString, причем плохо отформатированная. Как, черт возьми, я собираюсь разобрать это? - person bpromas; 08.03.2012
comment
Похоже, это строка, содержащая дополнительные данные JSON. Анализируйте его так же, как вы анализируете другие строки данных в формате JSON. А потом пожаловаться человеку, ответственному за генерацию этих данных, потому что они закодированы дважды. - person Rob Kennedy; 08.03.2012
comment
Я смог извлечь его в JsonString, и он содержит мой JsonArray. Я не могу понять, как удалить JSONArray из JSONString, поэтому я мог бы побеспокоить вас еще немного. - person bpromas; 08.03.2012
comment
Я не понимаю, какая у вас еще проблема. Вы можете создать объект JSON из строки так же, как всегда. Используйте 1_. Назовите это в своей строке: jArray := TJSONObject.ParseJSONValue((jPair.JsonValue as TJSONString).Value) as TJSONArray. - person Rob Kennedy; 08.03.2012
comment
TJSONObject.ParseJSONValue((jPair.JsonValue as TJSONString).Value), похоже, возвращает ноль. - person bpromas; 08.03.2012

вот пример кода для анализа и вывода ваших данных json. Я изменил ваши данные JSON и добавил поле ArrayData, которое содержит ваш исходный массив объектов:

program Project1;
{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils, dbxjson;

const JSON_DATA = '{"ArrayData":['+
                    '{"DAT_INCL":"07/03/2012 17:33:03", "NUM_ORDE":1,"NUM_ATND":1, "NUM_ACAO":2, "NUM_RESU":3},'+
                    '{"DAT_INCL":"07/03/2012 17:33:05", "NUM_ORDE":2,"NUM_ATND":1, "NUM_ACAO":4, "NUM_RESU":5},'+
                    '{"DAT_INCL":"07/03/2012 17:33:05", "NUM_ORDE":3,"NUM_ATND":1, "NUM_ACAO":8, "NUM_RESU":null}'+
                   ']}';


var jsv   : TJsonValue;
    originalObject : TJsonObject;

    jsPair : TJsonPair;
    jsArr : TJsonArray;
    jso  : TJsonObject;
    i : integer;
begin
    try
        //parse json string
        jsv := TJSONObject.ParseJSONValue(JSON_DATA);
        try
            //value as object
            originalObject := jsv as TJsonObject;

            //get pair, wich contains Array of objects
            jspair := originalObject.Get('ArrayData');
            //pair value as array
            jsArr := jsPair.jsonValue as  TJsonArray;

            writeln('array size: ', jsArr.Size);
            //enumerate objects in array
            for i := 0 to jsArr.Size - 1 do begin
                writeln('element ', i);
                // i-th object
                jso := jsArr.Get(i) as TJsonObject;

                //enumerate object fields
                for jsPair in jso do begin
                    writeln('   ', jsPair.JsonString.Value, ': ', jsPair.JsonValue.Value);
                end;
            end;
        finally
            jsv.Free();
            readln;
        end;
    except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
    end;
end.
person teran    schedule 08.03.2012
comment
Спасибо за ваш пример, он мне помог. Однако вместо того, чтобы перебирать размер массива, вы можете for jsValue in jsArr do begin jsObj := jsValue as TJSONObject; просто для меня это выглядит намного чище. - person RobbZ; 04.11.2019