4

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"
  }]
}
bob_saginowski
  • 1,429
  • 2
  • 20
  • 35
  • 1
    Do you really need to hardcode those pairs creation? you can just pass the object to JSON-generator and ask him to read all the properties automatically http://stackoverflow.com/questions/7731833 – Arioch 'The Jul 29 '15 at 12:54

3 Answers3

10

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;
Caleth
  • 52,200
  • 2
  • 44
  • 75
2

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)]);
Stijn Sanders
  • 35,982
  • 11
  • 45
  • 67
0

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;

bob_saginowski
  • 1,429
  • 2
  • 20
  • 35
  • 2
    This arrives at a working result not really understanding what has gone wrong, and doens't explain itself – Caleth Jul 29 '15 at 11:26