【问题标题】:Python lxml XPath : preceding keyword does not give expected resultPython lxml XPath:前面的关键字没有给出预期的结果
【发布时间】:2016-03-07 02:15:55
【问题描述】:

我正在尝试按如下方式解析 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>ABC</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>ABC</p3>
        <p3>12</p3>

     </p2>

</p1>
</doc>
"""
root = fromstring(inString)

nodes = root.xpath("./doc//p1/p2/p3[contains(text(),'ABC')]//preceding::p2//p3")

print " ".join([re.sub('[\s+]', ' ', para.text.encode('utf-8').strip()) for para in nodes])

所以,对于每个&lt;p1&gt; 标签,我想访问&lt;p2&gt; 中的&lt;p3&gt; 标签。然后我只想要&lt;p3&gt; 标签到具有ABC 之类的文本的标签。但是,如果我运行上面的代码,我会得到

1 2 ABC 3 4 5 ABC 6 7 8 ABC 9

想要的输出是

1 2 4 5 7 8 10 11

另外,如果我做出这个改变

nodes = root.xpath("./doc//p1/p2/p3[contains(text(),'ABC')]")

我明白了

ABC ABC ABC ABC

所以看起来第二种方法能够根据 xpath 从整个文档中获取所有 &lt;p3&gt; 节点,这很好。为什么我的第一个查询不起作用?

如何获得所需的输出?

【问题讨论】:

  • 顺便说一句,你为什么使用lxml.html 来处理 XML 数据?为什么不lxml.etree
  • 我想用soupparser来利用beautiful soup的html parser

标签: python xml xpath xml-parsing lxml


【解决方案1】:

找到包含ABCp3 后,您无需爬上树 - 只需使用preceding-sibling“侧身”走:

./doc//p1/p2/p3[contains(text(),'ABC')]/preceding-sibling::p3

打印1 2 4 5 7 8 10 11

【讨论】:

  • 完美!谢谢 :) 顺便说一句,为什么前面只有一个 / ?
  • @AbtPst 我不确定,但我认为 /// 在前面的兄弟姐妹之前不会有任何区别。谢谢。
  • // is short for /descendant-or-self::node()/ 所以-or-self 部分会在这里得到相同的结果,因为没有p3 孩子descendant 部分// 不会选择任何东西
猜你喜欢
  • 1970-01-01
  • 2021-01-06
  • 2021-08-31
  • 2020-06-30
  • 1970-01-01
  • 1970-01-01
  • 2020-05-29
  • 1970-01-01
  • 2019-06-15
相关资源
最近更新 更多