??xml version="1.0" encoding="utf-8" standalone="yes"?>
Z都很喜欢 XML 以及它所提供的灵zL和互操作性,但是Q通过使用一些技巧,可以使与 XML 的互操作和与 XML 一起用的工具更加单。在处理 XML 时养成一些良好的习惯可以保证最高效地利用您?XML 文档和应用程序?/p>
![]() ![]() |
![]()
|
以下?10 U最良好?XML 习惯Q?/p>
![]() ![]() |
![]()
|
![]() |
|
在快速创?XML 文档Ӟ一般都会們于创建基本的l构q开一些普?XML 文需求,包括指定 XML 文声明?XML 文包含的数据的~码cd?
考虑清单 1 所C的 XML 文?/p>
清单 1. 未包?XML 声明和数据编码类型的 XML 文
<phrases> <phrase lang="en">Hello</phrase> <phrase lang="it">Buongiorno</phrase> <phrase lang="fr">Salut!</phrase> </phrases> |
对于普通h来说Q可以查看该文q将其识别ؓ XMLQ但是对于计机来说Q则很难作出q样的判断。在文g剙d XML 声明Q可以它更加明、更Ҏ识别。一行简单的代码可以说明文档是 XMLQƈ且指出版本号?XML 数据使用的字W编码类型。例如:
<?xml version="1.0" encoding="us-ascii"?> |
~码说明中的内容也应该确保正性。XML 解析器用编码确?XML 文的单个字W被正确载入。例如,l箋 清单 1 中基于短语的CZQ如果向文d一个俄语条目,则会出现问题Q因为目前指定的~码不支持扩展的字符集(使用俄语短语表示 hello 时要求用扩展字W集Q?/p>
指定错误的编码意味着解析器不能正处理文;例如Q如果将一个多字节扩展字符dZ个单字节l成的序列,那么会导致数据的损坏和不良输出?
![]() ![]() |
![]()
|
d?XML 声明后,应该保使用 DTD ?XSD 定义有效?XML 文g的结构。这两种Ҏ都允?XML 解析器检查ƈ定 XML 文g的内容与建模数据对应的结构相匚w?/p>
例如Q给Z个针对联p(contactQ数据库的简?XML l构Q您希望定义一U结构来指定联系人的姓名、地址和电话号码。?DTD Ҏ可以使您映射q种l构q确保结构中的每一个联pMh与布局相匹配?
例如Q清?2 中显CZ针对联系数据库的 DTD?
<!ELEMENT phone (#PCDATA)> <!ATTLIST phone type (home | work | mobile) #REQUIRED> <!ELEMENT contact (#PCDATA | name | phone | address)*> <!ELEMENT contacts (#PCDATA | contact)*> <!ELEMENT country (#PCDATA)> <!ELEMENT road (#PCDATA)> <!ELEMENT address (#PCDATA | road | city | state | postcode | country)*> <!ATTLIST address type (home | work) #REQUIRED> <!ELEMENT state (#PCDATA)> <!ELEMENT name (#PCDATA)> <!ELEMENT postcode (#PCDATA)> <!ELEMENT city (#PCDATA)> |
DTD 定义了描q联pMh所需要的元素、属性(以及q些属性所支持的|。例如,?清单 2 可以看到Qphone 元素有一?type 属性,?address 和其中的 component 元素也有属性?
使用 DTD 可以帮助保属性的有效性,q且Q和验证q程一起用时可以识别M问题。当和支?XML 的编辑器一起用时QDTD 可以帮助~辑和自动完成内宏V?/p>
XSDsQ即模式Q可以执行很多与 DTD 相同的功能,但有其独特的用途。例如,一?XML ~辑器需要?DTD 自动完成内容Q然而模式在设计文档实际层次l构斚w更加灉|。您可以Ҏ具体环境选择工具?/p>
![]() ![]() |
![]()
|
查看清单 3Q能否找出其中的问题Q?/p>
清单 3. 验证CZ
<contacts> <contact> <name>Martin</name> <phone type="home">123 456 7890</phone> <phone type="mobile">123 456 7890</phone> <phone type="work">123 456 7890</phone> <address type="home"> <road>Home road</road> <city>Home city</city> <state>Home state</state> <zipcode>12434</zipcode> <country>USA</country> </address> </contact> <contact> <name>Sharon</name> <phone type="work">234 567 8901</phone> <phone>234 567 8901</phone> <address type="home"> <road>Other home road</road> <city>Other city</city> <state>Other state</state> <zipcode>39487</zipcode> <country>USA</country> </address> <address type="work> <road>Work building, work road</road> <city>Work city</city> <state>Work state</state> <zipcode>12347</zipcode> <country>USA</country> </address> </contact> </contacts> |
手动查找问题非常ȝ。但是可以通过 xmllintQ一Ƒ֏以检?XML 文g的内容和l构的免费工Pq行文gQ您可以查看q行该文件的输出Q如清单 4 所C?
$ xmllint contacts.xml contacts.xml:27: parser error : Unescaped '<' not allowed in attributes values <road>Work building, work road</road> ^ contacts.xml:27: parser error : attributes construct error <road>Work building, work road</road> ^ contacts.xml:27: parser error : Couldn't find end of Start Tag address line 26 <road>Work building, work road</road> ^ contacts.xml:32: parser error : Opening and ending tag mismatch: contact line 15 and address </address> ^ contacts.xml:33: parser error : Opening and ending tag mismatch: contacts line 1 and contact </contact> ^ contacts.xml:34: parser error : Extra content at the end of the document </contacts> |
管与最初的问题Q其中的一个属性没有结束)相比g复杂了很多,但却为您查找问题提供了一个v炏V?
xmllint q支持各U各L命o行选项Q帮助选择诊断Ҏ和结果。其中最有用的一个选项?--noout
Q它L xmllint 在解析文件时回传内容。对于较短的文g来说没有什么媄响,但对于大型文件来说则是一个问题?
如果正在使用 DTDQ那么?--postvalid
选项告诉 xmllint 针对 DTD 验证内容Q确保内容不仅是有效?XMLQ而且q与 DTD 的结构相匚w。如果将 使用 DTD ?XSD ?contact 文g生成?DTD d到文Ӟ那么属性定义错误将被纠正,但随后将生成一个不同的错误Q如清单 5 所C?
$ xmllint --noout --postvalid contacts.xml contacts.xml:9: element address: validity error : Element zipcode is not declared in address list of possible children contacts.xml:21: element address: validity error : Element zipcode is not declared in address list of possible children contacts.xml:28: element address: validity error : Element zipcode is not declared in address list of possible children Document contacts.xml does not validate |
q样使用 xmllint 可以方便快捷地确定文的l构是否有效。xmllint ?libxml2 工具q一部分Q该工具已l定?Linux、UNIX® ?Mac OS XQ但 Windows® 需要独立下载。有?xmllint ?libxml2 的更多信息,请参?参考资?/a>?/p>
![]() ![]() |
![]()
|
使用 xmllint 和类似工具验?XML 文gQ特别是如果使用?DTDQ,是验?XML 文g内容的很好方法。然而,q种Ҏ也有其局限性。例如,如何处理 XML 文g的内容?
使用 DTD ?XSDQ您可以为属性指定明的内容。您只是创徏了带有一个字W串?ID 的属性(可以是受限制的可用选项列表的一部分Q,但是不能使用q种方式控制或限制元素的内容?
例如Q在联系人示例中Qtelephone numbers 元素包含数字和空根{但是没办法L用户向该元素d字母字符。这样做在?xmllint q行验证时不会检查出错误Qƈ且编辑器和其他支?XML 的解x案也无法解决或识别这个问题。应用程序出现的故障可能和您预料的一P因ؓ它识别出一个非标准数据cd?
而言之,XML 验证只能保证l构正确Q而无法保证数据的有效性?
解决此问题的最单方法是~写一个解析器Q它可以d XML 文gq实际验证数据内宏V但是不要过度地验证内容Q只需保数据W合应用E序的要求?
![]() ![]() |
![]()
|
对于I竟是用属性还是元素来描述希望?XML 文g中呈现的信息Qh们存在着不同的看法?/p>
一般的做法是,使用元素Q即标记之间的数据)定义文g包含的信息,而属性则用于提供所描述数据的扩展限制?/p>
元素和属性都各有弊端。例如,属性不能够在标C重复Q这是元素优于属性的典型例子。元素支持重复信息的能力使其非常实用。相反,使用元素限制数据有时处理h会比较复杂?/p>
联系人示例中的电话号码很好地解释了属性的优点。在q个CZ中,如清?6 所C,使用属性限制电话号码的cdQ例如办公、住宅或Ud电话Q?
<phone type="home">123 456 7890</phone> <phone type="mobile">123 456 7890</phone> <phone type="work">123 456 7890</phone> |
使用q种l构Q能够轻村֜把号码作Z个整体(忽略属性)Q或者挑选特定的电话LcdQ用属性)?
此l构与清?7 中只使用元素设计的结构进行比较?/p>
清单 7. 只用元素限制电话号?/strong>
<phone> <type>home</type> <number>123 456 7890</number> </phone> <phone> <type>mobile</type> <number>123 456 7890</number> </phone> <phone> <type>work</type> <number>123 456 7890</number> </phone> |
现在q很隑ֈ断孰优孰劣。尽从理论上说M XML 解析器或适当?XPath 定义都可以把您需要的信息抽取出来。但q样做获益不大,q且使得 XML 文很难阅读?/p>
![]() ![]() |
![]()
|
在处?XML 数据Ӟ查找需要的信息非常复杂。您可以~写一个解析器来挑选需要的信息Q但在某些情况下Q您只需要快速地扑ֈ文g中的一段信息?/p>
例如Q如果需要从联系?XML 文g中提出所有国家的列表Q以便查看联pMh在全球的分布范围Q那么可以?XPath 来挑选信息?/p>
通过?XML 文g的结构作为查询的一部分QXPath 使您能够?XML 文g中抽取数据。例如,通过提供特定元素?XML 文g中的路径Q您可以提取该元素的数据Q?
$ xpath contacts.xml '//contact/address/country' |
您可以按照下面这样分析内容:
注意Q在q个CZ中,您限定了从中选择信息的地址的类型,因此选择所有地址。您可以在清?8 中查?XPath 查询的结果?/p>
清单 8. XPath 查询的结?/strong>
$ xpath contacts.xml '//contact/address/country' Found 3 nodes: -- NODE -- <country>USA</country>-- NODE -- <country>USA</country>-- NODE -- <country>USA</country> |
如果需要挑选更具体的数据,可以指定要匹配的元素或属性的内容。例如,如果只选择手机LQ您需要指定属性类型和倹{ؓ此,使用Q@Q符P它表C您要求搜烦一个属性,然后指定需要匹配的|参加清单 9 Q?/p>
清单 9. 只选择手机L
$ xpath contacts.xml '//contact/phone[@type="mobile"]' Found 1 nodes: -- NODE -- <phone type="mobile">123 456 7890</phone> |
清单 8 ?9 都用了一个命令行工具。很?XML 工具都提供了原生方法来处理 XPath 元素Qƈ且您可以使用 XPath 规范提取数据在应用程序中直接使用Q而不需要用解析器来获取信息?/p>
![]() ![]() |
![]()
|
管有些意想不到Q但您ƈ一定需要用一U功能完善的 XML 解析器,使用 SAX、DOM 或其他技术(?XPath ?XQueryQ从 XML 文g中提取需要的信息?/p>
XML 文g使用l构化的格式包含数据Q但是有时您需要信息用自w的l构化格式。要快速查找一个信息片D|Q通常可以使用更简单的解决Ҏ?
通常Q您仅需使用 grep、Perl 或其他类似工h取所需的数据,而不需要以 XML 文g的Ş式实际解释文的l构或内宏V?/p>
例如Q您可以使用 grep 选择电话LQ参见清?10Q?/p>
清单 10. 使用 grep 选择电话L
$ grep '<phone' contacts.xml <phone type="home">123 456 7890</phone> <phone type="mobile">123 456 7890</phone> <phone type="work">123 456 7890</phone> <phone type="work">234 567 8901</phone> <phone>234 567 8901</phone> |
您?grep 选择了需要的信息Qƈ且不需要考虑信息?XML 格式或者信息的l构?/p>
如果需要查扄短的信息片段Q简化的处理技术可以查扑ֈ所需的信息,q且避免了用传l解析方法的开销?
![]() ![]() |
![]()
|
当ؓ文构徏一个解析器以获得所需信息Ӟ常常很难军_何时使用Z SAX 的处理程序,何时使用Z DOM 的处理程序?
关于q个问题的最单解x法是同时考虑文的复杂性和所查找信息的用途。如果要转换文Q或者文档非常大Q那?SAX 是最佳选择?
SAX 逐个解析文档元素Q在识别元素时调用方法或函数。如果将一?XML 文转换为另一U格式,例如?XML 转换?HTMLQ那?SAX 是最有效的方式。您不必整个文加入到内存中,只需响应被识别出的元素和l构?
SAX 的缺ҎQ如果需要保存或记录l构Q或者理解整个文ƈ从其中挑选单个元素(例如Q从所有记录中选择单个联系人)Q则必须构徏复杂的处理程序,以加载数据ƈ数据记录到l构中,然后元素标识到输出目标中?
![]() ![]() |
![]()
|
DOM 可以整个文及其结构蝲入到内存Qƈ允许您在应用E序内部引用和?XML 文档的结构。如在联pMhCZ中,您可以将整个联系人数据库d内存Q然后通过遍历联系人选择所有的电话LQ接着在每个联pMh内部遍历每个电话L?
׃ DOM 保留了结构,更重要的是可以理解和处理l构Q您可以L地对l构q行整体或单独的处理。仍然以联系人示例ؓ例,使用 SAX 插入新的联系人将非常复杂。但是如果?DOMQ您只需一个表C新联系人的?XML 元素插入到现有的 XML 文档?
DOM 的缺h使用方式处理文??例如Q{换ؓ HTML ?q于复杂Q因为必dl构内逐个遍历每个元素来处理文?
此外Q由?DOM 在解析其间将整个 XML 文档载入到内存中QDOM 解析器会变得非常慢ƈ且需要更多的内存。但 DOM 处理q样做也有一些好处;例如Q在一ơ解析过E中Q可以对使用 DOM 解析?XML 文档q行多次处理。而?SAXQ则需要多ơ重复解析过E才能获得相同的效果?
讉K 参考资?/a>Q查找更多关于?DOM ?SAX 的信息?/p>
![]() ![]() |
![]()
|
如果l常需要编写和使用 XMLQ那么必L有一个良好的 XML ~辑器。XML ~辑器不同于标准的文本编辑器Q前者可以理?XML 的结构和布局。XML ~辑器提供的丰富Ҏ处理 XML 更加单,q些Ҏ包括:
好的 XML ~辑器包?Eclipse ?oXygenXMLQ但是还有很多其他选择?
![]() ![]() |
![]()
|
L良好?XML 处理习惯Q一切将大有不同Q包括利?XML 提供的功能、打?XML 标准q行验证的基知识以及正确处理解析。本文可以帮助您学习q?10 个好习惯Q从而提高处?XML 文和数据的效率?/p>