Streaming JSON/pl

From Lazarus wiki
Revision as of 09:49, 6 June 2020 by Slawek (talk | contribs) (→‎Ogólne wymagania: tłumaczenie na j. polski)
Jump to navigationJump to search

Deutsch (de) English (en) polski (pl) русский (ru) 中文(中国大陆)‎ (zh_CN)

JSON (JavaScript Object Notation) to tekstowy, znormalizowany format danych. Jak sama nazwa wskazuje, dokumenty JSON są poprawnym kodem JavaScript i mogą być bezpośrednio konwertowane na obiekty JavaScript. JSON może jednak służyć do wymiany danych niezależnie od używanego języka programowania.

W tym samouczku wyjaśniono, jak ładować dane JSON do programu Free Pascal i jak je w nim przetwarzać. Wyjaśnia także, jak konwertować dane z programu do JSON (np. Aby wysłać je do przeglądarki internetowej).

Ogólne wymagania

Ładowanie i przechowywanie (przesyłanie strumieniowe) obiektów odbywa się za pomocą modułu fpjsonrtti. Ale ma to sens, gdy użyty jest również moduł Classes (szczegóły poniżej).

Instrukcja użycia powinna zatem zawierać przynajmniej te dwa moduły:

uses Classes, fpjsonrtti;

Obecnie (maj 2014) istnieją pewne różnice między systemem przesyłania strumieniowego Free Pascala a JSON:

  • JSON to format danych, w którym rozróżniana jest wielkość liter. Wynika z tego, że właściwości obiektów Free Pascal muszą być zapisane w tym samym miejscu, co właściwości JSON.
  • Za pomocą DefineProperties nie można zdefiniować żadnych właściwości. Nie można zapisać odwołań do metod (procedur obsługi zdarzeń).2
  • TCollection i TStrings mogą być stosowane jako zamienniki tablic.

Programy demonstracyjne wraz z kodem źródłowym kompilatora Free Pascal znajdują się w katalogu packages/fcl-json/examples.

Taka jak poniżej struktura JSON, jest używana w dalszych przykładach:

{
  "id"     : 123,                                                // liczba całkowita (integer)
  "obj"    : { "name": "Witaj Świecie!" },                       // jakiś obiekt
  "coll"   : [ { "name": "Obiekt 1" }, { "name": "Obiekt 2" } ], // dwa obiekty w TCollection
  "strings": [ "Witaj 1", "Witaj 2" ]                            // ciągi znaków
}

Można ją zdefiniować w programie Free Pascal jako wartość stałą w następujący sposób:

const JSON_TESTDATA =
'{'+LineEnding+
'  "id": 123,'+LineEnding+
'  "obj": { "name": "Witaj Świecie!" },'+LineEnding+
'  "coll": [ { "name": "Obiekt 1" }, { "name": "Obiekt 2" } ],'+LineEnding+
'  "strings": [ "Witaj 1", "Witaj 2" ]'+LineEnding+
'}';

Data Structure

The base class for the data is TPersistent from the Classes unit, runtime type information (RTTI) is created for it and all subclasses. These are essential for streaming. Since fpjsonrtti does not integrate into the streaming system, any other class translated with the compiler switch {$M+} can also be used.

All properties to be read must be declared as a property in the published section of the class. As a rule, you can use read and write to refer directly to a data field (the variable). If you want, you can of course use getter and setter methods.

The following class definition results from the JSON structure:

type
  TNameObject = class(TCollectionItem) // class for the 'obj' property and TCollection 
  private
    fName: String;
  published
    property name: String read fName write fName;
  end;  

  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;

The TNameObject class was derived from TCollectionItem. This means that it can be used both for the obj property and in the collection. If this is not desired, then two different classes must be defined here.

The TCollection and the string list must be created in the constructor of the TBaseObject class and released in the destructor.

constructor TBaseObject.Create;
begin
  // Create Collection and StringList
  fColl    := TCollection.Create(TNameObject);
  fStrings := TStringList.Create;
  fObj     := TNameObject.Create(nil);
end;

destructor TBaseObject.Destroy;
begin
  // Release Collection and StringList
  fColl.Free;
  fStrings.Free;
  fObj.Free;
  inherited Destroy;
end;

If you do not want any more functionality in the data classes, their definition is now complete.

Load JSON

With the method Procedure JSONToObject(Const JSON : TJSONStringType; AObject : TObject); in the TJSONDeStreamer class you can assign JSON data directly to an existing 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 object o and then outputs the current values ​​of the properties to the console.

procedure DeStreamTest;
var
  DeStreamer: TJSONDeStreamer;
  o: TBaseObject;
  no: TNameObject;
  s: String;
begin
  WriteLn('DeStream test');
  WriteLn('======================================');

  // 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);

  // Cleanup
  finally
    o.Destroy;
    DeStreamer.Destroy;
  end;
end;

Saving JSON

The class TJSONStreamer is used to convert an object into JSON text. Here the method Function ObjectToJSONString(AObject : TObject) : TJSONStringType; is used.

In the following procedure, an object is created, filled with the test data, and then converted to JSON. The JSON text is output on the console. The order in which the properties are output cannot be specified.

procedure StreamTest;
var
  Streamer: TJSONStreamer;
  o: TBaseObject;
  JSONString: String;
begin
  WriteLn('Stream test');
  WriteLn('======================================');

  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');

    Streamer.Options := Streamer.Options + [jsoTStringsAsArray]; // Save strings as JSON array
    // convert to JSON and output to console
    JSONString := Streamer.ObjectToJSONString(o);
    WriteLn(JSONString);

  // Cleanup
  finally
    o.Destroy;
    Streamer.Destroy;
  end;
end;

Conclusion

With the knowledge presented, simple and complex JSON data structures can be loaded into Free Pascal programs. Should any pre- or post-processing of the JSON data be necessary, the text data can be first loaded from the jsonparser unit into a JSON data structure using the TJSONParser class and then manipulated as desired with the fpJSON unit.

The Options property of the TJSONStreamer class can be used to control how the output maps its own data structures in JSON.

See Also

Notes & References