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