Sign in Join
Wiki copytemporary

fcl-json: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: fcl-json

OldNewLine
1+# General info
2+
3+fcl-json is a [[JSON]] implementation.
4+
5+It contains units such as:
6+
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
11+
12+Note: In fpjson, accessing e.g.
13+
14+``` pascal
15+SomeJSONObject.Integers['price']
16+```
17+
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.
19+
20+# Streaming
21+
22+fcl-json contains the unit "fpjsonrtti" which is used to load objects (TObject instances) from or save them to JSON format.
23+
24+See [[Streaming JSON]] for a short example.
25+
26+# Examples
27+
28+## Getting Started
29+
30+``` pascal
31+uses
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;
76+```
77+
78+Note: it's necessary to free jData when you have finished with it. Otherwise a memory leak is created.
79+
80+## Traversing Items
81+
82+``` pascal
83+uses
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
106+ 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);
111+ end;
112+ end;
113+
114+ jData.Free;
115+end;
116+```
117+
118+## Save/load form position to/from file
119+
120+``` pascal
121+uses
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
140+ 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);
145+ 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;
164+ 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;
178+```
179+
180+## Save/load TStringList
181+
182+``` pascal
183+uses
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;
208+```
209+
210+## From JsonViewer
211+
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
215+procedure 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];
253+ end;
254+ finally
255+ EndUpdate;
256+ 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
290+ 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;
300+ end;
301+ jtNull:
302+ N:=TVJSON.Items.AddChild(AParent,SNull);
303+ else
304+ N:=TVJSON.Items.AddChild(AParent,Data.AsString);
305+ end;
306+ if Assigned(N) then
307+ begin
308+ N.ImageIndex:=ImageTypeMap[Data.JSONType];
309+ N.SelectedIndex:=ImageTypeMap[Data.JSONType];
310+ N.Data:=Data;
311+ end;
312+ end;
313+end;
314+```
315+
316+## Change formatting of float numbers
317+
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+`"coordinates" : [`\
321+`     5.5978631048365003E+001,`\
322+`     2.2100000000000000E+002`\
323+`]`
324+
325+I want to see normal form:
326+
327+`"coordinates" : [`\
328+`     55.978631048365003,`\
329+`     221.0`\
330+`]`
331+
332+A (forum members **y.ivanov**, **rvk**, **wp**):
333+
334+``` pascal
335+{$mode objfpc}{$h+}
336+uses
337+ fpjson,
338+ jsonparser,
339+ SysUtils;
340+
341+type
342+ TJSONFloat4Number = class(TJSONFloatNumber)
343+ protected
344+ function GetAsString: TJSONStringType; override;
345+ end;
346+
347+function TJSONFloat4Number.GetAsString: TJSONStringType;
348+var
349+ F: TJSONFloat;
350+ fs: TFormatSettings;
351+begin
352+ fs := DefaultFormatSettings;
353+ fs.DecimalSeparator := '.';
354+ F := GetAsFloat;
355+ Result := FormatFloat('0.0###############', F, fs); // format with your preferences
356+end;
357+
358+procedure JSONTest;
359+var
360+ jData: TJSONData;
361+begin
362+ jData := GetJSON('{"coordinates": [5.5978631048365003E+001, 2.2100000000000000E+002]}');
363+ writeln(jData.FormatJSON);
364+ jData.Free;
365+end;
366+
367+begin
368+ SetJSONInstanceType(jitNumberFloat, TJSONFloat4Number);
369+ JSONTest;
370+ Readln;
371+end.
372+```
373+
374+## See also
375+
376+- The FpcTwit example in the [[Components and Code examples]] library makes use of JSON to send/receive data.
377+- [FCL Reference](https://lazarus-ccr.sourceforge.io/fpcdoc/fcl/fpjson/index.html) for unit fpjson.
378+- [An article (PDF)](http://www.freepascal.org/~michael/articles/webdata/webdata.pdf) covering use of XML and JSON in FreePascal.
379+- [[Package List]]
380+
381+---
382+*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).*

Back to history