3.5 使用命名空间
Java语言使用包来避免名字冲突。程序员可以为不同的类使用相同的名字,只要它们不在同一个包中即可。XML也有类似的命名空间(namespace)机制,可以用于元素名和属性名。
名字空间是由统一资源标识符(Uniform Resource Identif?ier, URI)来标识的,比如:
HTTP的URL格式是最常见的标识符。注意,URL只用作标识符字符串,而不是一个文件的定位符。例如,名字空间标识符:
表示了不同的命名空间,尽管Web服务器将为这两个URL提供同一个文档。
在命名空间的URL所表示的位置上不需要有任何文档,XML解析器不会尝试去该处查找任何东西。然而,为了给可能会遇到不熟悉的命名空间的程序员提供一些帮助,人们习惯于将解释该命名空间的文档放在URL位置上。例如,如果你把浏览器指向XML Schema的命名空间URL(http://www.w3.org /2001/XMLSchema),就会发现一个描述XML Schema标准的文档。
为什么要用HTTP URL作为命名空间的标识符?这是因为这样容易确保它们是独一无二的。如果使用实际的URL,那么主机部分的唯一性就将由域名系统来保证。然后,你的组织可以安排URL余下部分的唯一性,这和Java包名中的反向域名是一个原理。
尽管长名字空间的唯一性很好,但是你肯定不想处理超出必需范围的长标识符。在Java编程语言中,可以用import机制来指定很长的包名,然后就可以只使用较短的类名了。在XML中有类似的机制,比如:
现在,该元素和它的子元素都是给定命名空间的一部分了。
子元素可以提供自己的命名空间,例如:
这时,第一个子元素和孙元素都是第二个命名空间的一部分。
无论是只需要一个命名空间,还是命名空间本质上是嵌套的,这个简单机制都工作得很好。如若不然,就需要使用第二种机制,而Java中并没有类似的机制。你可以用一个前缀来表示命名空间,即为特定文档选取的一个短的标识符。下面是一个典型的例子:
用于定义命名空间和前缀。在我们的例子中,前缀是字符串xsd。这样,xsd:schema实际上指的是命名空间http://www.w3.org/2001/XMLSchema中的schema。
注意:只有子元素继承了它们父元素的命名空间,而不带显式前缀的属性并不是命名空间的一部分。请看下面这个特意构造出来的例子:
在这个示例中,元素conf?iguration和size是URI为http://www.horstmann.com/ corejava的命名空间的一部分。属性si:unit是URI为http://www.bipm.fr/enus/3_SI/si.html的命名空间的一部分。然而,属性value不是任何命名空间的一部分。
你可以控制解析器对命名空间的处理。默认情况下,Java XML库的DOM解析器并非“命名空间感知的”。
要打开命名空间处理特性,请调用DocumentBuilderFactory类的setNamespace Aware方法:
这样,该工厂产生的所有生成器便都支持命名空间了。每个节点有三个属性:
- 带有前缀的限定名(qualif?ied),由getNodeName和getTagName等方法返回。
- 命名空间URI,由getNamespaceURI方法返回。
- 不带前缀和命名空间的本地名(local name),由getLocalName方法返回。
下面是一个例子。假设解析器看到了以下元素:
它会报告如下信息:
- 限定名 = xsd:schema
- 命名空间 URI = http://www.w3.org/2001/XMLSchema
-
本地名 = schema
注意:如果对命名空间的感知特性被关闭,getLocalName和getNamespaceURI方法将返回null。