Sign in Join
Wiki copytemporary

Streaming JSON/de: what changed

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

OldNewLine
11[[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.
22
33In 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).
44
55## Allgemeines und Voraussetzungen
66
77Das 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:
88
99``` pascal
1010uses Classes, fpjsonrtti;
1111```
1212
1313Zum derzeitigen Zeitpunkt (Mai 2014) gibt es einige Unterschiede zum [[Streaming components/de|Streaming-Systems]] von Free Pascal:
1414
1515- 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.
1616- Es können keine Eigenschaften mit DefineProperties definiert werden; es können keine Referenzen auf Methoden (Event-Handler) gespeichert werden.2
1717- [[TCollection]] und [[TStrings]] können als Ersatz für Arrays verwendet werden.
1818
1919Mit den Quelltexten des Free-Pascal-Compilers wird im Verzeichnis `<fpc-quellen>/packages/fcl-json/examples/demortti.pp` ein Demoprogramm mitgeliefert.
2020
2121Als Beispiel wird im Folgenden immer diese JSON-Struktur verwendet.
2222
2323``` JavaScript
2424{
2525 "id" : 123, // ein Integer
2626 "obj" : { "name": "Hallo Welt!" }, // ein Objekt
2727 "coll" : [ { "name": "Objekt 1" }, { "name": "Object 2" } ], // zwei Objekte in einer TCollection
2828 "strings": [ "Hallo 1", "Hallo 2" ] // eine String-Liste
2929}
3030```
3131
3232Im eigenen Programmquelltext kann sie so definiert werden:
3333
3434``` pascal
3535const JSON_TESTDATA =
3636'{'+LineEnding+
3737' "id": 123,'+LineEnding+
3838' "obj": { "name": "Hallo Welt!" },'+LineEnding+
3939' "coll": [ { "name": "Objekt 1" }, { "name": "Objekt 2" } ],'+LineEnding+
4040' "strings": [ "Hallo 1", "Hallo 2" ]'+LineEnding+
4141'}';
4242```
4343
4444## Datenstruktur
4545
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.
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]] (RTTI) 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.
4747
4848Alle 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.
4949
5050Aus der JSON-Struktur ergibt sich folgende Klassendefinition.
5151
5252``` pascal
5353type
5454 TNameObject = class(TCollectionItem) // Klasse für die Eigenschaft 'obj' und die TCollection
5555 private
5656 fName: String;
5757 published
5858 property name: String read fName write fName;
5959 end;
6060
6161 TBaseObject = class(TPersistent) // Klasse für die gesamte JSON-Struktur
6262 private
6363 fid: Integer;
6464 fObj: TNameObject;
6565 fColl: TCollection;
6666 fStrings: TStrings;
6767 public
6868 constructor Create;
6969 destructor Destroy; override;
7070 published // alle Eigenschaften müssen published sein
7171 property id: Integer read fid write fid;
7272 property obj: TNameObject read fObj write fObj;
7373 property coll: TCollection read fColl;
7474 property strings: TStrings read fStrings;
7575 end;
7676```
7777
7878Die 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.
7979
8080Im Konstruktor der Klasse TBaseObject müssen die TCollection sowie die String-Liste erstellt und im Destruktor wieder freigegeben werden.
8181
8282``` pascal
8383constructor TBaseObject.Create;
8484begin
8585 // Collection und StringList erstellen
8686 fColl := TCollection.Create(TNameObject);
8787 fStrings := TStringList.Create;
8888 fObj := TNameObject.Create(nil);
8989end;
9090
9191destructor TBaseObject.Destroy;
9292begin
9393 // Collection und StringList wieder freigeben
9494 fColl.Free;
9595 fStrings.Free;
9696 fObj.Free;
9797 inherited Destroy;
9898end;
9999```
100100
101101Sofern Sie keine weitere Funktionalität in den Datenklassen haben möchten, ist ihre Definition bereits fertig.
102102
103103## JSON laden
104104
105105Mit 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.
106106
107107Die 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.
108108
109109``` pascal
110110procedure DeStreamTest;
111111var
112112 DeStreamer: TJSONDeStreamer;
113113 o: TBaseObject;
114114 no: TNameObject;
115115 s: String;
116116begin
117117 WriteLn('DeStream test');
118118 WriteLn('======================================');
119119
120120 // DeStreamer-Objekt und Ziel-Objekt erstellen
121121 DeStreamer := TJSONDeStreamer.Create(nil);
122122 o := TBaseObject.Create;
123123 try
124124 // JSON-Daten in das Objekt o laden
125125 DeStreamer.JSONToObject(JSON_TESTDATA, o);
126126 // ID ausgeben
127127 WriteLn(o.id);
128128 // Objekt-Name ausgeben
129129 WriteLn(o.obj.name);
130130 // alle Namen der Objekte ausgeben
131131 for TCollectionItem(no) in o.coll do
132132 Writeln(no.name);
133133 // alle Strings ausgeben
134134 for s in o.strings do
135135 WriteLn(s);
136136
137137 // aufräumen
138138 finally
139139 o.Destroy;
140140 DeStreamer.Destroy;
141141 end;
142142end;
143143```
144144
145145## JSON speichern
146146
147147Um ein Objekt in einen JSON-Text zu überführen, wird die Klasse [[TJSONStreamer]] verwendet. Hier wird die Methode `Function ObjectToJSONString(AObject : TObject) : TJSONStringType;` verwendet.
148148
149149In 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
150150
151151``` pascal
152152procedure StreamTest;
153153var
154154 Streamer: TJSONStreamer;
155155 o: TBaseObject;
156156 JSONString: String;
157157begin
158158 WriteLn('Stream test');
159159 WriteLn('======================================');
160160
161161 Streamer := TJSONStreamer.Create(nil);
162162 o := TBaseObject.Create;
163163 try
164164 // Daten festlegen
165165 o.id := 123;
166166 o.obj.name := 'Hallo Welt!';
167167 TNameObject(o.coll.Add).name := 'Objekt 1';
168168 TNameObject(o.coll.Add).name := 'Objekt 2';
169169 o.strings.Add('Hallo 1');
170170 o.strings.Add('Hallo 2');
171171
172172 Streamer.Options := Streamer.Options + [jsoTStringsAsArray]; // Strings als JSON-Array ausgeben
173173 // nach JSON überführen und ausgeben
174174 JSONString := Streamer.ObjectToJSONString(o);
175175 WriteLn(JSONString);
176176
177177 // aufräumen
178178 finally
179179 o.Destroy;
180180 Streamer.Destroy;
181181 end;
182182end;
183183```
184184
185185## Ausblick
186186
187187Mit 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.
188188
189189Über die Eigenschaft Options der Klasse TJSONStreamer kann gesteuert werden, wie die Ausgabe die eigenen Datenstrukturen in JSON abgebildet werden.
190190
191191## Siehe auch
192192
193193- [[JSON]]
194194- [[fcl-json]]
195195- [[Streaming components/de]]
196196
197197## Einzelnachweise
198198
199-1. <div id="ref1">
200-
201- <http://lists.freepascal.org/fpc-pascal/2013-January/036254.html>
202-
203- </div>
199+1. <http://lists.freepascal.org/fpc-pascal/2013-January/036254.html>
204200
2052012. \<div id="ref2\>http://lists.lazarus.freepascal.org/pipermail/lazarus/2011-January/058878.html
206- </div>
207202
208203---
209204*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