- Java核心技术·卷Ⅱ:高级特性(原书第10版)
- (美)凯S.霍斯特曼
- 1237字
- 2024-12-20 22:36:06
3.5 使用命名空间
Java语言使用包来避免名字冲突。程序员可以为不同的类使用相同的名字,只要它们不在同一个包中即可。XML也有类似的命名空间(namespace)机制,可以用于元素名和属性名。
名字空间是由统一资源标识符(Uniform Resource Identifier,URI)来标识的,比如:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/159-2-i.jpg?sign=1739553672-R41l3Ckb0J1cdfRzauxbnclymN4urIiA-0-bb4201d815a8184358a70834a55aaaca)
HTTP的URL格式是最常见的标识符。注意,URL只用作标识符字符串,而不是一个文件的定位符。例如,名字空间标识符:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/159-3-i.jpg?sign=1739553672-6Vg8q86NTi293whgS2Z6Ol4xzEqVb7Fc-0-be501e7dc335f58129a47f821b9b66af)
表示了不同的命名空间,尽管Web服务器将为这两个URL提供同一个文档。
在命名空间的URL所表示的位置上不需要有任何文档,XML解析器不会尝试去该处查找任何东西。然而,为了给可能会遇到不熟悉的命名空间的程序员提供一些帮助,人们习惯于将解释该命名空间的文档放在URL位置上。例如,如果你把浏览器指向XML Schema的命名空间URL(http://www.w3.org/2001/XMLSchema),就会发现一个描述XML Schema标准的文档。
为什么要用HTTP URL作为命名空间的标识符?这是因为这样容易确保它们是独一无二的。如果使用实际的URL,那么主机部分的唯一性就将由域名系统来保证。然后,你的组织可以安排URL余下部分的唯一性,这和Java包名中的反向域名是一个原理。
尽管长名字空间的唯一性很好,但是你肯定不想处理超出必需范围的长标识符。在Java编程语言中,可以用import机制来指定很长的包名,然后就可以只使用较短的类名了。在XML中有类似的机制,比如:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/160-i.jpg?sign=1739553672-wbLXd9kAlN0SixkmwHWFDgMPwClZyKWr-0-dc2f34bd1e543d387b905d237c70909d)
现在,该元素和它的子元素都是给定命名空间的一部分了。
子元素可以提供自己的命名空间,例如:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/160-2-i.jpg?sign=1739553672-yFRRibTeWIlq3yNbHDG95OzmaELdHDhL-0-2418ae389ab565e64ac0f533d1ea2ec6)
这时,第一个子元素和孙元素都是第二个命名空间的一部分。
无论是只需要一个命名空间,还是命名空间本质上是嵌套的,这个简单机制都工作得很好。如若不然,就需要使用第二种机制,而Java中并没有类似的机制。你可以用一个前缀来表示命名空间,即为特定文档选取的一个短的标识符。下面是一个典型的例子:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/160-3-i.jpg?sign=1739553672-vHGO2prIaUwo7nsXGgzpPaiIJFcbXR9F-0-fb8cd2b7f0c38b9d6baa756723a337f0)
下面的属性:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/160-4-i.jpg?sign=1739553672-8GI4a2En1NX1gCFM4FbsjvyCKuUd0YRR-0-59e30573ce2de6c7d3ab09d8fb49881a)
用于定义命名空间和前缀。在我们的例子中,前缀是字符串xsd。这样,xsd:schema实际上指的是命名空间http://www.w3.org/2001/XMLSchema中的schema。
注意:只有子元素继承了它们父元素的命名空间,而不带显式前缀的属性并不是命名空间的一部分。请看下面这个特意构造出来的例子:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/160-5-i.jpg?sign=1739553672-iDj5m4lTEAm1j9CvZxw49gTT5eDrFdzT-0-5b4bcc4ac373ef93434adbe97c3e0c61)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/161-i.jpg?sign=1739553672-10ZIJ560SDdR4l3fSIvNUjFl3GYYYgwL-0-564b31a93d919cfb216196edead880bf)
在这个示例中,元素configuration和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方法:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/161-2-i.jpg?sign=1739553672-P2AInQMobzTtwxe6RkZ98ah1OwWCApGc-0-4ff5f6534df6d5a08f3ba67b9f509682)
这样,该工厂产生的所有生成器便都支持命名空间了。每个节点有三个属性:
·带有前缀的限定名(qualified),由getNodeName和getTagName等方法返回。
·命名空间URI,由getNamespaceURI方法返回。
·不带前缀和命名空间的本地名(local name),由getLocalName方法返回。
下面是一个例子。假设解析器看到了以下元素:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/161-3-i.jpg?sign=1739553672-NVgZADqfqajKb8Iy3Yh3diw49E0QnJFJ-0-f843ba2a47fa3703d9a3b27a62d7e8a3)
它会报告如下信息:
·限定名=xsd:schema
·命名空间URI=http://www.w3.org/2001/XMLSchema
·本地名=schema
注意:如果对命名空间的感知特性被关闭,getLocalName和getNamespaceURI方法将返回null。
org.w3c.dom.Node 1.4
·String getLocalName()
返回本地名(不带前缀),或者在解析器不感知命名空间时,返回null。
·String getNamespaceURI()
返回命名空间URI,或者在解析器不感知命名空间时,返回null。
javax.xml.parsers.DocumentBuilderFactory 1.4
·boolean isNamespaceAware()
·void setNamespaceAware(boolean value)
获取或设置工厂的namespaceAware属性。当设为true时,工厂产生的解析器是命名空间感知的。