Python 如何用lxml中的文本替换元素?
使用lxml的ElementTreeAPI实现可以很容易地从XML文档中完全删除给定的元素,但是我看不到一种简单的方法来一致地用一些文本替换元素。例如,给定以下输入:Python 如何用lxml中的文本替换元素?,python,xml,lxml,elementtree,Python,Xml,Lxml,Elementtree,使用lxml的ElementTreeAPI实现可以很容易地从XML文档中完全删除给定的元素,但是我看不到一种简单的方法来一致地用一些文本替换元素。例如,给定以下输入: input = '''<everything> <m>Some text before <r/></m> <m><r/> and some text after.</m> <m><r/></m> <m>
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>
'''
但是,如何用文本替换每个元素以获得输出:
<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>
删除之前的一些文本
删除和一些文字后。
删除
删除前和删除后的文本
同级之后的文本删除同级之前的文本
在我看来,由于ElementTree API通过每个元素的.text
和.tail
属性而不是树中的节点来处理文本,这意味着您必须根据元素是否具有同级元素来处理许多不同的情况,现有元素是否具有.tail
属性,依此类推。我错过了一些简单的方法吗?使用:
导入io
将lxml.etree作为ET导入
数据=“”
之前的一些文本
之后还有一些文字。
前后文本
兄弟姐妹后的文本兄弟姐妹前的文本
'''
f=ET.fromstring(数据)
xslt=''\
删除
'''
xslt_doc=ET.parse(io.BytesIO(xslt))
transform=ET.XSLT(XSLT\u doc)
f=变换(f)
打印(等至字符串(f))
屈服
<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>
删除之前的一些文本
删除和一些文字后。
删除
删除前和删除后的文本
同级之后的文本删除同级之前的文本
我认为unutbu的XSLT解决方案可能是实现目标的正确方法
然而,这里有一种有点老套的方法来实现它,方法是修改
标记的尾部,然后使用etree.strip\u元素
从lxml导入etree
数据=“”
之前的一些文本
之后还有一些文字。
前后文本
兄弟姐妹后的文本兄弟姐妹前的文本
'''
f=etree.fromstring(数据)
对于f.xpath('//r')中的r:
r、 tail='DELETED'+r.tail如果r.tail其他'DELETED'
etree.strip_元素(f,'r',带_tail=False)
打印etree.tostring(f,pretty\u print=True)
给你:
<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>
删除之前的一些文本
删除和一些文字后。
删除
删除前和删除后的文本
同级之后的文本删除同级之前的文本
使用strip\u元素
的缺点是,您无法使它在替换其他元素时保留部分
元素。它还需要存在ElementTree
实例(可能不是这样)。最后,您不能使用它来替换XML注释或处理指令。
以下是你应该做的工作:
如果
有子项,是否也要删除这些子项?或者合并到
的父节点中?在本例中,我只想删除
节点及其所有子节点,并用文本字符串替换它。希望这更容易:)+1这是一个很好的,但确实不明显的答案:)我想到这个问题是因为我的能力不足,我希望有一个比这个更简单的方法。即使有这样一个简短的例子,XSLT也很冗长,与我问题中删除元素的代码相比,很难理解。谢谢,这是一个很好的解决方案-我不知道strip\u elements
或with\u tail
选项,我不愿意使用lxml进行html处理。但可能会切换到Beautifulsoup,它对基本html修改更加直观,并且可以使用lxml作为解析器soup=BeautifulSoup(文本,“lxml”)/soup。查找所有('r')。将所有('u替换为('DELETED')
感谢@benzkij提供的提示!非常奇怪的是,文本有时被视为ElementTree API中其他节点的尾部,而不仅仅是xml想要的普通文本节点。我认为text='DELETED'+r.tail
应该是text='DELETED'+r.tail,如果r.tail是'DELETED'
。
<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>
<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>
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)