var
  jo: ISuperObject;
  jts: TSuperTableString;
begin 
  jo: = SO ('{A: 1, B: 2, C: 3, D: {x: 4, y: 5, z: 6}}');

  jts: = jo.AsObject;
  ShowMessage (IntToStr (jts.count));     // 4
  ShowMessage (jts.GetNames.AsString);   // ["D", "C", "B", "A"]
  ShowMessage (jts.GetValues.AsString); // [{"z": 6, "y": 5, "x": 4}, 3,2,1]

  jts: = jo ['D'] .AsObject;
  ShowMessage (IntToStr (jts.count));     // 3
  ShowMessage (jts.GetNames.AsString);   // ["z", "y", "x"]
  ShowMessage (jts.GetValues.AsString); // [6,5,4]
end ;


JSON is essentially a binary tree (SuperObject supports 32 layers of depth, which is enough);

each node of the binary tree mainly represents a Name: Value; where Name is a string, Value may be a string, integer, array, or another ISuperObject, so The type of Value can only be ISuperObject.

The class describing this node is TSuperAvlEntry, we can enumerate the current layer and each TSuperAvlEntry from a TSuperTableString.

var
  jo, io: ISuperObject;
  item: TSuperAvlEntry;
begin 
  jo: = SO ('{A: 1, B: 2, C: 3, D: {x: 4, y: 5, z: 6}}');

  {Enum TSuperAvlEntry from TSuperTableString (here is obtained with jo.AsObject)}
  Memo1.Clear;
  for itemin jo.AsObjectdo 
    Memo1.Lines.Add (Format ('Name:% s; Value:% s', [item.Name, item.Value.AsString]));

  {Enumerate "child ISuperObject" directly from ISuperObject}
  Memo1.Lines.Add (EmptyStr);
  for ioin jodo 
    Memo1.Lines.Add (Format ('Value:% s', [io.AsString]));
end ;


The above traversal did not go deep. To thoroughly traverse, you need to write a callback function.

Below are two callback functions, the first one does not consider the objects in the array:

uses SuperObject;

// One of the traversal processes using callbacks: the objects in the array are not considered
procedure Proc1 (jo: ISuperObject;var List: TStrings);
var
  item: TSuperAvlEntry;
begin
  for itemin jo.AsObjectdo
    if item.Value.DataType = stObjectthen 
      Proc1 (item.Value, List) {Callback if it is an object}
    else  {Add to list if it is not an object}
      List.Add (Format ('% s:% s', [item.Name, item.Value.AsString])); 
end ;

// The second traversal process using callbacks:
procedure Proc2 (jo: ISuperObject;var List: TStrings);
var
  i: Integer;
  item: TSuperAvlEntry;
begin
  for itemin jo.AsObjectdo
  begin
    if item.Value.DataType = stObjectthen 
      Proc2 (item.Value, List) {Callback if it is an object}
    else begin  {Add to list if it is not an object}
      List.Add (Format ('% s:% s', [item.Name, item.Value.AsString]));
      if item.Value.DataType = stArraythen begin  {if it is an array, see if there are objects in it}
        for i: =0 to item.Value.AsArray.Length-1 do
          if item.Value.AsArray [i] .DataType = stObjectthen 
            Proc2 (item.Value.AsArray [i], List); { Call back if it is an object}
      end ;
    end ;
  end ;
end ;

// call test
procedure TForm1.Button1Click (Sender: TObject);
var
  jo: ISuperObject;
  List: TStrings;
begin 
  jo: = SO ('{A: 1, B: 2, C: 3, D: [4, 5, {X: 6}, {Y: [7,8, {m: 9}]}]}');

  List: = TStringList.Create;
  Proc1 (jo, List);
  ShowMessage (List.Text);

  List.Clear;
  Proc2 (jo, List);
  ShowMessage (List.Text);

  List.Free;
end ;