2

我有以下简单的xml:

<root>
 <item>
  <d>2002-05-30T09:00:00</d>
 </item>
 <item>
  <d>2005-05-30T09:00:00</d>
 </item>
 <item>
  <d>2003-05-30T09:00:00</d>
 </item>
</root>

现在我想使用 XPath 找到最小或最大 dateTime 节点。

我目前的解决方案是:

/root/item[not(number(translate(./d, 'TZ:-', '.')) <= number(translate(following-sibling::item, 'TZ:-', '.')))][not(number(translate(./d, 'TZ:-', '.')) <= number(translate(preceding-sibling::item, 'TZ:-', '.')))][1]/d

它有效,但丑陋得要命,而且效率不高。基本上它将 dateTime 转换为数字,然后将它们相互比较。我从这里改编了这个。

最好的方法是什么?

干杯

4

3 回答 3

12

如果您事先不知道 的数量,那么您不能在 XPath 1.0 中使用,item因为每个没有节点集参数的函数都将其参数转换为节点集中的第一个节点,并且顺序比较运算符不适用于字符串。

在 XPath 2.0 中,您可以使用:

max(/root/item/d/xs:dateTime(.))
于 2010-08-30T15:14:32.633 回答
2

@neo,您列出的 XPath 表达式在我测试时不起作用。尝试不同的数据集,你会看到:

<root>
   <item>
      <d>2003-05-30T09:00:00</d>
   </item>
   <item>
      <d>2002-05-30T09:00:00</d>
   </item>
   <item>
      <d>2005-05-30T09:00:00</d>
   </item>
</root>

您的 XPath 生成2003-05-30T09:00:00,这显然不是最大值。

并且它不起作用是有道理的,因为 translate() 函数中的前面的兄弟:: 和后面的兄弟:: 轴只会产生一个兄弟。您正在尝试对每个轴上的所有同级进行一般(设置)比较,但 translate() 的第一个参数必须转换为字符串,然后一般比较运算符才有机会做它的事情。将节点集转换为字符串会忽略除文档顺序中的第一个节点之外的所有节点。

此外,translate(./d, 'TZ:-', '.')为您提供类似2003.05.30.09.00.00. 这不是一个有效的数字,超出了“5”。您的测试数据之所以有效,是因为年份都不同。你会得到更好的结果,translate(./d, 'TZ:-', '')这会产生 20030530090000.

Alejandro 说在 XPath 1.0 中不可能做到这一点,他可能是对的。让我们尝试一下,即使我们不成功,也许我们也会学到一些东西。

接下来,我将尝试在 translate 函数之外使用一般比较,以便它可以比较整个节点集。像这种天真的尝试:

/root/item[
    not(following-sibling::item[
         translate($current/d, 'TZ:-', '') &lt;= translate(./d, 'TZ:-', '')])
    and not(preceding-sibling::item[
         translate($current/d, 'TZ:-', '') &lt;= translate(./d, 'TZ:-', '')])]

然而,这是不完整的,如伪变量 $current 所示,它应该引用最外层的项目,即所有谓词之外的上下文节点。不幸的是,当内部谓词将另一个上下文压入堆栈时,XPath 1.0 没有为我们提供一种方法来引用该外部上下文。

(我似乎记得\一些 XSLT 的实现,例如 MSXML,允许您使用扩展功能来执行此操作current(1),但我目前找不到关于此的信息。无论如何,您要求提供 XPath 解决方案,并且current()不是 XPath。)

在这一点上,我将同意 Alejandro 的观点,即在纯粹的标准 XSLT 1.0 中这是不可能的。

如果您指定使用 XPath 的环境,例如 XSLT、Javascript 或 XQuery,我们可能会建议一种有效的方法来获得您需要的内容。如果是 XPath 2.0,Alejandro 有你的答案。

如果您有 XQuery 1.0,它应该支持 XPath 2.0,因此您可以使用 Alejandro 的解决方案,使用 doc() 来访问您的输入 XML 文档:

max(doc("myInput.xml")/root/item/d/xs:dateTime(.))
于 2010-08-30T17:07:29.930 回答
0

它对我有用,但我现在正在寻找增强的 xpath,即以下数据:

<root>
 <items>
  <item>
   <d>2002-05-30T09:00:00</d>
  </item>
 </items>
 <items>
  <item>
   <d>2005-05-30T09:00:00</d>
  </item>
 </items>
 <items>
  <item>
   <d>2005-05-30T10:00:00</d>
  </item>
 </items>  
</root>
于 2017-01-16T12:20:06.980 回答