Mar*_*air 13 python xml lxml elementtree
使用lxml的ElementTree API实现从XML文档中完全删除给定元素很容易,但是我看不到用一些文本一致地替换元素的简单方法.例如,给出以下输入:
input = '''<everything>
<m>Some text before <r/></m>
<m><r/> and some text after.</m>
<m><r/></m>
<m>Text before <r/> and after</m>
<m><b/> Text after a sibling <r/> Text before a sibling<b/></m>
</everything>
'''
Run Code Online (Sandbox Code Playgroud)
...你可以轻松删除每个<r>元素:
from lxml import etree
f = etree.fromstring(data)
for r in f.xpath('//r'):
r.getparent().remove(r)
print etree.tostring(f, pretty_print=True)
Run Code Online (Sandbox Code Playgroud)
但是,你将如何用文本替换每个元素,以获得输出:
<everything>
<m>Some text before DELETED</m>
<m>DELETED and some text after.</m>
<m>DELETED</m>
<m>Text before DELETED and after</m>
<m><b/>Text after a sibling DELETED Text before a sibling<b/></m>
</everything>
Run Code Online (Sandbox Code Playgroud)
在我看来,这是因为通过与文字ElementTree的API交易.text和.tail每一个元素,而不是在树节点的属性,这意味着你必须处理依赖于元素是否已兄弟元素或者没有很多的不同的情况下,无论是现有元素有一个.tail属性,依此类推.我错过了一些简单的方法吗?
Mat*_*ttH 18
我认为unutbu的XSLT解决方案可能是实现目标的正确方法.
然而,通过修改<r/>标签的尾部然后使用,这是实现它的一种有点hacky的方式etree.strip_elements.
from lxml import etree
data = '''<everything>
<m>Some text before <r/></m>
<m><r/> and some text after.</m>
<m><r/></m>
<m>Text before <r/> and after</m>
<m><b/> Text after a sibling <r/> Text before a sibling<b/></m>
</everything>
'''
f = etree.fromstring(data)
for r in f.xpath('//r'):
r.tail = 'DELETED' + r.tail if r.tail else 'DELETED'
etree.strip_elements(f,'r',with_tail=False)
print etree.tostring(f,pretty_print=True)
Run Code Online (Sandbox Code Playgroud)
给你:
<everything>
<m>Some text before DELETED</m>
<m>DELETED and some text after.</m>
<m>DELETED</m>
<m>Text before DELETED and after</m>
<m><b/> Text after a sibling DELETED Text before a sibling<b/></m>
</everything>
Run Code Online (Sandbox Code Playgroud)
小智 7
使用strip_elements的缺点是你不能<r>在替换其他元素时保留一些元素.它还需要存在一个ElementTree实例(可能不是这种情况).最后,您不能使用它来替换XML注释或处理指令.以下应该做你的工作:
for r in f.xpath('//r'):
text = 'DELETED' + r.tail
parent = r.getparent()
if parent is not None:
previous = r.getprevious()
if previous is not None:
previous.tail = (previous.tail or '') + text
else:
parent.text = (parent.text or '') + text
parent.remove(r)
Run Code Online (Sandbox Code Playgroud)