I can't get my server app to properly receive anything.
Sender code using a design-time TIdHTTP component, with property
Request.Accept = text/html, */*
procedure TFrmTTWebserviceTester.Button1Click(Sender: TObject);
var
lJSO : ISuperObject;
lRequest: TStringStream;
lResponse: String;
begin
lJSO := SO('{"name": "Henri Gourvest", "vip": true, "telephones": ["000000000", "111111111111"], "age": 33, "size": 1.83, "adresses": [ { "adress": "blabla", "city": "Metz", "pc": 57000 }, { "adress": "blabla", "city": "Nantes", "pc": 44000 } ]}');
lRequest := TStringStream.Create(lJSO.AsString,TEncoding.UTF8); // or ASCII
// showmessage(lRequest.DataString); Correct data
IdHTTP.Request.ContentType := 'application/json';
// idHTTP.Request.Charset := 'utf-8';
lResponse := IdHTTP.Post('http://localhost:8085/ttposttest',lRequest);
// ShowMessage(lResponse.dataString);
lRequest.Free;
lJSO := nil;
end;
Receiver is a TWebAction on a TWebModule, set for MethodType mtPost (or mtAny) with handler:
procedure TWebModuleWebServices.WebModuleWebServicesTTPostTestAction(
Sender: TObject; Request: TWebRequest; Response: TWebResponse;
var Handled: Boolean);
var S: String;
begin
S := Request.Query;
Handled := true;
end; { WebModuleWebServicesTTPostTestAction }
Request.Query is empty.
All VCL apps. I have read these SO posts and many others but must be overlooking something...
TIA, Jan
The TWebRequest.Query property returns the URL query string, which you are not sending any. That is why it is blank. Your POST data is accessible from the TWebRequest.Content and TWebRequest.RawContent properties instead.
Related
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;
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.
I have these JSON Object , I read it well , But when i read oauth value i got an empty result ,
How I can read it ?
{
"status": true,
"message": "Success",
"items": {
"id": 6,
"name": "Tesst1",
"email": "Test1#tesst.Test",
"image": "https://www.website.com/images/man.png",
"created_at": "2017-08-24 09:18:15",
"updated_at": "2017-08-24 09:18:15",
"oauth": {
"token_type": "abc",
"expires_in": 1296000,
"access_token": "jI5NiwiZXhGVzIjpbXX0.RaC3ixxUeyYnCB6vNlwKsdjf09UeOwUJlcKmKErmE_LTAeQ-4fm8iBOKqUgpikTkyB3ztDGf4DAsaeEjUMqH76jZdbPHnX0vr676dCXkEunWoDEB8sYiHz7XRVgQ5W0O9yybA93mPO_XyrWPibkGW7GLQOApRD605N0e6vw0v9Kb_WQBim7zjTNqoLM1fSjgKJezFqf9_s3KIqBc4bjsayYLl7duzo2fzRmWtnGFfbsgO6YcaIz8ezNtWbtixLRMKnJEj1-MluqjWubsbq_gTI6yiyyac3_oY22Ge0QDdCtljadgO7wRz5VT5aJkxmJRB90u0ovm0tpGzYOO_4giY-J5egpOptjt2VZbPeM-vWPEo4-c6NYMZx6WqxBHjkZwiKUsM-tufzl5P5lFRJ9V_rBUBHEiSonTAk9FVDAwjqLc6N_IC1lsFDEC_3NBy4",
"refresh_token": "def502003e7826477c1072497ad66d7f11ea29e81a0fafef6223a63b6a0a3d18de71165afb9a340d10facca3ac7ee955aac5786a5c66a39cdf77e3f6449458e07271cbcde699aabf4d7f72dad10d586c37497216552f88460e50e9ea4944214984d5b23bac04b5f8265d132"
}
}
}
If i read the oauth as a JSON Object I got an exception about unsupported conversion,
conversion from TJSONObject to string is not supported
what is the wrong with my code ??
if JsonRespnse <> '' then
begin
jsonObiekt := TJSONObject.ParseJSONValue
(TEncoding.ASCII.GetBytes(JsonRespnse), 0) as TJSONObject;
try
try
LoginValue := jsonObiekt.get('status').JsonValue;
LoginValueIsTrue := StrToBool(LoginValue.value);
if LoginValueIsTrue = True then
begin
ItemsValue := jsonObiekt.get('items').JsonValue;
if ItemsValue is TJSONObject then
begin
strIdValue := ItemsValue.GetValue<string>('id');
// strOuthValue := ItemsValue.GetValue<string>('oauth');
OauthValue := TJSONObject(ItemsValue).get('oauth').JsonValue;
if OauthValue is TJSONObject then
Memo1.Lines.Add('oauth : ' + OauthValue.value);
end;
end;
except
on E: Exception do
ShowMessage('Read JSON : ' + E.Message);
end;
finally
jsonObiekt.Free;
end;
end;
strOuthValue := ItemsValue.GetValue<string>('oauth');
Is not working because it’s not a string in the context of the TJSON* classes. The key oauth is an json object just like 'items'.
You can read the values of the oauth object like you did it with 'items.id'
if OauthValue is TJSONObject then
begin
Memo1.Lines.Add('oauth : ' + TJSONObject(OauthValue).ToString);
Memo1.Lines.Add('oauth.token_type: ' + TJSONObject(OauthValue).Values['token_type'].ToString);
end;
Does this cover your question?
Any way to retrieve url key from this JSON?
{
"data": {
"is_silhouette": false,
"url": "https://fbcdn-profile-a.akamaihd.net/hprofile-ak-xpf1/v/t1.0-1/p200x200/13178742_10205047662871072_6233795154346712405_n.jpg?oh=194b0150c2325660390490779bf9b942&oe=57C22031&__gda__=1472746057_dc9b0557adc8408840fafb73ed325ef8"
}
}
It is provided by Facebook's Graph API. I'm using a Rest Library in Delphi 10.0 Seattle to retrieve it.
Start by reading Embarcadero's JSON documentation. You can use the classes in the System.JSON unit, eg:
uses
..., System.JSON;
var
json: string;
obj, data: TJSONObject;
url: string;
begin
json := ...; // JSON data retrieved from REST server
obj := TJSONObject.ParseJSONValue(json) as TJSONObject;
try
data := obj.Values['data'] as TJSONObject;
url := data.Values['url'].Value;
finally
obj.Free;
end;
end;
Alternatively, if you are using Embarcadero's REST client library, it can retrieve and pre-parse the JSON for you:
var
obj, data: TJSONObject;
url: string;
begin
RESTRequest1.Execute;
obj := RESTResponse1.JSONValue as TJSONObject;
data := obj.Values['data'] as TJSONObject;
url := data.Values['url'].Value;
end;
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;