Sign in Join
Wiki copytemporary

fcl-json/ru: what changed

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

OldNewLine
11# Информация
22
33fcl-json реализация стандарта [[JSON]].
44
55Пакет содержит юниты:
66
77- fpjson: базовый юнит, который реализует TJsonData и их потомков, например TJsonObject
88- JsonParser: реализует TJsonParser, используется в примере ниже
99- jsonConf: реализует TJsonConfig, что удобно для чтения/записи данных файлов приложения
1010- jsonScanner: лексический анализатор исходников json
1111
1212> **Note:** В fpjson, доступ, например, `SomeJSONObject.Integers['цена']` может дать Нарушение SIGSEGV/Access, если это целая переменная не существует. Это, очевидно, сделано намеренно, см [[http://bugs.freepascal.org/view.php?id=22273]].
1313
1414Вы должны были бы использовать метод Find (доступен в FPC 2.6.2), чтобы сначала проверить, существует ли элемент ('цена' в данном примере).
1515
1616# Маршаллинг
1717
1818fcl-json содержит юнит "fpjsonrtti", который используется для загрузки из объектов или сохранения их в формате JSON(экземпляров TObject).
1919
2020Смотрите [[Streaming JSON/ru|Streaming JSON]] для короткого примера.
2121
2222# Примеры
2323
2424## Итак, начнём
2525
2626``` Pascal
2727
2828USES fpjson, jsonparser;
2929
3030PROCEDURE JSONTest;
3131VAR
3232 jData : TJSONData;
3333 jObject : TJSONObject;
3434 jArray : TJSONArray;
3535 s : string;
3636BEGIN
3737 // это лишь минимальный пример того, что можно сделать с помощью этого API
3838
3939 // создать строки JSON
4040 jData := GetJSON('{"поле1" : "Привет", "поле2" : 42, "Цвет" : ["Красный", "Зелёный", "Голубой"]}');
4141
4242 // вывести как плоскую строку
4343 s := jData.AsJSON;
4444
4545 // вывести замечательно-отформатированный JSON
4646 s := jData.FormatJSON;
4747
4848 // передан как TJSONObject для простого доступа
4949 jObject := TJSONObject(jData);
5050
5151 // передача значения ключа "поле1"
5252 s := jObject.Get('поле1');
5353
5454 // установка значения ключа "поле2"
5555 jObject.Integers['поле2'] := 123;
5656
5757 // передача второго цвета
5858 s := jData.FindPath('Цвет[1]').AsString;
5959
6060 // добавить новый элемент
6161 jObject.Add('Happy', True);
6262
6363 // передать новый подмассив
6464 jArray := TJSONArray.Create;
6565 jArray.Add('Север');
6666 jArray.Add('Юг');
6767 jArray.Add('Восток');
6868 jArray.Add('Запад');
6969 jObject.Add('Направление', jArray);
7070
7171END;
7272```
7373
7474## Перемещение пунктов
7575
7676``` pascal
7777uses
7878 Classes, TypInfo, fpjson, jsonparser;
7979
8080procedure JSONItems(Info: TStrings);
8181var
8282 jData : TJSONData;
8383 jItem : TJSONData;
8484 i, j: Integer;
8585 object_name, field_name, field_value, object_type, object_items: String;
8686begin
8787 jData := GetJSON('{"A":{"field1":0, "field2": false},"B":{"field1":0, "field2": false}}');
8888
8989 for i := 0 to jData.Count - 1 do
9090 begin
9191 jItem := jData.Items[i];
9292
9393 object_type := GetEnumName(TypeInfo(TJSONtype), Ord(jItem.JSONType));
9494 object_name := TJSONObject(jData).Names[i];
9595 WriteStr(object_items, jItem.Count);
9696
9797 Info.Append('object type: ' + object_type + '|object name: ' + object_name + '|number of fields: ' + object_items);
9898
9999 for j := 0 to jItem.Count - 1 do
100100 begin
101101 field_name := TJSONObject(jItem).Names[j];
102102 field_value := jItem.FindPath(TJSONObject(jItem).Names[j]).AsString;
103103
104104 Info.Append(field_name + '|' + field_value);
105105 end;
106106 end;
107107
108108 jData.Free;
109109end;
110110```
111111
112112## Сохранение/загрузка позиции/размера диалога
113113
114114``` Pascal
115115USES jsonConf;
116116
117117PROCEDURE TfmMain.SaveOptionsPos;
118118VAR
119119 c: TJSONConfig;
120120BEGIN
121121 c:= TJSONConfig.Create(nil);
122122 TRY
123123 c.Filename:= GetAppPath(cFileHistory);
124124 c.SetValue('/dialog/max', WindowState=wsMaximized);
125125 if WindowState<>wsMaximized then
126126 BEGIN
127127 c.SetValue('/dialog/posx', Left);
128128 c.SetValue('/dialog/posy', Top);
129129 c.SetValue('/dialog/sizex', Width);
130130 c.SetValue('/dialog/sizey', Height);
131131 END;
132132 FINALLY
133133 c.Free;
134134 END;
135135END;
136136
137137procedure TfmMain.LoadOptionsPos;
138138var
139139 nLeft, nTop, nW, nH: integer;
140140 c: TJSONConfig;
141141begin
142142 c:= TJSONConfig.Create(nil);
143143 try
144144 c.Filename:= GetAppPath(cFileHistory);
145145
146146 nLeft:= c.GetValue('/dialog/posx', Left);
147147 nTop:= c.GetValue('/dialog/posy', Top);
148148 nW:= c.GetValue('/dialog/sizex', Width);
149149 nH:= c.GetValue('/dialog/sizey', Height);
150150 SetBounds(nLeft, nTop, nW, nH);
151151
152152 if c.GetValue('/dialog/max', false) then
153153 WindowState:= wsMaximized;
154154 finally
155155 c.Free;
156156 end;
157157end;
158158```
159159
160160## Сохранение/загрузка TStringList
161161
162162``` Pascal
163163//Пример пути: '/list_find'
164164
165165PROCEDURE SLoadStringsFromFile(cfg: TJsonConfig; const path: string; List: TStrings);
166166VAR
167167 i: integer;
168168 s: UnicodeString;
169169BEGIN
170170 List.Clear;
171171 FOR i:= 0 TO OptMaxHistoryItems-1 DO
172172 BEGIN
173173 s:= cfg.GetValue(path+'/'+inttostr(i), '');
174174 IF s='' THEN break;
175175 List.Add(Utf8Encode(s));
176176 END;
177177END;
178178
179179PROCEDURE SSaveStringsToFile(cfg: TJsonConfig; const path: string; List: TStrings);
180180VAR
181181 i: integer;
182182 s: string;
183183BEGIN
184184 FOR i:= 0 TO OptMaxHistoryItems-1 DO
185185 BEGIN
186186 IF i<List.Count THEN
187187 s:= List[i]
188188 ELSE
189189 s:= '';
190190 cfg.SetDeleteValue(path+'/'+inttostr(i), Utf8Decode(s), '');
191191 END;
192192END;
193193```
194194
195195## Использование JsonViewer
196196
197197Пример использования можно найти в инструментах Lazarus: jsonviewer (расположенный в lazarus/tools/jsonviewer). В частности, эта часть инструмента показывает, как использовать JSON:
198198
199199``` Pascal
200200PROCEDURE TMainForm.OpenFile(Const AFileName : String);
201201VAR
202202 S : TFileStream;
203203 P : TJSONParser;
204204 D : TJSONData;
205205BEGIN
206206 S:=TFileStream.Create(AFileName,fmOpenRead);
207207 TRY
208208 P:=TJSONParser.Create(S);
209209 TRY
210210 P.Strict:=FStrict;
211211 D:=P.Parse;
212212 FINALLY
213213 P.Free;
214214 END;
215215 FINALLY
216216 S.Free;
217217 END;
218218 FFileName:=AFileName;
219219 SetCaption;
220220 FreeAndNil(FRoot);
221221 FRoot:=D;
222222 ShowJSONDocument;
223223END;
224224
225225PROCEDURE TMainForm.ShowJSONDocument;
226226BEGIN
227227 WITH TVJSON.Items DO
228228 BEGIN
229229 BeginUpdate;
230230 TRY
231231 TVJSON.Items.Clear;
232232 SHowJSONData(Nil,FRoot);
233233 WITH TVJSON DO
234234 IF (Items.Count>0) AND Assigned(Items[0]) THEN
235235 BEGIN
236236 Items[0].Expand(False);
237237 Selected:=Items[0];
238238 END;
239239 FINALLY
240240 EndUpdate;
241241 END;
242242 END;
243243END;
244244
245245PROCEDURE TMainForm.ShowJSONData(AParent : TTreeNode; Data : TJSONData);
246246VAR
247247 N,N2 : TTreeNode;
248248 I : Integer;
249249 D : TJSONData;
250250 C : String;
251251 S : TStringList;
252252BEGIN
253253 N:=Nil;
254254 IF Assigned(Data) THEN
255255 BEGIN
256256 CASE Data.JSONType OF
257257 jtArray,
258258 jtObject:
259259 BEGIN
260260 IF (Data.JSONType=jtArray) THEN
261261 C:=SArray
262262 ELSE
263263 C:=SObject;
264264 N:=TVJSON.Items.AddChild(AParent,Format(C,[Data.Count]));
265265 S:=TstringList.Create;
266266 TRY
267267 FOR I:=0 TO Data.Count-1 DO
268268 IF Data.JSONtype=jtArray THEN
269269 S.AddObject(IntToStr(I),Data.items[i])
270270 ELSE
271271 S.AddObject(TJSONObject(Data).Names[i],Data.items[i]);
272272 IF FSortObjectMembers and (Data.JSONType=jtObject) THEN
273273 S.Sort;
274274 FOR I:=0 TO S.Count-1 DO
275275 BEGIN
276276 N2:=TVJSON.Items.AddChild(N,S[i]);
277277 D:=TJSONData(S.Objects[i]);
278278 N2.ImageIndex:=ImageTypeMap[D.JSONType];
279279 N2.SelectedIndex:=ImageTypeMap[D.JSONType];
280280 ShowJSONData(N2,D);
281281 END
282282 FINALLY
283283 S.Free;
284284 END;
285285 END;
286286 jtNull:
287287 N:=TVJSON.Items.AddChild(AParent,SNull);
288288 ELSE
289289 N:=TVJSON.Items.AddChild(AParent,Data.AsString);
290290 END;
291291 IF Assigned(N) THEN
292292 BEGIN
293293 N.ImageIndex:=ImageTypeMap[Data.JSONType];
294294 N.SelectedIndex:=ImageTypeMap[Data.JSONType];
295295 N.Data:=Data;
296296 END;
297297 END;
298298END;
299299```
300300
301301Библиотека [[Components and Code examples]] использует JSON для передачи/приема данных.
302302
303303## Изменение формата чисел с плавающей запятой
304304
305305Вопрос: моя программа генерирует и записывает данные в файл JSON. Я использую метод `FormatJSON()`, чтобы сделать вывод более читабельным. Меня не совсем устраивает, как выглядят числа с плавающей точкой:
306306
307-`"coordinates" : [`\
308-`     5.5978631048365003E+001,`\
309-`     2.2100000000000000E+002`\
310-`]`
307+```text
308+"coordinates" : [
309+ 5.5978631048365003E+001,
310+ 2.2100000000000000E+002
311+]
312+```
311313
312314Я хочу видеть нормальную форму:
313315
314-`"coordinates" : [`\
315-`     55.978631048365003,`\
316-`     221.0`\
317-`]`
316+```text
317+"coordinates" : [
318+ 55.978631048365003,
319+ 221.0
320+]
321+```
318322
319323Ответ: (пользователи форума **y.ivanov**, **rvk**, **wp**):
320324
321325``` pascal
322326{$mode objfpc}{$h+}
323327uses
324328 fpjson,
325329 jsonparser,
326330 SysUtils;
327331
328332type
329333 TJSONFloat4Number = class(TJSONFloatNumber)
330334 protected
331335 function GetAsString: TJSONStringType; override;
332336 end;
333337
334338function TJSONFloat4Number.GetAsString: TJSONStringType;
335339var
336340 F: TJSONFloat;
337341 fs: TFormatSettings;
338342begin
339343 fs := DefaultFormatSettings;
340344 fs.DecimalSeparator := '.';
341345 F := GetAsFloat;
342346 Result := FormatFloat('0.0###############', F, fs); // форматирование с вашими предпочтениями
343347end;
344348
345349procedure JSONTest;
346350var
347351 jData: TJSONData;
348352begin
349353 jData := GetJSON('{"coordinates": [5.5978631048365003E+001, 2.2100000000000000E+002]}');
350354 writeln(jData.FormatJSON);
351355 jData.Free;
352356end;
353357
354358begin
355359 SetJSONInstanceType(jitNumberFloat, TJSONFloat4Number);
356360 JSONTest;
357361 Readln;
358362end.
359363```
360364
361365## Смотрите также
362366
363367- Статья охватывает использование XML и JSON в Free Pascal: [PDF](http://www.freepascal.org/~michael/articles/webdata/webdata.pdf)
364368- [[Package List]]
365369
366370---
367371*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