Sign in Join
Wiki copytemporary

fcl-json: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11# General info
22
3-fcl-json is a [[JSON]] implementation.
4-
5-It contains units such as:
3+fcl-json is a [[JSON]] implementation.
64
7-- fpjson: base unit which implements TJsonData and its children, e.g. TJsonObject
8-- jsonParser: implements TJsonParser, used in the From JsonViewer example below
9-- jsonConf: implements TJsonConfig which is handy to read/write application data from/to files
10-- jsonScanner: json source lexical analyzer
5+It contains units such as:
116
12-Note: In fpjson, accessing e.g.
7+ * fpjson: base unit which implements TJsonData and its children, e.g. TJsonObject
8+ * jsonParser: implements TJsonParser, used in the From JsonViewer example below
9+ * jsonConf: implements TJsonConfig which is handy to read/write application data from/to files
10+ * jsonScanner: json source lexical analyzer
1311
14-``` pascal
12+Note: In fpjson, accessing e.g.
13+```
1514SomeJSONObject.Integers['price']
1615```
1716
18-may give a SIGSEGV/Access Violation if that integer variable does not exist. This is apparently intentional, see [1](http://bugs.freepascal.org/view.php?id=22273). 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.
17+may give a SIGSEGV/Access Violation if that integer variable does not exist. This is apparently intentional, see [[1]](<http://bugs.freepascal.org/view.php?id=22273>). 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.
1918
2019# Streaming
2120
22-fcl-json contains the unit "fpjsonrtti" which is used to load objects (TObject instances) from or save them to JSON format.
21+fcl-json contains the unit "fpjsonrtti" which is used to load objects (TObject instances) from or save them to JSON format.
2322
24-See [[Streaming JSON]] for a short example.
23+See [[Streaming JSON]] for a short example.
2524
2625# Examples
2726
2827## Getting Started
29-
30-``` pascal
28+```
3129uses
32- fpjson, jsonparser;
33-
34-procedure JSONTest;
35-var
36- jData : TJSONData;
37- jObject : TJSONObject;
38- jArray : TJSONArray;
39- s : String;
40-begin
41- // this is only a minimal sampling of what can be done with this API
42-
43- // create from string
44- jData := GetJSON('{"Fld1" : "Hello", "Fld2" : 42, "Colors" : ["Red", "Green", "Blue"]}');
45-
46- // output as a flat string
47- s := jData.AsJSON;
48-
49- // output as nicely formatted JSON
50- s := jData.FormatJSON;
51-
52- // cast as TJSONObject to make access easier
53- jObject := jData as TJSONObject;
54-
55- // retrieve value of Fld1
56- s := jObject.Get('Fld1');
57-
58- // change value of Fld2
59- jObject.Integers['Fld2'] := 123;
60-
61- // retrieve the second color
62- s := jData.FindPath('Colors[1]').AsString;
63-
64- // add a new element
65- jObject.Add('Happy', True);
66-
67- // add a new sub-array
68- jArray := TJSONArray.Create;
69- jArray.Add('North');
70- jArray.Add('South');
71- jArray.Add('East');
72- jArray.Add('West');
73- jObject.Add('Directions', jArray);
74-
75-end;
30+ fpjson, jsonparser;
31+
32+ procedure JSONTest;
33+ var
34+ jData : TJSONData;
35+ jObject : TJSONObject;
36+ jArray : TJSONArray;
37+ s : String;
38+ begin
39+ // this is only a minimal sampling of what can be done with this API
40+
41+ // create from string
42+ jData := GetJSON('{"Fld1" : "Hello", "Fld2" : 42, "Colors" : ["Red", "Green", "Blue"]}');
43+
44+ // output as a flat string
45+ s := jData.AsJSON;
46+
47+ // output as nicely formatted JSON
48+ s := jData.FormatJSON;
49+
50+ // cast as TJSONObject to make access easier
51+ jObject := jData as TJSONObject;
52+
53+ // retrieve value of Fld1
54+ s := jObject.Get('Fld1');
55+
56+ // change value of Fld2
57+ jObject.Integers['Fld2'] := 123;
58+
59+ // retrieve the second color
60+ s := jData.FindPath('Colors[1]').AsString;
61+
62+ // add a new element
63+ jObject.Add('Happy', True);
64+
65+ // add a new sub-array
66+ jArray := TJSONArray.Create;
67+ jArray.Add('North');
68+ jArray.Add('South');
69+ jArray.Add('East');
70+ jArray.Add('West');
71+ jObject.Add('Directions', jArray);
72+
73+ end;
7674```
7775
78-Note: it's necessary to free jData when you have finished with it. Otherwise a memory leak is created.
76+Note: it's necessary to free jData when you have finished with it. Otherwise a memory leak is created.
7977
8078## Traversing Items
81-
82-``` pascal
79+```
8380uses
84- Classes, TypInfo, fpjson, jsonparser;
85-
86-procedure JSONItems(Info: TStrings);
87-var
88- jData : TJSONData;
89- jItem : TJSONData;
90- i, j: Integer;
91- object_name, field_name, field_value, object_type, object_items: String;
92-begin
93- jData := GetJSON('{"A":{"field1":0, "field2": false},"B":{"field1":0, "field2": false}}');
94-
95- for i := 0 to jData.Count - 1 do
96- begin
97- jItem := jData.Items[i];
98-
99- object_type := GetEnumName(TypeInfo(TJSONtype), Ord(jItem.JSONType));
100- object_name := TJSONObject(jData).Names[i];
101- WriteStr(object_items, jItem.Count);
102-
103- Info.Append('object type: ' + object_type + '|object name: ' + object_name + '|number of fields: ' + object_items);
104-
105- for j := 0 to jItem.Count - 1 do
81+ Classes, TypInfo, fpjson, jsonparser;
82+
83+ procedure JSONItems(Info: TStrings);
84+ var
85+ jData : TJSONData;
86+ jItem : TJSONData;
87+ i, j: Integer;
88+ object_name, field_name, field_value, object_type, object_items: String;
10689 begin
107- field_name := TJSONObject(jItem).Names[j];
108- field_value := jItem.FindPath(TJSONObject(jItem).Names[j]).AsString;
109-
110- Info.Append(field_name + '|' + field_value);
90+ jData := GetJSON('{"A":{"field1":0, "field2": false},"B":{"field1":0, "field2": false}}');
91+
92+ for i := 0 to jData.Count - 1 do
93+ begin
94+ jItem := jData.Items[i];
95+
96+ object_type := GetEnumName(TypeInfo(TJSONtype), Ord(jItem.JSONType));
97+ object_name := TJSONObject(jData).Names[i];
98+ WriteStr(object_items, jItem.Count);
99+
100+ Info.Append('object type: ' + object_type + '|object name: ' + object_name + '|number of fields: ' + object_items);
101+
102+ for j := 0 to jItem.Count - 1 do
103+ begin
104+ field_name := TJSONObject(jItem).Names[j];
105+ field_value := jItem.FindPath(TJSONObject(jItem).Names[j]).AsString;
106+
107+ Info.Append(field_name + '|' + field_value);
108+ end;
109+ end;
110+
111+ jData.Free;
111112 end;
112- end;
113-
114- jData.Free;
115-end;
116113```
117114
118115## Save/load form position to/from file
119-
120-``` pascal
116+```
121117uses
122- jsonConf;
123-
124-procedure SaveFormPos(AForm: TForm; const AFilename: string);
125-var
126- c: TJSONConfig;
127-begin
128- c:= TJSONConfig.Create(Nil);
129- try
130- //try/except to handle broken json file
131- try
132- c.Formatted:= true;
133- c.Filename:= AFilename;
134- except
135- exit;
136- end;
137-
138- c.SetValue('/dialog/max', AForm.WindowState=wsMaximized);
139- if AForm.WindowState<>wsMaximized then
118+ jsonConf;
119+
120+ procedure SaveFormPos(AForm: TForm; const AFilename: string);
121+ var
122+ c: TJSONConfig;
140123 begin
141- c.SetValue('/dialog/posx', AForm.Left);
142- c.SetValue('/dialog/posy', AForm.Top);
143- c.SetValue('/dialog/sizex', AForm.Width);
144- c.SetValue('/dialog/sizey', AForm.Height);
124+ c:= TJSONConfig.Create(Nil);
125+ try
126+ //try/except to handle broken json file
127+ try
128+ c.Formatted:= true;
129+ c.Filename:= AFilename;
130+ except
131+ exit;
132+ end;
133+
134+ c.SetValue('/dialog/max', AForm.WindowState=wsMaximized);
135+ if AForm.WindowState<>wsMaximized then
136+ begin
137+ c.SetValue('/dialog/posx', AForm.Left);
138+ c.SetValue('/dialog/posy', AForm.Top);
139+ c.SetValue('/dialog/sizex', AForm.Width);
140+ c.SetValue('/dialog/sizey', AForm.Height);
141+ end;
142+ finally
143+ c.Free;
144+ end;
145145 end;
146- finally
147- c.Free;
148- end;
149-end;
150-
151-procedure LoadFormPos(AForm: TForm; const AFilename: string);
152-var
153- nLeft, nTop, nW, nH: Integer;
154- c: TJSONConfig;
155-begin
156- c:= TJSONConfig.Create(Nil);
157- try
158- //try/except to handle broken json file
159- try
160- c.Formatted:= true;
161- c.Filename:= AFilename;
162- except
163- exit;
146+
147+ procedure LoadFormPos(AForm: TForm; const AFilename: string);
148+ var
149+ nLeft, nTop, nW, nH: Integer;
150+ c: TJSONConfig;
151+ begin
152+ c:= TJSONConfig.Create(Nil);
153+ try
154+ //try/except to handle broken json file
155+ try
156+ c.Formatted:= true;
157+ c.Filename:= AFilename;
158+ except
159+ exit;
160+ end;
161+
162+ nLeft:= c.GetValue('/dialog/posx', AForm.Left);
163+ nTop:= c.GetValue('/dialog/posy', AForm.Top);
164+ nW:= c.GetValue('/dialog/sizex', AForm.Width);
165+ nH:= c.GetValue('/dialog/sizey', AForm.Height);
166+ AForm.SetBounds(nLeft, nTop, nW, nH);
167+
168+ if c.GetValue('/dialog/max', false) then
169+ AForm.WindowState:= wsMaximized;
170+ finally
171+ c.Free;
172+ end;
164173 end;
165-
166- nLeft:= c.GetValue('/dialog/posx', AForm.Left);
167- nTop:= c.GetValue('/dialog/posy', AForm.Top);
168- nW:= c.GetValue('/dialog/sizex', AForm.Width);
169- nH:= c.GetValue('/dialog/sizey', AForm.Height);
170- AForm.SetBounds(nLeft, nTop, nW, nH);
171-
172- if c.GetValue('/dialog/max', false) then
173- AForm.WindowState:= wsMaximized;
174- finally
175- c.Free;
176- end;
177-end;
178174```
179175
180176## Save/load TStringList
181-
182-``` pascal
177+```
183178uses
184- jsonConf;
185-var
186- cfg: TJSONConfig;
187- List: TStringList;
188- path: string;
189-begin
190- List:= TStringList.Create;
191- cfg:= TJSONConfig.Create(nil);
192- try
193- //try/except to handle broken json file
194- try
195- cfg.Formatted:= true;
196- cfg.Filename:= AJsonFilename;
197- except
198- exit;
199- end;
200-
201- cfg.GetValue('/mylist', List, '');
202- List.Add('some_value');
203- cfg.SetValue('/mylist', List);
204- finally
205- cfg.Free;
206- List.Free;
207- end;
179+ jsonConf;
180+ var
181+ cfg: TJSONConfig;
182+ List: TStringList;
183+ path: string;
184+ begin
185+ List:= TStringList.Create;
186+ cfg:= TJSONConfig.Create(nil);
187+ try
188+ //try/except to handle broken json file
189+ try
190+ cfg.Formatted:= true;
191+ cfg.Filename:= AJsonFilename;
192+ except
193+ exit;
194+ end;
195+
196+ cfg.GetValue('/mylist', List, '');
197+ List.Add('some_value');
198+ cfg.SetValue('/mylist', List);
199+ finally
200+ cfg.Free;
201+ List.Free;
202+ end;
208203```
209204
210205## From JsonViewer
211206
212-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:
213-
214-``` pascal
207+Example usage can be found in the Lazarus jsonviewer tool (located in lazarus/tools/jsonviewer). In particular, this part of the tool shows how a json file is read into a TTreeView (named "TVJSON", in the code):
208+```
215209procedure TMainForm.OpenFile(Const AFileName : String);
216-var
217- S : TFileStream;
218- P : TJSONParser;
219- D : TJSONData;
220-begin
221- S:=TFileStream.Create(AFileName,fmOpenRead);
222- try
223- P:=TJSONParser.Create(S);
224- try
225- P.Strict:=FStrict;
226- D:=P.Parse;
227- finally
228- P.Free;
229- end;
230- finally
231- S.Free;
232- end;
233- FFileName:=AFileName;
234- SetCaption;
235- FreeAndNil(FRoot);
236- FRoot:=D;
237- ShowJSONDocument;
238-end;
239-
240-procedure TMainForm.ShowJSONDocument;
241-begin
242- with TVJSON.Items do
243- begin
244- BeginUpdate;
245- try
246- TVJSON.Items.Clear;
247- SHowJSONData(Nil,FRoot);
248- with TVJSON do
249- if (Items.Count>0) and Assigned(Items[0]) then
250- begin
251- Items[0].Expand(False);
252- Selected:=Items[0];
210+ var
211+ S : TFileStream;
212+ P : TJSONParser;
213+ D : TJSONData;
214+ begin
215+ S:=TFileStream.Create(AFileName,fmOpenRead);
216+ try
217+ P:=TJSONParser.Create(S);
218+ try
219+ P.Strict:=FStrict;
220+ D:=P.Parse;
221+ finally
222+ P.Free;
253223 end;
254- finally
255- EndUpdate;
224+ finally
225+ S.Free;
226+ end;
227+ FFileName:=AFileName;
228+ SetCaption;
229+ FreeAndNil(FRoot);
230+ FRoot:=D;
231+ ShowJSONDocument;
256232 end;
257- end;
258-end;
259-
260-procedure TMainForm.ShowJSONData(AParent : TTreeNode; Data : TJSONData);
261-var
262- N,N2 : TTreeNode;
263- I : Integer;
264- D : TJSONData;
265- C : String;
266- S : TStringList;
267-begin
268- N:=Nil;
269- if Assigned(Data) then
270- begin
271- case Data.JSONType of
272- jtArray,
273- jtObject:
274- begin
275- if (Data.JSONType=jtArray) then
276- C:=SArray
277- else
278- C:=SObject;
279- N:=TVJSON.Items.AddChild(AParent,Format(C,[Data.Count]));
280- S:=TstringList.Create;
281- try
282- for I:=0 to Data.Count-1 do
283- if Data.JSONtype=jtArray then
284- S.AddObject(IntToStr(I),Data.items[i])
285- else
286- S.AddObject(TJSONObject(Data).Names[i],Data.items[i]);
287- if FSortObjectMembers and (Data.JSONType=jtObject) then
288- S.Sort;
289- for I:=0 to S.Count-1 do
233+
234+ procedure TMainForm.ShowJSONDocument;
235+ begin
236+ with TVJSON.Items do
237+ begin
238+ BeginUpdate;
239+ try
240+ TVJSON.Items.Clear;
241+ SHowJSONData(Nil,FRoot);
242+ with TVJSON do
243+ if (Items.Count>0) and Assigned(Items[0]) then
290244 begin
291- N2:=TVJSON.Items.AddChild(N,S[i]);
292- D:=TJSONData(S.Objects[i]);
293- N2.ImageIndex:=ImageTypeMap[D.JSONType];
294- N2.SelectedIndex:=ImageTypeMap[D.JSONType];
295- ShowJSONData(N2,D);
296- end
297- finally
298- S.Free;
299- end;
245+ Items[0].Expand(False);
246+ Selected:=Items[0];
247+ end;
248+ finally
249+ EndUpdate;
300250 end;
301- jtNull:
302- N:=TVJSON.Items.AddChild(AParent,SNull);
303- else
304- N:=TVJSON.Items.AddChild(AParent,Data.AsString);
251+ end;
305252 end;
306- if Assigned(N) then
253+
254+ procedure TMainForm.ShowJSONData(AParent : TTreeNode; Data : TJSONData);
255+ var
256+ N,N2 : TTreeNode;
257+ I : Integer;
258+ D : TJSONData;
259+ C : String;
260+ S : TStringList;
307261 begin
308- N.ImageIndex:=ImageTypeMap[Data.JSONType];
309- N.SelectedIndex:=ImageTypeMap[Data.JSONType];
310- N.Data:=Data;
262+ N:=Nil;
263+ if Assigned(Data) then
264+ begin
265+ case Data.JSONType of
266+ jtArray,
267+ jtObject:
268+ begin
269+ if (Data.JSONType=jtArray) then
270+ C:=SArray
271+ else
272+ C:=SObject;
273+ N:=TVJSON.Items.AddChild(AParent,Format(C,[Data.Count]));
274+ S:=TstringList.Create;
275+ try
276+ for I:=0 to Data.Count-1 do
277+ if Data.JSONtype=jtArray then
278+ S.AddObject(IntToStr(I),Data.items[i])
279+ else
280+ S.AddObject(TJSONObject(Data).Names[i],Data.items[i]);
281+ if FSortObjectMembers and (Data.JSONType=jtObject) then
282+ S.Sort;
283+ for I:=0 to S.Count-1 do
284+ begin
285+ N2:=TVJSON.Items.AddChild(N,S[i]);
286+ D:=TJSONData(S.Objects[i]);
287+ N2.ImageIndex:=ImageTypeMap[D.JSONType];
288+ N2.SelectedIndex:=ImageTypeMap[D.JSONType];
289+ ShowJSONData(N2,D);
290+ end
291+ finally
292+ S.Free;
293+ end;
294+ end;
295+ jtNull:
296+ N:=TVJSON.Items.AddChild(AParent,SNull);
297+ else
298+ N:=TVJSON.Items.AddChild(AParent,Data.AsString);
299+ end;
300+ if Assigned(N) then
301+ begin
302+ N.ImageIndex:=ImageTypeMap[Data.JSONType];
303+ N.SelectedIndex:=ImageTypeMap[Data.JSONType];
304+ N.Data:=Data;
305+ end;
306+ end;
311307 end;
312- end;
313-end;
314308```
315309
316310## Change formatting of float numbers
317311
318-Q: My program generates and writes data to JSON file. I use FormatJSON() method to make output more readable. I'm not quite satisfied how numbers with float point look:
319-
320-```text
321-"coordinates" : [
322- 5.5978631048365003E+001,
323- 2.2100000000000000E+002
324-]
312+Q: My program generates and writes data to JSON file. I use FormatJSON() method to make output more readable. I'm not quite satisfied how numbers with float point look:
325313```
326-
327-I want to see normal form:
328-
329-```text
330-"coordinates" : [
331- 55.978631048365003,
332- 221.0
333-]
314+"coordinates" : [
315+ 5.5978631048365003E+001,
316+ 2.2100000000000000E+002
317+ ]
334318```
335319
336-A (forum members **y.ivanov**, **rvk**, **wp**):
320+I want to see normal form:
321+```
322+"coordinates" : [
323+ 55.978631048365003,
324+ 221.0
325+ ]
326+```
337327
338-``` pascal
328+A (forum members **y.ivanov** , **rvk** , **wp**):
329+```
339330{$mode objfpc}{$h+}
340-uses
341- fpjson,
342- jsonparser,
343- SysUtils;
344-
345-type
346- TJSONFloat4Number = class(TJSONFloatNumber)
347- protected
348- function GetAsString: TJSONStringType; override;
349- end;
350-
351-function TJSONFloat4Number.GetAsString: TJSONStringType;
352-var
353- F: TJSONFloat;
354- fs: TFormatSettings;
355-begin
356- fs := DefaultFormatSettings;
357- fs.DecimalSeparator := '.';
358- F := GetAsFloat;
359- Result := FormatFloat('0.0###############', F, fs); // format with your preferences
360-end;
361-
362-procedure JSONTest;
363-var
364- jData: TJSONData;
365-begin
366- jData := GetJSON('{"coordinates": [5.5978631048365003E+001, 2.2100000000000000E+002]}');
367- writeln(jData.FormatJSON);
368- jData.Free;
369-end;
370-
371-begin
372- SetJSONInstanceType(jitNumberFloat, TJSONFloat4Number);
373- JSONTest;
374- Readln;
375-end.
331+ uses
332+ fpjson,
333+ jsonparser,
334+ SysUtils;
335+
336+ type
337+ TJSONFloat4Number = class(TJSONFloatNumber)
338+ protected
339+ function GetAsString: TJSONStringType; override;
340+ end;
341+
342+ function TJSONFloat4Number.GetAsString: TJSONStringType;
343+ var
344+ F: TJSONFloat;
345+ fs: TFormatSettings;
346+ begin
347+ fs := DefaultFormatSettings;
348+ fs.DecimalSeparator := '.';
349+ F := GetAsFloat;
350+ Result := FormatFloat('0.0###############', F, fs); // format with your preferences
351+ end;
352+
353+ procedure JSONTest;
354+ var
355+ jData: TJSONData;
356+ begin
357+ jData := GetJSON('{"coordinates": [5.5978631048365003E+001, 2.2100000000000000E+002]}');
358+ writeln(jData.FormatJSON);
359+ jData.Free;
360+ end;
361+
362+ begin
363+ SetJSONInstanceType(jitNumberFloat, TJSONFloat4Number);
364+ JSONTest;
365+ Readln;
366+ end.
376367```
377368
378369## See also
379370
380-- The FpcTwit example in the [[Components and Code examples]] library makes use of JSON to send/receive data.
381-- [FCL Reference](https://lazarus-ccr.sourceforge.io/fpcdoc/fcl/fpjson/index.html) for unit fpjson.
382-- [An article (PDF)](http://www.freepascal.org/~michael/articles/webdata/webdata.pdf) covering use of XML and JSON in FreePascal.
383-- [[Package List]]
371+ * The FpcTwit example in the [[Components and Code examples]] library makes use of JSON to send/receive data.
372+ * [FCL Reference](<https://www.freepascal.org/docs-html/fcl/index.html>) for unit fpjson.
373+ * [An article (PDF)](<http://www.freepascal.org/~michael/articles/webdata/webdata.pdf>) covering use of XML and JSON in FreePascal.
374+ * [[Package List]]
384375
385376---
386-*From the Free Pascal wiki, page "fcl-json", as it stood on 2022-10-06 after a change by Alextp, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
377+*From the Free Pascal wiki, page "fcl-json", as the Internet Archive kept it on 2025-11-14, last changed on 2025-10-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history