Understanding JSON Iteration - json

I work in a language called AL for work but we have JSON Objects, Arrays, etc..
I'm querying this api: http://citibikenyc.com/stations/json and I have the result stored in a text variable.
My objective is to store the ID and Station Names in a separate table. I can't figure out how I should iterate through all of the elements for ID and stationName.
I understand the path will be stationBeanList[0].id and increment the 0 every time I just don't know how to write it.
if Client.Get(url, Response) then begin
if Response.IsSuccessStatusCode then begin
Response.Content.ReadAs(Json);
J.ReadFrom(Json);
JsonBuffer.ReadFromText(Json);
JsonObj.ReadFrom(Json);
// How to iterate though all of the Elements
end;
end;
Any help or suggestions is appreciated.

I came up with the following which works but please lot me know how it could be improved.
I hate having a resultToken2 and a resulttoken3.
url := 'http://citibikenyc.com/stations/json';
if Client.Get(url, Response) then begin
if Response.IsSuccessStatusCode then begin
Response.Content.ReadAs(Json);
J.ReadFrom(Json);
JsonBuffer.ReadFromText(Json);
if not Jtoken.ReadFrom(Json) then
Error('Invalid response from the web service. Invalid JSON object.');
if not Jtoken.SelectToken('stationBeanList', resultToken) then
Error('Invalid response from the web service. Invalid JSON object.');
if not resultToken.IsArray then
Error('Invalid response from the web service. Invalid JSON object.');
arrayToken := resultToken.AsArray();
for i := 0 to arrayToken.Count() - 1 do begin
arrayToken.get(i, resultToken);
resultToken.AsObject().Get('id', resultToken2);
resultToken.AsObject().Get('stationName', resultToken3);
StationDetails.Init();
StationDetails.ID := resultToken2.AsValue().AsInteger();
StationDetails."Station Name" := resultToken3.AsValue().AsText();
StationDetails.Insert(true);
end;
end;
end;

Related

ulkJson usage in Delphi 6

lets says i have a code like this,
json:= TlkJSON.ParseText(Memo1.Text);
if Assigned(json) then
begin
json:= json.Field['journals'];
if Assigned(json) then
begin
json:= json.Field['journal_details'];
if Assigned(json) then
begin
Memo2.Lines.Add(VarToStr(json.Child[0].Value));
end;
end;
end;
it's used for tracing my json object had field "journals" and "journal_details" in it.
I want to make it more dynamic so it can detect if the value in json object was array/list/custom list and it contain all the detail error message i want to re - translate again so the user can understand the message.
Any clue will be appreciated.
as #MyICQ suggestion, this is snippet of data that i want to re - translate look like.
[{"code":"H003","validations":["phone_invalid_format"]},{"code":"H004","validations":["phone_invalid_format"]},{"code":"H005","validations":["phone_invalid_format"]},{"code":"H006","validations":["phone_invalid_format"]},{"code":"H010","validations":["phone_invalid_format"]}]
with note, the string was not always with the same structure.
this is the output, i wish to have at least
Error List Data :
> H003 : Note = Phone_invalid_format
> H004 : Note = Phone_invalid_format
> H005 : Note = Phone_invalid_format
> H006 : Note = Phone_invalid_format
> H010 : Note = Phone_invalid_format
so far all i can get is to detect how many array or object in the string, but failed in retrieve the value in it.
There is a function in lkJSON to find the type of element. This is called SelfType, enumeration of TlkJSONtypes: (jsBase, jsNumber, jsString, jsBoolean, jsNull, jsList, jsObject).
You can write this out using SelfTypeName where you get the same as enum, only as a string.
So basically something along:
begin
js := TlkJSON.ParseText(txt);
writeln(js.SelfTypeName); // get the type as a string
if js.SelfType in [jsList] then
begin
// process as list
end
else
if js.SelfType in [jsObject] then
begin
// process as object
end
else if js.SelfType not in [jsBase] then
begin
// write the value of number, string, boolean, null
end;
end;
Obviously you can then make a parse_element function which you can call recursively.
lkJSON seems to be still updated, this GitHub project lists 1.09 from 1 Oct 2021.
The documentation is fairly sparse, but it does the job on older Delphi versions where superobject unfortunately won't compile.
If you google keywords like SelfName and lkJSON there are plenty examples online to get you going.

Get an OUT BLOB type Parameter of a Stored Procedure as TStream

I have a stored procedure on my MySQL Database with 2 OUT parameters as Blob type
I want to get their values as TStream with UniDAC`s SP component, I have tried this code for testing :
SP := TUniStoredProc.Create(nil);
M := TMemoryStream.Create;
try
try
SP.StoredProcName := 'user_getpic';
SP.PrepareSQL(False);
SP.Params.ParamByName('fUID').AsString := '...';
SP.Params.ParamByName('fDiceCode').AsString := '...';
...
SP.ExecProc;
M.LoadFromStream(SP.Params.ParamByName('fUPic').AsStream);
except
on E:EXception do
begin
ShowMessage('Error : ' + E.Message);
end;
end;
finally
SP.Free;
M.Free;
end;
The problem is Param.AsStream returns Nil but Param.AsBlob is not Nil
When I Call this SP on MySQL directly fUPic have blob data and there is no problem on SP
I have tried SP.CreateBlobStream() but what I should pass to it`s first parameter as TField ?!
I have tried casting to TBlobStream from Param.AsBlob but no chance !
I want to know how I can get an OUT blob parameter as TStream ?
I`m using Delphi XE6 and UniDAC 6.1.4
Use AsBlob. It returns the blob as a byte array. You can either use that directly, or if you need to access the data via a stream do so with TBytesStream.
Stream := TBytesStream.Create(Param.AsBlob);

UTL_HTTP GET response does not return all requested data using PL/SQL

I'm using PL/JSON library to parse data from MongoDB to Oracle DB. I use UTL_HTTP package as follows:
l_http_request := UTL_HTTP.begin_request('https://api.appery.io/rest/1/db/collections/Outlets'
, 'GET'
, 'HTTP/1.1');
-- ...set header's attributes
UTL_HTTP.set_header(l_http_request, 'X-Appery-Database-Id', '53f2dac5e4b');
--UTL_HTTP.set_header(l_http_request, 'Content-Length', LENGTH(l_param_list));
-- ...set input parameters
-- get Response and obtain received value
l_http_response := UTL_HTTP.get_response(l_http_request);
--using a loop read the response.
BEGIN
LOOP
UTL_HTTP.read_text(l_http_response, buf);
l_response_text := l_response_text || buf;
END LOOP;
EXCEPTION
WHEN UTL_HTTP.end_of_body THEN
NULL;
END;
l_list := json_list(l_response_text);
FOR i IN 1..l_list.count
LOOP
A_id := json_ext.get_string(json(l_list.get(i)),'_id');
.....
The loop extracts and inserts records. However, the number of records inserted does not exceed 100 records even though the data requested is much more than that.
I tried with different JSON collections, and different Oracle tables but the result is same. The maximum number of records I get is 100 records.
Is their any attributes I need to add to my response?

In Delphi using MyDAC, how do I write an entire record as a string?

As the title suggests, using Delphi 2010 and MyDAC 7.1, how do I output an entire string as a string like JSON / XML / CSV or some other plain text option?
eg output:
{user_id:1;username:testuser;password:testpass}
Presuming that MyDAC is a standard TDataSet descendant, you can build the string manually. For instance, for JSON:
var
i: Integer;
Output: string;
begin
Output := '{'; // #123;
for i := 0 to MyQry.FieldCount - 1 do
Output := Output +
MyQry.Fields[i].FieldName + ':' + // #58
MyQry.Fields[i].AsString + ';'; // #59
// Replace final ; with closing } instead
Output[Length(Output)] := '}'; // #125
end;
Or you can Google to find a Delphi JSON library (like SuperObject) and use it instead, as is done here.
For XML, use the same type loop with TXMLDocument. You can search for previous posts here tagged with Delphi to find examples.
For CSV, it can get complicated based on your data and the requirements. For instance, do you want or need a header row with field names? Does your data contain data that contains spaces or punctuation or CR/LFs? The easiest solution is to search for an already-existing library (via Google or Bing, not here) that exports to CSV.
According to the documentation you can use the SaveToXML procedures. should be something like this:
var
MyQuery: TMyQuery;
begin
try
MyQuery := TMyQuery.Create();
MyQuery.Connection := AConnection;
MyQuery.SQL.Text := ACommand;
MyQuery.Execute();
MyQuery.SaveToXML(<tstream or file>)
except
raise;
end;
end;

Delphi webservice JSON array

I am really new to Delphi and I am doing an experiment on how to output JSON array through delphi. This maybe sound simple to anyone but I just dont know how. I already created a simple program.
Now, what i want to do is to create a command/request with parameter like:
http://localhost:8001/hello?json={"names":["Jay","Chris","John"]}
that would create a result in the browser like this:
{
result: ["Hello Jay","Hello Chris","Hello John"],
id: "",
time_elapsed: 0
}
Please, i really need help on this. Anybody?
EDIT:
This is the code i just did today but it still doesn't show my desired output:
procedure TPrimeJSONMHelloPeople.ProcessJSONRPCRequest(
var ResultValue: TlkJSONbase; var ResultSuccess: Boolean);
var
jsonPeople:TlkJSONlist;
dmPool:TObject;
dm:TPrimeDataModuleBaseDM;
i:integer;
begin
FjsonObj1 := TlkJSONobject.Create;
jsonPeople := FjsonObj1.CreateListValue('names');
jsonPeople.AddVarString('jay');
jsonPeople.AddVarString('ann');
jsonPeople.AddVarString('john');
inherited;
CheckRequiredParameter('names');
PrimeDataModuleWebService.TDataModuleDMCreateInstanceDefault(dmPool);
try
dm := TPrimeDataModuleDefaultDM(dmPool).GetModule;
try
//this part here will loop and output the name
//if jsonPeople <> nil then
if Params.Field['names'] <> nil then
begin
for i := 0 to FjsonObj1.Field['names'].Count - 1 do
begin
ResultValue := TlkJSONlist.Create
end;
end;
ResultValue := TlkJSONlist.Create;
finally
dm.Release;
end;
finally
dmPool.Free;
end;
FjsonObj1.Free;
ResultSuccess := True;
end;
I don't know what's missing in the code, It only shows:
{
result: [ ],
id: "",
time_elapsed: 0
}
and not :
{
result: ["Hello Jay","Hello Chris","Hello John"],
id: "",
time_elapsed: 0
}
i have just found the right answer. Here's the code:
procedure TSample1.ProcessJSONRPCRequest(
var ResultValue: TlkJSONbase; var ResultSuccess: Boolean);
var
dmPool:TObject;
dm:TPrimeDataModuleBaseDM;
jsonPeople:TlkJSONlist; //used Tlkjsonlist since I want to create an array
i:integer;
begin
inherited;
jsonPeople:=TlkJSONlist.Create; //create jsonPeople as an array
CheckRequiredParameter('names'); //names parameter needed
PrimeDataModuleWebService.TDataModuleDMCreateInstanceDefault(dmPool);
try
dm := TPrimeDataModuleDefaultDM(dmPool).GetModule;
try
if Params.Field['names'] <> nil then //check if the names parameter is empty
begin
ResultValue:=jsonPeople;
for i := 0 to Params.Field['names'].Count - 1 do
begin
jsonPeople.AddVarString('hello ' + Params.Field['names'].Child[i].value);
end;
end;
finally
dm.Release;
end;
finally
dmPool.Free;
end;
ResultSuccess := True;
end;
end.
The request is http://localhost/sample1?json={"names":["john","jay"]}
The output is
{
-
result: [
"hello john"
"hello jay"
]
id: ""
time_elapsed: 0
}
Hope this can help someone who is new in creating web service request using delphi.
First of all, I think your URI shown in your question is already decoded. You should encode the URI parameters in the HTTP protocol.
If you want to create such HTTP-oriented JSON access, take a look at the RESTful approach. It would help you not reinvent the well, and be able to make your server more AJAX ready.
Then you seems to use the third-party lkJSON Delphi library... So you could get directly help from its author or support forum.
From the source code of the library, you should use a TlkJSONlist instance to handle a JSON array, from both URI input and result output.