Sign in Join
Wiki copytemporary

Streaming JSON/de: what changed

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

Title: Streaming JSON/de

OldNewLine
1+[[JSON]] (JavaScript Object Notation) ist ein textbasiertes, standardisiertes Datenformat. Wie der Name sagt, sind JSON-Dokumente gültiger JavaScript-Code und können dort direkt in Objekte umgesetzt werden. An und für sich kann es aber zum Datenaustausch unabhängig von der verwendeten Programmiersprache verwendet werden.
2+
3+In diesem Tutorial wird erklärt, wie man JSON-Daten in ein Free-Pascal-Programm lädt um sie dort zu verarbeiten; Ebenso wird erklärt, wie man die Daten aus dem Programm in JSON konvertiert (um sie dann zum Beispiel an einen Webbrowser zu senden).
4+
5+## Allgemeines und Voraussetzungen
6+
7+Das Laden und Speichern von Objekten erfolgt mit der Unit [[fpjsonrtti]]. Weiterhin ist die Unit Classes sinnvoll (mehr dazu weiter unten im Abschnitt Datenstruktur ?; Die [[Uses/de|uses]]-Anweisung sollte also mindestens diese beiden Units enthalten:
8+
9+``` pascal
10+uses Classes, fpjsonrtti;
11+```
12+
13+Zum derzeitigen Zeitpunkt (Mai 2014) gibt es einige Unterschiede zum [[Streaming components/de|Streaming-Systems]] von Free Pascal:
14+
15+- JSON-Daten sind abhängig von Groß- und Kleinschreibung (case insensitive).1 Daraus folgt, dass die Eigenschaften der Free-Pascal-Objekte genau wie die JSON-Eigenschaften geschrieben werden müssen.
16+- Es können keine Eigenschaften mit DefineProperties definiert werden; es können keine Referenzen auf Methoden (Event-Handler) gespeichert werden.2
17+- [[TCollection]] und [[TStrings]] können als Ersatz für Arrays verwendet werden.
18+
19+Mit den Quelltexten des Free-Pascal-Compilers wird im Verzeichnis `<fpc-quellen>/packages/fcl-json/examples/demortti.pp` ein Demoprogramm mitgeliefert.
20+
21+Als Beispiel wird im Folgenden immer diese JSON-Struktur verwendet.
22+
23+``` JavaScript
24+{
25+ "id" : 123, // ein Integer
26+ "obj" : { "name": "Hallo Welt!" }, // ein Objekt
27+ "coll" : [ { "name": "Objekt 1" }, { "name": "Object 2" } ], // zwei Objekte in einer TCollection
28+ "strings": [ "Hallo 1", "Hallo 2" ] // eine String-Liste
29+}
30+```
31+
32+Im eigenen Programmquelltext kann sie so definiert werden:
33+
34+``` pascal
35+const JSON_TESTDATA =
36+'{'+LineEnding+
37+' "id": 123,'+LineEnding+
38+' "obj": { "name": "Hallo Welt!" },'+LineEnding+
39+' "coll": [ { "name": "Objekt 1" }, { "name": "Objekt 2" } ],'+LineEnding+
40+' "strings": [ "Hallo 1", "Hallo 2" ]'+LineEnding+
41+'}';
42+```
43+
44+## Datenstruktur
45+
46+Als Basisklasse für die Daten bietet sich [[TPersistent]] aus der Unit Classes an, da für sie und alle Unterklassen [[Runtime Type Information (RTTI)|Laufzeit-Typinformationen]] (<abbr title="Runtime Type Information">RTTI</abbr>) erstellt werden. Diese werden für das Streaming zwingend benötigt. Da sich *fpjsonrtti* nicht in das Streaming-System integriert, kann auch jede andere Klasse, die mit dem Compilerschalter `{$M+}` übersetzt wurde, verwendet werden.
47+
48+Alle zu lesenden Eigenschaften müssen als [[Property/de|property]] im [[Published/de|published]]-Abschnitt der Klasse deklariert werden. In der Regel, kann hier mit read und write direkt auf ein Datenfeld (die Variable) verweisen werden. Wenn man möchte, können natürlich auch Getter- und Setter-Methoden verwendet werden.
49+
50+Aus der JSON-Struktur ergibt sich folgende Klassendefinition.
51+
52+``` pascal
53+type
54+ TNameObject = class(TCollectionItem) // Klasse für die Eigenschaft 'obj' und die TCollection
55+ private
56+ fName: String;
57+ published
58+ property name: String read fName write fName;
59+ end;
60+
61+ TBaseObject = class(TPersistent) // Klasse für die gesamte JSON-Struktur
62+ private
63+ fid: Integer;
64+ fObj: TNameObject;
65+ fColl: TCollection;
66+ fStrings: TStrings;
67+ public
68+ constructor Create;
69+ destructor Destroy; override;
70+ published // alle Eigenschaften müssen published sein
71+ property id: Integer read fid write fid;
72+ property obj: TNameObject read fObj write fObj;
73+ property coll: TCollection read fColl;
74+ property strings: TStrings read fStrings;
75+ end;
76+```
77+
78+Die Klasse `TNameObject` wurde von [[TCollectionItem]] abgeleitet. Damit kann sie sowohl für die Eigenschaft *obj* als auch in der Collection verwendet werden. Wenn dies nicht gewünscht ist, müssen hier zwei unterschiedliche Klassen definiert werden.
79+
80+Im Konstruktor der Klasse TBaseObject müssen die TCollection sowie die String-Liste erstellt und im Destruktor wieder freigegeben werden.
81+
82+``` pascal
83+constructor TBaseObject.Create;
84+begin
85+ // Collection und StringList erstellen
86+ fColl := TCollection.Create(TNameObject);
87+ fStrings := TStringList.Create;
88+ fObj := TNameObject.Create(nil);
89+end;
90+
91+destructor TBaseObject.Destroy;
92+begin
93+ // Collection und StringList wieder freigeben
94+ fColl.Free;
95+ fStrings.Free;
96+ fObj.Free;
97+ inherited Destroy;
98+end;
99+```
100+
101+Sofern Sie keine weitere Funktionalität in den Datenklassen haben möchten, ist ihre Definition bereits fertig.
102+
103+## JSON laden
104+
105+Mit der Methode `Procedure JSONToObject(Const JSON : TJSONStringType; AObject : TObject);` der Klasse [[TJSONDeStreamer]] können Sie JSON-Daten direkt an ein *vorhandenes* Objekt zuweisen. Bevor Sie die Methode aufrufen, müssen Sie TJSONDeStreamer und das Ziel-Objekt erstellen.
106+
107+Die folgende Methode lädt die Daten aus der JSON-Struktur `JSON_TESTDATA` in das Objekt o und gibt die aktuellen Werte der Eigenschaften danach auf der Konsole aus.
108+
109+``` pascal
110+procedure DeStreamTest;
111+var
112+ DeStreamer: TJSONDeStreamer;
113+ o: TBaseObject;
114+ no: TNameObject;
115+ s: String;
116+begin
117+ WriteLn('DeStream test');
118+ WriteLn('======================================');
119+
120+ // DeStreamer-Objekt und Ziel-Objekt erstellen
121+ DeStreamer := TJSONDeStreamer.Create(nil);
122+ o := TBaseObject.Create;
123+ try
124+ // JSON-Daten in das Objekt o laden
125+ DeStreamer.JSONToObject(JSON_TESTDATA, o);
126+ // ID ausgeben
127+ WriteLn(o.id);
128+ // Objekt-Name ausgeben
129+ WriteLn(o.obj.name);
130+ // alle Namen der Objekte ausgeben
131+ for TCollectionItem(no) in o.coll do
132+ Writeln(no.name);
133+ // alle Strings ausgeben
134+ for s in o.strings do
135+ WriteLn(s);
136+
137+ // aufräumen
138+ finally
139+ o.Destroy;
140+ DeStreamer.Destroy;
141+ end;
142+end;
143+```
144+
145+## JSON speichern
146+
147+Um ein Objekt in einen JSON-Text zu überführen, wird die Klasse [[TJSONStreamer]] verwendet. Hier wird die Methode `Function ObjectToJSONString(AObject : TObject) : TJSONStringType;` verwendet.
148+
149+In der folgenden Prozedur wird ein Objekt erstellt, mit den Testdaten befüllt und anschließend nach JSON überführt. Der JSON-Text wird auf der Konsole ausgegeben. Es kann nicht festgelegt werden, in welcher Reihenfolge die Eigenschaften ausgeben werden
150+
151+``` pascal
152+procedure StreamTest;
153+var
154+ Streamer: TJSONStreamer;
155+ o: TBaseObject;
156+ JSONString: String;
157+begin
158+ WriteLn('Stream test');
159+ WriteLn('======================================');
160+
161+ Streamer := TJSONStreamer.Create(nil);
162+ o := TBaseObject.Create;
163+ try
164+ // Daten festlegen
165+ o.id := 123;
166+ o.obj.name := 'Hallo Welt!';
167+ TNameObject(o.coll.Add).name := 'Objekt 1';
168+ TNameObject(o.coll.Add).name := 'Objekt 2';
169+ o.strings.Add('Hallo 1');
170+ o.strings.Add('Hallo 2');
171+
172+ Streamer.Options := Streamer.Options + [jsoTStringsAsArray]; // Strings als JSON-Array ausgeben
173+ // nach JSON überführen und ausgeben
174+ JSONString := Streamer.ObjectToJSONString(o);
175+ WriteLn(JSONString);
176+
177+ // aufräumen
178+ finally
179+ o.Destroy;
180+ Streamer.Destroy;
181+ end;
182+end;
183+```
184+
185+## Ausblick
186+
187+Mit dem vorgestellten Wissen können einfache und komplexe JSON-Datenstrukturen in Free Pascal geladen werden. Sollte eine Vor- oder Nachbearbeitung der JSON-Daten notwendig sein, können die Textdaten zunächst mit der Klasse [[TJSONParser]] aus der Unit [[jsonparser]] in eine JSON-Datenstruktur geladen werden und dann mit der Unit [[fpJSON]] beliebig manipuliert werden.
188+
189+Über die Eigenschaft Options der Klasse TJSONStreamer kann gesteuert werden, wie die Ausgabe die eigenen Datenstrukturen in JSON abgebildet werden.
190+
191+## Siehe auch
192+
193+- [[JSON]]
194+- [[fcl-json]]
195+- [[Streaming components/de]]
196+
197+## Einzelnachweise
198+
199+1. <div id="ref1">
200+
201+ <http://lists.freepascal.org/fpc-pascal/2013-January/036254.html>
202+
203+ </div>
204+
205+2. \<div id="ref2\>http://lists.lazarus.freepascal.org/pipermail/lazarus/2011-January/058878.html
206+ </div>
207+
208+---
209+*From the Free Pascal wiki, page "Streaming JSON/de", as it stood on 2022-08-06 after a change by Kai Burghardt, 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