Recent

Author Topic: Пытаюсь распарсить 2 JSONа и скопировать значениия  (Read 10419 times)

blackspaceghost

  • New Member
  • *
  • Posts: 14
Всем доброго времени суток, в общем пытаюсь распарсить 2 JSON объекта, в принципе всё получается, кроме одного но, во вложенном объекте тип jtArray напрочь отказывается копироваться в другой объект, ссылаясь на разного рода ошибки. (Хотя не во вложенном объекте всё работает, подходя таким же принципом) Поэтому и закрадывается вопрос, как быть-то, ведь оно должно работать, и должно работать так же. Я уже перепробовал разные подходы к решению данной задачи, ничего, все тщетно. Вложенный jtArray не поддаётся. Уповаю на вашу помощь и ниже прилагаю код и 2 JSON объекта:
Code: Pascal  [Select][+][-]
  1.     program Project1;
  2.      
  3.     {$mode objfpc}{$H+}
  4.      
  5.     uses
  6.      {$IFDEF UNIX}
  7.       cthreads,
  8.                             {$ENDIF}
  9.       Classes,
  10.       SysUtils,
  11.       CustApp { you can add units after this },
  12.       jsonscanner,
  13.       fpjson,
  14.       jsonparser;
  15.      
  16.     type
  17.      
  18.       { TMyTimeTest }
  19.      
  20.       TMyTimeTest = class(TCustomApplication)
  21.       private
  22.         fFileData: string;
  23.         fPath1: string;
  24.         fPath2: string;
  25.         fFlag: boolean;
  26.         fStr1: string;
  27.         fStr2: string;
  28.      
  29.         procedure SetPath1(path: string);
  30.         procedure SetPath2(path: string);
  31.         procedure SetFlag(flag: boolean);
  32.         procedure SetStr1(str1: string);
  33.         procedure SetStr2(str2: string);
  34.       protected
  35.         procedure DoRun; override;
  36.       public
  37.         JSONObject1, JSONObject2: TJSONObject;
  38.         JSONEnum1, JSONEnum2: TBaseJSONEnumerator;
  39.         constructor Create(TheOwner: TComponent); override;
  40.         destructor Destroy; override;
  41.         procedure WriteHelp; virtual;
  42.         procedure WriteInfo;
  43.         procedure SetFileData;
  44.         procedure ParseAndSet;
  45.         procedure WriteInFile;
  46.         property Path1: string read fPath1 write SetPath1;
  47.         property Flag: boolean read fFlag write SetFlag;
  48.         property Str1: string read fStr1 write SetStr1;
  49.         property Str2: string read fStr2 write SetStr2;
  50.       end;
  51.      
  52.       { TMyTimeTest }
  53.      
  54.       procedure TMyTimeTest.SetPath1(path: string);
  55.       begin
  56.         fPath1 := path;
  57.       end;
  58.      
  59.       procedure TMyTimeTest.SetPath2(path: string);
  60.       begin
  61.         fPath2 := path;
  62.       end;
  63.      
  64.       procedure TMyTimeTest.SetFlag(flag: boolean);
  65.       begin
  66.         fFlag := flag;
  67.       end;
  68.      
  69.       procedure TMyTimeTest.SetStr1(str1: string);
  70.       begin
  71.         fStr1 := str1;
  72.       end;
  73.      
  74.       procedure TMyTimeTest.SetStr2(str2: string);
  75.       begin
  76.         fStr2 := str2;
  77.       end;
  78.      
  79.       procedure TMyTimeTest.SetFileData;
  80.       var
  81.      
  82.         L: TStringList;
  83.      
  84.       begin
  85.      
  86.         //if str1 = '' then
  87.         //  fPath1 := ParamStr(1)
  88.         //else
  89.         //  fPath2 := ParamStr(2);
  90.         fPath1 := '/media/sf_Devices/u1.json';
  91.         fPath2 := '/media/sf_Devices/u2.json';
  92.         try
  93.           try
  94.             L := TStringList.Create;
  95.             L.LoadFromFile(fPath1);
  96.             if L <> nil then
  97.             begin
  98.               fFileData := L.Text;
  99.               Self.SetFlag(True);
  100.               if str1 = '' then
  101.                 str1 := fFileData;
  102.             end;
  103.           finally
  104.             L.Free;
  105.           end;
  106.         except
  107.           ShowException(Exception.Create('1'));
  108.           Terminate;
  109.           Halt;
  110.         end;
  111.         //if str1 = '' then
  112.         //  fPath1 := ParamStr(1)
  113.         //else
  114.         //  fPath2 := ParamStr(2);
  115.         try
  116.           try
  117.             L := TStringList.Create;
  118.             L.LoadFromFile(fPath2);
  119.             if L <> nil then
  120.             begin
  121.               fFileData := L.Text;
  122.               Self.SetFlag(True);
  123.               if str2 = '' then
  124.                 str2 := fFileData;
  125.             end;
  126.           finally
  127.             L.Free;
  128.           end;
  129.         except
  130.           ShowException(Exception.Create('1'));
  131.           Terminate;
  132.           Halt;
  133.         end;
  134.       end;
  135.      
  136.       procedure TMyTimeTest.ParseAndSet;
  137.       var
  138.         JSONParser1, JSONParser2: TJSONParser;
  139.         JNestObject1, JNestObject2: TJSONObject;
  140.         JSONNestEnum1, JSONNestEnum2, JSONArrayEnum: TBaseJSONEnumerator;
  141.         i: integer;
  142.       begin
  143.         JSONParser1 := TJSONParser.Create(str1, DefaultOptions);
  144.         JSONParser2 := TJSONParser.Create(str2, DefaultOptions);
  145.         try
  146.           JSONObject1 := JSONParser1.Parse as TJSONObject;
  147.           JSONObject2 := JSONParser2.Parse as TJSONObject;
  148.           try
  149.             JSONEnum1 := JSONObject1.GetEnumerator;
  150.             JSONEnum2 := JSONObject2.GetEnumerator;
  151.      
  152.             try
  153.              
  154.               while JSONEnum1.MoveNext do
  155.                 while JSONEnum2.MoveNext do
  156.                 begin
  157.                   if JSONEnum1.Current.Value.JSONType = jtObject then
  158.                    
  159.                   begin
  160.                    
  161.                     JNestObject1 := JSONEnum1.Current.Value as TJSONObject;
  162.                     JNestObject2 := JSONObject2.Find(JSONEnum1.Current.Key) as TJSONObject;
  163.                     try
  164.                       JSONNestEnum1 := JNestObject1.GetEnumerator;
  165.                       JSONNestEnum2 := JNestObject2.GetEnumerator;
  166.                       while JSONNestEnum1.MoveNext do
  167.                         while JSONNestEnum2.MoveNext do
  168.                         begin
  169.                           if JSONObject2.FindPath(JSONEnum1.Current.key + '.' + JSONNestEnum1.Current.Key) <> nil then
  170.                           begin
  171.                             if JSONNestEnum1.Current.Value.JSONType = jtString then
  172.                            
  173.                             begin
  174.                               JNestObject2.Strings[JSONNestEnum1.Current.Key] := JSONNestEnum1.Current.Value.AsString;
  175.                              
  176.                               Break;
  177.                              
  178.                             end
  179.                             else if JSONNestEnum1.Current.Value.JSONType = jtNumber then
  180.                              
  181.                             begin
  182.                               JNestObject2.Integers[JSONNestEnum1.Current.Key] := JSONNestEnum1.Current.Value.AsInt64;
  183.                               Break;
  184.                             end
  185.                             else if JSONNestEnum1.Current.Value.JSONType = jtBoolean then
  186.                              
  187.                             begin
  188.                               JNestObject2.Booleans[JSONNestEnum1.Current.Key] := JSONNestEnum1.Current.Value.AsBoolean;
  189.                              
  190.                               Break;
  191.      
  192.                             end
  193.                             else if JSONNestEnum1.Current.Value.JSONType = jtArray then
  194.                             begin
  195.                               JSONArrayEnum := TJSONArray(JSONNestEnum1.Current.Value).GetEnumerator;
  196.                               JSONObject2.Arrays[JSONNestEnum1.Current.Key].Clear;
  197.                               while JSONArrayEnum.MoveNext do
  198.                                 JSONObject2.Arrays[JSONNestEnum1.Current.key].Add(JSONArrayEnum.Current.Value);
  199.                               //JSONObject2.Arrays[JSONNestEnum1.Current.Key] := (TJSONArray(JNestObject2.Items[2]));;
  200.                               //for i:=0 to TJSONArray(JNestObject2.Items[2]).Count-1 do
  201.      
  202.                             end;
  203.                             Break;
  204.                           end;
  205.                         end;
  206.                     finally
  207.                       FreeAndNil(JSONNestEnum1);
  208.                       FreeAndNil(JSONNestEnum2);
  209.                     end;
  210.                   end
  211.                   else if JSONObject2.FindPath(JSONEnum1.Current.Key) <> nil then
  212.                   begin
  213.                     if JSONEnum1.Current.Value.JSONType = jtString then
  214.                      
  215.                     begin
  216.                       JSONObject2.Strings[JSONEnum1.Current.Key] := JSONEnum1.Current.Value.AsString;
  217.                      
  218.                       Break;
  219.                      
  220.                     end
  221.                     else if JSONEnum1.Current.Value.JSONType = jtNumber then
  222.                      
  223.                     begin
  224.                       JSONObject2.Integers[JSONEnum1.Current.Key] := JSONEnum1.Current.Value.AsInt64;
  225.                       Break;
  226.                     end
  227.                     else if JSONEnum1.Current.Value.JSONType = jtBoolean then
  228.                      
  229.                     begin
  230.                       JSONObject2.Booleans[JSONEnum1.Current.Key] := JSONEnum1.Current.Value.AsBoolean;
  231.                    
  232.                       Break;
  233.                     end
  234.                     else if JSONEnum1.Current.Value.JSONType = jtArray then
  235.                     begin
  236.                       JSONArrayEnum := TJSONArray(JSONEnum1.Current.Value).GetEnumerator;
  237.                       JSONObject2.Arrays[JSONEnum1.Current.Key].Clear;
  238.                       while JSONArrayEnum.MoveNext do
  239.                         JSONObject2.Arrays[JSONEnum1.Current.key].Add(JSONArrayEnum.Current.Value);
  240.                       Break;
  241.                     end;
  242.                     Break;
  243.                   end;
  244.                   Break;
  245.                 end;
  246.             finally
  247.               FreeAndNil(JsonEnum1);
  248.               FreeAndNil(JsonEnum2);
  249.      
  250.             end;
  251.           finally
  252.             //FreeAndNil(JsonObject1);
  253.             //FreeAndNil(JsonObject2);
  254.           end;
  255.      
  256.         finally
  257.           FreeAndNil(JsonParser1);
  258.           FreeAndNil(JsonParser2);
  259.         end;
  260.       end;
  261.      
  262.       procedure TMyTimeTest.WriteInFile;
  263.       var
  264.         L: TStringList;
  265.       begin
  266.         L := TStringList.Create;
  267.         try
  268.           L.Text := Trim(JSONObject2.FormatJSON);
  269.           L.SaveToFile(fPath2);
  270.           ShowException(Exception.Create('0'));
  271.         finally
  272.           L.Free;
  273.           JSONObject2.Free;
  274.         end;
  275.       end;
  276.      
  277.      
  278.       procedure TMyTimeTest.DoRun;
  279.       var
  280.         ErrorMsg: string;
  281.       begin
  282.      
  283.         // parse parameters
  284.         if HasOption('h', 'help') then
  285.         begin
  286.           WriteHelp;
  287.           Terminate;
  288.           Exit;
  289.         end;
  290.      
  291.         if HasOption('i', 'info') then
  292.         begin
  293.           WriteInfo;
  294.           Terminate;
  295.           Exit;
  296.         end;
  297.      
  298.         // quick check parameters
  299.         ErrorMsg := CheckOptions('h', 'help');
  300.         if ErrorMsg <> '' then
  301.         begin
  302.           ShowException(Exception.Create(ErrorMsg));
  303.          
  304.           Terminate;
  305.           Exit;
  306.         end;
  307.      
  308.      
  309.      
  310.         { add your program here }
  311.         Self.SetFileData;        
  312.         Self.SetFileData;        
  313.         if flag = True then
  314.         begin
  315.           Self.ParseAndSet;
  316.           Self.WriteInFile;
  317.         end;
  318.      
  319.         // stop program loop
  320.         Terminate;
  321.       end;
  322.      
  323.      
  324.      
  325.       constructor TMyTimeTest.Create(TheOwner: TComponent);
  326.       begin
  327.         inherited Create(TheOwner);
  328.         StopOnException := True;
  329.       end;
  330.      
  331.       destructor TMyTimeTest.Destroy;
  332.       begin
  333.         inherited Destroy;
  334.       end;
  335.      
  336.       procedure TMyTimeTest.WriteHelp;
  337.       begin
  338.         { add your help code here }
  339.        
  340.      
  341.       end;
  342.      
  343.       procedure TMyTimeTest.WriteInfo;
  344.       begin
  345.        
  346.       end;
  347.      
  348.     var
  349.       Application: TMyTimeTest;
  350.      
  351.     begin
  352.       Application := TMyTimeTest.Create(nil);
  353.       Application.Title := 'MyTimeTest';
  354.       Application.Run;
  355.       Application.Free;
  356.     end.

Code: Text  [Select][+][-]
  1.     {
  2.             "host":{
  3.                     "wired": "192.168.209.2",
  4.                     "usb_wifi": "192.168.25.5",
  5.                     "ports":[2000, 23000, 40000]  
  6.                     },
  7.             "port": {
  8.                     "wired": 20002,
  9.                     "usb_wifi": 20003
  10.                     },
  11.             "devices": ["uspd", "rip", "asr"],
  12.             "writedebug": True,
  13.             "writecriticalsection": True
  14.            
  15.     }
Code: Text  [Select][+][-]
  1.     {
  2.             "host":{
  3.                     "wired": "0.0.0.0",
  4.                     "usb_wifi": "0.0.0.0",
  5.                     "ports": [],  
  6.                     "modem_managed_0": "0.0.0.0"
  7.                     },
  8.                    
  9.             "port": {
  10.                     "wired": 20002,
  11.                     "usb_wifi": 20002,
  12.                     "modem_managed_0": 20002
  13.                     },
  14.             "devices": [],
  15.             "writedebug": false,
  16.             "writecriticalsection": false,
  17.             "writemagicdebugid": -1,
  18.             "writembusdebugid": -1
  19.            
  20.     }

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2762
    • havefunsoft.com
...пытаюсь распарсить 2 JSON объекта,... напрочь отказывается копироваться в другой объект
так парсить, или копировать? в чём задача состоит?

У TJsonData есть метод .Clone ты его пробовал ?
« Last Edit: August 10, 2021, 07:31:45 pm by skalogryz »

blackspaceghost

  • New Member
  • *
  • Posts: 14
Задача состоит в копировании значений совпадающих ключей в 2-х объектах, парсинг это как раз частный случай. Clone пробовал, не помогло тоже. Вообще, я написал на англоязычный форум, и там мне привели рабочий вариант: https://forum.lazarus.freepascal.org/index.php?topic=55763.msg414741#msg414741, только вот теперь не могу добавить из файла подгрузку, вылетают ошибки. Видимо, не могу привести в нормальный вид входные данные

zoltanleo

  • Sr. Member
  • ****
  • Posts: 431
А использование сторонних модулей не рассматривается? Например, этого
Win10 LTSC x64/Deb 11 amd64(gtk2/qt5)/Darwin Cocoa (Monterey):
Lazarus x32/x64 2.3(trunk); FPC 3.3.1 (trunk), FireBird 3.0.10; IBX by Rik

Sorry for my bad English, I'm using translator ;)

Red_prig

  • Jr. Member
  • **
  • Posts: 66
Стандартный json парсер и его DOM по мне довольно ужасен, я сильно переписал парсер и DOM для своих нужд, если кому интересно:
https://github.com/red-prig/netlibs/tree/master/xpath

zoltanleo

  • Sr. Member
  • ****
  • Posts: 431
А какой-то внятный мануал к нему есть, чтобы по исходникам не рыться?
Win10 LTSC x64/Deb 11 amd64(gtk2/qt5)/Darwin Cocoa (Monterey):
Lazarus x32/x64 2.3(trunk); FPC 3.3.1 (trunk), FireBird 3.0.10; IBX by Rik

Sorry for my bad English, I'm using translator ;)

Red_prig

  • Jr. Member
  • **
  • Posts: 66

AlexTP

  • Hero Member
  • *****
  • Posts: 1900
    • UVviewsoft
Стандартный json парсер и его DOM по мне довольно ужасен
А как-то улучшить стандартный можно? может там, патч какой, может его примут?

Red_prig

  • Jr. Member
  • **
  • Posts: 66
Если говорить именно о парсере, то основная проблема в нём это скорость, на размере файла в мегабайт уже заметно зависание. А по поводу патча, мне сейчас лень этим заниматься, мож когда нить потом. (Хотя я вообще собирался его полностью переписать но забил :( )

AlexTP

  • Hero Member
  • *****
  • Posts: 1900
    • UVviewsoft
Буду рад патчу и ускорению, т.к. использую обычный JsonConf.
А вот переход на другой компонент- мне не ОК.
« Last Edit: August 20, 2021, 02:06:11 pm by Alextp »

avk

  • Hero Member
  • *****
  • Posts: 614
    • my self-education project
Стандартный json парсер и его DOM по мне довольно ужасен, я сильно переписал парсер и DOM для своих нужд...
Интересно, что скажет этот переписанный парсер насчёт вот такого JSON'а?
Code: Text  [Select][+][-]
  1.   {"a":"b"}#
  2.  

Red_prig

  • Jr. Member
  • **
  • Posts: 66
а что не так с этим файлом?

avk

  • Hero Member
  • *****
  • Posts: 614
    • my self-education project
Так он как бы не совсем JSON.

avk

  • Hero Member
  • *****
  • Posts: 614
    • my self-education project
Должен заметить, непереписанный тоже не усматривает никакой причины забраковать этот JSON.
Хотя любой онлайн валидатор сразу же даст отлуп.
Попробуйте проверить ещё вот такие варианты:
Code: Text  [Select][+][-]
  1.   []]
  2.  
Code: Text  [Select][+][-]
  1.   {"a": 1.e-}
  2.  

AlexTP

  • Hero Member
  • *****
  • Posts: 1900
    • UVviewsoft
Валидатор должен быть встроен. в FPJson (JsonConf) он как раз хорош.

 

TinyPortal © 2005-2018