1

I'm totally new to XML and I'm stuck on how to append children to a root node of an already exisitng XML file using Python and XML DOM. Right now I have this script to create an output file:

from xml.dom.minidom import Document

doc = Document()

root_node = doc.createElement("notes")                          # Root
doc.appendChild(root_node)

object_node = doc.createElement("data")                         # Child
root_node.appendChild(object_node)

object_node.setAttribute("a_version", "something_v001.0001.ma") # Set attributes
object_node.setAttribute("b_user", "Me")
object_node.setAttribute("c_comment", "comment about file")

xml_file = open("C:/Temp/file_notes.xml", "w")                  # Append
xml_file.write(doc.toprettyxml())
xml_file.close()

This gives me an output file that looks like this:

<?xml version="1.0" ?>
<notes>
    <data a_version="Me" b_user="something_v001.0001.ma" c_comment="comment about file"/>
</notes>

I'd like to append future data to this file so it will look something like this after 2 additional versions:

<?xml version="1.0" ?>
<notes>
    <data a_version="something_v001.0001.ma" b_user="Me" c_comment="comment about file"/>
    <data a_version="something_v001.0002.ma" b_user="You" c_comment="minor save"/>
    <data a_version="something_v002.0003.ma" b_user="Them" c_comment="major save"/>
</notes>

But every attempt I make at appending data comes out like this:

<?xml version="1.0" ?>
<notes>
    <data a_version="Me" b_user="something_v001.0001.ma" c_comment="comment about file"/>
</notes>
<?xml version="1.0" ?>
<notes>
    <data a_version="Me" b_user="something_v001.0001.ma" c_comment="comment about file"/>
</notes>
<?xml version="1.0" ?>
<notes>
    <data a_version="Me" b_user="something_v001.0001.ma" c_comment="comment about file"/>
</notes>

If anyone has any alternative methods to accomplish this task by using ElementTree that would be appreciated as well. There seem to be a lot more resources, but I'm not sure how to implement the solution with Maya. Thanks!

Mike Bourbeau
  • 481
  • 11
  • 29

1 Answers1

2

You haven't shown us any code demonstrating "every attempt I make at appending data". But never mind, here is how you can use ElementTree to append new elements to an existing XML file.

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

# Assume that we have an existing XML document with one "data" child
doc = ET.parse("file_notes.xml")
root = doc.getroot()

# Create 2 new "data" elements
data1 = ET.Element("data", {"a_version": "something_v001.0002.ma",
                            "b_user": "You",
                            "c_comment": "minor save"})
data2 = ET.Element("data", {"a_version": "something_v001.0003.ma",
                            "b_user": "Them",
                            "c_comment": "major save"})

# Append the new "data" elements to the root element of the XML document
root.append(data1)
root.append(data2)

# Now we have a new well-formed XML document. It is not very nicely formatted...
out = ET.tostring(root)

# ...so we'll use minidom to make the output a little prettier
dom = minidom.parseString(out)
print dom.toprettyxml()

Output:

<?xml version="1.0" ?>
<notes>


    <data a_version="Me" b_user="something_v001.0001.ma" c_comment="comment about file"/>


    <data a_version="something_v001.0002.ma" b_user="You" c_comment="minor save"/>
    <data a_version="something_v001.0003.ma" b_user="Them" c_comment="major save"/>
</notes>

ElementTree does not have a built-in pretty-printer, so we use minidom for that. The output contains some superfluous whitespace, but it is better than what ElementTree can provide.

mzjn
  • 48,958
  • 13
  • 128
  • 248
  • Thank you for taking the time to answer so thoroughly, this is a huge help. Would it be possible to get rid of the superfluous white space using another method, or is this expected with Element Tree? – Mike Bourbeau Jul 08 '15 at 16:12
  • *or is this expected with minidom? – Mike Bourbeau Jul 08 '15 at 18:08
  • 1
    The output from minidom shown in the answer is not perfect, but I wouldn't worry too much about some extra whitespace. There have been many questions about pretty-printing XML in Python. Here is one with several answers: http://stackoverflow.com/questions/749796/pretty-printing-xml-in-python. – mzjn Jul 08 '15 at 18:22
  • Agreed, as long as the computer can read it I'm find (which it can :D). I'd just like to mention that that each time I append data it's adding more blank lines exponentially. So a file that that has 15 lines of appended data is around 300 lines. Is this expected/a problem? – Mike Bourbeau Jul 08 '15 at 18:46
  • 1
    I don't think it's a problem. You could simply skip pretty-printing altogether; my answer works without it. It is just a convenience to make the resulting XML structure easier to read for a human. – mzjn Jul 08 '15 at 19:01
  • Assuming of course that you are going to process the XML file in some way, and not just look at it. – mzjn Jul 08 '15 at 19:27
  • 1
    Since Python 3.9, ElementTree has a pretty-printer: https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.indent. – mzjn Feb 16 '21 at 05:55