1

So I'm talking to this webserver, and it's returning me a json entry like this:

{
 "result": [
  [],
  ["{\"success\": \"true\", \"Message\":\"User 1 has been deleted.\"}"]
 ]
}

{"result":[[],["{\"success\": \"true\", \"Message\":\"User 1 has been deleted.\"}"]]}

And I'm having trouble getting things out of it. Looking at it, I made a jsonobject, pulled the value of result and made it an array, then pulled the second entry of the first array as another array, then took that jsonstring and turned it into another jsonarray, then took the values out. but for some reason the first jsonarray claims to have two values, both of which are empty. I'm sure there are other errors in my approach past that point as well.

Can I get a hand ironing this thing out?

procedure DeleteUser;
var
 aJSON, aResult : String;
 aJsonResponse  : TJsonObject;
 aResultArrayA  : TJsonArray;
 aResultArrayB  : TJsonArray;
 aResultArrayC  : TJsonArray;
 aParsed        : TJsonValue;
 i              : Integer;
Begin
 aresult := '{"result":[[],["{\"success\": \"true\", \"Message\":\"User 1 has been deleted.\"}"]]}';
 aJsonResponse := TJsonObject.ParseJSONValue(aResult) as TJsonObject;
 if not (aJsonResponse is TJsonObject) then
    raise Exception.Create('InvalidResponse');
 aResultArrayA := aJsonResponse.getValue('result') as TJsonArray;
 if aResultArrayA.Count <= 0 then  //is 2
    raise Exception.Create('InvalidResponse');
 aJSON := aResultArrayA.Items[0].Value; // is ''
 aJSON := aResultArrayA.Items[1].Value; // is ''
 aResultArrayB :=  aResultArrayA.Items[0] as TJSONArray;
 if aResultArrayB.Count <= 0 then // is 0
    raise Exception.Create('InvalidResponse'); //raises here
 aJSON := aResultArrayB.Items[0].Value;
 aJSON := aResultArrayB.Items[1].Value;
 aResultArrayC := TJSONObject.ParseJSONValue(aResultArrayB.Items[1].Value) as TJSONArray;
 for aParsed in aResultArrayC do begin
    aJson := aJson + aParsed.GetValue<string>('success') + ' ';
    aJson := aJson + aParsed.GetValue<string>('message') + ' ';
 end;
end;

Thanks everyone.

2 Answers 2

1

I really think that the best way to work with JSON is serialization and deserialization. Yes, there is some situations when it's better to use parsing, but look at this:

uses ...,Rest.Json;

  TMyArray = ARRAY of ARRAY of string;
  //class for deserialization outer JSON object
  TMyParse = CLASS
    private
      FResult:TMyArray;
    procedure SetResult(const Value: TMyArray);
    public
      property result:TMyArray read FResult write SetResult;
  END;

  //class for deserialization inner JSON object
  TMyInnerParse = class
    private
      FSuccess:Boolean;
      FMessage:string;
      procedure SetMessage(const Value: String);
      procedure SetSuccess(const Value: Boolean);
    public
      property success:Boolean read FSuccess write SetSuccess;
      property message:String read FMessage write SetMessage;
  end;

procedure DeleteUser;
var
  OuterObj: TMyParse;
  InnerObj: TMyInnerParse;
  aResult: String;
  i,j: Integer;
Begin
 aResult := '{"result":[[],["{\"success\": \"true\", \"Message\":\"User 1 has been deleted.\"}"]]}';
 try
 OuterObj := TJson.JsonToObject<TMyParse>(aResult);
 if Length(OuterObj.result) > 0 then
 for i := 0 to Length(OuterObj.result) - 1 do
   if length(OuterObj.result[i]) > 0 then
   for j := 0 to Length(OuterObj.result[i]) - 1 do
    begin
      try
        InnerObj := TJson.JsonToObject<TMyInnerParse>(OuterObj.result[i][j]);
        //Do your work with result, that in InnerObj now
      finally
        if assigned(InnerObj) then
           FreeAndNil(InnerObj);
      end;
    end;
 finally
    if assigned(OuterObj) then
       FreeAndNil(OuterObj);
 end;
end;

procedure TMyParse.SetResult(const Value: TMyArray);
begin
  FResult := value;
end;

procedure TMyInnerParse.SetMessage(const Value: String);
begin
  FMessage := value;
end;
procedure TMyInnerParse.SetSuccess(const Value: Boolean);
begin
  FSuccess := value;
end;

For cycles in this code are awful, but it's the fastest way to show how you can solve your problem. And it's working.

I don't know what information can be in first empty array and this can be the reason for exceptions. Look at this code as working example, not full solution because lack of information.

It was tested on Delphi 10.1: Result from Delphi 10.1

P.S. Using arrays are very old way of coding in this situation. But some time ago I met problem with serializing/deserializing TList and TObjectList. I'll try to use them and will return with result.

P.P.S. It tried to use TList, but my attempt fails. Maybe someone can describe how to implement it in a code above.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for this, +1 for working code, but I ended up going with the answer I found instead.
1

Found these functions in system.JSON and they just clicked for me.

/// <summary>Finds a JSON value and returns reference to it. </summary>
/// <remarks> Raises an exception when a JSON value could not be found. </remarks>
property P[const APath: string]: TJSONValue read GetValueP;{ default;}
property A[const AIndex: Integer]: TJSONValue read GetValueA;


var
 aSuccess, aMessage : String
 aJSON : TJSONObject;
begin
  var aJSON:= TJSONObject.ParseJSONValue('{"result":[[],["{\"success\": \"true\", \"Message\":\"User  has been deleted.\"}"]]}');
    aSuccess := TJSONObject.ParseJSONValue(aJSON.P['result'].A[1].A[0].AsType<String>).P['success'].AsType<String>;
    aMessage := TJSONObject.ParseJSONValue(aJSON.P['result'].A[1].A[0].AsType<String>).P['Message'].AsType<String>;
end;

Note that this needs exception handling, all of these functions will throw an exception if they fail to find the specified property.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.