级别: 中级 Uche Ogbuji (uche.ogbuji@fourthought.com), 首席顾问, Fourthought, Inc.
2004 年 4 月 01 日 对于困难的问题,XML 名称空间是一种不完善的解决方案。从基本的信息体系结构到 API 的难点,如果使用时不注意,名称空间都可能使您陷入痛苦的泥潭。在本文中,Uche Ogbuji 探讨了一些更重要的设计原则,按照这些原则可以减少名称空间带来的问题。
多数经常使用 XML 的人都非常熟悉 XML 名称空间,并将其看作 XML 的一个基本组成部分。偶然遇到名称空间的奇怪行为时,他们只是摇摇头,通常不再在深加思考。但是在 XML 专家中,从第一天起 XML 名称空间就颇受争议。争议的理由很充分:名称空间解决了一种困难问题,但只是解决这种问题的方法之一,每种方法各有长短。W3C XML 名称空间是一种折衷方案,像所有折衷一样,通常难以满足每个用户的需要。即使过了这么长时间,要把名称空间无缝集成到 XML 信息体系结构中也被证明是很困难的,而且没有考虑名称空间对 XML 处理工具带来的很多复杂问题。本文将讨论一些设计技巧,有助于避免使用 XML 名称空间造成的这类问题。所建议的指导原则一般使用黑体表示。
本文将介绍 XML namespaces 1.0(包括所有的勘误表)。XML namespaces 1.1 在修订时加了很多细节,这是一个全新的规范,还没有得到很好的工具支持。我认为 XML namespaces 1.1 很快会成为标准(和 XML 1.1 不同,比方说,后者很难说会真正成为标准)。
基本原则
XML 名称空间机制包括几个活动的部分:本地名、名称空间 URI、前缀和声明。有效使用名称空间最重要的一步是学习如何保持这些成分的条理性。
本地名
名称空间的目的是能够在每个上下文中对每个元素或属性使用最简洁的名称,然后把这些名称放在区分不同上下文的名称空间中。名称中简洁的、只需在自身上下文中保持唯一的那一部分称为
本地名。一定要利用可以辨别的上下文,
不要在本地名中重复名称空间本身中固有的那些信息。比如,不需要在 XHTML 名称空间中把链接元素的本地名设成
xhtml-link 。因为这是 XHTML 名称空间中已有的信息,只需要使用
link 就可以了。由于历史的原因,XHTML 规范在命名根元素
html 时违背了这一原则,本来可以更名为
document 的。
名称空间 URI
名称空间是采用
URI 语法的字符串(常常不必要的称为“名称空间 URI”)。名称空间是元素或属性名完整的一部分。本地名和名称空间的组合称为
通用名。为了强调名称空间的重要性,XML
先驱 James Clark 为通用名开发了一种符号,强调名称空间与本地名的基本绑定(请参阅
参考资料)。比如,本地部分为
customer 、名称空间为
http://uche.ogbuji.net/eg/ns
的通用名,用 Clark 的符号表示就是
{http://uche.ogbuji.net/eg/ns}customer 。
选择名称空间 URI 很重要。使用 URL 还是 URN 哪种更好是争论的焦点之一。前者的好处是人们非常熟悉,但是人们也常常创建没有对应资源的名称空间 URL,就是说如果浏览相应的 URL 就会得到 404 “未找到”的错误信息。URN 的好处是不鼓励人们尝试在浏览器中查看它们。
如果在
URL 上精心放置对读者有用的某种文档,则对名称空间使用 URL。我建议在对应名称空间的 URL 上放置 RDDL 1.0 文档(请参阅
参考资料),除非采用更专门的约定。比如,在
RDF/XML 文档中,作为 URL 解析时名称空间通常指向 RDF 模式文档。URN 有很多类(URN 的类正式名称也是“名称空间”,不要与 XML 名称空间混淆)。假设不愿意使用 URL,
如果公司有管理和解析相应
URN 类的机制则使用 URN。URN 名称空间的例子包括
oid (ISO 批准的为网络节点分配数字编码标识符的系统)和
publicid (SGML 和 XML 中定义的正式公共标识符实体)。
前缀
在 XML 文档中指定通用名时,使用
前缀(可选)附加本地名的缩写形式。这种缩写称为
限定名或者
qname。前缀是可选的,因为有一种特殊的语法形式允许指定
默认名称空间,默认名称空间与没有前缀的 qname 关联。前缀
完全 是一种语法上的便利,一般而言实际上并不属于
XML 语言设计中的问题,仅仅是作者或者工具偏好的问题。我称这类问题为
实例细节,在这些文章中,按我的设计经验,只有设计者不得不考虑这类问题时才会触及到。我建议
对名称空间使用人所共知的前缀,但永远不要强制性使用任何前缀。
在创建文档时为名称空间选择人们熟知的前缀,但是
在阅读文档时接受任何选用的名称空间前缀。
名称空间声明
名称空间声明是在 XML 文档中把前缀分配给名称空间的语法设施。从技术上讲这是一种实例细节,但是它如此重要,我专门用一小节(参见
后述)说明名称空间声明的指导原则。
名称空间的使用和演变
一些设计者最初并没有使用名称空间,后来当认为需要混合使用词汇表时才开始采用名称空间。考虑到名称空间的微妙性,这种小心谨慎的方法是合理的。问题在于因为名称空间是
XML 名称的基本成分,这种变化可能比您所认识到的更加显著。它需要工具和其他相关资料中的广泛变动。您可以采用其他方式解决名称冲突的问题。除了名称空间之外,最主要的方法是基于
SGML
结构表的思想,名称直接在结构表中声明,一旦发生冲突可以使用工具修改。设想一下
XML 设计以后开发的难度,决定是否要处理名称冲突以及如何处理。我同意对 XML 名称空间的许多批评,也非常希望有更加清晰的、得到工具很好支持的一种机制。由于实践的原因,这些天几乎在所有的
XML 设计中我一直使用名称空间。
决定何时演化或者区分名称空间也很困难。名称空间可能用于标识版本,或者区分域中的概念。决定什么时候这样做的关键是要记住名称空间是名字的一部分。只有在希望对每个元素和属性的定义进行真正的、本质的区别时才改变或者区分名称空间。如果版本的变化明显地改变了
XML 词汇表中名称的含义,改变名称空间可能就是合适的。否则应使用其他的版本标识机制,比如在顶层元素中增加版本属性。
在一个域中使用名称空间进行区分的不足最好通过一个例子来说明。1999 年,XHTML 1.0 成为最终的建议标准。它实际上仅仅是 HTML 4.01 上的一个 XML 变体,有三种不同的 DTD:严格、过渡和框架集。XHTML 工作组决定对应 XHTML DTD 使用三个不同的名称空间。这一决策引起了
XML 社区的强烈反响。主要的问题是尽管存在三个不同的 DTD,但彼此之间每个元素的意义并没有很大的差异,XHTML 过渡 DTD 中的
code
元素和 XHTML 严格 DTD 中的
code 元素含义基本相同。根据情况的变化改变名字,XHTML 的设计违背了这一点。最后,XHTML
工作组发布了新的规范,在整个 XHTML 1.0 域内使用单一名称空间,从而纠正了这一问题。您应该很好地注意这一教训。
只有在命名的事物存在真正的区别时才在
XML 名称空间中加以区分。
不幸的是,事物很少有绝对的。新版本的词汇表增加新元素是一种很常见的情况。继续保留的元素含义可能不会改变,因此改变名称空间似乎是不妥的。但是如果使用过去的名称空间,向原来名称空间中的新词汇表添加元素似乎也不妥当。仅仅为新元素使用不同的名称空间几乎肯定是不合理的选择。最终,您只能运用自己的判断力决定词汇表的名称空间是否要演变。关于名称空间的一些诀窍也许能够提供其他的选择(使用名称空间区分版本的有关技巧,请参阅
参考资料),但使用这些技巧也必须小心谨慎。
Joe English 关于名称空间的精神健康的比喻
XML 名称空间声明是
有界的,就是说声明的前缀(或者默认名称空间)仅对声明所出现的元素(及其后代元素)有效,除非另有一个名称空间覆盖了它。但是,这种灵活性可能对处理造成一些问题。Joe English 是一位在 Advanced Rotorcraft Technology, Inc. 工作的 XML 专家,他以使用精神健康的比喻来解释这些问题而知名,我把他的比喻复制在下面(原文请参阅
参考资料)。下面是我建议避免使用名称空间的应用模式。
在一篇
精神恍惚的文档中(大概是指 Borderline Personality Disorder),有多个前缀映射到同一个名称空间:
<org>
<a:employee xmlns:a='urn:bogus:ns'>EP</a:employee>
<b:employee xmlns:b='urn:bogus:ns'>TSE</b:employee>
</org>
|
而在一篇
神经错乱的文档中,同一个前缀则用于多个名称空间:
<h:memo xmlns:a='urn:bogus:ns'>
<h:body xmlns:a='http://www.w3.org/1999/xhtml'>
Now hear <h:i>this</h:i>
</h:body>
</h:memo>
|
根据我的经验,这种用法通常是因为作者想在一定程度上避免使用前缀。比如下面的例子,说它神经错乱是因为默认名称空间随着文档中的不同位置而变化:
<memo xmlns='urn:bogus:ns'>
<body xmlns='http://www.w3.org/1999/xhtml'>
Now hear <i>this</i>
</body>
</memo>
|
在一篇
发神经的文档中,同一作用域围内为同一名称空间声明了两个不同的前缀:
<org xmlns:a='urn:bogus:ns' xmlns:b='urn:bogus:ns'>
<a:employee>EP</a:employee>
<b:employee>TSE</b:employee>
</org>
|
如果所有的名称空间声明都在根元素中,而且没有为同一名称空间声明两个不同的前缀,这样的文档称为是
名称空间规范的:
<memo xmlns='urn:bogus:ns' xmlns:html='http://www.w3.org/1999/xhtml'>
<html:body>
Now hear <html:i>this</html:i>
</html:body>
</memo>
|
避免神经恍惚、神经错乱和发神经的文档。尽可能保持文档名称空间的规范性,因为这样最容易阅读和处理。
结束语
XML 名称空间表面上看起来似乎很简单,但如果使用的时候漫不经心,细微之处就隐藏着真正的复杂和笨拙。在使用名称空间设计词汇表和创建真正的实例文档时,一定要深入理解组成 XML 名称空间各种概念的意义、规则和内涵,并始终坚持简单的惯例。
参考资料
关于作者
对本文的评价
|