Scenario
I use the JsonDataObjects unit by Andreas Hausladen in various places in my Delphi 2009 project, and now I have a requirement to parse the simple JSON returned by an API call to cpanel on a remote server.
Most of it I can do, but the JSON returned in this case appears, at least at the moment, to have an empty object {}
(not one that is null), and I would appreciate some help (a) testing for an empty object, and (b) obtaining some values from the object if it is not empty.
The data
The cpanel API documentation here says that the returns JSON has the form below where metadata is empty.
{
"apiversion": 3,
"func": "add_host",
"module": "Mysql",
"result": {
"data": null,
"errors": null,
"messages": null,
"metadata": { },
"status": 1,
"warnings": null
}
}
In fact, the documentation is wrong and the data I get back has this form, i.e. there is no results
object. However, the metadata
object is still empty, as in the documentation. I don't know what it will look like if the metadata
object is ever not empty. The documentation doesn't say.
{
"data":"MyData",
"errors":["The first error text"],
"warnings":null,
"status":0,
"messages":null,
"metadata":{}
}
The questions
How do I test for the object
MainObj['metadata']
being empty? It isn'tnull
as it contain{}
, soIf MainObj['metadata'].isnull ...
returns false, and the code drops into theelse
part.Once I have tested for it being empty, how do I extract the object's data (which presumably is null) when it doesn't have a name?
The problem code
This is a small test procedure to demonstrate my problem parsing this data. Most lines produce the expected result. The issue is with the object MainObj['metadata']
, which is (currently) empty in the JSON.
procedure TForm1.btn1Click(Sender: TObject);
const
THEJSON = ''
+' { '
+' "data":"MyData", '
+' "errors":["The first error text"], '
+' "warnings":null, '
+' "status":0, '
+' "messages":null, '
+' "metadata":{} '
+' } ';
var
MainObj, MetaDataObject: TJsonObject;
i : Integer;
begin
MainObj := TJsonObject.Parse(THEJSON) as TJsonObject;
try
if MainObj['data'].IsNull then
Memo2.Lines.Add('data = NULL')
else
Memo2.Lines.Add('data = ' + MainObj['data'].value);
if MainObj['warnings'].IsNull then
Memo2.Lines.Add('warnings = NULL')
else
Memo2.Lines.Add('warnings = ' + MainObj['warnings'].value);
if MainObj['status'].IsNull then
Memo2.Lines.Add('status = NULL')
else
Memo2.Lines.Add('status = ' + MainObj['status'].value);
if MainObj['messages'].IsNull then
Memo2.Lines.Add('messages = NULL')
else
Memo2.Lines.Add('messages = ' + MainObj['messages'].value);
if MainObj['errors'].IsNull then
Memo2.Lines.Add('errors = NULL')
else
for I := 0 to MainObj['errors'].count - 1 do
Memo2.Lines.Add('Error' + IntToStr(i) + ' = ' + MainObj['errors'].items[i]) ;
if MainObj['metadata'].isnull then
Memo2.Lines.Add('metadata = No object')
else
begin
//this is where it goes pear shaped!
MetaDataObject := TJsonObject.Parse(MainObj['metadata']) as TJsonObject; //cannot cast object to string???
try
Memo2.Lines.Add('metadata text is ' + MetaDataObject.ToString);
if MetaDataObject['????].isnull then / if MetaDataObject['????] is empty then //what goes here?
Memo2.Lines.Add('metadata = NULL')
else '
Memo2.Lines.Add('metadata = ' + MetaDataObject.Value);
finally
MetaDataObject.Free;
end;
end;
finally
MainObj.Free;
end;
end;
Expected result
data = MyData
warnings = NULL
status = 0
messages = NULL
Error0 = The first error text
followed by
metadata text is {}
metadata = NULL
Or, if there is data there, followed by
metadata text is {"meta_1":"mymeta"}
metadata = mymeta
Actual results
data = MyData
warnings = NULL
status = 0
messages = NULL
Error0 = The first error text
followed by a runtime error 'cannot cast object to string'.
What I have tried
if not Assigned(MetaDataObject) then ...
if not Assigned(MainObj['metadata']) then ...
if Assigned (TJsonObject(MainObj['metadata'])) then
MetaDataObject := TJsonObject.Parse(MainObj['metadata']) as TJsonObject;
Where I have looked