Sign in Join
Wiki copytemporary

Streaming JSON/zh: what changed

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

Title: Streaming JSON/zh

OldNewLine
1+JSON(JavaScript Object Notation)是一种基于文本的标准化数据格式。顾名思义,JSON 文档是有效的 JavaScript 代码,可以直接转换为 JavaScript 对象。但是,无论使用哪种编程语言,JSON 都可用于数据交换。
2+
3+本教程解释了如何将 JSON 数据加载到免费的 Pascal 程序中并在那里进行处理。它还解释了如何将数据从程序转换为JSON(例如将其发送到Web浏览器)。
4+
5+目录 1 一般要求 2 数据结构 3 加载数据别名记录 4 保存 JSON 5 自定义属性 6 结论 7 参见 8 注释和参考文献 General requirements 加载和存储(流式处理)对象是通过 fpjsonrtti 单元完成的。使用类单元也很有意义(有关详细信息,请参见下文)。
6+
7+因此,uses 语句应至少包含以下两个单元:
8+
9+uses Classes, fpjsonrtti; 目前(2014 年 \<\> 月)Free Pascal 的流媒体系统和 JSON 之间存在一些差异:
10+
11+JSON 是一种区分大小写的数据格式。因此,Free Pascal 对象的属性必须以与 JSON 属性相同的大小写方式编写。 不能使用 DefineProperties 定义任何属性。不能保存对方法(事件处理程序)的引用。阿拉伯数字 可以用作阵列的替代品。 演示程序在 packages/fcl-json/examples 目录中提供了免费的 Pascal 编译器源代码。
12+
13+以下示例中使用此 JSON 结构:
14+
15+{
16+
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`
21+
22+} 它可以在您的自由 Pascal 程序中使用常量赋值定义,如下所示:
23+
24+const 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+} 翻译的任何其他类。
25+
26+所有要读取的属性都必须在类的已发布部分中声明为属性。通常,您可以使用读取和写入直接引用数据字段(变量)。如果你愿意,你当然可以使用getter和setter方法。
27+
28+以下类定义来自 JSON 结构:
29+
30+type
31+
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;  `
38+
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;`
54+
55+该类派生自 TCollectionItem。这意味着它既可以用于 obj 属性,也可以用于集合。如果不需要这样做,则必须在此处定义两个不同的类。TNameObject
56+
57+必须在 TBaseObject 类的构造函数中创建字符串列表,并在析构函数中释放。
58+
59+constructor TBaseObject.Create; begin
60+
61+` // Create Collection and StringList`\
62+` fColl    := TCollection.Create(TNameObject);`\
63+` fStrings := TStringList.Create;`\
64+` fObj     := TNameObject.Create(nil);`
65+
66+end;
67+
68+destructor TBaseObject.Destroy; begin
69+
70+` // Release Collection and StringList`\
71+` fColl.Free;`\
72+` fStrings.Free;`\
73+` fObj.Free;`\
74+` inherited Destroy;`
75+
76+end; 如果您不希望数据类中有更多功能,则它们的定义现在已完成。
77+
78+Load JSON 使用 TJSONDeStreamer 类中的方法,您可以将 JSON 数据直接分配给现有对象。在调用该方法之前,必须创建 TJSONDeStreamer 和目标对象。Procedure JSONToObject(Const JSON : TJSONStringType; AObject : TObject);
79+
80+以下方法从对象 o 中的 JSON 结构加载数据,然后将属性的当前值输出到控制台。JSON_TESTDATA
81+
82+procedure DeStreamTest; var
83+
84+` DeStreamer: TJSONDeStreamer;`\
85+` o: TBaseObject;`\
86+` no: TNameObject;`\
87+` s: String;`
88+
89+begin
90+
91+` WriteLn('DeStream test');`\
92+` WriteLn('======================================');`
93+
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);`
110+
111+` // Cleanup`\
112+` finally`\
113+`   o.Destroy;`\
114+`   DeStreamer.Destroy;`\
115+` end;`
116+
117+end; Saving JSON 类TJSONStreamer用于将对象转换为JSON文本。这里使用该方法。Function ObjectToJSONString(AObject : TObject) : TJSONStringType;
118+
119+在下面的过程中,将创建一个对象,用测试数据填充,然后将其转换为 JSON。JSON 文本在控制台上输出。无法指定属性的输出顺序。
120+
121+procedure StreamTest; var
122+
123+` Streamer: TJSONStreamer;`\
124+` o: TBaseObject;`\
125+` JSONString: String;`
126+
127+begin
128+
129+` WriteLn('Stream test');`\
130+` WriteLn('======================================');`
131+
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');`
142+
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);`
147+
148+` // Cleanup`\
149+` finally`\
150+`   o.Destroy;`\
151+`   Streamer.Destroy;`\
152+` end;`
153+
154+end; Custom properties 现在我们可以保存并加载到 JSON 中,我们还可以自定义属性的保存方式。默认情况下,TColor (TGraphicsColor) 被保存为数字,但例如我们希望将其设置为字符串,因此更易于人类阅读。
155+
156+此示例使用 BGRABitmap 库,该库具有从字符串轻松转换为颜色的功能。在这种情况式处理的控件是 BGRAControls 包中的按钮控件。
157+
158+这将自定义保存和加载 TColor 的方式。
159+
160+保存代码:
161+
162+procedure TForm1.Button1Click(Sender: TObject); var
163+
164+` Streamer: TJSONStreamer;`\
165+` JSONString: String;`
166+
167+begin
168+
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;`
177+
178+end; procedure TForm1.OnStreamProperty(Sender: TObject; AObject: TObject;
179+
180+` Info: PPropInfo; var Res: TJSONData);`
181+
182+var
183+
184+` bgracolor: TBGRAPixel;`
185+
186+begin
187+
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;`
194+
195+end; 加载代码:
196+
197+procedure TForm1.Button2Click(Sender: TObject); var
198+
199+` DeStreamer: TJSONDeStreamer;`\
200+` s: String;`
201+
202+begin
203+
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;`
211+
212+end; procedure TForm1.OnRestoreProperty(Sender: TObject; AObject: TObject;
213+
214+` Info: PPropInfo; AValue: TJSONData; var Handled: Boolean);`
215+
216+var
217+
218+` bgracolor: TBGRAPixel;`
219+
220+begin
221+
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;`
229+
230+end; Conclusion 有了这些知识,简单和复杂的JSON数据结构可以加载到Free Pascal程序中。如果需要对 JSON 数据进行任何预处理或后处理,可以首先使用 TJSONParser 类将文本数据从 jsonparser 单元加载到 JSON 数据结构中,然后根据需要使用 fpJSON 单元进行操作。
231+
232+类的 Options 属性可用于控制输出如何在 JSON 中映射其自己的数据结构。
233+
234+---
235+*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