我有以下解析xml的方法
import re
from lxml.html.soupparser import fromstring
inString = """
<doc>
<q></q>
<p1>
<p2 dd="ert" ji="pp">
<p3>1</p3>
<p3>2</p3>
<p3>32</p3>
<p3>3</p3>
</p2>
<p2 dd="ert" ji="pp">
<p3>4</p3>
<p3>5</p3>
<p3>ABC</p3>
<p3>6</p3>
</p2>
</p1>
<r></r>
<p1>
<p2 dd="ert" ji="pp">
<p3>7</p3>
<p3>8</p3>
<p3>ABC</p3>
<p3>9</p3>
</p2>
<p2 dd="ert" ji="pp">
<p3>10</p3>
<p3>11</p3>
<p3>XYZ</p3>
<p3>12</p3>
</p2>
</p1>
</doc>
"""
root = fromstring(inString)
#nodes = root.xpath("./doc//p1/p2/p3[contains(text(),'ABC') or contains(text(),'XYZ')]/preceding-sibling::p3")
ns = {"re": "http://exslt.org/regular-expressions"}
nodes = root.xpath(".//p3[re:match(.,'XYZ') or re:match(.,'ABC')]/preceding-sibling::p3", namespaces=ns)
给了我
4 5 7 8 10 11
所以它完全跳过我理想输出的第一个<p2>
1 2 32 3 4 5 7 8 10 11
所以,如果我无法在<p3>ABC<p3>
中找到<p3>XYZ<p3>
或<p2>
,我仍然需要<p3>
的所有<p2>
。那可能吗?
修改
我试过
".//p3[re:match(.,'XYZ') or re:match(.,'ABC')]/preceding-sibling::p3 | .//p3"
但是这给了我
1 2 32 3 4 5 ABC 6 7 8 ABC 9 10 11 XYZ 12
这就是一切
部分解决方案
我尝试了以下xpath
".//p3[re:match(.,'XYZ') or re:match(.,'ABC')]/preceding-sibling::p3 | .//p3[not (contains(text(),'ABC') or contains(text(),'XYZ'))]/preceding-sibling::p3"
给了我
1 2 32 4 5 ABC 7 8 ABC 10 11 XYZ
哪个更好但仍然不正确。请注意,它不在6
,而且包含我不想要的ABC
和XYZ
答案 0 :(得分:1)
良好的开端,怎么样:
.//p3[text() = 'XYZ' or text() = 'ABC']/preceding-sibling::p3 | .//p2[not(p3[text() = 'ABC' or text() = 'XYZ'])]/p3
那就是:对于没有p3孩子等于ABC或XYZ的每个p2,给我p3孩子。
(字符串等于而不是regexp,因为在此示例中不需要regexp,但您可以使用regexp)