bob_saginowski
bob_saginowski

Reputation: 1429

Build JSON with Delphi

I'm trying to implement a function which returns a json object containing elements of class. Here is my function:

procedure ListToJson(AInputList: TList<TRating>;
  AResponse: TJSONObject);
var
  i: Integer;
  jsonPair: TJSONPair;
  jsonObject: TJSONObject;
  jsonArray: TJSONArray;
begin
  jsonArray := TJSONArray.Create();
  jsonObject := TJSONObject.Create();
  jsonPair := TJSONPair.Create('ratings', jsonArray);

  for i := 0 to AInputList.Count - 1 do
  begin
    jsonObject.AddPair(TJSONPair.Create('idrating', IntToStr(AInputList[i].IdRating)));
    jsonObject.AddPair(TJSONPair.Create('idmark', IntToStr(AInputList[i].IdMark)));
    jsonObject.AddPair(TJSONPair.Create('value', IntToStr(AInputList[i].Value)));
    jsonObject.AddPair(TJSONPair.Create('description', AInputList[i].Description));
    jsonObject.AddPair(TJSONPair.Create('timeposted', FormatDateTime('yyyy-mm-dd hh:mm:ss', AInputList[i].TimePosted)));

    jsonArray.AddElement(jsonObject);
  end;

  AResponse.AddPair(jsonPair);
 end;

And when I test it with a list which contains two elements the returned string is:

{
  "ratings":[{
      "idrating":"1",
      "idmark":"0",
      "value":"0",
      "description":"",
      "timeposted":"2015-07-29 11:25:03",
      "idrating":"2",
      "idmark":"0",
      "value":"0",
      "description":"",
      "timeposted":"2015-07-29 11:25:24"
  },{
      "idrating":"1",
      "idmark":"0",
      "value":"0",
      "description":"",
      "timeposted":"2015-07-29 11:25:03",
      "idrating":"2",
      "idmark":"0",
      "value":"0",
      "description":"",
      "timeposted":"2015-07-29 11:25:24"
  }]
} 

I tried to remove all pairs after each loop iteration:

procedure ListToJson(AInputList: TList<TRating>;
  AResponse: TJSONObject);
var
  i: Integer;
  jsonPair: TJSONPair;
  jsonObject: TJSONObject;
  jsonArray: TJSONArray;
begin
  jsonArray := TJSONArray.Create();
  jsonObject := TJSONObject.Create();
  jsonPair := TJSONPair.Create('ratings', jsonArray);

  for i := 0 to AInputList.Count - 1 do
  begin
    jsonObject.AddPair(TJSONPair.Create('idrating', IntToStr(AInputList[i].IdRating)));
    jsonObject.AddPair(TJSONPair.Create('idmark', IntToStr(AInputList[i].IdMark)));
    jsonObject.AddPair(TJSONPair.Create('value', IntToStr(AInputList[i].Value)));
    jsonObject.AddPair(TJSONPair.Create('description', AInputList[i].Description));
    jsonObject.AddPair(TJSONPair.Create('timeposted', FormatDateTime('yyyy-mm-dd hh:mm:ss', AInputList[i].TimePosted)));

    jsonArray.AddElement(jsonObject);
    jsonObject.RemovePair('idrating');
    jsonObject.RemovePair('idmark');
    jsonObject.RemovePair('value');
    jsonObject.RemovePair('description');
    jsonObject.RemovePair('timeposted');
  end;

  AResponse.AddPair(jsonPair);
 end;

And the ouput is an array with n(count of list elements) empty objects: {"ratings":[{},{}]}

And the json I'm trying to build should be like:

{
  "ratings":[{
    "idrating":"1",
    "idmark":"0",
    "value":"0",
    "description":"",
    "timeposted":"2015-07-29 11:25:03"
  },{
    "idrating":"2",
    "idmark":"0",
    "value":"0",
    "description":"",
    "timeposted":"2015-07-29 11:25:24"
  }]
}

Upvotes: 4

Views: 25140

Answers (3)

Stijn Sanders
Stijn Sanders

Reputation: 36840

Is it me, or is that just really ugly (and codous, or what's the word for a lot of code for what it does). Since I really (really) hate to see long lists of overloads for all kinds of types, and really (really) like the Variant type, I've created jsonDoc, and it would look like this:

var
  x:array of OleVariant;
  i:integer;
begin
  SetLength(x,AInputList.Count);
  for i:=0 to AInputListCount-1 do
    x[i]:=JSON(
      ['idrating',AInputList[i].IdRating
      ,'idmark',AInputList[i].IdMark
      ,'value',AInputList[i].Value
      ,'description',AInputList[i].Description
      ,'timeposted',FormatDateTime('yyyy-mm-dd hh:mm:ss', AInputList[i].TimePosted)//VarFromDateTime?
      ]);
  end;
  AResponse:=JSON(['ratings',VarArrayOf(x)]);

Upvotes: 2

Caleth
Caleth

Reputation: 62531

You have one jsonObject, so whatever state it ends up in is repeated each time you add it to the array.

Construct jsonObject within the loop, and then you will have different objects in your array.

  for i := 0 to AInputList.Count - 1 do
  begin
    jsonObject := TJSONObject.Create();
    jsonObject.AddPair(TJSONPair.Create('idrating', IntToStr(AInputList[i].IdRating)));
    jsonObject.AddPair(TJSONPair.Create('idmark', IntToStr(AInputList[i].IdMark)));
    jsonObject.AddPair(TJSONPair.Create('value', IntToStr(AInputList[i].Value)));
    jsonObject.AddPair(TJSONPair.Create('description', AInputList[i].Description));
    jsonObject.AddPair(TJSONPair.Create('timeposted', FormatDateTime('yyyy-mm-dd hh:mm:ss', AInputList[i].TimePosted)));

    jsonArray.AddElement(jsonObject);
  end;

Alternatly, you can define a function to create a TJSONObject from a TRating, and use that in your loop

function TRatingToJSON( Rating: TRating ): TJSONObject;
begin
  Result := TJSONObject.Create();

  Result.AddPair(TJSONPair.Create('idrating', IntToStr(Rating.IdRating)));
  Result.AddPair(TJSONPair.Create('idmark', IntToStr(Rating.IdMark)));
  Result.AddPair(TJSONPair.Create('value', IntToStr(Rating.Value)));
  Result.AddPair(TJSONPair.Create('description', Rating.Description));
  Result.AddPair(TJSONPair.Create('timeposted', FormatDateTime('yyyy-mm-dd hh:mm:ss', Rating.TimePosted)));
end;

procedure ListToJson(AInputList: TList<TRating>;
  AResponse: TJSONObject);
var
  i: Integer;
  jsonArray: TJSONArray;
begin
  jsonArray := TJSONArray.Create();

  for i := 0 to AInputList.Count - 1 do
  begin
    jsonArray.AddElement(TRatingToJSON(AInputList[i]));
  end;

  AResponse.AddPair(TJSONPair.Create('ratings', jsonArray));
 end;

Upvotes: 10

bob_saginowski
bob_saginowski

Reputation: 1429

Found a workraround:

procedure ListToJson(AInputList: TList<TRating>;
  AResponse: TJSONObject);
var
  i: Integer;
  jsonPair: TJSONPair;
  jsonObject: TList<TJSONObject>;
  jsonArray: TJSONArray;
begin
  jsonArray := TJSONArray.Create();
  jsonObject := TList<TJSONObject>.Create;
  jsonPair := TJSONPair.Create('ratings', jsonArray);

  try
    for i := 0 to AInputList.Count - 1 do
    begin
      jsonObject.Add(TJSONObject.Create());

      jsonObject.Last.AddPair(TJSONPair.Create('idrating', IntToStr(AInputList[i].IdRating)));
      jsonObject.Last.AddPair(TJSONPair.Create('idmark', IntToStr(AInputList[i].IdMark)));
      jsonObject.Last.AddPair(TJSONPair.Create('value', IntToStr(AInputList[i].Value)));
      jsonObject.Last.AddPair(TJSONPair.Create('description', AInputList[i].Description));
      jsonObject.Last.AddPair(TJSONPair.Create('timeposted', FormatDateTime('yyyy-mm-dd hh:mm:ss', AInputList[i].TimePosted)));

      jsonArray.AddElement(jsonObject.Last);
    end;

  AResponse.AddPair(jsonPair);
finally
  jsonObject.Free;
end;

end;

Upvotes: 0

Related Questions