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.

Jan Doggen
  • 8,799
  • 13
  • 70
  • 144
Nuno Jemaio
  • 163
  • 2
  • 11

1 Answers1

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;
Marjan Venema
  • 19,136
  • 6
  • 65
  • 79
  • if you have large json you dont have to write to parse each object – Nuno Jemaio Dec 29 '12 at 18:54
  • Can you post a modified version without using ProcessObject twice within ProcessObject makes it very hard to understand and read :) – Nuno Jemaio Dec 30 '12 at 10:24
  • Sorry no, recursion is the natural fit for a composite structure. There might be other approaches, but my head won't fit around them. – Marjan Venema Dec 30 '12 at 10:26
  • Well i cannot pass other variables to the procedure then :( Now you have a procedure calling itself twice :D – Nuno Jemaio Dec 30 '12 at 10:27
  • 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. – Marjan Venema Dec 30 '12 at 10:30
  • Yes but i think this is a bad design. Because the procedure is calling itself twice instead of looping it. – Nuno Jemaio Dec 30 '12 at 10:34
  • 1
    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. – Marjan Venema Dec 30 '12 at 10:37
  • 1
    This is not bad design. This is excellent design. When you have a recursive data structure, you use recursive code. – David Heffernan Dec 30 '12 at 11:46
  • 1
    @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. – Marjan Venema Dec 30 '12 at 12:16