XML Tutorial/ja: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: XML Tutorial/ja
| Old | New | Line | |
|---|---|---|---|
| 1 | + | ## 導入 | |
| 2 | + | ||
| 3 | + | XML(=The Extensible Markup Language)は、[W3C](http://www.w3.org/) が推奨する、異なるシステム間で情報を交換するための言語です。情報はテキスト形式で保存しており、XHTMLのようなWebサービスでもよく使われる現代的なデータ交換方法は、XMLを基礎としています。 | |
| 4 | + | ||
| 5 | + | Free Pascal Compiler の Free Component Library(FCL)には、XMLをサポートする "XMLRead"、"XMLWrite"、"DOM" といったユニットがあります。 FCL はすでに Lazarus のデフォルトの検索パスにはいっていますので、これらのユニットを uses に追加するだけで XML に関する機能を実装できるようになります。 FCL は現時点(October / 2005 訳注たぶん2008/12時点も同じ)で文書化されていませんので、このチュートリアルでは、これらのユニットを使った XML へのアクセス方法を紹介します。 | |
| 6 | + | ||
| 7 | + | XML の Document Object Model(DOM) は、異なる言語やシステム間で XML を利用するために同じようなインターフェースを提供する、標準化されたオブジェクトの集合です。 | |
| 8 | + | ||
| 9 | + | 標準化は、メソッド、プロパティ、オブジェクトの他へのインターフェース部分についてのみ行われており、色々な言語のために、実装方法は自由になっています。 FCL では現在、完全に [DOM 1.0](http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/%7CXML) をサポートしています. | |
| 10 | + | ||
| 11 | + | (訳注注:日本語版 wiki で "XML" の項目が "ネットワーク" に書かれていたときの訳注をそのまま乗せています。訳注: XML , DOM を「完全に」パースする、という実装は、かなり大変なことです。また、異機種間での利用を目的に作られていることに注意しましょう。 Lazarus は、クロスコンパイル環境であり、これを標準で持っている事は、とても便利に快適にプログラムが出来ると思われます。日本語がどこまで検証されているのか、というところは、訳からはちょっと分かりませんが...。) | |
| 12 | + | ||
| 13 | + | ## 利用例 | |
| 14 | + | ||
| 15 | + | 以下に、 XML データの利用例を記述しています。徐々に複雑な内容を説明していきます。 | |
| 16 | + | ||
| 17 | + | ### textノードを読み込む | |
| 18 | + | ||
| 19 | + | Delphi プログラマーの皆さん: TXMLDocument を用いるときには注意して下さい。ノード内のテキストは個々の TEXT ノードと扱われるため、個々のノードとしてノードのテキスト値を取得する必要があります。 | |
| 20 | + | ||
| 21 | + | 別の方法として、 **TextContent** プロパティを用いて、与えられた一つのノード以下の全てのテキストノードを一つにまとまって取得することもできます。 | |
| 22 | + | ||
| 23 | + | **ReadXMLFile** プロシージャは、いつも新しい **TXMLDocument** を生成するため、あらかじめ **TXMLDocument** を生成する必要はありません。 しかし、不要になったときには、 **Free** をコールして document を確実に破棄して下さい。 | |
| 24 | + | ||
| 25 | + | 例えば、以下のxmlファイルについてアクセスする場合、 | |
| 26 | + | ||
| 27 | + | 注:全てのxmlサンプル類、サンプルコードは、UTF-8で保存する必要があるようです。また、以下の例では文頭に"半角スペース"を記入して、整形済みテキストとして表示しており、ほとんどのコードはそのまま動きますが、\<?xml\>\<sample\>は先頭の半角スペースを削除しないとうまく動きませんでした。 \<XML\> \<?xml version="1.0"?\> | |
| 28 | + | ||
| 29 | + | `<sample name="s1" >sampleXML`\ | |
| 30 | + | ` <group name="g1" >G1`\ | |
| 31 | + | ` <user>123</user>`\ | |
| 32 | + | ` <item val="int" >999</item>`\ | |
| 33 | + | ` <item val="str" >abc</item>`\ | |
| 34 | + | ` </group>`\ | |
| 35 | + | ` <group name="g2" >G2`\ | |
| 36 | + | ` <item val="str" >def</item>`\ | |
| 37 | + | ` </group>`\ | |
| 38 | + | ` <gr name="gr1" >GR1`\ | |
| 39 | + | ` <item val="str" >def</item>`\ | |
| 40 | + | ` </gr>`\ | |
| 41 | + | `</sample></XML>` | |
| 42 | + | ||
| 43 | + | 以下のコードで、テキストノードから値を取得する場合の、正しい方法と間違った方法をお見せします。 | |
| 44 | + | ||
| 45 | + | 注: 既存のコードがうまく動かなかったので(おそらく私のコンソールアプリの理解不足です)、全てのコードをGUIコードとして作り直しました。 (動作確認は、windowsXPSP2 上の lazarus0.9.26 で行いました。) | |
| 46 | + | ||
| 47 | + | はじめの設定 | |
| 48 | + | ||
| 49 | + | 1.usesに XMLRead, Domを追加 | |
| 50 | + | ||
| 51 | + | 2.form1にmemo1,button1,OpenDialogを追加 | |
| 52 | + | ||
| 53 | + | ``` pascal | |
| 54 | + | procedure TForm1.Button1Click(Sender: TObject); | |
| 55 | + | var | |
| 56 | + | tmpNode: TDOMNode; | |
| 57 | + | Doc: TXMLDocument; | |
| 58 | + | begin | |
| 59 | + | // Doc := TXMLDocument.Create;//ここで生成する必要はありません。 | |
| 60 | + | Memo1.Lines.Clear; | |
| 61 | + | ||
| 62 | + | // xml fileを読み込みます。 | |
| 63 | + | Opendialog1.Execute; | |
| 64 | + | ReadXMLFile(Doc,Opendialog1.FileName); | |
| 65 | + | // "password" ノードを取得します。 | |
| 66 | + | tmpNode := Doc.DocumentElement.FindNode('group'); | |
| 67 | + | ||
| 68 | + | // 選択したノードの値の書き出し | |
| 69 | + | Memo1.Lines.Add(tmpNode.NodeValue);// 空白値""しか取得できません。 | |
| 70 | + | // (ノードのテキスト値は、実際は個々の小ノードになっています。) | |
| 71 | + | Memo1.Lines.Add(tmpNode.FirstChild.NodeValue);// "abc" が取得できます。 | |
| 72 | + | // 他の方法 | |
| 73 | + | Memo1.Lines.Add(tmpNode.TextContent); | |
| 74 | + | // 最後に、documentを破棄します。 | |
| 75 | + | Doc.Free; | |
| 76 | + | end; | |
| 77 | + | ``` | |
| 78 | + | ||
| 79 | + | 出力は以下のようになります。 | |
| 80 | + | ||
| 81 | + | ||
| 82 | + | G1 | |
| 83 | + | G1 123999abc | |
| 84 | + | ||
| 85 | + | ### ノードの名前を出力する | |
| 86 | + | ||
| 87 | + | ノードに順番にアクセスする場合、 **FirstChild** と **NextSibling** プロパティ(前方から繰り返し), または **LastChild** と **PreviousSibling** (後方から繰り返し)を用いればよいでしょう。 | |
| 88 | + | ||
| 89 | + | ランダムアクセスには、**ChildNodes** または **GetElementsByTagName** メソッドが使えますが、これらは 最終的に破棄する必要のある TDOMNodeList オブジェクトを生成します。 | |
| 90 | + | ||
| 91 | + | これは、他の DOM 実装(例えばMXSML) とは異なりますが、この理由は、FCL での実装がobject-basedであり、interface-based では無いためです。 | |
| 92 | + | ||
| 93 | + | 以下に、 form 上の TMemo にノードの名前を出力するサンプルを示します。 (訳注:元々の例は、上側の例と異なっているため(ファイル名がtestoなど)、記述を上記例に統一しました。) | |
| 94 | + | ||
| 95 | + | 以下のxmlファイルにアクセスする場合、 | |
| 96 | + | ||
| 97 | + | ``` xml | |
| 98 | + | <?xml version="1.0"?> | |
| 99 | + | <sample name="s1" >sampleXML | |
| 100 | + | <group name="g1" >G1 | |
| 101 | + | <user>123</user> | |
| 102 | + | <item val="int" >999</item> | |
| 103 | + | <item val="str" >abc</item> | |
| 104 | + | </group> | |
| 105 | + | <group name="g2" >G2 | |
| 106 | + | <item val="str" >def</item> | |
| 107 | + | </group> | |
| 108 | + | <gr name="gr1" >GR1 | |
| 109 | + | <item val="str" >def</item> | |
| 110 | + | </gr> | |
| 111 | + | </sample> | |
| 112 | + | ``` | |
| 113 | + | ||
| 114 | + | はじめの設定 | |
| 115 | + | ||
| 116 | + | 1.usesに XMLRead, Dom を追加 | |
| 117 | + | ||
| 118 | + | 2.form1にmemo1,button1,OpenDialogを追加 | |
| 119 | + | ||
| 120 | + | 1a.**FirstChild** と **NextSibling** プロパティを使用(順番にアクセス) (訳注:英語版のコードは上記ノートと利用プロパティ、メソッドに整合性が無いため修正しました。) | |
| 121 | + | ||
| 122 | + | ``` pascal | |
| 123 | + | procedure TForm1.Button1Click(Sender: TObject); | |
| 124 | + | var | |
| 125 | + | Child: TDOMNode; | |
| 126 | + | Doc: TXMLDocument; | |
| 127 | + | cnt: Integer; | |
| 128 | + | begin | |
| 129 | + | Memo1.Lines.Clear; | |
| 130 | + | Opendialog1.Execute; | |
| 131 | + | ReadXMLFile(Doc,Opendialog1.FileName); | |
| 132 | + | ||
| 133 | + | // FirstChild プロパティの使用 | |
| 134 | + | Child := Doc.DocumentElement.FirstChild; | |
| 135 | + | while Assigned(Child) do | |
| 136 | + | begin | |
| 137 | + | cnt:=cnt+1; | |
| 138 | + | Memo1.Lines.Add(inttostr(cnt) | |
| 139 | + | + ' ' + Child.NodeName + ' ' + Child.NodeValue); | |
| 140 | + | // NextSibling プロパティの使用 | |
| 141 | + | Child := Child.NextSibling; | |
| 142 | + | end; | |
| 143 | + | Doc.Free; | |
| 144 | + | end; | |
| 145 | + | ``` | |
| 146 | + | ||
| 147 | + | 出力は以下のようになります。 | |
| 148 | + | ||
| 149 | + | 1 #text sampleXML | |
| 150 | + | 2 group | |
| 151 | + | 3 group | |
| 152 | + | 4 gr | |
| 153 | + | ||
| 154 | + | 1b.**ChildNodes** と **getElementsByTagName** メソッドを使用(ランダムアクセス) 注)DOMNodeListのノード数はCountとなる。 | |
| 155 | + | ||
| 156 | + | ``` pascal | |
| 157 | + | procedure TForm1.Button1Click(Sender: TObject); | |
| 158 | + | var | |
| 159 | + | tmpNodes: TDOMNodeList; | |
| 160 | + | Doc: TXMLDocument; | |
| 161 | + | i: Integer; | |
| 162 | + | begin | |
| 163 | + | Memo1.Lines.Clear; | |
| 164 | + | Opendialog1.Execute; | |
| 165 | + | ReadXMLFile(Doc,Opendialog1.FileName); | |
| 166 | + | ||
| 167 | + | // ChildNodes メソッドの使用 | |
| 168 | + | tmpNodes:=Doc.DocumentElement.ChildNodes; | |
| 169 | + | Memo1.Lines.Add('1.ChildNodes count=' + inttostr(tmpNodes.Count)); | |
| 170 | + | if(tmpNodes.Count <> 0) then | |
| 171 | + | for i:=0 to tmpNodes.Count-1 do begin | |
| 172 | + | Memo1.Lines.Add(inttostr(i) | |
| 173 | + | + ' ' + tmpNodes[i].NodeName | |
| 174 | + | + ' ' + tmpNodes[i].NodeValue); | |
| 175 | + | end; | |
| 176 | + | tmpNodes.Free; | |
| 177 | + | ||
| 178 | + | // getElementsByTagName メソッドの使用 | |
| 179 | + | tmpNodes:= Doc.GetElementsByTagName('group'); | |
| 180 | + | Memo1.Lines.Add('2.getEBTN count=' + inttostr(tmpNodes.Count)); | |
| 181 | + | if(tmpNodes.Count <> 0) then | |
| 182 | + | for i:=0 to tmpNodes.Count-1 do begin | |
| 183 | + | Memo1.Lines.Add(inttostr(i) | |
| 184 | + | + ' ' + tmpNodes[i].NodeName | |
| 185 | + | + ' ' + tmpNodes[i].NodeValue); | |
| 186 | + | end; | |
| 187 | + | tmpNodes.Free; | |
| 188 | + | end; | |
| 189 | + | ``` | |
| 190 | + | ||
| 191 | + | 出力は以下のようになります。 | |
| 192 | + | ||
| 193 | + | 1.ChildNodes count=4 | |
| 194 | + | 0 #text sampleXML | |
| 195 | + | 1 group | |
| 196 | + | 2 group | |
| 197 | + | 3 gr | |
| 198 | + | 2.getEBTN count=2 | |
| 199 | + | 0 group | |
| 200 | + | 1 group | |
| 201 | + | ||
| 202 | + | 2.**ChildNodes** メソッドを用いた順次アクセスのコードは以下のようになります。 (注:日本語版の"ネットワーク"項目のXMLが記述されていたコードがあったので、とりあえず入れておきます。) | |
| 203 | + | ||
| 204 | + | ``` pascal | |
| 205 | + | procedure TForm1.Button1Click(Sender: TObject); | |
| 206 | + | var | |
| 207 | + | Doc: TXMLDocument; | |
| 208 | + | i, j: Integer; | |
| 209 | + | begin | |
| 210 | + | Memo1.Lines.Clear; | |
| 211 | + | Opendialog1.Execute; | |
| 212 | + | ReadXMLFile(Doc,Opendialog1.FileName); | |
| 213 | + | ||
| 214 | + | // ChildNodes メソッドの使用 | |
| 215 | + | with Doc.DocumentElement.ChildNodes do | |
| 216 | + | begin | |
| 217 | + | for i := 0 to (Count - 1) do | |
| 218 | + | begin | |
| 219 | + | Memo1.Lines.Add('i' + inttostr(i) | |
| 220 | + | + Item[i].NodeName + ' ' + Item[i].NodeValue); | |
| 221 | + | for j := 0 to (Item[i].ChildNodes.Count - 1) do | |
| 222 | + | begin | |
| 223 | + | Memo1.Lines.Add(' j' + inttostr(j) | |
| 224 | + | + ' ' + Item[i].ChildNodes.Item[j].NodeName | |
| 225 | + | + ' ' + Item[i].ChildNodes.Item[j].NodeValue); | |
| 226 | + | end; | |
| 227 | + | end; | |
| 228 | + | end; | |
| 229 | + | Doc.Free; | |
| 230 | + | end; | |
| 231 | + | ``` | |
| 232 | + | ||
| 233 | + | 出力は以下のようになります。 | |
| 234 | + | ||
| 235 | + | i0#text sampleXML | |
| 236 | + | i1group | |
| 237 | + | j0 #text G1 | |
| 238 | + | j1 user | |
| 239 | + | j2 item | |
| 240 | + | j3 item | |
| 241 | + | i2group | |
| 242 | + | j0 #text G2 | |
| 243 | + | j1 item | |
| 244 | + | i3gr | |
| 245 | + | j0 #text GR1 | |
| 246 | + | j1 item | |
| 247 | + | ||
| 248 | + | ### XML を TreeView で表示する | |
| 249 | + | ||
| 250 | + | XMLファイルの一般的な利用として、XMLファイルの内容を TreeView の形で表示することがあります。 Lazarusの ”Common Controls” タブに TTreeView コンポーネントがあります。 | |
| 251 | + | ||
| 252 | + | 以下の手続きは、既にファイルから読み込んだか、コードの中で生成するかした XML 文書を取得し、その内容をTreeViewの形で表示します。それぞれのノードがもつキャプションが、最初の属性の内容になります。 | |
| 253 | + | ||
| 254 | + | はじめの設定 | |
| 255 | + | ||
| 256 | + | 1.usesに XMLRead, Dom を追加 | |
| 257 | + | ||
| 258 | + | 2.form1にTTreeView1を追加 | |
| 259 | + | ||
| 260 | + | 3.TForm1のtypeにメソッド”procedure XML2Tree(tree: TTreeView; XMLDoc: TXMLDocument); ”を追加 | |
| 261 | + | ||
| 262 | + | ``` pascal | |
| 263 | + | procedure TForm1.XML2Tree(tree: TTreeView; XMLDoc: TXMLDocument); | |
| 264 | + | var | |
| 265 | + | iNode: TDOMNode; | |
| 266 | + | ||
| 267 | + | procedure ProcessNode(Node: TDOMNode; TreeNode: TTreeNode); | |
| 268 | + | var | |
| 269 | + | cNode: TDOMNode; | |
| 270 | + | begin | |
| 271 | + | if Node = nil then Exit; // Stops if reached a leaf | |
| 272 | + | ||
| 273 | + | // Adds a node to the tree | |
| 274 | + | TreeNode := tree.Items.AddChild(TreeNode, | |
| 275 | + | Node.Attributes[0].NodeValue); | |
| 276 | + | ||
| 277 | + | // Goes to the child node | |
| 278 | + | cNode := Node.FirstChild; | |
| 279 | + | ||
| 280 | + | // Processes all child nodes | |
| 281 | + | while cNode <> nil do | |
| 282 | + | begin | |
| 283 | + | ProcessNode(cNode, TreeNode); | |
| 284 | + | cNode := cNode.NextSibling; | |
| 285 | + | end; | |
| 286 | + | end; | |
| 287 | + | ||
| 288 | + | begin | |
| 289 | + | iNode := XMLDoc.DocumentElement.FirstChild; | |
| 290 | + | while iNode <> nil do | |
| 291 | + | begin | |
| 292 | + | ProcessNode(iNode, nil); // Recursive | |
| 293 | + | iNode := iNode.NextSibling; | |
| 294 | + | end; | |
| 295 | + | end; | |
| 296 | + | ``` | |
| 297 | + | ||
| 298 | + | ### XML 書類を修正する | |
| 299 | + | ||
| 300 | + | まず、TDOMDocuments は DOM への*ハンドル*であることを覚えてください。このクラスのインスタンスは、インスタンスを作成 (create) してもXML文書をロードしても得ることができます。 | |
| 301 | + | ||
| 302 | + | 一方、ノードは通常のオブジェクトのようには生成することができません。必ず TDOMDocument クラスのメソッドを用いてください。その後、別のメソッドによって、新たに生成したノードをツリーの中の然るべき場所に置きます。これはノードというものがDOMの中の特定の文書によって「所有」される必要があるからです。 | |
| 303 | + | ||
| 304 | + | 以下に、TDOMDocumentのいくつかの普通のメソッドを示します。 | |
| 305 | + | ||
| 306 | + | ``` pascal | |
| 307 | + | function CreateElement(const tagName: DOMString): TDOMElement; virtual; | |
| 308 | + | function CreateTextNode(const data: DOMString): TDOMText; | |
| 309 | + | function CreateCDATASection(const data: DOMString): TDOMCDATASection; | |
| 310 | + | virtual; | |
| 311 | + | function CreateAttribute(const name: DOMString): TDOMAttr; virtual; | |
| 312 | + | ``` | |
| 313 | + | ||
| 314 | + | 次は、選択されたアイテムを TTreeView の中に置き、そのツリーが表す XML 文書の中に子ノードを挿入するメソッドの例です。[[Networking|XML2Tree function]] によってあらかじめ XML の全ての内容を TreeView に含めておく必要があります。 | |
| 315 | + | ||
| 316 | + | ``` pascal | |
| 317 | + | procedure TForm1.actAddChildNode(Sender: TObject); | |
| 318 | + | var | |
| 319 | + | position: Integer; | |
| 320 | + | NovoNo: TDomNode; | |
| 321 | + | begin | |
| 322 | + | // 選択された要素を発見する | |
| 323 | + | if TreeView1.Selected = nil then Exit; | |
| 324 | + | ||
| 325 | + | if TreeView1.Selected.Level = 0 then | |
| 326 | + | begin | |
| 327 | + | position := TreeView1.Selected.Index; | |
| 328 | + | ||
| 329 | + | NovoNo := XMLDoc.CreateElement('item'); | |
| 330 | + | TDOMElement(NovoNo).SetAttribute('nome', 'Item'); | |
| 331 | + | TDOMElement(NovoNo).SetAttribute('arquivo', 'Arquivo'); | |
| 332 | + | with XMLDoc.DocumentElement.ChildNodes do | |
| 333 | + | begin | |
| 334 | + | Item[position].AppendChild(NovoNo); | |
| 335 | + | Free; | |
| 336 | + | end; | |
| 337 | + | ||
| 338 | + | // TreeView を更新する | |
| 339 | + | TreeView1.Items.Clear; | |
| 340 | + | XML2Tree(TreeView1, XMLDoc); | |
| 341 | + | end | |
| 342 | + | else if TreeView1.Selected.Level >= 1 then | |
| 343 | + | begin | |
| 344 | + | {******************************************************************* | |
| 345 | + | * この手続きはツリーの最初のレベルでしかうまく働かないが、 | |
| 346 | + | * ツリーの全ての深さに適用できるよう改造するのは容易である。 | |
| 347 | + | *******************************************************************} | |
| 348 | + | end; | |
| 349 | + | end; | |
| 350 | + | ``` | |
| 351 | + | ||
| 352 | + | ### TXMLDocument を一つの文字列から生成する | |
| 353 | + | ||
| 354 | + | MyXmlString がある XML ファイルの内容を含んだものだとすると、次のコードによって DOM を生成することができます。 | |
| 355 | + | ||
| 356 | + | ``` pascal | |
| 357 | + | Var | |
| 358 | + | S : TStringStream; | |
| 359 | + | XML : TXMLDocument; | |
| 360 | + | ||
| 361 | + | begin | |
| 362 | + | S:= TStringStream.Create(MyXMLString); | |
| 363 | + | Try | |
| 364 | + | S.Position:=0; | |
| 365 | + | XML:=Nil; | |
| 366 | + | ReadXMLFile(XML,S); // Complete XML document | |
| 367 | + | // Alternatively: | |
| 368 | + | ReadXMLFragment(AParentNode,S); // Read only XML fragment. | |
| 369 | + | Finally | |
| 370 | + | S.Free; | |
| 371 | + | end; | |
| 372 | + | end; | |
| 373 | + | ``` | |
| 374 | + | ||
| 375 | + | ### 文書の検証 | |
| 376 | + | ||
| 377 | + | 2007年3月以降、DTDの有効性を検証する機能が FCL XMLパーザに加わっています。文書の論理構造があらかじめ定義された *Document Type Definition* (DTD) と呼ばれる規則に則っている場合、有効です。 | |
| 378 | + | ||
| 379 | + | 次は DTD 付きの XML 文書の例です: | |
| 380 | + | ||
| 381 | + | ``` xml | |
| 382 | + | <?xml version='1.0'?> | |
| 383 | + | <!DOCTYPE root [ | |
| 384 | + | <!ELEMENT root (child)+ > | |
| 385 | + | <!ELEMENT child (#PCDATA)> | |
| 386 | + | ]> | |
| 387 | + | <root> | |
| 388 | + | <child>This is a first child.</child> | |
| 389 | + | <child>And this is the second one.</child> | |
| 390 | + | </root> | |
| 391 | + | ``` | |
| 392 | + | ||
| 393 | + | この DTD はルートとなる要素が一つまたは複数の「子」ををち、それらの「子」は内部に文字データのみを持っていることを示しています。パーザが何か違反を発見した場合、レポートされます。 | |
| 394 | + | ||
| 395 | + | この種の文書をロードするのは若干複雑になっています。TStream オブジェクトに XML データが含まれているとしましょう: | |
| 396 | + | ||
| 397 | + | ``` pascal | |
| 398 | + | procedure TMyObject.DOMFromStream(AStream: TStream); | |
| 399 | + | var | |
| 400 | + | Parser: TDOMParser; | |
| 401 | + | Src: TXMLInputSource; | |
| 402 | + | TheDoc: TXMLDocument; | |
| 403 | + | begin | |
| 404 | + | // パーザオブジェクトを生成する | |
| 405 | + | Parser := TDOMParser.Create; | |
| 406 | + | // 入力ソースオブジェクトも | |
| 407 | + | Src := TXMLInputSource.Create(AStream); | |
| 408 | + | // 検証しなくちゃ | |
| 409 | + | Parser.Options.Validate := True; | |
| 410 | + | // 報告を受け取るためのエラーハンドラを関連づける | |
| 411 | + | Parser.OnError := @ErrorHandler; | |
| 412 | + | // やっと仕事ができる | |
| 413 | + | Parser.Parse(Src, TheDoc); | |
| 414 | + | // ...後始末もできる。 | |
| 415 | + | Src.Free; | |
| 416 | + | Parser.Free; | |
| 417 | + | end; | |
| 418 | + | ||
| 419 | + | procedure TMyObject.ErrorHandler(E: EXMLReadError); | |
| 420 | + | begin | |
| 421 | + | if E.Severity = esError then // 検査エラー以外関心がない | |
| 422 | + | writeln(E.Message); | |
| 423 | + | end; | |
| 424 | + | ``` | |
| 425 | + | ||
| 426 | + | ### XML ファイルを生成する | |
| 427 | + | ||
| 428 | + | 以下に、 XML ファイルを書き出すコードを示します。 (これは、DeveLazarus ブログのチュートリアルから転載しています)。 Uses 節に DOM と XMLWrite を追加することを忘れないでください。 | |
| 429 | + | ||
| 430 | + | ``` pascal | |
| 431 | + | unit Unit1; | |
| 432 | + | ||
| 433 | + | {$mode objfpc}{$H+} | |
| 434 | + | ||
| 435 | + | interface | |
| 436 | + | ||
| 437 | + | uses | |
| 438 | + | Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, | |
| 439 | + | DOM, XMLWrite; | |
| 440 | + | ||
| 441 | + | type | |
| 442 | + | { TForm1 } | |
| 443 | + | TForm1 = class(TForm) | |
| 444 | + | Button1: TButton; | |
| 445 | + | Label1: TLabel; | |
| 446 | + | Label2: TLabel; | |
| 447 | + | procedure Button1Click(Sender: TObject); | |
| 448 | + | private | |
| 449 | + | { private declarations } | |
| 450 | + | public | |
| 451 | + | { public declarations } | |
| 452 | + | end; | |
| 453 | + | ||
| 454 | + | var | |
| 455 | + | Form1: TForm1; | |
| 456 | + | ||
| 457 | + | implementation | |
| 458 | + | ||
| 459 | + | { TForm1 } | |
| 460 | + | ||
| 461 | + | procedure TForm1.Button1Click(Sender: TObject); | |
| 462 | + | var | |
| 463 | + | xdoc: TXMLDocument; // 文書を格納する変数 | |
| 464 | + | RootNode, parentNode, nofilho: TDOMNode; // ノードを格納する変数 | |
| 465 | + | begin | |
| 466 | + | //文書を作成する | |
| 467 | + | xdoc := TXMLDocument.create; | |
| 468 | + | ||
| 469 | + | //ルートノードを作成する | |
| 470 | + | RootNode := xdoc.CreateElement('register'); | |
| 471 | + | Xdoc.Appendchild(RootNode); // ルートノードを保存する | |
| 472 | + | ||
| 473 | + | //親ノードを作成する | |
| 474 | + | RootNode:= xdoc.DocumentElement; | |
| 475 | + | parentNode := xdoc.CreateElement('usuario'); | |
| 476 | + | TDOMElement(parentNode).SetAttribute('id', '001'); // 親ノードを示す属性を作成する | |
| 477 | + | RootNode.Appendchild(parentNode); // 親ノードを保存する | |
| 478 | + | ||
| 479 | + | //子ノードを作成する | |
| 480 | + | parentNode := xdoc.CreateElement('nome'); // 子ノードを一つ作成する | |
| 481 | + | //TDOMElement(parentNode).SetAttribute('sexo', 'M'); // 属性を作成する | |
| 482 | + | nofilho := xdoc.CreateTextNode('Fernando'); // ノードに値を挿入する | |
| 483 | + | parentNode.Appendchild(nofilho); // ノードを保存する | |
| 484 | + | RootNode.ChildNodes.Item[0].AppendChild(parentNode); // 子ノードをそれぞれの親ノードに挿入する | |
| 485 | + | ||
| 486 | + | //子ノードを作成する | |
| 487 | + | parentNode := xdoc.CreateElement('idade'); // 子ノードを一つ作成する | |
| 488 | + | //TDOMElement(parentNode).SetAttribute('ano', '1976'); // 性を作成する | |
| 489 | + | nofilho := xdoc.CreateTextNode('32'); // ノードに値を挿入する | |
| 490 | + | parentNode.Appendchild(nofilho); // ノードを保存する | |
| 491 | + | .ChildNodes.Item[0].AppendChild(parentNode); // 子ノードをそれぞれの親ノードに挿入する | |
| 492 | + | ||
| 493 | + | writeXMLFile(xDoc,'teste.xml'); // XML に書く | |
| 494 | + | Xdoc.free; // メモリを解放する | |
| 495 | + | end; | |
| 496 | + | ||
| 497 | + | initialization | |
| 498 | + | {$I unit1.lrs} | |
| 499 | + | ||
| 500 | + | end. | |
| 501 | + | ``` | |
| 502 | + | ||
| 503 | + | 結果、書き出される XML ファイルは以下のようになります。: | |
| 504 | + | ||
| 505 | + | ``` xml | |
| 506 | + | <?xml version="1.0"?> | |
| 507 | + | <register> | |
| 508 | + | <usuario id="001"> | |
| 509 | + | <nome>Fernando</nome> | |
| 510 | + | <idade>32</idade> | |
| 511 | + | </usuario> | |
| 512 | + | </register> | |
| 513 | + | ``` | |
| 514 | + | ||
| 515 | + | また、以下にアイテムの番号による参照が不要な例を示します。 | |
| 516 | + | ||
| 517 | + | ``` pascal | |
| 518 | + | procedure TForm1.Button2Click(Sender: TObject); | |
| 519 | + | var | |
| 520 | + | Doc: TXMLDocument; | |
| 521 | + | RootNode, ElementNode,ItemNode,TextNode: TDOMNode; | |
| 522 | + | i: integer; | |
| 523 | + | begin | |
| 524 | + | try | |
| 525 | + | // TXML ドキュメント を生成 | |
| 526 | + | Doc := TXMLDocument.Create; | |
| 527 | + | // Create a root node | |
| 528 | + | RootNode := Doc.CreateElement('Root'); | |
| 529 | + | Doc.Appendchild(RootNode); | |
| 530 | + | RootNode:= Doc.DocumentElement; | |
| 531 | + | // ノード を生成 | |
| 532 | + | for i := 1 to 20 do | |
| 533 | + | begin | |
| 534 | + | ElementNode:=Doc.CreateElement('Element'); | |
| 535 | + | TDOMElement(ElementNode).SetAttribute('id', IntToStr(i)); | |
| 536 | + | ||
| 537 | + | ItemNode:=Doc.CreateElement('Item1'); | |
| 538 | + | TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i)); | |
| 539 | + | TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i)); | |
| 540 | + | TextNode:=Doc.CreateTextNode('Item1Value is '+IntToStr(i)); | |
| 541 | + | ItemNode.AppendChild(TextNode); | |
| 542 | + | ElementNode.AppendChild(ItemNode); | |
| 543 | + | ||
| 544 | + | ItemNode:=Doc.CreateElement('Item2'); | |
| 545 | + | TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i)); | |
| 546 | + | TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i)); | |
| 547 | + | TextNode:=Doc.CreateTextNode('Item2Value is '+IntToStr(i)); | |
| 548 | + | ItemNode.AppendChild(TextNode); | |
| 549 | + | ElementNode.AppendChild(ItemNode); | |
| 550 | + | ||
| 551 | + | RootNode.AppendChild(ElementNode); | |
| 552 | + | end; | |
| 553 | + | // XML を保存 | |
| 554 | + | WriteXMLFile(Doc,'TestXML_v2.xml'); | |
| 555 | + | finally | |
| 556 | + | Doc.Free; | |
| 557 | + | end; | |
| 558 | + | ``` | |
| 559 | + | ||
| 560 | + | 生成される XML は以下のとおりです。: | |
| 561 | + | ||
| 562 | + | ``` xml | |
| 563 | + | <?xml version="1.0"?> | |
| 564 | + | <Root> | |
| 565 | + | <Element id="1"> | |
| 566 | + | <Item1 Attr1="1" Attr2="1">Item1Value is 1</Item1> | |
| 567 | + | <Item2 Attr1="1" Attr2="1">Item2Value is 1</Item2> | |
| 568 | + | </Element> | |
| 569 | + | <Element id="2"> | |
| 570 | + | <Item1 Attr1="2" Attr2="2">Item1Value is 2</Item1> | |
| 571 | + | <Item2 Attr1="2" Attr2="2">Item2Value is 2</Item2> | |
| 572 | + | </Element> | |
| 573 | + | <Element id="3"> | |
| 574 | + | <Item1 Attr1="3" Attr2="3">Item1Value is 3</Item1> | |
| 575 | + | <Item2 Attr1="3" Attr2="3">Item2Value is 3</Item2> | |
| 576 | + | </Element> | |
| 577 | + | </Root> | |
| 578 | + | ``` | |
| 579 | + | ||
| 580 | + | ### エンコーディング | |
| 581 | + | ||
| 582 | + | FPC version 2.4 から、 XML reader is able to process data in any encoding by using external decoders. 詳細は [[XML Decoders/ja]] を見てください。 | |
| 583 | + | ||
| 584 | + | XML の標準では、 XML の最初の行のエンコーディング属性は必須ではありません。いても置かなくてもかまいません。 | |
| 585 | + | ||
| 586 | + | 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). | |
| 587 | + | ||
| 588 | + | 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 コンポーネントでは最初の行のエンコーディング属性は無視されます。 | |
| 589 | + | ||
| 590 | + | - FPC 2.4 doesn´t generate an encoding attribute in the first line of the XML file | |
| 591 | + | - 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. | |
| 592 | + | ||
| 593 | + | ## 以下もご参照ください | |
| 594 | + | ||
| 595 | + | - [[XML Decoders|XML デコーダ]] | |
| 596 | + | - [[Using INI Files|INI ファイルを使う]] | |
| 597 | + | - [[fcl-xml]] | |
| 598 | + | - [[Internet Tools]], for XPath 2 / XQuery processing | |
| 599 | + | ||
| 600 | + | ## 外部リンク | |
| 601 | + | ||
| 602 | + | - [W3Schools](http://www.w3schools.com/xml/default.asp) XML のチュートリアル | |
| 603 | + | - [Thomas Zastrow article](http://www.thomas-zastrow.de/texte/fpcxml/index.php) [Alternate link](http://web.archive.org/web/20080802150722/http://www.thomas-zastrow.de/texte/fpcxml/index.php) FPC と XML | |
| 604 | + | ||
| 605 | + | --- | |
| 606 | + | *From the Free Pascal wiki, page "XML Tutorial/ja", as it stood on 2020-03-02 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
