JSON nested object shows empty in rest debugger and RestResponse (XE6) - json

I use C++Builder XE6 Pro and have the following JSON response (see the full response here):
[
{
"id":"10186",
"dataset":"krs_podmioty",
"url":"https://api-v3.mojepanstwo.pl/dane/krs_podmioty/10186",
"mp_url":"https://mojepanstwo.pl/dane/krs_podmioty/10186",
"schema_url":"https://api-v3.mojepanstwo.pl/schemas/dane/krs_podmioty.json",
"global_id":"3157847",
"slug":"bank-millennium",
"score":12.13878,
"data":
{
"krs_podmioty.nazwa_organu_reprezentacji":"ZARZĄD",
"krs_podmioty.dotacje_ue_beneficjent_id":"0",
"krs_podmioty.liczba_prokurentow":0,
...
"gpw":true
}
...
]
I am using REST components, but when I try to parse this, both in the REST Debugger and at design/run-time, I am getting empty values for the "dataset":"krs_podmioty" elements, but the "gpw":true elements show correctly.
I've choosen the JSON root element as DataObject, and marked Nested
and set NestedElementDepth to 3. I have tried another settings as well, but without success.
How to get the "dataset":"krs_podmioty" values correctly ?

This is how I'm able to read those values:
uses
System.Json;
procedure TForm1.Button1Click(Sender: TObject);
var
jsonText: string;
jsonArray: TJsonArray;
dataObj: TJsonObject;
Jobj: TJsonObject;
krsPodmiotyNazwaOrganuReprezentacjiValue: TJsonValue;
krsPodmiotyDotacjeUeBeneficjentIdValue: TJsonValue;
krsPodmiotyLiczbaProkurentowValue: TJsonValue;
begin
jsonText := '[{Your JSON content here}]';
Jobj := TJSONObject.ParseJSONValue(jsonText) as TJsonObject;
jsonArray :=Jobj.GetValue('Dataobject') as TJsonArray;
dataObj := (jsonArray.Items[0] as TJsonObject).GetValue('data') as TJsonObject;
krsPodmiotyNazwaOrganuReprezentacjiValue := dataObj.GetValue('krs_podmioty.nazwa_organu_reprezentacji');
krsPodmiotyDotacjeUeBeneficjentIdValue := dataObj.GetValue('krs_podmioty.dotacje_ue_beneficjent_id');
krsPodmiotyLiczbaProkurentowValue := dataObj.GetValue('krs_podmioty.liczba_prokurentow');
MessageDlg(krsPodmiotyNazwaOrganuReprezentacjiValue.Value, mtInformation, [mbOK], 0, mbOK);
MessageDlg(krsPodmiotyDotacjeUeBeneficjentIdValue.Value, mtInformation, [mbOK], 0, mbOK);
MessageDlg(krsPodmiotyLiczbaProkurentowValue.Value, mtInformation, [mbOK], 0, mbOK);
end;
However, if you are not using anything from the System.Json namespace, this might not answer your question.

Related

Parsing a JSON string that contains an array of an array of a string of another jsonstring in Delphi

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.
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:
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.
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.

delphi what is difference of [ and { in json array

I have a JSON string and need to parse it
JsonString :='{"uid":"1","full_name":"test","user_name":"test","mobile":"0999","send_sms":""' +',"recieve_sms":"","mob_app":"","password":"test","email":"","credit":"0.00","status":"agent","add_date":"2020-01-04 13:05:32","agent":"0","theme":""}';
LJsonArr := TJSONObject.ParseJSONValue(JsonString) as TJSONArray;
for LJsonValue in LJsonArr do
begin
for LItem in TJSONArray(LJsonValue) do begin
memo1.Lines.Add(Format('%s : %s',[TJSONPair(LItem).JsonString.Value, TJSONPair(LItem).JsonValue.Value]));
end;
end;
this not working but if I put JSON string in a [] the code work well.
what is the difference of [{}] with {} or [] and how can I process my string with just {}
Your code doesn't work because the JSON in question does not contain any arrays at all, so all of your typecasts to TJSONArray are wrong. The JSON represents a single object (a TJSONObject) containing name/value pairs of strings, nothing more.
By surrounding the JSON with [], you create an array that contains 1 element, an object. So your outer loop is satisfied, but your inner loop is still wrong since it would need to typecast LJsonValue to TJSONObject rather than TSONArray.
To process the original JSON correctly, try this instead:
JsonString :='{"uid":"1","full_name":"test","user_name":"test","mobile":"0999","send_sms":""' +',"recieve_sms":"","mob_app":"","password":"test","email":"","credit":"0.00","status":"agent","add_date":"2020-01-04 13:05:32","agent":"0","theme":""}';
LJsonValue := TJSONObject.ParseJSONValue(JsonString);
if LJsonValue <> nil then
try
LJsonObj := LJsonValue as TJSONObject;
for LJsonPair in LJsonObj do
begin
Memo1.Lines.Add(Format('%s : %s',[LJsonPair.JsonString.Value, LJsonPair.JsonValue.Value]));
end;
finally
LJsonValue.Free;
end;

Delphi. Parse JSON

I'm trying to parse JSON string (http://pastebin.com/zXn8pwtL):
sListing contains JSON string
jsObj: TJSONObject;
jsItem, jsElem, jsAsserts: TJSONValue;
...
jsObj := TJSONObject.ParseJSONValue(sListing) as TJSONObject;
jsAsserts := TJSONObject(TJSONObject(jsObj.Get('assets').JsonValue).Get('730').JsonValue).Get('2').JsonValue;
for jsElem in TJSONArray(jsAsserts) do
WriteLn(jsElem.ToString);
How can I get all values from jsElem->descriptions? I've tried to enum all:
for jsItem in TJSONArray(jsElem) do
WriteLn(jsItem.ToString);
But got EAccessViolation Read of address 00000001
Ok. Thanks for all. It was some misunderstanding with JSON types. It is fixed now:
jsAsserts: TJSONObject;
jsDesc: TJSONArray;
iCurEl: integer;
jsItem: TJSONPair;
...
jsAsserts := TJSONObject(TJSONObject(jsObj.Get('assets').JsonValue).Get('730').JsonValue).Get('2').JsonValue as TJSONObject;
for iCurEl := 0 to jsAsserts.Count - 1 do
begin
jsItem := jsAsserts.Pairs[iCurEl];
jsDesc := (jsItem.JsonValue as TJSONObject).Get('descriptions').JsonValue as TJSONArray;
WriteLn(jsDesc.ToString);
end;

JSON parsing "NULL"

I have this code working until today. If there is for egxample this:
"status":null
there will be exception "Invalid class type". How to fix it? Thanks for help.
procedure TForm1.Button10Click(Sender: TObject);
var
IdHTTP: TIdHTTP;
IdSSL: TIdSSLIOHandlerSocketOpenSSL;
JSON: string;
jsonObiekt: TJSONObject;
streams: TJSONArray;
stream: TJSONObject;
channel: TJSONObject;
status: TJSONString;
liczbaStrumieni: integer;
i: integer;
begin
IdHTTP := TIdHTTP.Create;
try
IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
IdHTTP.IOHandler := IdSSL;
IdHTTP.Request.Accept := 'application/vnd.twitchtv.v3+json';
IdHTTP.Request.CustomHeaders.AddValue('Client-ID', 'smb61nyd0vxmqdn9d3k735qbx41cdyg');
JSON := IdHTTP.Get('https://api.twitch.tv/kraken/streams?game=StarCraft:%20Brood%20War');
finally
IdHTTP.Free;
end;
jsonObiekt := TJSONObject.ParseJSONValue(JSON) as TJSONObject;
try
streams := jsonObiekt.Get('streams').JsonValue as TJSONArray;
liczbaStrumieni := streams.Size;
for i := 0 to liczbaStrumieni - 1 do
begin
stream := streams.Get(i) as TJSONObject;
channel := stream.Get('channel').JsonValue as TJSONObject;
status := channel.Get('status').JsonValue as TJSONString;
Memo6.Lines.Add(status.Value);
end;
finally
jsonObiekt.Free;
end;
end;
I see from the comments that you're familiar with the JSON specification on JSON.org. Your problem appears to be with understanding how it maps to the DBXJSON model.
Specifically, TJSONObject represents an Object as defined by the JSON standard. It does not mean "a (Delphi) object that holds JSON data." That's what TJSONValue is there for. Try using that instead.

Extracting/parsing data returned as JSON from PHP

I'm getting JSON data back from a PHP call using TIdHTTP. I'm expecting to use TJSONObject but can't work out how to use it for this purpose. And there are no examples in the XE3 help.
Sample JSON data
[{"fleet_id":"2","fleet":"EMB195"},{"fleet_id":"3","fleet":"EMB175"},{"fleet_id"‌:"1","fleet":"DHC84-400Q"}]
I'm sure this is simple, but how!
Thanks.
Use TJsonObject.ParseJsonValue to convert the input string into a JSON value:
var
val: TJsonValue;
s := '[{"fleet_id":"2","fleet":"EMB195"},{"fleet_id":"3","fleet":"EMB175"},{"fleet_id"‌:"1","fleet":"DHC84-400Q"}]';
val := TJsonObject.ParseJsonValue(s);
In this case, the JSON happens to represent an array, so you can type-cast it to that:
var
arr: TJsonArray;
arr := val as TJsonArray;
You can access the elements of the array with Get, and type-cast the results to TJsonObject.
var
i: Integer;
elem: TJsonObject;
for i := 0 to Pred(arr.Size) do begin
elem := arr.Get(i) as TJsonObject;
end;
To inspect the properties of the object, you can use the Get method, which returns a TJsonPair holding the name and value.