How to make nested xml structure flat with python
<p>I have XML with huge nested structure.
Like this one </p>

<pre><code>&lt;root&gt;
 &lt;node1&gt;
  &lt;subnode1&gt;
    &lt;name1&gt;text1&lt;/name1&gt;
  &lt;/subnode1&gt;
 &lt;/node1&gt;
 &lt;node2&gt;
  &lt;subnode2&gt;
     &lt;name2&gt;text2&lt;/name2&gt;
  &lt;/subnode2&gt;
 &lt;/node2&gt;
&lt;/root&gt;
</code></pre>

<p>I want convert it to</p>

<pre><code>&lt;root&gt;
  &lt;node1&gt;
    &lt;name1&gt;text1&lt;/name1&gt;
  &lt;/node1&gt;
  &lt;node2&gt;
    &lt;name2&gt;text2&lt;/name2&gt;
  &lt;/node2&gt;
&lt;/root&gt;
</code></pre>

<p>I was tried with following steps</p>

<pre><code>from xml.etree import ElementTree as et

tr = etree.parse(path)
root = tr.getroot()

for node in root.getchildren():
  for element in node.iter():
    if (element.text is not None):
      node.extend(element) 
</code></pre>

<p>I also tried with <code>node.append(element)</code> but it also does not work it adds element in end and i got infinity loop.
Any helps be appreciated.</p>

<p>A few points to mention here: </p>

<p>Firstly, your test <code>element.text is not None</code> always returns <code>True</code> if you parse your XML file as given above using <code>xml.etree.Elementree</code> since at the end of each node, there is a new line character, hence, the text in each supposedly not-having-text node always have <code>\n</code> character. An alternative is to use <code>lxml.etree.parse</code> with a <code>lxml.etree.XMLParser</code> that ignore the blank text as below. </p>

<p>Secondly, it's not good to append to a tree while reading through it. The same reason for why this code will give infinite loop:</p>

<pre><code>&gt;&gt;&gt; a = [1,2,3,4]
&gt;&gt;&gt; for k in a:
        a.append(5)
</code></pre>

<p>You could see @Alex Martelli answer for this question here: <a href="http://stackoverflow.com/questions/1637807/modifying-list-while-iterating">Modifying list while iterating</a> regarding the issue.</p>

<p>Hence, you should make a <em>buffer</em> XML tree and build it accordingly rather than modifying your tree while traversing it.</p>

<pre><code>from xml.etree import ElementTree as et
import pdb;

from lxml import etree

p = etree.XMLParser(remove_blank_text=True)
path = 'test.xml'
tr = et.parse(path, parser = p)
root = tr.getroot()

buffer = et.Element(root.tag);

for node in root.getchildren():
    bnode = et.Element(node.tag)
    for element in node.iter():
        #pdb.set_trace()
        if (element.text is not None):
            bnode.append(element)
            #node.extend(element)
    buffer.append(bnode)

et.dump(buffer)
</code></pre>

<p>Sample run and results:</p>

<pre><code>Chip chip@ 01:01:53@ ~: python stackoverflow.py
&lt;root&gt;&lt;node1&gt;&lt;name1&gt;text1&lt;/name1&gt;&lt;/node1&gt;&lt;node2&gt;&lt;name2&gt;text2&lt;/name2&gt;&lt;/node2&gt;&lt;/root&gt;
</code></pre>

<p>NOTE: you can always try to print a pretty XML tree using <code>lxml</code> package in python following tutorials here: <a href="http://stackoverflow.com/questions/749796/pretty-printing-xml-in-python">Pretty printing XML in Python</a> since the tree I printed out is rather horrible to read by naked eyes.</p>

python xml