Removing an element from a parsed XML tree disrupts iteration
<p>I want to parse an xml file, then process the result tree by removing selected elements.  My problem is that removing an element disrupts the loop that iterates over the elements.</p>

<p>Consider the following xml data:</p>

<pre><code>&lt;results&gt;
    &lt;group&gt;
        &lt;a /&gt;
        &lt;b /&gt;
        &lt;c /&gt;
    &lt;/group&gt;
&lt;/results&gt;
</code></pre>

<p>and the code:</p>

<pre><code>import xml.etree.ElementTree as ET

def showGroup(group,s):
    print(s + '  len=' + str(len(group)))
    print('&lt;group&gt;' )
    for e in group:
        print('   &lt;' + e.tag + '&gt;')
    print('&lt;/group&gt;\n')

def processGroup(group):
    for e in group:
        if e.tag != 'a':
            group.remove(e)
            showGroup(group,'removed &lt;' + e.tag + '&gt;')

tree = ET.parse('x.xml')
root = tree.getroot()

for group in root:
    processGroup(group)
</code></pre>

<p>I expected the for loop to process elements <code>&lt;a&gt;</code>, <code>&lt;b&gt;</code>, and <code>&lt;c&gt;</code> in order.  In particular:</p>

<ol>
<li>processing <code>&lt;a&gt;</code> should not remove any element</li>
<li>processing <code>&lt;b&gt;</code> should remove <code>&lt;b&gt;</code></li>
<li>processing <code>&lt;c&gt;</code> should remove <code>&lt;c&gt;</code></li>
</ol>

<p>I expected the resulting tree to have a single element inside <code>&lt;group&gt;</code> (the <code>&lt;a&gt;</code> element), and that len(group) would return 1.</p>

<p>Instead, after processing <code>&lt;b&gt;</code>, the for loop decides the end test has been met, and it does not process element <code>&lt;c&gt;</code>.  If it did, <code>&lt;c&gt;</code> would be removed.  Instead, I am left with a tree with elements <code>&lt;a&gt;</code> and <code>&lt;c&gt;</code>, and len(group) returns 2.</p>

<h2>What do I need to do to process all three elements while removing selected elements? PS: any comments on style or better ways to do something are welcome.</h2>

<p>Update: an ugly hack "fixes" the problem at the cost of some efficiency, if there is no code after removing the element.  But in my real program, there is a lot of code after the pruning loop.</p>

<pre><code>for e in group:
    if e.tag != 'a':
        group.remove(e)
        showGroup(group,'removed &lt;' + e.tag + '&gt;')
        processGroup(group)
</code></pre>

<p>I assume that if the for loop is disrupted, then starting again with the group at the beginning might solve the problem. Recursion is a tidy way of doing that - at the expense of reprocessing all elements that have already been checked but not removed.</p>

<p>I am not satisfied with this solution.</p>