Sign in Join
Wiki copytemporary

Streaming JSON/zh: what changed

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

OldNewLine
11JSON(JavaScript Object Notation)是一种基于文本的标准化数据格式。顾名思义,JSON 文档是有效的 JavaScript 代码,可以直接转换为 JavaScript 对象。但是,无论使用哪种编程语言,JSON 都可用于数据交换。
22
33本教程解释了如何将 JSON 数据加载到免费的 Pascal 程序中并在那里进行处理。它还解释了如何将数据从程序转换为JSON(例如将其发送到Web浏览器)。
44
55目录 1 一般要求 2 数据结构 3 加载数据别名记录 4 保存 JSON 5 自定义属性 6 结论 7 参见 8 注释和参考文献 General requirements 加载和存储(流式处理)对象是通过 fpjsonrtti 单元完成的。使用类单元也很有意义(有关详细信息,请参见下文)。
66
77因此,uses 语句应至少包含以下两个单元:
88
99uses Classes, fpjsonrtti; 目前(2014 年 \<\> 月)Free Pascal 的流媒体系统和 JSON 之间存在一些差异:
1010
1111JSON 是一种区分大小写的数据格式。因此,Free Pascal 对象的属性必须以与 JSON 属性相同的大小写方式编写。 不能使用 DefineProperties 定义任何属性。不能保存对方法(事件处理程序)的引用。阿拉伯数字 可以用作阵列的替代品。 演示程序在 packages/fcl-json/examples 目录中提供了免费的 Pascal 编译器源代码。
1212
1313以下示例中使用此 JSON 结构:
1414
1515{
1616
17-` "id"     : 123,                                                // an integer`\
18-` "obj"    : { "name": "Hello world!" },                         // an object`\
19-` "coll"   : [ { "name": "Object 1" }, { "name": "Object 2" } ], // two objects in a TCollection`\
20-` "strings": [ "Hello 1", "Hello 2" ]                            // a string list`
17+``` pascal
18+ "id" : 123, // an integer
19+ "obj" : { "name": "Hello world!" }, // an object
20+ "coll" : [ { "name": "Object 1" }, { "name": "Object 2" } ], // two objects in a TCollection
21+ "strings": [ "Hello 1", "Hello 2" ] // a string list
22+```
2123
2224} 它可以在您的自由 Pascal 程序中使用常量赋值定义,如下所示:
2325
2426const JSON_TESTDATA = '{'+LineEnding+ ' "id": 123,'+LineEnding+ ' "obj": { "name": "Hello world!" },'+LineEnding+ ' "coll": \[ { "name": "Object 1" }, { "name": "Object 2" } \],'+LineEnding+ ' "strings": \[ "Hello 1", "Hello 2" \]'+LineEnding+ '}'; Data Structure 数据的基类是类单元中的 TPersistient,为它和所有子类创建运行时类型信息 (RTTI)。这些对于流式传输至关重要。由于 fpjsonrtti 不集成到流系统中,因此也可以使用使用编译器开关 {\$M+} 翻译的任何其他类。
2527
2628所有要读取的属性都必须在类的已发布部分中声明为属性。通常,您可以使用读取和写入直接引用数据字段(变量)。如果你愿意,你当然可以使用getter和setter方法。
2729
2830以下类定义来自 JSON 结构:
2931
3032type
3133
32-` TNameObject = class(TCollectionItem) // class for the 'obj' property and TCollection `\
33-` private`\
34-`   fName: String;`\
35-` published`\
36-`   property name: String read fName write fName;`\
37-` end;  `
34+``` pascal
35+ TNameObject = class(TCollectionItem) // class for the 'obj' property and TCollection
36+ private
37+ fName: String;
38+ published
39+ property name: String read fName write fName;
40+ end;
41+```
3842
39-` TBaseObject = class(TPersistent)  // class for the entire JSON structure`\
40-` private`\
41-`   fid: Integer;`\
42-`   fObj: TNameObject;`\
43-`   fColl: TCollection;`\
44-`   fStrings: TStrings;`\
45-` public`\
46-`   constructor Create;`\
47-`   destructor Destroy; override;`\
48-` published                         // all properties must be published `\
49-`   property id: Integer read fid write fid;`\
50-`   property obj: TNameObject read fObj write fObj;`\
51-`   property coll: TCollection read fColl;`\
52-`   property strings: TStrings read fStrings;`\
53-` end;`
43+``` pascal
44+ TBaseObject = class(TPersistent) // class for the entire JSON structure
45+ private
46+ fid: Integer;
47+ fObj: TNameObject;
48+ fColl: TCollection;
49+ fStrings: TStrings;
50+ public
51+ constructor Create;
52+ destructor Destroy; override;
53+ published // all properties must be published
54+ property id: Integer read fid write fid;
55+ property obj: TNameObject read fObj write fObj;
56+ property coll: TCollection read fColl;
57+ property strings: TStrings read fStrings;
58+ end;
59+```
5460
5561该类派生自 TCollectionItem。这意味着它既可以用于 obj 属性,也可以用于集合。如果不需要这样做,则必须在此处定义两个不同的类。TNameObject
5662
5763必须在 TBaseObject 类的构造函数中创建字符串列表,并在析构函数中释放。
5864
5965constructor TBaseObject.Create; begin
6066
61-` // Create Collection and StringList`\
62-` fColl    := TCollection.Create(TNameObject);`\
63-` fStrings := TStringList.Create;`\
64-` fObj     := TNameObject.Create(nil);`
67+``` pascal
68+ // Create Collection and StringList
69+ fColl := TCollection.Create(TNameObject);
70+ fStrings := TStringList.Create;
71+ fObj := TNameObject.Create(nil);
72+```
6573
6674end;
6775
6876destructor TBaseObject.Destroy; begin
6977
70-` // Release Collection and StringList`\
71-` fColl.Free;`\
72-` fStrings.Free;`\
73-` fObj.Free;`\
74-` inherited Destroy;`
78+``` pascal
79+ // Release Collection and StringList
80+ fColl.Free;
81+ fStrings.Free;
82+ fObj.Free;
83+ inherited Destroy;
84+```
7585
7686end; 如果您不希望数据类中有更多功能,则它们的定义现在已完成。
7787
7888Load JSON 使用 TJSONDeStreamer 类中的方法,您可以将 JSON 数据直接分配给现有对象。在调用该方法之前,必须创建 TJSONDeStreamer 和目标对象。Procedure JSONToObject(Const JSON : TJSONStringType; AObject : TObject);
7989
8090以下方法从对象 o 中的 JSON 结构加载数据,然后将属性的当前值输出到控制台。JSON_TESTDATA
8191
8292procedure DeStreamTest; var
8393
84-` DeStreamer: TJSONDeStreamer;`\
85-` o: TBaseObject;`\
86-` no: TNameObject;`\
87-` s: String;`
94+```text
95+ DeStreamer: TJSONDeStreamer;
96+ o: TBaseObject;
97+ no: TNameObject;
98+ s: String;
99+```
88100
89101begin
90102
91-` WriteLn('DeStream test');`\
92-` WriteLn('======================================');`
103+```text
104+ WriteLn('DeStream test');
105+ WriteLn('======================================');
106+```
93107
94-` // Create the DeStreamer object and target object`\
95-` DeStreamer := TJSONDeStreamer.Create(nil);`\
96-` o := TBaseObject.Create;`\
97-` try`\
98-`   // Load JSON data into object o`\
99-`   DeStreamer.JSONToObject(JSON_TESTDATA, o);`\
100-`   // output ID`\
101-`   WriteLn(o.id);`\
102-`   // output object name`\
103-`   WriteLn(o.obj.name); `\
104-`   // output the names of all objects`\
105-`   for TCollectionItem(no) in o.coll do`\
106-`     Writeln(no.name);`\
107-`   // output all strings`\
108-`   for s in o.strings do`\
109-`     WriteLn(s);`
108+``` pascal
109+ // Create the DeStreamer object and target object
110+ DeStreamer := TJSONDeStreamer.Create(nil);
111+ o := TBaseObject.Create;
112+ try
113+ // Load JSON data into object o
114+ DeStreamer.JSONToObject(JSON_TESTDATA, o);
115+ // output ID
116+ WriteLn(o.id);
117+ // output object name
118+ WriteLn(o.obj.name);
119+ // output the names of all objects
120+ for TCollectionItem(no) in o.coll do
121+ Writeln(no.name);
122+ // output all strings
123+ for s in o.strings do
124+ WriteLn(s);
125+```
110126
111-` // Cleanup`\
112-` finally`\
113-`   o.Destroy;`\
114-`   DeStreamer.Destroy;`\
115-` end;`
127+``` pascal
128+ // Cleanup
129+ finally
130+ o.Destroy;
131+ DeStreamer.Destroy;
132+ end;
133+```
116134
117135end; Saving JSON 类TJSONStreamer用于将对象转换为JSON文本。这里使用该方法。Function ObjectToJSONString(AObject : TObject) : TJSONStringType;
118136
119137在下面的过程中,将创建一个对象,用测试数据填充,然后将其转换为 JSON。JSON 文本在控制台上输出。无法指定属性的输出顺序。
120138
121139procedure StreamTest; var
122140
123-` Streamer: TJSONStreamer;`\
124-` o: TBaseObject;`\
125-` JSONString: String;`
141+```text
142+ Streamer: TJSONStreamer;
143+ o: TBaseObject;
144+ JSONString: String;
145+```
126146
127147begin
128148
129-` WriteLn('Stream test');`\
130-` WriteLn('======================================');`
149+```text
150+ WriteLn('Stream test');
151+ WriteLn('======================================');
152+```
131153
132-` Streamer := TJSONStreamer.Create(nil);`\
133-` o := TBaseObject.Create;`\
134-` try`\
135-`   // Setup data`\
136-`   o.id := 123;`\
137-`   o.obj.name := 'Hello world!';`\
138-`   TNameObject(o.coll.Add).name := 'Object 1';`\
139-`   TNameObject(o.coll.Add).name := 'Object 2';`\
140-`   o.strings.Add('Hello 1');`\
141-`   o.strings.Add('Hello 2');`
154+``` pascal
155+ Streamer := TJSONStreamer.Create(nil);
156+ o := TBaseObject.Create;
157+ try
158+ // Setup data
159+ o.id := 123;
160+ o.obj.name := 'Hello world!';
161+ TNameObject(o.coll.Add).name := 'Object 1';
162+ TNameObject(o.coll.Add).name := 'Object 2';
163+ o.strings.Add('Hello 1');
164+ o.strings.Add('Hello 2');
165+```
142166
143-`   Streamer.Options := Streamer.Options + [jsoTStringsAsArray]; // Save strings as JSON array`\
144-`   // convert to JSON and output to console`\
145-`   JSONString := Streamer.ObjectToJSONString(o);`\
146-`   WriteLn(JSONString);`
167+``` pascal
168+ Streamer.Options := Streamer.Options + [jsoTStringsAsArray]; // Save strings as JSON array
169+ // convert to JSON and output to console
170+ JSONString := Streamer.ObjectToJSONString(o);
171+ WriteLn(JSONString);
172+```
147173
148-` // Cleanup`\
149-` finally`\
150-`   o.Destroy;`\
151-`   Streamer.Destroy;`\
152-` end;`
174+``` pascal
175+ // Cleanup
176+ finally
177+ o.Destroy;
178+ Streamer.Destroy;
179+ end;
180+```
153181
154182end; Custom properties 现在我们可以保存并加载到 JSON 中,我们还可以自定义属性的保存方式。默认情况下,TColor (TGraphicsColor) 被保存为数字,但例如我们希望将其设置为字符串,因此更易于人类阅读。
155183
156184此示例使用 BGRABitmap 库,该库具有从字符串轻松转换为颜色的功能。在这种情况式处理的控件是 BGRAControls 包中的按钮控件。
157185
158186这将自定义保存和加载 TColor 的方式。
159187
160188保存代码:
161189
162190procedure TForm1.Button1Click(Sender: TObject); var
163191
164-` Streamer: TJSONStreamer;`\
165-` JSONString: String;`
192+```text
193+ Streamer: TJSONStreamer;
194+ JSONString: String;
195+```
166196
167197begin
168198
169-` Streamer := TJSONStreamer.Create(nil);`\
170-` try`\
171-`   Streamer.OnStreamProperty:=@OnStreamProperty;`\
172-`   JSONString := Streamer.ObjectToJSONString(BCButton1.StateNormal);`\
173-`   Memo1.Lines.Text := JSONString;`\
174-` finally`\
175-`   Streamer.Destroy;`\
176-` end;`
199+``` pascal
200+ Streamer := TJSONStreamer.Create(nil);
201+ try
202+ Streamer.OnStreamProperty:=@OnStreamProperty;
203+ JSONString := Streamer.ObjectToJSONString(BCButton1.StateNormal);
204+ Memo1.Lines.Text := JSONString;
205+ finally
206+ Streamer.Destroy;
207+ end;
208+```
177209
178210end; procedure TForm1.OnStreamProperty(Sender: TObject; AObject: TObject;
179211
180-` Info: PPropInfo; var Res: TJSONData);`
212+``` pascal
213+ Info: PPropInfo; var Res: TJSONData);
214+```
181215
182216var
183217
184-` bgracolor: TBGRAPixel;`
218+```text
219+ bgracolor: TBGRAPixel;
220+```
185221
186222begin
187223
188-` if (Info^.PropType^.Name = 'TGraphicsColor') then`\
189-` begin`\
190-`   bgracolor := ColorToBGRA(TColor(GetPropValue(AObject, Info, False)));`\
191-`   Res.Free;`\
192-`   Res := TJSONString.Create('rgb('+IntToStr(bgracolor.red)+','+IntToStr(bgracolor.green)+','+IntToStr(bgracolor.blue)+')');`\
193-` end;`
224+``` pascal
225+ if (Info^.PropType^.Name = 'TGraphicsColor') then
226+ begin
227+ bgracolor := ColorToBGRA(TColor(GetPropValue(AObject, Info, False)));
228+ Res.Free;
229+ Res := TJSONString.Create('rgb('+IntToStr(bgracolor.red)+','+IntToStr(bgracolor.green)+','+IntToStr(bgracolor.blue)+')');
230+ end;
231+```
194232
195233end; 加载代码:
196234
197235procedure TForm1.Button2Click(Sender: TObject); var
198236
199-` DeStreamer: TJSONDeStreamer;`\
200-` s: String;`
237+```text
238+ DeStreamer: TJSONDeStreamer;
239+ s: String;
240+```
201241
202242begin
203243
204-` DeStreamer := TJSONDeStreamer.Create(nil);`\
205-` try`\
206-`   DeStreamer.OnRestoreProperty:=@OnRestoreProperty;`\
207-`   DeStreamer.JSONToObject(Memo1.Lines.Text, BCButton1.StateNormal);`\
208-` finally`\
209-`   DeStreamer.Destroy;`\
210-` end;`
244+``` pascal
245+ DeStreamer := TJSONDeStreamer.Create(nil);
246+ try
247+ DeStreamer.OnRestoreProperty:=@OnRestoreProperty;
248+ DeStreamer.JSONToObject(Memo1.Lines.Text, BCButton1.StateNormal);
249+ finally
250+ DeStreamer.Destroy;
251+ end;
252+```
211253
212254end; procedure TForm1.OnRestoreProperty(Sender: TObject; AObject: TObject;
213255
214-` Info: PPropInfo; AValue: TJSONData; var Handled: Boolean);`
256+``` pascal
257+ Info: PPropInfo; AValue: TJSONData; var Handled: Boolean);
258+```
215259
216260var
217261
218-` bgracolor: TBGRAPixel;`
262+```text
263+ bgracolor: TBGRAPixel;
264+```
219265
220266begin
221267
222-` Handled := False;`\
223-` if (Info^.PropType^.Name = 'TGraphicsColor') then`\
224-` begin`\
225-`   Handled := True;`\
226-`   bgracolor := StrToBGRA(AValue.AsString);`\
227-`   SetPropValue(AObject, Info, BGRAToColor(bgracolor));`\
228-` end;`
268+``` pascal
269+ Handled := False;
270+ if (Info^.PropType^.Name = 'TGraphicsColor') then
271+ begin
272+ Handled := True;
273+ bgracolor := StrToBGRA(AValue.AsString);
274+ SetPropValue(AObject, Info, BGRAToColor(bgracolor));
275+ end;
276+```
229277
230278end; Conclusion 有了这些知识,简单和复杂的JSON数据结构可以加载到Free Pascal程序中。如果需要对 JSON 数据进行任何预处理或后处理,可以首先使用 TJSONParser 类将文本数据从 jsonparser 单元加载到 JSON 数据结构中,然后根据需要使用 fpJSON 单元进行操作。
231279
232280类的 Options 属性可用于控制输出如何在 JSON 中映射其自己的数据结构。
233281
234282---
235283*From the Free Pascal wiki, page "Streaming JSON/zh", as it stood on 2023-05-01 after a change by Clzwf, 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