Sign in Join
Wiki copytemporary

fcl-json/ru: what changed

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

Title: fcl-json/ru

OldNewLine
1+# Информация
2+
3+fcl-json реализация стандарта [[JSON]].
4+
5+Пакет содержит юниты:
6+
7+- fpjson: базовый юнит, который реализует TJsonData и их потомков, например TJsonObject
8+- JsonParser: реализует TJsonParser, используется в примере ниже
9+- jsonConf: реализует TJsonConfig, что удобно для чтения/записи данных файлов приложения
10+- jsonScanner: лексический анализатор исходников json
11+
12+> **Note:** В fpjson, доступ, например, `SomeJSONObject.Integers['цена']` может дать Нарушение SIGSEGV/Access, если это целая переменная не существует. Это, очевидно, сделано намеренно, см [[http://bugs.freepascal.org/view.php?id=22273]].
13+
14+Вы должны были бы использовать метод Find (доступен в FPC 2.6.2), чтобы сначала проверить, существует ли элемент ('цена' в данном примере).
15+
16+# Маршаллинг
17+
18+fcl-json содержит юнит "fpjsonrtti", который используется для загрузки из объектов или сохранения их в формате JSON(экземпляров TObject).
19+
20+Смотрите [[Streaming JSON/ru|Streaming JSON]] для короткого примера.
21+
22+# Примеры
23+
24+## Итак, начнём
25+
26+``` Pascal
27+
28+USES 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;
72+```
73+
74+## Перемещение пунктов
75+
76+``` pascal
77+uses
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
100+ 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);
105+ end;
106+ end;
107+
108+ jData.Free;
109+end;
110+```
111+
112+## Сохранение/загрузка позиции/размера диалога
113+
114+``` Pascal
115+USES 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
126+ 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);
131+ 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;
158+```
159+
160+## Сохранение/загрузка TStringList
161+
162+``` Pascal
163+//Пример пути: '/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;
193+```
194+
195+## Использование JsonViewer
196+
197+Пример использования можно найти в инструментах Lazarus: jsonviewer (расположенный в lazarus/tools/jsonviewer). В частности, эта часть инструмента показывает, как использовать JSON:
198+
199+``` Pascal
200+PROCEDURE 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
228+ BEGIN
229+ BeginUpdate;
230+ 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;
239+ FINALLY
240+ EndUpdate;
241+ END;
242+ 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
255+ BEGIN
256+ CASE Data.JSONType OF
257+ jtArray,
258+ jtObject:
259+ 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
275+ 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;
284+ END;
285+ END;
286+ jtNull:
287+ N:=TVJSON.Items.AddChild(AParent,SNull);
288+ ELSE
289+ N:=TVJSON.Items.AddChild(AParent,Data.AsString);
290+ 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;
299+```
300+
301+Библиотека [[Components and Code examples]] использует JSON для передачи/приема данных.
302+
303+## Изменение формата чисел с плавающей запятой
304+
305+Вопрос: моя программа генерирует и записывает данные в файл JSON. Я использую метод `FormatJSON()`, чтобы сделать вывод более читабельным. Меня не совсем устраивает, как выглядят числа с плавающей точкой:
306+
307+`"coordinates" : [`\
308+`     5.5978631048365003E+001,`\
309+`     2.2100000000000000E+002`\
310+`]`
311+
312+Я хочу видеть нормальную форму:
313+
314+`"coordinates" : [`\
315+`     55.978631048365003,`\
316+`     221.0`\
317+`]`
318+
319+Ответ: (пользователи форума **y.ivanov**, **rvk**, **wp**):
320+
321+``` pascal
322+{$mode objfpc}{$h+}
323+uses
324+ fpjson,
325+ jsonparser,
326+ SysUtils;
327+
328+type
329+ TJSONFloat4Number = class(TJSONFloatNumber)
330+ protected
331+ function GetAsString: TJSONStringType; override;
332+ end;
333+
334+function TJSONFloat4Number.GetAsString: TJSONStringType;
335+var
336+ F: TJSONFloat;
337+ fs: TFormatSettings;
338+begin
339+ fs := DefaultFormatSettings;
340+ fs.DecimalSeparator := '.';
341+ F := GetAsFloat;
342+ Result := FormatFloat('0.0###############', F, fs); // форматирование с вашими предпочтениями
343+end;
344+
345+procedure JSONTest;
346+var
347+ jData: TJSONData;
348+begin
349+ jData := GetJSON('{"coordinates": [5.5978631048365003E+001, 2.2100000000000000E+002]}');
350+ writeln(jData.FormatJSON);
351+ jData.Free;
352+end;
353+
354+begin
355+ SetJSONInstanceType(jitNumberFloat, TJSONFloat4Number);
356+ JSONTest;
357+ Readln;
358+end.
359+```
360+
361+## Смотрите также
362+
363+- Статья охватывает использование XML и JSON в Free Pascal: [PDF](http://www.freepascal.org/~michael/articles/webdata/webdata.pdf)
364+- [[Package List]]
365+
366+---
367+*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).*

Back to history