SuperObject - Extract All
Asked Answered
D

1

6

How to get ALL 'id' member values from a generic JSON. Without knowing structure of it. Because its very complex and it has a lot of sub objects. It has to loop through all the sub objects.

Again for people that keep on asking where is the example JSON. My question is about how to extract a member value in my case "id" from any generic JSON that has this member inside.

Druse answered 29/12, 2012 at 15:1 Comment(0)
B
11

If you don't know the structure of the JSON you receive from somewhere, it is important to note that JSON is "simply" a composite pattern and you can traverse it like any other composite structure. The following example traverse the complete structure in a JSON text and prints the path of any member named 'id'.

procedure ParseJSON;
var
  JSONText: string;
  JSON: ISuperObject;
begin
  // Retrieve JSON as a string into JSONText variable any way you like.
  JSON := SO(JSONText);
  ProcessObject(JSON.AsObject);
end;

procedure ProcessObject(const aAsObject: TSuperTableString; const aPrefix: string = '');
var
  Names: ISuperObject;
  Name: string;
  Items: ISuperObject;
  Item: ISuperObject;
  idx: Integer;
  Value: string;
  ArrayItem: ISuperObject;
begin
  if Assigned(aAsObject) then
  begin
    Names := aAsObject.GetNames;
    Items := aAsObject.GetValues;

    for idx := 0 to Items.AsArray.Length - 1 do
    begin
      Name := Names.AsArray[idx].AsString;
      Item := Items.AsArray[idx];
      if Item.DataType = stObject then
        Value := '<Object>'
      else if Item.DataType = stArray then
        Value := '<Array>'
      else
        Value := Item.AsString;

      if SameText(Name, 'id') then
        WriteLn(Format('%s: %s', [aPrefix + Name, Value]));

      if Item.DataType = stArray then
        for ArrayItem in Item do
          ProcessObject(ArrayItem.AsObject, aPrefix + Name + '.');

      if Item.DataType = stObject then
        ProcessObject(Item.AsObject, aPrefix + Name + '.');
    end;
  end;
end;
Bolide answered 29/12, 2012 at 17:12 Comment(9)
if you have large json you dont have to write to parse each objectDruse
Can you post a modified version without using ProcessObject twice within ProcessObject makes it very hard to understand and read :)Druse
Sorry no, recursion is the natural fit for a composite structure. There might be other approaches, but my head won't fit around them.Bolide
Well i cannot pass other variables to the procedure then :( Now you have a procedure calling itself twice :DDruse
Why ever not? You pass them on the initial call from ParseJSON and pass them along with each subsequent call, either what you received or modified. Just modify the methods signature. If you are getting problems with the default value for the aPrefix, just remove that and call `ProcessObject(JSON, '') from ParseJSON. But anyway, if you have additional questions, you should really post a new question. SO is intended as a 1 post 1 question kinda thing.Bolide
Yes but i think this is a bad design. Because the procedure is calling itself twice instead of looping it.Druse
If you want to call it bad design, fine. A procedure or function calling itself is actually a very well known and accepted code construct. Look up "recursion". Yes, it takes some mind bending to get the hang of it, but it is a fundamental tool every programmer should have in his/her toolbox.Bolide
This is not bad design. This is excellent design. When you have a recursive data structure, you use recursive code.Secularism
@NunoJemaio And you expect me to do what with that? I already told you I can't get my head around a non-recursive solution for what you want. The data is recursive, recursive code is a natural fit, and I don't have the stomach to try anything else. Besides, going out in five minutes and not back until late.Bolide

© 2022 - 2024 — McMap. All rights reserved.