I am accessing a TJSONValue in Delphi(using REST components and Google Books' API). I want to know how many elements are in the array: 'items'.
This is the format of the JSONValue:
"kind": "books#volumes",
"totalItems": 221,
"items": [
{...},
{...},
{...}]
Note* "totalItems" does not refer to the size of the array.
I've tried somethin along this line, but it raises a conversion error.
var
JSONBook: TJSONValue;
CountItems: integer;
begin
JSONBook := RESTResponse1.JSONValue;
ShowMessage(IntToStr(JSONBook.GetValue<string>('items').Length));
CountItems := JSONBook.GetValue<string>('items').Length;
for i := 0 to CountItems-1 do
begin
...
end;
end;
The items field is an array, so retrieving it as a string is just wrong, so it makes sense that reading the array count via a string length would not work.
Try this instead:
uses
..., System.JSON;
var
JSONBook, JSONItem: TJSONObject;
JSONItems: TJSONArray;
CountItems: integer;
begin
JSONBook := RESTResponse1.JSONValue as TJSONObject;
JSONItems := JSONBook.GetValue('items') as TJSONArray;
CountItems := JSONItems.Count;
ShowMessage(IntToStr(CountItems));
for i := 0 to CountItems-1 do
begin
JSONItem := JSONItems.Items[i] as TJSONObject;
...
end;
end;
Related
I have the following JSON structure, calling it from web:
[
{
"Code":"31212",
"Desc":"JOHN",
"DOYDESC":"MADRID",
"Street":"Str41",
"StreetNo":"86"
},
{
"Code":"30214",
"Desc":"GEORGE",
"DOYDESC":"NEW YORK",
"Street":"Str3",
"StreetNo":null
},
{
"Code":"09215",
"Desc":"MARY",
"DOYDESC":"PARIS",
"Street":"Str3",
"StreetNo":"22"
},
{
"Code":"10217",
"Desc":"MEGAN",
"DOYDESC":"ROME",
"Street":"Str4",
"StreetNo":null
}
]
I want the user to give a number in Edit.Text, and then search the values of Code to find if the given value exists.
Is there a way to create an array named Code with the values from the JSON?
For example, to create something like this:
Code = ["31212","30214","09215","10217"]
and then make the search? Or, is there another way to find a specific value of Code from the JSON? I tried this so far:
procedure Tlog_form.Button2Click(Sender: TObject);
var
jso : TJsonObject;
jsv,jsval : TJsonValue;
jsa,jsarr : TJsonArray;
data,str : string;
i,j,user : integer;
jsp : TJsonPair;
arr : array of string;
begin
try
data := GetURLAsString('http://...');
except
on E: exception do
end;
try
jsv := TJSONObject.ParseJSONValue(data);
try
jsa := jsv as TJSONArray;
try
for I := 0 to jsa.Size - 1 do
begin
jso := jsa.Get(i) as TJsonObject;
if jso.ToString = 'Code' then
begin
str := jso.GetValue('Code').ToString;
if Edit1.Text = str then
begin
ShowMessage('found it');
end;
end;
end;
finally
end;
finally
jsv.Free;
end;
except
on E: exception do
end;
end;
When I debug, it doesn't get any error. but it still doesn't work.
You are converting each TJSONObject in the array to a string, and then comparing that to your TEdit text. Which will obviously not match. You need to compare only the Code field of each TJSONObject, which you would be doing if you remove the if jso.ToString = 'Code' then check completely, eg:
procedure Tlog_form.Button2Click(Sender: TObject);
var
jsv : TJSONValue;
jsa : TJSONArray;
jso : TJSONObject;
data, str, code : string;
I : integer;
begin
str := Edit1.Text;
try
data := GetURLAsString('http://...');
jsv := TJSONObject.ParseJSONValue(data);
if jsv <> nil then
try
jsa := jsv as TJSONArray;
for I := 0 to jsa.Size - 1 do
begin
jso := jsa.Get(I) as TJSONObject;
code := jso.GetValue('Code').ToString;
if str = code then
begin
ShowMessage('found it');
end;
end;
finally
jsv.Free;
end;
except
end;
end;
I'm not sure I understand you very well, but if you try TALJsonDocument (https://github.com/Zeus64/alcinoe), you have this function:
Function ALFindJsonNodeByTextChildNodeValue(const JsonNode:TalJsonNode;
Const ChildNodeName: AnsiString;
Const ChildNodeValue : AnsiString;
Const Recurse: Boolean = False): TALJsonNode;
Sorry, I searched here for This problem on the site
But the Json I have is unlike any other here on the site Because it begins with '['
and I got tired trying to extract the values
Then how I can Extract Values from key and array on JSON begins with '['
[{"date":"12/11/1990","name":"Delphi7"},{"date":"03/05/2012","name":"Delphi 10.4"}]
Or extract Form This :
[{"User":{"date":"12/11/1990","name":"Delphi7"}},{"User":{"date":"03/05/2012","name":"Delphi 10.4"}}]
In JSON, [] denotes an array. In this case, both examples you have provided represent an array of objects.
If you parse these strings using TJSONObject.ParseJSONValue(), it will return a TJSONValue pointer to a TJSONArray object that is holding TJSONObject elements, eg:
uses
..., System.JSON;
var
JSONStr, DateStr, NameStr: string;
JSONVal: TJSONValue;
JSONArr: TJSONArray;
JSONObj: TJSONObject;
I: Integer;
begin
JSONStr := '[{"date":"12/11/1990","name":"Delphi7"},{"date":"03/05/2012","name":"Delphi 10.4"}]';
JSONVal := TJSONObject.ParseJSONValue(JSONStr);
try
JSONArr := JSONVal as TJSONArray;
for I := 0 to JSONArr.Count-1 do
begin
JSONObj := JSONArr[I] as TJSONObject;
DateStr := JSONObj.GetValue('date').Value;
NameStr := JSONObj.GetValue('name').Value;
...
end;
finally
JSONVal.Free;
end;
end;
uses
..., System.JSON;
var
JSONStr, DateStr, NameStr: string;
JSONVal: TJSONValue;
JSONArr: TJSONArray;
JSONObj, JSONUser: TJSONObject;
I: Integer;
begin
JSONStr := '[{"User":{"date":"12/11/1990","name":"Delphi7"}},{"User":{"date":"03/05/2012","name":"Delphi 10.4"}}]';
JSONVal := TJSONObject.ParseJSONValue(JSONStr);
try
JSONArr := JSONVal as TJSONArray;
for I := 0 to JSONArr.Count-1 do
begin
JSONObj := JSONArr[I] as TJSONObject;
JSONUser := JSONObj.GetValue('User') as TJSONObject;
DateStr := JSONUser.GetValue('date').Value;
NameStr := JSONUser.GetValue('name').Value;
...
end;
finally
JSONVal.Free;
end;
end;
I have a problem to parse an array in Json. The Json is like this example:
[
[
A1,
A2,
A3,
],
[
B1,
B2,
B3,
],
and so on.
I get always an access violation error if I try to parse it:
procedure tform1.test;
var
i:integer
value,A:string;
jValue:TJSONValue;
JSonValue:TJSonValue;
Jarray:TJSONArray;
begin
jValue:=RESTResponse1.JSONValue;
Jarray := TJSonObject.ParseJSONValue(value) as tjsonarray;
for i := 0 to Jarray.Count - 1 do
A:=Jarray.items[i].value;
end;
What am I doing wrong?
Use JsonValue as TJSONArray twice. A working example:
procedure TForm1.Test1;
var
I: Integer;
Value, A: String;
jValue: TJSONValue;
JSonValue1, JSonValue2: TJSonValue;
JArray, JArr: TJSONArray;
begin
Value := '[["A1","A2","A3"],["B1","B2","B3"]]';
JsonValue1 := TJSonObject.ParseJSONValue(Value);
try
JArray := JsonValue1 as TJSONArray;
for JsonValue2 in JArray do
begin
JArr := JsonValue2 as TJSONArray;
A := JArr.Items[0].Value;
ShowMessage(A);
end;
finally
JsonValue1.Free;
end;
end;
I have been searching the internet for a couple of days and have been trying out lots of things but I did not manage to create a JSONArray without a name yet.
Normally a JSONArray looks like this:
"MyArray" [
//content
]
But I need this:
[
//content
]
My JSON-File needs to look like this in the end:
[
{
"videos":"Hello.MOV",
"render-status":"ready",
"output":"test\\out1.mov"
},
{
"videos":"123.MOV",
"render-status":"ready",
"output":"test\\out1.mov"
},
]
By the way I am using Delphi 10.2.
Can anyone point me in the right direction?
Micha
You can use the Stadard System.JSON objects in Delphi as well.
uses
System.JSON;
function CreateArray: TJSONArray;
var
LTempObject: TJSONOBject;
begin
Result := TJSONArray.Create;
LTempObject := TJSONOBject.Create;
LTempObject.AddPair('videos', 'Hello.MOV');
LTempObject.AddPair('render-status', 'ready');
LTempObject.AddPair('output', 'test\out1.mov');
Result.AddElement(LTempObject);
LTempObject := TJSONOBject.Create;
LTempObject.AddPair('videos', '123.MOV');
LTempObject.AddPair('render-status', 'ready');
LTempObject.AddPair('output', 'test\out1.mov');
Result.AddElement(LTempObject);
end;
Use Like so:
var
LJSON: TJSONArray;
begin
LJSON := CreateArray;
//Will give you exact string as above
//without and formatting
memo.Text := LJSON.ToJSON;
end;
Using JsonDataObjects
uses
JsonDataObjects;
const
JSON_ARRAY =
'[{"videos":"Hello.MOV","render-status":"ready","output":"test\\out1.mov"},{"videos":"123.MOV","render-status":"ready","output":"test\\out1.mov"}]';
procedure TJsonTests.BuildArrayTest;
var
A: TJsonArray;
O: TJsonObject;
V: string;
begin
A := TJsonArray.Create;
try
O := A.AddObject;
O.S['videos'] := 'Hello.MOV';
O.S['render-status'] := 'ready';
O.S['output'] := 'test\out1.mov';
O := A.AddObject;
O.S['videos'] := '123.MOV';
O.S['render-status'] := 'ready';
O.S['output'] := 'test\out1.mov';
CheckEquals(2, A.Count);
V:= A.ToJSON();
CheckEquals(JSON_ARRAY, V);
finally
A.Free;
end;
end;
procedure TJsonTests.ParseArrayTest;
var
A: TJsonArray;
V: string;
begin
A := TJsonArray.Create;
try
A.FromUtf8JSON(JSON_ARRAY);
CheckEquals(2, A.Count);
V:= A.ToJSON();
CheckEquals(JSON_ARRAY, V);
finally
A.Free;
end;
end;
I have function to search for TItem (my own class) in array of TItem.
function IndexOfArray(const Value: TItem; Things: array of TItem): integer;
var
i: integer;
begin
Result := -1;
for i := Low(Things) to High(Things) do
if Value = Things[i] then
begin
Result := i;
Break;
end;
end;
It's working for array of TItem. But I want to use it with TItem or TIamge or TLabel. I tried TObject or TComponent as input parameters of this method, but compiler shouts:
E2010 Incompatible types: 'array of TComponent' and 'Dynamic array'
The array of TLabel/TImage/TItem MUST be dynamic. Any ideas please?
TArray.BinarySearch does that for you.
if TArray.BinarySearch<TLabel>(Labels,LabelLoaded,index) then
// Index holds the index of the found item
Note: BinarySearch requires that the array be sorted.
If you just want to compare the pointer value of the objects, here is an example:
Type
TMyArray = record
class function IndexOfArray<T:Class>(const value: T; const Things: array of T): Integer; static;
end;
class function TMyArray.IndexOfArray<T>(const value: T; const Things: array of T): Integer;
var
i: Integer;
begin
for i := 0 to High(Things) do
if value = Things[i] then
Exit(i);
Result := -1;
end;
If you want to write your own bicycle you can try something like this:
type
myAr = array of TObject;
. . .
function IndexOfArray(const Value: TObject; Things: myAr): integer;
var
i: integer;
begin
Result := -1;
for i := Low(Things) to High(Things) do
if (Things[i] is Value.ClassType) and // don't sure that this is nessesary
(Value = Things[i]) then
begin
Result := i;
Break;
end;
end;
procedure someProc;
var
ar : myAr;
lbl : TLabel;
i : integer;
begin
SetLength(ar, 10);
for I := Low(ar) to High(ar) do
ar[i] := TLabel.Create(self);
lbl := TLabel.Create(Self);
i := IndexOfArray(lbl, ar);
end;
Also you can use standard System.Generics.Collections.TArray.BinarySearch class.