什么行不通
这是不起作用的基本示例.
XML:
<spring> <objects xmlns="http://www.springframework.net"> <object id="CultureResolver" type="Spring.Globalization.Resolvers.SessionCultureResolver,Spring.Web"> <!--configure for server--> <property name="DefaultCulture" value="en" /> </object> </objects> </spring>
XPath的:
//spring/objects/object[@id='CultureResolver']/@type
Spring.Globalization.Resolvers.SessionCultureResolver,Spring.Web
我期待的工作
我或许天真地希望以下方面有效.
修改后的XML:
<spring> <spring:objects xmlns:spring="http://www.springframework.net"> <spring:object id="CultureResolver" type="Spring.Globalization.Resolvers.SessionCultureResolver,Spring.Web"> <!--configure for server--> <spring:property name="DefaultCulture" value="en" /> </spring:object> </spring:objects> </spring>
//spring/spring:objects/spring:object[@id='CultureResolver']/@type
此查询在我使用的the online tester中引发错误:
ERROR - Failed to evaluate XPath expression: org.apache.xpath.domapi.XPathStylesheetDOM3Exception: Prefix must resolve to a namespace: spring
什么工作
修改后的XML:
<spring xmlns="" xmlns:spring="http://www.springframework.net"> <spring:objects> <spring:object id="CultureResolver" type="Spring.Globalization.Resolvers.SessionCultureResolver,Spring.Web"> <!--configure for server--> <spring:property name="DefaultCulture" value="en" /> </spring:object> </spring:objects> </spring>
//spring/spring:objects/spring:object[@id='CultureResolver']/@type
为了增加混淆,我发现以下XPath查询适用于原始示例XML(在在线测试器XPath引擎中):
//spring/*[local-name() = 'objects' and namespace-uri() = 'http://www.springframework.net']/*[@id='CultureResolver' and local-name() = 'object' and namespace-uri() = 'http://www.springframework.net']/@type
为什么?
由于命名空间和前缀之间的相互作用,这是否令人困惑?似乎声明没有前缀的命名空间不仅包括该命名空间中的相关元素,还包括其所有子节点,因此将其描述为“默认命名空间”(如this answer中的相关问题).声明带有前缀的命名空间甚至不包括该命名空间中的相关元素!
是否有某些原因需要将名称空间包含在XML文档的根元素中,而不依赖于特定的XPath实现?
我的XPath引擎
我试图解决的问题涉及Microsoft Web Deploy(MSDeploy)使用的任何XPath引擎.
我也在使用this online XPath tester.
简短的回答
不,这种行为一般与XPath或XPath规范无关.这是由于个别实施.
规格说什么
就XML和XPath规范而言,名称空间可以在任何元素上声明,并且最外层(或“根”)元素没有什么特别之处.根元素上的命名空间声明就像任何其他声明一样.
当然还有规则.例如,前缀必须与使用其QName的元素上的名称空间URI相关联,或者与该元素(或该属性的)的祖先相关联.所以,以下不是格式良好的XML:
<prefix:root> <child xmlns:prefix="www.example.com"/> </prefix:root>
第二个重要规则:默认命名空间只能应用于声明它的元素和所有后代元素.在以下文档中,根元素根本没有命名空间:
<root> <child xmlns="www.example.com"> <grandchild/> </child> </root>
我所说的规格是XML,XML Namespaces和Xpath规格.
在XPath的实现中会发生什么
现在,如果针对XML文档计算XPath表达式,则此输入文档中存在的所有名称空间声明也必须明确地可用于(声明或“注册”)到XPath引擎.
XPath的一些实现通过简单地重新声明在作为Xpath引擎的输入的XML文档的元素或属性的范围内的所有名称空间声明来简化这一点(也见this).
在您的情况下,似乎只考虑在最外层元素上做出的声明.这就是你最后一个XML文档的原因:
<spring xmlns="" xmlns:spring="http://www.springframework.net"> <spring:objects> <spring:object id="CultureResolver" type="Spring.Globalization.Resolvers.SessionCultureResolver,Spring.Web"> <!--configure for server--> <spring:property name="DefaultCulture" value="en" /> </spring:object> </spring:objects> </spring>
works – 因为名称空间声明是在根元素上进行的,并且您从根元素执行XPath表达式.您可以省略默认命名空间的未声明,因为它没有任何效果.
最后,回答你的上一个问题:
Is there some reason why namespaces need to be included in the root element of the XML document,independent of particular XPath implementations?
不,没有理由命名空间声明应该在根元素上,除了
>在我看来,在根元素上声明它们更容易找到(非常主观)
>如果您要为整个文档声明默认命名空间.在根元素上声明它是使它也适用于根元素的唯一方法
>如果根元素本身具有限定名称,即带有前缀.然后,您必须在根元素上声明此前缀和名称空间URI.
如果您的XPath实现自动重新声明范围内的命名空间声明,您当然可以利用它,但有时也会让您感到困惑,正如您所注意到的那样.