You can skip straight to the code, if you want to. The leading text is explanation, but not necessary.
I am trying to use SuperObject to parse Delphi.
I was just using the plain JSON classes that come with Delphi 10.4, but had difficulty with some slightly complex functionality.
E.g stuff, such as does a.b.c
exist, or a.b.c.d
- where d
is an array - or a.b.c.d[3]
.
And how to iterate over a.b.c.d
. And to assign a value to a.b.c.d.e
, updating it if it exists, creating it if not; and, if only part of the path exists, create it all e.g only a.b
exists and I want to assign a value to a.b.c.d[3].e
.
If anyone can point me to some examples of that sort of thing, I would be grateful.
Now, to my question. It seemed from various posts that SuperObject would be the answer, but I am failing at my first basic step - to test the existence of a nested JSN element.
Here's my code (is there an online JSON Fiddle site?)
unit fMainForm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses System.IOUtils,
SuperObject;
procedure TForm1.FormCreate(Sender: TObject);
var json: ISuperObject;
jsonString : String;
begin
// Example JSON taken from https://stackoverflow.com/questions/10539797/complex-json-nesting-of-objects-and-arrays
jsonString := '{' +
'"problems": [{' +
' "Diabetes":[{' +
' "medications":[{' +
' "medicationsClasses":[{' +
' "className":[{' +
' "associatedDrug":[{' +
' "name":"asprin",' +
' "dose":"",' +
' "strength":"500 mg"' +
' }],' +
' "associatedDrug#2":[{' +
' "name":"somethingElse",' +
' "dose":"",' +
' "strength":"500 mg"' +
' }]' +
' }],' +
' "className2":[{' +
' "associatedDrug":[{' +
' "name":"asprin",' +
' "dose":"",' +
' "strength":"500 mg"' +
' }],' +
' "associatedDrug#2":[{' +
' "name":"somethingElse",' +
' "dose":"",' +
' "strength":"500 mg"' +
' }]' +
' }]' +
' }]' +
' }],' +
' "labs":[{' +
' "missing_field": "missing_value"' +
' }]' +
' }],' +
' "Asthma":[{}]' +
'}]}';
json := SO(jsonString);
if json.AsObject.Exists('problems') then
Memo1.Lines.Add('"problems" found')
else
Memo1.Lines.Add('"problems" not found');
if json.AsObject.Exists('problems.Diabetes') then
Memo1.Lines.Add('"problems.Diabetes" found')
else
Memo1.Lines.Add('"problems.Diabetes" not found');
end;
end.
When I run it, the memo contains
"problems" found
"problems.Diabetes" not found
How do I test for the existence of problems.Diabetes
?
If I can crack that, I will try to update the strength
of an associatedDrug
, then insert a new key/value pair into the associatedDrug
, then extend an existing key by adding several depths.
You've picked one of the worst JSON examples, because its structure needlessly puts everything into arrays (always
[{
and]}
) when array elements would be enough already. You should have grabbed an easier example and start with that, to get familiar with what an object is and what an array is. Likewise I restructured and shortened the JSON data to make it tinier and more clear. If you managed to understand that you can go on and reach yourstrength
property:Single step through it with the debugger to see how every check is necessary to finally even reach the property
Diabetes
and to then check if its value is actually a text (and not another object/array).A better format of that initial JSON data would be this, freed from needless arrays and using also numbers as datatypes instead of texts only (the syntax is valid, it may look odd for you but I think this is a more logical display):