XML Tutorial/zh CN: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: XML Tutorial/zh CN
| Old | New | Line | |
|---|---|---|---|
| 1 | + | 可扩展标记语言(XML)是一个世界万维网组织([W3C](http://www.w3.org/))推荐的在不同系统间交换信息的语言。 | |
| 2 | + | ||
| 3 | + | 它是一种基于文本的信息储存方式,而不是直接基于二进制数据。 | |
| 4 | + | ||
| 5 | + | 许多现代的电子数据交换语言,比如XHTML,包括世界上最流行的网络技术都是基于XML的。这篇WIKI只能给出一些关于XML极短的描述,主要的关注点在如何在Pascal中使用XML文件,如果你对XML十分感兴趣,你可以访问[XML的维基百科](http://zh.wikipedia.org/wiki/XML) | |
| 6 | + | ||
| 7 | + | ## 介绍 | |
| 8 | + | ||
| 9 | + | 目前,有一大堆的单元提供Pascal中的XML支持,这些单元包括 "XMLRead","XMLWrite"和"DOM",他们是FPC中免费组件库(FCL)的一部分,FCL已经包括在Lazarus编译器的单元搜索路径中了,所以你只需要在uses中加上要使用的单元名就可以获得XML的支持。FCL的文档并不完整(至少在2005年10月),所以这篇简短的教程将将把侧重点放在如何使用这些单元上。 | |
| 10 | + | ||
| 11 | + | XML DOM(文档对象模型)是一些在不同语言与系统中提供了相似XML支持的标准对象,这个标准只描述了方法、属性和其他一些对象的接口,把具体的实现交给了各种语言。FCL完全支持[XML DOM 2.0](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/)以及它的子集[XML DOM 3.0](http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/)列出的[[dom|这些内容]]. | |
| 12 | + | ||
| 13 | + | ## 使用范例 | |
| 14 | + | ||
| 15 | + | 下面有一些从简单到复杂的XML操作示例。 | |
| 16 | + | ||
| 17 | + | ### 在Uses中引用的单元:Unicode或Ansi | |
| 18 | + | ||
| 19 | + | FPC带来的XML单元通常使用ANSI编码所以在任何一个平台上编码都有可能不同,可能不是Uniocde。 Lazarus带来另一个单独的XML单元且在所有平台都完全支持UTF-8。这些单元是互相兼容而且可以通过修改Uses来进行切换。 | |
| 20 | + | ||
| 21 | + | FPC中使用系统编码的字符串XML支持单元: | |
| 22 | + | ||
| 23 | + | - DOM | |
| 24 | + | - XMLRead | |
| 25 | + | - XMLWrite | |
| 26 | + | - XMLCfg | |
| 27 | + | - XMLUtils | |
| 28 | + | - XMLStreaming | |
| 29 | + | ||
| 30 | + | Lazarus中完全使用UTF-8 Unicode的XML支持单元: | |
| 31 | + | ||
| 32 | + | - laz2_DOM | |
| 33 | + | - laz2_XMLRead | |
| 34 | + | - laz2_XMLWrite | |
| 35 | + | - laz2_XMLCfg | |
| 36 | + | - laz2_XMLUtils | |
| 37 | + | - laz_XMLStreaming | |
| 38 | + | ||
| 39 | + | 然而,并不是在每个实例中都需要其中所有的单元,你需要DOM单元因为它定义了很多的类型包括TXMLDocument。 | |
| 40 | + | ||
| 41 | + | ### 读取一个XML节点 | |
| 42 | + | ||
| 43 | + | 致Delphi程序员: | |
| 44 | + | ||
| 45 | + | 请注意使用TXMLDocument时,节点中的文本被囊括在独立的TEXT节点中,所以,你必须作为单独的节点访问一个节点的文本值。 另外,"TextContent"属性可以检索在一个节点中所有的文本节点并衔接在一起。 | |
| 46 | + | ||
| 47 | + | **ReadXMLFile**过程总是创建一个新的**TXMLDocument**对象,所以你不必预先创建,但是,当你使用完后请牢记使用**Free**过程释放XML文档。 | |
| 48 | + | ||
| 49 | + | 例如,思考下面的XML文档: | |
| 50 | + | ||
| 51 | + | ``` xml | |
| 52 | + | <?xml version="1.0"?> | |
| 53 | + | <request> | |
| 54 | + | <request_type>PUT_FILE</request_type> | |
| 55 | + | <username>123</username> | |
| 56 | + | <password>abc</password> | |
| 57 | + | </request> | |
| 58 | + | ``` | |
| 59 | + | ||
| 60 | + | 下面的代码同时展示了正确与错误的获取文本值得方式:(添加**laz2_XMLRead**与**laz2_DOM** 到uses列表) | |
| 61 | + | ||
| 62 | + | ``` pascal | |
| 63 | + | var | |
| 64 | + | PassNode: TDOMNode; | |
| 65 | + | Doc: TXMLDocument; | |
| 66 | + | begin | |
| 67 | + | try | |
| 68 | + | // 从磁盘读取XML文档 | |
| 69 | + | ReadXMLFile(Doc, 'test.xml'); | |
| 70 | + | // 获取Password节点 | |
| 71 | + | PassNode := Doc.DocumentElement.FindNode('password'); | |
| 72 | + | // 输出节点的值 | |
| 73 | + | WriteLn(PassNode.NodeValue); // 将会输出空白 | |
| 74 | + | // 节点的文本值在独立的子节点中 | |
| 75 | + | WriteLn(PassNode.FirstChild.NodeValue); // 正确地输出 "abc" | |
| 76 | + | // 另一种选择 | |
| 77 | + | WriteLn(PassNode.TextContent); | |
| 78 | + | finally | |
| 79 | + | // 最后,释放XML文档 | |
| 80 | + | Doc.Free; | |
| 81 | + | end; | |
| 82 | + | end; | |
| 83 | + | ``` | |
| 84 | + | ||
| 85 | + | 请注意ReadXMLFile在解析时忽略所有空白字符,空白字符类目将会教授你如何保留它们 | |
| 86 | + | ||
| 87 | + | ### 输出每一个节点和属性的名字 | |
| 88 | + | ||
| 89 | + | 如果你希望浏览DOM树: 当你需要访问序列中的节点, 最好的方法是使用 **FirstChild** 和 **NextSibling** 属性 (从第一个节点向后访问), 或者 **LastChild** 和 **PreviousSibling** (从最后的节点向前访问). | |
| 90 | + | ||
| 91 | + | 如果想随机的访问节点,应该使用 **ChildNodes** 或者 **GetElementsByTagName** 方法, 但这样需要创建一个TDOMNodeList 对象,并且这个对象最终必须被释放. 由于 FCL 的DOM实现是基于对象的,而不是基于接口的,所以这和其它的DOM实现,如MSXML,是有区别的. | |
| 92 | + | ||
| 93 | + | 下面的示例演示了如何将节点的名称显示在一个 TMemo 控件中. | |
| 94 | + | ||
| 95 | + | 名为'test.xml'的 XML文件如下: | |
| 96 | + | ||
| 97 | + | ``` xml | |
| 98 | + | <?xml version="1.0"?> | |
| 99 | + | <images directory="mydir"> | |
| 100 | + | <imageNode URL="graphic.jpg" title=""> | |
| 101 | + | <Peca DestinoX="0" DestinoY="0">Pecacastelo.jpg1.swf</Peca> | |
| 102 | + | <Peca DestinoX="0" DestinoY="86">Pecacastelo.jpg2.swf</Peca> | |
| 103 | + | </imageNode> | |
| 104 | + | </images> | |
| 105 | + | ``` | |
| 106 | + | ||
| 107 | + | 示例Pascal代码如下: | |
| 108 | + | ||
| 109 | + | ``` pascal | |
| 110 | + | var | |
| 111 | + | Doc: TXMLDocument; | |
| 112 | + | Child: TDOMNode; | |
| 113 | + | j: Integer; | |
| 114 | + | begin | |
| 115 | + | try | |
| 116 | + | ReadXMLFile(Doc, 'test.xml'); | |
| 117 | + | Memo.Lines.Clear; | |
| 118 | + | // 使用FirstChild和NextSibling属性 | |
| 119 | + | Child := Doc.DocumentElement.FirstChild; | |
| 120 | + | while Assigned(Child) do | |
| 121 | + | begin | |
| 122 | + | Memo.Lines.Add(Child.NodeName + ' ' + Child.Attributes.Item[0].NodeValue); | |
| 123 | + | // 使用 ChildNodes方法 | |
| 124 | + | with Child.ChildNodes do | |
| 125 | + | try | |
| 126 | + | for j := 0 to (Count - 1) do | |
| 127 | + | Memo.Lines.Add(format('%s %s (%s=%s; %s=%s)', | |
| 128 | + | [ | |
| 129 | + | Item[j].NodeName, | |
| 130 | + | Item[j].FirstChild.NodeValue, | |
| 131 | + | Item[j].Attributes.Item[0].NodeName, // 第1个属性值 | |
| 132 | + | Item[j].Attributes.Item[0].NodeValue, | |
| 133 | + | Item[j].Attributes.Item[1].NodeName, // 第2个属性值 | |
| 134 | + | Item[j].Attributes.Item[1].NodeValue | |
| 135 | + | ])); | |
| 136 | + | finally | |
| 137 | + | Free; | |
| 138 | + | end; | |
| 139 | + | Child := Child.NextSibling; | |
| 140 | + | end; | |
| 141 | + | finally | |
| 142 | + | Doc.Free; | |
| 143 | + | end; | |
| 144 | + | end; | |
| 145 | + | ``` | |
| 146 | + | ||
| 147 | + | 在TMemo显示结果如下: | |
| 148 | + | ||
| 149 | + | imageNode graphic.jpg | |
| 150 | + | Peca Pecacastelo.jpg1.swf (DestinoX=0; DestinoY=0) | |
| 151 | + | Peca Pecacastelo.jpg2.swf (DestinoX=0; DestinoY=86) | |
| 152 | + | ||
| 153 | + | ### 将树状图转化为XML | |
| 154 | + | ||
| 155 | + | XML文件的一种常见的用法是将其解析并将内容显示为树状图形式. 在Lazarus中,你可以在"Common Controls"控件页中找到TTreeView控件. 下面的函数将一个先前加载的或代码生成的XML文档的内容生成对应的树状图TreeView. 每个节点的标题作为该节点的第一个属性内容. | |
| 156 | + | ||
| 157 | + | ``` pascal | |
| 158 | + | procedure TForm1.XML2Tree(tree: TTreeView; XMLDoc: TXMLDocument); | |
| 159 | + | var | |
| 160 | + | iNode: TDOMNode; | |
| 161 | + | ||
| 162 | + | procedure ProcessNode(Node: TDOMNode; TreeNode: TTreeNode); | |
| 163 | + | var | |
| 164 | + | cNode: TDOMNode; | |
| 165 | + | s: string; | |
| 166 | + | begin | |
| 167 | + | if Node = nil then Exit; // 如果到达树末端,则停止 | |
| 168 | + | ||
| 169 | + | // 添加节点到树 | |
| 170 | + | if Node.HasAttributes and (Node.Attributes.Length>0) then | |
| 171 | + | s := Node.Attributes[0].NodeValue | |
| 172 | + | else | |
| 173 | + | s := ''; | |
| 174 | + | TreeNode := tree.Items.AddChild(TreeNode, s); | |
| 175 | + | ||
| 176 | + | // 转到子节点 | |
| 177 | + | cNode := Node.FirstChild; | |
| 178 | + | ||
| 179 | + | // 处理所有子节点 | |
| 180 | + | while cNode <> nil do | |
| 181 | + | begin | |
| 182 | + | ProcessNode(cNode, TreeNode); | |
| 183 | + | cNode := cNode.NextSibling; | |
| 184 | + | end; | |
| 185 | + | end; | |
| 186 | + | ||
| 187 | + | begin | |
| 188 | + | iNode := XMLDoc.DocumentElement.FirstChild; | |
| 189 | + | while iNode <> nil do | |
| 190 | + | begin | |
| 191 | + | ProcessNode(iNode, nil); // 递归 | |
| 192 | + | iNode := iNode.NextSibling; | |
| 193 | + | end; | |
| 194 | + | end; | |
| 195 | + | ``` | |
| 196 | + | ||
| 197 | + | 另一个示例显示完整的XML结构,包括所有属性值(注: 为了使代码在本wiki中的易读,对TreeView的相关的长行引用将被断行处理; 你在书写代码时不必进行断行操作,除非你喜欢这种风格) : | |
| 198 | + | ||
| 199 | + | ``` pascal | |
| 200 | + | procedure XML2Tree(XMLDoc:TXMLDocument; TreeView:TTreeView); | |
| 201 | + | ||
| 202 | + | // 输出全部节点属性到一个字符串的函数 | |
| 203 | + | function GetNodeAttributesAsString(pNode: TDOMNode):string; | |
| 204 | + | var i: integer; | |
| 205 | + | begin | |
| 206 | + | Result:=''; | |
| 207 | + | if pNode.HasAttributes then | |
| 208 | + | for i := 0 to pNode.Attributes.Length -1 do | |
| 209 | + | with pNode.Attributes[i] do | |
| 210 | + | Result := Result + format(' %s="%s"', [NodeName, NodeValue]); | |
| 211 | + | ||
| 212 | + | // 移除首尾的空格 | |
| 213 | + | Result:=Trim(Result); | |
| 214 | + | end; | |
| 215 | + | ||
| 216 | + | // 通过递归函数处理节点及其全部子节点 | |
| 217 | + | ||
| 218 | + | procedure ParseXML(Node:TDOMNode; TreeNode: TTreeNode); | |
| 219 | + | begin | |
| 220 | + | // 如果已无节点需要处理,则退出过程 | |
| 221 | + | if Node = nil then Exit; | |
| 222 | + | ||
| 223 | + | // 添加节点到TreeView | |
| 224 | + | TreeNode := TreeView.Items.AddChild(TreeNode, | |
| 225 | + | Trim(Node.NodeName+' '+ | |
| 226 | + | GetNodeAttributesAsString(Node)+ | |
| 227 | + | Node.NodeValue) | |
| 228 | + | ); | |
| 229 | + | ||
| 230 | + | // 处理全部子节点 | |
| 231 | + | Node := Node.FirstChild; | |
| 232 | + | while Node <> Nil do | |
| 233 | + | begin | |
| 234 | + | ParseXML(Node, TreeNode); | |
| 235 | + | Node := Node.NextSibling; | |
| 236 | + | end; | |
| 237 | + | end; | |
| 238 | + | ||
| 239 | + | begin | |
| 240 | + | TreeView.Items.Clear; | |
| 241 | + | ParseXML(XMLDoc.DocumentElement,nil); | |
| 242 | + | end; | |
| 243 | + | ``` | |
| 244 | + | ||
| 245 | + | ### 修改一个XML文档 | |
| 246 | + | ||
| 247 | + | 首先要记住的是,TDOMDocument是DOM的“句柄”。你可以实例化这个类,创建或加载一个XML文档。 | |
| 248 | + | ||
| 249 | + | Nodes on the other hand cannot be created like a normal object. You *must* use the methods provided by TDOMDocument to create them, and later use other methods to put them in the correct place in the tree. This is because nodes must be "owned" by a specific document in DOM. ~~另一方面节点不能像正常对象一样被创建。你*必须*使用TDOMDocument提供的方法来创建它们,~~ | |
| 250 | + | ||
| 251 | + | 下面是TDOMDocument中常用的方法: | |
| 252 | + | ||
| 253 | + | ``` pascal | |
| 254 | + | function CreateElement(const tagName: DOMString): TDOMElement; virtual; | |
| 255 | + | function CreateTextNode(const data: DOMString): TDOMText; | |
| 256 | + | function CreateCDATASection(const data: DOMString): TDOMCDATASection; virtual; | |
| 257 | + | function CreateAttribute(const name: DOMString): TDOMAttr; virtual; | |
| 258 | + | ``` | |
| 259 | + | ||
| 260 | + | `CreateElement` 创建新元素。 | |
| 261 | + | ||
| 262 | + | `CreateTextNode` 创建文本节点。 | |
| 263 | + | ||
| 264 | + | `CreateAttribute` 创建属性节点。 | |
| 265 | + | ||
| 266 | + | `CreateCDATASection` 创建 CDATA 数据: regular XML markup characters such as \<\> are not interpreted within the CDATA section. 查看 [CDATA维基百科](https://en.wikipedia.org/wiki/CDATA) | |
| 267 | + | ||
| 268 | + | 操作属性更方便的方法是使用 `TDOMElement.SetAttribute` , 这也表示为`TDOMElement`的默认属性: | |
| 269 | + | ||
| 270 | + | ``` pascal | |
| 271 | + | // 这两条语句是等价的 | |
| 272 | + | Element.SetAttribute('name', 'value'); | |
| 273 | + | Element['name'] := 'value'; | |
| 274 | + | ``` | |
| 275 | + | ||
| 276 | + | And here an example method that will locate the selected item on a TTreeView and then insert a child node to the XML document it represents. The TreeView must be previously filled with the contents of an XML file using the [[Networking|XML2Tree function]]. | |
| 277 | + | ||
| 278 | + | ``` pascal | |
| 279 | + | procedure TForm1.actAddChildNode(Sender: TObject); | |
| 280 | + | var | |
| 281 | + | position: Integer; | |
| 282 | + | NovoNo: TDomNode; | |
| 283 | + | begin | |
| 284 | + | {******************************************************************* | |
| 285 | + | * Detects the selected element | |
| 286 | + | *******************************************************************} | |
| 287 | + | if TreeView1.Selected = nil then Exit; | |
| 288 | + | ||
| 289 | + | if TreeView1.Selected.Level = 0 then | |
| 290 | + | begin | |
| 291 | + | position := TreeView1.Selected.Index; | |
| 292 | + | ||
| 293 | + | NovoNo := XMLDoc.CreateElement('item'); | |
| 294 | + | TDOMElement(NovoNo).SetAttribute('nome', 'Item'); | |
| 295 | + | TDOMElement(NovoNo).SetAttribute('arquivo', 'Arquivo'); | |
| 296 | + | with XMLDoc.DocumentElement.ChildNodes do | |
| 297 | + | begin | |
| 298 | + | Item[position].AppendChild(NovoNo); | |
| 299 | + | Free; | |
| 300 | + | end; | |
| 301 | + | ||
| 302 | + | {******************************************************************* | |
| 303 | + | * Updates the TreeView | |
| 304 | + | *******************************************************************} | |
| 305 | + | TreeView1.Items.Clear; | |
| 306 | + | XML2Tree(TreeView1, XMLDoc); | |
| 307 | + | end | |
| 308 | + | else if TreeView1.Selected.Level >= 1 then | |
| 309 | + | begin | |
| 310 | + | {******************************************************************* | |
| 311 | + | * This function only works on the first level of the tree, | |
| 312 | + | * but can easily be modified to work for any number of levels | |
| 313 | + | *******************************************************************} | |
| 314 | + | end; | |
| 315 | + | end; | |
| 316 | + | ``` | |
| 317 | + | ||
| 318 | + | ### 从字符串创建TXMLDocument | |
| 319 | + | ||
| 320 | + | 给定一个存放在字符串变量*MyXmlString*中的XML文档, 以下代码将创建对应的DOM: | |
| 321 | + | ||
| 322 | + | ``` pascal | |
| 323 | + | var | |
| 324 | + | S: TStringStream; | |
| 325 | + | XML: TXMLDocument; | |
| 326 | + | begin | |
| 327 | + | S := TStringStream.Create(MyXMLString); | |
| 328 | + | try | |
| 329 | + | // Read complete XML document | |
| 330 | + | ReadXMLFile(XML, S); | |
| 331 | + | // Alternatively: read only an XML Fragment | |
| 332 | + | ReadXMLFragment(AParentNode, S); | |
| 333 | + | finally | |
| 334 | + | S.Free; | |
| 335 | + | end; | |
| 336 | + | end; | |
| 337 | + | ``` | |
| 338 | + | ||
| 339 | + | ### 验证一个XML文档 | |
| 340 | + | ||
| 341 | + | Since March 2007, DTD validation facility has been added to the FCL XML parser. Validation is checking that logical structure of the document conforms to the predefined rules, called *Document Type Definition* (DTD). | |
| 342 | + | ||
| 343 | + | Here is an example of XML document with a DTD: | |
| 344 | + | ||
| 345 | + | ``` xml | |
| 346 | + | <?xml version='1.0'?> | |
| 347 | + | <!DOCTYPE root [ | |
| 348 | + | <!ELEMENT root (child)+ > | |
| 349 | + | <!ELEMENT child (#PCDATA)> | |
| 350 | + | ]> | |
| 351 | + | <root> | |
| 352 | + | <child>This is a first child.</child> | |
| 353 | + | <child>And this is the second one.</child> | |
| 354 | + | </root> | |
| 355 | + | ``` | |
| 356 | + | ||
| 357 | + | This DTD specifies that 'root' element must have one or more 'child' elements, and that 'child' elements may have only character data inside. If parser detects any violations from these rules, it will report them. | |
| 358 | + | ||
| 359 | + | Loading such document is slightly more complicated. Let's assume we have XML data in a TStream object: | |
| 360 | + | ||
| 361 | + | ``` pascal | |
| 362 | + | procedure TMyObject.DOMFromStream(AStream: TStream); | |
| 363 | + | var | |
| 364 | + | Parser: TDOMParser; | |
| 365 | + | Src: TXMLInputSource; | |
| 366 | + | TheDoc: TXMLDocument; | |
| 367 | + | begin | |
| 368 | + | try | |
| 369 | + | // create a parser object | |
| 370 | + | Parser := TDOMParser.Create; | |
| 371 | + | // and the input source | |
| 372 | + | Src := TXMLInputSource.Create(AStream); | |
| 373 | + | // we want validation | |
| 374 | + | Parser.Options.Validate := True; | |
| 375 | + | // assign a error handler which will receive notifications | |
| 376 | + | Parser.OnError := @ErrorHandler; | |
| 377 | + | // now do the job | |
| 378 | + | Parser.Parse(Src, TheDoc); | |
| 379 | + | // ...and cleanup | |
| 380 | + | finally | |
| 381 | + | Src.Free; | |
| 382 | + | Parser.Free; | |
| 383 | + | end; | |
| 384 | + | end; | |
| 385 | + | ||
| 386 | + | procedure TMyObject.ErrorHandler(E: EXMLReadError); | |
| 387 | + | begin | |
| 388 | + | if E.Severity = esError then // we are interested in validation errors only | |
| 389 | + | writeln(E.Message); | |
| 390 | + | end; | |
| 391 | + | ``` | |
| 392 | + | ||
| 393 | + | ### 空字符 | |
| 394 | + | ||
| 395 | + | If you want to preserve leading whitespace characters in node texts, the above method is the way to load your XML document. Leading whitespace characters are ignored by default. That is the reason why the ReadXML(...) function never returns any leading whitespace characters in node texts. Before calling *Parser.Parse(Src, TheDoc)* insert the line | |
| 396 | + | ||
| 397 | + | ``` pascal | |
| 398 | + | Parser.Options.PreserveWhitespace := True; | |
| 399 | + | ``` | |
| 400 | + | ||
| 401 | + | This will force the parser to return all whitespace characters. This includes all the newline characters that exist in an XML document to make it more readable! | |
| 402 | + | ||
| 403 | + | ### 生成一个XML文件 | |
| 404 | + | ||
| 405 | + | 下面是写入一个XML文件的完整源代码. (来自DeveLazarus博客的一个教程) 请记着在单元的uses段引用 DOM 和 XMLWrite 单元. | |
| 406 | + | ||
| 407 | + | ``` pascal | |
| 408 | + | unit Unit1; | |
| 409 | + | ||
| 410 | + | {$mode objfpc}{$H+} | |
| 411 | + | ||
| 412 | + | interface | |
| 413 | + | ||
| 414 | + | uses | |
| 415 | + | Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, | |
| 416 | + | DOM, XMLWrite; | |
| 417 | + | ||
| 418 | + | type | |
| 419 | + | { TForm1 } | |
| 420 | + | TForm1 = class(TForm) | |
| 421 | + | Button1: TButton; | |
| 422 | + | Label1: TLabel; | |
| 423 | + | Label2: TLabel; | |
| 424 | + | procedure Button1Click(Sender: TObject); | |
| 425 | + | private | |
| 426 | + | { private declarations } | |
| 427 | + | public | |
| 428 | + | { public declarations } | |
| 429 | + | end; | |
| 430 | + | ||
| 431 | + | var | |
| 432 | + | Form1: TForm1; | |
| 433 | + | ||
| 434 | + | implementation | |
| 435 | + | ||
| 436 | + | { TForm1 } | |
| 437 | + | ||
| 438 | + | procedure TForm1.Button1Click(Sender: TObject); | |
| 439 | + | var | |
| 440 | + | Doc: TXMLDocument; // variable to document | |
| 441 | + | RootNode, parentNode, nofilho: TDOMNode; // variable to nodes | |
| 442 | + | begin | |
| 443 | + | try | |
| 444 | + | // Create a document | |
| 445 | + | Doc := TXMLDocument.Create; | |
| 446 | + | ||
| 447 | + | // Create a root node | |
| 448 | + | RootNode := Doc.CreateElement('register'); | |
| 449 | + | Doc.Appendchild(RootNode); // save root node | |
| 450 | + | ||
| 451 | + | // Create a parent node | |
| 452 | + | RootNode:= Doc.DocumentElement; | |
| 453 | + | parentNode := Doc.CreateElement('usuario'); | |
| 454 | + | TDOMElement(parentNode).SetAttribute('id', '001'); // create atributes to parent node | |
| 455 | + | RootNode.Appendchild(parentNode); // save parent node | |
| 456 | + | ||
| 457 | + | // Create a child node | |
| 458 | + | parentNode := Doc.CreateElement('nome'); // create a child node | |
| 459 | + | // TDOMElement(parentNode).SetAttribute('sexo', 'M'); // create atributes | |
| 460 | + | nofilho := Doc.CreateTextNode('Fernando'); // insert a value to node | |
| 461 | + | parentNode.Appendchild(nofilho); // save node | |
| 462 | + | RootNode.ChildNodes.Item[0].AppendChild(parentNode); // insert child node in respective parent node | |
| 463 | + | ||
| 464 | + | // Create a child node | |
| 465 | + | parentNode := Doc.CreateElement('idade'); // create a child node | |
| 466 | + | // TDOMElement(parentNode).SetAttribute('ano', '1976'); // create atributes | |
| 467 | + | nofilho := Doc.CreateTextNode('32'); // insert a value to node | |
| 468 | + | parentNode.Appendchild(nofilho); // save node | |
| 469 | + | RootNode.ChildNodes.Item[0].AppendChild(parentNode); // insert a childnode in respective parent node | |
| 470 | + | ||
| 471 | + | writeXMLFile(Doc, 'test.xml'); // write to XML | |
| 472 | + | finally | |
| 473 | + | Doc.Free; // free memory | |
| 474 | + | end; | |
| 475 | + | end; | |
| 476 | + | ||
| 477 | + | initialization | |
| 478 | + | {$I unit1.lrs} | |
| 479 | + | ||
| 480 | + | end. | |
| 481 | + | ``` | |
| 482 | + | ||
| 483 | + | 结果将生成以下内容的XML文件: | |
| 484 | + | ||
| 485 | + | ``` xml | |
| 486 | + | <?xml version="1.0"?> | |
| 487 | + | <register> | |
| 488 | + | <usuario id="001"> | |
| 489 | + | <nome>Fernando</nome> | |
| 490 | + | <idade>32</idade> | |
| 491 | + | </usuario> | |
| 492 | + | </register> | |
| 493 | + | ``` | |
| 494 | + | ||
| 495 | + | 另一个示例,这里不需要使用索引(index)来访问节点项. | |
| 496 | + | ||
| 497 | + | ``` pascal | |
| 498 | + | procedure TForm1.Button2Click(Sender: TObject); | |
| 499 | + | var | |
| 500 | + | Doc: TXMLDocument; | |
| 501 | + | RootNode, ElementNode,ItemNode,TextNode: TDOMNode; | |
| 502 | + | i: integer; | |
| 503 | + | begin | |
| 504 | + | try | |
| 505 | + | // Create a document | |
| 506 | + | Doc := TXMLDocument.Create; | |
| 507 | + | // Create a root node | |
| 508 | + | RootNode := Doc.CreateElement('Root'); | |
| 509 | + | Doc.Appendchild(RootNode); | |
| 510 | + | RootNode:= Doc.DocumentElement; | |
| 511 | + | // Create nodes | |
| 512 | + | for i := 1 to 20 do | |
| 513 | + | begin | |
| 514 | + | ElementNode:=Doc.CreateElement('Element'); | |
| 515 | + | TDOMElement(ElementNode).SetAttribute('id', IntToStr(i)); | |
| 516 | + | ||
| 517 | + | ItemNode:=Doc.CreateElement('Item1'); | |
| 518 | + | TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i)); | |
| 519 | + | TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i)); | |
| 520 | + | TextNode:=Doc.CreateTextNode('Item1Value is '+IntToStr(i)); | |
| 521 | + | ItemNode.AppendChild(TextNode); | |
| 522 | + | ElementNode.AppendChild(ItemNode); | |
| 523 | + | ||
| 524 | + | ItemNode:=Doc.CreateElement('Item2'); | |
| 525 | + | TDOMElement(ItemNode).SetAttribute('Attr1', IntToStr(i)); | |
| 526 | + | TDOMElement(ItemNode).SetAttribute('Attr2', IntToStr(i)); | |
| 527 | + | TextNode:=Doc.CreateTextNode('Item2Value is '+IntToStr(i)); | |
| 528 | + | ItemNode.AppendChild(TextNode); | |
| 529 | + | ElementNode.AppendChild(ItemNode); | |
| 530 | + | ||
| 531 | + | RootNode.AppendChild(ElementNode); | |
| 532 | + | end; | |
| 533 | + | // Save XML | |
| 534 | + | WriteXMLFile(Doc,'TestXML_v2.xml'); | |
| 535 | + | finally | |
| 536 | + | Doc.Free; | |
| 537 | + | end; | |
| 538 | + | ``` | |
| 539 | + | ||
| 540 | + | 生成的 XML: | |
| 541 | + | ||
| 542 | + | ``` xml | |
| 543 | + | <?xml version="1.0"?> | |
| 544 | + | <Root> | |
| 545 | + | <Element id="1"> | |
| 546 | + | <Item1 Attr1="1" Attr2="1">Item1Value is 1</Item1> | |
| 547 | + | <Item2 Attr1="1" Attr2="1">Item2Value is 1</Item2> | |
| 548 | + | </Element> | |
| 549 | + | <Element id="2"> | |
| 550 | + | <Item1 Attr1="2" Attr2="2">Item1Value is 2</Item1> | |
| 551 | + | <Item2 Attr1="2" Attr2="2">Item2Value is 2</Item2> | |
| 552 | + | </Element> | |
| 553 | + | <Element id="3"> | |
| 554 | + | <Item1 Attr1="3" Attr2="3">Item1Value is 3</Item1> | |
| 555 | + | <Item2 Attr1="3" Attr2="3">Item2Value is 3</Item2> | |
| 556 | + | </Element> | |
| 557 | + | </Root> | |
| 558 | + | ``` | |
| 559 | + | ||
| 560 | + | ### 编码 | |
| 561 | + | ||
| 562 | + | Starting from FPC version 2.4 (more precisely, from SVN revision 12582), XML reader is able to process data in any encoding by using external decoders. See [[XML Decoders]] for more details. | |
| 563 | + | ||
| 564 | + | According to the XML standard, 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). | |
| 565 | + | ||
| 566 | + | TXMLDocument has an encoding property since FPC 2.4. It is ignored as WriteXMLFile always uses UTF-8. | |
| 567 | + | ||
| 568 | + | - FPC 2.4 doesn´t generate an encoding attribute in the first line of the XML file | |
| 569 | + | - 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. | |
| 570 | + | ||
| 571 | + | ## 相关链接 | |
| 572 | + | ||
| 573 | + | - [[XML Decoders]] | |
| 574 | + | - [[Using INI Files]] | |
| 575 | + | - [[fcl-xml]] | |
| 576 | + | - [[Internet Tools]], for XPath 2 / XQuery processing | |
| 577 | + | ||
| 578 | + | ## 扩展链接 | |
| 579 | + | ||
| 580 | + | - [W3Schools](http://www.w3schools.com/xml/default.asp) Xml 教程 | |
| 581 | + | ||
| 582 | + | - [Thomas Zastrow 文章](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 and XML | |
| 583 | + | ||
| 584 | + | --- | |
| 585 | + | *From the Free Pascal wiki, page "XML Tutorial/zh CN", 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).* |
