как удалить элемент в lxml

мне нужно полностью удалить элементы, основанные на содержимом атрибута, используя 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>"

3 ответов


использовать remove метод xmlElement:

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.


Вы ищите


Я встретил одну ситуацию:

<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.

обратите внимание, что это не удалит элемент (или корень 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
       )