jsondelphidelphi-10.3-rio

JSON object- how to iterate through all properties without knowing their names?


I have a fairly simple JSON:

[
    {
      "hero-img": "girl-ipad.png",
      "main-story-headline": "How to Stay Mentally Healthy During a Pandemic",
      "main-story-paragraph": "lorem ipsum",
      "main-story-button-text": "Read More"
    },
    {
      "hero-img": "painter-woman.png",
      "main-story-headline": "How to Stay Mentally Healthy During a Pandemic",
      "main-story-paragraph": "lorem ipsum",
      "main-story-button-text": "Explore More"
    },
    {
      "hero-img": "old-man.png",
      "main-story-headline": "How to Stay Mentally Healthy During a Pandemic",
      "main-story-paragraph": "lorem ipsum",
      "main-story-button-text": "Get Yours Now"
    } ]

By using Delphi 10.3 Rio, I want to iterate through all properties no matter how they are named. I've started this way:

program JuTemplates;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, System.JSON, System.IOUtils, System.Types;

var
  root, OutputDir, TemplatesDir, JsonDir, jsonText: string;
  JsonFiles: TStringDynArray;
  i, j: Integer;
  JSONValue: TJSONObject;
  JSONValues: TJSONArray;
begin
  try

    try
      root := ExtractFilePath(ParamStr(0));
      OutputDir := root + 'OutputDir\';
      TemplatesDir := root + 'TemplatesDir\';
      JsonDir := root + 'JsonDir\';
      writeln('Processing: ' + JsonDir);
      JsonFiles := TDirectory.GetFiles(JsonDir);
      for i := 0  to High(JsonFiles) do
      begin
        jsonText := TFILE.ReadAllText(JsonFiles[i]);
        JSONValues := TJSONObject.ParseJSONValue(jsonText) as TJSONArray;

        for j := 0 to JSONValues.Count - 1 do
        begin
          JSONValue := JSONValues.Items[i] as TJSONObject;
          // here I should iterate through that JSONValue object
        end;
      end;
    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  finally
    writeln ('Press any key to continue');
    readln;
  end;
end.

Solution

  • To enumerate a JSONObject, you can use an enumerator like below.

    Use for..in loop (implicit enumerator)

    procedure TForm1.Button1Click(Sender: TObject);
    var
       JSONData       : String;
       JSONObject     : TJSONObject;
       JSONPair       : TJSONPair;
    begin
       JSONData   := '... some JSON data ...';   // Place you data here
       JSONObject := TJSonObject.ParseJSONValue(JSONData) as TJSONObject;
       try
         for JSONPair in JSONObject do
             ShowMessage(Format('1) Key=%s Value=%s',
                         [JSONPair.JsonString.ToString,
                          JSONPair.JsonValue.ToString]));
       finally
         JSONObject.Free;
       end;
    end;
    

    Use a classic for loop:

    procedure TForm1.Button1Click(Sender: TObject);
    var
       JSONData       : String;
       JSONObject     : TJSONObject;
       JSONPair       : TJSONPair;
       I              : Integer;
    begin
       JSONData   := '... some JSON data ...';   // Place you data here
       JSONObject := TJSonObject.ParseJSONValue(JSONData) as TJSONObject;
       try
         for I := 0 to JSONObject.Count - 1 do begin
           ShowMessage(Format('Key=%s Value=%s',
                       [JSONObject.Pairs[I].JsonString.ToString,
                        JSONObject.Pairs[I].JsonValue.ToString]));
         end;
       finally
         JSONObject.Free;
       end;
    end;
    

    Use an explicit enumerator and a while loop:

    procedure TForm1.Button1Click(Sender: TObject);
    var
       JSONData       : String;
       JSONObject     : TJSONObject;
       JSONEnumerator : TJSONObject.TEnumerator;
       JSONPair       : TJSONPair;
    begin
       JSONData   := '... some JSON data ...';   // Place you data here
       JSONObject := TJSonObject.ParseJSONValue(JSONData) as TJSONObject;
       try
         JSONEnumerator := JSONObject.GetEnumerator;
         try
           while JSONEnumerator.MoveNext do begin
             JSONPair := JSONEnumerator.Current;
             ShowMessage(Format('Key=%s Value=%s',
                         [JSONPair.JsonString.ToString,
                          JSONPair.JsonValue.ToString]));
           end;
         finally
           JSONEnumerator.Free;
         end;
       finally
         JSONObject.Free;
       end;
    end;
    

    Note that you may need to check if JSONPair.JsonValue has childs and enumerate those childs with another enumerator, recursively.