python - how to write empty tree node as empty string to xml file
<p>I want to remove elements of a certain tag value and then write out the <code>.xml</code> file WITHOUT any tags for those deleted elements; is my only option to create a new tree?</p>

<p>There are two options to remove/delete an element:</p>

<blockquote>
  <p><a href="https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.clear" rel="nofollow">clear()</a>
  Resets an element. This function removes all subelements, clears all
  attributes, and sets the text and tail attributes to None.</p>
</blockquote>

<p>At first I used this and it works for the purpose of removing the <strong>data</strong> from the element but I'm still left with an empty element:</p>

<pre><code># Remove all elements from the tree that are NOT "job" or "make" or "build" elements
log = open("debug.log", "w")
for el in root.iter(*):

    if el.tag != "job" and el.tag != "make" and el.tag != "build":
        print("removed = ", el.tag, el.attrib, file=log)
        el.clear()
    else:
        print("NOT", el.tag, el.attrib, file=log)

log.close()
tree.write("make_and_job_tree.xml", short_empty_elements=False)
</code></pre>

<p>The problem is that <code>xml.etree.ElementTree.ElementTree.write()</code> <a href="https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.ElementTree.write" rel="nofollow">still writes out empty tags no matter what:</a></p>

<blockquote>
  <p>...The keyword-only short_empty_elements parameter controls the
  formatting of elements that contain no content. If True (the default),
  they are emitted as a <strong>single self-closed tag</strong>, otherwise they are
  emitted as a <strong>pair of start/end tags</strong>.</p>
</blockquote>

<p>Why isn't there an option to just not print out those empty tags! Whatever.</p>

<p>So then I thought I might try</p>

<blockquote>
  <p><a href="https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.remove" rel="nofollow">remove(subelement)</a>
  Removes subelement from the element. Unlike the find* methods this
  method compares elements based on the instance identity, not on tag
  value or contents.</p>
</blockquote>

<p>But this only operates on the child elements.</p>

<p>So I'd have to <a href="https://docs.python.org/3/library/xml.etree.elementtree.html#parsing-xml" rel="nofollow">do something like</a>:</p>

<pre><code>for el in root.iter(*):
    for subel in el:
        if subel.tag != "make" and subel.tag != "job" and subel.tag != "build":
            el.remove(subel)
</code></pre>

<p>But there's a big problem here: I'm invalidating the iterator by removing elements, right?</p>

<p>Is it enough to simply check if the element is empty by adding <code>if subel</code>?:</p>

<pre><code>if subel and subel.tag != "make" and subel.tag != "job" and subel.tag != "build"
</code></pre>

<p>Or do I have to get a new iterator to the tree elements every time I invalidate it?</p>

<p>Remember: I just wanted to write out the xml file with no tags for the empty elements.</p>

<p>Here's an example.</p>

<pre><code>&lt;?xml version="1.0"?&gt;
&lt;data&gt;
    &lt;country name="Liechtenstein"&gt;
        &lt;rank&gt;1&lt;/rank&gt;
        &lt;year&gt;2008&lt;/year&gt;
        &lt;gdppc&gt;141100&lt;/gdppc&gt;
        &lt;neighbor name="Austria" direction="E"/&gt;
        &lt;neighbor name="Switzerland" direction="W"/&gt;
    &lt;/country&gt;
    &lt;country name="Singapore"&gt;
        &lt;rank&gt;4&lt;/rank&gt;
        &lt;year&gt;2011&lt;/year&gt;
        &lt;gdppc&gt;59900&lt;/gdppc&gt;
        &lt;neighbor name="Malaysia" direction="N"/&gt;
    &lt;/country&gt;
    &lt;country name="Panama"&gt;
        &lt;rank&gt;68&lt;/rank&gt;
        &lt;year&gt;2011&lt;/year&gt;
        &lt;gdppc&gt;13600&lt;/gdppc&gt;
        &lt;neighbor name="Costa Rica" direction="W"/&gt;
        &lt;neighbor name="Colombia" direction="E"/&gt;
    &lt;/country&gt;
&lt;/data&gt;
</code></pre>

<p>Let's say I want to remove any mention of <code>neighbor</code>.
Ideally, I'd want this output after the removal:</p>

<pre><code>&lt;?xml version="1.0"?&gt;
&lt;data&gt;
    &lt;country name="Liechtenstein"&gt;
        &lt;rank&gt;1&lt;/rank&gt;
        &lt;year&gt;2008&lt;/year&gt;
        &lt;gdppc&gt;141100&lt;/gdppc&gt;
    &lt;/country&gt;
    &lt;country name="Singapore"&gt;
        &lt;rank&gt;4&lt;/rank&gt;
        &lt;year&gt;2011&lt;/year&gt;
        &lt;gdppc&gt;59900&lt;/gdppc&gt;
    &lt;/country&gt;
    &lt;country name="Panama"&gt;
        &lt;rank&gt;68&lt;/rank&gt;
        &lt;year&gt;2011&lt;/year&gt;
        &lt;gdppc&gt;13600&lt;/gdppc&gt;
    &lt;/country&gt;
&lt;/data&gt;
</code></pre>

<p>Problem, is when I run the code using clear() (see first code block up above) and write it to a file, I get this:</p>

<pre><code>&lt;data&gt;
    &lt;country name="Liechtenstein"&gt;
        &lt;rank&gt;1&lt;/rank&gt;
        &lt;year&gt;2008&lt;/year&gt;
        &lt;gdppc&gt;141100&lt;/gdppc&gt;
        &lt;neighbor&gt;&lt;/neighbor&gt;&lt;neighbor&gt;&lt;/neighbor&gt;&lt;/country&gt;
    &lt;country name="Singapore"&gt;
        &lt;rank&gt;4&lt;/rank&gt;
        &lt;year&gt;2011&lt;/year&gt;
        &lt;gdppc&gt;59900&lt;/gdppc&gt;
        &lt;neighbor&gt;&lt;/neighbor&gt;&lt;/country&gt;
    &lt;country name="Panama"&gt;
        &lt;rank&gt;68&lt;/rank&gt;
        &lt;year&gt;2011&lt;/year&gt;
        &lt;gdppc&gt;13600&lt;/gdppc&gt;
        &lt;neighbor&gt;&lt;/neighbor&gt;&lt;neighbor&gt;&lt;/neighbor&gt;&lt;/country&gt;
&lt;/data&gt;
</code></pre>

<p>Notice <code>neighbor</code> still appears.</p>

<p>I know I could easily run a regex over the output but there's gotta be a way (or another Python api) that does this on the fly instead of requiring me to touch my <code>.xml</code> file again.</p>