Another json problem lazarus / 21-General ---------------------------------------------------------------------- arneolav · 2022-02-08 22:06 Run into another Json problem here This does partly work but can't see what's wrong. NodesArray.count=1, expected 7. Any help, Thanks in advance. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);type   TData = record    from,  too,    consumptionUnit : string;     cost,    unitPrice ,    unitPriceVAT,    consumption     : double;   end; var  s: string;  d, o, p: TJsonData;  ja, NodesArray: TJsonArray;  jo: TJsonObject;  a: array of TData;  I,J: Integer;   C : String;  Sl : TStringList;begin   s := ' {"data":{"viewer":{"homes":[{"consumption":{"nodes":[{"from":"2 022-02-08T19:00:00.000+01:00","to":"2022-02- 08T20:00:00.000+01:00","cost":null,"unitPrice":1.6671125,"unitPriceVAT ":0.3334225,"consumption":null,"consumptionUnit":"kWh"}]}},{"consumpti on":{"nodes":[{"from":"2022-02-08T19:00:00.000+01:00","to":"2022-02- 08T20:00:00.000+01:00","cost":2.23393075,"unitPrice":1.6671125,"unitPr iceVAT":0.3334225,"consumption":1.34,"consumptionUnit":"kWh"}]}}]}}}'; d := GetJSON(s);  Memo1.Append(s);  o := d.FindPath('data.viewer.homes');  if (o <> nil) and (o.JSONType = jtArray) then  begin    ja := TJsonArray(o);     for I := 0 to ja.Count - 1 do    begin      p := ja.Objects[I].FindPath('consumption.nodes');    // <--- TJsonObject found ok       if (p <> nil) and (p.JSONType = jtArray) then      begin                                                             // <---  TJsonArray found ok         NodesArray := TJsonArray(p);         SetLength(a, NodesArray.Count) ;         for J := 0 to NodesArray.Count - 1 do           // <--- NodesArray.Count = 1, Hmmm       begin            if (p <> nil) and (p.JSONType = jtObject) then   // <--- TJsonObject NOT found           begin              jo := TJsonObject(p);               with a[J] do              begin                  from            := jo.Strings['from'];                    too             := jo.Strings['to'];                    cost          := jo.Floats['cost'];                    unitPrice       := jo.Floats['unitPrice'];                    unitPriceVAT    := jo.Floats['unitPriceVAT'];                    consumption     := jo.Floats['consumption'];                    consumptionUnit := jo.Strings['consumptionUnit']              end;            end else showmessage('TJsonObject NOT found');         end;      end else showmessage('consumption.nodes NOT found');    end;  end;   d.Free;   for I := 0 to High(a) do begin    Memo1.Append('Item ' + I.ToString);    Memo1.Append('  from: ' + a[I].from);    Memo1.Append('  to: ' + a[I].too);    Memo1.Append('  cost: ' + a[I].cost.ToString);    Memo1.Append('  unitPrice: ' + a[I].unitPrice.ToString);    Memo1.Append('  unitPriceVAT : ' + a[I].unitPriceVAT.ToString);    Memo1.Append('  consumption  : ' + a[I].consumption.ToString);    Memo1.Append('  consumptionUnit: ' + a[I].consumptionUnit);   end;end; ---------------------------------------------------------------------- engkin · 2022-02-08 22:48 Your json String has only one home with two consumption nodes. ---------------------------------------------------------------------- arneolav · 2022-02-08 23:10 Yes, I see, it's received from API like this, but I don't see the problem. ---------------------------------------------------------------------- avk · 2022-02-09 05:00 Just in case, your JSON string in formatted form: Code: Javascript  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {    "data":    {        "viewer":        {            "homes":            [                {                    "consumption":                  {                        "nodes":                        [                          {                                "from": "2022-02-08T19:00:00.000+01:00",                                "to": "2022-02-08T20:00:00.000+01:00",                                "cost": null,                                "unitPrice": 1.6671125,                              "unitPriceVAT": 0.3334225,                              "consumption": null,                                "consumptionUnit": "kWh"                            }                      ]                    }                },                {                  "consumption":                    {                      "nodes":                        [                            {                              "from": "2022-02-08T19:00:00.000+01:00",                              "to": "2022-02-08T20:00:00.000+01:00",                              "cost": 2.23393075,                              "unitPrice": 1.6671125,                                "unitPriceVAT": 0.3334225,                                "consumption": 1.34,                                "consumptionUnit": "kWh"                            }                        ]                  }                }            ]        }    }} ---------------------------------------------------------------------- Jurassic Pork · 2022-02-09 05:31 hello, you can try something like this : Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);  type     TData = record      from,      too,      consumptionUnit : string;       cost,      unitPrice ,      unitPriceVAT,      consumption     : double;     end;   var    s: string;    d, o, p: TJsonData;    jo: TJsonObject;  oEnum: TJsonEnum;    pEnum: TJsonEnum;    a: array of TData;    I,J: Integer;     C : String;    Sl : TStringList;  begin     s := ' {"data ":{"viewer":{"homes":[{"consumption":{"nodes":[{"from":"2022-02- 08T19:00:00.000+01:00","to":"2022-02- 08T20:00:00.000+01:00","cost":null,"unitPrice":1.6671125,"unitPriceVAT ":0.3334225,"consumption":null,"consumptionUnit":"kWh"}]}},{"consumpti on":{"nodes":[{"from":"2022-02-08T19:00:00.000+01:00","to":"2022-02- 08T20:00:00.000+01:00","cost":2.23393075,"unitPrice":1.6671125,"unitPr iceVAT":0.3334225,"consumption":1.34,"consumptionUnit":"kWh"}]}}]}}}';   d := GetJSON(s);    Memo1.Append(s);    o := d.FindPath('data.viewer.homes');    I := 0;    SetLength(a, o.Count) ;    for oEnum in o do      begin        p := TJsonArray(oEnum.Value).FindPath('consumption.nodes');        for pEnum in p do          begin             jo :=   TJsonObject(pEnum.Value);             with a[I] do                begin                   if jo.Types['from'] = jtString then                    from := jo.Strings['from'];                   if jo.Types['to'] = jtString then                      too              := jo.Strings['to'];                   if jo.Types['cost'] = jtNumber then                      cost            := jo.Floats['cost'];                 if jo.Types['unitPrice'] = jtNumber then                    unitPrice       := jo.Floats['unitPrice'];                   if jo.Types['unitPriceVAT'] = jtNumber then                      unitPriceVAT    := jo.Floats['unitPriceVAT'];                   if jo.Types['consumption'] = jtNumber then                      consumption     := jo.Floats['consumption'];                   if jo.Types['consumptionUnit'] = jtString then                      consumptionUnit := jo.Strings['consumptionUnit']                end;            I:= I+1;           end;      end;    d.Free;     for I := 0 to High(a) do begin      Memo1.Append('Item ' + I.ToString);      Memo1.Append('  from: ' + a[I].from);      Memo1.Append('  to: ' + a[I].too);      Memo1.Append('  cost: ' + a[I].cost.ToString);      Memo1.Append('  unitPrice: ' + a[I].unitPrice.ToString);      Memo1.Append('  unitPriceVAT : ' + a[I].unitPriceVAT.ToString);      Memo1.Append('  consumption  : ' + a[I].consumption.ToString);      Memo1.Append('  consumptionUnit: ' + a[I].consumptionUnit);     end;  end;       Résult : QuoteItem 0   from: 2022-02-08T19:00:00.000+01:00   to: 2022-02-08T20:00:00.000+01:00   cost: 0   unitPrice: 1,6671125   unitPriceVAT : 0,3334225   consumption  : 0   consumptionUnit: kWh Item 1   from: 2022-02-08T19:00:00.000+01:00   to: 2022-02-08T20:00:00.000+01:00   cost: 2,23393075   unitPrice: 1,6671125   unitPriceVAT : 0,3334225   consumption  : 1,34   consumptionUnit: kWh Friendly, J.P ---------------------------------------------------------------------- arneolav · 2022-02-09 09:08 Thank's Jurassic Pork This does the trick. But I should like to know what's wrong with my code, could it be done that way? ---------------------------------------------------------------------- arneolav · 2022-02-09 19:59 As array a was too small on API data I had to do a small correction: SetLength(a, I+1) ;                             //<---------------------------- View Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);  type     TData = record      from,      too,      consumptionUnit : string;       cost,      unitPrice ,      unitPriceVAT,      consumption     : double;     end;   var    s: string;    d, o, p: TJsonData;    jo: TJsonObject;  oEnum: TJsonEnum;    pEnum: TJsonEnum;    a: array of TData;    I,J: Integer;     C : String;    Sl : TStringList;  begin     s := ' {"data ":{"viewer":{"homes":[{"consumption":{"nodes":[{"from":"2022-02- 08T19:00:00.000+01:00","to":"2022-02- 08T20:00:00.000+01:00","cost":null,"unitPrice":1.6671125,"unitPriceVAT ":0.3334225,"consumption":null,"consumptionUnit":"kWh"}]}},{"consumpti on":{"nodes":[{"from":"2022-02-08T19:00:00.000+01:00","to":"2022-02- 08T20:00:00.000+01:00","cost":2.23393075,"unitPrice":1.6671125,"unitPr iceVAT":0.3334225,"consumption":1.34,"consumptionUnit":"kWh"}]}}]}}}';   d := GetJSON(s);    Memo1.Append(s);    o := d.FindPath('data.viewer.homes');    I := 0;  //  SetLength(a, o.Count) ;      <----------------------------    for oEnum in o do      begin      p := TJsonArray(oEnum.Value).FindPath('consumption.nodes');      for pEnum in p do          begin             jo :=   TJsonObject(pEnum.Value);             SetLength(a, I+1) ;                           //<----------------------------             with a[I] do                begin                   if jo.Types['from'] = jtString then                      from := jo.Strings['from'];                 if jo.Types['to'] = jtString then                      too            := jo.Strings['to'];                   if jo.Types['cost'] = jtNumber then                      cost            := jo.Floats['cost'];                   if jo.Types['unitPrice'] = jtNumber then                      unitPrice       := jo.Floats['unitPrice'];                   if jo.Types['unitPriceVAT'] = jtNumber then                      unitPriceVAT    := jo.Floats['unitPriceVAT'];                   if jo.Types['consumption'] = jtNumber then                      consumption     := jo.Floats['consumption'];                   if jo.Types['consumptionUnit'] = jtString then                      consumptionUnit := jo.Strings['consumptionUnit']                end;            I:= I+1;           end;      end;    d.Free;     for I := 0 to High(a) do begin      Memo1.Append('Item ' + I.ToString);      Memo1.Append('  from: ' + a[I].from);      Memo1.Append('  to: ' + a[I].too);      Memo1.Append('  cost: ' + a[I].cost.ToString);      Memo1.Append('  unitPrice: ' + a[I].unitPrice.ToString);      Memo1.Append('  unitPriceVAT : ' + a[I].unitPriceVAT.ToString);      Memo1.Append('  consumption  : ' + a[I].consumption.ToString);      Memo1.Append('  consumptionUnit: ' + a[I].consumptionUnit);     end;  end; ---------------------------------------------------------------------- krolikbest · 2022-02-09 21:09 Hi a little changed yor code. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,  fpjson, jsonparser; type   TData = record    from,    too,    consumptionUnit : string;     cost,    unitPrice ,    unitPriceVAT,    consumption     : double;  end;   { TForm1 }   TForm1 = class(TForm)    Button1: TButton;    Memo1: TMemo;    procedure Button1Click(Sender: TObject);  private   public   end; var  Form1: TForm1;  s: string;  d, o, p: TJsonData;  ja, NodesArray: TJsonArray;  jo: TJsonObject;  a: array of TData;  I: Integer; implementation {$R *.lfm} { TForm1 } procedure TForm1.Button1Click(Sender: TObject);begin  s := ' {"data":{"viewer":{ "homes":[{"consumption":{"nodes":[{"from":"2022-02- 08T19:00:00.000+01:00","to":"2022-02- 08T20:00:00.000+01:00","cost":null,"unitPrice":1.6671125,"unitPriceVAT ":0.3334225,"consumption":null,"consumptionUnit":"kWh"}]}},{"consumpti on":{"nodes":[{"from":"2021-02-08T19:00:00.000+01:00","to":"2022-02- 08T20:00:00.000+01:00","cost":2.23393075,"unitPrice":1.6671125,"unitPr iceVAT":0.3334225,"consumption":1.34,"consumptionUnit":"kWh"}]}}]}}}'; d := GetJSON(s);  o := d.FindPath('data.viewer.homes');  if (o <> nil) and (o.JSONType = jtArray) then  begin      ja := TJsonArray(o);       memo1.Lines.Add('Count : '+inttostr(ja.Count));    SetLength(a, ja.Count) ;       for I := 0 to ja.Count - 1 do      begin         p := ja[i].FindPath('consumption.nodes');        memo1.Lines.Add('consumption.nodes  '+ inttostr(i));         if (p <> nil) and (p.JSONType = jtArray) then        begin           NodesArray := TJsonArray(p);            //c:=nodesArray.Items[0].FindPath('from').AsString;           //memo1.Lines.Add(c);          jo := TJsonObject(nodesArray.Items[0]); //there is only one item in every consumption.nodes node! that is why index=0           with a[i] do       begin           from            := jo.Strings['from'];           too             := jo.Strings['to'];           if jo.Types['cost']=jtNumber then            cost            := jo.Floats['cost'];           unitPrice       := jo.Floats['unitPrice'];           unitPriceVAT    := jo.Floats['unitPriceVAT'];           if jo.Types['consumption']=jtNumber then            consumption     := jo.Floats['consumption'];           consumptionUnit := jo.Strings['consumptionUnit']         end;        end else showmessage('consumption.nodes NOT found');       end;  end;  d.Free;   for I := 0 to High(a) do  begin      Memo1.Append('Item ' + I.ToString);      Memo1.Append('  from: ' + a[I].from);      Memo1.Append('  to: ' + a[I].too);      Memo1.Append('  cost: ' + a[I].cost.ToString);      Memo1.Append('  unitPrice: ' + a[I].unitPrice.ToString);      Memo1.Append('  unitPriceVAT : ' + a[I].unitPriceVAT.ToString);      Memo1.Append('  consumption  : ' + a[I].consumption.ToString);      Memo1.Append('  consumptionUnit: ' + a[I].consumptionUnit);  end;end; end. ---------------------------------------------------------------------- arneolav · 2022-02-09 21:49 Thanks that was interesting! But, the number of consumption.nodes is unknown, try this:   s := ' {"data":{"viewer":{"homes":[{"consumption":{"nodes":[{"from": "2022-02-09T20:00:00.000+01:00","to":"2022-02- 09T21:00:00.000+01:00","cost":null,"unitPrice":1.566625,"unitPriceVAT" :0.313325,"consumption":null,"consumptionUnit":"kWh"},{"from":"2022- 02-09T21:00:00.000+01:00","to":"2022-02- 09T22:00:00.000+01:00","cost":null,"unitPrice":1.548,"unitPriceVAT":0. 3096,"consumption":null,"consumptionUnit":"kWh"}]}},{"consumption":{"n odes":[{"from":"2022-02-09T20:00:00.000+01:00","to":"2022-02- 09T21:00:00.000+01:00","cost":4.574545,"unitPrice":1.566625,"unitPrice VAT":0.313325,"consumption":2.92,"consumptionUnit":"kWh"},{"from":"202 2-02-09T21:00:00.000+01:00","to":"2022-02- 09T22:00:00.000+01:00","cost":5.58828,"unitPrice":1.548,"unitPriceVAT" :0.3096,"consumption":3.61,"consumptionUnit":"kWh"}]}}]}}} '; ---------------------------------------------------------------------- engkin · 2022-02-09 22:09 It is known, almost. TJsonArray gives you the number of items. krolikbest's code needs a small change: move Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   SetLength(a, ja.Count) ;From line 62 to line 73 and replace ja with NodesArray Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   SetLength(a, NodesArray.Count) ; If data.viewer.homes node has more than one home and you want the data of all of them in array a, then change it to: SetLength(a, Length(a) + NodesArray.Count) ; You get the idea. What might cause confusion having ja for homes, and a for nodes. ---------------------------------------------------------------------- arneolav · 2022-02-09 23:36 Hi! Move/replace SetLength(a, ja.Count) ; by   SetLength(a, NodesArray.Count) ; Did not work pefekt; don't get values from consumption 3 and 4 I need to have a closer look. ... Sorry, I was some familiar with XML some years ago, but to Json I'm newbie ---------------------------------------------------------------------- Jurassic Pork · 2022-02-10 01:37 hello, Quote from: arneolav on February 10, 2022, 12:36:14 amHi! Move/replace SetLength(a, ja.Count) ; by   SetLength(a, NodesArray.Count) ; Did not work pefekt; don't get values from consumption 3 and 4 I need to have a closer look. ... Sorry, I was some familiar with XML some years ago, but to Json I'm newbie in the Krolikbest's program he considers only one item in the consumption.nodes  node : Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  jo := TJsonObject(nodesArray.Items[0]); //there is only one item in every consumption.nodes node! that is why index=0have a look to my program i have a loop for all the items in the consumption.nodes node, so you must add a loop in the Krolikbest's program. And for a array , it is safe to add one element just before to use it  : Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     SetLength(a,length(a)+1) ;         with a[i] do       you must remove the SetLength before. So the first time, length(a) value is 0 . i isn't the good index for a you can try a[length(a)-1]. Friendly, J.P ---------------------------------------------------------------------- avk · 2022-02-10 08:06 Hi, It seems, looking at the structure of the current JSON document, the Pascal structure needed to extract values from it should look something like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TNode = record    from,    too,    consumptionUnit : string;    cost,    unitPrice ,    unitPriceVAT,    consumption     : double;  end;   TConsumption = record    Nodes: array of TNode;  end;   THomes = array of TConsumption;  Data extracting accordingly: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function TryExtractData(const s: string; out aHomes: THomes): Boolean;var  Homes, Nodes: TJsonArray;  CurrNode: TJsonObject;  jRoot: TJsonData = nil;  I, J: Integer;begin  try    jRoot := GetJSON(s);    try      Homes := TJsonArray(jRoot.FindPath('data.viewer.homes'));      SetLength(aHomes, Homes.Count);      for I := 0 to High(aHomes) do begin        Nodes :=  TJsonArray(Homes[I].FindPath('consumption.nodes'));        SetLength(aHomes[I].Nodes, Nodes.Count);        for J := 0 to High(aHomes[I].Nodes) do begin          CurrNode := Nodes.Objects[J];          with aHomes[I].Nodes[J], CurrNode do begin            from := Strings['from'];            too := Strings['to'];            consumptionUnit := Strings['consumptionUnit'];            if Types['cost'] = jtNull then              cost := 0            else            cost := Floats['cost'];            unitPrice := Floats['unitPrice'];            unitPriceVAT := Floats['unitPriceVAT'];            if Types['consumption'] = jtNull then              consumption := 0            else              consumption := Floats['consumption'];          end;        end;      end;    finally      jRoot.Free;    end;  except    exit(False);  end;  Result := True;end; procedure TfrmMain.Button1Click(Sender: TObject);var  s: string;  h: THomes;  I, J: Integer;begin  s := ' {"da ta":{"viewer":{"homes":[{"consumption":{"nodes":[{"from":"2022-02- 09T20:00:00.000+01:00","to":"2022-02- 09T21:00:00.000+01:00","cost":null,"unitPrice":1.566625,"unitPriceVAT" :0.313325,"consumption":null,"consumptionUnit":"kWh"},{"from":"2022- 02-09T21:00:00.000+01:00","to":"2022-02- 09T22:00:00.000+01:00","cost":null,"unitPrice":1.548,"unitPriceVAT":0. 3096,"consumption":null,"consumptionUnit":"kWh"}]}},{"consumption":{"n odes":[{"from":"2022-02-09T20:00:00.000+01:00","to":"2022-02- 09T21:00:00.000+01:00","cost":4.574545,"unitPrice":1.566625,"unitPrice VAT":0.313325,"consumption":2.92,"consumptionUnit":"kWh"},{"from":"202 2-02-09T21:00:00.000+01:00","to":"2022-02- 09T22:00:00.000+01:00","cost":5.58828,"unitPrice":1.548,"unitPriceVAT" :0.3096,"consumption":3.61,"consumptionUnit":"kWh"}]}}]}}} ';  if not TryExtractData(s, h) then    begin      Memo1.Append('Failed to extract data');      exit;    end;  for I := 0 to High(h) do begin    Memo1.Append('Home ' + I.ToString);    for J := 0 to High(h[I].Nodes) do      with h[I].Nodes[J] do begin        Memo1.Append('  Node ' + J.ToString);        Memo1.Append('    from: ' + from);        Memo1.Append('    to: ' + too);        Memo1.Append('    cost: ' + cost.ToString);        Memo1.Append('    unitPrice: ' + unitPrice.ToString);        Memo1.Append('    unitPriceVAT: ' + unitPriceVAT.ToString);        Memo1.Append('    consumption: ' + consumption.ToString);        Memo1.Append('    consumptionUnit: ' + consumptionUnit);      end;  end;end; It prints Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Home 0  Node 0    from: 2022-02-09T20:00:00.000+01:00    to: 2022-02-09T21:00:00.000+01:00    cost: 0    unitPrice: 1,566625    unitPriceVAT: 0,313325    consumption: 0    consumptionUnit: kWh  Node 1    from: 2022-02-09T21:00:00.000+01:00    to: 2022-02-09T22:00:00.000+01:00    cost: 0    unitPrice: 1,548    unitPriceVAT: 0,3096    consumption: 0    consumptionUnit: kWhHome 1  Node 0    from: 2022-02-09T20:00:00.000+01:00    to: 2022-02-09T21:00:00.000+01:00    cost: 4,574545    unitPrice: 1,566625    unitPriceVAT: 0,313325    consumption: 2,92    consumptionUnit: kWh  Node 1    from: 2022-02-09T21:00:00.000+01:00  to: 2022-02-09T22:00:00.000+01:00    cost: 5,58828    unitPrice: 1,548    unitPriceVAT: 0,3096    consumption: 3,61    consumptionUnit: kWh ---------------------------------------------------------------------- arneolav · 2022-02-10 09:53 Many thanks to avk. As I am (or at least have been) well acquainted with records and dynastic arrays, this makes it easier to understand Json's structure. And many thanks to everyone else who has helped me find good solutions, it helps me a lot in the project and saves me a lot of time.