Difference between revisions of "fcl-json"
(→Examples: Add traversig items example) |
m (Slightly changed English grammar and capitalisation a bit. Also fixed some inconsistent indentation here and there :)) |
||
Line 3: | Line 3: | ||
= Info = | = Info = | ||
− | fcl-json is [[JSON]] implementation. | + | fcl-json is a [[JSON]] implementation. |
− | + | It contains units such as: | |
* fpjson: base unit which implements TJsonData and its children, e.g. TJsonObject | * fpjson: base unit which implements TJsonData and its children, e.g. TJsonObject | ||
− | * jsonParser: implements TJsonParser used in example below | + | * jsonParser: implements TJsonParser, used in the [[#From_JsonViewer|From JsonViewer]] example below |
− | * jsonConf: implements TJsonConfig which is handy to read/write application data to files | + | * jsonConf: implements TJsonConfig which is handy to read/write application data from/to files |
* jsonScanner: json source lexical analyzer | * jsonScanner: json source lexical analyzer | ||
Line 27: | Line 27: | ||
<syntaxhighlight> | <syntaxhighlight> | ||
− | uses fpjson, jsonparser; | + | uses |
+ | fpjson, jsonparser; | ||
procedure JSONTest; | procedure JSONTest; | ||
var | var | ||
− | + | jData : TJSONData; | |
− | + | jObject : TJSONObject; | |
− | + | jArray : TJSONArray; | |
− | + | s : String; | |
begin | begin | ||
− | + | ||
− | + | // this is only a minimal sampling of what can be done with this API | |
− | + | // create from string | |
− | + | jData := GetJSON('{"Fld1" : "Hello", "Fld2" : 42, "Colors" : ["Red", "Green", "Blue"]}'); | |
− | + | // output as a flat string | |
− | + | s := jData.AsJSON; | |
− | + | // output as nicely formatted JSON | |
− | + | s := jData.FormatJSON; | |
− | + | // cast as TJSONObject to make access easier | |
− | + | jObject := TJSONObject(jData); | |
− | + | // retrieve value of Fld1 | |
− | + | s := jObject.Get('Fld1'); | |
− | + | // change value of Fld2 | |
− | + | jObject.Integers['Fld2'] := 123; | |
− | + | // retrieve the second color | |
− | + | s := jData.FindPath('Colors[1]').AsString; | |
− | + | // add a new element | |
− | + | jObject.Add('Happy', True); | |
− | + | // add a new sub-array | |
− | + | jArray := TJSONArray.Create; | |
− | + | jArray.Add('North'); | |
− | + | jArray.Add('South'); | |
− | + | jArray.Add('East'); | |
− | + | jArray.Add('West'); | |
− | + | jObject.Add('Directions', jArray); | |
end; | end; | ||
Line 85: | Line 86: | ||
jData : TJSONData; | jData : TJSONData; | ||
jItem : TJSONData; | jItem : TJSONData; | ||
− | i, j: | + | i, j: Integer; |
− | object_name, field_name, field_value, object_type, object_items: | + | object_name, field_name, field_value, object_type, object_items: String; |
begin | begin | ||
jData := GetJSON('{"A":{"field1":0, "field2": false},"B":{"field1":0, "field2": false}}'); | jData := GetJSON('{"A":{"field1":0, "field2": false},"B":{"field1":0, "field2": false}}'); | ||
Line 116: | Line 117: | ||
<syntaxhighlight> | <syntaxhighlight> | ||
− | uses jsonConf; | + | uses |
+ | jsonConf; | ||
procedure TfmMain.SaveOptionsPos; | procedure TfmMain.SaveOptionsPos; | ||
Line 122: | Line 124: | ||
c: TJSONConfig; | c: TJSONConfig; | ||
begin | begin | ||
− | c:= TJSONConfig.Create( | + | c:= TJSONConfig.Create(Nil); |
try | try | ||
c.Filename:= GetAppPath(cFileHistory); | c.Filename:= GetAppPath(cFileHistory); | ||
Line 140: | Line 142: | ||
procedure TfmMain.LoadOptionsPos; | procedure TfmMain.LoadOptionsPos; | ||
var | var | ||
− | nLeft, nTop, nW, nH: | + | nLeft, nTop, nW, nH: Integer; |
c: TJSONConfig; | c: TJSONConfig; | ||
begin | begin | ||
− | c:= TJSONConfig.Create( | + | c:= TJSONConfig.Create(Nil); |
try | try | ||
c.Filename:= GetAppPath(cFileHistory); | c.Filename:= GetAppPath(cFileHistory); | ||
Line 166: | Line 168: | ||
//Example of path: '/list_find' | //Example of path: '/list_find' | ||
− | procedure SLoadStringsFromFile(cfg: TJsonConfig; const path: | + | procedure SLoadStringsFromFile(cfg: TJsonConfig; const path: String; List: TStrings); |
var | var | ||
− | i: | + | i: Integer; |
s: UnicodeString; | s: UnicodeString; | ||
begin | begin | ||
Line 175: | Line 177: | ||
begin | begin | ||
s:= cfg.GetValue(path+'/'+inttostr(i), ''); | s:= cfg.GetValue(path+'/'+inttostr(i), ''); | ||
− | if s='' then Break; | + | if s='' then |
+ | Break; | ||
List.Add(Utf8Encode(s)); | List.Add(Utf8Encode(s)); | ||
end; | end; | ||
end; | end; | ||
− | procedure SSaveStringsToFile(cfg: TJsonConfig; const path: | + | procedure SSaveStringsToFile(cfg: TJsonConfig; const path: String; List: TStrings); |
var | var | ||
− | i: | + | i: Integer; |
− | s: | + | s: String; |
begin | begin | ||
for i:= 0 to OptMaxHistoryItems-1 do | for i:= 0 to OptMaxHistoryItems-1 do | ||
Line 203: | Line 206: | ||
<syntaxhighlight> | <syntaxhighlight> | ||
procedure TMainForm.OpenFile(Const AFileName : String); | procedure TMainForm.OpenFile(Const AFileName : String); | ||
− | + | var | |
− | |||
S : TFileStream; | S : TFileStream; | ||
P : TJSONParser; | P : TJSONParser; | ||
Line 229: | Line 231: | ||
procedure TMainForm.ShowJSONDocument; | procedure TMainForm.ShowJSONDocument; | ||
− | |||
begin | begin | ||
− | + | with TVJSON.Items do | |
− | + | begin | |
BeginUpdate; | BeginUpdate; | ||
try | try | ||
TVJSON.Items.Clear; | TVJSON.Items.Clear; | ||
SHowJSONData(Nil,FRoot); | SHowJSONData(Nil,FRoot); | ||
− | + | with TVJSON do | |
− | + | if (Items.Count>0) and Assigned(Items[0]) then | |
− | + | begin | |
Items[0].Expand(False); | Items[0].Expand(False); | ||
Selected:=Items[0]; | Selected:=Items[0]; | ||
− | + | end; | |
finally | finally | ||
EndUpdate; | EndUpdate; | ||
end; | end; | ||
− | + | end; | |
end; | end; | ||
procedure TMainForm.ShowJSONData(AParent : TTreeNode; Data : TJSONData); | procedure TMainForm.ShowJSONData(AParent : TTreeNode; Data : TJSONData); | ||
− | + | var | |
− | |||
N,N2 : TTreeNode; | N,N2 : TTreeNode; | ||
I : Integer; | I : Integer; | ||
Line 257: | Line 257: | ||
C : String; | C : String; | ||
S : TStringList; | S : TStringList; | ||
− | |||
begin | begin | ||
N:=Nil; | N:=Nil; | ||
if Assigned(Data) then | if Assigned(Data) then | ||
− | + | begin | |
− | + | case Data.JSONType of | |
jtArray, | jtArray, | ||
jtObject: | jtObject: | ||
begin | begin | ||
− | + | if (Data.JSONType=jtArray) then | |
− | + | C:=SArray | |
− | + | else | |
− | + | C:=SObject; | |
− | + | N:=TVJSON.Items.AddChild(AParent,Format(C,[Data.Count])); | |
− | + | S:=TstringList.Create; | |
− | + | try | |
− | + | for I:=0 to Data.Count-1 do | |
− | + | if Data.JSONtype=jtArray then | |
− | + | S.AddObject(IntToStr(I),Data.items[i]) | |
− | + | else | |
− | + | S.AddObject(TJSONObject(Data).Names[i],Data.items[i]); | |
− | + | if FSortObjectMembers and (Data.JSONType=jtObject) then | |
− | + | S.Sort; | |
− | + | for I:=0 to S.Count-1 do | |
begin | begin | ||
− | + | N2:=TVJSON.Items.AddChild(N,S[i]); | |
− | + | D:=TJSONData(S.Objects[i]); | |
− | + | N2.ImageIndex:=ImageTypeMap[D.JSONType]; | |
− | + | N2.SelectedIndex:=ImageTypeMap[D.JSONType]; | |
− | + | ShowJSONData(N2,D); | |
end | end | ||
− | + | finally | |
− | + | S.Free; | |
− | + | end; | |
end; | end; | ||
jtNull: | jtNull: | ||
N:=TVJSON.Items.AddChild(AParent,SNull); | N:=TVJSON.Items.AddChild(AParent,SNull); | ||
− | + | else | |
− | + | N:=TVJSON.Items.AddChild(AParent,Data.AsString); | |
end; | end; | ||
− | + | if Assigned(N) then | |
− | + | begin | |
N.ImageIndex:=ImageTypeMap[Data.JSONType]; | N.ImageIndex:=ImageTypeMap[Data.JSONType]; | ||
N.SelectedIndex:=ImageTypeMap[Data.JSONType]; | N.SelectedIndex:=ImageTypeMap[Data.JSONType]; | ||
N.Data:=Data; | N.Data:=Data; | ||
− | |||
end; | end; | ||
+ | end; | ||
end; | end; | ||
</syntaxhighlight> | </syntaxhighlight> |
Revision as of 22:33, 1 August 2018
│
English (en) │
polski (pl) │
русский (ru) │
中文(中国大陆) (zh_CN) │
Info
fcl-json is a JSON implementation.
It contains units such as:
- fpjson: base unit which implements TJsonData and its children, e.g. TJsonObject
- jsonParser: implements TJsonParser, used in the From JsonViewer example below
- jsonConf: implements TJsonConfig which is handy to read/write application data from/to files
- jsonScanner: json source lexical analyzer
Note: In fpjson, accessing e.g. SomeJSONObject.Integers['price'] may give a SIGSEGV/Access Violation if that integer variable does not exist. This is apparently intentional, see [1]. You'd have to use the Find method (available since FPC 2.6.2) to first check if the element ('price' in this example) exists.
Streaming
fcl-json contains the unit "fpjsonrtti" which is used to load objects (TObject instances) from or save them to JSON format.
See Streaming JSON for a short example.
Examples
Getting Started
uses
fpjson, jsonparser;
procedure JSONTest;
var
jData : TJSONData;
jObject : TJSONObject;
jArray : TJSONArray;
s : String;
begin
// this is only a minimal sampling of what can be done with this API
// create from string
jData := GetJSON('{"Fld1" : "Hello", "Fld2" : 42, "Colors" : ["Red", "Green", "Blue"]}');
// output as a flat string
s := jData.AsJSON;
// output as nicely formatted JSON
s := jData.FormatJSON;
// cast as TJSONObject to make access easier
jObject := TJSONObject(jData);
// retrieve value of Fld1
s := jObject.Get('Fld1');
// change value of Fld2
jObject.Integers['Fld2'] := 123;
// retrieve the second color
s := jData.FindPath('Colors[1]').AsString;
// add a new element
jObject.Add('Happy', True);
// add a new sub-array
jArray := TJSONArray.Create;
jArray.Add('North');
jArray.Add('South');
jArray.Add('East');
jArray.Add('West');
jObject.Add('Directions', jArray);
end;
Traversing Items
uses
Classes, TypInfo, fpjson, jsonparser;
procedure JSONItems(Info: TStrings);
var
jData : TJSONData;
jItem : TJSONData;
i, j: Integer;
object_name, field_name, field_value, object_type, object_items: String;
begin
jData := GetJSON('{"A":{"field1":0, "field2": false},"B":{"field1":0, "field2": false}}');
for i := 0 to jData.Count - 1 do
begin
jItem := jData.Items[i];
object_type := GetEnumName(TypeInfo(TJSONtype), Ord(jItem.JSONType));
object_name := TJSONObject(jData).Names[i];
WriteStr(object_items, jItem.Count);
Info.Append('object type: ' + object_type + '|object name: ' + object_name + '|number of fields: ' + object_items);
for j := 0 to jItem.Count - 1 do
begin
field_name := TJSONObject(jItem).Names[j];
field_value := jItem.FindPath(TJSONObject(jItem).Names[j]).AsString;
Info.Append(field_name + '|' + field_value);
end;
end;
jData.Free;
end;
Save/load dialog position/size
uses
jsonConf;
procedure TfmMain.SaveOptionsPos;
var
c: TJSONConfig;
begin
c:= TJSONConfig.Create(Nil);
try
c.Filename:= GetAppPath(cFileHistory);
c.SetValue('/dialog/max', WindowState=wsMaximized);
if WindowState<>wsMaximized then
begin
c.SetValue('/dialog/posx', Left);
c.SetValue('/dialog/posy', Top);
c.SetValue('/dialog/sizex', Width);
c.SetValue('/dialog/sizey', Height);
end;
finally
c.Free;
end;
end;
procedure TfmMain.LoadOptionsPos;
var
nLeft, nTop, nW, nH: Integer;
c: TJSONConfig;
begin
c:= TJSONConfig.Create(Nil);
try
c.Filename:= GetAppPath(cFileHistory);
nLeft:= c.GetValue('/dialog/posx', Left);
nTop:= c.GetValue('/dialog/posy', Top);
nW:= c.GetValue('/dialog/sizex', Width);
nH:= c.GetValue('/dialog/sizey', Height);
SetBounds(nLeft, nTop, nW, nH);
if c.GetValue('/dialog/max', false) then
WindowState:= wsMaximized;
finally
c.Free;
end;
end;
Save/load TStringList
//Example of path: '/list_find'
procedure SLoadStringsFromFile(cfg: TJsonConfig; const path: String; List: TStrings);
var
i: Integer;
s: UnicodeString;
begin
List.Clear;
for i:= 0 to OptMaxHistoryItems-1 do
begin
s:= cfg.GetValue(path+'/'+inttostr(i), '');
if s='' then
Break;
List.Add(Utf8Encode(s));
end;
end;
procedure SSaveStringsToFile(cfg: TJsonConfig; const path: String; List: TStrings);
var
i: Integer;
s: String;
begin
for i:= 0 to OptMaxHistoryItems-1 do
begin
if i<List.Count then
s:= List[i]
else
s:= '';
cfg.SetDeleteValue(path+'/'+inttostr(i), Utf8Decode(s), '');
end;
end;
From JsonViewer
Example usage can be found in the Lazarus jsonviewer tool (located in lazarus/tools/jsonviewer). In particular, this part of the tool shows how to use json:
procedure TMainForm.OpenFile(Const AFileName : String);
var
S : TFileStream;
P : TJSONParser;
D : TJSONData;
begin
S:=TFileStream.Create(AFileName,fmOpenRead);
try
P:=TJSONParser.Create(S);
try
P.Strict:=FStrict;
D:=P.Parse;
finally
P.Free;
end;
finally
S.Free;
end;
FFileName:=AFileName;
SetCaption;
FreeAndNil(FRoot);
FRoot:=D;
ShowJSONDocument;
end;
procedure TMainForm.ShowJSONDocument;
begin
with TVJSON.Items do
begin
BeginUpdate;
try
TVJSON.Items.Clear;
SHowJSONData(Nil,FRoot);
with TVJSON do
if (Items.Count>0) and Assigned(Items[0]) then
begin
Items[0].Expand(False);
Selected:=Items[0];
end;
finally
EndUpdate;
end;
end;
end;
procedure TMainForm.ShowJSONData(AParent : TTreeNode; Data : TJSONData);
var
N,N2 : TTreeNode;
I : Integer;
D : TJSONData;
C : String;
S : TStringList;
begin
N:=Nil;
if Assigned(Data) then
begin
case Data.JSONType of
jtArray,
jtObject:
begin
if (Data.JSONType=jtArray) then
C:=SArray
else
C:=SObject;
N:=TVJSON.Items.AddChild(AParent,Format(C,[Data.Count]));
S:=TstringList.Create;
try
for I:=0 to Data.Count-1 do
if Data.JSONtype=jtArray then
S.AddObject(IntToStr(I),Data.items[i])
else
S.AddObject(TJSONObject(Data).Names[i],Data.items[i]);
if FSortObjectMembers and (Data.JSONType=jtObject) then
S.Sort;
for I:=0 to S.Count-1 do
begin
N2:=TVJSON.Items.AddChild(N,S[i]);
D:=TJSONData(S.Objects[i]);
N2.ImageIndex:=ImageTypeMap[D.JSONType];
N2.SelectedIndex:=ImageTypeMap[D.JSONType];
ShowJSONData(N2,D);
end
finally
S.Free;
end;
end;
jtNull:
N:=TVJSON.Items.AddChild(AParent,SNull);
else
N:=TVJSON.Items.AddChild(AParent,Data.AsString);
end;
if Assigned(N) then
begin
N.ImageIndex:=ImageTypeMap[Data.JSONType];
N.SelectedIndex:=ImageTypeMap[Data.JSONType];
N.Data:=Data;
end;
end;
end;
FpcTwit
The fpctwit library makes use of JSON to send/receive data.
See also
- An article covering use of XML and JSON in FreePascal: PDF
- Package List