我有一个简单的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中删除<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
标记时 - 我才认为这是测试人员的一个怪癖。输出是:
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提供了一个有效的解决方案,使用Pythontail
函数而不是完整的xpath。鉴于来自@alecxe的评论所引用的文档不适用于lxml,我将保持开放状态,任何人都想知道在应该有完整的xpath实现时原始问题存在的原因。
答案 0 :(得分:2)
您应该使用xpath()
方法:
for todo in root.xpath('//en-note//en-todo/following-sibling::text()[1]'):
print todo
另请注意 - 我在开头添加了//
并删除了.text
- 您已经拥有了文本节点 - 他们没有{ {1}}属性。
答案 1 :(得分:1)
注意:此答案针对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()
个空格。