Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Build JSON with Delphi

Tags:

json

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"
  }]
}
like image 734
bob_saginowski Avatar asked Dec 20 '22 01:12

bob_saginowski


2 Answers

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;
like image 174
Caleth Avatar answered Dec 24 '22 00:12

Caleth


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)]);
like image 35
Stijn Sanders Avatar answered Dec 24 '22 00:12

Stijn Sanders