Extract specific values from JSON array - json

I have a JSON response that is formatted this way:
- Client 1
- Date: 15.07.2017
- Name: John
- URL: www.google.com
- Client 2
- Date: 15.07.2017
- Name: Jane
- URL: www.google.com
- Client N...
How could I extract only the Name & URL value from each client so I could add them to a listbox for example? Also please note that "Client 1" could be named otherwise, like "User 1" or just "1", that's not important, but the code should extract the values regardless of the parent object name.
PS: Sorry for missleading, the JSON format above was pseudo-code from memory, the actual format is:
[
{
"date":"xxx",
"name":"xxx",
"url":"xxx"
},
{
"date":"xxx",
"name":"xxx",
"url":"xxx"
},
{
"date":"xxx",
"name":"xxx",
"url":"xxx"
}
]

Answer in case anybody is looking.
procedure Answer;
var
JSON: string;
ClientItem: TJSONValue;
ClientList: TJSONArray;
ListBoxItem: TListBoxItem;
begin
JSON := TFile.ReadAllText('.\your-file.json');
ClientList := TJSONObject.ParseJSONValue(JSON) as TJSONArray;
if Assigned(ClientList) then
try
ListBox.Items.BeginUpdate;
try
for ClientItem in ClientList do
begin
ListBoxItem := TListBoxItem.Create(ListBox);
ListBoxItem.StyleLookup := 'CustomListbox';
ListBoxItem.StylesData['URL'] := ClientItem.GetValue<string>('url');
ListBoxItem.StylesData['Name'] := ClientItem.GetValue<string>('name');
Listbox.AddObject(ListBoxItem);
end;
finally
Listbox.Items.EndUpdate;
end;
finally
ClientList.Free;
end;
end;

Related

Call remote server through oracle apex

How to call external server or remote server from Oracle APEX using various restful services kindly let me know.
Thanks & Regards,
Yokes G
One way to do it is to set up a Rest Data Source entry. I am using Oracle Apex 20.2.
eg called myRest
using Simple HTTP
Remote Server: Server name without https: include the endpoint
JSON Operation: GET
Parameters: the header parameters
It is very easy to copy and paste this from PostMan.
Then you can use the following type of code to access this REST service
declare
l_params apex_exec.t_parameters;
begin
apex_exec.add_parameter( l_params, 'content', 'hello david' );
apex_exec.add_parameter( l_params, 'to', '123456' );
apex_exec.execute_rest_source(
'myRest',
'GET',
NULL,
l_params );
end;
Note that I couldn't get the JSON to work properly using Rest Data Sources and so I use make_rest_request instead as follows:
declare
l_host constant varchar2(200) := 'https://platform.xxx.com';
l_host_path constant varchar2(200) := l_host || '/v1/message';
l_clob clob;
l_body clob;
begin
l_body := '{
"messages": [
{
"channel": "xxx",
"to": "123",
"content": "Hello from APEX"
}
]
}';
apex_web_service.g_request_headers(1).name := 'Content-Type';
apex_web_service.g_request_headers(1).value := 'application/json';
apex_web_service.g_request_headers(2).name := 'Authorization';
apex_web_service.g_request_headers(2).value := 'yourkey';
l_clob := apex_web_service.make_rest_request(
p_url => l_host_path,
p_http_method => 'POST',
p_body => l_body);
end;
This second method is nice as then everything is in one place and you don't need to reference the REST Data Sources.

Nested JSON Objects

I am using an API to output a JSON file as such, and so cannot edit the format of the JSON file. Is there any way to be able to iterate through each intraday date, to find the value of open in each date?
I have tried using Object.intraday[0].open however this does not seem to work, as the it is not contained within an array?
I realise that I can use Object.intraday.date.open (where date is e.g "2018-10-19 15:59:00:"); however I want to be able to index to the different times.
{
"symbol": "AAPL",
"stock_exchange_short": "NASDAQ",
"timezone_name": "America/New_York",
"intraday": {
"2018-10-19 15:59:00:" {
"open": "219.49",
"close": "219.23",
"high": "219.61",
"low": "219.19",
"volume": "302415"
},
"2018-10-19 15:58:00:" {
"open": "219.62",
"close": "219.48",
"high": "219.70",
"low": "219.48",
"volume": "173762"
},
....
This is the pascal code that I am using in order to do this, using a test JSON of {"intraday":{"2018-10-1915:59:00":{"open":"23","low":"4"},"2018-10-1915:58:00":{"open":"25","low":"21"}}}
JSONValue := TJSONObject.ParseJSONValue('{"intraday":{"2018-10-1915:59:00":{"open":"23","low":"4"},"2018-10-1915:58:00":{"open":"25","low":"21"}}}');
j:=0;
begin
if JSONVAlue is TJSONObject then
begin
// Get the quote and low values
quote := JSONValue.GetValue<string>('intraday[0]');
low := JSONValue.GetValue<string>('intraday.low');
Memo1.Lines.Add(quote + ': ' + low);
j := j+1;
end;
end;
procedure TfmMain.ParseIntraDay(AMemo: TMemo);
var
LObject, LIntraDayObj: TJSONObject;
LEnumerator: TJsonPairEnumerator;
LQuote, LLow: String;
begin
LObject := TJSONObject.ParseJSONValue('{"intraday":{"2018-10-19 15:59:00":{"open":"23","low":"4"},"2018-10-19 15:58:00":{"open":"25","low":"21"}}}') as TJSONObject;
try
LIntraDayObj := LObject.GetValue('intraday') as TJSONObject; //{"2018-10-19 15:59:00":{"open":"23","low":"4"},"2018-10-19 15:58:00":{"open":"25","low":"21"}}
LEnumerator := LIntraDayObj.GetEnumerator;
while LEnumerator.MoveNext do
begin
LQuote := LEnumerator.Current.JsonString.Value;
LLow := (LEnumerator.Current.JsonValue As TJsonObject).Values['low'].Value;
AMemo.Lines.Add(String.Format('%s: %s', [LQuote, LLow]));
end;
finally
LObject.Free;
end;
end;
Should give the following output in the memo:
2018-10-19 15:59:00: 4
2018-10-19 15:58:00: 21
Youcan use this as a basis for what you want.

How to get odata.nextLink from the returned JSON object using oracle's apex_json

I am retrieving data from an odata service. The response contains a link for loading more data i.e. odata.nextLink which I need to retrieve to load more data. How do I do this using oracle's apex_json?
The server's response is something like this:
{
"odata.metadata":"http://localhost:60497/odata/$metadata#tables","value":[
{"id":001,"name":"abc" }
.
.
],
"odata.nextLink":"http://localhost:60497/odata/tables?$skip=10"
}
Normally I would parse the data and then retrieve the information like this next_link := apex_json.get_varchar2('odata.nextLink'); but since it contains a point that won't work.
In this case:
apex_json.get_varchar2('odata.nextLink');
it is considering nextLink as the value of odata.
DECLARE
v_json APEX_JSON.T_VALUES;
v_str_json VARCHAR2(4000);
next_link VARCHAR2(4000);
BEGIN
v_str_json := '{
"odata" : {"nextLink" : "mylink"},
"odata.metadata":"http://localhost:60497/odata/$metadata#tables","value":[
{"id":001,"name":"abc" }
],
"odata.nextLink":"http://localhost:60497/odata/tables?$skip=10"
}
}';
APEX_JSON.PARSE(v_json, v_str_json);
next_link := APEX_JSON.GET_VARCHAR2(p_path => 'odata.nextLink', p_values => v_json);
dbms_output.put_line(next_link);
END;
>> OUTPUT: mylink
I do not know how to say "odata.nextLink" to be interpreted literally; and not as a path.
If nobody knows:
1 - or stop sending "odata." at the beginning of the name of each attribute;
2 - or use replace to remove.

How to hide "ownsObjects" and "listHelper" TObjectList's properties from a Json using Delphi (Rest.JSON)?

I'm using Delphi Tokyo and trying to convert an object into a json using TJson. ObjectToJsonString method present in Rest.Json.
A simple object with simple properties such as String or Integer it's ok, but when a add a property TObjectList, the json is poluted with the properties "ownsObjects" and "listHelper", but the WebService doesn't accept these fields. How can I "hide" it from a Json?
You can put the JsonReflect attribute on fields and control how they are being serialized.
Here is some example code of how to write your own specialized "serialize this object list as array" attribute that takes care of that - just add the unit to the uses and add [SerializeObjectList] to your field.
unit CollectionsReflect;
interface
uses
Generics.Collections,
REST.JsonReflect;
type
SerializeObjectListAttribute = class(JsonReflectAttribute)
constructor Create;
end;
implementation
uses
Rtti;
type
TListOfObjectInterceptor = class(TJSONInterceptor)
function ObjectsConverter(Data: TObject; Field: string): TListOfObjects; override;
end;
{ TListOfObjectInterceptor }
function TListOfObjectInterceptor.ObjectsConverter(Data: TObject;
Field: string): TListOfObjects;
var
ctx: TRttiContext;
list: TList<TObject>;
begin
list := TList<TObject>(ctx.GetType(Data.ClassInfo).GetField(Field).GetValue(Data).AsObject);
Result := TListOfObjects(list.List);
SetLength(Result, list.Count);
end;
{ SerializeObjectListAttribute }
constructor SerializeObjectListAttribute.Create;
begin
inherited Create(ctObjects, rtObjects, TListOfObjectInterceptor);
end;
end.
Unfortunately the opposite way does not work this way as there seems to be a bug inside of TJSONUnMarshal.PopulateFields that causes an AV when trying to populate the list from the json string.
// How to hide “ownsObjects” and “listHelper” TObjectList's properties from a Json
type
TSameClass = class(...)
....
public
...
function GetAsJson: string;
...
end;
...
// метод любого класса Txxxxx для получения его json, у которого, для всех его
// переменных с типом TObjectList, будут очищены “ownsObjects” и “listHelper” свойства
function TSameClass.GetAsJson: string;
procedure ClearJsonObjectList(AJson: TJSONObject);
var je: TJSONObject.TEnumerator;
begin
// проходим по всему дереву json и удаляем ненужные нам пары
je := AJson.GetEnumerator();
while je.MoveNext() do
if je.Current.JsonValue is TJSONObject then
// рекурсивный вызов
ClearJsonObjectList(je.Current.JsonValue as TJSONObject)
else
// если есть этот Pair, то есть и другой
if Assigned(AJson.RemovePair('listHelper')) then
AJson.RemovePair('ownsObjects');
end;
var j: TJSONObject;
begin
// получаем json класса, в котором могут быть или не быть TObjectList с ненужными нам парами
j := TJson.ObjectToJsonObject(Self);
// в этой процедуре очищаем полученный json от этих пар
ClearJsonObjectList(j);
// возвращаем результат в виде строки json
Result := j.ToString;
end;
(*
// example
// json before ClearJsonObjectList --------------->
{
"content":{
"checkClose":{
"payments":{
"ownsObjects":true, <<-- must be removed
"listHelper":[ <<-- must be removed
]
},
...
},
"positions":{
"ownsObjects":true, <<-- must be removed
"listHelper":[ <<-- must be removed
]
},
...
},
...
}
// json after ClearJsonObjectList --------------->
{
"content":{
"checkClose":{
"payments":{
},
...
},
"positions":{
},
...
},
...
}
*)
I recommend that you create an array of objects instead of a list, if not generally, then for the purpose of serialization to JSON. This works much better with JSON, both reading and writing. Just make sure to handle the memory involved, i.e. free the objects in the list, something like this:
procedure TSomeContainerObject.BeforeDestruction;
var
o: TSomeObjectInTheArray;
begin
for o in fObjectArray do
o.Free;
inherited;
end;
I usually put this in my *.dpr file just to make sure:
begin
{$IFDEF Debug}
ReportMemoryLeaksOnShutdown := true;
{$ENDIF}
// The rest of your startup code here
end.
function TSrvMethContab.GetConecctions: TJSONObject;
var
lContext : TDbContext ;
lLista : TList<TConexions>;
jResult : TJSONObject;
begin
lContext := TDbContext.Create(strConexion);
try
lLista := lContext.Select<TConexions>();
jResult := TJson.ObjectToJsonObject(lLista);
jResult.RemovePair('listHelper');
Result := jResult;
finally
lContext.Free;
end;
end;

Delphi / SuperObject - Accessing Subnodes

I have the following JSON from my server:
{
"userid":"12",
"username":"TestChar",
"logged":"yes",
"status":"Premium User",
"areas":{
"SERVICEAREA_XX1":{
"id":"1",
"area":"SERVICEAREA_XX1",
"version":"3000",
"usr_group":"0"
},
"SERVICEAREA_XX2":{
"id":"2",
"area":"SERVICEAREA_XX2",
"version":"31000",
"usr_group":"0"
},
"SERVICEAREA_XX3":{
"id":"3",
"area":"SERVICEAREA_XX3",
"version":"2000",
"usr_group":"1"
}
}
}
With SuperObjects i can get the count of "SERVICEAREA"'s with
ob['areas'].AsObject.count
How can i now get access to the elements of the different "SERVICEAREA"'s?
Thanks for your help...
you can access elements of an array using a for ... in loop:
var
item: ISuperObject;
begin
for item in ob['areas'] do ...
or without an enumerator, using a 'normal' for loop:
var
idx: Integer;
item: ISuperObject;
begin
for idx := 0 to ob['areas'].AsArray.Length - 1 do
item := ob['areas'].AsArray[idx];
Marjan has the answer for you. Here is a little more information how to access the item properties with an example:
var
item: ISuperObject;
...
for item in ob['areas'] do
begin
WriteLn(item['id'].AsInteger);
WriteLn(item['area'].AsString);
WriteLn(item['version'].AsInteger);
end;
use this code If you want to access key/value(like Javascriptfor..in)
if ObjectFindFirst(JsonData, ite) then
with JsonData.AsObject do
repeat
PutO(ite.key, ite.val.Clone);
until not ObjectFindNext(ite);
ObjectFindClose(ite);