Sign in Join
Wiki copytemporary

Streaming JSON/zh

Deutsch · English · Polski · Русский · 中文 · 中文(中国)

JSON(JavaScript Object Notation)是一种基于文本的标准化数据格式。顾名思义,JSON 文档是有效的 JavaScript 代码,可以直接转换为 JavaScript 对象。但是,无论使用哪种编程语言,JSON 都可用于数据交换。

本教程解释了如何将 JSON 数据加载到免费的 Pascal 程序中并在那里进行处理。它还解释了如何将数据从程序转换为JSON(例如将其发送到Web浏览器)。

目录 1 一般要求 2 数据结构 3 加载数据别名记录 4 保存 JSON 5 自定义属性 6 结论 7 参见 8 注释和参考文献 General requirements 加载和存储(流式处理)对象是通过 fpjsonrtti 单元完成的。使用类单元也很有意义(有关详细信息,请参见下文)。

因此,uses 语句应至少包含以下两个单元:

uses Classes, fpjsonrtti; 目前(2014 年 <> 月)Free Pascal 的流媒体系统和 JSON 之间存在一些差异:

JSON 是一种区分大小写的数据格式。因此,Free Pascal 对象的属性必须以与 JSON 属性相同的大小写方式编写。 不能使用 DefineProperties 定义任何属性。不能保存对方法(事件处理程序)的引用。阿拉伯数字 可以用作阵列的替代品。 演示程序在 packages/fcl-json/examples 目录中提供了免费的 Pascal 编译器源代码。

以下示例中使用此 JSON 结构:

{

pascal
 "id"     : 123,                                                // an integer
 "obj"    : { "name": "Hello world!" },                         // an object
 "coll"   : [ { "name": "Object 1" }, { "name": "Object 2" } ], // two objects in a TCollection
 "strings": [ "Hello 1", "Hello 2" ]                            // a string list

} 它可以在您的自由 Pascal 程序中使用常量赋值定义,如下所示:

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+} 翻译的任何其他类。

所有要读取的属性都必须在类的已发布部分中声明为属性。通常,您可以使用读取和写入直接引用数据字段(变量)。如果你愿意,你当然可以使用getter和setter方法。

以下类定义来自 JSON 结构:

type

pascal
 TNameObject = class(TCollectionItem) // class for the 'obj' property and TCollection 
 private
   fName: String;
 published
   property name: String read fName write fName;
 end;
pascal
 TBaseObject = class(TPersistent)  // class for the entire JSON structure
 private
   fid: Integer;
   fObj: TNameObject;
   fColl: TCollection;
   fStrings: TStrings;
 public
   constructor Create;
   destructor Destroy; override;
 published                         // all properties must be published 
   property id: Integer read fid write fid;
   property obj: TNameObject read fObj write fObj;
   property coll: TCollection read fColl;
   property strings: TStrings read fStrings;
 end;

该类派生自 TCollectionItem。这意味着它既可以用于 obj 属性,也可以用于集合。如果不需要这样做,则必须在此处定义两个不同的类。TNameObject

必须在 TBaseObject 类的构造函数中创建字符串列表,并在析构函数中释放。

constructor TBaseObject.Create; begin

pascal
 // Create Collection and StringList
 fColl    := TCollection.Create(TNameObject);
 fStrings := TStringList.Create;
 fObj     := TNameObject.Create(nil);

end;

destructor TBaseObject.Destroy; begin

pascal
 // Release Collection and StringList
 fColl.Free;
 fStrings.Free;
 fObj.Free;
 inherited Destroy;

end; 如果您不希望数据类中有更多功能,则它们的定义现在已完成。

Load JSON 使用 TJSONDeStreamer 类中的方法,您可以将 JSON 数据直接分配给现有对象。在调用该方法之前,必须创建 TJSONDeStreamer 和目标对象。Procedure JSONToObject(Const JSON : TJSONStringType; AObject : TObject);

以下方法从对象 o 中的 JSON 结构加载数据,然后将属性的当前值输出到控制台。JSON_TESTDATA

procedure DeStreamTest; var

text
 DeStreamer: TJSONDeStreamer;
 o: TBaseObject;
 no: TNameObject;
 s: String;

begin

text
 WriteLn('DeStream test');
 WriteLn('======================================');
pascal
 // Create the DeStreamer object and target object
 DeStreamer := TJSONDeStreamer.Create(nil);
 o := TBaseObject.Create;
 try
   // Load JSON data into object o
   DeStreamer.JSONToObject(JSON_TESTDATA, o);
   // output ID
   WriteLn(o.id);
   // output object name
   WriteLn(o.obj.name); 
   // output the names of all objects
   for TCollectionItem(no) in o.coll do
     Writeln(no.name);
   // output all strings
   for s in o.strings do
     WriteLn(s);
pascal
 // Cleanup
 finally
   o.Destroy;
   DeStreamer.Destroy;
 end;

end; Saving JSON 类TJSONStreamer用于将对象转换为JSON文本。这里使用该方法。Function ObjectToJSONString(AObject : TObject) : TJSONStringType;

在下面的过程中,将创建一个对象,用测试数据填充,然后将其转换为 JSON。JSON 文本在控制台上输出。无法指定属性的输出顺序。

procedure StreamTest; var

text
 Streamer: TJSONStreamer;
 o: TBaseObject;
 JSONString: String;

begin

text
 WriteLn('Stream test');
 WriteLn('======================================');
pascal
 Streamer := TJSONStreamer.Create(nil);
 o := TBaseObject.Create;
 try
   // Setup data
   o.id := 123;
   o.obj.name := 'Hello world!';
   TNameObject(o.coll.Add).name := 'Object 1';
   TNameObject(o.coll.Add).name := 'Object 2';
   o.strings.Add('Hello 1');
   o.strings.Add('Hello 2');
pascal
   Streamer.Options := Streamer.Options + [jsoTStringsAsArray]; // Save strings as JSON array
   // convert to JSON and output to console
   JSONString := Streamer.ObjectToJSONString(o);
   WriteLn(JSONString);
pascal
 // Cleanup
 finally
   o.Destroy;
   Streamer.Destroy;
 end;

end; Custom properties 现在我们可以保存并加载到 JSON 中,我们还可以自定义属性的保存方式。默认情况下,TColor (TGraphicsColor) 被保存为数字,但例如我们希望将其设置为字符串,因此更易于人类阅读。

此示例使用 BGRABitmap 库,该库具有从字符串轻松转换为颜色的功能。在这种情况式处理的控件是 BGRAControls 包中的按钮控件。

这将自定义保存和加载 TColor 的方式。

保存代码:

procedure TForm1.Button1Click(Sender: TObject); var

text
 Streamer: TJSONStreamer;
 JSONString: String;

begin

pascal
 Streamer := TJSONStreamer.Create(nil);
 try
   Streamer.OnStreamProperty:=@OnStreamProperty;
   JSONString := Streamer.ObjectToJSONString(BCButton1.StateNormal);
   Memo1.Lines.Text := JSONString;
 finally
   Streamer.Destroy;
 end;

end; procedure TForm1.OnStreamProperty(Sender: TObject; AObject: TObject;

pascal
 Info: PPropInfo; var Res: TJSONData);

var

text
 bgracolor: TBGRAPixel;

begin

pascal
 if (Info^.PropType^.Name = 'TGraphicsColor') then
 begin
   bgracolor := ColorToBGRA(TColor(GetPropValue(AObject, Info, False)));
   Res.Free;
   Res := TJSONString.Create('rgb('+IntToStr(bgracolor.red)+','+IntToStr(bgracolor.green)+','+IntToStr(bgracolor.blue)+')');
 end;

end; 加载代码:

procedure TForm1.Button2Click(Sender: TObject); var

text
 DeStreamer: TJSONDeStreamer;
 s: String;

begin

pascal
 DeStreamer := TJSONDeStreamer.Create(nil);
 try
   DeStreamer.OnRestoreProperty:=@OnRestoreProperty;
   DeStreamer.JSONToObject(Memo1.Lines.Text, BCButton1.StateNormal);
 finally
   DeStreamer.Destroy;
 end;

end; procedure TForm1.OnRestoreProperty(Sender: TObject; AObject: TObject;

pascal
 Info: PPropInfo; AValue: TJSONData; var Handled: Boolean);

var

text
 bgracolor: TBGRAPixel;

begin

pascal
 Handled := False;
 if (Info^.PropType^.Name = 'TGraphicsColor') then
 begin
   Handled := True;
   bgracolor := StrToBGRA(AValue.AsString);
   SetPropValue(AObject, Info, BGRAToColor(bgracolor));
 end;

end; Conclusion 有了这些知识,简单和复杂的JSON数据结构可以加载到Free Pascal程序中。如果需要对 JSON 数据进行任何预处理或后处理,可以首先使用 TJSONParser 类将文本数据从 jsonparser 单元加载到 JSON 数据结构中,然后根据需要使用 fpJSON 单元进行操作。

类的 Options 属性可用于控制输出如何在 JSON 中映射其自己的数据结构。


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.

Revision 2, last changed by WikiArchive .

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.