Удаление элемента из разобранного дерева XML прерывает итерацию

Я хочу проанализировать XML-файл, а затем обработать дерево результатов, удалив выбранные элементы. Моя проблема в том, что удаление элемента нарушает цикл, который выполняет итерацию над элементами.

Рассмотрим следующие XML-данные:

<results> <group> <a /> <b /> <c /> </group> </results> 

и код:

 import xml.etree.ElementTree as ET def showGroup(group,s): print(s + ' len=' + str(len(group))) print('<group>' ) for e in group: print(' <' + e.tag + '>') print('</group>\n') def processGroup(group): for e in group: if e.tag != 'a': group.remove(e) showGroup(group,'removed <' + e.tag + '>') tree = ET.parse('x.xml') root = tree.getroot() for group in root: processGroup(group) 

Я ожидал, что цикл for обработает элементы <a> , <b> и <c> по порядку. В частности:

  1. обработка <a> не должна удалять какой-либо элемент
  2. обработка <b> должна удалить <b>
  3. обработка <c> должна удалить <c>

Я ожидал, что полученное дерево будет иметь один элемент внутри <group> (элемент <a> ) и что len (group) вернет 1.

Вместо этого, после обработки <b> , цикл for принимает решение о завершении теста и не обрабатывает элемент <c> . Если это так, <c> будет удалено. Вместо этого у меня осталось дерево с элементами <a> и <c> , а len (group) возвращает 2.

Что мне нужно сделать для обработки всех трех элементов при удалении выбранных элементов? PS: любые комментарии по стилю или лучшие способы сделать что-то приветствуются.

Обновление: уродливый взлом «исправляет» проблему за счет некоторой эффективности, если после удаления элемента нет кода. Но в моей реальной программе после цикла обрезки есть много кода.

 for e in group: if e.tag != 'a': group.remove(e) showGroup(group,'removed <' + e.tag + '>') processGroup(group) 

Я предполагаю, что если цикл for будет нарушен, то повторное начало с группой в начале может решить проблему. Рекурсия – это аккуратный способ сделать это – за счет переработки всех элементов, которые уже были проверены, но не удалены.

Я не удовлетворен этим решением.

  • Файл файла Python Open
  • Заполнение Many2many поля (odoo 8)
  • Разбить XML-файл на объект Python
  • selfClosingTags в BeautifulSoup
  • Python ElementTree: анализ строки и получение экземпляра ElementTree
  • Как создать документ Word с помощью Python?
  • есть ли что-нибудь, чтобы преобразовать xml -> yaml напрямую?
  • Как установить идентификатор элемента в xml.dom.minidom Python?
  • One Solution collect form web for “Удаление элемента из разобранного дерева XML прерывает итерацию”

    Проблема в том, что вы удаляете элементы из того, что вы итерируете, когда вы удаляете элемент, остальные элементы меняются, поэтому вы можете удалить неправильные элементы:

    Простое решение состоит в том, чтобы перебирать копию дерева или использовать обратное :

    копия:

      def processGroup(group): # creates a shallow copy so we are removing from the original # but iterating over a copy. for e in group[:]: if e.tag != 'a': group.remove(e) showGroup(group,'removed <' + e.tag + '>') 

    наоборот:

     def processGroup(group): # starts at the end, as the container shrinks. # when an element is removed, we still see # elements at the same position when we started out loop. for e in reversed(group): if e.tag != 'a': group.remove(e) showGroup(group,'removed <' + e.tag + '>') 

    используя логику копирования:

     In [7]: tree = ET.parse('test.xml') In [8]: root = tree.getroot() In [9]: for group in root: ...: processGroup(group) ...: removed <b> len=2 <group> <a> <c> </group> removed <c> len=1 <group> <a> </group> 

    Вы также можете использовать ET.tostring вместо цикла for:

     import xml.etree.ElementTree as ET def show_group(group,s): print(s + ' len=' + str(len(group))) print(ET.tostring(group)) def process_group(group): for e in group[:]: if e.tag != 'a': group.remove(e) show_group(group, 'removed <' + e.tag + '>') tree = ET.parse('test.xml') root = tree.getroot() for group in root.findall(".//group"): process_group(group) 
    Python - лучший язык программирования в мире.