4

给定 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按表达式返回给我的节点列表:按属性查找dc子节点的最大节点dt(将其解析为date),如果其v属性值为“0”,则返回该c节点。

我希望得到一个c节点(@cid="c0"),因为/root/c[cid="c1"]/d[@dt="2016-01-01"]/@v不等于 0(等于 1)。

到目前为止,我一直坚持使用此 XPath:

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

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

XPath 因以下原因而失败:没有为以布尔值、数字、字符串或 URI 以外的原子值开头的序列定义有效的布尔值

我想这是由于滥用max功能,但无法使其正常工作。

更新:

  1. 让我们假设c节点将具有其属性d的唯一最大值的子节点。dt
  2. 我还尝试了 XPath 3.0 表达式:

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

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

4

2 回答 2

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表达式来恢复显式预计算:

/root/c[
  let $max := max(d/@dt/xs:date(.))
  return d[@dt = $max]/@v = '0'
]
于 2016-10-05T10:53:37.420 回答
2

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

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

享受!

于 2016-10-06T02:51:33.557 回答