2010-01-29 157 views
34

这里是我的XML的摘录:的XPath:选择所有的兄弟姐妹之后,直到另一个兄弟

<node/> 
<node/> 
<node id="1">content</node> 
<node/> 
<node/> 
<node/> 
<node id="2">content</node> 
<node/> 
<node/> 

我定位在node[@id='1']。我需要一个Xpath来匹配所有的<node/>元素,直到下一个非空节点(这里是node[@id='2'])。


编辑: 的@id属性只更清楚地解释我的问题,但不是在我原来的XML。我需要一个不使用@id属性的解决方案。


我做希望node[@id='2']后为空的兄弟姐妹匹配,所以我不能用一个天真following-sibling::node[text()='']

我该如何做到这一点?

+0

参见:http://stackoverflow.com/questions/2165566/xslt-select-following-sibling -until-reaching-a-specified-tag – WBT 2012-07-09 21:56:06

+0

这可能是有用的:[http://stackoverflow.com/questions/2063619/how-to-reformat-xml-with-group-adjacent-xslt](http:/ /stackoverflow.com/questions/2063619/how-to-reformat-xml-with-group-adjacent-xslt) – igor 2010-01-29 13:25:18

回答

21

可以这样来做:

 
../node[not(text()) and preceding-sibling::node[@id][1][@id='1']] 

其中'1'是当前节点的ID(动态生成的表达)。

表达说:

  • 从当前上下文去父
  • 选择
  • 没有文本,并从所有“前面
  • 有一个ID兄弟节点的子节点“第一个必须具有ID为1

如果您处于XSLT中,则可以从以下同级轴中进行选择用钥匙

<!-- the for-each is merely to switch the current node --> 
<xsl:for-each select="node[@id='1']"> 
    <xsl:copy-of select=" 
    following-sibling::node[ 
     not(text()) and 
     generate-id(preceding-sibling::node[@id][1]) 
     = 
     generate-id(current()) 
    ] 
    " /> 
</xsl:for-each> 

或简单(和更有效):澳洲英语,你可以使用current()功能

<xsl:key 
    name="kNode" 
    match="node[not(text())]" 
    use="generate-id(preceding-sibling::node[@id][1])" 
/> 

<xsl:copy-of select="key('kNode', generate-id(node[@id='1']))" /> 
+0

我终于走上了另一条路线,因为我在XSLT之外,因此我选择了所有以下兄弟节点,并迭代它们,并在我遇到下一个时停止我的循环空。我接受你的答案是最彻底的,因为我现在认为XPath中没有一行代码可以完成我所要求的功能。 – glmxndr 2010-02-03 08:09:29

+0

@subtenante:呃 - 但是* *是一个XPath单行代码,在我的答案中是否正确? – Tomalak 2010-02-03 08:16:33

+0

是的,你说得对,我的问题并不十分清楚,因为我提出的id属性只是为了展示和解释问题。实际上我的XML中没有id属性。 – glmxndr 2010-02-03 08:27:21

8

的XPath 2.0有运营商的< <“和 '>>',其中node1 << node2是如果node1以文档顺序在node2之前,则为true。 因此,基于该使用XPath 2.0在XSLT样式表2.0,其中当前节点是节点[@id =“1”]可以使用

following-sibling::node[not(text()) and . << current()/following-sibling::node[@od][1]] 

这也需要从XSLT的电流()函数,因此这就是为什么我说“在XSLT 2.0样式表中使用XPath 2.0”。上面的语法是纯XPath,在XSLT样式表中,您需要将'< <'转义为'& lt; & lt;'。

8
比接受的答案简单

//node[@id='1']/following-sibling::node[following::node[@id='2']] 
  • 找不到任何相关节点的ID为 '1'
  • 现在找到以下所有兄弟node元素
  • ...但所元素也有nodeid="2"之后的某个地方。

图中所示为行动,以更加清晰的测试文件(和法律id值):

xml = '<root> 
<node id="a"/><node id="b"/> 
<node id="c">content</node> 
<node id="d"/><node id="e"/><node id="f"/> 
<node id="g">content</node> 
<node id="h"/><node id="i"/> 
</root>' 

# A Ruby library that uses libxml2; http://nokogiri.org 
require 'nokogiri'; doc = Nokogiri::XML(xml) 

expression = "//node[@id='c']/following-sibling::node[following::node[@id='g']]" 
puts doc.xpath(expression) 
#=> <node id="d"/> 
#=> <node id="e"/> 
#=> <node id="f"/> 
+0

为什么你在这里选择'跟随'轴?如果文档较大(除了跟随轴比任何其他轴慢),这可能会导致进一步误报。 – Abel 2015-10-17 22:53:16