Ken*_*itt 8 xml xpath namespaces
我无法弄清楚XPath本身是否应该受到指责,或者是否是特定的XPath实现使得这一点变得如此困难.问题 - 如何使用MSDeploy Parameters.xml文件更改名称空间中的XML元素? - 是我的灵感.
这是不起作用的基本示例.
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>
Run Code Online (Sandbox Code Playgroud)
XPath的:
//spring/objects/object[@id='CultureResolver']/@type
Run Code Online (Sandbox Code Playgroud)
XPath查询不返回任何内容,而不是:
Spring.Globalization.Resolvers.SessionCultureResolver, Spring.Web
Run Code Online (Sandbox Code Playgroud)
我或许天真地希望以下方面有效.
修改后的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>
Run Code Online (Sandbox Code Playgroud)
修改过的XPath查询:
//spring/spring:objects/spring:object[@id='CultureResolver']/@type
Run Code Online (Sandbox Code Playgroud)
此查询在我使用的在线测试程序中引发错误:
ERROR - Failed to evaluate XPath expression: org.apache.xpath.domapi.XPathStylesheetDOM3Exception: Prefix must resolve to a namespace: spring
Run Code Online (Sandbox Code Playgroud)
修改后的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>
Run Code Online (Sandbox Code Playgroud)
修改过的XPath查询(与我期望的工作相同):
//spring/spring:objects/spring:object[@id='CultureResolver']/@type
Run Code Online (Sandbox Code Playgroud)
为了增加混淆,我发现以下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
Run Code Online (Sandbox Code Playgroud)
由于命名空间和前缀之间的相互作用,这是否令人困惑?似乎声明没有前缀的命名空间不仅包括该命名空间中的相关元素,而且还包括其所有子节点,因此将其描述为"默认命名空间"(如在相关问题的答案中).声明带前缀的命名空间甚至不包含该命名空间中的相关元素!
是否有某些原因需要将名称空间包含在XML文档的根元素中,而不依赖于特定的XPath实现?
我试图解决的问题涉及Microsoft Web Deploy(MSDeploy)使用的任何XPath引擎.
我也在使用这个在线XPath测试器.
一个有趣且问题很好的问题!据我所知,难点在于XPath引擎处理输入文档中的命名空间声明的方式.
简短的回答
不,这种行为一般与XPath或XPath规范无关.这是由于个别实施.
规格说什么
就XML和XPath规范而言,名称空间可以在任何元素上声明,并且最外层(或"根")元素没有什么特别之处.根元素上的命名空间声明就像任何其他声明一样.
当然还有规则.例如,前缀必须与使用其QName的元素上的名称空间URI相关联,或者与该元素(或该属性)的祖先相关联.所以,以下不是格式良好的XML:
<prefix:root>
<child xmlns:prefix="www.example.com"/>
</prefix:root>
Run Code Online (Sandbox Code Playgroud)
第二个重要规则:默认命名空间只能应用于声明它的元素和所有后代元素.在以下文档中,root元素根本没有命名空间:
<root>
<child xmlns="www.example.com">
<grandchild/>
</child>
</root>
Run Code Online (Sandbox Code Playgroud)
在XPath的实现中会发生什么
现在,如果针对XML文档计算XPath表达式,则此输入文档中存在的所有名称空间声明也必须明确地可用于(声明或"注册")到XPath引擎.
的XPath的一些实施方式通过简单地简化这个重新声明所有命名空间声明是在范围为元素或属性,可作为一个XPath引擎(也参见输入XML文档的这个).
在您的情况下,似乎只考虑在最外层元素上做出的声明.这就是你上一篇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>
Run Code Online (Sandbox Code Playgroud)
works - 因为名称空间声明是在根元素上进行的,并且您从根元素执行XPath表达式.您可以省略默认命名空间的未声明,因为它没有任何效果.
最后,回答你的上一个问题:
是否有某些原因需要将名称空间包含在XML文档的根元素中,而不依赖于特定的XPath实现?
不,没有理由命名空间声明应该在根元素上,除了
如果您的XPath实现自动重新声明范围内的命名空间声明,您当然可以利用它,但有时也会让您感到困惑,正如您所注意到的那样.