如何在lxml中移除元素
我需要根据某个属性的内容,完全删除一些元素,使用的是Python的lxml库。举个例子:
import lxml.etree as et
xml="""
<groceries>
<fruit state="rotten">apple</fruit>
<fruit state="fresh">pear</fruit>
<fruit state="fresh">starfruit</fruit>
<fruit state="rotten">mango</fruit>
<fruit state="fresh">peach</fruit>
</groceries>
"""
tree=et.fromstring(xml)
for bad in tree.xpath("//fruit[@state=\'rotten\']"):
#remove this element from the tree
print et.tostring(tree, pretty_print=True)
我希望这段代码能打印出:
<groceries>
<fruit state="fresh">pear</fruit>
<fruit state="fresh">starfruit</fruit>
<fruit state="fresh">peach</fruit>
</groceries>
有没有办法做到这一点,而不需要先存一个临时变量,然后手动打印,比如:
newxml="<groceries>\n"
for elt in tree.xpath('//fruit[@state=\'fresh\']'):
newxml+=et.tostring(elt)
newxml+="</groceries>"
6 个回答
15
我遇到了一种情况:
<div>
<script>
some code
</script>
text here
</div>
div.remove(script)
这个命令会把我不想删除的 text here
部分也删掉。
根据这里的回答 我发现,使用 etree.strip_elements
对我来说是个更好的解决方案,因为它可以通过 with_tail=(bool)
参数来控制是否删除后面的文本。
不过我还是不太确定这个方法能否用 xpath 过滤标签。我只是想把这个信息分享出来。
这里是相关文档:
strip_elements(tree_or_element, *tag_names, with_tail=True)
这个命令会从一个树或子树中删除所有指定标签名的元素。它会删除这些元素及其整个子树,包括所有属性、文本内容和子元素。如果你不特别把
with_tail
参数设置为 False,它也会删除元素后面的文本。标签名可以使用通配符,就像在
_Element.iter
中一样。需要注意的是,即使你传入的元素(或元素树的根元素)匹配了标签名,这个命令也不会删除它。它只会处理它的子元素。如果你想包括根元素,最好在调用这个函数之前直接检查它的标签名。
示例用法:
strip_elements(some_element, 'simpletagname', # non-namespaced tag '{http://some/ns}tagname', # namespaced tag '{http://some/other/ns}*' # any tag from a namespace lxml.etree.Comment # comments )
31
你需要找的是 remove
函数。你可以调用树的 remove 方法,并传入你想要删除的子元素。
import lxml.etree as et
xml="""
<groceries>
<fruit state="rotten">apple</fruit>
<fruit state="fresh">pear</fruit>
<punnet>
<fruit state="rotten">strawberry</fruit>
<fruit state="fresh">blueberry</fruit>
</punnet>
<fruit state="fresh">starfruit</fruit>
<fruit state="rotten">mango</fruit>
<fruit state="fresh">peach</fruit>
</groceries>
"""
tree=et.fromstring(xml)
for bad in tree.xpath("//fruit[@state='rotten']"):
bad.getparent().remove(bad)
print et.tostring(tree, pretty_print=True)
结果:
<groceries>
<fruit state="fresh">pear</fruit>
<fruit state="fresh">starfruit</fruit>
<fruit state="fresh">peach</fruit>
</groceries>
191
使用xmlElement的 remove
方法:
tree=et.fromstring(xml)
for bad in tree.xpath("//fruit[@state=\'rotten\']"):
bad.getparent().remove(bad) # here I grab the parent of the element to call the remove directly on it
print et.tostring(tree, pretty_print=True, xml_declaration=True)
如果要和@Acorn的版本做个比较,我的这个方法即使要删除的元素不直接在xml的根节点下面,也能正常工作。