Parse JSON using lkJSON - json

I have a JSON file which I need to parse and extract one value.
{
"user": {
"pk": 25025320,
"username": "instagram",
"full_name": "Instagram",
"is_private": false,
"profile_pic_url": "https://instagram.fmad3-5.fna.fbcdn.net/vp/295f9e76d3c26fdf613d7856e7b43348/5B4F495B/t51.2885-19/s150x150/14719833_310540259320655_1605122788543168512_a.jpg",
"profile_pic_id": "1360316971354486387_25025320",
"is_verified": true,
"has_anonymous_profile_picture": false,
"media_count": 5164,
"follower_count": 233901016,
"following_count": 187,
"biography": "Discovering — and telling — stories from around the world.",
"external_url": "",
"usertags_count": 144,
"hd_profile_pic_versions": [
{
"width": 320,
"height": 320,
"url": "https://instagram.fmad3-5.fna.fbcdn.net/vp/893534d61bdc5ea6911593d3ee0a1922/5B6363AB/t51.2885-19/s320x320/14719833_310540259320655_1605122788543168512_a.jpg"
}
],
"hd_profile_pic_url_info": {
"url": "https://instagram.fmad3-5.fna.fbcdn.net/vp/8ae8a89c80ff4722eeab592b685276cb/5B5D40A1/t51.2885-19/14719833_310540259320655_1605122788543168512_a.jpg",
"width": 320,
"height": 320
},
"has_highlight_reels": true,
"auto_expand_chaining": false
},
"status": "ok"
}
I want to extract and send the value of hd_profile_pic_url_info.url to Memo2 using the lkJSON library, Instagram API and code below to achievie this result.
var
sJSON: string;
js, Items, Item: TlkJSONbase;
I, J: Integer;
begin
sJSON := Memo1.text;
js := TlkJSON.ParseText(sJSON);
for I := 0 to Pred(js.Count) do
begin
Items := js.Child[I].Field['user'];
for J := 0 to Pred(Items.Count) do
begin
Item := Items.Child[J];
Memo2.Lines.Add(VarToStr(Item.Field['hd_profile_pic_url_info'].Value));
end;
end;
end;

You forgot that hd_profile_pic_url_info is another object containing url, width, and height, so you need to go down one more time. Here is an example of how this should be done properly.
var
js : TlkJSONbase;
begin
js := TlkJSON.ParseText(Memo1.Text);
if Assigned(js) then
begin
js := js.Field['user'];
if Assigned(js) then
begin
js := js.Field['hd_profile_pic_url_info'];
if Assigned(js) then
begin
js := js.Field['url'];
if Assigned(js) then
Memo2.Lines.Add(VarToStr(js.Value));
end;
end;
end;
end;

i use this function :
function ChildValueStr(AChild: TlkJSONbase; const Name: string; DefaultValue:
AnsiString = ''): {$IF CompilerVersion>=26}WideString{$ELSE}AnsiString{$IFEND};
var
tmpIndex: integer;
tmpStr: {$IF CompilerVersion>=26}WideString{$ELSE}AnsiString{$IFEND};
begin
Result:= DefaultValue;
if IsNil(AChild) then exit;
tmpStr:= (AChild as TlkJSONobject).{$IF CompilerVersion>=26}getWideString{$ELSE}getString{$IFEND}(Name);
if tmpStr = '' then
begin
tmpIndex := (AChild as TlkJSONobject).IndexOfName(Name);
if tmpIndex <> -1 then
Result := (AChild as TlkJSONobject).getString(tmpIndex);
end
else Result:= tmpStr;
end;
so with your code, you can use it :
var sJSON: String;
js, Items, Item: TlkJSONBase;
I, J: Integer;
begin
sJSON := Memo1.text;
js := TlkJSON.ParseText(sJSON);
for I := 0 to Pred(js.Count) do
begin
Items := js.Child[I].Field['user'];
Memo2.Lines.Add(ChildValueStr(Items, 'hd_profile_pic_url_info'));
end;
end;
I hope this can help u

Another alternative to parse JSON without use external components is the free online service https://jsontodelphi.com/
You paste the JSON text and it generate a unit with delphi classes to parse the text without problems. Better if the JSON text is complicated.
In this case, the code to access to the value is simpliest:
procedure TForm2.Button1Click(Sender: TObject);
var
root:TRootClass;
begin
root := TRootClass.FromJsonString(Memo1.Lines.Text {your JSON text});
// The caption get the URL of the pic
Caption := root.user.hd_profile_pic_url_info.url;
end;

Related

Delphi pointer variable required

I am trying to create a global procedure which can append a JSON field to a main JSON object dynamically.
procedure TJSONAdapter.addField(Key, Field: String);
var
i: Integer;
strArr: TStringList;
j: Integer;
pJSONObj: ^TJSONObject;
begin
strArr:= TStringList.Create;
Split('.', Key, strArr);
pJSONObj:= #STATICJSON;
i:= 0;
repeat
begin
if IsSimpleJsonValue(STATICJSON.GetValue(strArr[i])) then
begin
Exit;
end;
if STATICJSON.GetValue(strArr[i]) is TJSONObject then
begin
pJSONObj:= #(STATICJSON.GetValue(strArr[i]) as TJSONObject); -> error in this line
if i + 1 = strArr.Count then
begin
I store my values in a JSON object named STATICJSON until the program closes, and then I save it to file.
I am trying to add a field somewhere in STATICJSON. For example;
{
"colors" :
{
"id": "F00",
"color": "red",
"details" : [
{
"name_en": "Red",
},
{
"name_de": "Rot"
}
]
},
{
"id": "0F0",
"color": "green",
"details" : [
{
"name_en": "Green",
},
{
"name_de": "Grün"
}
]
}
}
If I want to add a code field in every details of the first object in the colors array:
obj.addField('colors.0.details.X', 'code');
What I expected :
{
"colors" :
{
"id": "F00",
"color": "red",
"details" : [
{
"name_en": "Red",
"code": ""
},
{
"name_de": "Rot",
"code": ""
}
]
},
{
"id": "0F0",
"color": "green",
"details" : [
{
"name_en": "Green",
},
{
"name_de": "Grün"
}
]
}
}
So I am trying to go to the details array of the first color and addField using a pointer.
I was using:
STATICJSON:= STATICJSON.GetValue(strArr[i]) as TJSONObject;
and it works well, but STATICJSON content is changed to this:
"details" : [
{
"name_en": "Red",
"code": ""
},
{
"name_de": "Rot",
"code": ""
}
]
So I lost all other JSON content. This is why I want to use a pointer. But I'm getting an error on this line:
pJSONObj:= #(STATICJSON.GetValue(strArr[i]) as TJSONObject);
Variable required
UPDATE :
procedure TJSONAdapter.addField(Key, Field: String);
var
i: Integer;
strArr: TStringList;
j: Integer;
begin
strArr:= TStringList.Create;
Split('.', Key, strArr);
i:= 0;
repeat
begin
if IsSimpleJsonValue(STATICJSON.GetValue(strArr[i])) then
begin
Exit;
end;
if STATICJSON.GetValue(strArr[i]) is TJSONObject then
begin
STATICJSON:= STATICJSON.GetValue(strArr[i]) as TJSONObject;
if i + 1 = strArr.Count then
begin
STATICJSON.AddPair(TJSONPair.Create(Field, ''));
Exit;
end;
end;
if STATICJSON.GetValue(strArr[i]) is TJSONArray then
begin
if strArr[i + 1] = 'X' then
begin
for j := 0 to (STATICJSON.GetValue(strArr[i]) as TJSONArray).Size -1 do
begin
((STATICJSON.GetValue(strArr[i]) as TJSONArray).Get(j) as TJSONObject).AddPair(TJSONPair.Create(Field, ''));
end;
Exit;
end;
STATICJSON:= (STATICJSON.GetValue(strArr[i]) as TJSONArray).Get(StrToInt(strArr[i+1])) as TJSONObject;
i:= i+1;
end;
Inc(i);
end;
until i = strArr.Count;
strArr.Free;
end;
It works, but because of these lines:
STATICJSON:= STATICJSON.GetValue(strArr[i]) as TJSONObject;
STATICJSON:= (STATICJSON.GetValue(strArr[i]) as TJSONArray).Get(StrToInt(strArr[i+1])) as TJSONObject;
I lost the main JSON content, so I don't want to assign STATICJSON, i just want to assign its address to a pointer to not lose its content.
Delphi objects are reference types. TJSONObject is already a pointer, so there is no need to use ^TJSONObject.
Try something more like this:
var
STATICJSON: TJSONObject = nil;
procedure TJSONAdapter.addField(Key, Field: String);
var
I, J, Index: Integer;
strArr: TStringList;
pJSONVal: TJSONValue;
begin
strArr := TStringList.Create;
try
Split('.', Key, strArr);
if STATICJSON = nil then begin
STATICJSON := TJSONObject.Create;
end;
pJSONVal := STATICJSON;
For I := 0 to strArr.Count-1 then
begin
if TryStrToInt(strArr[I], Index) then
begin
if not (pJSONVal is TJSONArray) then Exit;
pJSONVal := TJSONArray(pJSONVal).Get(Index);
end
else if strArr[I] = '*' then
begin
if I <> (strArr.Count-1) then Exit;
if not (pJSONVal is TJSONArray) then Exit;
with TJSONArray(pJSONVal) do
begin
For J := 0 to Count-1 do
begin
pJSONVal := Get(Index);
if pJSONVal is TJSONObject then
TJSONObject(pJSONVal).AddPair(Field, '');
end;
end;
end
else if pJSONVal is TJSONObject then
begin
pJSONVal := TJSONObject(pJSONVal).Get(strArr[I]);
if pJSONVal = nil then Exit;
end
else Exit;
end;
if pJSONVal is TJSONObject then
TJSONObject(pJSONVal).AddPair(Field, '');
finally
strArr.Free;
end;
end;
obj.addField('colors.0.details.*', 'code');

Inno Setup: Change value in JSON array

I would like to create an installer with the help of Inno Setup. In order to make the program work on every computer, I need to change the tool directory in a .json-file. Here is an excerpt from this file:
{
"commandScriptLinux" : "",
"copyToolBehavior" : "once",
"deleteWorkingDirectoriesAfterWorkflowExecution" : true,
"deleteWorkingDirectoriesKeepOnErrorOnce" : true,
"deleteWorkingDirectoriesNever" : true,
"documentationFilePath" : "",
"enableCommandScriptWindows" : true,
"imitationScript" : "",
"imitationToolOutputFilename" : "",
"launchSettings" :
[
{
"limitInstallationInstancesNumber" : "1",
"limitInstallationInstances" : "false",
"toolDirectory" : "%Selected Setup Folder%",
"version" : "1.0"
}
],
}
I hoped to solve this by using the inno-json-config library. Unfortunately, after executing the code, the lines are reversed (last line comes first now) and the changes weren't made.
[Setup]
AppName=Change_Config
AppVersion=1.0
DefaultDirName={userdocs}\Change_Config
[Files]
Source: "JSONConfig.dll"; Flags: dontcopy
[Code]
function JSONQueryString(FileName, Section, Key, Default: WideString;
var Value: WideString; var ValueLength: Integer): Boolean;
external 'JSONQueryString#files:jsonconfig.dll stdcall';
function JSONWriteString(FileName, Section, Key,
Value: WideString): Boolean;
external 'JSONWriteString#files:jsonconfig.dll stdcall';
procedure InitializeWizard;
var
FileName: WideString;
IntValue: Int64;
StrValue: WideString;
StrLength: Integer;
BoolValue: Boolean;
begin
FileName := 'c:\configuration.json';
SetLength(StrValue, 16);
StrLength := Length(StrValue);
if JSONQueryString(
FileName, 'launchSettings', 'toolDirectory', 'Default', StrValue, StrLength) then
MsgBox('Section_1:Key_1=' + StrValue, mbInformation, MB_OK);
if not JSONWriteString(FileName, 'launchSettings', 'toolDirectory', 'Test') then
MsgBox('JSONWriteString Section_1:Key_1 failed!', mbError, MB_OK);
end;
Thank you very much for your support!
Regards,
Alex
The launchSettings is an array. I believe that the inno-json-config library does not support arrays.
You can use JsonParser library instead.
[Code]
#include "JsonParser.pas"
function FindJsonValue(
Output: TJsonParserOutput; Parent: TJsonObject; Key: TJsonString;
var Value: TJsonValue): Boolean;
var
I: Integer;
begin
for I := 0 to Length(Parent) - 1 do
begin
if Parent[I].Key = Key then
begin
Value := Parent[I].Value;
Result := True;
Exit;
end;
end;
Result := False;
end;
function FindJsonArray(
Output: TJsonParserOutput; Parent: TJsonObject; Key: TJsonString;
var Arr: TJsonArray): Boolean;
var
JsonValue: TJsonValue;
begin
Result :=
FindJsonValue(Output, Parent, Key, JsonValue) and
(JsonValue.Kind = JVKArray);
if Result then
begin
Arr := Output.Arrays[JsonValue.Index];
end;
end;
{ ... }
var
JsonLines: TStringList;
JsonParser: TJsonParser;
LaunchSettingsArray: TJsonArray;
ToolDirectoryValue: TJsonValue;
I: Integer;
begin
{ ... }
JsonLines := TStringList.Create;
JsonLines.LoadFromFile(FileName);
ParseJson(JsonParser, JsonLines.Text);
if Length(JsonParser.Output.Errors) > 0 then
begin
Log('Error parsing JSON');
for I := 0 to Length(JsonParser.Output.Errors) - 1 do
begin
Log(JsonParser.Output.Errors[I]);
end;
end
else
begin
if FindJsonArray(
JsonParser.Output, JsonParser.Output.Objects[0],
'launchSettings', LaunchSettingsArray) and
(GetArrayLength(LaunchSettingsArray) >= 0) and
(LaunchSettingsArray[0].Kind = JVKObject) and
FindJsonValue(
JsonParser.Output,
JsonParser.Output.Objects[LaunchSettingsArray[0].Index], 'toolDirectory',
ToolDirectoryValue) and
(ToolDirectoryValue.Kind = JVKString) then
begin
Log(Format(
'launchSettings[0]:toolDirectory:%s', [
JsonParser.Output.Strings[ToolDirectoryValue.Index]]));
JsonParser.Output.Strings[ToolDirectoryValue.Index] := 'Test';
JsonLines.Clear;
PrintJsonParserOutput(JsonParser.Output, JsonLines);
JsonLines.SaveToFile(FileName);
end;
end;
ClearJsonParser(JsonParser);
JsonLines.Free;
end;
It still won't preserve the order (but that should not matter).
Though in your case, you do not need to parse the JSON. You can simply replace the %Selected Setup Folder% with the desired value.
See Replace placeholder in an installed text file with input entered by user.

Delphi / REST / JSON

I'm using Delphi Tokyo 10.2 Update 1 and the RESTRequest, RESTResponse and RESTClient components to communicate with a REST server. This is my first attempt with REST/JSON.
I have successfully sent a login request (POST) and received the response expected (a GUID). I then use the GUID to do various other requests (GET). Two of the requests that are made send back an empty file and document JSON template which I then have to populate. This is where I'm stuck. I'm not sure of the best way to update property values in the JSON object.
Here is the empty JSON file template I'm getting back:
{
"boxId": 0,
"changedBy": 0,
"customSort": "",
"dateChanged": "1990-01-01T00:00:00",
"dateStarted": "1990-01-01T00:00:00",
"destruction": "1990-01-01T00:00:00",
"documentCount": 0,
"documents": {
"TotalCount": 0,
"Collection": [
]
},
"extraData": {
"TotalCount": 0,
"Collection": [
]
},
"fieldDefs": {
"TotalCount": 0,
"Collection": null
},
"field": [
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
""
],
"fileId": 0,
"filePtr": 0,
"id": 0,
"isIndexed": false,
"keyValue": "",
"keyVisualValue": "",
"labelPrinted": "1990-01-01T00:00:00",
"lineItems": {
"TotalCount": 0,
"Collection": [
]
},
"notes": "",
"objectType": 5,
"projectId": 0,
"routeInfo": null,
"routingDoc": null,
"remoteId": 0,
"saveNotesOnly": false,
"saveStyle": -999,
"status": 1,
"syncFlag": 0,
"totalDocumentCount": 0,
"viewerContext": 0
}
In Python to populate the first two values in the field property array I simply would do:
inc_filetemplate = json.loads(requests.get(NEWFILE_string).text)
inc_doctemplate = json.loads(requests.get(NEWDOC_string).text)
filetemplate = inc_filetemplate
doctemplate = inc_doctemplate
filetemplate['field'][1] = dcn
filetemplate['field'][2] = batchname
EASY!!!! ;)
What is the best way to do this with Delphi?
I can get the values from the "field" array (first two items in this example which happen to be empty). Just not sure the best way to set the values for those items.
This is what I have started:
procedure PopulateFileTemplate(const AFileTemplate: String);
var
JO: TJSONObject;
JOPair: TJSONPair;
JOArray: TJSONArray;
FieldDCN: String;
FieldBatchName: String;
begin
JO := TJSONObject.ParseJSONValue(AFileTemplate) as TJSONObject;
try
if JO = nil then
begin
MessageDlg('Unable to parse JSON file template.', mtError, [mbOK], 0);
Exit;
end;
JOArray := JO.Get('field').JsonValue as TJSONArray;
FieldDCN := JOArray.Items[0].Value;
FieldBatchName := JOArray.Items[1].Value;
Memo1.Lines.Add('The old value of DCN is: ' + FieldDCN);
Memo1.Lines.Add('The old value of BatchName is: ' + FieldBatchName);
// Best way to set Values here???????
Memo1.Lines.Add('The new value of DCN is: ' + FieldDCN);
Memo1.Lines.Add('The new value of BatchName is: ' + FieldBatchName);
finally
JO.Free;
end;
end;
The TJSONArray.Items[] property returns a TJSONValue, which in your example are TJSONString objects since fields an array of strings.
TJSONArray is actually not designed to allow modifying existing objects in the array. You can add new objects to the end of the array, and remove arbitrary objects from the array, but you cannot insert new objects at arbitrary indexes, or replace existing objects with new objects.
The closest you can get to that kind of functionality is to construct a TList<TJSONValue> with the desired objects in it, and then pass it to TJSONArray.SetElements(). Not ideal.
And TJSONString does not have any methods or properties for editing its string value (except for TJSONString.AddChar()).
You could try using an accessor/helper class to gain access to the protected TJSONString.FStrBuffer member and then edit its content as needed:
type
TJSONStringAccess = class(TJSONString)
end;
procedure SetJSONStringValue(JSONValue: TJSONString; const S: string);
begin
with TJSONStringAccess(JSONValue) do
begin
FStrBuffer.Clear;
FStrBuffer.Append(S);
end;
end;
procedure PopulateFileTemplate(const AFileTemplate: String);
var
JO: TJSONObject;
JOPair: TJSONPair;
JOArray: TJSONArray;
FieldDCN: TJSONString;
FieldBatchName: TJSONString;
begin
JO := TJSONObject.ParseJSONValue(AFileTemplate) as TJSONObject;
if JO = nil then
begin
MessageDlg('Unable to parse JSON file template.', mtError, [mbOK], 0);
Exit;
end;
try
JOArray := JO.Get('field').JsonValue as TJSONArray;
FieldDCN := JOArray.Items[0] as TJSONString;
FieldBatchName := JOArray.Items[1] as TJSONString;
Memo1.Lines.Add('The old value of DCN is: ' + FieldDCN.Value);
Memo1.Lines.Add('The old value of BatchName is: ' + FieldBatchName.Value);
SetJSONStringValue(FieldDCN, '...');
SetJSONStringValue(FieldBatchName, '...');
Memo1.Lines.Add('The new value of DCN is: ' + FieldDCN.Value);
Memo1.Lines.Add('The new value of BatchName is: ' + FieldBatchName.Value);
finally
JO.Free;
end;
end;
type
TJSONStringHelper = helper class for TJSONString
procedure SetValue(const S: string);
end;
procedure TJSONStringHelper.SetValue(const S: string);
begin
Self.FStrBuffer.Clear;
Self.FStrBuffer.Append(S);
end;
procedure PopulateFileTemplate(const AFileTemplate: String);
var
JO: TJSONObject;
JOPair: TJSONPair;
JOArray: TJSONArray;
FieldDCN: TJSONString;
FieldBatchName: TJSONString;
begin
JO := TJSONObject.ParseJSONValue(AFileTemplate) as TJSONObject;
if JO = nil then
begin
MessageDlg('Unable to parse JSON file template.', mtError, [mbOK], 0);
Exit;
end;
try
JOArray := JO.Get('field').JsonValue as TJSONArray;
FieldDCN := JOArray.Items[0] as TJSONString;
FieldBatchName := JOArray.Items[1] as TJSONString;
Memo1.Lines.Add('The old value of DCN is: ' + FieldDCN.Value);
Memo1.Lines.Add('The old value of BatchName is: ' + FieldBatchName.Value);
FieldDCN.SetValue('...');
FieldBatchName.SetValue('...');
Memo1.Lines.Add('The new value of DCN is: ' + FieldDCN.Value);
Memo1.Lines.Add('The new value of BatchName is: ' + FieldBatchName.Value);
finally
JO.Free;
end;
end;
Otherwise, consider switching to a 3rd party JSON library that natively supports editing values. Such as SuperObject.

Delphi XE5 JSON nested object

I am trying to generate JSON, data source is a DB FireBird.
I have a schema to generate path like this:
schema:= TDictionary<string, string>.Create;
schema.Add('DBTableName1', 'nest1.valueKeyName1');
schema.Add('DBTableName2', 'nest1.valueKeyName2');
schema.Add('DBTableName3', 'nest2.valueKeyName1');
schema.Add('DBTableName4', 'nest3.valueKeyName1');
schema.Add('DBTableName5', 'nest3.valueKeyName2');
schema.Add('DBTableName6', 'nest4.valueKeyName1');
How to create function for generate path to make nested objects?
{
"nest1": {
valueKeyName1: DBTableValue1,
valueKeyName2: DBTableValue2,
},
"nest2": {
valueKeyName1: DBTableValue3
},
"nest5":{
"nest6": {
"key1": "value1",
"key2": "value2",
},
"nest7": {}
}
In JavaScript I can do something like:
if (object.hasOwnProperty['key'] == false) object['key'] = {};
object = object['key'];
But in Delphi I have problem, and do not know, how to go deeper:
function TKlient.wprowadzWartoscDoJSON(wartosc: string; JSON: TJSONObject; sciezka: TStringList): TJSONObject;
var
i: integer;
obiekt: TJSONObject;
para: TJSONPair;
zagniezdzen: integer;
begin
zagniezdzen := sciezka.Count - 2;
obiekt := JSON;
para:= obiekt.Get(sciezka[i]);
for i := 1 to zagniezdzen do
begin
if obiekt.Get(sciezka[i]) = nil then obiekt.AddPair(sciezka[i], TJSONObject.Create)
else obiekt := obiekt.Get(sciezka[i]);
end;
obiekt.AddPair(sciezka[sciezka.Count - 1], wartosc);
result := obiekt;
end;
Here I've used a TDictionary<string, TJSONObject> to keep track of the object paths.
var
schema: TDictionary<string, string>;
pathSchema: TDictionary<string{path to every object}, TJSONObject>;
pair: TPair<string, string>;
values: TStringDynArray;
jsonObj,
jsonChildObj,
jsonParentObj: TJSONObject;
path: string;
i: Integer;
begin
schema := TDictionary<string, string>.Create;
try
schema.Add('DBTableName1', 'nest1.valueKeyName1');
schema.Add('DBTableName2', 'nest1.valueKeyName2');
schema.Add('DBTableName3', 'nest2.valueKeyName1');
schema.Add('DBTableName4', 'nest3.valueKeyName1');
schema.Add('DBTableName5', 'nest3.valueKeyName2');
schema.Add('DBTableName6', 'nest4.valueKeyName1');
schema.Add('value1', 'nest5.nest6.key1');
schema.Add('value2', 'nest5.nest6.key2');
pathSchema := TDictionary<string, TJSONObject>.Create;
try
jsonObj := TJSONObject.Create;
try
for pair in schema do begin
values := SplitString(pair.Value, '.');
path := '';
jsonParentObj := jsonObj;
for i := Low(values) to High(values)-1 do begin
if i > 0 then
path := path + '.';
path := path + values[i];
if pathSchema.ContainsKey(path) then
jsonChildObj := pathSchema[path]
else begin
jsonChildObj := TJSONObject.Create;
jsonParentObj.AddPair(TJSONPair.Create(values[i], jsonChildObj));
pathSchema.Add(path, jsonChildObj);
end;
jsonParentObj := jsonChildObj;
end;
jsonChildObj.AddPair(TJSONPair.Create(values[High(values)], pair.Key));
end;
WriteLn(jsonObj.ToString);
finally
jsonObj.Free;
end;
finally
pathSchema.Free;
end;
finally
schema.Free;
end;
ReadLn;
end.
The above prints the following:
{
"nest4":{
"valueKeyName1":"DBTableName6"
},
"nest2":{
"valueKeyName1":"DBTableName3"
},
"nest5":{
"nest6":{
"key1":"value1",
"key2":"value2"
}
},
"nest1":{
"valueKeyName1":"DBTableName1",
"valueKeyName2":"DBTableName2"
},
"nest3":{
"valueKeyName1":"DBTableName4",
"valueKeyName2":"DBTableName5"
}
}

Read a specific value from a JSON request using SuperObject

Hello I get the next result in a web API in JSON format:
[
{
"$id":"47",
"CodISO":"BIH",
"ES":"Bosnia y Herzegovina",
"EN":"Bosnia and Herzegovina"
},
{
"$id":"48",
"CodISO":"BLR",
"ES":"Bielorrusia",
"EN":"Belarus"
},
{
"$id":"49",
"CodISO":"BLZ",
"ES":"Belice",
"EN":"Belize"
},
{
"$id":"50",
"CodISO":"BOL",
"ES":"Bolivia",
"EN":"Bolivia"
},
{
"$id":"51",
"CodISO":"BON",
"ES":"Bonaire",
"EN":"Bonaire"
},
{
"$id":"52",
"CodISO":"BOT",
"ES":"Botsuana",
"EN":"Botswana"
},
{
"$id":"53",
"CodISO":"BRA",
"ES":"Brasil",
"EN":"Brazil"
},
{
"$id":"54",
"CodISO":"BRB",
"ES":"Barbados",
"EN":"Barbados"
}
]
Now, I want read the value from item 'ES' where the value of item 'CodISO' = 'BOL' in Delphi SuperObject, I'm not able to find the solution, took all day trying it.
I don't know how iterate with SuperObject elements as I do it with Embarcadero TJSONValue, TJSONObject, TJSONArray. I'm a newbie with SuperObject:
var
json: ISuperObject;
Retriever: TIdHTTP;
Url: string;
AnsiStr: AnsiString;
begin
URL := Form1.RestClient1.BaseURL;
try
Retriever := TIdHTTP.Create(nil);
try
AnsiStr := Retriever.Get(Url);
json := SO(AnsiStr);
{ Here code to iterate with json elements in SuperObject.......
.
.
.
.
}
finally
Retriever.Free;
end;
except
on E: Exception do
ShowMessage(E.ClassName + ': ' + E.Message);
end;
End;
As Sir Rufo said, you need to read the SuperObject documentation.
Try something like this:
var
JsonArr, JsonObj: ISuperObject;
Retriever: TIdHTTP;
Url, JsonStr, ES: string;
I: Integer;
begin
URL := Form1.RestClient1.BaseURL;
try
Retriever := TIdHTTP.Create(nil);
try
JsonStr := Retriever.Get(Url);
finally
Retriever.Free;
end;
JsonArr := SO(JsonStr).AsArray;
for I := 0 to JsonArr.Length-1 do
begin
JsonObj := JsonArr.O[I];
if JsonObj.S['CodISO'] = 'BOL' then
begin
ES := JsonObj.S['ES'];
Break;
end;
end;
except
on E: Exception do
ShowMessage(E.ClassName + ': ' + E.Message);
end;
end;