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']
>>>