摘自 2001 年 7 月版 MSDN 杂志。

MSDN 杂志

了解 XML 命名空间
Aaron Skonnard
N

amespaces 是 XML 中许多混淆的根源,尤其是那些不熟悉该技术的人。 我从读者、学生和会议与会者那里收到的大多数问题都以这样或那样的方式与命名空间相关。 这实际上有点讽刺,因为 XML 建议 () http://www.w3.org/TR/REC-xml-names 中的命名空间是较短的 XML 规范之一,只有不到 10 页,不包括附录。 但是,这种混淆与命名空间语义有关,而不是规范概述的语法。 若要完全了解 XML 命名空间,必须了解什么是命名空间、如何定义命名空间以及如何使用它们。
      本专栏的其余部分专门回答这三个问题,包括语法和抽象问题。 阅读完本文后,你将了解命名空间如何影响 XML 技术系列。

什么是命名空间?

      命名空间是一组名称,其中所有名称都是唯一的。 例如,可以将我的孩子的名称视为命名空间,加州公司的名称、C++ 类型标识符的名称或 Internet 域的名称也是如此。 每个名称必须唯一的任何逻辑相关名称集都是命名空间。
      使用命名空间可以更轻松地提供唯一名称。 想象一下,如果这个名字在地球上必须是唯一的,那么给你的下一个孩子起名字是多么困难。 将唯一性限制在更有限的上下文中(如我的一组孩子)可以极大地简化事情。 当我给下一个孩子起名字时,我唯一的考虑是,我使用的名字与我已经为我的其他孩子使用过的名字不同。 另一组父级可以选择我为其子级选择的同一个名称,但这些名称将是不同命名空间的一部分,因此可以轻松区分。
      在将新名称添加到命名空间之前,命名空间颁发机构必须确保命名空间中尚不存在新名称。 在某些情况下,这与子命名一样简单。 在其他人中,这相当复杂。 今天的许多互联网命名机构都提供了一个很好的例子。 但是,如果跳过此步骤,重复的名称最终会损坏命名空间,因此无法毫无歧义地引用某些名称。 发生这种情况时,名称集不再正式被视为命名空间-根据定义,命名空间必须确保其成员的唯一性。
      命名空间本身也必须提供名称才能发挥作用。 命名空间具有名称后,就可以引用其成员。 例如,请考虑 图 1 中两个框中显示的示例命名空间。 这些示例命名空间的名称分别为 Microsoft 和 AcmeHardware。 请注意,即使这两个命名空间都包含一些相同的本地名称,也可以通过命名空间限定的名称来引用它们,如图 1 所示。

图 1 非歧义命名空间
图 1非歧义命名空间

      当然,这假定命名空间名称也是唯一的。 如果无法保证这一点,则实际命名空间名称本身也可以放入自己的命名空间中。 例如,如果有多个 AcmeHardware 存储 (一个在加利福尼亚州,一个在犹他州) ,将名称 AcmeHardware 放在两个不同的命名空间中可以解决冲突,如下所示:
  California.AcmeHardware.Paint
Utah.AcmeHardware.Paint

      可以根据需要多次继续此模式,以确保命名空间名称的唯一性。 这正是 Internet 域名系统 (DNS) 的工作原理 , 它只是命名空间的一个大命名空间。
      如果没有这种类型的命名空间分区,将被迫使用非常长的 (不常见的) 名称来确保唯一性:
  MicrosoftWindowsOperatingSystemPaintApplication

      想象一下,只有一个无法分区的全局命名空间的复杂性和由此产生的挫折感。 人员在日常社交交互中严重依赖命名空间,尽管在大多数情况下,它们并不明确。 但是,若要在软件开发中使用命名空间,必须通过具体的语法将其显式化。 在介绍 XML 中的命名空间之前,让我们看一下当今主流编程语言之一的命名空间语法示例。

编程语言中的命名空间

      若要在编程语言中使用命名空间,必须熟悉用于定义命名空间和引用命名空间中的对象的语法。 当今的许多语言(包括 C++、Java 和 C#)都支持命名空间。 在 C++ 中,命名空间是通过命名空间块定义的,如图 2 所示。 此示例定义了两个命名空间,foo1 和 foo2,每个命名空间包含两个名称,即 bar 和 baz (,在本例中) 类标识符。
  foo1::bar b1;   // refers to bar class in foo1
foo2::bar b2;   // refers to bar class in foo2

若要引用特定命名空间的条形图类,条形图标识符必须使用给定的命名空间标识符进行限定。
      为了方便起见,还可以声明你在给定源文件中使用特定命名空间。 这实质上使指定的命名空间成为源文件的默认命名空间之一。 然后,不再需要完全限定特定的命名空间成员,除非当然绝对需要它来避免歧义:
  using namespace foo1;
bar b1; // refers to bar class in foo1

      如你所看到的,用于在 C++ 中定义和使用命名空间的语法简单明了。 C# 的工作方式非常类似,但有一些细微的变化。 Java 中命名空间的语法略有不同,但概念是相同的。
      命名空间在许多编程语言中使用,以帮助避免名称冲突。 这正是完成 XML 1.0 规范所需的解决方案类型。

XML 中的命名空间

      许多开发人员认为 XML 1.0 规范 (http://www.w3.org/TR/REC-xml) 不完整,因为它不提供命名空间支持。 因此,XML 文档中使用的所有名称都属于一个全局命名空间,因此很难想出唯一的名称。
      大多数开发人员(包括 XML 1.0 作者自己)都知道,这最终会在基于 XML 的大型分布式系统中造成太多歧义。 例如,请考虑以下 XML 文档:
  <student>
  <id>3235329</id>
  <name>Jeff Smith</name>
  <language>C#</language>
  <rating>9.5</rating>
</student>

本文档使用多个名称,每个名称都很常见。 student 元素为软件培训课程的学生建模。 id、语言和评分元素对学生的数据库记录编号、首选编程语言以及学生为课程 (评分进行建模,总分为 10) 。 这些名称中的每一个肯定会用于其他没有传达相同含义的情况。
      例如,下面是另一个以完全不同的方式使用相同名称的 XML 文档:
  <student>
  <id>534-22-5252</id>
  <name>Jill Smith</name>
  <language>Spanish</language>
  <rating>3.2</rating>
</student>

在本例中,学生元素为小学生建模。 现在,id、语言和评级元素分别模拟孩子的社会保险号码、母语口语和学生的当前成绩平均分 (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 提供对命名空间的支持,则很容易避免这些问题。
      XML 建议中的命名空间是 W3C 针对 XML 1.0 命名问题的解决方案。 此规范定义如何扩展 XML 1.0 具体语法以支持命名空间。 由于大多数开发人员认为此添加是基本且绝对必要的,因此,它通常受到官方 XML 1.0 附录的尊重,即使它不是一个附录。 事实上,如今许多开发人员拒绝单独引用 XML 1.0,而是出于相同的原因而将其称为“XML 1.0 + 命名空间”。
      XML 建议中的命名空间定义用于命名 XML 命名空间的语法,以及用于引用 XML 命名空间中某些对象的语法。 但是,它不会解决用于定义 XML 命名空间中的内容的语法。 这留给另一个规范,即 XML 架构。 其中每个方面都需要一些解释。

命名命名空间

      使用 C++ 等编程语言定义命名空间时,名称中可以使用的字符存在限制。 XML 命名空间标识符还必须符合特定的语法,即统一资源标识符 (URI) 引用的语法。 这意味着 XML 命名空间标识符必须遵循 RFC 2396 定义的 URI 的通用语法。
      URI 定义为用于标识抽象或物理资源的压缩字符串。 在大多数情况下,URI 引用用于标识物理资源 (网页、要下载的文件等) ,但在 XML 命名空间中,URI 引用标识抽象资源,特别是命名空间。
      根据 URI 规范,URI 有两种常规形式:统一资源定位符 (URL) 和统一资源名称 (URN) 。 任一类型的 URI 都可用作命名空间标识符。 下面是可用作命名空间标识符的两个 URL 的示例:
  http://www.develop.com/student
http://www.ed.gov/elementary/students

下面是一些也可以用作命名空间标识符的 URN 示例:
  urn:www-develop-com:student
urn:www.ed.gov:elementary.students
urn:uuid:E7F73B13-05FE-44ec-81CE-F898C4A6CDB4

      命名空间标识符最重要的属性是它是唯一的。 作者可以通过向 Internet 命名机构注册域名来保证 URL 的唯一性。 然后,作者负责确保域名后使用的所有字符串都是唯一的。
      URNs 的工作方式相同。 下面是基本 URN 语法:
  urn:<namespace identifier>:<namespace specific string>

      若要保证 URN 的唯一性,作者必须再次向 Internet 命名机构注册其命名空间标识符。 然后,作者负责遵循生成特定于命名空间的唯一字符串的方案。
      定义 XML 命名空间的组织应开发一个用于创建新命名空间名称的一致方案。 例如,W3C 不断定义新的 XML 命名空间。 他们使用相当直观的启发式,它使用当年和工作组的名称。 图 3 演示了 W3C 使用的模式。

图 3 W3C URI 构造
图 3W3C URI 构造

      根据定义,URI 是唯一的,因此无需在 XML 命名空间标识符之上分层其他命名空间。 只要命名空间作者保证命名空间标识符的唯一性,始终可以使用单个命名空间限定符在 XML 中唯一标识某些内容。 这大大简化了在 XML 中使用命名空间的工作。
      XML 处理器将命名空间标识符视为不透明的字符串,永远不会视为可解析的资源。 让我重复一遍:命名空间标识符只是字符串! 两个命名空间标识符在字符完全相同时被视为相同。
      最后,选择使用哪种类型的 URI 引用并不重要。 许多开发人员喜欢使用 URL,因为它们更易于阅读和记住,而其他开发人员则更喜欢 URL,因为它们具有灵活性。

定义命名空间

      XML 建议中的命名空间不提供用于定义命名空间中的内容的语法。 在许多情况下,甚至不需要这种类型的语法定义。 如今,大多数 XML 命名空间都在正式规范文档中定义,这些文档描述了元素的名称以及属性及其语义。 这正是正式定义所有 W3C 命名空间的方式, (请参阅中的 http://www.w3.org/TR/xslt XSLT 1.0 规范以获取示例) 。
      定义命名空间后,软件开发人员将实现该命名空间,如规范所述。 例如,MSXML 3.0、Xalan 和 Saxon 都是 XSLT 1.0 规范的实现。 这些实现是硬编码的,以查找属于 XSLT 1.0 命名空间的元素 (http://www.w3.org/1999/XSL/Transform). 若要使用这些实现,需要为它们提供一个 XML 文档,该文档正确使用 XSLT 1.0 命名空间中的名称, (下一部分) 。 如果 XSLT 1.0 命名空间中的任何内容发生更改,则必须更新支持软件。
      ) (http://www.w3.org/XML/Schema XML 架构工作组目前正在将一个新的规范 (XML 架构) 组合在一起,该规范定义基于 XML 的语法,用于定义命名空间中的元素、属性和类型。 XML 架构最终允许提供命名空间的语法定义,如图 4 所示。
      此示例将命名空间 http://www.develop.com/student 定义为包含四个命名元素:student、id、name、language 和 rating。 除了提供命名空间外,此架构还提供其他元数据,例如学生子元素的顺序及其类型。
      使用语法命名空间定义(如 XML 架构提供的语法命名空间定义),可以构建更复杂的软件,以在运行时利用名称和类型信息。 XML 架构仍不定义定义的元素和属性的语义,因此仍需要随附的规范。 将来,大多数 XML 命名空间将通过规范和架构定义进行定义。

使用命名空间

      我定义使用命名空间作为在 XML 文档中使用给定命名空间中的一个或多个元素或属性的过程。 这需要了解 XML 建议中命名空间概述的语法,以便使用命名空间标识符限定元素和属性名称。
      元素和属性名称都可以使用命名空间前缀进行限定。 前缀实际上只是命名空间标识符 (URI) 的缩写,通常相当长。 前缀首先通过命名空间声明映射到命名空间标识符。 命名空间声明的语法为:
  xmlns:<prefix>='<namespace identifier>'

      命名空间声明看起来就像) 元素上的属性 (,但就逻辑文档结构而言,它们不是正式视为属性 (也就是说,使用 DOM) 时,它们不会显示在元素的属性集合中。
      命名空间前缀被视为声明元素及其任何后代元素的作用域内。 声明后,前缀可以在由冒号 ((如 s:student) )分隔的任何元素或属性名称前面使用。 包含前缀的此完整名称称为 QName) (限定名称:
  QName = <prefix>:<local name>

前缀将元素或属性与映射到当前范围内的前缀的命名空间标识符相关联。
      假设开发人员想要使用 XSLT 1.0 命名空间。 他需要提供命名空间声明,用于将任意前缀映射到官方 XSLT 1.0 命名空间标识符 (http://www.w3.org/1999/XSL/Transform). 然后,开发人员想要从 XSLT 1.0 命名空间使用的每个元素或属性只需相应地添加前缀,如以下示例所示:
  <x:transform version='1.0'
   xmlns:x='http://www.w3.org/1999/XSL/Transform'
>
   <x:template match='/'>
      <hello_world/>
   </x:template>
</x:transform>

      上一个示例演示了用于引用命名空间中的元素的语法。 每个以“x”为前缀的元素都来自 http://www.w3.org/1999/XSL/Transform 命名空间,而没有前缀的任何元素都来自任何命名空间 (例如,hello_world) 。 处理器现在可以区分 XSLT 1.0 编程构造和用于输出的文本元素,例如hello_world。 如果 XSLT 1.0 命名空间被一个字符拼写错误,XSLT 1.0 处理器将无法将文档识别为它所理解的词汇。
      实质上,每个元素现在都有一个两部分的名称、一个命名空间标识符和一个本地名称。 这两个名称的组合通常称为命名空间名称 (注意:这与 QName 不同,QName 是前缀和本地名称) 的组合。
      作为另一个示例,以下 XML 文档演示如何使用此列前面所示的 XML 架构定义中的元素:
  <d:student xmlns:d='http://www.develop.com/student'>
  <d:id>3235329</d:id>
  <d:name>Jeff Smith</d:name>
  <d:language>C#</d:language>
  <d:rating>9.5</d:rating>
</d:student>

请注意,无论如何定义命名空间,引用它们的语法都是相同的。
      当文档使用来自多个命名空间的元素或属性时,在给定元素上通常有多个命名空间声明,如以下示例所示:
  <d:student xmlns:d='http://www.develop.com/student'
  xmlns:i='urn:schemas-develop-com:identifiers'
  xmlns:p='urn:schemas-develop-com:programming-languages'
>
  <i:id>3235329</i:id>
  <name>Jeff Smith</name>
  <p:language>C#</p:language>
  <d:rating>9.5</d:rating>
</d:student>

      在这里,学生和评分都来自同一命名空间,而 id 和语言都来自不同的命名空间,但 name 不属于命名空间。
      命名空间前缀也可以通过在嵌套范围重新声明前缀来重写,如下所示:
  <d:student xmlns:d='http://www.develop.com/student'>
  <d:id>3235329</d:id>  
  <d:name xmlns:d='urn:names-r-us'>Jeff Smith</d:name>
  <d:language>C#</d:language>
  <d:rating>35</d:rating>
</d:student>

在此示例中,除 name 元素(来自 urn:names-r-us 命名空间)之外,所有内容均来自同一命名空间。 虽然可以重新声明命名空间前缀,但无法取消声明命名空间前缀。 例如,以下内容是非法的:
  <d:student xmlns:d='http://www.develop.com/student'>
  <d:id xmlns:d=''>3235329</d:id>  
   •••
</d:student>

      对于大多数软件开发人员来说,用于引用 XML 命名空间中事物的面向前缀的语法非常直观。 如果 XML 建议中的命名空间已停止在此处,命名空间的混淆就少得多。

默认命名空间

      还有一种类型的命名空间声明可用于将命名空间标识符与元素名称相关联。 这称为默认命名空间声明,它使用以下语法:
  xmlns='<namespace identifier>'

请注意,没有前缀。 当对元素使用默认命名空间声明时,其范围内的所有未限定元素名称将自动与指定的命名空间标识符相关联。 但是,默认命名空间声明对属性绝对没有影响。 将属性与命名空间标识符关联的唯一方法是通过前缀。
      请考虑以下示例:
  <d:student  xmlns:d='http://www.develop.com/student'
     xmlns='urn:foo' id='3235329'
>
  <name>Jeff Smith</name>
  <language xmlns=''>C#</language>
  <rating>35</rating>
</d:student>

此处,“student”来自命名空间, http://www.develop.com/student 而“name”和“rating”来自默认命名空间 urn:foo。 id 属性不属于命名空间,因为属性不会自动与默认命名空间标识符关联。
      此示例还说明,只需将默认命名空间标识符设置回空字符串,即可取消声明默认命名空间,如语言元素所示, (请记住,不能使用前缀声明) 执行此操作。 因此,语言元素也不属于命名空间。
      默认命名空间的语法设计是为了方便起见,但它们往往会导致比价值更大的混淆。 这种混淆通常源于这样一个事实:元素和属性的处理方式不同,并且嵌套元素并没有立即被分配为默认命名空间标识符。 然而,最后,在前缀和默认命名空间之间进行选择主要是风格问题,除非属性发挥作用。

命名空间抽象

      与处理上述词法问题相比,从 XML 文档的抽象视图中处理命名空间要简单得多。 XML 信息集 (Infoset) 定义 XML 文档的抽象结构,使开发人员免受基础序列化格式的复杂性(如刚才所述的命名空间语法)的困扰。
      根据 Infoset,每个元素或属性都有两个名称属性:命名空间标识符和本地名称。 图 5 演示了包含命名空间限定名称的 XML 文档的逻辑结构。 请注意,学生、ID 和语言都来自同一命名空间,而评级来自不同的命名空间,并且名称不属于任何命名空间。 可以使用上一部分所述的任一技术来序列化本文档。

图 5 命名空间限定的 XML 文档
图 5命名空间限定的 XML 文档

      考虑当今主流 API SAX 和 DOM 如何实现此抽象数据模型。 SAX 通过 ContentHandler 的 startElement/endElement 方法调用为元素建模:
  public interface contentHandler
{
•••
void startElement(String namespaceURI, String localName, 
   String qName, Attributes atts) throws SAXException;
void endElement(String namespaceURI, String localName, 
   String qName) throws SAXException;
•••
}

      请注意,元素的命名空间标识符和本地名称的组合标识 ((可选)QName) 。 属性也通过特性接口上的一组命名空间感知方法进行标识。 由 SAX 分析程序 (或任何其他生成者应用程序) 在提供文档流时提供命名空间名称。 也就是说,使用 SAX 可以轻松地以编程方式区分不同类型的学生元素 (请参阅 图 6) 。
      由于命名空间名称 (命名空间标识符 + 本地名称) 由 SAX 分析程序自动解析,因此,如果在源文档中的特定元素或属性上使用了任何) ,则 (前缀无关紧要,这主要是序列化详细信息。 但这并不意味着,一旦分析,前缀就会被丢弃。 请考虑以下 XML 文档:
  <student xmlns:xsd='http://www.w3.org/2000/10/XMLSchema'
 xmlns:xsi='http://www.w3.org/2000/10/XMLSchema-instance'
>
  <age xsi:type='xsd:double'>35.0</age>
</student>

请注意,age 上的 XML Schema xsi:type 属性包含 QName 值。 每当在元素或属性内容中使用 QName 时,使用方应用程序都需要手动处理它。 使用应用程序正确解释此值的唯一方法是,如果它知道“xsd”绑定到的命名空间标识符。 因此,Infoset 还维护文档中每个元素的作用域内命名空间声明集。 SAX 通过 startPrefixMapping 和 endPrefixMapping 方法调用为此信息建模。
      DOM API 是 Infoset 的另一个实现。 DOM 的 Node 接口通过两个名称属性(namespaceURI 和 localName)为元素/属性节点的基本标识建模。 它还通过 nodeName 和 prefix 属性为节点的 QName 和前缀建模。 图 7 中的 Java 语言代码演示了如何使用 DOM 区分两个不同的学生元素。
      与 SAX 一样,生成 DOM 树的 XML 分析程序负责相应地填充命名空间属性。 因此,同样,在使用逻辑文档结构后,命名空间在源文档中的声明方式并不重要。 如果要通过 DOM API 创建文档,则需负责在创建时为每个元素和属性提供命名空间标识符:
  void generateStudentDocument(Document doc)
{
   Node docEl = doc.createElementNS("urn:dm:student", "student");
   doc.appendChild(docEl);
   Node n = doc.createElementNS("", "name");
   docEl.appendChild(n);
   •••
}

      如你所看到的,此代码允许你直接创建逻辑结构。 然后由 DOM 实现来确定如何将命名空间声明序列化为基础 XML 1.0 文档。 此特定 DOM 树可以按如下所示进行序列化:
  <student xmlns='urn:dm:student'>
   <name xmlns=''/>
</student>

      处理通过 SAX/DOM API (XML 文档的抽象视图时) 请务必注意,没有默认命名空间的概念。 在前面引用的示例中,调用“student”的 createElementNS 后,urn:dm:student 并没有神奇地成为默认命名空间。 对没有命名空间的“name”的 createElementNS 的调用为 name 元素分配了空命名空间标识符, (不是 urn:dm:student) 。 这同样适用于一系列 startElement/endElement 方法调用的 SAX。 每个元素/属性节点始终与名称信息独立处理。
      XPath 是另一个 XML 规范,用于定义如何标识抽象文档结构中的节点。 通过 XPath 表达式,可以按命名空间限定的名称来标识元素和属性。 由于 XPath 名称测试是简单的字符串表达式,因此将 XPath 名称测试与命名空间标识符相关联的唯一方法是通过命名空间前缀。
      可以将 XPath 节点测试视为 QName 类型。 这意味着,如果节点测试不包含前缀,这类似于请求属于“无命名空间”的给定名称。 例如,采用以下 XPath 表达式:
  /student/name

此表达式标识不属于任何命名空间的所有名称元素,这些元素是不属于任何命名空间的根学生元素的子元素。 若要标识属于 urn:dm:student 命名空间的学生和名称元素,首先需要将命名空间前缀与 urn:dm:student 相关联。 然后,可以在 XPath 表达式中使用该前缀。
      假设“dm”已与 XPath 上下文中的 urn:dm:student 相关联,则以下表达式现在将标识属于 urn:dm:store 命名空间的名称元素,这些名称元素是根 student 元素的子元素,也属于 urn:dm:store 命名空间:
  /dm:student/dm:name

如果查询的文档看起来与后面的代码类似,则前面的表达式将标识所有三个名称元素,这些名称元素是学生的子元素(无论其前缀如何),因为它们都来自有问题的同一命名空间。
  <s:student xmlns:s='urn:dm:student'>
   <s:name/>
   <n:name xmlns:n='urn:dm:student'/>
   <s:name/>
</s:student>

      前缀以依赖于实现的方式在 XPath 上下文中映射 (请参阅 2001 年 5 月的 XML 文件 列,详细了解如何在 MSXML 3.0) 中工作。 其中一个示例是 XSLT,它提供使用 XPath 表达式的上下文。 若要在 XSLT 文档中使用命名空间限定的 XPath 表达式,可以使用标准命名空间声明将目标命名空间标识符映射到任意前缀:
  <x:transform version='1.0'
   xmlns:x='http://www.w3.org/1999/XSL/Transform'
   xmlns:d='urn:dm:student'
>
   <x:template match='d:student'>
     <!-- transform student here -->
     <x:apply-templates select='d:name'/>
   </x:template>
   •••
</x:transform>

请注意,第一个模板与 urn:dm:student 命名空间中的 student 元素匹配。 如果匹配值只是“student”,则它只匹配不具有命名空间的学生元素。 然后,apply-templates 元素处理也是 urn:dm:student 命名空间的所有子名称元素。
      如你所看到的,了解命名空间在词法和抽象上的工作原理对于理解整个 XML 规范系列至关重要。 你将遇到许多类似这种情况,这些情况分散在整个新兴的 XML 规范中。

回顾

      命名空间是一组名称,其中所有名称都是唯一的。 通过 XML 中的命名空间,可以赋予元素和属性唯一的名称。 尽管命名空间往往是许多混淆的根源,但一旦你熟悉了它们的定义和使用方式(无论是语法上还是抽象上),它们就很容易理解。 有关命名空间的详细信息,请参阅 上的 XML 中的命名空间建议http://www.w3.org/TR/REC-xml-names,以及 和 http://www.jclark.com/xml/xmlns.htmhttp://www.xml.com/pub/1999/01/namespaces.html上的 Ronald Bourret http://www.rpbourret.com/xml/NamespacesFAQ.htm 的命名空间常见问题解答。


向 发送有关 Aaron xmlfiles@microsoft.com的问题和评论。
Aaron Skonnard 是 DevelopMentor 的讲师和研究员,在那里他开发 XML 课程。 Aaron 合著 Essential XML (Addison-Wesley Longman,2000年) ,并写了 Essential WinInet (Addison-Wesley Longman,1998年) 。在 与 Aaron http://staff.develop.com/aarons联系。