独上高楼网站
  •    你所在位置:首页 VS.netXMLXML经验〉了解 XML 命名空间
  • 了解 XML 命名空间
  • 作者:佚名  文章来源:http://msdn2.microsoft.com/zh-cn/default.aspx  发布日期:2007-07-07  浏览次数:658
  • 打印这篇文章
  • 本页内容

    什么是命名空间?

    编程语言中的命名空间

    XML 中的命名空间

    对命名空间进行命名

    定义命名空间

    使用命名空间

    命名空间抽象

    小结

    Aaron Skonnard 撰写的了解 XML 命名空间最初刊登在 2001 7 月的 MSDN Magazine 中。此更新版本的使用经过授权。版权所有 ? 2001 Microsoft Corp. CMP Media LLC

    命名空间是 XML 中许多混淆的来源,初学该技术的用户对命名空间尤其感到困惑。读者、学生和与会者经常问到的问题总是与命名空间有关。这实际上具有一定的讽刺意味,因为 Namespaces in XML Recommendation 是一种精简的 XML 规范(不含附录,不超过 10 页)。然而,这种混淆与命名空间语义有关,而与该规范中概述的语法无关。为了充分了解 XML 命名空间,您必须知道什么是命名空间、如何定义命名空间以及如何使用它们。

    本专栏的其余部分将专门从语法和理论上回答这三个问题。在读完本文后,您将了解命名空间是如何影响 XML 技术家族的。

    什么是命名空间?

    命名空间是一组保持唯一的名称。例如,可以将我所有孩子的姓名视为一个命名空间,就像加利福尼亚州的公司的名称、C++ 类型标识符的名称或 Internet 域名。命名空间就是在逻辑上相关的任何一组名称,而且每个名称都必须唯一。

    使用命名空间更便于产生唯一的名称。设想一下,如果姓名必须在全球保持唯一,那么,要给自己的下一个小孩起名将会多么困难。如果将唯一性限制在一个更窄的上下文(例如,我的所有孩子)中,情况就会简单得多。当我为我的下一个孩子起名时,我只需考虑不使用与我的其他孩子重名的名字。另一组父母可以为他们的某个孩子选择我已使用过的姓名,但是这些姓名必须属于不同的命名空间,以便易于区分。

    在将新名称添加到某个命名空间中之前,命名空间机构必须确保该命名空间中没有这个新名称。在某些情况下,这会非常简单,因为它属于子命名系统。在其他情况下,这会相当复杂。当今的许多 Internet 命名机构就是一个现实的例子。然而,如果忽略此步骤,重复的名称最终会损坏该命名空间,这使得无法引用某些没有多义性的名称。如果出现这种情况,这组名称将不再被正式视为命名空间根据定义,命名空间必须确保它的成员具有唯一性。

    为了使命名空间有用,还必须为其本身赋予名称。在命名空间有了名称之后,就可以引用其成员。例如,考虑显示在图 1 两个框中的示例命名空间,这两个示例命名空间的名称分别是 Microsoft AcmeHardware。请注意,即使这两个命名空间都包含一些相同的本地名称,也可以通过由命名空间限定的名称来引用没有多义性的本地名称,如图1 所示。

    1. 非多义性命名空间

    当然,其前提是假设这些命名空间名称也是唯一的。如果不能保证这一点,则还可以将实际命名空间名称本身放到其各自的命名空间中。例如,如果有多个 AcmeHardware 商店(一个在加利福尼亚州,一个在犹他州),则将名称 AcmeHardware 放在两个不同的命名空间就会解决这种冲突,如下所示:

    California.AcmeHardware.Paint

    Utah.AcmeHardware.Paint

    这种模式可根据需要重复任意多次,以保证命名空间名称的唯一性。这与 Internet 域名系统 (DNS) 的工作方式完全相同,DNS 就是一个由多个命名空间组成的大命名空间。

    如果没有这种类型的命名空间分区,您将不得不使用极长(不常用)的名称来确保唯一性:

    MicrosoftWindowsOperatingSystemPaintApplication

    设想一下,如果只有一个不能进行分区的全局命名空间,会有多么复杂、多么令人头痛。人们在日常社交中相当依赖命名空间,尽管在大多数情况下人们并没有清楚地意识到这一点。然而,要在软件开发中使用命名空间,必须通过具体的语法明确它们。在转入讨论 XML 中的命名空间之前,让我们看一下当今某个主流编程语言中命名空间的语法示例。

    返回页首

    编程语言中的命名空间

    要在某个编程语言中使用命名空间,您必须熟悉用来定义命名空间并引用其中的某些内容的语法。当今的许多语言(包括 C++Java C#)为命名空间提供支持。在 C++ 中,命名空间是通过命名空间块来定义的,如下所示。

    namespace foo1

    {

       class bar

       {

          ????????????

       };

       class baz

       {

          ????????????

       };

    }

    namespace foo2

    {

       class bar

       {

          ????????????

       };

       class baz

       {

          ????????????

       };

    }

    本例定义了两个命名空间:foo1 foo2。这两个命名空间均包含两个名称:bar baz(在本例中,它们是类标识符)。

    foo1::bar b1;   // refers to bar class in foo1

    foo2::bar b2;   // refers to bar class in foo2

    要引用特定命名空间的 bar 类,必须用给定的命名空间标识符来限定 bar 标识符。

    为方便起见,还可以做如下声明:在给定的源文件中使用特定的命名空间。这会从本质上使指定的命名空间成为源文件的默认命名空间。于是,就没有必要完全限定特定的命名空间成员,当然,在绝对有必要避免多义性时也可以完全限定:

    using namespace foo1;

    bar b1; // refers to bar class in foo1

    正如您所看到的,C++ 中定义和使用命名空间的语法简单明了。C# 的工作方式与 C++ 非常相似,只是有几个小区别。Java 中的命名空间语法稍有不同,但概念是相同的。

    在许多编程语言中,命名空间可用来帮助避免名称冲突,这正是完成 XML 1.0 规范所需的解决方案类型。

    返回页首

    XML 中的命名空间

    因为 XML 1.0 规范不提供命名空间支持,所以许多开发人员感到它不完整。因此,用在 XML 文档中的所有名称都属于一个全局命名空间,这便难于实现唯一的名称。

    许多开发人员(包括 XML 1.0 作者本身)知道这在基于 XML 的大型分布式系统中最终会导致太多的多义性。例如,考虑下面的 XML 文档:

    student>

      id>3235329/id>

      name>Jeff Smith/name>

      language>C#/language>

      rating>9.5/rating>

    /student>

    此文档使用几个名称,每个名称都相当普通。student 元素对软件培训课程的学生进行建模。idlanguage rating 元素对学生的数据库记录编号、首选的编程语言以及学生对该课程的评分(基准分是 10)进行建模。其中的每个名称肯定都会在其他情况下用到在这些情况下,它们会具有不同的含义。

    例如,下面是另一个 XML 文档,它以一种完全不同的方式来使用相同的名称:

    student>

      id>534-22-5252/id>

      name>Jill Smith/name>

      language>Spanish/language>

      rating>3.2/rating>

    /student>

    在本例中,student 元素对小学生进行建模。现在,idlanguage rating 元素分别对孩子的社会保障号、本民族语言和当前的年级平均成绩(基准分是 4)进行建模。这两个文档的作者可以使用较长的、不太常用的名称来帮助确保实现唯一性,但这最终还是无法保证唯一性,而且更加难以使用。

    尽管人们能够在查看这两个文档后找出二者的区别,但是它们对于软件来说看上去却完全相同。设想一下,您负责构建一个学生管理应用程序,该应用程序必须支持与学生有关的许多不同的 XML 文档(包括刚提到的两个文档)。在编写代码时,您打算如何(从编程上)区分专业学生和小学生或者任何其他类型的学生?没有一种可靠的方法来进行这种区分。

    在同一个文档或应用程序中使用来自不同 XML 词汇表中的元素和属性,无论如何都会产生命名冲突。请考虑 XSLT,它本身是用来定义转换的 XML 词汇表。在给定的转换中,可以输出用户定义的文本元素。因此,既然 XSLT 词汇表中包含名为 template 的元素,那么如何输出名称同样为 template 的用户定义的文本元素呢?

    !-- this is the template element from XSLT -->

    template match="foo">

      !-- I want to output this template element -->

      template match="foo"/>

    /template>

    在大量混合 XML 词汇表的语言(例如,XSLT XML 架构)中,出现名称冲突的可能性极大。然而,如果 XML 提供对命名空间的支持,就可以很容易地避免这些问题的发生。

    “Namespaces in XML Recommendation” W3C XML 1.0 命名问题提供的解决方案。此规范定义了如何对 XML 1.0 具体语法进行扩展,以便支持命名空间。因为大多数开发人员都认为这个新增功能是绝对有必要添加的基本功能,所以此规范通常被视为 XML 1.0 的正式补充,尽管它不是正式的。实际上,许多开发人员现在拒绝单独提及 XML 1.0,而是提及“XML 1.0 + 命名空间,其原因就在于此。

    “Namespaces in XML Recommendation” 定义了 XML 命名空间的命名语法以及在 XML 命名空间中引用某些内容的语法。然而,它没有涉及到用来定义 XML 命名空间中有何内容的语法。这留给了另一个规范(即,XML 架构)。其中的每个领域都需要一些解释。

    返回页首

    对命名空间进行命名

    当您在编程语言(例如,C++)中定义命名空间时,有一些对可用在该名称中的字符的限制。XML 命名空间标识符还必须符合特定的语法统一资源标识符 (URI) 引用的语法。这表示 XML 命名空间标识符必须遵守由 RFC 2396 定义的 URI 的常用语法。

    URI 被定义为用来标识抽象或物理资源的紧凑字符串。在大多数情况下,URI 引用用来标识物理资源(网页、要下载的文件等),但是,对于 XML 命名空间来说,URI 引用用于标识抽象资源(特别是命名空间)。

    按照 URI 规范,有两种常规类型的 URI:统一资源定位器 (URL) 和统一资源名称 (URN)。这两种类型的 URI 都可以用作命名空间标识符。下面是一个可用作命名空间标识符的两个 URL