最短的XPath,用于查找兄弟dateTime节点的最小/最大值

时间:2010-08-30 14:32:02

标签: xml datetime xpath xpath-2.0

我有以下简单的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转换为数字,然后将它们相互比较。我从here改编了这个。

最好的方法是什么?

干杯

3 个答案:

答案 0 :(得分:11)

如果你事先不知道item的数量,你就不能在XPath 1.0中了,因为每个函数都有一个no node-set参数,它的参数是第一个节点在节点集中,并且顺序比较运算符不适用于字符串。

在XPath 2.0中,您可以使用:

max(/root/item/d/xs:dateTime(.))

答案 1 :(得分: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()函数中的previous-sibling ::和following-sibling :: axes每个只产生一个兄弟。你试图对每个轴上的所有兄弟进行一般性(集合)比较,但是在一般比较运算符有机会完成它之前,translate()的第一个参数必须转换为字符串。 Converting a nodeset to a string ignores all nodes except the first one in document order.

此外,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,亚历杭德罗有你的答案。

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

max(doc("myInput.xml")/root/item/d/xs:dateTime(.))

答案 2 :(得分: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>