XML 的使用越来越广泛,但是很多 XML 的结构并不好。即便结构良好,也常常设计得很糟,使得处理和维护非常困难。而大部分用于 XML 的基础结构使问题更加恶化。于是出现了关于 XML 最佳实践的公开讨论,比如 Henri Sivonen 的文章“HOWTO Avoid Being Called a Bozo When Producing XML”。Uche Ogbuji 经常在 IBM developerWorks 上讨论 XML 最佳实践,这里他提出了在这些文章中讨论的要点。
几年来我一直在本专栏和其他系列文章中讨论 XML 最佳实践。其他人,比如和我同行的专栏作家 Elliotte Rusty Harold 也谈到这个问题。参加 XML 设计原则讨论的 XML 专家越好越好,这样社区就会对在不同层次上采用 XML 的开发人员提供一致的建议。本文将结合最新和过去的文章,更详细地介绍了 XML 最佳实践。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)不再有笨蛋
Henri Sivonen 撰写了一篇有用的文章“HOWTO Avoid Being Called a Bozo When Producing XML”(请参阅参考资料)。他采用了基于 XML 的 Web 提要格式(如 RSS 和 Atom)的观点,提出了用名称空间生成结构良好的 XML 应该做和不应该做哪些事情的指南。正如他在简介中所说的:
有些开发人员似乎认为以编程方式生成 XML 而保持结构良好非常困难(如果不是不可能的话),另一些开发人员却能够做到这一点,并奇怪其他人为什么如此无能。我假设没有人愿意显得无能或者被点名。因此,我希望下列建议能够帮助开发人员从第一类人转变成第二类人。
Henri 给出的第一条建议是“不要将 XML 看作是文本格式”,我认为这是一条危险的建议。当然其基本观点是正确的 —— 不能像简单的文本文档那样随心所欲的生成和编辑 XML,但是这种要求适用于所有有结构的文本格式。但是,说 XML 不是文本就背弃了 XML 一个最重要的特点,而这点在规范的 XML 定义中被奉为圭臬。(“文本对象是结构良好的 XML 文档[如果符合本规范]”。) Henri 的提法也让人糊涂,因为有关于 XML 文本的技术定义,大致上是将它解释为 XML 的字符序列。文本不仅仅是叶子元素或者属性中的主要成分 —— 技术上称这类文本为字符数据。文本还是所有 XML 实体的主要成分,因此说 XML 不是文本是自相矛盾的。我认为强调 XML 和开发人员已经熟悉的文本格式的区别会更有意义。
上面的评述表明,Henri 的建议可能由于过分关心生成结构良好的 Web 提要的问题而有些偏激。警告人们简单的堆砌字符串,期望它成为结构良好的 XML 的做法是危险的,这一点上他是正确的。我也在文章中建议人们使用成熟的 XML 工具箱而不是使用简单的文本工具来创建 XML(请参阅参考资料)。我疑虑的是 Henri 描述这个建议的方式有点混乱,在更广泛的 XML 处理上下文中会造成误解。他在“Don't use text-based templates”和“Don't print”两节中反复重申这个观点。我认为可以将他的建议归纳为“不要使用不能保证产生结构良好的 XML 的机制。”这确实是一项很重要的建议。正像 Herni 所提到的,安全创建 XML 的一种方法是发送 SAX 事件,“使用树或栈(或者 XML 解析器)”。但即使这样做也不能令您高枕无忧。使用的 SAX 工具不一定要进行所有必要的结构良好性检查。比如,XML 中禁止某些 Unicode 字符。为了解决这些问题可能需要进行额外的检查。
Henri 建议用户不要尝试手工管理名称空间,这是正确的。我曾经在 developerWorks 上讨论过,必须非常小心地处理 XML 名称空间。他建议开发人员,按照统一名[名称空间统一资源标识符(URI)加上本地名]来考虑一般情况就行了,但有时候不可避免地要面对前缀或者 XML 声明。在 XSLT 这样的规范中,QName(前缀/本地名组合)可在属性值中使用,并假定前缀根据作用范围内的名称空间声明解释。这种模式称为上下文中的 QName。在这种情况下,开发人员必须控制声明的前缀,否则 XML 处理就会失败。如果开发人员管理自己的名称空间声明,由于 XML 名称空间的复杂性,结果往往会显得杂乱无章。
因为经过 XML 处理管道之后名称空间语法可能变得非常混乱,一种解决方法是在管道的最后插入一个规范化步骤。XML 规范化消除了 XML 1.0 和 XML 名称空间允许的各种语法变体,包括不同的名称空间声明方式。规范化不能消除使名称空间声明对开发人员变得危险的所有问题。规范化也不能解决上下文中的 QName 问题,因为它并没有改变文档中使用的前缀,但它确实可以减轻名称空间声明的混乱程度,使您很容易确定问题所在,甚至可以编写代码自动纠正这些问题。GenX 库是 Henri 建议使用的 XML 创建工具之一,能够自动生成规范的 XML,其他很多工具箱也作为选项提供了规范化功能。
Henri 关于 Unicode 和字符处理的建议基本上是完全正确的。不过我认为“Avoid adding pretty-printing white space in character data”一节有点夸大其词。多数情况下,元素之间而不是带有字符数据的元素内部的精细打印是安全的。如 Henri 所述,清单 1 所示的如果以清单 2 的形式呈现通常是不安全的。
清单 1. XML 例子
foobar/foo
清单 2. 在字符数据中增加空白后的 XML 例子
foo
bar
/foo
但通常以清单 3 的形式打印 XML 是安全的,输出结果如清单 4 所示。
清单 3. 另一个 XML 例子
docfoobar/foo/doc
清单 4. 清单 3 中的 XML 在字符数据中增加了空格
doc
foobar/foo
/doc
很多 XML 序列化工具能够理解相对安全和不安全的的打印格式。必须知道的是,如果在混合内容中增加空格,则清单 3 和 4 中所示的精细打印形式可能造成扭曲。如果使用模式制导的序列化,则可以避免这类问题。但在实践中,使用混合内容的多数词汇表对空白规范化没有这么敏感,因此不用过于担心精细打印。应该充分了解该问题,并知道没有办法关闭精细打印(最好默认不用精细打印)。Henri 提出了清单 5 所示的精细打印实践,但是我不同意,因为我认为那些难看的标记不容易理解。
清单 5. Henri Sivonen 建议但本文作者不同意的精细打印方式
foo
bar/foo
修道院的建议
现在换换档,本文要探讨的第二篇资料是 Simon St. Laurent 撰写的“Monastic XML”(请参阅参考资料)。这是一组小短文,围绕着如何充分利用 XML 而就处理和思考 XML 提出了一些建议。Simon 使用修道院和禁欲主义作为比喻,提出为 XML 增加不适应其简单文本根 (textual root) 的过多负担是危险的。 在“Marking-up at the foundation”中,他讨论了字符数据和标记(元素和属性)的本质作用。在“Naming things and reading names”中,他解释了为何一般标识符(也称为元素类型名)是一个重要的概念,应该作为标记信息结构的惟一关键成分。理想情况下,如果使用 XML 名称空间,关键就是统一名称(名称空间 URI 加上本地名),这种复杂化就是 Simon 在“Namespaces as opportunity”中厉声疾呼的原因之一。“Accepting the discipline of trees”揭示了 XML 一个不幸的秘密:尽管看起来 XML 的层次结构很容易扩展成图形结构,但实践证明用 XML 建模图有点困难。但目前为止,“Monastic XML”网站上最重要的建议是“优化标记的处理总是不成熟”。XML 是一种声明性技术,对很多开发人员来说,关于它的强大和不足有很多不实之词。那些尽量把 XML 设计和处理细节拉近的开发人员,从长期来看,通常使得处理更加困难。XML 成功的关键是关注需要抽象表示的信息的特点,将它与需要处理这些信息的系统的技术设计分离开来。
结束语
讨论 XML 最佳实践时总是有一些不同的观点,特别是在初期阶段,但听到不同的声音是一件好事。关于这个话题的参考资料很少,我将继续在本专栏中讨论它。如果对最佳实践有什么资料或者建议或者希望分享您的观点,请参加 Thinking XML 论坛上的讨论。