Difference between revisions of "Streaming JSON"
Jwdietrich (talk | contribs) (categorization) |
(Some language fixes: this really wasn't English/comprehensible without the original German. Don't use <source> but <syntaxhighlight>) |
||
Line 1: | Line 1: | ||
{{Translate}} | {{Translate}} | ||
− | note: This article was translated from [[Streaming_JSON/de]] German on 20141002 using Google | + | note: This article was originally translated from [[Streaming_JSON/de]] German on 20141002 using Google Translat. |
− | [[JSON]] (JavaScript Object Notation) is a text-based, standardized data format. As the name implies, JSON documents are valid JavaScript code where they can be directly converted into objects | + | [[JSON]] (JavaScript Object Notation) is a text-based, standardized data format. As the name implies, JSON documents are valid JavaScript code where they can be directly converted into JavaScript objects. But in and of itself it can be used regardless of the programming language used for data exchange. |
− | |||
− | |||
+ | This tutorial explains how to load JSON data in a Free Pascal program to process it. It also explains how to convert FPC data into JSON (e.g. to send it to a web server). | ||
== General and conditions == | == General and conditions == | ||
− | Loading and storing | + | Loading and storing (streaming) FPC object data is done with the fpjsonrtti unit. Furthermore, the Classes unit is useful (see below for details). |
− | |||
− | |||
+ | The uses statement should therefore contain at least these two units: | ||
+ | <syntaxhighlight>uses Classes, fpjsonrtti;</syntaxhighlight> | ||
− | + | Currently (May 2014) there are some differences to the streaming system of Free Pascal with ??presumably JavaScript??: | |
− | * JSON data | + | * JSON data is case-sensitive. Therefore, the properties of Free Pascal objects as JSON properties must be written with correct casing. |
− | * | + | * No properties can be defined with DefineProperties. Neither can references to methods (event handlers) be stored. [[#ref2|<sup>2</sup>]] |
* [[TCollection]] and [[TStrings]] could be used as a substitute for arrays. | * [[TCollection]] and [[TStrings]] could be used as a substitute for arrays. | ||
− | Demo programs are provided with the source code of Free Pascal Compiler | + | Demo programs are provided with the source code of Free Pascal Compiler (in the packages/fcl-json/examples directory). |
As an example, we will start with the following JSON data: | As an example, we will start with the following JSON data: | ||
− | < | + | <syntaxhighlight lang="JavaScript"> |
{ | { | ||
"id" : 123, // an Integer | "id" : 123, // an Integer | ||
− | "obj" : { "name": " | + | "obj" : { "name": "Hello world!" }, // an Object |
− | "coll" : [ { "name": " | + | "coll" : [ { "name": "Object 1" }, { "name": "Object 2" } ], // two objects in a TCollection |
− | "strings": [ "Hallo 1", " | + | "strings": [ "Hallo 1", "Hello 2" ] // a string list |
} | } | ||
− | </ | + | </syntaxhighlight> |
This can be assigned in FreePascal using a constant assignment as follows: | This can be assigned in FreePascal using a constant assignment as follows: | ||
− | < | + | <syntaxhighlight> |
const JSON_TESTDATA = | const JSON_TESTDATA = | ||
'{'+LineEnding+ | '{'+LineEnding+ | ||
' "id": 123,'+LineEnding+ | ' "id": 123,'+LineEnding+ | ||
− | ' "obj": { "name": " | + | ' "obj": { "name": "Hello world!" },'+LineEnding+ |
− | ' "coll": [ { "name": " | + | ' "coll": [ { "name": "Object 1" }, { "name": "Object 2" } ],'+LineEnding+ |
− | ' "strings": [ " | + | ' "strings": [ "Hello 1", "Hello 2" ]'+LineEnding+ |
'}'; | '}'; | ||
− | </ | + | </syntaxhighlight> |
== Data Structure == | == Data Structure == | ||
Line 51: | Line 50: | ||
From the JSON structure results in the following class definition. | From the JSON structure results in the following class definition. | ||
− | < | + | <syntaxhighlight> |
type | type | ||
TNameObject = class(TCollectionItem) // class for the property 'obj' and the TCollection | TNameObject = class(TCollectionItem) // class for the property 'obj' and the TCollection | ||
Line 75: | Line 74: | ||
property strings: TStrings read fStrings; | property strings: TStrings read fStrings; | ||
end; | end; | ||
− | </ | + | </syntaxhighlight> |
The class <source enclose="none">TNameObject</source> is of [[TCollectionItem]] derived. So they can both for the property ''obj'' be used as well in the collection. If this is not desired, here two different classes must be defined. | The class <source enclose="none">TNameObject</source> is of [[TCollectionItem]] derived. So they can both for the property ''obj'' be used as well in the collection. If this is not desired, here two different classes must be defined. | ||
Line 81: | Line 80: | ||
In the constructor of the class TBaseObject the TCollection and the string list must be created and released in the destructor. | In the constructor of the class TBaseObject the TCollection and the string list must be created and released in the destructor. | ||
− | < | + | <syntaxhighlight> |
constructor TBaseObject.Create; | constructor TBaseObject.Create; | ||
begin | begin | ||
Line 98: | Line 97: | ||
inherited Destroy; | inherited Destroy; | ||
end; | end; | ||
− | </ | + | </syntaxhighlight> |
If you do not want any more functionality in the data classes, their definition is already done. | If you do not want any more functionality in the data classes, their definition is already done. | ||
Line 108: | Line 107: | ||
The following method loads the data from the JSON structure <source enclose="none">JSON_TESTDATA</source> in the o object and returns the current values of the properties then on the console. | The following method loads the data from the JSON structure <source enclose="none">JSON_TESTDATA</source> in the o object and returns the current values of the properties then on the console. | ||
− | < | + | <syntaxhighlight> |
procedure DeStreamTest; | procedure DeStreamTest; | ||
var | var | ||
Line 142: | Line 141: | ||
end; | end; | ||
end; | end; | ||
− | </ | + | </syntaxhighlight> |
== JSON store == | == JSON store == | ||
− | To convert an object into a JSON text, the class [[TJSONStreamer]] is used. Here is the method < | + | To convert an object into a JSON text, the class [[TJSONStreamer]] is used. Here is the method <syntaxhighlight enclose="none">Function ObjectToJSONString(AObject : TObject) : TJSONStringType;</syntaxhighlight> used. |
In the following procedure, an object is created, filled with the test data, and then transferred to JSON. The JSON text is printed to the console. It can not be defined, the order in which the properties are to spend | In the following procedure, an object is created, filled with the test data, and then transferred to JSON. The JSON text is printed to the console. It can not be defined, the order in which the properties are to spend | ||
− | < | + | <syntaxhighlight> |
procedure StreamTest; | procedure StreamTest; | ||
var | var | ||
Line 182: | Line 181: | ||
end; | end; | ||
end; | end; | ||
− | </ | + | </syntaxhighlight> |
== Outlook == | == Outlook == | ||
Line 194: | Line 193: | ||
* [[JSON]] | * [[JSON]] | ||
* [[fcl-json]] | * [[fcl-json]] | ||
− | * [[Streaming components | + | * [[Streaming components]] |
== Notes & References == | == Notes & References == | ||
Line 200: | Line 199: | ||
# <div id="ref2>http://lists.lazarus.freepascal.org/pipermail/lazarus/2011-January/058878.html</div> | # <div id="ref2>http://lists.lazarus.freepascal.org/pipermail/lazarus/2011-January/058878.html</div> | ||
− | [[Category:Tutorials | + | [[Category:Tutorials]] |
+ | [[Category:JSON]] | ||
[[Category:JavaScript]] | [[Category:JavaScript]] |
Revision as of 09:32, 5 November 2014
note: This article was originally translated from Streaming_JSON/de German on 20141002 using Google Translat.
JSON (JavaScript Object Notation) is a text-based, standardized data format. As the name implies, JSON documents are valid JavaScript code where they can be directly converted into JavaScript objects. But in and of itself it can be used regardless of the programming language used for data exchange.
This tutorial explains how to load JSON data in a Free Pascal program to process it. It also explains how to convert FPC data into JSON (e.g. to send it to a web server).
General and conditions
Loading and storing (streaming) FPC object data is done with the fpjsonrtti unit. Furthermore, the Classes unit is useful (see below for details).
The uses statement should therefore contain at least these two units:
uses Classes, fpjsonrtti;
Currently (May 2014) there are some differences to the streaming system of Free Pascal with ??presumably JavaScript??:
- JSON data is case-sensitive. Therefore, the properties of Free Pascal objects as JSON properties must be written with correct casing.
- No properties can be defined with DefineProperties. Neither can references to methods (event handlers) be stored. 2
- TCollection and TStrings could be used as a substitute for arrays.
Demo programs are provided with the source code of Free Pascal Compiler (in the packages/fcl-json/examples directory).
As an example, we will start with the following JSON data:
{
"id" : 123, // an Integer
"obj" : { "name": "Hello world!" }, // an Object
"coll" : [ { "name": "Object 1" }, { "name": "Object 2" } ], // two objects in a TCollection
"strings": [ "Hallo 1", "Hello 2" ] // a string list
}
This can be assigned in FreePascal using a constant assignment as follows:
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
As the base class for the data itself provides TPersistent on from the Classes unit, since for them and all subclasses Laufzeit-Typinformationen (RTTI) to be created. These are absolutely required for streaming. Since fpjsonrtti not integrated into the streaming system, any other class that the compiler switch {$M+}
was translated, are used.
All properties must be read as a property in published section of the class are declared. In general, (the variable) may here with read and write directly to a data field will refer. If you want to, of course getter and setter methods can be used.
From the JSON structure results in the following class definition.
type
TNameObject = class(TCollectionItem) // class for the property 'obj' and the TCollection
private
fName: String;
published
property name: String read fName write fName;
end;
TBaseObject = class(TPersistent) // class for the JSON structure
private
fid: Integer;
fObj: TNameObject;
fColl: TCollection;
fStrings: TStrings;
public
constructor Create;
destructor Destroy; override;
published // all properties have 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;
The class TNameObject
is of TCollectionItem derived. So they can both for the property obj be used as well in the collection. If this is not desired, here two different classes must be defined.
In the constructor of the class TBaseObject the TCollection and the string list must be created and released in the destructor.
constructor TBaseObject.Create;
begin
// Collection and StringList constructor
fColl := TCollection.Create(TNameObject);
fStrings := TStringList.Create;
fObj := TNameObject.Create(nil);
end;
destructor TBaseObject.Destroy;
begin
// Collection and StringList destructor
fColl.Free;
fStrings.Free;
fObj.Free;
inherited Destroy;
end;
If you do not want any more functionality in the data classes, their definition is already done.
Load JSON
With the method Procedure JSONToObject(Const JSON : TJSONStringType; AObject : TObject);
the class TJSONDeStreamer you can JSON data directly to an existing assigned object. Before you call the method, you must create TJSONDeStreamer and the target object.
The following method loads the data from the JSON structure JSON_TESTDATA
in the o object and returns the current values of the properties then on the console.
procedure DeStreamTest;
var
DeStreamer: TJSONDeStreamer;
o: TBaseObject;
no: TNameObject;
s: String;
begin
WriteLn('DeStream test');
WriteLn('======================================');
// DeStreamer object and target object create
DeStreamer := TJSONDeStreamer.Create(nil);
o := TBaseObject.Create;
try
// JSON data in the object o Load
DeStreamer.JSONToObject(JSON_TESTDATA, o);
// ID
WriteLn(o.id);
// Object-Name
WriteLn(o.obj.name);
// Print the names of all objects
for TCollectionItem(no) in o.coll do
Writeln(no.name);
// all strings output
for s in o.strings do
WriteLn(s);
// Cleanup
finally
o.Destroy;
DeStreamer.Destroy;
end;
end;
JSON store
To convert an object into a JSON text, the class TJSONStreamer is used. Here is the method Function ObjectToJSONString(AObject : TObject) : TJSONStringType;
used.
In the following procedure, an object is created, filled with the test data, and then transferred to JSON. The JSON text is printed to the console. It can not be defined, the order in which the properties are to spend
procedure StreamTest;
var
Streamer: TJSONStreamer;
o: TBaseObject;
JSONString: String;
begin
WriteLn('Stream test');
WriteLn('======================================');
Streamer := TJSONStreamer.Create(nil);
o := TBaseObject.Create;
try
// Data set
o.id := 123;
o.obj.name := 'Hallo Welt!';
TNameObject(o.coll.Add).name := 'Objekt 1';
TNameObject(o.coll.Add).name := 'Objekt 2';
o.strings.Add('Hallo 1');
o.strings.Add('Hallo 2');
Streamer.Options := Streamer.Options + [jsoTStringsAsArray]; // Strings als JSON-Array ausgeben
// JSON convert and output
JSONString := Streamer.ObjectToJSONString(o);
WriteLn(JSONString);
// Cleanup
finally
o.Destroy;
Streamer.Destroy;
end;
end;
Outlook
With the presented knowledge simple and complex JSON data structures in Free Pascal can be loaded. Should any preparatory or finishing the JSON data be necessary, the text data can initially with the classTJSONParser from the Unit jsonparser be loaded into a JSON data structure and then with the Unit fpJSON be manipulated.
Use the Options property of the class TJSONStreamer can be controlled, such as the issue's own data structures are represented in JSON.