【问题标题】:How to get an element with varying namespace如何获取具有不同命名空间的元素
【发布时间】:2014-08-11 07:30:05
【问题描述】:

我希望得到以下 xml 的元素名称。 我的请求中的问题是我想获取 Payload 元素。为此我使用了这个表达式

name(//env:Payload)

所以我得到了这个结果 env:Payload

<env:requeset xmlns:env="http://eai.ssss.xxx/Envelope" xmlns:ggg="http://fai.dgn.sss/ggg">
<env:clientbody>
<env:Payload>
<ggg:Service>
<ggg:Request>
<a>name</a>
<b>age</b>
<c>address</c>
</ggg:Request>
</ggg:Service>
</env:Payload>
</env:clientbody>
</env:requeset>

但有时我的客户发送带有不同元素的请求,有时也没有命名空间。那么我如何也得到以下请求

<requeset xmlns:="http://eai.ssss.xxx/Envelope" xmlns:ggg="http://fai.dgn.sss/ggg">
<clientbody>
<Payload>
<ggg:Service>
<ggg:Request>
<a>name</a>
<b>age</b>
<c>address</c>
</ggg:Request>
</ggg:Service>
</Payload>
</clientbody>
</requeset>

对于上述请求,我使用了相同的表达式,所以它给出了错误,所以我将如何在 2 种情况下或任何情况下获取 Payload 元素。 我试过了,但它不起作用

name(//( local-name()='Payload'))

它给ERROR - Failed to evaluate XPath expression: A location step was expected following the '/' or '//' token.

所以请指导获取没有命名空间和不同命名空间的元素,我也尝试过包含表达式,但我无法得到。

【问题讨论】:

    标签: xml xpath xquery


    【解决方案1】:

    如错误消息所示,您编写的语法不正确。如果要比较每个元素的本地名称,可以这样做:

    //*(local-name() = 'Payload')
    

    但是等等,还有更好的选择可以实现这一目标。您在这里所做的基本上是无视命名空间。您还可以使用通配符命名空间运算符* 以更清晰的语法实现此目的。就这么简单

    //*:Payload
    

    如果您仍想尊重命名空间,您还可以使用联合运算符| 合并两个结果。这样,您将获得带有 env 命名空间但没有任何命名空间的 Payload 元素:

    //env:Payload | //Payload
    

    当然,在所有这些情况下,您都可以使用name() 来获取元素名称。

    【讨论】:

    • +1 用于展示不同的方法——即使我不同意 *:Payload 的语法比使用 local-name() 更清晰。
    • @MathiasMüller 好吧,也许这是一个品味问题。但是,它肯定更短。此外,对于许多处理器,命名空间通配符表示会更快,更容易优化。
    • 但是有些时候命名空间没有像没有前缀那样定义时间 //*:Payload 将无法工作,给出前缀错误所以我将如何获得带有前缀但没有前缀的元素名称,并且命名空间会有所不同。再次 / /*(local-name() = 'Payload') 这给出了同样的错误
    • @user3595078 你错了,//*:Payload 会给你 Payload 有和没有命名空间。此外,另一个表达式绝对是有效的 XPath。你可能说错了。您使用哪个处理器以及如何调用 XPath 执行?
    【解决方案2】:

    您误解了您的数据和您的问题;因此,您提出的问题与您的情况无关。

    您没有任何具有不同命名空间的元素。您显示的两个请求都有扩展名称为 {http://eai.ssss.xxx/Envelope}Payload; 的元素。它们的区别仅在于对该命名空间使用不同的前缀(env 与根本没有前缀)。相同的查询应该适用于两者;一个简单的演示是:

    declare namespace e = "http://eai.ssss.xxx/Envelope";
    
    let $testdata := <data>
      <env:requeset xmlns:env="http://eai.ssss.xxx/Envelope" 
                    xmlns:ggg="http://fai.dgn.sss/ggg">
        <env:clientbody>
          <env:Payload>
            ...
          </env:Payload>
        </env:clientbody>
      </env:requeset>
      <requeset xmlns="http://eai.ssss.xxx/Envelope"
                xmlns:ggg="http://fai.dgn.sss/ggg">
        <clientbody>
          <Payload>
            ...
          </Payload>
        </clientbody>
      </requeset>
    </data>
    
    return $testdata//e:Payload
    

    如果你试试这个,你会发现它返回两个元素,而不仅仅是一个。

    如果您的第二个示例输入有问题,可能是因为字符串 xmlns: 不是命名空间声明的合法名称。将xmlns:="http://eai.ssss.xxx/Envelope" 更改为xmlns="http://eai.ssss.xxx/Envelope"

    【讨论】:

      猜你喜欢
      • 2013-02-18
      • 2014-09-14
      • 1970-01-01
      • 1970-01-01
      • 2021-10-19
      • 1970-01-01
      • 1970-01-01
      • 2015-09-12
      • 1970-01-01
      相关资源
      最近更新 更多