我发布了一个类似的问题,我收到了非常有用的答复。 现在问题有点不同,所以我发布了。 我指定它是一个与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。
这可能吗?
提前致谢。
答案 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]
表示以下内容:
包含ID(763)的“打开”时间内的所有条目
选择那些直接跟随兄弟姐妹的人不属于该组(关闭或不包含763)
从第一个开始。
从上面步骤3中选择的节点和$vOpen
中的最后一个元素中取出第一个(按文档顺序)。如果其中的所有条目都包含给定的Id,这将在“打开”小时内选择最后一个条目。
这里我们基本上使用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,这是我认为你正在寻找的。 p>
<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