Icon View Thread

The following is the text of the current message along with any replies.
Messages 1 to 10 of 14 total
Thread TReader parsing problem with nested arrays
Thu, Mar 22 2018 4:55 AMPermanent Link

Uli Becker

Hi,

Not easy to read, sorry. Maybe something for Tim.

I am using TReader to parse JSON (persistent fields).
Attached some screenshots (better than posting unformatted text) to make clear what's my problem:

Clip1:

"state": I use MyReader.LoadObject and pull out what I need (I don't need the values from the array "XY"). No problem.

Clip2:

"capabilities": I don't need this at all (at the moment), but here TReader throws an exception (Clip3). Obviously the nested arrays "colorgamut" cause the problem.

Two questions:
1. How can I skip the whole object "capabilities"?
2. If I need the values from "colorgamut": how do I parse an array of arrays?

Thanks Uli  



Attachments: Clip1.png Clip2.png Clip3.png
Thu, Mar 22 2018 5:15 AMPermanent Link

Matthew Jones

First step, I'd create matching objects, and a simple project that has a fixed string. Then you can experiment a lot more easily. (Maybe you have already done this, worth posting for people to play with perhaps.)

You don't show any code, so hard to comment further. Do you have a function in your object like this:

function TMyObject.LoadProperty(AReader: TReader): Boolean;
var
   szPropertyName : String;
begin
   Result := False;
   szPropertyName := AReader.GetPropertyName;
   if (szPropertyName <> '') then
   begin
       if SameText(szPropertyName, 'myarray') then
       begin
           Result := True;
           AReader.SkipPropertyName;
           AReader.SkipPropertySeparator;
           LoadArray(AReader);
       end
       else
       begin
           Result := inherited LoadProperty(AReader);
       end;
   end;
end;

That's the basic way to be reading properties that are other objects and arrays. I found that it was handy to run through the code in the Chrome debugger too, as you can see what is happening, or add other debugging "printf"s.

--

Matthew Jones
Thu, Mar 22 2018 9:05 AMPermanent Link

Uli Becker

Matthew,

> First step, I'd create matching objects, and a simple project that has a fixed string. Then you can experiment a lot more easily. (Maybe you have already done this, worth posting for people to play with perhaps.)

Yes, I did then when writing the code for this app. Ran fine until the incoming JSON was changed from a simple array to an array of arrays like I showed.

> Do you have a function in your object like this:

Generally yes, sure. But in this case I don't need the values of the array, so I've no code for it.

In the "state" object there is also an array "xy", which I don't need (and don't parse). No problem for TReader. The question is how to deal with the "colorgamut" array (or how to skip it).

Thanks Uli  
Thu, Mar 22 2018 9:50 AMPermanent Link

Matthew Jones

Uli Becker wrote:

>  I don't need the values of the array, so I've no code for it.

I think you are going to have to write the code for it, skipping the objects until it gets back to where you started. I had code for the old parser to do this, and maybe there is code in the library that shows how to skip hierarchically. Recursion may follow! 8-)

--

Matthew Jones
Thu, Mar 22 2018 11:23 AMPermanent Link

Raul

Team Elevate Team Elevate

On 3/22/2018 4:55 AM, Uli Becker wrote:
> Two questions:
> 1. How can I skip the whole object "capabilities"?
> 2. If I need the values from "colorgamut": how do I parse an array of
> arrays?

Could you post a sample json ? (i did not see one)

I find this type of thing a lot easier to look at with a sample.

Raul
Thu, Mar 22 2018 1:49 PMPermanent Link

Uli Becker

Raul,

> Could you post a sample json ? (i did not see one)
>
> I find this type of thing a lot easier to look at with a sample.

Sure, I posted screenshot of formatted json to make it more readable,
but here a part of the json I'm trying to parse:

"1": {
    "state": {
      "on": true,
      "bri": 142,
      "hue": 2905,
      "sat": 115,
      "effect": "none",
      "xy": [
        0.4945,
        0.3659
      ],
      "ct": 432,
      "alert": "none",
      "colormode": "xy",
      "mode": "homeautomation",
      "reachable": true
    },
    "swupdate": {
      "state": "noupdates",
      "lastinstall": "2017-12-22T15:59:36"
    },
    "type": "Extended color light",
    "name": "Vitrine",
    "modelid": "LCT015",
    "manufacturername": "Philips",
    "productname": "Hue color lamp",
    "capabilities": {
      "certified": true,
      "control": {
        "mindimlevel": 1000,
        "maxlumen": 806,
        "colorgamuttype": "C",
        "colorgamut": [
          [
            0.6915,
            0.3083
          ],
          [
            0.17,
            0.7
          ],
          [
            0.1532,
            0.0475
          ]
        ],
        "ct": {
          "min": 153,
          "max": 500
        }
      },
      "streaming": {
        "renderer": true,
        "proxy": true
      }
    },
    "config": {
      "archetype": "sultanbulb",
      "function": "mixed",
      "direction": "omnidirectional"
    },
    "uniqueid": "00:17:88:01:03:6f:9d:57-0b",
    "swversion": "1.29.0_r21169",
    "swconfigid": "3416C2DD",
    "productid": "Philips-LCT015-1-A19ECLv5"
  }

Thanks Uli
Fri, Mar 23 2018 6:33 AMPermanent Link

Uli Becker

Meanwhile I found a solution (maybe not the best, but it works):

Since the "inner" array has no PropertyName, I set a variable to identify the array, then parse this array like this:

function TLight.LoadProperty(AReader: TReader): Boolean;
var
   TempName: String;
begin
   Result := False;
   TempName := AReader.GetPropertyName;
   CurrentPropertyName := TempName;
   if SameText(TempName,'state') then
   begin
      ...
   end else if SameText(TempName,'Capabilities') then
   begin
      ...
   end else if SameText(TempName,'Control') then
   begin
      ...
   end else if SameText(TempName,'ColorGamut') then
   begin
      Result := True;
      AReader.SkipPropertyName;
      AReader.SkipPropertySeparator;
      LoadArray(AReader);
   end else if SameText(TempName,'ColorGamutInner') then
   begin
      Result := True;
      LoadArray(AReader);
   end else
      inherited LoadProperty(AReader);
end;

function TLight.LoadArrayElement(AReader: TReader): Boolean;
begin
   if SameText(CurrentPropertyName,'ColorGamut') then
   begin
      CurrentPropertyName := 'ColorGamutInner';
      AReader.ReadString; // no need to read the values, just to continue
      result := true;
   end else if SameText(CurrentPropertyName,'ColorGamutInner') then
   begin
      AReader.ReadString; // no need to read the values, just to continue
      result := true;
   end else
      result := inherited LoadArrayElement(AReader);
end;

Thanks to all.

Uli
Sat, Mar 24 2018 6:29 AMPermanent Link

Walter Matte

Tactical Business Corporation

Uli Becker wrote:

<<Meanwhile I found a solution (maybe not the best, but it works):>>

I posted a JSON Parser unit in EWB components (with a test program with your sample JSON) - mine may not be the best parser - but it works.

https://www.elevatesoft.com/forums?action=view&category=ewb&id=ewb_components&page=1&msg=152#152

Walter
Sat, Mar 24 2018 6:57 AMPermanent Link

Uli Becker

Hi Walter,

> I posted a JSON Parser unit in EWB components (with a test program with your sample JSON) - mine may not be the best parser - but it works.

Thanks a lot for that - much appreciated.
It works even with unformatted JSON, takes about 10 seconds though. Since incoming JSON is never formatted, that will be a problem. Have to look into the sources.

Great work anyway.

Uli
Sat, Mar 24 2018 8:24 AMPermanent Link

Walter Matte

Tactical Business Corporation

Uli

Formatted or unformated - does not matter is parses character by character.... size of json string parsed will therefore affect speed.  ...  I didn't play with larger samples...  I will for fun.

Walter
Page 1 of 2Next Page »
Jump to Page:  1 2
Image