Xpath查询和时间

时间:2009-01-24 12:01:17

标签: xpath time

嗨,这是我的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资源。谢谢!

4 个答案:

答案 0 :(得分: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数据加载到一组数据结构中,并使用更适合此任务的语言来查看项目。

答案 1 :(得分:2)

以下是两个解决方案:

予。 XPath 1.0

这是一对选择所需节点的XPath 1.0个表达式

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

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

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

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

我们可以在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样式表,必须转义<运算符

  5. II。 XPath 2.0

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

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

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

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

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

    我们可以在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

答案 2 :(得分:1)

只要时间是HH:MM就像以下一样: (我必须原谅我的语法,因为我只是在不跑步,考虑这个伪x路径):

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

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

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

您还可以将值'12:59'作为e xternal parameter传递到xpath评估中。

答案 3 :(得分:0)

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

的方式进行简单的数值比较
//sub[@time > 1389893892]