查找兄弟日期时间节点的最小/最大的最短 XPath

发布于 2024-09-16 09:25:11 字数 775 浏览 5 评论 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 查找最小或最大日期时间节点。

我目前的解决方案是:

/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

它有效,但非常丑陋而且效率不高。基本上它将日期时间转换为数字,然后将它们相互比较。我从此处改编了此内容。

最好的方法是什么?

干杯

I have the following simple 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>

Now I want to find the minimum or maximum dateTime node using XPath.

My solution at the moment is:

/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

It works but is is ugly as hell and not very efficient. Basically it converts the dateTime to a number and then compares them with each other. I adapted this from here.

What is the nicest way to do this?

Cheers

neo

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

彩虹直至黑白 2024-09-23 09:25:11

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

在 XPath 2.0 中你可以使用:

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

You could not in XPath 1.0 if you will not know in advance the number of item because every function wich has a no node-set argument cast its argument taking the first node in node-set, and order comparison operator doesn't work with strings.

In XPath 2.0 you could use:

max(/root/item/d/xs:dateTime(.))
他是夢罘是命 2024-09-23 09:25:11

@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:: 和 follow-sibling:: 轴只会产生一个同级。您试图对每个轴上的所有同级进行常规(设置)比较,但在常规比较运算符有机会执行其操作之前,translate() 的第一个参数必须转换为字符串。 将节点集转换为字符串会忽略除文档顺序中的第一个节点之外的所有节点。

此外,translate(./d, 'TZ:-', '.') 会给出类似 2003.05.30.09.00.00 的结果。这不是一个超出“5”的有效数字。您的测试数据仅有效,因为年份都不同。使用 translate(./d, 'TZ:-', '') 可以获得更好的结果,生成 20030530090000

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

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

/root/item[
    not(following-sibling::item[
         translate($current/d, 'TZ:-', '') <= translate(./d, 'TZ:-', '')])
    and not(preceding-sibling::item[
         translate($current/d, 'TZ:-', '') <= 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(.))

@neo, the XPath expression you list doesn't work when I test it. Try a different data set and you'll see:

<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>

Your XPath produces 2003-05-30T09:00:00, which obviously is not the max.

And it makes sense that it doesn't work, because the preceding-sibling:: and following-sibling:: axes inside the translate() functions will only yield one sibling each. You're trying to go a general (set) comparison over all the siblings on each axis, but the first argument to translate() has to get converted to a string, before the general comparison operator has a chance to do its thing. Converting a nodeset to a string ignores all nodes except the first one in document order.

Furthermore, translate(./d, 'TZ:-', '.') gives you results like 2003.05.30.09.00.00. That's not a valid number, beyond the '5'. Your test data only works because the years are all different. You would get better results with translate(./d, 'TZ:-', '') which would yield 20030530090000.

Alejandro says it's not possible to do this in XPath 1.0, and he may be right. Let's try it, and maybe we'll learn something even if we don't succeed.

Next, I would try to use the general comparison outside the translate function, so that it can compare whole node-sets. Something like this naive attempt:

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

However this is incomplete as shown by the pseudo-variable $current, which is supposed to refer to the outermost item, the one that is the context node outside all predicates. Unfortunately, XPath 1.0 does not give us a way to refer to that outer context when another context has been pushed on the stack by an inner predicate.

(I seem to recall that \some implementations of XSLT, such as maybe MSXML, allow you to do this using an extended feature like current(1), but I can't find information on that at the moment. Anyway you asked for an XPath solution, and current() is not XPath.)

At this point I'm going to agree with Alejandro that it's impossible in pure, standard XSLT 1.0.

If you specify the environment you're using XPath in, e.g. XSLT, or Javascript, or XQuery, we can probably suggest an efficient way to get what you need. If it's XPath 2.0, Alejandro has your answer.

If you have XQuery 1.0, it should support XPath 2.0, so you can use Alejandro's solution, with doc() to access your input XML document:

max(doc("myInput.xml")/root/item/d/xs:dateTime(.))
拧巴小姐 2024-09-23 09:25:11

它对我有用,但我现在正在寻找增强的 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>

It worked for me, but I am looking an enhance xpath now i.e. for below data:

<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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文