Difference between revisions of "XML Tutorial/ja"
Miyatakejiro (talk | contribs) |
m (Really fixed syntax highlighting :-l) |
||
(34 intermediate revisions by 6 users not shown) | |||
Line 1: | Line 1: | ||
{{XML Tutorial}} | {{XML Tutorial}} | ||
+ | {{Japanese Menu}} | ||
− | |||
== 導入 == | == 導入 == | ||
− | XML(=The Extensible Markup | + | XML(=The Extensible Markup Language)は、[http://www.w3.org/ W3C] が推奨する、異なるシステム間で情報を交換するための言語です。情報はテキスト形式で保存しており、XHTMLのようなWebサービスでもよく使われる現代的なデータ交換方法は、XMLを基礎としています。 |
− | |||
− | |||
− | |||
− | |||
− | + | Free Pascal Compiler の Free Component Library(FCL)には、XMLをサポートする "XMLRead"、"XMLWrite"、"DOM" といったユニットがあります。 FCL はすでに Lazarus のデフォルトの検索パスにはいっていますので、これらのユニットを uses に追加するだけで XML に関する機能を実装できるようになります。 | |
− | + | FCL は現時点(October / 2005 訳注たぶん2008/12時点も同じ)で文書化されていませんので、このチュートリアルでは、これらのユニットを使った XML へのアクセス方法を紹介します。 | |
− | + | XML の Document Object Model(DOM) は、異なる言語やシステム間で XML を利用するために同じようなインターフェースを提供する、標準化されたオブジェクトの集合です。 | |
− | |||
− | + | 標準化は、メソッド、プロパティ、オブジェクトの他へのインターフェース部分についてのみ行われており、色々な言語のために、実装方法は自由になっています。 FCL では現在、完全に [http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/|XML DOM 1.0] をサポートしています. | |
− | |||
− | + | (訳注注:日本語版 wiki で "XML" の項目が "ネットワーク" に書かれていたときの訳注をそのまま乗せています。訳注: XML , DOM を「完全に」パースする、という実装は、かなり大変なことです。また、異機種間での利用を目的に作られていることに注意しましょう。 Lazarus は、クロスコンパイル環境であり、これを標準で持っている事は、とても便利に快適にプログラムが出来ると思われます。日本語がどこまで検証されているのか、というところは、訳からはちょっと分かりませんが...。) | |
== 利用例 == | == 利用例 == | ||
− | + | 以下に、 XML データの利用例を記述しています。徐々に複雑な内容を説明していきます。 | |
− | |||
=== textノードを読み込む === | === textノードを読み込む === | ||
Delphi プログラマーの皆さん: | Delphi プログラマーの皆さん: | ||
− | + | TXMLDocument を用いるときには注意して下さい。ノード内のテキストは個々の TEXT ノードと扱われるため、個々のノードとしてノードのテキスト値を取得する必要があります。 | |
− | |||
− | + | 別の方法として、 '''TextContent''' プロパティを用いて、与えられた一つのノード以下の全てのテキストノードを一つにまとまって取得することもできます。 | |
− | |||
− | + | '''ReadXMLFile''' プロシージャは、いつも新しい '''TXMLDocument''' を生成するため、あらかじめ '''TXMLDocument''' を生成する必要はありません。 しかし、不要になったときには、 '''Free''' をコールして document を確実に破棄して下さい。 | |
− | |||
− | + | 例えば、以下のxmlファイルについてアクセスする場合、 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | 注:全てのxmlサンプル類、サンプルコードは、UTF-8で保存する必要があるようです。また、以下の例では文頭に"半角スペース"を記入して、整形済みテキストとして表示しており、ほとんどのコードはそのまま動きますが、<?xml><sample>は先頭の半角スペースを削除しないとうまく動きませんでした。 | ||
+ | <XML> <?xml version="1.0"?> | ||
+ | <sample name="s1" >sampleXML | ||
+ | <group name="g1" >G1 | ||
+ | <user>123</user> | ||
+ | <item val="int" >999</item> | ||
+ | <item val="str" >abc</item> | ||
+ | </group> | ||
+ | <group name="g2" >G2 | ||
+ | <item val="str" >def</item> | ||
+ | </group> | ||
+ | <gr name="gr1" >GR1 | ||
+ | <item val="str" >def</item> | ||
+ | </gr> | ||
+ | </sample></XML> | ||
以下のコードで、テキストノードから値を取得する場合の、正しい方法と間違った方法をお見せします。 | 以下のコードで、テキストノードから値を取得する場合の、正しい方法と間違った方法をお見せします。 | ||
− | + | 注: 既存のコードがうまく動かなかったので(おそらく私のコンソールアプリの理解不足です)、全てのコードをGUIコードとして作り直しました。 (動作確認は、windowsXPSP2 上の lazarus0.9.26 で行いました。) | |
− | |||
はじめの設定 | はじめの設定 | ||
− | |||
− | |||
− | + | 1.usesに XMLRead, Domを追加 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | // xml fileを読み込みます。 | + | 2.form1にmemo1,button1,OpenDialogを追加 |
− | + | <syntaxhighlight lang=pascal> procedure TForm1.Button1Click(Sender: TObject); | |
− | + | var | |
− | + | tmpNode: TDOMNode; | |
− | + | Doc: TXMLDocument; | |
+ | begin | ||
+ | // Doc := TXMLDocument.Create;//ここで生成する必要はありません。 | ||
+ | Memo1.Lines.Clear; | ||
+ | |||
+ | // xml fileを読み込みます。 | ||
+ | Opendialog1.Execute; | ||
+ | ReadXMLFile(Doc,Opendialog1.FileName); | ||
+ | // "password" ノードを取得します。 | ||
+ | tmpNode := Doc.DocumentElement.FindNode('group'); | ||
+ | |||
+ | // 選択したノードの値の書き出し | ||
+ | Memo1.Lines.Add(tmpNode.NodeValue);// 空白値""しか取得できません。 | ||
+ | // (ノードのテキスト値は、実際は個々の小ノードになっています。) | ||
+ | Memo1.Lines.Add(tmpNode.FirstChild.NodeValue);// "abc" が取得できます。 | ||
+ | // 他の方法 | ||
+ | Memo1.Lines.Add(tmpNode.TextContent); | ||
+ | // 最後に、documentを破棄します。 | ||
+ | Doc.Free; | ||
+ | end;</syntaxhighlight> | ||
+ | 出力は以下のようになります。 | ||
+ | <pre> | ||
+ | G1 | ||
+ | G1 123999abc</pre> | ||
− | + | === ノードの名前を出力する === | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | ノードに順番にアクセスする場合、 '''FirstChild''' と '''NextSibling''' プロパティ(前方から繰り返し), または '''LastChild''' と '''PreviousSibling''' (後方から繰り返し)を用いればよいでしょう。 | |
− | |||
− | |||
− | |||
ランダムアクセスには、'''ChildNodes''' または '''GetElementsByTagName''' メソッドが使えますが、これらは 最終的に破棄する必要のある TDOMNodeList オブジェクトを生成します。 | ランダムアクセスには、'''ChildNodes''' または '''GetElementsByTagName''' メソッドが使えますが、これらは 最終的に破棄する必要のある TDOMNodeList オブジェクトを生成します。 | ||
− | これは、他の DOM | + | これは、他の DOM 実装(例えばMXSML) とは異なりますが、この理由は、FCL での実装がobject-basedであり、interface-based では無いためです。 |
− | + | 以下に、 form 上の TMemo にノードの名前を出力するサンプルを示します。 | |
− | + | (訳注:元々の例は、上側の例と異なっているため(ファイル名がtestoなど)、記述を上記例に統一しました。) | |
− | + | 以下のxmlファイルにアクセスする場合、 | |
− | <xml> | + | <syntaxhighlight lang="xml"> <?xml version="1.0"?> |
− | + | <sample name="s1" >sampleXML | |
− | < | + | <group name="g1" >G1 |
− | + | <user>123</user> | |
− | + | <item val="int" >999</item> | |
− | + | <item val="str" >abc</item> | |
− | + | </group> | |
− | + | <group name="g2" >G2 | |
− | </ | + | <item val="str" >def</item> |
− | + | </group> | |
− | < | + | <gr name="gr1" >GR1 |
− | + | <item val="str" >def</item> | |
− | + | </gr> | |
− | < | + | </sample></syntaxhighlight> |
− | |||
− | |||
− | </ | ||
− | </ | ||
− | |||
− | |||
− | |||
はじめの設定 | はじめの設定 | ||
− | |||
− | |||
− | + | 1.usesに XMLRead, Dom を追加 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | 2.form1にmemo1,button1,OpenDialogを追加 | |
− | |||
− | + | 1a.'''FirstChild''' と '''NextSibling''' プロパティを使用(順番にアクセス) | |
− | Child : | + | (訳注:英語版のコードは上記ノートと利用プロパティ、メソッドに整合性が無いため修正しました。) |
− | + | <syntaxhighlight lang=pascal> procedure TForm1.Button1Click(Sender: TObject); | |
− | + | var | |
− | + | Child: TDOMNode; | |
− | + | Doc: TXMLDocument; | |
− | + | cnt: Integer; | |
− | + | begin | |
− | + | Memo1.Lines.Clear; | |
− | + | Opendialog1.Execute; | |
− | + | ReadXMLFile(Doc,Opendialog1.FileName); | |
− | + | ||
− | + | // FirstChild プロパティの使用 | |
− | + | Child := Doc.DocumentElement.FirstChild; | |
− | + | while Assigned(Child) do | |
− | + | begin | |
− | end; | + | cnt:=cnt+1; |
− | </ | + | Memo1.Lines.Add(inttostr(cnt) |
+ | + ' ' + Child.NodeName + ' ' + Child.NodeValue); | ||
+ | // NextSibling プロパティの使用 | ||
+ | Child := Child.NextSibling; | ||
+ | end; | ||
+ | Doc.Free; | ||
+ | end;</syntaxhighlight> | ||
+ | 出力は以下のようになります。 | ||
− | + | <pre>1 #text sampleXML | |
+ | 2 group | ||
+ | 3 group | ||
+ | 4 gr </pre> | ||
− | + | 1b.'''ChildNodes''' と '''getElementsByTagName''' メソッドを使用(ランダムアクセス) | |
− | + | 注)DOMNodeListのノード数はCountとなる。 | |
− | |||
− | |||
− | |||
− | === | + | <syntaxhighlight lang=pascal> procedure TForm1.Button1Click(Sender: TObject); |
− | + | var | |
− | + | tmpNodes: TDOMNodeList; | |
+ | Doc: TXMLDocument; | ||
+ | i: Integer; | ||
+ | begin | ||
+ | Memo1.Lines.Clear; | ||
+ | Opendialog1.Execute; | ||
+ | ReadXMLFile(Doc,Opendialog1.FileName); | ||
+ | |||
+ | // ChildNodes メソッドの使用 | ||
+ | tmpNodes:=Doc.DocumentElement.ChildNodes; | ||
+ | Memo1.Lines.Add('1.ChildNodes count=' + inttostr(tmpNodes.Count)); | ||
+ | if(tmpNodes.Count <> 0) then | ||
+ | for i:=0 to tmpNodes.Count-1 do begin | ||
+ | Memo1.Lines.Add(inttostr(i) | ||
+ | + ' ' + tmpNodes[i].NodeName | ||
+ | + ' ' + tmpNodes[i].NodeValue); | ||
+ | end; | ||
+ | tmpNodes.Free; | ||
+ | |||
+ | // getElementsByTagName メソッドの使用 | ||
+ | tmpNodes:= Doc.GetElementsByTagName('group'); | ||
+ | Memo1.Lines.Add('2.getEBTN count=' + inttostr(tmpNodes.Count)); | ||
+ | if(tmpNodes.Count <> 0) then | ||
+ | for i:=0 to tmpNodes.Count-1 do begin | ||
+ | Memo1.Lines.Add(inttostr(i) | ||
+ | + ' ' + tmpNodes[i].NodeName | ||
+ | + ' ' + tmpNodes[i].NodeValue); | ||
+ | end; | ||
+ | tmpNodes.Free; | ||
+ | end;</syntaxhighlight> | ||
− | + | 出力は以下のようになります。 | |
− | < | + | <pre> 1.ChildNodes count=4 |
− | + | 0 #text sampleXML | |
− | + | 1 group | |
− | + | 2 group | |
+ | 3 gr | ||
+ | 2.getEBTN count=2 | ||
+ | 0 group | ||
+ | 1 group </pre> | ||
− | + | 2.'''ChildNodes''' メソッドを用いた順次アクセスのコードは以下のようになります。 | |
− | + | (注:日本語版の"ネットワーク"項目のXMLが記述されていたコードがあったので、とりあえず入れておきます。) | |
− | + | <syntaxhighlight lang=pascal> procedure TForm1.Button1Click(Sender: TObject); | |
+ | var | ||
+ | Doc: TXMLDocument; | ||
+ | i, j: Integer; | ||
+ | begin | ||
+ | Memo1.Lines.Clear; | ||
+ | Opendialog1.Execute; | ||
+ | ReadXMLFile(Doc,Opendialog1.FileName); | ||
+ | |||
+ | // ChildNodes メソッドの使用 | ||
+ | with Doc.DocumentElement.ChildNodes do | ||
begin | begin | ||
− | + | for i := 0 to (Count - 1) do | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
begin | begin | ||
− | + | Memo1.Lines.Add('i' + inttostr(i) | |
− | + | + Item[i].NodeName + ' ' + Item[i].NodeValue); | |
+ | for j := 0 to (Item[i].ChildNodes.Count - 1) do | ||
+ | begin | ||
+ | Memo1.Lines.Add(' j' + inttostr(j) | ||
+ | + ' ' + Item[i].ChildNodes.Item[j].NodeName | ||
+ | + ' ' + Item[i].ChildNodes.Item[j].NodeValue); | ||
+ | end; | ||
end; | end; | ||
end; | end; | ||
− | + | Doc.Free; | |
− | + | end;</syntaxhighlight> | |
− | + | 出力は以下のようになります。 | |
− | + | <pre> i0#text sampleXML | |
− | + | i1group | |
− | + | j0 #text G1 | |
− | + | j1 user | |
− | + | j2 item | |
− | + | j3 item | |
− | </ | + | i2group |
+ | j0 #text G2 | ||
+ | j1 item | ||
+ | i3gr | ||
+ | j0 #text GR1 | ||
+ | j1 item </pre> | ||
+ | |||
+ | === XML を TreeView で表示する === | ||
+ | |||
+ | XMLファイルの一般的な利用として、XMLファイルの内容を TreeView の形で表示することがあります。 Lazarusの ”Common Controls” タブに TTreeView コンポーネントがあります。 | ||
+ | 以下の手続きは、既にファイルから読み込んだか、コードの中で生成するかした XML 文書を取得し、その内容をTreeViewの形で表示します。それぞれのノードがもつキャプションが、最初の属性の内容になります。 | ||
− | + | はじめの設定 | |
− | + | 1.usesに XMLRead, Dom を追加 | |
− | + | 2.form1にTTreeView1を追加 | |
− | |||
− | < | + | 3.TForm1のtypeにメソッド”procedure XML2Tree(tree: TTreeView; XMLDoc: TXMLDocument); ”を追加 |
− | procedure TForm1.XML2Tree(tree: TTreeView; XMLDoc: TXMLDocument); | + | <syntaxhighlight lang=pascal> procedure TForm1.XML2Tree(tree: TTreeView; XMLDoc: TXMLDocument); |
− | var | + | var |
iNode: TDOMNode; | iNode: TDOMNode; | ||
− | + | ||
procedure ProcessNode(Node: TDOMNode; TreeNode: TTreeNode); | procedure ProcessNode(Node: TDOMNode; TreeNode: TTreeNode); | ||
var | var | ||
Line 227: | Line 259: | ||
begin | begin | ||
if Node = nil then Exit; // Stops if reached a leaf | if Node = nil then Exit; // Stops if reached a leaf | ||
− | + | ||
// Adds a node to the tree | // Adds a node to the tree | ||
− | TreeNode := tree.Items.AddChild(TreeNode, Node.Attributes[0].NodeValue); | + | TreeNode := tree.Items.AddChild(TreeNode, |
− | + | Node.Attributes[0].NodeValue); | |
+ | |||
// Goes to the child node | // Goes to the child node | ||
− | cNode := Node. | + | cNode := Node.FirstChild; |
− | + | ||
// Processes all child nodes | // Processes all child nodes | ||
while cNode <> nil do | while cNode <> nil do | ||
begin | begin | ||
− | + | ProcessNode(cNode, TreeNode); | |
cNode := cNode.NextSibling; | cNode := cNode.NextSibling; | ||
end; | end; | ||
end; | end; | ||
− | + | ||
− | begin | + | begin |
− | + | iNode := XMLDoc.DocumentElement.FirstChild; | |
− | + | while iNode <> nil do | |
− | + | begin | |
− | + | ProcessNode(iNode, nil); // Recursive | |
− | + | iNode := iNode.NextSibling; | |
− | + | end; | |
− | end; | + | end;</syntaxhighlight> |
− | </ | ||
− | |||
+ | === XML 書類を修正する === | ||
+ | まず、TDOMDocuments は DOM への''ハンドル''であることを覚えてください。このクラスのインスタンスは、インスタンスを作成 (create) してもXML文書をロードしても得ることができます。 | ||
− | + | 一方、ノードは通常のオブジェクトのようには生成することができません。必ず TDOMDocument クラスのメソッドを用いてください。その後、別のメソッドによって、新たに生成したノードをツリーの中の然るべき場所に置きます。これはノードというものがDOMの中の特定の文書によって「所有」される必要があるからです。 | |
− | + | 以下に、TDOMDocumentのいくつかの普通のメソッドを示します。 | |
− | + | <syntaxhighlight lang=pascal> function CreateElement(const tagName: DOMString): TDOMElement; virtual; | |
− | |||
− | |||
− | |||
− | < | ||
− | |||
function CreateTextNode(const data: DOMString): TDOMText; | function CreateTextNode(const data: DOMString): TDOMText; | ||
function CreateCDATASection(const data: DOMString): TDOMCDATASection; | function CreateCDATASection(const data: DOMString): TDOMCDATASection; | ||
virtual; | virtual; | ||
− | function CreateAttribute(const name: DOMString): TDOMAttr; virtual; | + | function CreateAttribute(const name: DOMString): TDOMAttr; virtual;</syntaxhighlight> |
− | </ | ||
− | + | 次は、選択されたアイテムを TTreeView の中に置き、そのツリーが表す XML 文書の中に子ノードを挿入するメソッドの例です。[[Networking#Populating a TreeView with XML|XML2Tree function]] によってあらかじめ XML の全ての内容を TreeView に含めておく必要があります。 | |
− | < | + | <syntaxhighlight lang=pascal> procedure TForm1.actAddChildNode(Sender: TObject); |
− | procedure TForm1.actAddChildNode(Sender: TObject); | ||
var | var | ||
position: Integer; | position: Integer; | ||
NovoNo: TDomNode; | NovoNo: TDomNode; | ||
begin | begin | ||
− | + | // 選択された要素を発見する | |
− | |||
− | |||
if TreeView1.Selected = nil then Exit; | if TreeView1.Selected = nil then Exit; | ||
Line 297: | Line 321: | ||
end; | end; | ||
− | + | // TreeView を更新する | |
− | |||
− | |||
TreeView1.Items.Clear; | TreeView1.Items.Clear; | ||
XML2Tree(TreeView1, XMLDoc); | XML2Tree(TreeView1, XMLDoc); | ||
Line 306: | Line 328: | ||
begin | begin | ||
{******************************************************************* | {******************************************************************* | ||
− | * | + | * この手続きはツリーの最初のレベルでしかうまく働かないが、 |
− | * | + | * ツリーの全ての深さに適用できるよう改造するのは容易である。 |
*******************************************************************} | *******************************************************************} | ||
end; | end; | ||
− | end; | + | end;</syntaxhighlight> |
− | </ | ||
− | === | + | === TXMLDocument を一つの文字列から生成する === |
− | + | MyXmlString がある XML ファイルの内容を含んだものだとすると、次のコードによって DOM を生成することができます。 | |
− | < | + | <syntaxhighlight lang=pascal>Var |
− | Var | ||
S : TStringStream; | S : TStringStream; | ||
XML : TXMLDocument; | XML : TXMLDocument; | ||
Line 333: | Line 353: | ||
S.Free; | S.Free; | ||
end; | end; | ||
− | end; | + | end;</syntaxhighlight> |
− | </ | ||
− | === | + | === 文書の検証 === |
− | + | 2007年3月以降、DTDの有効性を検証する機能が FCL XMLパーザに加わっています。文書の論理構造があらかじめ定義された ''Document Type Definition'' (DTD) と呼ばれる規則に則っている場合、有効です。 | |
− | + | 次は DTD 付きの XML 文書の例です: | |
− | <xml> | + | <syntaxhighlight lang="xml"> <?xml version='1.0'?> |
− | |||
<!DOCTYPE root [ | <!DOCTYPE root [ | ||
<!ELEMENT root (child)+ > | <!ELEMENT root (child)+ > | ||
Line 351: | Line 369: | ||
<child>This is a first child.</child> | <child>This is a first child.</child> | ||
<child>And this is the second one.</child> | <child>And this is the second one.</child> | ||
− | </root> | + | </root></syntaxhighlight> |
− | </ | ||
− | + | この DTD はルートとなる要素が一つまたは複数の「子」ををち、それらの「子」は内部に文字データのみを持っていることを示しています。パーザが何か違反を発見した場合、レポートされます。 | |
− | + | この種の文書をロードするのは若干複雑になっています。TStream オブジェクトに XML データが含まれているとしましょう: | |
− | < | + | <syntaxhighlight lang=pascal>procedure TMyObject.DOMFromStream(AStream: TStream); |
− | procedure TMyObject.DOMFromStream(AStream: TStream); | ||
var | var | ||
Parser: TDOMParser; | Parser: TDOMParser; | ||
Line 365: | Line 381: | ||
TheDoc: TXMLDocument; | TheDoc: TXMLDocument; | ||
begin | begin | ||
− | // | + | // パーザオブジェクトを生成する |
Parser := TDOMParser.Create; | Parser := TDOMParser.Create; | ||
− | // | + | // 入力ソースオブジェクトも |
Src := TXMLInputSource.Create(AStream); | Src := TXMLInputSource.Create(AStream); | ||
− | // | + | // 検証しなくちゃ |
Parser.Options.Validate := True; | Parser.Options.Validate := True; | ||
− | // | + | // 報告を受け取るためのエラーハンドラを関連づける |
Parser.OnError := @ErrorHandler; | Parser.OnError := @ErrorHandler; | ||
− | // | + | // やっと仕事ができる |
Parser.Parse(Src, TheDoc); | Parser.Parse(Src, TheDoc); | ||
− | // ... | + | // ...後始末もできる。 |
Src.Free; | Src.Free; | ||
Parser.Free; | Parser.Free; | ||
Line 382: | Line 398: | ||
procedure TMyObject.ErrorHandler(E: EXMLReadError); | procedure TMyObject.ErrorHandler(E: EXMLReadError); | ||
begin | begin | ||
− | if E.Severity = esError then // | + | if E.Severity = esError then // 検査エラー以外関心がない |
writeln(E.Message); | writeln(E.Message); | ||
− | end; | + | end;</syntaxhighlight> |
− | </ | ||
− | === | + | === XML ファイルを生成する === |
− | + | 以下に、 XML ファイルを書き出すコードを示します。 | |
− | + | (これは、DeveLazarus ブログのチュートリアルから転載しています)。 | |
− | + | Uses 節に DOM と XMLWrite を追加することを忘れないでください。 | |
− | < | + | <syntaxhighlight lang=pascal>unit Unit1; |
− | unit Unit1; | ||
{$mode objfpc}{$H+} | {$mode objfpc}{$H+} | ||
Line 426: | Line 440: | ||
procedure TForm1.Button1Click(Sender: TObject); | procedure TForm1.Button1Click(Sender: TObject); | ||
var | var | ||
− | xdoc: TXMLDocument; // | + | xdoc: TXMLDocument; // 文書を格納する変数 |
− | RootNode, parentNode, nofilho: TDOMNode; // | + | RootNode, parentNode, nofilho: TDOMNode; // ノードを格納する変数 |
begin | begin | ||
− | // | + | //文書を作成する |
xdoc := TXMLDocument.create; | xdoc := TXMLDocument.create; | ||
− | // | + | //ルートノードを作成する |
RootNode := xdoc.CreateElement('register'); | RootNode := xdoc.CreateElement('register'); | ||
− | Xdoc.Appendchild(RootNode); // | + | Xdoc.Appendchild(RootNode); // ルートノードを保存する |
− | // | + | //親ノードを作成する |
RootNode:= xdoc.DocumentElement; | RootNode:= xdoc.DocumentElement; | ||
parentNode := xdoc.CreateElement('usuario'); | parentNode := xdoc.CreateElement('usuario'); | ||
− | TDOMElement(parentNode).SetAttribute('id', '001'); // | + | TDOMElement(parentNode).SetAttribute('id', '001'); // 親ノードを示す属性を作成する |
− | RootNode.Appendchild(parentNode); // | + | RootNode.Appendchild(parentNode); // 親ノードを保存する |
− | // | + | //子ノードを作成する |
− | parentNode := xdoc.CreateElement('nome'); // | + | parentNode := xdoc.CreateElement('nome'); // 子ノードを一つ作成する |
− | //TDOMElement(parentNode).SetAttribute('sexo', 'M'); // | + | //TDOMElement(parentNode).SetAttribute('sexo', 'M'); // 属性を作成する |
− | nofilho := xdoc.CreateTextNode('Fernando'); // | + | nofilho := xdoc.CreateTextNode('Fernando'); // ノードに値を挿入する |
− | parentNode.Appendchild(nofilho); // | + | parentNode.Appendchild(nofilho); // ノードを保存する |
− | RootNode.ChildNodes.Item[0].AppendChild(parentNode); // | + | RootNode.ChildNodes.Item[0].AppendChild(parentNode); // 子ノードをそれぞれの親ノードに挿入する |
− | // | + | //子ノードを作成する |
− | parentNode := xdoc.CreateElement('idade'); // | + | parentNode := xdoc.CreateElement('idade'); // 子ノードを一つ作成する |
− | //TDOMElement(parentNode).SetAttribute('ano', '1976'); // | + | //TDOMElement(parentNode).SetAttribute('ano', '1976'); // 性を作成する |
− | nofilho := xdoc.CreateTextNode('32'); // | + | nofilho := xdoc.CreateTextNode('32'); // ノードに値を挿入する |
− | parentNode.Appendchild(nofilho); // | + | parentNode.Appendchild(nofilho); // ノードを保存する |
− | .ChildNodes.Item[0].AppendChild(parentNode); // | + | .ChildNodes.Item[0].AppendChild(parentNode); // 子ノードをそれぞれの親ノードに挿入する |
− | writeXMLFile(xDoc,'teste.xml'); // | + | writeXMLFile(xDoc,'teste.xml'); // XML に書く |
− | Xdoc.free; // | + | Xdoc.free; // メモリを解放する |
end; | end; | ||
Line 463: | Line 477: | ||
{$I unit1.lrs} | {$I unit1.lrs} | ||
− | end. | + | end.</syntaxhighlight> |
− | </ | ||
− | + | 結果、書き出される XML ファイルは以下のようになります。: | |
− | <xml> | + | <syntaxhighlight lang="xml"><?xml version="1.0"?> |
− | <?xml version="1.0"?> | ||
<register> | <register> | ||
<usuario id="001"> | <usuario id="001"> | ||
Line 474: | Line 486: | ||
<idade>32</idade> | <idade>32</idade> | ||
</usuario> | </usuario> | ||
− | </register> | + | </register></syntaxhighlight> |
− | </xml> | + | |
+ | また、以下にアイテムの番号による参照が不要な例を示します。 | ||
+ | |||
+ | <syntaxhighlight lang=pascal> | ||
+ | procedure TForm1.Button2Click(Sender: TObject); | ||
+ | var | ||
+ | Doc: TXMLDocument; | ||
+ | RootNode, ElementNode,ItemNode,TextNode: TDOMNode; | ||
+ | i: integer; | ||
+ | begin | ||
+ | try | ||
+ | // TXML ドキュメント を生成 | ||
+ | Doc := TXMLDocument.Create; | ||
+ | // Create a root node | ||
+ | RootNode := Doc.CreateElement('Root'); | ||
+ | Doc.Appendchild(RootNode); | ||
+ | RootNode:= Doc.DocumentElement; | ||
+ | // ノード を生成 | ||
+ | for i := 1 to 20 do | ||
+ | begin | ||
+ | ElementNode:=Doc.CreateElement('Element'); | ||
+ | TDOMElement(ElementNode).SetAttribute('id', IntToStr(i)); | ||
+ | |||
+ | ItemNode:=Doc.CreateElement('Item1'); | ||
+ | TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i)); | ||
+ | TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i)); | ||
+ | TextNode:=Doc.CreateTextNode('Item1Value is '+IntToStr(i)); | ||
+ | ItemNode.AppendChild(TextNode); | ||
+ | ElementNode.AppendChild(ItemNode); | ||
+ | |||
+ | ItemNode:=Doc.CreateElement('Item2'); | ||
+ | TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i)); | ||
+ | TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i)); | ||
+ | TextNode:=Doc.CreateTextNode('Item2Value is '+IntToStr(i)); | ||
+ | ItemNode.AppendChild(TextNode); | ||
+ | ElementNode.AppendChild(ItemNode); | ||
+ | |||
+ | RootNode.AppendChild(ElementNode); | ||
+ | end; | ||
+ | // XML を保存 | ||
+ | WriteXMLFile(Doc,'TestXML_v2.xml'); | ||
+ | finally | ||
+ | Doc.Free; | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | 生成される XML は以下のとおりです。: | ||
+ | <syntaxhighlight lang="xml"> | ||
+ | <?xml version="1.0"?> | ||
+ | <Root> | ||
+ | <Element id="1"> | ||
+ | <Item1 Attr1="1" Attr2="1">Item1Value is 1</Item1> | ||
+ | <Item2 Attr1="1" Attr2="1">Item2Value is 1</Item2> | ||
+ | </Element> | ||
+ | <Element id="2"> | ||
+ | <Item1 Attr1="2" Attr2="2">Item1Value is 2</Item1> | ||
+ | <Item2 Attr1="2" Attr2="2">Item2Value is 2</Item2> | ||
+ | </Element> | ||
+ | <Element id="3"> | ||
+ | <Item1 Attr1="3" Attr2="3">Item1Value is 3</Item1> | ||
+ | <Item2 Attr1="3" Attr2="3">Item2Value is 3</Item2> | ||
+ | </Element> | ||
+ | </Root> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === エンコーディング === | ||
+ | |||
+ | |||
+ | FPC version 2.4 から、 XML reader is able to process data in any encoding by using external decoders. 詳細は [[XML_Decoders/ja]] を見てください。 | ||
+ | |||
+ | XML の標準では、 XML の最初の行のエンコーディング属性は必須ではありません。いても置かなくてもかまいません。 | ||
− | -- | + | the encoding attribute in the first line of the XML is optional in case the actual encoding is UTF-8 ('''without''' BOM - Byte Order Marker) or UTF-16 (UTF-16 BOM). |
− | + | TXMLDocument has an encoding property since FPC 2.4. It is ignored as WriteXMLFile always uses UTF-8. | |
+ | TXMLDocument コンポーネントは、FPC 2.4 以降でエンコーディングを示すプロパティを持ちます。しかし、 常に UTF-8 を用いる writeXMLFile コンポーネントでは最初の行のエンコーディング属性は無視されます。 | ||
− | |||
− | + | * FPC 2.4 doesn´t generate an encoding attribute in the first line of the XML file | |
+ | * FPC 2.6.0 and later explicitly write an UTF8 encoding attribute, as this is needed for some programs that cannot handle the XML without it. | ||
− | + | == 以下もご参照ください == | |
− | * [ | + | * [[XML Decoders|XML デコーダ]] |
+ | * [[Using INI Files|INI ファイルを使う]] | ||
+ | * [[fcl-xml|fcl-xml]] | ||
+ | * [[Internet Tools]], for XPath 2 / XQuery processing | ||
− | + | == 外部リンク == | |
− | + | * [http://www.w3schools.com/xml/default.asp W3Schools] XML のチュートリアル | |
− | [[ | + | * [http://www.thomas-zastrow.de/texte/fpcxml/index.php Thomas Zastrow article] [http://web.archive.org/web/20080802150722/http://www.thomas-zastrow.de/texte/fpcxml/index.php Alternate link] FPC と XML |
Latest revision as of 03:46, 2 March 2020
│
Deutsch (de) │
English (en) │
español (es) │
français (fr) │
magyar (hu) │
Bahasa Indonesia (id) │
italiano (it) │
日本語 (ja) │
한국어 (ko) │
português (pt) │
русский (ru) │
中文(中国大陆) (zh_CN) │
導入
XML(=The Extensible Markup Language)は、W3C が推奨する、異なるシステム間で情報を交換するための言語です。情報はテキスト形式で保存しており、XHTMLのようなWebサービスでもよく使われる現代的なデータ交換方法は、XMLを基礎としています。
Free Pascal Compiler の Free Component Library(FCL)には、XMLをサポートする "XMLRead"、"XMLWrite"、"DOM" といったユニットがあります。 FCL はすでに Lazarus のデフォルトの検索パスにはいっていますので、これらのユニットを uses に追加するだけで XML に関する機能を実装できるようになります。 FCL は現時点(October / 2005 訳注たぶん2008/12時点も同じ)で文書化されていませんので、このチュートリアルでは、これらのユニットを使った XML へのアクセス方法を紹介します。
XML の Document Object Model(DOM) は、異なる言語やシステム間で XML を利用するために同じようなインターフェースを提供する、標準化されたオブジェクトの集合です。
標準化は、メソッド、プロパティ、オブジェクトの他へのインターフェース部分についてのみ行われており、色々な言語のために、実装方法は自由になっています。 FCL では現在、完全に DOM 1.0 をサポートしています.
(訳注注:日本語版 wiki で "XML" の項目が "ネットワーク" に書かれていたときの訳注をそのまま乗せています。訳注: XML , DOM を「完全に」パースする、という実装は、かなり大変なことです。また、異機種間での利用を目的に作られていることに注意しましょう。 Lazarus は、クロスコンパイル環境であり、これを標準で持っている事は、とても便利に快適にプログラムが出来ると思われます。日本語がどこまで検証されているのか、というところは、訳からはちょっと分かりませんが...。)
利用例
以下に、 XML データの利用例を記述しています。徐々に複雑な内容を説明していきます。
textノードを読み込む
Delphi プログラマーの皆さん: TXMLDocument を用いるときには注意して下さい。ノード内のテキストは個々の TEXT ノードと扱われるため、個々のノードとしてノードのテキスト値を取得する必要があります。
別の方法として、 TextContent プロパティを用いて、与えられた一つのノード以下の全てのテキストノードを一つにまとまって取得することもできます。
ReadXMLFile プロシージャは、いつも新しい TXMLDocument を生成するため、あらかじめ TXMLDocument を生成する必要はありません。 しかし、不要になったときには、 Free をコールして document を確実に破棄して下さい。
例えば、以下のxmlファイルについてアクセスする場合、
注:全てのxmlサンプル類、サンプルコードは、UTF-8で保存する必要があるようです。また、以下の例では文頭に"半角スペース"を記入して、整形済みテキストとして表示しており、ほとんどのコードはそのまま動きますが、<?xml><sample>は先頭の半角スペースを削除しないとうまく動きませんでした。 <XML> <?xml version="1.0"?>
<sample name="s1" >sampleXML <group name="g1" >G1 <user>123</user> <item val="int" >999</item> <item val="str" >abc</item> </group> <group name="g2" >G2 <item val="str" >def</item> </group> <gr name="gr1" >GR1 <item val="str" >def</item> </gr> </sample></XML>
以下のコードで、テキストノードから値を取得する場合の、正しい方法と間違った方法をお見せします。
注: 既存のコードがうまく動かなかったので(おそらく私のコンソールアプリの理解不足です)、全てのコードをGUIコードとして作り直しました。 (動作確認は、windowsXPSP2 上の lazarus0.9.26 で行いました。)
はじめの設定
1.usesに XMLRead, Domを追加
2.form1にmemo1,button1,OpenDialogを追加
procedure TForm1.Button1Click(Sender: TObject);
var
tmpNode: TDOMNode;
Doc: TXMLDocument;
begin
// Doc := TXMLDocument.Create;//ここで生成する必要はありません。
Memo1.Lines.Clear;
// xml fileを読み込みます。
Opendialog1.Execute;
ReadXMLFile(Doc,Opendialog1.FileName);
// "password" ノードを取得します。
tmpNode := Doc.DocumentElement.FindNode('group');
// 選択したノードの値の書き出し
Memo1.Lines.Add(tmpNode.NodeValue);// 空白値""しか取得できません。
// (ノードのテキスト値は、実際は個々の小ノードになっています。)
Memo1.Lines.Add(tmpNode.FirstChild.NodeValue);// "abc" が取得できます。
// 他の方法
Memo1.Lines.Add(tmpNode.TextContent);
// 最後に、documentを破棄します。
Doc.Free;
end;
出力は以下のようになります。
G1 G1 123999abc
ノードの名前を出力する
ノードに順番にアクセスする場合、 FirstChild と NextSibling プロパティ(前方から繰り返し), または LastChild と PreviousSibling (後方から繰り返し)を用いればよいでしょう。
ランダムアクセスには、ChildNodes または GetElementsByTagName メソッドが使えますが、これらは 最終的に破棄する必要のある TDOMNodeList オブジェクトを生成します。
これは、他の DOM 実装(例えばMXSML) とは異なりますが、この理由は、FCL での実装がobject-basedであり、interface-based では無いためです。
以下に、 form 上の TMemo にノードの名前を出力するサンプルを示します。 (訳注:元々の例は、上側の例と異なっているため(ファイル名がtestoなど)、記述を上記例に統一しました。)
以下のxmlファイルにアクセスする場合、
<?xml version="1.0"?>
<sample name="s1" >sampleXML
<group name="g1" >G1
<user>123</user>
<item val="int" >999</item>
<item val="str" >abc</item>
</group>
<group name="g2" >G2
<item val="str" >def</item>
</group>
<gr name="gr1" >GR1
<item val="str" >def</item>
</gr>
</sample>
はじめの設定
1.usesに XMLRead, Dom を追加
2.form1にmemo1,button1,OpenDialogを追加
1a.FirstChild と NextSibling プロパティを使用(順番にアクセス) (訳注:英語版のコードは上記ノートと利用プロパティ、メソッドに整合性が無いため修正しました。)
procedure TForm1.Button1Click(Sender: TObject);
var
Child: TDOMNode;
Doc: TXMLDocument;
cnt: Integer;
begin
Memo1.Lines.Clear;
Opendialog1.Execute;
ReadXMLFile(Doc,Opendialog1.FileName);
// FirstChild プロパティの使用
Child := Doc.DocumentElement.FirstChild;
while Assigned(Child) do
begin
cnt:=cnt+1;
Memo1.Lines.Add(inttostr(cnt)
+ ' ' + Child.NodeName + ' ' + Child.NodeValue);
// NextSibling プロパティの使用
Child := Child.NextSibling;
end;
Doc.Free;
end;
出力は以下のようになります。
1 #text sampleXML 2 group 3 group 4 gr
1b.ChildNodes と getElementsByTagName メソッドを使用(ランダムアクセス) 注)DOMNodeListのノード数はCountとなる。
procedure TForm1.Button1Click(Sender: TObject);
var
tmpNodes: TDOMNodeList;
Doc: TXMLDocument;
i: Integer;
begin
Memo1.Lines.Clear;
Opendialog1.Execute;
ReadXMLFile(Doc,Opendialog1.FileName);
// ChildNodes メソッドの使用
tmpNodes:=Doc.DocumentElement.ChildNodes;
Memo1.Lines.Add('1.ChildNodes count=' + inttostr(tmpNodes.Count));
if(tmpNodes.Count <> 0) then
for i:=0 to tmpNodes.Count-1 do begin
Memo1.Lines.Add(inttostr(i)
+ ' ' + tmpNodes[i].NodeName
+ ' ' + tmpNodes[i].NodeValue);
end;
tmpNodes.Free;
// getElementsByTagName メソッドの使用
tmpNodes:= Doc.GetElementsByTagName('group');
Memo1.Lines.Add('2.getEBTN count=' + inttostr(tmpNodes.Count));
if(tmpNodes.Count <> 0) then
for i:=0 to tmpNodes.Count-1 do begin
Memo1.Lines.Add(inttostr(i)
+ ' ' + tmpNodes[i].NodeName
+ ' ' + tmpNodes[i].NodeValue);
end;
tmpNodes.Free;
end;
出力は以下のようになります。
1.ChildNodes count=4 0 #text sampleXML 1 group 2 group 3 gr 2.getEBTN count=2 0 group 1 group
2.ChildNodes メソッドを用いた順次アクセスのコードは以下のようになります。 (注:日本語版の"ネットワーク"項目のXMLが記述されていたコードがあったので、とりあえず入れておきます。)
procedure TForm1.Button1Click(Sender: TObject);
var
Doc: TXMLDocument;
i, j: Integer;
begin
Memo1.Lines.Clear;
Opendialog1.Execute;
ReadXMLFile(Doc,Opendialog1.FileName);
// ChildNodes メソッドの使用
with Doc.DocumentElement.ChildNodes do
begin
for i := 0 to (Count - 1) do
begin
Memo1.Lines.Add('i' + inttostr(i)
+ Item[i].NodeName + ' ' + Item[i].NodeValue);
for j := 0 to (Item[i].ChildNodes.Count - 1) do
begin
Memo1.Lines.Add(' j' + inttostr(j)
+ ' ' + Item[i].ChildNodes.Item[j].NodeName
+ ' ' + Item[i].ChildNodes.Item[j].NodeValue);
end;
end;
end;
Doc.Free;
end;
出力は以下のようになります。
i0#text sampleXML i1group j0 #text G1 j1 user j2 item j3 item i2group j0 #text G2 j1 item i3gr j0 #text GR1 j1 item
XML を TreeView で表示する
XMLファイルの一般的な利用として、XMLファイルの内容を TreeView の形で表示することがあります。 Lazarusの ”Common Controls” タブに TTreeView コンポーネントがあります。
以下の手続きは、既にファイルから読み込んだか、コードの中で生成するかした XML 文書を取得し、その内容をTreeViewの形で表示します。それぞれのノードがもつキャプションが、最初の属性の内容になります。
はじめの設定
1.usesに XMLRead, Dom を追加
2.form1にTTreeView1を追加
3.TForm1のtypeにメソッド”procedure XML2Tree(tree: TTreeView; XMLDoc: TXMLDocument); ”を追加
procedure TForm1.XML2Tree(tree: TTreeView; XMLDoc: TXMLDocument);
var
iNode: TDOMNode;
procedure ProcessNode(Node: TDOMNode; TreeNode: TTreeNode);
var
cNode: TDOMNode;
begin
if Node = nil then Exit; // Stops if reached a leaf
// Adds a node to the tree
TreeNode := tree.Items.AddChild(TreeNode,
Node.Attributes[0].NodeValue);
// Goes to the child node
cNode := Node.FirstChild;
// Processes all child nodes
while cNode <> nil do
begin
ProcessNode(cNode, TreeNode);
cNode := cNode.NextSibling;
end;
end;
begin
iNode := XMLDoc.DocumentElement.FirstChild;
while iNode <> nil do
begin
ProcessNode(iNode, nil); // Recursive
iNode := iNode.NextSibling;
end;
end;
XML 書類を修正する
まず、TDOMDocuments は DOM へのハンドルであることを覚えてください。このクラスのインスタンスは、インスタンスを作成 (create) してもXML文書をロードしても得ることができます。
一方、ノードは通常のオブジェクトのようには生成することができません。必ず TDOMDocument クラスのメソッドを用いてください。その後、別のメソッドによって、新たに生成したノードをツリーの中の然るべき場所に置きます。これはノードというものがDOMの中の特定の文書によって「所有」される必要があるからです。
以下に、TDOMDocumentのいくつかの普通のメソッドを示します。
function CreateElement(const tagName: DOMString): TDOMElement; virtual;
function CreateTextNode(const data: DOMString): TDOMText;
function CreateCDATASection(const data: DOMString): TDOMCDATASection;
virtual;
function CreateAttribute(const name: DOMString): TDOMAttr; virtual;
次は、選択されたアイテムを TTreeView の中に置き、そのツリーが表す XML 文書の中に子ノードを挿入するメソッドの例です。XML2Tree function によってあらかじめ XML の全ての内容を TreeView に含めておく必要があります。
procedure TForm1.actAddChildNode(Sender: TObject);
var
position: Integer;
NovoNo: TDomNode;
begin
// 選択された要素を発見する
if TreeView1.Selected = nil then Exit;
if TreeView1.Selected.Level = 0 then
begin
position := TreeView1.Selected.Index;
NovoNo := XMLDoc.CreateElement('item');
TDOMElement(NovoNo).SetAttribute('nome', 'Item');
TDOMElement(NovoNo).SetAttribute('arquivo', 'Arquivo');
with XMLDoc.DocumentElement.ChildNodes do
begin
Item[position].AppendChild(NovoNo);
Free;
end;
// TreeView を更新する
TreeView1.Items.Clear;
XML2Tree(TreeView1, XMLDoc);
end
else if TreeView1.Selected.Level >= 1 then
begin
{*******************************************************************
* この手続きはツリーの最初のレベルでしかうまく働かないが、
* ツリーの全ての深さに適用できるよう改造するのは容易である。
*******************************************************************}
end;
end;
TXMLDocument を一つの文字列から生成する
MyXmlString がある XML ファイルの内容を含んだものだとすると、次のコードによって DOM を生成することができます。
Var
S : TStringStream;
XML : TXMLDocument;
begin
S:= TStringStream.Create(MyXMLString);
Try
S.Position:=0;
XML:=Nil;
ReadXMLFile(XML,S); // Complete XML document
// Alternatively:
ReadXMLFragment(AParentNode,S); // Read only XML fragment.
Finally
S.Free;
end;
end;
文書の検証
2007年3月以降、DTDの有効性を検証する機能が FCL XMLパーザに加わっています。文書の論理構造があらかじめ定義された Document Type Definition (DTD) と呼ばれる規則に則っている場合、有効です。
次は DTD 付きの XML 文書の例です:
<?xml version='1.0'?>
<!DOCTYPE root [
<!ELEMENT root (child)+ >
<!ELEMENT child (#PCDATA)>
]>
<root>
<child>This is a first child.</child>
<child>And this is the second one.</child>
</root>
この DTD はルートとなる要素が一つまたは複数の「子」ををち、それらの「子」は内部に文字データのみを持っていることを示しています。パーザが何か違反を発見した場合、レポートされます。
この種の文書をロードするのは若干複雑になっています。TStream オブジェクトに XML データが含まれているとしましょう:
procedure TMyObject.DOMFromStream(AStream: TStream);
var
Parser: TDOMParser;
Src: TXMLInputSource;
TheDoc: TXMLDocument;
begin
// パーザオブジェクトを生成する
Parser := TDOMParser.Create;
// 入力ソースオブジェクトも
Src := TXMLInputSource.Create(AStream);
// 検証しなくちゃ
Parser.Options.Validate := True;
// 報告を受け取るためのエラーハンドラを関連づける
Parser.OnError := @ErrorHandler;
// やっと仕事ができる
Parser.Parse(Src, TheDoc);
// ...後始末もできる。
Src.Free;
Parser.Free;
end;
procedure TMyObject.ErrorHandler(E: EXMLReadError);
begin
if E.Severity = esError then // 検査エラー以外関心がない
writeln(E.Message);
end;
XML ファイルを生成する
以下に、 XML ファイルを書き出すコードを示します。 (これは、DeveLazarus ブログのチュートリアルから転載しています)。 Uses 節に DOM と XMLWrite を追加することを忘れないでください。
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls,
DOM, XMLWrite;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
Label2: TLabel;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
xdoc: TXMLDocument; // 文書を格納する変数
RootNode, parentNode, nofilho: TDOMNode; // ノードを格納する変数
begin
//文書を作成する
xdoc := TXMLDocument.create;
//ルートノードを作成する
RootNode := xdoc.CreateElement('register');
Xdoc.Appendchild(RootNode); // ルートノードを保存する
//親ノードを作成する
RootNode:= xdoc.DocumentElement;
parentNode := xdoc.CreateElement('usuario');
TDOMElement(parentNode).SetAttribute('id', '001'); // 親ノードを示す属性を作成する
RootNode.Appendchild(parentNode); // 親ノードを保存する
//子ノードを作成する
parentNode := xdoc.CreateElement('nome'); // 子ノードを一つ作成する
//TDOMElement(parentNode).SetAttribute('sexo', 'M'); // 属性を作成する
nofilho := xdoc.CreateTextNode('Fernando'); // ノードに値を挿入する
parentNode.Appendchild(nofilho); // ノードを保存する
RootNode.ChildNodes.Item[0].AppendChild(parentNode); // 子ノードをそれぞれの親ノードに挿入する
//子ノードを作成する
parentNode := xdoc.CreateElement('idade'); // 子ノードを一つ作成する
//TDOMElement(parentNode).SetAttribute('ano', '1976'); // 性を作成する
nofilho := xdoc.CreateTextNode('32'); // ノードに値を挿入する
parentNode.Appendchild(nofilho); // ノードを保存する
.ChildNodes.Item[0].AppendChild(parentNode); // 子ノードをそれぞれの親ノードに挿入する
writeXMLFile(xDoc,'teste.xml'); // XML に書く
Xdoc.free; // メモリを解放する
end;
initialization
{$I unit1.lrs}
end.
結果、書き出される XML ファイルは以下のようになります。:
<?xml version="1.0"?>
<register>
<usuario id="001">
<nome>Fernando</nome>
<idade>32</idade>
</usuario>
</register>
また、以下にアイテムの番号による参照が不要な例を示します。
procedure TForm1.Button2Click(Sender: TObject);
var
Doc: TXMLDocument;
RootNode, ElementNode,ItemNode,TextNode: TDOMNode;
i: integer;
begin
try
// TXML ドキュメント を生成
Doc := TXMLDocument.Create;
// Create a root node
RootNode := Doc.CreateElement('Root');
Doc.Appendchild(RootNode);
RootNode:= Doc.DocumentElement;
// ノード を生成
for i := 1 to 20 do
begin
ElementNode:=Doc.CreateElement('Element');
TDOMElement(ElementNode).SetAttribute('id', IntToStr(i));
ItemNode:=Doc.CreateElement('Item1');
TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i));
TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i));
TextNode:=Doc.CreateTextNode('Item1Value is '+IntToStr(i));
ItemNode.AppendChild(TextNode);
ElementNode.AppendChild(ItemNode);
ItemNode:=Doc.CreateElement('Item2');
TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i));
TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i));
TextNode:=Doc.CreateTextNode('Item2Value is '+IntToStr(i));
ItemNode.AppendChild(TextNode);
ElementNode.AppendChild(ItemNode);
RootNode.AppendChild(ElementNode);
end;
// XML を保存
WriteXMLFile(Doc,'TestXML_v2.xml');
finally
Doc.Free;
end;
生成される XML は以下のとおりです。:
<?xml version="1.0"?>
<Root>
<Element id="1">
<Item1 Attr1="1" Attr2="1">Item1Value is 1</Item1>
<Item2 Attr1="1" Attr2="1">Item2Value is 1</Item2>
</Element>
<Element id="2">
<Item1 Attr1="2" Attr2="2">Item1Value is 2</Item1>
<Item2 Attr1="2" Attr2="2">Item2Value is 2</Item2>
</Element>
<Element id="3">
<Item1 Attr1="3" Attr2="3">Item1Value is 3</Item1>
<Item2 Attr1="3" Attr2="3">Item2Value is 3</Item2>
</Element>
</Root>
エンコーディング
FPC version 2.4 から、 XML reader is able to process data in any encoding by using external decoders. 詳細は XML_Decoders/ja を見てください。
XML の標準では、 XML の最初の行のエンコーディング属性は必須ではありません。いても置かなくてもかまいません。
the encoding attribute in the first line of the XML is optional in case the actual encoding is UTF-8 (without BOM - Byte Order Marker) or UTF-16 (UTF-16 BOM).
TXMLDocument has an encoding property since FPC 2.4. It is ignored as WriteXMLFile always uses UTF-8. TXMLDocument コンポーネントは、FPC 2.4 以降でエンコーディングを示すプロパティを持ちます。しかし、 常に UTF-8 を用いる writeXMLFile コンポーネントでは最初の行のエンコーディング属性は無視されます。
- FPC 2.4 doesn´t generate an encoding attribute in the first line of the XML file
- FPC 2.6.0 and later explicitly write an UTF8 encoding attribute, as this is needed for some programs that cannot handle the XML without it.
以下もご参照ください
- XML デコーダ
- INI ファイルを使う
- fcl-xml
- Internet Tools, for XPath 2 / XQuery processing
外部リンク
- W3Schools XML のチュートリアル
- Thomas Zastrow article Alternate link FPC と XML