级别: 初级 David Marston (David_Marston@us.ibm.com), 工程师, IBM Research
2002 年 11 月 01 日 这个两部分的文章介绍了 XML 名称空间,研究了它们实际好处,并向您展示了如何在 W3C 定义的标准 XML 格式和工具中使用它们。在本文(第 2 部分)中,David 向您展示了如何混合 XML 词汇表以及如何定义自己的词汇表,并突出介绍了几种最佳实践。最佳实践包括从术语使用直至系统范围设计在内的各个方面。
注:本文档提到了 2002 年 9 月发布的 Namespaces in XML V1.1 的“ Last Call Working Draft”中提出的更改。
在
第 1 部分中,您了解了万维网联盟(World Wide Web Consortium,W3C)本身如何在使用 XML 时建立引用单元。第 1 部分还提供了用于讨论这个主题一致的术语集。最重要的讨论将是有关构建您自己的 XML 词汇表。
在 XML 中混合名称
与特定名称空间相关联的元素可以拥有属于其它名称空间的子元素和属性。以下是一个示例,其中的数据本身使用了五个名称空间,所有名称空间都有前缀,并且是在这个示例元素之外声明的:
<snac:delivery>
<dc:date>20020717</dc:date>
<snac:recipient>725577</snac:recipient>
<upc:upc1>0-30000-06410-8</upc:upc1>
<snac:size-each>
<snac:value>3</snac:value>
<wm:weight>imperial-ounce</wm:weight>
</snac:size-each>
<snac:quantity>48</snac:quantity>
<snac:invoice-price>
<snac:money-amount>1.54</snac:money-amount>
<fin:currency>us-dollar</fin:currency>
</snac:invoice-price>
</snac:delivery>
|
在本示例中,
snac 名称空间的创建者只定义了那些尚未由其它协会建立的元素。在其设计中,
delivery 元素的日期、UPC 代码、重量和尺寸以及货币名称都依赖于其它名称空间。
或者,您可以将一个名称空间应用为特定的属性,就象这样:
<snac:size-each value="3" wm:weight="imperial-ounce" />
|
构建到 XML 中的支持较少,但您可以将名称空间应用为文本字符串,就象这样:
<snac:size-each value="3" weight="wm:imperial-ounce" />
|
在这个示例中,将
snac:size-each 元素定义为拥有 value 和 weight 属性,后者包含一个来自
wm 字符串枚举列表的字符串,
wm 字符串是重量和尺寸的标准名称。当您想将一个字符串约束成限定名称时,XML 模式(XML Schema)的 QName 数据类型是一个好的选择。(可以命名的其它 XML 项,如处理指令目标和实体,不能拥有用名称空间限定的名称。它们的名称不允许包含冒号,尽管解析器可能不强制执行该规则。)
将名称空间看作一种方法,用来分隔或隔离那些原本看起来有些类似的术语,是一种
最佳实践
。
不要将名称空间仅仅当作相关元素的信息位的载体使用;请将属性用于这种用途。
例如,在某种情况下,一个人尝试处理所有
card 元素,而不管它们是
red:card 、
blue:card 还是其它别的。(已更改元素名称以防出错。)这是对名称空间的滥用,因为不同类型的卡片明显有一些共同点,而前缀会显示出不同类型的卡片根本不相关。颜色应该成为一种属性。
创建自己的名称空间创建自己的名称空间
您可能想开发一个或多个严格地在内部使用的 XML 词汇表。如果只有一个词汇表,您
或许能成功地避免应用名称空间,但
最佳实践
是即使您只有一个自己的词汇表,也要对它应用名称空间。这样做的一个很好的理由是:将来您也许希望引入新版本。(如果您在数据处理中需要一样东西,那就是对于增强的需求!)
应用名称空间仅意味着:您从自己控制的域名中选取了一个 URI,并将该 URI 定义成特定 XML 标记集的名称空间 URI。如果您用系统化的方法来使用标记,那么您可能会有说明每个标记的规则的设计文档;在设计文档中,可应用的名称空间 URI 的定义可能是一两条句子。如果您想以 XML 表达设计和规则,考虑 XML 模式。
URI 管理方面的
最佳实践
是协调在您的域名下的命名,就象您对网络和 Web URL 上的机器名所做的一样。首先,保留一个类似于 http://www.example.com/namespace/ 或 http://namespace.example.com/ 的 URL 作为您域名下的所有名称空间 URI 的根。(提示:如果您的 IS 部门不理解 XML,则请求一台名为“namespace”的机器作为网络的节点,然后将该机器的全限定域名作为名称空间 URI 的根。)在建立了根名称之后,添加额外的字段来指定词汇表名称和版本号。
名称空间允许先开始项目,同时还支持稍后的修改和增强。假定未来会有新的 XML 元素和属性。如果您有多个使用 XML 的项目,它们并行地发展,彼此之间的协调很松散,那么给每个项目一个单独的名称空间。例如,如果一个公司希望在新的 Bill Of Materials 和 Procurement 项目中使用 XML,则可能给它们指定不同的 URI ― http://namespace.example.com/BOM/V1 和 http://namespace.example.com/Procurement/V1。如果设计这两个词汇表的人员想共同使用一些元素,则他们可以选择一个名称空间来保存那些公用项(
最佳实践
),但他们仍可以自由地独立工作。此外,他们可以规划在版本 1(URI 中的“V1”)上使用来自先前非 XML 系统的名称,并且从零开始设计,单独规划“V2”名称。
对于词汇表的每次实际更改(包括添加构成旧词汇表的严格超集的新元素)都改变名称空间 URI,这是一种
最佳实践
。在这种策略下,您可以在任何版本上执行模式验证,甚至可以为最初发布时没有模式的版本新建一个模式。
XML 建议书中的 Namespaces 章节说:标识符可以是“URI 引用”而不仅是 URI。RFC 2396 第 4 部分描述了两者的差异,但
最佳实践
是使用普通 URI。
URI 引用(以及 IRI 引用,在它们开始出现时)可以是相对的,但不推荐将相对 URI 用于名称空间。W3C 似乎开始转变对名称空间 URI 的看法,将它看作不需要根据一些引用框架进行解析的字符串。URI 引用可以在 # 符号后带有片段标识符,但 RFC 明确地限制用片段来检索资料。正如
第 1 部分所描述,名称空间 URI 不是用于检索的。
当编制您自己的 XML 词汇表时,可能需要引用客户、供应商或其它您将要与之交换数据的伙伴的 URI。RFC 2606 中定义的一个
最佳实践
是:在您的文档中对示例使用域名 example.com、example.net 和/或 example.org。
可以更改名称的转换
W3C 要求 XSLT 转换处理器识别和使用名称空间。XSLT 可用来获取特定结构(模式)的 XML,并将它转换成相同结构的 XML,但会更改部分或全部名称。当然,XSLT 也可以重构 XML。当名称更改时,可应用的名称空间也可以更改,如果您有较旧的 XML 需要转换成名称空间不同的较新模式,则这种更改就很有用。当您希望将旧 XML 文档使用的缺省名称空间转换成带前缀的名称空间时,这种更改特别有用。
XSLT 示例
以下是用 XSLT 进行重命名的一些示例。我从一个不涉及名称空间的示例入手,然后扩展成基线示例,以便您理解其中的差异。
如果您想复制 XML 文档,但要更改输入中所有命名为
name_to_change 的元素的名称,则关键模板如下:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<!-- Other templates... -->
<xsl:template match="name_to_change">
<new_name>
<!-- First copy the attributes, then the children. -->
<xsl:copy-of select="@*"/>
<xsl:copy-of select="*"/>
</new_name>
</xsl:template>
</xsl:stylesheet>
|
上述代码假定旧名称和新名称都是未限定的(无名称空间)。可能存在其它变体。
如果您想复制 XML 文档,但要对输入中所有命名为
name_to_change 的元素应用一个名称空间,那么您必须在样式表中声明该名称空间,并使
new_name 与它相关联:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ourspace="http://www.example.com/namespace/data1" >
<!-- Other templates... -->
<xsl:template match="name_to_change">
<ourspace:new_name>
<!-- First copy the attributes, then the children. -->
<xsl:copy-of select="@*"/>
<xsl:copy-of select="*"/>
</ourspace:new_name>
</xsl:template>
</xsl:stylesheet>
|
这次,旧名称是未限定的,但至少这个元素的新名称(
new_name 是名称的本地部分)在新的名称空间(
ourspace 前缀)中。
要复制 XML 文档,但又要将元素的限定名重命名为另一个限定名,您需要匹配输入文档和样式表之间的名称空间 URI。在下例中,输入中所有命名为
zz:name_to_change (其中通过在输入文档中声明 xmlns 将
zz 与 URI“http://example.com/namespace/orders”相关联)的元素都将成为结果中的
ourspace:new_name 元素。请注意,样式表不必知道输入中是使用了
zz 还是其它一些前缀,因为它会将每个文档(输入和样式表)中的前缀单独解析为 URI,然后再匹配 URI。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:theirspace="http://example.com/namespace/orders"
xmlns:ourspace="http://www.fictitious.com/namespace/data/V1"
exclude-result-prefixes="theirspace">
<!-- Other templates... -->
<xsl:template match="theirspace:name_to_change">
<ourspace:new_name>
<!-- First copy the attributes, then the children. -->
<xsl:copy-of select="@*"/>
<xsl:copy-of select="*"/>
</ourspace:new_name>
</xsl:template>
</xsl:stylesheet>
|
为了清理结果,我在
exclude-result-prefixes 列表上指定了来自输入的名称空间,假定该名称空间中的所有元素(以及属性和关键字字符串)都将被重新命名到其它名称空间。这意味着我不需要对结果中的
theirspace 进行声明。
即使样式表提供了供使用的前缀,XSLT 建议书也允许 XSLT 处理器使用它已经构建的前缀。我不知道与任何在不需要时更改前缀的 XSLT 处理器相比,哪种更好。处理器通过提供您所要求的前缀来帮助您遵循这些最佳实践。
正如先前提到的,XSLT 使命名对象只在其样式表内是已知的,对指定元素名称、属性和它所创建的处理指令的能力也是如此。可以对模板命名,而且可以将那些名称限定到名称空间,但模板的名称空间不影响输入或输出 XML 文档。如果输出是 XML,您可以使用样式表中的 exclude-result-prefixes,以使当只在样式表中使用名称空间时,禁止在输出中创建名称空间声明。例如,样式表可能既有
<xsl:template name="system:max"> 又有
<xsl:element name="fin:currency"> ,两者都具有适当的内容。因为
xsl:element 在输出中创建了元素,所以有必要让 XSLT 处理器也为
fin 名称空间创建名称空间声明。实际上,如果需要声明,则 exclude-result-prefixes 不会妨碍创建它。您可以使用 exclude-result-prefixes 来禁止输出中的
system 名称空间,如果它是严格地用于模板名称的话。
最佳实践摘要
规划您的名称空间
- 建立符合逻辑而又一致的前缀名称以促进开发人员的生产力。
- 各处都使用前缀,或者至少在除了传送到最终用户的实际内容之外的所有项上使用它们。
- 要对您自己的词汇表应用名称空间,哪怕只有一个词汇表。
- 将名称空间看作一种方法,用来分隔或隔离那些原本看起来有些类似的术语。
- 在设计两个有一些公共元素的词汇表时,选择一个名称空间(可以独立于两个原始的名称空间)保存公共项。
- 将 HTTP URL 用于您的 URI,但不带片段标识符。
- 协调您域名下的 URI 命名,就象您对网络和 Web URL 上的机器名所做的一样。
- 对于词汇表的每次实际更改(包括添加构成旧词汇表的严格超集的新元素)都改变名称空间 URI。
XML 文档中的用法
- 如有可能,在系统中的所有 XML 文档中通篇使用一个前缀。
- 在每个文档中显式地声明名称空间,减少假设和相关性。
- 如果可能,将所有名称空间的声明都编排到文档元素的开始标记中。
- 对于 W3C 定义的元素和属性,使用 W3C 所用的前缀。
- 使用
xml:lang 属性来声明元素的内容使用某种特定的自然语言。
文档编制和会话式用法
- 当讨论开始标记中的项时,将“namespace declaration”与“attribute”区别对待。
- 避免使用术语“namespace name”或仅在您清楚其意义的上下文中使用它。
- 在您的文档中对示例使用域名 example.com、example.net 或 example.org。
参考资料
关于作者  | |  | David Marston 自 1998 年末就一直从事 XML 技术。他在计算业务方面有 25 年以上的工作经验,期间曾参与了软件开发所有方面的工作。他毕业于达特默思学院(Dartmouth College),是 ACM 的成员。他目前在 IBM Research 的 Next-Generation Web 团队工作。您可以通过
David_Marston@us.ibm.com与他联系。
|
对本文的评价
|