Reputation: 805
Can someone please help me with the correct syntax to access a string inside a nested object using JSONDataObjects from Andreas Hausladen
I have a JSON string returned from an API that contains an array of customers followed by a cursor pagination object (meta) eg
{
"customers": [
{
"id": "CU000DWEQWMRN4",
"email": "[email protected]",
"metadata": {
"member_name": "BLOGGS jim",
"membership_id": "4088"
}
},
{
"id": "CU000DVEKR579S",
"email": "[email protected]",
"metadata": {
"membership_id": "5647"
}
}
],
"meta": {
"cursors": {
"before": null,
"after": "ID456"
},
"limit": 50
}
}
I an trying to get the values of before
and after
inside the meta
object at the end
What I have tried
var Obj: TJsonObject;
AfterID : string;
begin
Obj := TJsonObject.Parse(theJSON) as TJsonObject;
AfterID := Obj['meta']['cursors']['after'] ;
Problem I get the error message cannot convert object to string
I also tried
var
Obj: TJsonObject;
AfterID : string;
begin
obj := Obj['meta'];
Obj := Obj['cursors'];
AfterID := Obj['after'];
Problem I get the error message cannot convert object to string
I've also tried many other combinations of syntax but I won't clutter the question with all of those!
I am puzzled as I my syntax is correct when doing the same thing with a slightly different JSON retuned from another API that has a simpler cursor pagination structure eg
{
"items": [
{
"event": "accepted",
"id": "G3wOhh",
"user-variables": {},
"log-level": "info",
"method": "smtp"
},
{
"event": "accepted",
"id": "KLT56",
"user-variables": {},
"log-level": "info",
"method": "smtp"
}
],
"paging": {
"previous": "line 4",
"first": "line 1",
"last": "line 12",
"next": "line 6"
}
}
with this JSON, using
var
Obj : TJsonObject;
nextID : string;
begin
Obj := TJsonObject.Parse(TheReturnedJSON) as TJDOJsonObject;
nextID := Obj['paging']['next'];
I get the correct value returned
Upvotes: 1
Views: 577
Reputation: 805
Incidentally, I'll add to Remy's answer to say that since the value of 'before'
in my sample JSON was null
, I found I had to use the following code to avoid getting another typecast error when reading that value as Obj.Values['meta'].O['cursors'].S['before'];
var
temp : variant;
BeforeID : string;
begin
//read the value into a variant by using .V just in case it's null.
//if it is then reading a string using .S gives an error
temp := Obj.Values['meta'].O['cursors'].V['before'];
if not VarIsNull(temp) then // it's not a null so we can convert to a string
BeforeID := VarToStr(temp)
else // it is null so assign whatever string is appropriate
BeforeID := '';
But using .V
was just a guess. I'd love to know where all this is documented!
Upvotes: 1
Reputation: 596582
TJsonObject
's default []
property is its Values[]
property, which returns a TJsonDataValueHelper
:
property Values[const Name: string]: TJsonDataValueHelper read GetValue write SetValue; default;
So, reading Obj['cursors']
returns a TJsonDataValueHelper
, not a TJsonObject
.
TJsonDataValueHelper
's default []
property is its O[]
property, which returns a TJsonDataValueHelper
representing a JSON object, not a JSON string:
property O[const Name: string]: TJsonDataValueHelper read {$IFDEF BCB}GetObj{$ELSE}GetObject{$ENDIF} write SetObject; default;
TJsonDataValueHelper
has an S[]
property to read a string value:
property S[const Name: string]: string read GetObjectString write SetObjectString; // returns '' if property doesn't exist, auto type-cast except for array/object
So, try this instead:
AfterID := Obj['meta']['cursors'].S['after'];
nextID := Obj['paging'].S['next'];
Alternatively, don't use TJsonDataValueHelper
at all. TJsonObject
has an O[]
property that returns a TJsonObject
, and an S[]
property for reading a string:
property S[const Name: string]: string read GetString write SetString; // returns '' if property doesn't exist, auto type-cast except for array/object
...
property O[const Name: string]: TJsonObject read {$IFDEF BCB}GetObj{$ELSE}GetObject{$ENDIF} write SetObject; // auto creates object on first access
For example:
AfterID := Obj.O['meta'].O['cursors'].S['after'];
nextID := Obj.O['paging'].S['next'];
Upvotes: 1