Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Паскаль, Turbo Pascal, PascalABC.NET
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 26.07.2021, 14:42   #1
blackspaceghost
Новичок
Джуниор
 
Регистрация: 26.07.2021
Сообщений: 5
По умолчанию Как распарсить вложенный объект в JSON

Всем доброго времени суток, форумчане.Суть задачи состоит в сравнении пар ключ-значения 2-х JSON'ов. Подзадача: Пытаюсь распарсить JSON, в котором в значении ключа хранится вложенный объект. Делаю на примере данной статьи: https://webdelphi.ru/2020/05/rabota-...s-free-pascal/. Все бы хорошо, только вот AsString у меня не работает и вызывает исключение типа: EJSON с сообщением "Cannot convert data from object value", хотя не понимаю, почему не работает, ведь тип Value есть TJSONData, и AsString как раз и предназначен для того, чтобы перевести этот тип в строку. Вот, собственно, код: (на логику while'ов пока можете не обращать внимания, всё довольно сыро и меня беспокоит проблема сабжа непосредственно). Надеюсь на вашу помощь.
Код:
program Project1;
 
{$mode objfpc}{$H+}
 
uses
 {$IFDEF UNIX}
  cthreads,
    {$ENDIF}
  Classes,
  SysUtils,
  CustApp { you can add units after this } ,
  jsonscanner,
  fpjson,
  jsonparser;
 
type
 
  { TMyTimeTest }
 
  TMyTimeTest = class(TCustomApplication)
  private
    fFileData: string;
  protected
    procedure DoRun; override;
  public
    str1, str2, buf: string;
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
    procedure WriteHelp; virtual;
    procedure SetFileData(path: string);
    procedure ParseMyStr;
  end;
 
  { TMyTimeTest }
  procedure TMyTimeTest.SetFileData(path: string);
  var
    Strm : TFileStream;
    n: longint;
  begin
    try
       Strm := TFileStream.Create(path,fmOpenRead);
       n := Strm.size;
       SetLength(fFileData, n);
       Strm.read(fFileData[1], n);
       if str1 = '' then
          str1 := fFileData
       else if str2 = '' then
          str2 := fFileData;
    finally
      Strm.free;
    end;
  end;
 
  procedure TMyTimeTest.ParseMyStr;
  var
     JsonParser1, JsonParser2, JsonNestParser1, JsonNestParser2: TJSONParser;
     JsonObject1, JsonObject2, JsonNestedObject1, JsonNestedObject2: TJSONObject;
     JsonEnum1, JsonEnum2, JsonEnumNested1, JsonEnumNested2: TBaseJSONEnumerator;
     test: string;
  begin
     JsonParser1 := TJSONParser.Create(str1, DefaultOptions);
     JsonParser2 := TJSONParser.Create(str2, DefaultOptions);
  try
    JsonObject1 := JsonParser1.Parse as TJSONObject;
    JsonObject2 := JsonParser2.Parse as TJSONObject;
    try
      JsonEnum1 := JsonObject1.GetEnumerator;//получаем перечислитель пар
      JsonEnum2 := JsonObject2.GetEnumerator;//получаем перечислитель пар
      try
        //проходим по каждой паре в объекте
        while JsonEnum1.MoveNext do
        begin
          while JsonEnum2.MoveNext do
          begin
            if JsonEnum1.Current.Value.ToString = 'TJSONObject' then
               begin
                 JsonNestParser1 := TJSONParser.Create(JsonEnum1.Current.Value.AsString, DefaultOptions);
               end;
            if JsonEnum1.Current.Key = JsonEnum2.Current.Key then
            begin
               // что-то происходит, а именно запись значения во 2-ой JSON
               Break;
            end;
          end;
        end;
      finally
        FreeAndNil(JsonEnum1);
        FreeAndNil(JsonEnum2);
      end;
    finally
      FreeAndNil(JsonObject1);
      FreeAndNil(JsonObject2);
    end;
  finally
    FreeAndNil(JsonParser1);
    FreeAndNil(JsonParser2);
  end;
  end;
А вот, собственно, JSON:
Код:
{
    "host":{
        "wired": "192.168.1.1",
        "usb_wifi": "192.168.1.2"
        },
    "port": {
        "wired": 20002,
        "usb_wifi": 20003
        },
 
    "writedebug": True,
    "writecriticalsection": True
}
До значений ключа-объекта получилось добраться таким способом:
Код:
if JSONObject1.Types[JsonEnum1.Current.Key] = jtObject then
               begin
               for i:=0 to (TJSONObject(JSONEnum1.Current.Value).Count)-1 do
                 begin
                 test := test + (TJSONObject(JSONEnum1.Current.Value).Items[i].AsString);
А вот до непосредственно ключа добраться не могу, почему-то. Через тот же Key вместо Value получить доступ не удаётся: вылетает исключение доступа к памяти: General protection fault. Товарищи старожилы, есть идеи как получить доступ к Key объекта ключа?
blackspaceghost вне форума Ответить с цитированием
Старый 27.07.2021, 10:19   #2
blackspaceghost
Новичок
Джуниор
 
Регистрация: 26.07.2021
Сообщений: 5
По умолчанию

Разобрался. Можно закрывать. Если кого интересует - скину код решения
blackspaceghost вне форума Ответить с цитированием
Старый 27.07.2021, 11:15   #3
Arigato
Высокая репутация
СуперМодератор
 
Аватар для Arigato
 
Регистрация: 27.07.2008
Сообщений: 16,219
По умолчанию

Цитата:
Сообщение от blackspaceghost Посмотреть сообщение
Если кого интересует - скину код решения
Ну скиньте, вдруг кому пригодится...
Arigato на форуме Ответить с цитированием
Старый 28.07.2021, 17:41   #4
blackspaceghost
Новичок
Джуниор
 
Регистрация: 26.07.2021
Сообщений: 5
По умолчанию

Код:
procedure TMyTimeTest.ParseAndSet;
  var
    JSONParser1, JSONParser2: TJSONParser;
    JSONObject1, JSONObject2, JNestObject1, JNestObject2:  TJSONObject;
    JSONEnum1, JSONEnum2, JSONNestEnum1, JSONNestEnum2: TBaseJSONEnumerator;
  begin
    JSONParser1 := TJSONParser.Create(str1, DefaultOptions);
    JSONParser2 := TJSONParser.Create(str2, DefaultOptions);
    try
      JSONObject1 := JSONParser1.Parse as TJSONObject;
      JSONObject2 := JSONParser2.Parse as TJSONObject;
      try
        JSONEnum1 := JSONObject1.GetEnumerator;//получаем перечислитель пар
        JSONEnum2 := JSONObject2.GetEnumerator;//получаем перечислитель пар

        try
          //проходим по каждой паре в объекте
          while JSONEnum1.MoveNext do
            while JSONEnum2.MoveNext do
              begin
                if JSONEnum1.Current.Value.JSONType = jtObject then //Если тип текущего значения ключа является объектом, тогда
                begin                                               //создаем два новых объекта для двух файлов соответственно, равных значениям объектов-значений ключа
                  JNestObject1 :=  JSONEnum1.Current.Value as TJSONObject;
                  JNestObject2 := JSONObject2.Find(JSONEnum1.Current.Key) as TJSONObject;
                  try
                    JSONNestEnum1 := JNestObject1.GetEnumerator;
                    JSONNestEnum2 := JNestObject2.GetEnumerator;
                    while JSONNestEnum1.MoveNext do
                      while JSONNestEnum2.MoveNext do
                      begin
                        if JSONNestEnum1.Current.Key = JSONNestEnum2.Current.Key then
                        begin
                          if (JSONNestEnum1.Current.Value.JSONType = jtString) then //если значение является строкой, тогда записываем как строку
                          begin
                            JNestObject2.Strings[JSONNestEnum1.Current.Key] := JSONNestEnum1.Current.Value.AsString; //если ключ первого объекта(JSON файла) соответствует ключу второго объекта(JSON файла),
                            Break;                                                                                   //то перезаписываем ключ второго объекта
                          end
                          else if JSONNestEnum1.Current.Value.JSONType = jtNumber then //если значение является целочисленным, тогда записываем как число
                          begin
                            JNestObject2.Integers[JSONNestEnum1.Current.Key] := JSONNestEnum1.Current.Value.AsInt64;
                            Break;
                          end
                          else if (JSONNestEnum1.Current.Value.JSONType = jtBoolean) then//если значения является булевым, тогда записываем как булево
                          begin
                            JNestObject2.Booleans[JSONNestEnum1.Current.Key] := JSONNestEnum1.Current.Value.AsBoolean;   //если ключ первого объекта(JSON файла) соответствует ключу второго объекта(JSON файла),
                            Break;
                          end;
                        end;
                        Break;
                      end;

                  finally
                     FreeAndNil(JSONNestEnum1);
                     FreeAndNil(JSONNestEnum2);
                  end;
                end
                else if JSONEnum1.Current.key = JSONEnum2.Current.Key then
                begin
                  if (JSONEnum1.Current.Value.JSONType = jtString) then //если значение является строкой, тогда записываем как строку
                  begin
                    JSONObject2.Strings[JSONEnum1.Current.Key] := JSONEnum1.Current.Value.AsString; //если ключ первого объекта(JSON файла) соответствует ключу второго объекта(JSON файла),
                    Break;                                                                                   //то перезаписываем ключ второго объекта
                  end
                  else if JSONEnum1.Current.Value.JSONType = jtNumber then //если значение является целочисленным, тогда записываем как число
                  begin
                    JSONObject2.Integers[JSONEnum1.Current.Key] := JSONEnum1.Current.Value.AsInt64;
                    Break;
                  end
                  else if (JSONEnum1.Current.Value.JSONType = jtBoolean) then//если значения является булевым, тогда записываем как булево
                  begin
                    JSONObject2.Booleans[JSONEnum1.Current.Key] := JSONEnum1.Current.Value.AsBoolean; //если ключ первого объекта(JSON файла) соответствует ключу второго объекта(JSON файла),
                    Break;
                  end;
                  Break;
                end;
              Break;
              end;
        finally
           FreeAndNil(JsonEnum1);
           FreeAndNil(JsonEnum2);

        end;
      finally
         JSONObject := JSONObject2 as TJSONObject;
         FreeAndNil(JsonObject1);
         //FreeAndNil(JsonObject2);
      end;

    finally
      FreeAndNil(JsonParser1);
      FreeAndNil(JsonParser2);
    end;
  end;
blackspaceghost вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как распарсить json remus-xe2 Общие вопросы Delphi 1 05.12.2020 12:31
Распарсить JSON массив SAMOUCHKA PHP 1 22.11.2018 15:00
Как распарсить Json в Delphi XE8 ArtGrek Общие вопросы Delphi 1 14.03.2017 15:22
Распарсить JSON nibufep Общие вопросы Delphi 1 01.05.2016 14:37
Как в JSON выразить объект? Utkin Общие вопросы по программированию, компьютерный форум 6 16.06.2012 00:01