微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

是否需要在根元素中声明XML命名空间以便通过XPath查询进行匹配?

我无法弄清楚XPath本身是否应该受到指责,或者是否是特定的XPath实现使得这一点变得如此困难. SO问题 – How to change an an XML element in a namespace with MSDeploy Parameters.xml file? – 是我的灵感来源.

什么行不通

这是不起作用的基本示例.

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

XPath查询不返回任何内容,而不是:

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>

修改过的XPath查询

//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>

修改过的XPath查询(与我期望的工作相同):

//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或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 NamespacesXpath规格.

在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实现自动重新声明范围内的命名空间声明,您当然可以利用它,但有时也会让您感到困惑,正如您所注意到的那样.

原文地址:https://www.jb51.cc/xml/293002.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。