XPath - 在两个节点之间提取文本

问题描述:

我遇到了XPath查询的问题。我必须解析一个分为未知数的“部分”的div。其中每个由h5用段名分隔。可能的部分标题列表是已知的,并且每个标题只能出现一次。此外,每个部分可以包含一些br标签。所以,假设我想提取“SecondHeader”下的文本。XPath - 在两个节点之间提取文本

HTML

<div class="some-class"> 
<h5>FirstHeader</h5> 
    text1 
<h5>SecondHeader</h5> 
    text2a<br> 
    text2b 
<h5>ThirdHeader</h5> 
    text3a<br> 
    text3b<br> 
    text3c<br> 
<h5>FourthHeader</h5> 
    text4 
</div> 

预期结果(对于SecondSection)

['text2a', 'text2b'] 

查询#1

//text()[following-sibling::h5/text()='ThirdHeader'] 

结果#1

['text1', 'text2a', 'text2b'] 

这显然有点太多了,所以我决定将结果限制在选定标题和标题之间的内容之前。

查询#2

//text()[following-sibling::h5/text()='ThirdHeader' and preceding-sibling::h5/text()='SecondHeader'] 

结果#2

['text2a', 'text2b'] 

取得了成果符合预期。但是,这不能用 - 我不知道SecondHeader/ThirdHeader是否存在于解析页面中。在查询中只需要使用一个部分标题。

查询#3

//text()[following-sibling::h5/text()='ThirdHeader' and not[preceding-sibling::h5/text()='ThirdHeader']] 

结果#3

[] 

能否请你告诉我,我究竟做错了什么?我已经在Google Chrome中进行了测试。

你应该能够只是测​​试第一前置兄弟h5 ...

//text()[preceding-sibling::h5[1][normalize-space()='SecondHeader']] 

如果所有的h5元素和文本节点都是兄弟节点,并且您需要逐个分组,并且可能的选项仅仅是通过之前的h5的计数来​​选择文本节点。

使用实例lxml(在Python)

>>> import lxml.html 
>>> s = ''' 
... <div class="some-class"> 
... <h5>FirstHeader</h5> 
... text1 
... <h5>SecondHeader</h5> 
... text2a<br> 
... text2b 
... <h5>ThirdHeader</h5> 
... text3a<br> 
... text3b<br> 
... text3c<br> 
... <h5>FourthHeader</h5> 
... text4 
... </div>''' 
>>> doc = lxml.html.fromstring(s) 
>>> doc.xpath("//text()[count(preceding-sibling::h5)=$count]", count=1) 
['\n text1\n '] 
>>> doc.xpath("//text()[count(preceding-sibling::h5)=$count]", count=2) 
['\n text2a', '\n text2b\n '] 
>>> doc.xpath("//text()[count(preceding-sibling::h5)=$count]", count=3) 
['\n text3a', '\n text3b', '\n text3c', '\n '] 
>>> doc.xpath("//text()[count(preceding-sibling::h5)=$count]", count=4) 
['\n text4\n'] 
>>>