Sign in Join
Wiki copytemporary

fcl-json/ru: what changed

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

OldNewLine
11# Информация
22
3-fcl-json реализация стандарта [[JSON]].
3+fcl-json реализация стандарта [[JSON/ru|JSON]].
44
5-Пакет содержит юниты:
5+Пакет содержит юниты:
66
7-- fpjson: базовый юнит, который реализует TJsonData и их потомков, например TJsonObject
8-- JsonParser: реализует TJsonParser, используется в примере ниже
9-- jsonConf: реализует TJsonConfig, что удобно для чтения/записи данных файлов приложения
10-- jsonScanner: лексический анализатор исходников json
7+ * fpjson: базовый юнит, который реализует TJsonData и их потомков, например TJsonObject
8+ * JsonParser: реализует TJsonParser, используется в примере ниже
9+ * jsonConf: реализует TJsonConfig, что удобно для чтения/записи данных файлов приложения
10+ * jsonScanner: лексический анализатор исходников json
1111
12-> **Note:** В fpjson, доступ, например, `SomeJSONObject.Integers['цена']` может дать Нарушение SIGSEGV/Access, если это целая переменная не существует. Это, очевидно, сделано намеренно, см [[http://bugs.freepascal.org/view.php?id=22273]].
12+![Light bulb](https://upload.wikimedia.org/wikipedia/commons/d/d8/Nuvola_apps_ktip.png) **Примечание:** В fpjson, доступ, например, `SomeJSONObject.Integers['цена']` может дать Нарушение SIGSEGV/Access, если это целая переменная не существует. Это, очевидно, сделано намеренно, см [[[1]](<http://bugs.freepascal.org/view.php?id=22273>)].
1313
14-Вы должны были бы использовать метод Find (доступен в FPC 2.6.2), чтобы сначала проверить, существует ли элемент ('цена' в данном примере).
14+Вы должны были бы использовать метод Find (доступен в FPC 2.6.2), чтобы сначала проверить, существует ли элемент ('цена' в данном примере).
1515
1616# Маршаллинг
1717
18-fcl-json содержит юнит "fpjsonrtti", который используется для загрузки из объектов или сохранения их в формате JSON(экземпляров TObject).
18+fcl-json содержит юнит "fpjsonrtti", который используется для загрузки из объектов или сохранения их в формате JSON(экземпляров TObject).
1919
20-Смотрите [[Streaming JSON/ru|Streaming JSON]] для короткого примера.
20+Смотрите [[Streaming JSON/ru|Streaming JSON]] для короткого примера.
2121
2222# Примеры
2323
2424## Итак, начнём
25-
26-``` Pascal
27-
25+```
2826USES fpjson, jsonparser;
29-
30-PROCEDURE JSONTest;
31-VAR
32- jData : TJSONData;
33- jObject : TJSONObject;
34- jArray : TJSONArray;
35- s : string;
36-BEGIN
37- // это лишь минимальный пример того, что можно сделать с помощью этого API
38-
39- // создать строки JSON
40- jData := GetJSON('{"поле1" : "Привет", "поле2" : 42, "Цвет" : ["Красный", "Зелёный", "Голубой"]}');
41-
42- // вывести как плоскую строку
43- s := jData.AsJSON;
44-
45- // вывести замечательно-отформатированный JSON
46- s := jData.FormatJSON;
47-
48- // передан как TJSONObject для простого доступа
49- jObject := TJSONObject(jData);
50-
51- // передача значения ключа "поле1"
52- s := jObject.Get('поле1');
53-
54- // установка значения ключа "поле2"
55- jObject.Integers['поле2'] := 123;
56-
57- // передача второго цвета
58- s := jData.FindPath('Цвет[1]').AsString;
59-
60- // добавить новый элемент
61- jObject.Add('Happy', True);
62-
63- // передать новый подмассив
64- jArray := TJSONArray.Create;
65- jArray.Add('Север');
66- jArray.Add('Юг');
67- jArray.Add('Восток');
68- jArray.Add('Запад');
69- jObject.Add('Направление', jArray);
70-
71-END;
27+
28+ PROCEDURE JSONTest;
29+ VAR
30+ jData : TJSONData;
31+ jObject : TJSONObject;
32+ jArray : TJSONArray;
33+ s : string;
34+ BEGIN
35+ // это лишь минимальный пример того, что можно сделать с помощью этого API
36+
37+ // создать строки JSON
38+ jData := GetJSON('{"поле1" : "Привет", "поле2" : 42, "Цвет" : ["Красный", "Зелёный", "Голубой"]}');
39+
40+ // вывести как плоскую строку
41+ s := jData.AsJSON;
42+
43+ // вывести замечательно-отформатированный JSON
44+ s := jData.FormatJSON;
45+
46+ // передан как TJSONObject для простого доступа
47+ jObject := TJSONObject(jData);
48+
49+ // передача значения ключа "поле1"
50+ s := jObject.Get('поле1');
51+
52+ // установка значения ключа "поле2"
53+ jObject.Integers['поле2'] := 123;
54+
55+ // передача второго цвета
56+ s := jData.FindPath('Цвет[1]').AsString;
57+
58+ // добавить новый элемент
59+ jObject.Add('Happy', True);
60+
61+ // передать новый подмассив
62+ jArray := TJSONArray.Create;
63+ jArray.Add('Север');
64+ jArray.Add('Юг');
65+ jArray.Add('Восток');
66+ jArray.Add('Запад');
67+ jObject.Add('Направление', jArray);
68+
69+ END;
7270```
7371
7472## Перемещение пунктов
75-
76-``` pascal
73+```
7774uses
78- Classes, TypInfo, fpjson, jsonparser;
79-
80-procedure JSONItems(Info: TStrings);
81-var
82- jData : TJSONData;
83- jItem : TJSONData;
84- i, j: Integer;
85- object_name, field_name, field_value, object_type, object_items: String;
86-begin
87- jData := GetJSON('{"A":{"field1":0, "field2": false},"B":{"field1":0, "field2": false}}');
88-
89- for i := 0 to jData.Count - 1 do
90- begin
91- jItem := jData.Items[i];
92-
93- object_type := GetEnumName(TypeInfo(TJSONtype), Ord(jItem.JSONType));
94- object_name := TJSONObject(jData).Names[i];
95- WriteStr(object_items, jItem.Count);
96-
97- Info.Append('object type: ' + object_type + '|object name: ' + object_name + '|number of fields: ' + object_items);
98-
99- for j := 0 to jItem.Count - 1 do
75+ Classes, TypInfo, fpjson, jsonparser;
76+
77+ procedure JSONItems(Info: TStrings);
78+ var
79+ jData : TJSONData;
80+ jItem : TJSONData;
81+ i, j: Integer;
82+ object_name, field_name, field_value, object_type, object_items: String;
10083 begin
101- field_name := TJSONObject(jItem).Names[j];
102- field_value := jItem.FindPath(TJSONObject(jItem).Names[j]).AsString;
103-
104- Info.Append(field_name + '|' + field_value);
84+ jData := GetJSON('{"A":{"field1":0, "field2": false},"B":{"field1":0, "field2": false}}');
85+
86+ for i := 0 to jData.Count - 1 do
87+ begin
88+ jItem := jData.Items[i];
89+
90+ object_type := GetEnumName(TypeInfo(TJSONtype), Ord(jItem.JSONType));
91+ object_name := TJSONObject(jData).Names[i];
92+ WriteStr(object_items, jItem.Count);
93+
94+ Info.Append('object type: ' + object_type + '|object name: ' + object_name + '|number of fields: ' + object_items);
95+
96+ for j := 0 to jItem.Count - 1 do
97+ begin
98+ field_name := TJSONObject(jItem).Names[j];
99+ field_value := jItem.FindPath(TJSONObject(jItem).Names[j]).AsString;
100+
101+ Info.Append(field_name + '|' + field_value);
102+ end;
103+ end;
104+
105+ jData.Free;
105106 end;
106- end;
107-
108- jData.Free;
109-end;
110107```
111108
112109## Сохранение/загрузка позиции/размера диалога
113-
114-``` Pascal
110+```
115111USES jsonConf;
116-
117-PROCEDURE TfmMain.SaveOptionsPos;
118-VAR
119- c: TJSONConfig;
120-BEGIN
121- c:= TJSONConfig.Create(nil);
122- TRY
123- c.Filename:= GetAppPath(cFileHistory);
124- c.SetValue('/dialog/max', WindowState=wsMaximized);
125- if WindowState<>wsMaximized then
112+
113+ PROCEDURE TfmMain.SaveOptionsPos;
114+ VAR
115+ c: TJSONConfig;
126116 BEGIN
127- c.SetValue('/dialog/posx', Left);
128- c.SetValue('/dialog/posy', Top);
129- c.SetValue('/dialog/sizex', Width);
130- c.SetValue('/dialog/sizey', Height);
117+ c:= TJSONConfig.Create(nil);
118+ TRY
119+ c.Filename:= GetAppPath(cFileHistory);
120+ c.SetValue('/dialog/max', WindowState=wsMaximized);
121+ if WindowState<>wsMaximized then
122+ BEGIN
123+ c.SetValue('/dialog/posx', Left);
124+ c.SetValue('/dialog/posy', Top);
125+ c.SetValue('/dialog/sizex', Width);
126+ c.SetValue('/dialog/sizey', Height);
127+ END;
128+ FINALLY
129+ c.Free;
130+ END;
131131 END;
132- FINALLY
133- c.Free;
134- END;
135-END;
136-
137-procedure TfmMain.LoadOptionsPos;
138-var
139- nLeft, nTop, nW, nH: integer;
140- c: TJSONConfig;
141-begin
142- c:= TJSONConfig.Create(nil);
143- try
144- c.Filename:= GetAppPath(cFileHistory);
145-
146- nLeft:= c.GetValue('/dialog/posx', Left);
147- nTop:= c.GetValue('/dialog/posy', Top);
148- nW:= c.GetValue('/dialog/sizex', Width);
149- nH:= c.GetValue('/dialog/sizey', Height);
150- SetBounds(nLeft, nTop, nW, nH);
151-
152- if c.GetValue('/dialog/max', false) then
153- WindowState:= wsMaximized;
154- finally
155- c.Free;
156- end;
157-end;
132+
133+ procedure TfmMain.LoadOptionsPos;
134+ var
135+ nLeft, nTop, nW, nH: integer;
136+ c: TJSONConfig;
137+ begin
138+ c:= TJSONConfig.Create(nil);
139+ try
140+ c.Filename:= GetAppPath(cFileHistory);
141+
142+ nLeft:= c.GetValue('/dialog/posx', Left);
143+ nTop:= c.GetValue('/dialog/posy', Top);
144+ nW:= c.GetValue('/dialog/sizex', Width);
145+ nH:= c.GetValue('/dialog/sizey', Height);
146+ SetBounds(nLeft, nTop, nW, nH);
147+
148+ if c.GetValue('/dialog/max', false) then
149+ WindowState:= wsMaximized;
150+ finally
151+ c.Free;
152+ end;
153+ end;
158154```
159155
160156## Сохранение/загрузка TStringList
161-
162-``` Pascal
157+```
163158//Пример пути: '/list_find'
164-
165-PROCEDURE SLoadStringsFromFile(cfg: TJsonConfig; const path: string; List: TStrings);
166-VAR
167- i: integer;
168- s: UnicodeString;
169-BEGIN
170- List.Clear;
171- FOR i:= 0 TO OptMaxHistoryItems-1 DO
172- BEGIN
173- s:= cfg.GetValue(path+'/'+inttostr(i), '');
174- IF s='' THEN break;
175- List.Add(Utf8Encode(s));
176- END;
177-END;
178-
179-PROCEDURE SSaveStringsToFile(cfg: TJsonConfig; const path: string; List: TStrings);
180-VAR
181- i: integer;
182- s: string;
183-BEGIN
184- FOR i:= 0 TO OptMaxHistoryItems-1 DO
185- BEGIN
186- IF i<List.Count THEN
187- s:= List[i]
188- ELSE
189- s:= '';
190- cfg.SetDeleteValue(path+'/'+inttostr(i), Utf8Decode(s), '');
191- END;
192-END;
159+
160+ PROCEDURE SLoadStringsFromFile(cfg: TJsonConfig; const path: string; List: TStrings);
161+ VAR
162+ i: integer;
163+ s: UnicodeString;
164+ BEGIN
165+ List.Clear;
166+ FOR i:= 0 TO OptMaxHistoryItems-1 DO
167+ BEGIN
168+ s:= cfg.GetValue(path+'/'+inttostr(i), '');
169+ IF s='' THEN break;
170+ List.Add(Utf8Encode(s));
171+ END;
172+ END;
173+
174+ PROCEDURE SSaveStringsToFile(cfg: TJsonConfig; const path: string; List: TStrings);
175+ VAR
176+ i: integer;
177+ s: string;
178+ BEGIN
179+ FOR i:= 0 TO OptMaxHistoryItems-1 DO
180+ BEGIN
181+ IF i<List.Count THEN
182+ s:= List[i]
183+ ELSE
184+ s:= '';
185+ cfg.SetDeleteValue(path+'/'+inttostr(i), Utf8Decode(s), '');
186+ END;
187+ END;
193188```
194189
195190## Использование JsonViewer
196191
197-Пример использования можно найти в инструментах Lazarus: jsonviewer (расположенный в lazarus/tools/jsonviewer). В частности, эта часть инструмента показывает, как использовать JSON:
198-
199-``` Pascal
192+Пример использования можно найти в инструментах Lazarus: jsonviewer (расположенный в lazarus/tools/jsonviewer). В частности, эта часть инструмента показывает, как использовать JSON:
193+```
200194PROCEDURE TMainForm.OpenFile(Const AFileName : String);
201-VAR
202- S : TFileStream;
203- P : TJSONParser;
204- D : TJSONData;
205-BEGIN
206- S:=TFileStream.Create(AFileName,fmOpenRead);
207- TRY
208- P:=TJSONParser.Create(S);
209- TRY
210- P.Strict:=FStrict;
211- D:=P.Parse;
212- FINALLY
213- P.Free;
214- END;
215- FINALLY
216- S.Free;
217- END;
218- FFileName:=AFileName;
219- SetCaption;
220- FreeAndNil(FRoot);
221- FRoot:=D;
222- ShowJSONDocument;
223-END;
224-
225-PROCEDURE TMainForm.ShowJSONDocument;
226-BEGIN
227- WITH TVJSON.Items DO
195+ VAR
196+ S : TFileStream;
197+ P : TJSONParser;
198+ D : TJSONData;
228199 BEGIN
229- BeginUpdate;
200+ S:=TFileStream.Create(AFileName,fmOpenRead);
230201 TRY
231- TVJSON.Items.Clear;
232- SHowJSONData(Nil,FRoot);
233- WITH TVJSON DO
234- IF (Items.Count>0) AND Assigned(Items[0]) THEN
235- BEGIN
236- Items[0].Expand(False);
237- Selected:=Items[0];
238- END;
202+ P:=TJSONParser.Create(S);
203+ TRY
204+ P.Strict:=FStrict;
205+ D:=P.Parse;
206+ FINALLY
207+ P.Free;
208+ END;
239209 FINALLY
240- EndUpdate;
210+ S.Free;
241211 END;
212+ FFileName:=AFileName;
213+ SetCaption;
214+ FreeAndNil(FRoot);
215+ FRoot:=D;
216+ ShowJSONDocument;
242217 END;
243-END;
244-
245-PROCEDURE TMainForm.ShowJSONData(AParent : TTreeNode; Data : TJSONData);
246-VAR
247- N,N2 : TTreeNode;
248- I : Integer;
249- D : TJSONData;
250- C : String;
251- S : TStringList;
252-BEGIN
253- N:=Nil;
254- IF Assigned(Data) THEN
218+
219+ PROCEDURE TMainForm.ShowJSONDocument;
255220 BEGIN
256- CASE Data.JSONType OF
257- jtArray,
258- jtObject:
221+ WITH TVJSON.Items DO
259222 BEGIN
260- IF (Data.JSONType=jtArray) THEN
261- C:=SArray
262- ELSE
263- C:=SObject;
264- N:=TVJSON.Items.AddChild(AParent,Format(C,[Data.Count]));
265- S:=TstringList.Create;
266- TRY
267- FOR I:=0 TO Data.Count-1 DO
268- IF Data.JSONtype=jtArray THEN
269- S.AddObject(IntToStr(I),Data.items[i])
270- ELSE
271- S.AddObject(TJSONObject(Data).Names[i],Data.items[i]);
272- IF FSortObjectMembers and (Data.JSONType=jtObject) THEN
273- S.Sort;
274- FOR I:=0 TO S.Count-1 DO
223+ BeginUpdate;
224+ TRY
225+ TVJSON.Items.Clear;
226+ SHowJSONData(Nil,FRoot);
227+ WITH TVJSON DO
228+ IF (Items.Count>0) AND Assigned(Items[0]) THEN
229+ BEGIN
230+ Items[0].Expand(False);
231+ Selected:=Items[0];
232+ END;
233+ FINALLY
234+ EndUpdate;
235+ END;
236+ END;
237+ END;
238+
239+ PROCEDURE TMainForm.ShowJSONData(AParent : TTreeNode; Data : TJSONData);
240+ VAR
241+ N,N2 : TTreeNode;
242+ I : Integer;
243+ D : TJSONData;
244+ C : String;
245+ S : TStringList;
246+ BEGIN
247+ N:=Nil;
248+ IF Assigned(Data) THEN
249+ BEGIN
250+ CASE Data.JSONType OF
251+ jtArray,
252+ jtObject:
275253 BEGIN
276- N2:=TVJSON.Items.AddChild(N,S[i]);
277- D:=TJSONData(S.Objects[i]);
278- N2.ImageIndex:=ImageTypeMap[D.JSONType];
279- N2.SelectedIndex:=ImageTypeMap[D.JSONType];
280- ShowJSONData(N2,D);
281- END
282- FINALLY
283- S.Free;
254+ IF (Data.JSONType=jtArray) THEN
255+ C:=SArray
256+ ELSE
257+ C:=SObject;
258+ N:=TVJSON.Items.AddChild(AParent,Format(C,[Data.Count]));
259+ S:=TstringList.Create;
260+ TRY
261+ FOR I:=0 TO Data.Count-1 DO
262+ IF Data.JSONtype=jtArray THEN
263+ S.AddObject(IntToStr(I),Data.items[i])
264+ ELSE
265+ S.AddObject(TJSONObject(Data).Names[i],Data.items[i]);
266+ IF FSortObjectMembers and (Data.JSONType=jtObject) THEN
267+ S.Sort;
268+ FOR I:=0 TO S.Count-1 DO
269+ BEGIN
270+ N2:=TVJSON.Items.AddChild(N,S[i]);
271+ D:=TJSONData(S.Objects[i]);
272+ N2.ImageIndex:=ImageTypeMap[D.JSONType];
273+ N2.SelectedIndex:=ImageTypeMap[D.JSONType];
274+ ShowJSONData(N2,D);
275+ END
276+ FINALLY
277+ S.Free;
278+ END;
279+ END;
280+ jtNull:
281+ N:=TVJSON.Items.AddChild(AParent,SNull);
282+ ELSE
283+ N:=TVJSON.Items.AddChild(AParent,Data.AsString);
284284 END;
285+ IF Assigned(N) THEN
286+ BEGIN
287+ N.ImageIndex:=ImageTypeMap[Data.JSONType];
288+ N.SelectedIndex:=ImageTypeMap[Data.JSONType];
289+ N.Data:=Data;
290+ END;
285291 END;
286- jtNull:
287- N:=TVJSON.Items.AddChild(AParent,SNull);
288- ELSE
289- N:=TVJSON.Items.AddChild(AParent,Data.AsString);
290292 END;
291- IF Assigned(N) THEN
292- BEGIN
293- N.ImageIndex:=ImageTypeMap[Data.JSONType];
294- N.SelectedIndex:=ImageTypeMap[Data.JSONType];
295- N.Data:=Data;
296- END;
297- END;
298-END;
299293```
300294
301-Библиотека [[Components and Code examples]] использует JSON для передачи/приема данных.
295+Библиотека [[Components and Code examples]] использует JSON для передачи/приема данных.
302296
303297## Изменение формата чисел с плавающей запятой
304298
305-Вопрос: моя программа генерирует и записывает данные в файл JSON. Я использую метод `FormatJSON()`, чтобы сделать вывод более читабельным. Меня не совсем устраивает, как выглядят числа с плавающей точкой:
306-
307-```text
308-"coordinates" : [
309- 5.5978631048365003E+001,
310- 2.2100000000000000E+002
311-]
299+Вопрос: моя программа генерирует и записывает данные в файл JSON. Я использую метод `FormatJSON()`, чтобы сделать вывод более читабельным. Меня не совсем устраивает, как выглядят числа с плавающей точкой:
312300```
313-
314-Я хочу видеть нормальную форму:
315-
316-```text
317-"coordinates" : [
318- 55.978631048365003,
319- 221.0
320-]
301+"coordinates" : [
302+ 5.5978631048365003E+001,
303+ 2.2100000000000000E+002
304+ ]
321305```
322306
323-Ответ: (пользователи форума **y.ivanov**, **rvk**, **wp**):
307+Я хочу видеть нормальную форму:
308+```
309+"coordinates" : [
310+ 55.978631048365003,
311+ 221.0
312+ ]
313+```
324314
325-``` pascal
315+Ответ: (пользователи форума **y.ivanov** , **rvk** , **wp**):
316+```
326317{$mode objfpc}{$h+}
327-uses
328- fpjson,
329- jsonparser,
330- SysUtils;
331-
332-type
333- TJSONFloat4Number = class(TJSONFloatNumber)
334- protected
335- function GetAsString: TJSONStringType; override;
336- end;
337-
338-function TJSONFloat4Number.GetAsString: TJSONStringType;
339-var
340- F: TJSONFloat;
341- fs: TFormatSettings;
342-begin
343- fs := DefaultFormatSettings;
344- fs.DecimalSeparator := '.';
345- F := GetAsFloat;
346- Result := FormatFloat('0.0###############', F, fs); // форматирование с вашими предпочтениями
347-end;
348-
349-procedure JSONTest;
350-var
351- jData: TJSONData;
352-begin
353- jData := GetJSON('{"coordinates": [5.5978631048365003E+001, 2.2100000000000000E+002]}');
354- writeln(jData.FormatJSON);
355- jData.Free;
356-end;
357-
358-begin
359- SetJSONInstanceType(jitNumberFloat, TJSONFloat4Number);
360- JSONTest;
361- Readln;
362-end.
318+ uses
319+ fpjson,
320+ jsonparser,
321+ SysUtils;
322+
323+ type
324+ TJSONFloat4Number = class(TJSONFloatNumber)
325+ protected
326+ function GetAsString: TJSONStringType; override;
327+ end;
328+
329+ function TJSONFloat4Number.GetAsString: TJSONStringType;
330+ var
331+ F: TJSONFloat;
332+ fs: TFormatSettings;
333+ begin
334+ fs := DefaultFormatSettings;
335+ fs.DecimalSeparator := '.';
336+ F := GetAsFloat;
337+ Result := FormatFloat('0.0###############', F, fs); // форматирование с вашими предпочтениями
338+ end;
339+
340+ procedure JSONTest;
341+ var
342+ jData: TJSONData;
343+ begin
344+ jData := GetJSON('{"coordinates": [5.5978631048365003E+001, 2.2100000000000000E+002]}');
345+ writeln(jData.FormatJSON);
346+ jData.Free;
347+ end;
348+
349+ begin
350+ SetJSONInstanceType(jitNumberFloat, TJSONFloat4Number);
351+ JSONTest;
352+ Readln;
353+ end.
363354```
364355
365356## Смотрите также
366357
367-- Статья охватывает использование XML и JSON в Free Pascal: [PDF](http://www.freepascal.org/~michael/articles/webdata/webdata.pdf)
368-- [[Package List]]
358+ * Статья охватывает использование XML и JSON в Free Pascal: [PDF](<http://www.freepascal.org/~michael/articles/webdata/webdata.pdf>)
359+ * [[Package List]]
369360
370361---
371-*From the Free Pascal wiki, page "fcl-json/ru", as it stood on 2022-10-06 after a change by Zoltanleo, 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).*
362+*From the Free Pascal wiki, page "fcl-json/ru", as the Internet Archive kept it on 2025-08-31, last changed on 2025-02-25. 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