【问题标题】:Xpath query and timeXpath 查询和时间
【发布时间】:2010-10-03 07:40:15
【问题描述】:

您好,这是我的 XML 文件的内容:

<?xml version="1.0" encoding="ISO-8859-1"?>
<mainNode>
    <sub time="08:00">
        <status id="2">On</status>
        <status id="3">Off</status>
    </sub>
    <sub time="13:00">
        <status id="4">On</status>
        <status id="7">On</status>
    </sub>
    <sub time="16:00">
        <status id="5">On</status>
        <status id="6">On</status>
        <status id="7">Off</status>
        <status id="8">On</status>
    </sub>
    <sub time="20:00">
        <status id="4">Off</status>
        <status id="7">On</status>
    </sub>
    <sub time="23:59">
        <status id="4">On</status>
        <status id="7">On</status>
    </sub>
</mainNode>

我的程序获取当前时间: 如果我得到 15.59,我必须检索下一个子时间(16.00)的所有状态 id:

<sub time="16:00">
        <status id="5">On</status>
        <status id="6">On</status>
        <status id="7">Off</status>
        <status id="8">On</status>
    </sub>

通过第二个 XPath 查询,我必须获取上一个子时间 (13.00) 的所有状态 ID。 怎么做?我知道 SQL,但我对 XPath 很陌生。如果有的话,我也接受重要的 XPath 资源的 url。谢谢!

【问题讨论】:

  • 您应该说明您的语言平台和 Xpath 版本。 XPath 2.0 将使这更容易,但您可能无法使用。
  • 您说的完全正确:我们谈论的是 XPath 2.0。
  • 我在回答中提供了两种解决方案:XPath 1.0 和 XPath 2.0。为问题 +1!
  • @vyger 感谢您指出这一点——“代码”按钮中的一些奇怪的错误。 XSLT 2 代码中的索引显示为 7 和 8。刚刚编辑它,如果继续,我将进一步编辑并且不会使用代码按钮。
  • @vyger 请参阅:tinyurl.com/dd4tsy 这是关于 XSLT 的书籍,但它们必须很好地涵盖 XPath。我最喜欢的是 Michael Kay 和他关于 XSLT 2.0 和 XPath 2.0 的最新著作。 BTW,如果你认为和回答是你想要的,你可以选择它(点击复选标记)

标签: xpath time


【解决方案1】:

这里有两种解决方案:

我。 XPath 1.0

这是一对XPath 1.0 表达式,用于选择所需的节点:

/*/*
    [translate(@time, ':','') 
    > 
     translate('15:59',':','')
    ][1]

选择时间晚于15:59 的第一个sub 节点。

/*/*
    [translate(@time, ':','') 
    < 
     translate('15:59',':','')
    ][last()]

selects 选择第一个sub 节点早于15:59sub 时间

我们可以将这些包含在 XSLT 转换中并检查是否产生了真正想要的结果:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes"/>

    <xsl:template match="/">
      First time after 15:59: 
      <xsl:copy-of select=
       "/*/*
          [translate(@time, ':','') 
         > 
           translate('15:59',':','')
          ][1]
      "/>

      First time before 15:59: 
      <xsl:copy-of select=
       "/*/*
          [translate(@time, ':','') 
         &lt; 
           translate('15:59',':','')
          ][last()]
      "/>
  </xsl:template>
</xsl:stylesheet>

当对最初提供的 XML 文档应用上述转换时

<mainNode>
    <sub time="08:00">
        <status id="2">On</status>
        <status id="3">Off</status>
    </sub>
    <sub time="13:00">
        <status id="4">On</status>
        <status id="7">On</status>
    </sub>
    <sub time="16:00">
        <status id="5">On</status>
        <status id="6">On</status>
        <status id="7">Off</status>
        <status id="8">On</status>
    </sub>
    <sub time="20:00">
        <status id="4">Off</status>
        <status id="7">On</status>
    </sub>
    <sub time="23:59">
        <status id="4">On</status>
        <status id="7">On</status>
    </sub>
</mainNode>

产生想要的结果

  First time after 15:59: 


<sub time="16:00">
        <status id="5">On</status>
        <status id="6">On</status>
        <status id="7">Off</status>
        <status id="8">On</status>
</sub>

  First time before 15:59: 

 <sub time="13:00">
        <status id="4">On</status>
        <status id="7">On</status>
 </sub>

请注意以下几点:

  1. 使用 XPath translate() 函数去掉冒号

  2. 第二个表达式中last()函数的使用

  3. 比较前无需将时间转换为秒

  4. 当用作 XML 文档(例如 XSLT 样式表)的一部分时,&lt; 运算符必须转义

二。 XPath 2.0

XPath 2.0 中我们可以使用以下两个表达式来生成选择所需的节点:

/*/*[xs:time(concat(@time,':00')) 
    gt 
     xs:time('15:59:00')
    ][1]

选择时间晚于15:59 的第一个sub 节点。

/*/*[xs:time(concat(@time,':00')) 
   lt 
     xs:time('15:59:00')
    ][last()]

selects 选择第一个sub 节点早于15:59sub 时间

我们可以将这些包含在 XSLT 2.0 转换中并检查是否产生了真正想要的结果:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output omit-xml-declaration="yes"/>

    <xsl:template match="/">
      First time after 15:59: 
      <xsl:copy-of select=
       "/*/*[xs:time(concat(@time,':00')) 
           gt 
             xs:time('15:59:00')
             ][1]
      "/>

      First time before 15:59: 
      <xsl:copy-of select=
       "/*/*[xs:time(concat(@time,':00')) 
           lt 
             xs:time('15:59:00')
          ][last()]
      "/>
    </xsl:template>
</xsl:stylesheet>

当对原始提供的 XML 文档应用上述转换时(与第一个解决方案相同),会产生相同的预期结果。

请注意以下几点:

  1. 在 XPath 2.0 中,xs:time 是本机数据类型。但是,为了从 xml 文档中的值构造 xs:time(),我们必须将缺失的秒数部分连接到它们。
  2. 在 XPath 2.0 中,xs:time 值可以与“atomic-value comarison operators 进行比较,例如 ltgt

【讨论】:

  • 嗨,Dimitre,为什么是 2? [翻译(@time, ':','') > 翻译('15:59',':','') ][2]
  • @vyger 感谢您指出这一点——“代码”按钮中的一些奇怪的错误。 XSLT 2 代码中的索引显示为 7 和 8。刚刚编辑它,如果继续,我将进一步编辑,不会使用代码按钮。
  • Dmitre,您的解决方案真的很完整,很抱歉指出那个错字。第一个是我一直在寻找的解决方案:我以为可以做到,但最终我不知道该怎么做。谢谢! :-) 你能推荐一本关于 XPath 的好书吗?
  • @vyger 请参阅:tinyurl.com/dd4tsy 这是关于 XSLT 的书籍,但它们必须很好地涵盖 XPath。我最喜欢的是 Michael Kay 和他关于 XSLT 2.0 和 XPath 2.0 的最新著作。 BTW,如果你认为和回答是你想要的,你可以选择它(点击复选标记)
  • @AnthonyWJones 谢谢,SO 是一个非常好的问答网站。
【解决方案2】:

这是丑陋的 Xpath 1.0 解决方案:-

sub[number((substring-before(@time, ':')) * 60 + number(substring-after(@time, ':'))) &gt; 959][1]

注意 959 = 15 * 60 + 59 我相信你可以在你的调用代码中做到这一点。

给那个节点前一个节点可以被访问为:-

preceding-sibling::sub[1]

然而,一个务实的、常识性的解决方案是将 XML 数据加载到一组数据结构中,并使用更适合此任务的语言来查找项目。

【讨论】:

  • 对于 XPath 解决方案,这就是要走的路。恕我直言,它甚至不是特别丑陋。 +1
  • 我将测试这个解决方案和 krosenvold 一个(最后一个听起来更有趣,特别是如果它有效的话):-)
  • @Tomalak:我必须承认我期待它更丑,但你说得对,它实际上并没有那么糟糕。
  • 不需要计算总秒数——看我的回答。
  • @AnthonyWJones:安东尼,有没有办法像字符串一样连接数字?我可以将 15:59 转换为 1559 并将其与 1600 进行比较。
【解决方案3】:

只要时间是 HH:MM 就应该像下面这样工作: (我必须原谅我的语法,因为我只是在不跑步的情况下涉足,考虑一下这个伪 xpath):

xmlns:fn="http://www.w3.org/2005/02/xpath-functions"

//sub[fn:compare(@time,'12:59') > 0][1]/status

这应该选择时间大于 12:59 的所有元素,然后选择这些元素中的第一个。

您还可以将值“12:59”作为 external parameter 传递到 xpath 评估中。

【讨论】:

  • 这听起来很有趣,我一定要试试。比较函数的确切链接是w3.org/TR/xpath-functions/#func-compare(也很好的解释)
  • 比较两个 xs:time 值时,只使用“lt”和“gt”会更简单。
【解决方案4】:

如果您自己生成 xml,您可以使用整数值(例如刻度)更改存储时间属性的方式,然后您可以使用类似的东西进行简单的数值比较

//sub[@time > 1389893892]

【讨论】:

  • 我自己不生成它,他们也不想改变它的生成方式......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-14
  • 2020-08-12
  • 2012-01-23
  • 1970-01-01
  • 2020-07-16
  • 1970-01-01
相关资源
最近更新 更多