Das Entfernen eines Elements aus einem geparsten XML-Baum stört die Iteration

Ich möchte eine XML-Datei analysieren und dann den Ergebnisbaum verarbeiten, indem ausgewählte Elemente entfernt werden. Mein Problem ist, dass das Entfernen eines Elements die Schleife stört, die über die Elemente iteriert.

Betrachten Sie die folgenden XML-Daten:

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

Und der Code:

 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) 

Ich erwartete die for-Schleife, um Elemente <a> , <b> und <c> in Bearbeitung zu verarbeiten. Bestimmtes:

  1. Verarbeitung <a> sollte kein Element entfernen
  2. Verarbeitung <b> sollte <b> entfernen
  3. Verarbeitung <c> sollte <c> entfernen

Ich erwartete, dass der daraus resultierende Baum ein einzelnes Element innerhalb von <group> (das <a> -Element) hat und dass len (group) 1 zurückgeben würde.

Stattdessen, nach der Verarbeitung <b> , entscheidet die for-Schleife, dass der Endtest erfüllt ist, und es verarbeitet das Element <c> . Wenn ja, würde <c> entfernt werden. Stattdessen bleibe ich mit einem Baum mit Elementen <a> und <c> , und len (Gruppe) gibt 2 zurück.

Was muss ich tun, um alle drei Elemente zu verarbeiten, während ausgewählte Elemente entfernt werden? PS: irgendwelche Kommentare zum Stil oder bessere Möglichkeiten, etwas zu tun sind willkommen.

Update: ein hässlicher Hack "fixes" das Problem auf Kosten einer gewissen Effizienz, wenn es keinen Code nach dem Entfernen des Elements gibt. Aber in meinem echten Programm gibt es nach der Beschneidungsschleife viel Code.

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

Ich nehme an, dass, wenn die for-Schleife unterbrochen wird, dann das Starten wieder mit der Gruppe am Anfang könnte das Problem lösen. Rekursion ist eine ordentliche Art, das zu tun – auf Kosten der Wiederaufbereitung aller Elemente, die bereits überprüft wurden, aber nicht entfernt wurden.

Ich bin mit dieser Lösung nicht zufrieden.

One Solution collect form web for “Das Entfernen eines Elements aus einem geparsten XML-Baum stört die Iteration”

Das Problem ist, dass Sie Elemente aus etwas entfernen, was Sie übertreiben, wenn Sie ein Element entfernen, werden die restlichen Elemente verschoben, so dass Sie am Ende die falschen Elemente entfernen können:

Eine einfache Lösung ist, über eine Kopie des Baumes zu iterieren oder umgekehrt zu verwenden :

Kopieren:

  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 + '>') 

rückgängig gemacht:

 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 + '>') 

Mit der Kopierlogik:

 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> 

Sie können auch ET.tostring anstelle von Ihrer for-Schleife verwenden:

 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) 
  • OSError: [Errno 36] Dateiname zu lang:
  • Parse XHTML5 mit undefinierten Entitäten
  • Wie bekomme ich den vollständigen XML- oder HTML-Inhalt eines Elements mit ElementTree?
  • Elementtree zeigt Elemente außer Betrieb
  • Wie verwandle ich eine XML-Datei mit XSLT in Python?
  • XML zu csv (-ähnliches) Format
  • Holen Sie die Details aus der SOAP-XML-Antwort
  • Wie man verschiedene Ausnahmen in verschiedenen Python-Version
  • Hübscher Druck in lxml scheitert, wenn ich Tags zu einem geparsten Baum hinzufüge
  • Python: xml.etree.ElementTree, Entfernen von "Namespaces"
  • Parsen einer großen (~ 40GB) XML-Textdatei in Python
  • Python ist die beste Programmiersprache der Welt.