计划使用 XML 名称空间,第 1 部分

有利于您使用 XML 名称空间的最佳方法

Comments

注:本文档提到了在 2002 年 9 月发布的 Namespaces in XML 1.0 版本的“最新召集的工作草案(Last Call Working Draft)”中提出的更改。

XML 可以解决的绝大多数业务和通信问题都需要组合几个 XML 词汇表。(如果您愿意,可以将术语 XML 词汇表读作 标记与属性集。)XML 有一种机制,它可以限定名称以分配到不同的名称空间,如应用到不同行业的名称空间。一个公司或者(更广些)一个行业协会可以将名称指定给元素,并使用象“title”或“state”等常用词汇,而无需担心那些名称会与另一个词汇表中使用的相同名称相冲突。

XML 名称空间还允许名称随时间的推移而发展变化。在使用了词汇表的第一版后,您的实际体验可能使您设计一个增补的词汇表。新的版本可以指定到另一个名称空间,而且您可以使用 XSLT 将数据从一个词汇表转换成另一个词汇表。

谈到 XSLT,它是一个样式表标准,规定了附属样式表的导入。它可以包含别人写的一般模板。模板的名称可以限定在一个名称空间中,同样避免了冲突。换言之,我的样式表可以调用一个命名模板,而该模板有一个限定于某个名称空间的独特名称(已由模板作者选择的)。我甚至可以使用在我的样式表中导入的多个模板库,每个库的不同名称空间将避免模板的重复名称。万维网联盟(W3C)的许多推荐标准都倡导使名称空间模块化。

XML 名称空间还允许使用处理 XML 的各种工具(如样式表驱动的 XSLT 处理器)以挑出它们应该服从的指令并把用于其它处理器的指令仅当作是更多的数据。把处理器设置成将来自一个或两个特定名称空间的元素当作指令。没有名称空间的元素是数据,除了那些被识别为指令的元素外,所有拥有一个名称空间的元素都与其相同,即都是数据。

XML 名称空间简介

名称空间的正式名称是 URI。通常,您会看到把 URL(URI 的一种形式)作为标识符。因为 URI 使用各种各样的字符,所以如果我们必须将完整的 URI 直接与每个限定名连接,就会对 XML 语法产生严重影响。因此,XML 名称空间建议书(XML Namespaces Recommendation)还定义了直接与名称连接的前缀。根据句法,在 URI 字符串前后使用引号(单引号或双引号),并用冒号将前缀分隔开;对其它字符没有任何规定。前缀是标准 XML 名称。通过将一个 URI 指定给所有无前缀的名称或费劲地(而且危险地)重新指定文档中需要的缺省名称空间,可以避免使用前缀。出于实用目的,在混合使用多个词汇表时,才需要前缀。

与 XML 的其它规范一样,XML 名称空间建议书是由 W3C 发布的。W3C 正在开发名称空间建议书的 1.1 版本,这一版中的正式名称将是国际化资源标识符(Internationalized Resource Identifier),简称 IRI。URI 与 IRI 之间的不同之处在于如何转义某些字符以使它们更适合。

让我们看一些实际的名称空间语法:

<mddl:custodian 
   xmlns:mddl="http://www.mddl.org/mddl/2001/1.0-final">Merrill Lynch</mddl:custodian>

这不只是一个 custodian 元素;它是由 URI http://www.mddl.org/mddl/2001/1.0-final 标识的词汇表中的一个 custodian 元素。前缀 mddl 用来将元素名称与 URI 相关联。URI 在 mddl.org 域中;mddl.org 是维护市场数据定义语言(Market Data Definition Language)这一 XML 词汇表的组织, custodian 是该词汇表中众多元素中的一个。(这个词汇表定义了属于投资和证券管理的元素。)请注意,mddl.org 已制定了一些规定,以便通过在其 URI 中包含几个字段来定义其它词汇表和发布 MDDL 词汇表的更高级版本。

名称的 本地部分是特定词汇表中的名称。对于那些没有限定在某个名称空间中的名称,本地部分就是唯一的部分。对于有前缀的名称,本地部分是冒号之后的部分。例如,名为 book:titlebook:isbn 的元素在同一名称空间中,但有不同的本地部分。名为 book:titleperson:title 的元素有相同的本地部分,却完全无关,因为它们属于不同的名称空间。

在限定名中使用的前缀

前缀简化了对工作的表述。在开发一个基于 XML 的系统时,您可以表述 book:titlexsl:apply-templates 以及类似的元素,而且只需偶尔考虑其各自名称空间的细节。从一定的技术观点看,前缀并不重要,因为它是将名称与名称空间 URI 相关联的一个瞬时缩写。

但是,建立合理的和一致的前缀名称是一种 最佳实践,它提高了开发人员的生产力。

前缀限定并关联了元素和属性的名称,在某些情况中还应用于关键字类型的文本字符串。例如,在阅读一个 XML 文档时, book:title 等价于“将 title 作为 book 的一个特征”,它为人们浏览某些 XML 时提供了便利。通过查阅前缀 book 连接到一个 URI 的位置,人们可以找到声明的更正式规范,例如,声明“title 是在由 abaa.org 于 1999 年发布的 book 词汇表中定义的”。

有几个 W3C 建议书用术语 QName来表示可能(或不可能)限定在名称空间中的 XML 名称,而且如果定期阅读规范,您甚至会偶尔看到“QName-but-not-NCName”,它表明 必须限定在名称空间中的 XML 名称。(术语 NCName指没有冒号的 XML 名称。NC 表示“无冒号”。)例如,可以用 QName 而非简单的 XML 名称来命名 XSLT 中的命名模板,以便于发布所有模板都在一个特定名称空间中命名的一个模板库。QName 用冒号(:)作为特殊字符把前缀与本地部分隔开。当然,前缀和本地部分不能包含冒号,但它们还要遵循 XML 名称的规定语法。

可以将多个前缀与特定 URI 相关联。XML 标准通常会强制把前缀解析成与其关联的 URI,因此即使前缀不同,但如果本地部分和 URI 匹配,那么名称就相同。一个前缀一次只能与一个 URI 相关联。

名称空间 URI

每篇有关 XML 名称空间的文章都必定会指出 URI 毫无作用,这意味着不需要访存看起来由 URI 标识的任何资料。实际上,没必要为标识的位置设置一个服务器,也没有必要在该位置上放有可访存的资料。尽管 XML 名称空间建议书的确简要提及名称空间值是一个 URI 引用并暗示该值应该遵循因特网工程任务组(Internet Engineering Task Force)RFC 2396 的语法,不过这一建议书只需要字符串匹配以确定两个 URI 是相同的。

W3C 发布的 URI 总是使用 http: 协议和 w3.org 域名,所以可以认为使用 HTTP URL 是安全的方法,因而这是 最佳实践

域名是避免名称冲突的关键。通过使用世界范围的域名系统(Domain Name System),名称空间 URI 提供了对“说的是谁?”这一问题的回答。如果您有一个域名,那就拥有由您控制名称的一片天地,而且这应用于您的 XML 名称空间,也应用于您的服务器。例如, mddl.org是属于一个组织的域名,该组织定义了属于投资的 XML 词汇表,其他任何人都无法在 mddl.org 域下指定名称和 URL。

将来,W3C 会建立一个将名称空间 URI 指向一个可访存资源的指导原则。各种 W3C 委员会正在讨论备选方案。很可能的是,由 URI 标识的资料本身就是一个指向实际模式或描述的间接指针,并允许实际描述的语法随时间推移而发展。目前,用于 W3C 名称空间的 URI 都指向简单的文本页,它声明该 URI 是一个名称空间。试一下这个示例: http://www.w3.org/1999/XSL/Transform

定义名称空间语法和函数的 W3C 文档使用术语 名称空间名称来表示名称空间的 URI。XML 信息集建议书(XML Information Set Recommendation)定义了 XML 文档中有意义的部分,它也以同一方法使用这个术语。不过,XPath 函数 name()local-name() 在应用于名称空间节点时会返回前缀。

因此,避免术语 名称空间名称或只在您意思明确的上下文中使用它是 最佳实践。XQuery 在讨论其语法时使用术语 名称空间前缀名称空间 URI。后者可以安全地用来表示名称空间声明中的 URI。

已使用的名称空间

名称空间被指定用于各种 XML 词汇表,而不管这些词汇表是由 W3C 自己发布的(如 MathML)还是由行业协会发布的(如来自 OASIS 技术委员会(OASIS Technical Committee)的 DSML)。(请参阅 参考资料。)您可以在您的组织内做相同的事。

而且,XML 系列的其它 W3C 建议书使用名称空间来辨别它们定义的内容。XML 建议书没有定义任何元素名称,而是描述了可在 XML 文档中使用的两个属性: xml:spacexml:lang 。XML 基本建议书(XML Base Recommendation)把 xml:base 添加到上述属性列表中。在每种情况下,使用 xml前缀都意味着它们是在缺省情况下为每个 XML 文档定义的名称空间中。在最近的“勘误表”中,W3C 声明了您不能对构建在 XML 中的名称使用除 xml以外的任何前缀。

W3C 对其定义的每个词汇表都使用唯一前缀。每个建议书都不厌其烦地指出这些前缀在功能上没有什么特别,只是始终如一地使用罢了。回到 MathML 示例,MathML 2.0 建议书推荐外部元素 <mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML"> ,其中 mml 是他们喜爱的前缀。另外,除了便于人们阅读文档外, mml 字符串并没有什么特别。URI(http://www.w3.org/1998/Math/MathML)是实际标识 MathML 词汇表的字符串。(在该词汇表中,带有本地部分名称 math的元素是外部元素。)

XML 包含建议书(XML Inclusions Recommendation)提出了一个设计难题:包含结构无法简化成象 xml:basexml:lang 那样可以做到的单个字符串值。包含声明需要三部分:

  • 被包含的资源 href
  • 其假定的编码,
  • 及其解析方法。

可以将这些都连接起来作为元素中的属性,但把该元素命名为 includexml:include 会影响 XML 中一组可用的元素名称,对人们和机器等产生凌乱的异常。解决方案是单为这一个元素定义一个名称空间。典型的 include 元素类似于:

<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" 
   href="http://example.com/std/defs" parse="xml" />

在这个示例中,请注意元素在其自己的开始标记内声明了 xi 前缀。如果一个文件有多个 XML 包含,您可能要在顶部声明 xi ,在这一情况中,每个元素的名称仍是 xi:include ,但在其开始标记内没有名称空间声明:

<document xmlns:xi="http://www.w3.org/2001/XInclude" ...>
<-- ...other content... -->
<xi:include href="http://example.com/system/common" parse="xml" />
<-- ...other content... -->
<xi:include href="http://example.com/system/style" parse="xml" />
<-- ...other content, and perhaps more include elements... -->
</document>

使名称空间用于泛化的 XML 包含还把其与 XSLT 和 XML 模式中特定于应用程序的包含分开。

详尽阐述的建议书需要完整的文档来分别描述转换或数据设计,XSLT 和 XML 模式就是适用于此的两种情况。这些文档分别称为 XSLT 样式表和模式定义。它们遵循 XML 的基本设计原则之一,因此是 XML 文档,而且使用专门名称空间的词汇表。事实上,XML 模式为模式定义文档定义了一个词汇表,为在 实例文档中出现的模式项或该模式定义的数据定义了另一个词汇表。模式定义和 XSLT 样式表可能会将其语言的元素和属性同其它名称空间的元素和属性混淆,所以需要前缀。

使用 W3C 所用的前缀是 最佳实践。例如,XSLT 建议书和大多数关于 XSLT 的书籍都使用前缀 xsl 来标识 XSLT 词汇表的元素。如果坚持在样式表上使用 xsl 前缀,那么可以只讨论部署计划和查阅 XSLT 书籍,而不必费神考虑前缀的转换。

在 XML 中建立限定名

XML 文档有一个树结构,从 document 元素或最外层元素向下排列。可以对任何元素声明名称空间,从而允许在由该元素及其所有子元素定义的子树内识别它。声明类似于属性,但大多数 W3C 建议书把它当作一个单独的节点类型。在查看 XML 时,您会发现在相关元素开始标记中的名称空间声明就在属性旁边。有两种语法变体:

  • xmlns:prefix="URI"
  • xmlns="URI"

通常使用第一种;它将前缀与 URI 相关联。第二种声明,对于那些没有前缀的元素存在一个缺省名称空间。在 XML 的总体设计中,这两种语法在为 XML 保留以字符 xml 开头的名称的情况下都适用。对缺省名称空间初始化,使之完全不是名称空间 URI,这样就存在一个语法,它通过向以前定义的缺省名称空间分配空字符串来取消对该名称空间的定义。(技术上,空字符串作为 URI 是有效的,但不允许作为名称空间 URI。)可以将前缀设置成不同的 URI,但不能取消定义,至少对 XML 1.0 文档是这样。

名称空间声明的变体
名称空间 URIxmlns=xmlns:prefix=
"http://URI"设置缺省值关联前缀
""(空字符串)清除缺省值非法!(可能会更改)

在 2002 年 4 月,W3C 的 XML 工作组宣布它正在考虑修订 XML 名称空间,可能会允许把名称空间前缀指定为空字符串。在 9 月版的提案中,该使用受到了限制,因此这样的声明只能为了避免发生冲突和消除不想要的名称空间节点而用来取消对前缀的定义,而限定名在文档中将前缀指定为空的任何地方都不能使用前缀。目前,请注意:如果您需要除去不想要的名称空间节点,那么只有未使用它们时,才可以用 XSLT 的 exclude-result-prefixes特性除去它们。

可以在树顶将前缀与一个 URI 相关联,而通过在子树顶端的元素开始标记中声明 xmlns:prefix="new-uri" ,就可以在子树内把前缀与另一个 URI 相关联,然后在子树内的子子树中将前缀与另一个 URI(或最初的 URI)相关联,以此类推。这样做会让那些要阅读原始 XML 文档的人员产生混淆。

这个示例比较紧凑,但想象一下要在大型文档中查找所有 xmlns 声明将有多么难:

<data:document xmlns:data="http://example.com/namespace/fields">
  <-- ...other content... -->
  <data:legacy xmlns:data="http://example.com/namespace/legacy-data">
    <-- ...data of an older style... -->
    <data:item xmlns:data="http://example.com/namespace/fields">
      <-- ...this one item within legacy uses the standard namespace... -->
    </data:item>
  </data:legacy>
  <-- ...other content... -->
</data:document>

可以应用下列首选实践:

这里的 最佳实践是仅对系统中所有 XML 文档中的一个名称空间使用给定的前缀。如果这不可行,至少试着将前缀只与一个文档中的一个 URI 关联。另一个 最佳实践是在 document 元素的开始标记中设置所有必要的关联,以便这些关联应用于整个文档。这使得查找所有声明变得更加容易。不限制在单个开始标记中可以出现的名称空间声明的数量。

当软件工具生成 XML 时,它必须将名称空间节点( xmlns 声明)置于树中,以便它们在需要限定名称的地方起作用。如果名称空间有关联的前缀,那么可以在需要该名称空间的元素上一层声明该名称空间。这样可以产生减少冗余声明这种令人满意的效果。Xalan XSLT 处理器是这样做的一个工具示例。

除了 xmlxmlns 外,在使用那些设想会在所有 XML 文档中起作用且不更改的所有前缀前,都必须先进行声明。您可能非常想利用象属性那样的语法把一些声明设置成外部实体中的缺省属性。

这里的 最佳实践是在文档中包含声明,从而减少假设和相关性。

使用缺省名称空间(一种可用于无前缀的元素名称的名称空间)是一个判断调用。如果您习惯于在任何地方都给所有元素名称加前缀,就避免了一些隐患。不过,有些人可能感到前缀很累人,或觉得一个名称空间可应用于文档的 实际内容,而且把它设为缺省值是进行区别的一种方法。如果您采取后一种途径,就需要建立一些设计原则来确定名称空间,使之在给定文档中成为缺省值。当然,这些规则只有利于那些真正要阅读(和可能创建)XML 文档的人。

关于使用前缀的 最佳实践是要么在任何地方都用前缀,要么在除传递给最终用户的实际内容外的所有项上使用它们。前缀可用于所有只由系统开发人员修改的过程控制元素,包括 XSLT 样式表、模式定义等。可能除了传递给最终用户的实际内容外,对所有来自您组织以外的 XML 词汇表的项都可用前缀。

属性有一点不同

属性可以出现在与包含该属性的元素不同的另一个名称空间中。例如, <movie:title xml:lang="fr"> 有一个不是来自 movie 名称空间的属性。如果属性名称有一个前缀,那么其名称在该前缀指明的名称空间中。但是,如果属性名称没有前缀,它就没有名称空间。即使指定了缺省名称空间,它仍没有名称空间。XML 建议书中的 W3C 名称空间用这个示例表明了这一点:

<x xmlns="http://www.w3.org" xmlns:n1="http://www.w3.org">
  <good a="1" n1:a="2" />
</x>

对缺省名称空间的 URI 进行声明会影响元素。即, xgood 都与 URI“http://www.w3.org”关联,因为它是缺省名称空间。由于属性 n1:a 使用了与同一 URI 关联的 n1 前缀,所以它也与该名称空间相关联。 a 属性声明了两次而没有发生冲突,因为 n1:ahttp://www.w3.org 名称空间中,而无前缀的 a 不在该名称空间中;后者不在任何名称空间中。

既然上面说明了 xml:lang ,就让我们注意一下:使用 xml:lang 属性作为一种方法来声明该元素的内容使用了特定的自然语言,这是 最佳实践

当 W3C 词汇表同时指定了元素和属性时,通常只要属性出现在受限的元素中,它就不需要将它们限定于名称空间。回到 XML Include 示例,在 <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="http://example.com/std/defs" parse="xml" /> 中, hrefparse 属性指定为 xi:include 元素有意义的属性,所以能对 xi:include 元素操作的 XML 解析器必须将这些属性解释为包含操作的详细信息。

在全部可能的属性名称中,以字母“xml”开头(以这一顺序,但可以是任何大小写组合)的所有名称都保留由 W3C 来定义。那样,象 xmlns="http://foo.com" 这样的名称空间声明可以使用属性的语法而非独特的语法。

大多数 W3C 规范把它称为 名称空间声明,而不是 属性,而且观察对话中的差异是 最佳实践。(名称空间建议书文档本身将这些声明当作 保留属性,这些声明长得足以介绍它们。DOM 第 3 级也把这些声明当作来自 xmlns 名称空间的属性。)

xmlns:fooname="http://foo.com" 这样的名称空间声明与带限定名的属性有相同的语法,但起始字母“xml”表明其特殊角色,而且它在对话中也是 名称空间声明。但是,象 xml:space="preserve" 这样的属性仍是严格意义的术语中的 属性,不过它在保留的名称空间中。如果 XML 文档是由识别 XML 但不能识别名称空间的应用程序处理的,那么可能会继续使用 QName,并且将名称空间声明当作属性。

xmlns 前缀已由第一版 Namespaces in XML 建议书指定为 没有关联的 URI。W3C 可能会选择在将来更改这一点。这可能不会在现实世界中产生很大的差别,因为大多数 XML 工具和过程都自动管理名称空间声明。当它们不自动管理时,您总是会有方法在 XML 类树表示法中创建或避免创建一个名称空间节点。当 XML 驻留在文件中时,名称空间声明在元素的开始标记中有标准的 xmlns 顺序,但无论 xmlns 是否与某个名称空间相关联,读取该文件的 XML 解析器都知道识别它。(因为 XML 在没有名称空间的情况下启动,所以您有可能会遇到不能识别名称空间的早期 XML 解析器;如果这里提到的最佳实践完全对您都适合,那么就要避免这样的解析器。)

确认和名称空间

XML 模式建议书(XML Schema Recommendation)对用有名称空间的元素和属性定义文档结构有完整的规定。而且,它为必须是有效限定名的字符串定义了一个专门的 QName 数据类型。模式定义文档可以为文档结构指定目标名称空间。

指定文档结构的早期文档类型定义(DTD)语法不能识别名称空间。但是,DTD 默认了包含冒号的元素和属性名称。如果您要同时使用 DTD 和名称空间,通过指定特定的前缀并把它们当作元素和属性名称的固定部分就可以做到了。这个技术在 The Cover Pages 中 C. M. Sperberg-McQueen 的备忘录中有详细说明(请参阅 参考资料)。如果您必须这样做,肯定会十分困难。(DTD 允许向 XML 文档中没有显式出现的属性指定值。通过这个 DTD 机制设置名为 xmlns 的属性不是一个好主意。)

展望

至此,我已介绍了 W3C 建立的基础知识。第 2 部分会更深入地提供建立您自己的 XML 词汇表的最佳方法。在第 2 部分中,您还会看到识别名称空间的重命名技术。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML
ArticleID=22196
ArticleTitle=计划使用 XML 名称空间,第 1 部分
publish-date=11012002