Python XPath:是否可以使用可选的XPath查询?

时间:2015-12-04 18:55:22

标签: python xml xpath

我有以下解析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,而且包含我不想要的ABCXYZ

1 个答案:

答案 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)