XPath 3.0:按条件选择节点(按日期查找最大子节点)

时间:2016-10-05 09:59:44

标签: xpath-2.0 xpath-3.0

鉴于XML:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <c cid="c0" v="100">
        <d did="c00" v="0" dt="2016-01-01" />
        <d did="c01" v="0" dt="2016-02-03" />
        <d did="c02" v="0" dt="2016-01-15" />
    </c>
    <c cid="c1" v="100">
        <d did="c10" v="1" dt="2016-01-01" />
        <d did="c11" v="0" dt="2015-03-03" />
        <d did="c12" v="0" dt="2015-04-15" />
    </c>
</root>

我必须找到XPath 2.0或3.0,它将按表达式返回c个节点列表:d cdt个子节点的最大date个节点attribute(将其解析为v),如果其c属性值为&#34; 0&#34;,则返回c节点。

我希望得到一个/root/c[cid="c1"]/d[@dt="2016-01-01"]/@v节点(带有@cid =&#34; c0&#34;),因为/root/c[d[max(xs:date(@dt))]/@v="0"] 不等于0(等于1) 。

我坚持使用这个XPath沙发:

max

它给了我一个错误(我使用Oxygen XML Editor,XPath 3.0):

  

XPath失败的原因是:没有为a定义有效的布尔值   序列以除布尔值,数字之外的原子值开始,   字符串或URI

我认为这是由于误用了c函数,但无法使其正常工作。

更新:

  1. 让我们假设d个节点的dt个子节点具有唯一的/root/c[d[@dt=max(.//@dt/xs:date(.))]/@v="0"]属性的最大值。
  2. 我也试过XPath 3.0表达式:

    $('.button').click(function() { $('.showvaluehere').text($(this).text()) })

  3. 但它返回了我所有节点(错误的结果)。

2 个答案:

答案 0 :(得分:2)

在XQuery中,查询非常简单,可以编写为仅计算每c个节点的最大日期:

for $c in /root/c
let $max := max($c/d/@dt/xs:date(.))
where $c/d[@dt = $max]/@v = '0'
return $c

在XPath中,您可以将查询写入(至少在概念上)每个d节点计算一次,并希望结果由处理器优化或者足够快:

/root/c[d[@dt = max(../d/@dt/xs:date(.))]/@v = '0']

您还可以使用XPath的let expression来恢复显式预计算:

/root/c[
  let $max := max(d/@dt/xs:date(.))
  return d[@dt = $max]/@v = '0'
]

答案 1 :(得分:2)

这是一个更短且效率更高的(每个 <c> 元素的最大值只计算一次) XPath 2.0 one-liner < /强>:

/*/c[max(d/xs:date(@dt)) = d[@v eq '0']/@dt]

享受!