今回はレコードデータをJSON形式で読み書きするというテーマです。
こちらのサイトを参考にさせてもらいました。
・TJsonSerializerの使い方。
⇒ https://lyna.hateblo.jp/entry/20170331/1490975195
・TJsonSerializerの実用例
⇒ https://lyna.hateblo.jp/entry/20170402/1491141694
JSON形式というのはこんな感じのテキストデータです。
{“ID1″:”ID1Value”,”ID2″:”ID2Value”,”ID3″:”ID3Value”}
文字列が複数行にわたる場合は改行文字は\r\nに変換されます。
単純に何かを処理するだけのアプリであれば別ですが、
通常、アプリはアプリ内で作成したデータをファイルに読み書きする機能が
実装されているものです。
ということで、そういった事について。
とりあえずコードを。まずは書き込みから。
#usesに REST.Json,System.JSON.Serializers を追加 #Rtはレコード型 function SaveToJson(Rt:TRecordXXXX):string; var serializer: TJsonSerializer; begin serializer := TJsonSerializer.Create; try Result:=serializer.Serialize(Rt); finally FreeAndNil(serializer); end; end;
こんな感じでレコードをJSONデータにシリアライズできます。
次に読込。
#usesに REST.Json,System.JSON.Serializers を追加 #Rtはレコード型 function LoadFromJson(Val:string):TRecordXXXX; var serializer: TJsonSerializer; begin serializer := TJsonSerializer.Create; try serializer.Populate(Val,Result); finally FreeAndNil(serializer); end; end;
こんな感じでJSONデータからレコード型に代入できます。
とりあえず、これで面倒な処理は任せる事が出来ます。
ライブラリって便利ですね。
で、
実際のサンプルとしてはこんな感じ。
type TRecordA=Record A:string; B:string; C:string; end; TRecordB=Record A:string; B:string; D:string; end; procedure TForm1.Button1Click(Sender: TObject); var RtA:TRecordA; RtB:TRecordB; s:string; function SaveToJsonA(Rt:TRecordA):string; var serializer: TJsonSerializer; begin serializer := TJsonSerializer.Create; try Result:=serializer.Serialize(Rt); finally FreeAndNil(serializer); end; end; function SaveToJsonB(Rt:TRecordB):string; var serializer: TJsonSerializer; begin serializer := TJsonSerializer.Create; try Result:=serializer.Serialize(Rt); finally FreeAndNil(serializer); end; end; begin with RtA do begin A:='A'; B:='B'; C:='C'; end; with RtB do begin A:='A'; B:='B'; D:='D'; end; s:=SaveToJsonA(RtA)+#13#10 +SaveToJsonB(RtB); Memo1.Lines.Text:=s; end; procedure TForm1.Button2Click(Sender: TObject); var RtA:TRecordA; RtB:TRecordB; s:string; function LoadFromJsonA(Val:string):TRecordA; var serializer: TJsonSerializer; begin serializer := TJsonSerializer.Create; try serializer.Populate(Val,Result); finally FreeAndNil(serializer); end; end; function LoadFromJsonB(Val:string):TRecordB; var serializer: TJsonSerializer; begin serializer := TJsonSerializer.Create; try serializer.Populate(Val,Result); finally FreeAndNil(serializer); end; end; begin with RtA do begin A:='-'; B:='-'; C:='-'; end; with RtB do begin A:='-'; B:='-'; D:='-'; end; s:=Memo1.Lines[1]; RtA:=LoadFromJsonA(s); s:=Memo1.Lines[0]; RtB:=LoadFromJsonB(s); end;
Button1,Button2,Memo1を配置して、
イベントハンドラを上記ソースのように設定します。
で、何をやっているかというと、
ボタン1をクリックすると2つの異なるレコード型変数に値をセットします。
そしてそのレコード型変数の内容を先ほどの関数を使ってシリアライズします。
で、Memo1にそれぞれのデータを表示させます。
この時、2行のテキストデータが表示されますが、
上が変数RtA(TRecordA型レコード)の内容をJSON形式で表したもの。
下が変数RtB(TRecordB型レコード)の内容をJSON形式で表したものになります。
こんな感じ。
{“A”:”A”,”B”:”B”,”C”:”C”}
{“A”:”A”,”B”:”B”,”D”:”D”}
次に、ボタン2をクリックすると変数RtA、RtBの内容を初期化して、
Memo1に表示されているJSON形式のデータを取得し、
それをもとにレコード型変数に代入しています。
その際、RtAとRtBのデータを逆に読み込んでいます。つまり、
RtA用のJSONデータをRtB変数に読み込ませ、
RtB用のJSONデータをRtA変数に読み込ませています。
ボタン1をクリックした後、ボタン2をクリックしたらどうなるか?
異なるレコード型のJSONデータを読み込んだらどうなるかという実験です。
実行結果はこうなりました。
RtA.A => A
RtA.B => B
RtA.C =>
RtB.A => A
RtB.B => B
RtB.D =>
ボタン2をクリックした際に、それぞれの変数は初期化しました。
その際に、各フィールド(レコード内の変数A,B,CまたはD)には
‐(半角マイナス)を設定したのですが、実行結果としては
JSONデータにないフィールドは空文字になりました。
この点から、JSONデータ内で設定されていないフィールド内容について、
事前に初期値を設定しておくという方法は使えないという事になります。
この点はちょいと面倒です。
設定でどうにかなるのかもしれませんが、
この点に関しては現時点では情報を把握していません。
当然、レコードフィールドにない(定義されていない)データは切り捨てられます。
実行環境はDelphi10.3 RIO CE。Windows7です。
アプリ内で使用するデータ形式(フィールド内容)が変更されることは良くあることです。
バージョンが変わるとデータが読めなくなるというのは問題ですから、
こういった問題はライブラリに任せる事が出来るので安心です。
これで安心してフィールドの追加などが出来るという事が分かりました。
ちなみに、レコードの中にレコードを入れるとどうなるかというと、
こうなります。
ソースはこれ。
type TNYRecordTestA=record ID :integer; Name:string; end; TNYRecordTestB=record ID :integer; Name:string; RecordNest:TNYRecordTestA; end; procedure TForm1.Button33Click(Sender: TObject); var serializer: TJsonSerializer; s:string; Rt:TNYRecordTestB; begin serializer := TJsonSerializer.Create; with Rt do begin ID:=1; Name:='Test'; with RecordNest do begin ID:=2; Name:='Nest'; end; end; try s:=serializer.Serialize(Rt); finally serializer.Free; end; Memo2.Lines.Text:=s; end;
これを実行すると、変数s の内容はこんな感じになります。
{“ID”:1,”Name”:”Test”,”RecordNest”:{“ID”:2,”Name”:”Nest”}}
上手く出来てますな。
この機能の使いどころとしては、通常のアプリ内で作成するデータをリスト化して
JSONデータ(テキストデータ)として保存するという方法もあります。
そのほかには、フォーム位置をレコード型で定義しておいて、
フォーム位置の保存・復帰に使用するという方法もあります。
また、設定データをレコード型で定義して、
それを保存・復帰するという方法もあります。
とりあえず基礎知識としてはこんなところでしょうか。
※実際にレコードリストとして運用するには、シリアライズ等の部分は、
呼び出し側でシリアライザー(serializer:=TJsonSerializer.Create;の部分)
を生成しておいてから、引数として関数に渡した方がコストとしては
良いのではないかと思います。
次の記事はフォームの位置・サイズをJSON形式で読み書きするです。