XPath 1查询

时间:2009-02-13 19:52:15

标签: xpath

我发布了一个类似的问题,我收到了非常有用的答复。 现在问题有点不同,所以我发布了。 我指定它是一个与XPath 1相关的问题。 这是我的XML文件的内容:

<?xml version="1.0" encoding="ISO-8859-1"?>
<mainNode>
    <subNode>
        <h hm="08:45">
            <store id="1563">Open</store>
        </h>
        <h hm="13:00">
            <store id="1045">Open</store>
            <store id="763">Open</store>
            <store id="1047">Open</store>
        </h>
        <h hm="16:30">
            <store id="1045">Open</store>
            <store id="763">Open</store>
            <store id="1047">Open</store>
        </h>
        <h hm="20:00">
            <store id="1045">Open</store>
            <store id="1043">Open</store>
            <store id="1052">Open</store>
        </h>
        <h hm="22:00">
            <store id="763">Open</store>
        <store id="1052">Open</store>
        </h>
    </subNode>
</mainNode>

我的程序获取当前时间:如果我得到12.40,我必须检索下一个h hm(13.00)的所有商店ID:此问题已经解决。

在检索数据后,使用第二个XPath查询,我必须得到,直到当天(XML文件为表示)的时候,将打开一个商店。 所以,想象一下商店是用id = 1045标识的商店,现在它早上是12.40。该商店将在20.00关闭,因为它位于h hm = 13.00子节点,h hm = 16.30子节点和h hm = 20.00子节点中。所以,我必须得到20.00。

案例2:它是12.40,我必须知道763什么时候会关闭。它将在16.30关闭,无论它是否包含在最后一个节点中(h hm = 22.00)。所以,我必须得到16.30。

这可能吗?

提前致谢。

4 个答案:

答案 0 :(得分:2)

以下是如何构建这样的XPatch表达式:

以下XPath表达式选择想要的结果

($vOpen[not(count(following-sibling::h[1] | $vOpen) 
          = 
           count($vOpen))
       ][1]/@hm
|

  $vOpen[last()]/@hm

 )

  [1]

其中$vOpen

定义为:

$vge1240[store/@id=$vId]

$vge1240定义为:

/*/*/h[translate(@hm,':','') >= 1240]

$vId定义为:

1045

763

上述变量可以在XSLT样式表中定义和引用,或者,如果XPath嵌入在另一个主机中,则每个变量引用必须用变量定义的右侧替换。在这种情况下,完整的XPath表达式将是:

   (/*/*/h[translate(@hm,':','') >= 1240][store/@id=763]
      [not(count(following-sibling::h[1]
                |             
                 /*/*/h[translate(@hm,':','') >= 1240][store/@id=763]
                 )     
          =       
           count(/*/*/h[translate(@hm,':','') >= 1240][store/@id=763])) 
          ]  
          [1]
            /@hm


     |
        /*/*/h[translate(@hm,':','') >= 1240][store/@id=763]
           [last()]
                   /@hm 
       )

        [1]

<强>解释

($vOpen[not(count(following-sibling::h[1] | $vOpen) 
          = 
           count($vOpen))
       ][1]/@hm
|

  $vOpen[last()]/@hm

 )

  [1]

表示以下内容:

  1. 包含ID(763)的“打开”时间内的所有条目

  2. 选择那些直接跟随兄弟姐妹的人不属于该组(关闭或不包含763)

  3. 从第一个开始。

  4. 从上面步骤3中选择的节点和$vOpen中的最后一个元素中取出第一个(按文档顺序)。如果其中的所有条目都包含给定的Id,这将在“打开”小时内选择最后一个条目。

  5. 这里我们基本上使用Kayesian方法来交叉两个节点集 $ ns1和$ ns2:

    $ ns1 [count(。| $ ns2)= count($ ns2)]

答案 1 :(得分:1)

我将在你提到的最后question重复我对你答案的最后一部分。

将XML加载到更有利于您的要求的某些数据结构中会更加实用。这个次要问题只是重新强化了这个建议的合理性。

答案 2 :(得分:0)

如果您要查找的商店标识位于$store,则会显示包含该ID的最后一个h/@hm,然后是h,其中包含包含该商店ID的最后一个h/@hm(适用于上一个h/@hm关闭的商店)。

//h[not(store/@id=$store)]/preceding-sibling::h[store/@id = $store][1]/@hm | //h[store/@id=$store][last()]/@hm

使用您的示例XML在XSLT中进行测试:

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:variable name="store" select="763"/>

    <xsl:template match="/">
        <closes>
            <xsl:value-of select="//h[not(store/@id=$store)]/preceding-sibling::h[store/@id = $store][1]/@hm | //h[store/@id=$store][last()]/@hm"/>
        </closes>
    </xsl:template>
</xsl:stylesheet>

打印<closes>16:30</closes>。如果您将$store更改为1052,则会改为打印<closes>22:00</closes>

答案 3 :(得分:0)

我认为这很有效。它找到store / @id的最后一次连续出现(在开始时间之后),其中@id = $ id,这是我认为你正在寻找的。

<xsl:variable name="id" select="'1045'"/>
<xsl:variable name="st" select="translate('12:40',':','')"/>

...

((//h[translate(@hm,':','') >= $st])[position() = count(preceding-sibling::*[store/@id=$id])+1 and store/@id=$id])[last()]/@hm

说明: 首先,选择共享开始时间&gt; =的所有元素到提供的开始。然后,在这些结果中,选择最后一个元素的@hm属性,该元素的位置等于其中包含所请求的store / @ id标记的在前元素的数量。

这个简短版本的一个限制是,如果在开始时间之后第一个元素中没有出现商店标识,它将失败。下面的内容通过从包含正确的store / @ id的开始时间之后的第一个开始来修复该限制,但它有点麻烦:

<xsl:variable name="id" select="'1045'"/>
<xsl:variable name="st" select="translate('12:40',':','')"/>

...

((//h[translate(@hm,':','') >= $st and position() >= count(//h[not(preceding-sibling::*[store/@id=$id])])])[position() = count(preceding-sibling::*[store/@id=$id])+1 and store/@id=$id])[last()]/@hm