Streaming JSON/ru

From Free Pascal wiki
Jump to navigationJump to search

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

Light bulb  Примечание: Эта статья является перевод статьи с английского Streaming_JSON от 2014-10-02, которая была переведена с помощью Google Translate с немецкого (оригинал). Понятно, что результат перевода может быть ужасным, вполне может требоваться ручная корректировка. Убедительная просьба не использовать автоматический перевод без окончательной обработки

JSON(JavaScript Object Notation) является текстовым, стандартизированным форматом данных. Как следует из названия, JSON документы являются правильным кодом JavaScript, где они могут быть непосредственно преобразованы в объекты JavaScript. Но сам по себе JSON может быть использован независимо от используемого языка программирования для обмена данными.

В этом руководстве объясняется, как загрузить данные в формате JSON в программе Free Pascal для обработки. Оно также объясняет, как преобразовать данные FPC в формате JSON (например, чтобы отправить их на веб-сервер).

Общие положения и условия

Loading and storing (streaming) FPC object data is done with the fpjsonrtti unit. Furthermore, the Classes unit is useful (see below for details). Загрузка и хранение (маршалинг) FPC данных объекта осуществляется с помощью юнита fpjsonrttiN. Кроме того, может пригоlиться Class в юните (см ниже).

В связи с этим оператор USES должен содержать, по крайней мере, эти два юнита:

USES Classes, fpjsonrtti;

В настоящее время (май 2014 г.) есть некоторые отличия от потоковой системы Free Pascal с ??_предположительно_ JavaScript ??:

  • Данные в формате JSON чувствительны к регистру. Таким образом, свойства объектов Free Pascal, как свойства JSON должны быть написаны с правильным регистром.
  • Нет свойств, которые могут быть определены как DefineProperties. Нельзя сохранить ссылки на методы (обработчики событий).2
  • TCollection и TStrings может быть использован в качестве замены массивов.

Демо-версия программы предоставляется с исходным кодом Free Pascal Compiler (в папке /packages/fcl-json/examples).

В качестве примера, мы приведём пример со следующими данными JSON:

{
  "id"     : 123,                                                // Integer
  "объект"    : { "имя": "Привет, мир!" },                          // Object
  "колл"   : [ { "имя": "Объект 1" }, { "имя": "Объект 2" } ], // два объекта  TCollection 
  "строки": [ "привет 1", "привет 2" ]                            // список строк
}

Это может быть выполнено в Free Pascal с использованием констант следующим образом:

const JSON_TESTDATA =
'{'+LineEnding+
'  "id": 123,'+LineEnding+
'  "объект": { "имя": "Hello world!" },'+LineEnding+
'  "колл": [ { "имя": "Объект 1" }, { "имя": "Объект 2" } ],'+LineEnding+
'  "строки": [ "привет 1", "привет 2" ]'+LineEnding+
'}';

Структура данных

В качестве базового класса для обслуживания данных существует класс TPersistent из юнита Classes, так как для них и всех подклассов должен быть создан Laufzeit-Typinformationen (RTTI). Это совершенно необходимо для маршаллинга. Поскольку fpjsonrtti не интегрирован в систему маршаллинга, любого другого класса, должна быть указана опция компилятора {$M+}, для использования.

Все объекты должны быть доступны как property для чтения в разделе класса published. В общем случае (переменная) должна быть доступна для чтения и записи непосредственно в поле данных. Если вы хотите, конечно, могут быть использованы методы getter и setter.

Для структуры JSON результаты определении класса представлены ниже.

TYPE
  TNameObject = CLASS(TCollectionItem) // класс для свойства 'obj' и TCollection 
  PRIVATE
    fName: String;
  PUBLISHED
    property name: String read fName write fName;
  END;  

  TBaseObject = CLASS(TPersistent)  // класс для структуры JSON
  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); 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 o object and then writes the current values ​​of the properties 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
    // Load JSON data in the object o
    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);
    // output all strings
    for s in o.strings do
      WriteLn(s);

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

Saving JSON

To convert an object into a JSON text, the class TJSONStreamer is used. 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 order in which the properties are saved cannot be influenced by the programmer.

Finally, the JSON text is printed to the console.

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 := '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
    // JSON convert and output
    JSONString := Streamer.ObjectToJSONString(o);
    WriteLn(JSONString);

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

Conclusion

With the presented knowledge, simple and complex JSON data structures can be loaded in your Free Pascal programs. Should any pre- or postprocessing of he JSON data be necessary, the text data can be initially loaded into a JSON data structure (with the classTJSONParser from the Unit jsonparser) and then manipulated with the Unit fpJSON.

The TJSONStreamer's Options property can be used to control the representation of your own data structures in JSON.

See Also

Notes & References