17

I've a xml file, and I'm trying to add additional element to it. the xml has the next structure :

<root>
  <OldNode/>
</root>

What I'm looking for is :

<root>
  <OldNode/>
  <NewNode/>
</root>

but actually I'm getting next xml :

<root>
  <OldNode/>
</root>

<root>
  <OldNode/>
  <NewNode/>
</root>

My code looks like that :

file = open("/tmp/" + executionID +".xml", 'a')
xmlRoot = xml.parse("/tmp/" + executionID +".xml").getroot()

child = xml.Element("NewNode")
xmlRoot.append(child)

xml.ElementTree(root).write(file)

file.close()

Thanks.

Igal
  • 4,603
  • 14
  • 41
  • 66

1 Answers1

16

You opened the file for appending, which adds data to the end. Open the file for writing instead, using the w mode. Better still, just use the .write() method on the ElementTree object:

tree = xml.parse("/tmp/" + executionID +".xml")

xmlRoot = tree.getroot()
child = xml.Element("NewNode")
xmlRoot.append(child)

tree.write("/tmp/" + executionID +".xml")

Using the .write() method has the added advantage that you can set the encoding, force the XML prolog to be written if you need it, etc.

If you must use an open file to prettify the XML, use the 'w' mode, 'a' opens a file for appending, leading to the behaviour you observed:

with open("/tmp/" + executionID +".xml", 'w') as output:
     output.write(prettify(tree))

where prettify is something along the lines of:

from xml.etree import ElementTree
from xml.dom import minidom

def prettify(elem):
    """Return a pretty-printed XML string for the Element.
    """
    rough_string = ElementTree.tostring(elem, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    return reparsed.toprettyxml(indent="  ")

e.g. the minidom prettifying trick.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343