【问题标题】:Python / ElementTree: following-sibling error (working in xpath tester)Python / ElementTree:跟随兄弟错误(在 xpath 测试器中工作)
【发布时间】:2016-12-31 15:08:00
【问题描述】:

我有一个简单的 XML 文档(实际上是 Evernote 的 ENML),如下所示:

<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
<en-note>
   <div>Here is the Evernote logo:</div>
   <div>
      <en-media type="image/png" hash="a54fe8bcd146e20a8a5742834558543c" />
   </div>
   <div>
      <br />
   </div>
   <div>
      <en-todo />
      Task 1
   </div>
   <div>making it a bit harder</div>
   <div>
      <en-todo />
      Task 2 | 2016-12-31
   </div>
   <div>
      <br />
   </div>
   <div>
      This is another to-do
      <en-todo />
      in an awkward place
   </div>
</en-note>

我正在尝试使用 Xpath 在 en-todo 标记之后立即访问文本。我的代码是:

parsed_note = ElementTree.fromstring(note_content)
for todo in parsed_note.findall('en-note//en-todo/following-sibling::text()[1]'):
    print todo.text

我已经使用 freeformatter.com 上的 Xpath 测试器对此进行了测试——它似乎有效,但只有当我从 XML 中删除 &lt;!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"&gt; 标记时——我认为这是测试器的一个怪癖。输出是:

Text='Task 1'
Text='Task 2 | 2016-12-31'
Text='in an awkward place'

这完全符合预期和期望。

当我尝试在 Python 中运行代码时,我得到:SyntaxError: prefix 'following-sibling' not found in prefix map

我怀疑这可能与测试人员有相同的怪癖并删除了文件类型标记,但同样的错误仍然存​​在。

我正在使用标准解析器:

import defusedxml.lxml as lxml
from lxml import etree as ElementTree

我哪里出错了 - 我的 xpath 语句是否有缺陷,还是有其他原因导致我遗漏了这一点?

编辑:@Tomalek 提供了一个可行的解决方案,使用 Python tail 函数而不是完整的 xpath。鉴于来自 @alecxe 的 cmets 所引用的文档不适用于 lxml,我将保持开放状态,以防有人想冒险了解为什么在应该有完整的 xpath 实现时存在原始问题。

【问题讨论】:

    标签: python xml xpath lxml elementtree


    【解决方案1】:

    你应该使用xpath()方法:

    for todo in root.xpath('//en-note//en-todo/following-sibling::text()[1]'):
        print todo
    

    另请注意 - 我在开头添加了 // 并删除了 .text - 您已经获得了文本节点 - 它们没有 .text 属性。

    【讨论】:

    • 我的代码已经有 2x ::。调用 xpath() 方法可以消除我的问题中的错误,但不返回任何内容。
    • @HO gotcha,更新了工作代码。希望对您有所帮助。
    【解决方案2】:

    注意:此答案针对xml.etree.ElementTree。类似但更高级的 lxml.etree 模块具有完整的 XPath 支持,但下面显示的方法也适用于此。


    直接来自the documentation,强调我的:

    19.7.2。 XPath 支持

    此模块为 XPath 表达式提供有限的支持 在树中定位元素。 目标是支持一小部分 缩写语法;完整的 XPath 引擎不在 模块。

    您可以通过在 Python 中执行部分遍历来解决它。

    在这种情况下,它特别容易,因为您可以使用方便的tail property。其他情况需要更多的工作。

    parsed_note = ElementTree.fromstring(note_content)
    for todo in parsed_note.findall('.//en-todo'):
        print todo.tail
    

    您必须在返回值中添加.strip() 空格。

    【讨论】:

    • 谢谢,很抱歉我没有看到这部分文档。我试过你的方法 - 它消除了错误,但似乎没有返回任何东西(可能是因为文本不在标签本身内 - 我会做更多工作以尝试在 python 中执行此操作)。
    • @HO 引用的文档适用于 xml.etree.ElementTree,而您使用的是具有完整 XPath 支持的 lxml.etree
    • 对您的解决方案稍作修改会返回正确的结果 - 我需要将 xpath 更改为 './/en-todo' - .tail 函数然后按预期工作。
    • @alecxe 啊,我总是把这两者搞混。不过,它应该适用于两者。
    • @HO 将该位添加到答案中。如果你使用 lxml.etree,你应该有更好的 XPath 支持,正如 Alex 所说。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多