如何处理两个元素之间的节点

时间:2019-04-16 08:02:36

标签: xpath

我想处理两个元素之间的节点;第二个由@xml:id标识,第一个通过此ID引用第二个。通常,其他兄弟元素(与该问题无关/应该照常处理)位于所讨论的两个元素之间。

<root>
... text i'm not interested in ...
<A ref="#id_1"/> interesting <C>text</C> no 1 <B xml:id="id_1"/>
... text i'm not interested in ...
<A ref="#id_2"/> interesting text no 2 <B xml:id="id_2"/>
... text i'm not interested in ...
</root>

我要寻找的是一个xPath命令,该命令为每个具有属性“ ref”的元素“ A”选择该元素之后的节点,直到具有a的“ ref”中提供的ID的特定元素“ B”。

因此在上面给出的示例中,对于第一个“ A”,应选择

"interesting <C>text</C> no 1"

第二个“ A”

"interesting text no 2"

(以此类推;“ A”和“ B”元素的数量非常高)。

到目前为止,我的粗略猜测是fn交集可能是解决方案的一部分。 (我正在使用xPath 2.0。)

2 个答案:

答案 0 :(得分:0)

choroba用户在评论中写道,您可以使用XPath Axes获取值:

//A/following-sibling::text()[1]

要仅获取具有 ref 属性的元素,可以使用:

//A[@ref]/following-sibling::text()[1]

更新:也许节点集相交的凯西方法可以帮助您(see this SO):

/*/A[1]/following-sibling::node()[count(.|/*/B[1]/preceding-sibling::node()) = count(/*/B[1]/preceding-sibling::node())]

要再次发生,只需将所有[1]替换为[2]

答案 1 :(得分:0)

此XPath 2.0表达式

/root/(
   for $a in A, 
       $b in B[concat('#', @xml:id) = $a/@ref][1] 
   return .//text()[$b >> .][. >> $a]
)

选择此文本节点(为清楚起见添加了引号):

' interesting '
'text'
' no 1 '
' interesting text no 2 '

https://xsltfiddle.liberty-development.net/bFN1y9t中测试

请注意:将for expression用于“内部联接”。

在XPath 1.0中,没有办法声明关闭,因此也没有办法进行“内部联接”。但是,如果您确定开始和结束标记之间没有重叠,则可以使用:

/root//text()[
  (preceding::A|preceding::B)[last()][self::A]
][(following::A|following::B)[1][self::B]
]

/root//text()[
   preceding::*[self::A|self::B][1][self::A]
][following::*[self::A|self::B][1][self::B]
]

http://www.xpathtester.com/xpath/a3051d2ad3af3423502b221bef6a580e中测试

编辑问题

  

我要寻找的是一个为每个选择的xPath命令   具有属性“ ref”的元素“ A”,此元素之后的节点   直到特定元素“ B”以及a的“ ref”中提供的ID。

如果现在要使用节点,则后代文本节点只需替换表达式中的路径即可:

XPath 2.0表达式

/root/(
   for $a in A, 
       $b in B[concat('#', @xml:id) = $a/@ref][1] 
   return node()[$b >> .][. >> $a]
)

XPath 1.0表达式

/root/node()[
  (preceding::A|preceding::B)[last()][self::A]
][(following::A|following::B)[1][self::B]
]