はじめに
Delphi の XMLデータバインディング凄い便利!嬉しい! と思ったのですが、ちょっと分からない所があったので、わかった部分を紹介しつつ、疑問点を書いてみたいと思います。開発環境は Delphi XE3 です。
基本的に、エンバカデロの解説ページを端折って紹介しているので、詳しい情報はそちらを見て頂いた方が良いかと思います。
XML データ バインディング ウィザードを使用する
XML_データバインドウィザードが生成するコードの使い方
使い方
例として、学校の試験成績を記録するXMLファイルを考えてみます。
<TestResult>
<Student>
<Id>01234</Id>
<Name>田中 太郎</Name>
<Score>
<Cource>English</Cource>
<Date>2014/05/30</Date>
<Value>80</Value>
</Score>
<Score>
<Cource>Mathematics</Cource>
<Date>2014/05/30</Date>
<Value>80</Value>
</Score>
</Student>
</TestResult>
上記をXMLファイルとして保存しておきます(エンコードは UTF-8 としておきました)。
XMLデータバインディングウィザード
手始めに、新規のフォームアプリケーションを作成します。次に、ファイル→新規作成→その他 を選択し、ダイアログからXMLデータバインディングを選択します。
ファイル内のタグの整合性に問題が無ければ、タグ要素を解析し、以下のような画面が表示されます。この画面で、タグ要素の取り込み方法を設定できます。
(下画面は、左側のツリーリストで、TestResultTypeをクリックした状態です。)
取り込んだXMLファイルには、Student要素が1つしかなかった為、Student要素の繰り返しのチェックがオフになっています。Score要素は予め繰り返し要素となっています。
Student要素は、繰り返し有り、と設定を変更しておきます。
テキストデータが入っているタグは、値をどの型で読み取るかを選択できます。
元ファイルに数字で入っていれば、自動でInteger型としてくれます。独自の型に変換したい場合は、一旦Stringとしておき、コード生成後に修正をする事になると思います。
要素の設定を確認後、次へをクリックすると、確認画面となります。
完了をクリックすると、コードが自動生成されます!
(コード量が多いので割愛)
なお、自動生成されたコードのユニット名は、最初に取込んだXMLファイル名となります。適宜変更して保存してください。
使用してみる
![テスト用フォーム](https://qiita-image-store.s3.amazonaws.com/0/33684/8e562291-a7ec-8227-58b0-8fd59563e20f.png)
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Sample, XMLIntf;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Button2: TButton;
OpenDialog1: TOpenDialog;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
WriteXml:IXMLTestResultType;
begin
WriteXml := NewTestResult;
WriteXml.Add;
WriteXml.Student[0].Id := 1000;
WriteXml.Student[0].Name := '佐藤 二郎';
WriteXml.Student[0].Score.Add ;
WriteXml.Student[0].Score[0].Date := Date;
WriteXml.Student[0].Score[0].Cource := 'English';
WriteXml.Student[0].Score[0].Value := 100;
WriteXml.Student[0].Score.Add ;
WriteXml.Student[0].Score[1].Date := Date;
WriteXml.Student[0].Score[1].Cource := 'Science';
WriteXml.Student[0].Score[1].Value := 40;
Memo1.Lines.Assign(WriteXml.OwnerDocument.XML);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
i,j:integer;
ReadXml:IXMLTestResultType;
Student: IXMLStudentType;
Score: IXMLScoreType;
begin
if OpenDialog1.Execute then begin
Memo1.Clear;
ReadXml := LoadTestResult(OpenDialog1.Files[0]);
for i:= 0 to ReadXml.Count-1 do begin
Student := ReadXml.Student[i];
Memo1.Lines.Add('Id:'+IntToStr(Student.Id));
Memo1.Lines.Add('Name:'+Student.Name);
for j := 0 to Student.Score.Count-1 do begin
Score := Student.Score[j];
Memo1.Lines.Add(' Score('+Score.Cource+') :'+IntToStr(Score.Value) );
end;
end;
end;
end;
end.
実行結果
![オブジェクト作成ボタンを押した時ー](https://qiita-image-store.s3.amazonaws.com/0/33684/2080a6c2-5fe7-b42b-75b3-580e3171241f.png) Button1Clickイベントで作成したオブジェクトがXMLテキストに変換出来ました。嬉しい!
(テストとして、最初にテンプレートとして使用したXMLファイルを読み込みました)
ファイルも無事パース出来ました!嬉しい!
疑問点
Qiita用に作り直している内に起きなくなったエラーも幾つかあり・・そこはまだ切り分けが出来ていません。for~inが使用できない?
ファイルを読み込んでいる箇所ですが、本当はfor Student in ReadXml do
と書きかったんですが、GetEnumerater が見つかりませんというコンパイルエラーが。
なにかパーサー側に修正が必要なのかも?
XMLタグの整形はできない?
オブジェクトからXMLテキストを書き出す場面ですが、WriteXml.OwnerDocument.Options := WriteXml.OwnerDocument.Options +[doNodeAutoIndent];
WriteXml.OwnerDocument.NodeIndentStr := ' ';
と設定しても、WriteXml.OwnerDocument.XML から取得できるXMLテキストには変化が無く。Delphi7 の TXMLDocumentでは出来ていたような気がしたのですが・・。
(テキストエディタで見たときに見辛いだけなので、大きな問題ではないと思いつつ)