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>"
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のルートノードの直下にない場合でも、私のものは動作します。
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>
私は1つの状況に出会った:
<div>
<script>
some code
</script>
text here
</div>
div.remove(script)
は、意図していないtext here
部分を削除します。
答え here に続いて、etree.strip_elements
が私にとってより良いソリューションであることがわかりました。with_tail=(bool)
paramを使用して、背後のテキストを削除するかどうかを制御できます。
しかし、これでタグにxpathフィルターを使用できるかどうかはわかりません。通知のためにこれを置いてください。
ドキュメントは次のとおりです。
strip_elements(tree_or_element、* tag_names、with_tail = True)
指定されたタグ名を持つすべての要素をツリーまたはサブツリーから削除します。これにより、すべての属性、テキストコンテンツ、および子孫を含む要素とそのサブツリー全体が削除されます。また、
with_tail
キーワード引数オプションを明示的にFalseに設定しない限り、要素の末尾テキストも削除されます。タグ名には、
_Element.iter
のようにワイルドカードを含めることができます。これは、一致した場合でも渡した要素(またはElementTreeルート要素)を削除しないことに注意してください。子孫のみを扱います。ルート要素を含める場合は、この関数を呼び出す前にタグ名を直接確認してください。
使用例::
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 )
すでに述べたように、remove()
メソッドを使用して、ツリーから(サブ)要素を削除できます。
for bad in tree.xpath("//fruit[@state=\'rotten\']"):
bad.getparent().remove(bad)
ただし、そのtail
を含む要素は削除されます。これは、HTMLのような混合コンテンツドキュメントを処理している場合に問題になります。
<div><fruit state="rotten">avocado</fruit> Hello!</div>
になる
<div></div>
これは、あなたがいつも望んでいないものだと思う:)要素だけを削除し、その尾を保つヘルパー関数を作成しました:
def remove_element(el):
parent = el.getparent()
if el.tail.strip():
prev = el.getprevious()
if prev:
prev.tail = (prev.tail or '') + el.tail
else:
parent.text = (parent.text or '') + el.tail
parent.remove(el)
for bad in tree.xpath("//fruit[@state=\'rotten\']"):
remove_element(bad)
この方法では、末尾のテキストが保持されます。
<div> Hello!</div>