Мне нужно полностью удалить элементы на основе содержимого атрибута, используя lxml python. Пример:
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>"
Вы ищете
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>
источник
.remove()
элемент должен быть дочерним по отношению к элементу, который вы его вызываете. Поэтому вам нужно вызвать его у родителя элемента, который вы хотите удалить. Ответ исправлен.Встречал одну ситуацию:
<div> <script> some code </script> text here </div>
div.remove(script)
удалитtext here
часть, которую я не хотел.после ответа здесь я обнаружил, что
etree.strip_elements
это лучшее решение для меня, которое вы можете контролировать, удаляете ли вы текст позади с помощьюwith_tail=(bool)
параметра.Но все же я не знаю, можно ли использовать фильтр xpath для тега. Просто поставьте это для информирования.
Вот документ:
источник
Как уже упоминалось, вы можете использовать этот
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>
источник
el.tail is not None
, как может быть такой случай.Вы также можете использовать html из lxml, чтобы решить эту проблему:
from lxml import html 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 = html.fromstring(xml) print("//BEFORE") print(html.tostring(tree, pretty_print=True).decode("utf-8")) for i in tree.xpath("//fruit[@state='rotten']"): i.drop_tree() print("//AFTER") print(html.tostring(tree, pretty_print=True).decode("utf-8"))
Он должен вывести это:
//BEFORE <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> //AFTER <groceries> <fruit state="fresh">pear</fruit> <fruit state="fresh">starfruit</fruit> <fruit state="fresh">peach</fruit> </groceries>
источник