1

I am having a problem with my XML creator, I am generating a whole bunch of data based on objects coming in from Maya and it would be best if I could have my attribute keys generated in the file in the order they are written in rather than (very annoyingly) having them alphabetically ordered.

I populate my elements like so:

bodies = ET.SubElement(root, "bodies") 
myRp = [ET.Element("object", name=str("rootPoint"))]
myBodies = [ET.Element("object", name=str(cObj), type=checkCollisionType(cObj), padding="-2.5") for cObj in cObjects]
bodies.extend(myRp)
bodies.extend(myBodies)

And I write them like so:

unformattedFile = ET.ElementTree(root)
unformattedFile.write(filePath)
prettyPrintXml(filePath)

My result should be something like this:

<body name="" enabled="" template="">
    <object name="" />
    <object name="" collision_type="" padding=""/>
</body>

But after it is written by element tree I get this:

<bodies>
  <body enabled="" name="" template="">
    <object name=""/>
    <object name="" padding="" type=""/>
</bodies>

For readability and generality I would really like to preserve my original order. I found someones re-work of the ElementTree module but it messed up a lot of things

I have scoured the net and havent been able to find a viable solution yet.

Any help would be greatly appreciated.

Cheers

Ben Hearn
  • 11
  • 2
  • possible duplicate of [Can ElementTree be told to preserve the order of attributes?](http://stackoverflow.com/questions/2741480/can-elementtree-be-told-to-preserve-the-order-of-attributes) – Cory Kramer Nov 05 '14 at 17:36
  • tl;dr No ET uses a dictionary to store those and is therefore unordered. – Cory Kramer Nov 05 '14 at 17:37
  • Balls. Is there any other module to use that would preserve the order of my XML file. I have looked into minidom but even the documentation for that says you should use ElementTree – Ben Hearn Nov 05 '14 at 18:19

2 Answers2

0

Just in case someone has a similar issue and is looking for an answer I made myself a small hack around for this issue.

Although it does not matter order of attributes in XML files for our system at work it is preferable. In the end what I did was tag each attribute with a letter. A, B etc. Since the dictionary is ordered in alphabetical order this worked for me.

For example:

myShadowMeshes = ET.Element("object", Aname=str(sObj), Benabled="true", Cshadow_caster='true')

What I then did is create a function that simply replaces all occurrences of these names with the correct name:

def findAndDeleteCaps(filePath):

    # toReplace specifies which items to replace and with what
    # e.g. Aname will be replaced with name, Btype is replaced with type
    toReplace = {"Aname":"name", "Benabled":"enabled", "Btype":"type", "Cshadow_caster":"shadow_caster", "Ctemplate":"template", "Cpadding":"padding", "Cmaterial":"material"}

    # Read in file as a string and open it to be written to
    textToReplace = open(filePath).read()
    writeFile = open(filePath,"w")

    # run through the dictionary using the original key and the new text to use
    for original, new in toReplace.iteritems():
        textToReplace = textToReplace.replace(original, new) # Replace the specified text
    writeFile.write(textToReplace)
    writeFile.close()

That is my workaround I hope someone finds it useful :)

Cheers,

Ben

Ben Hearn
  • 11
  • 2
0

Batted around with this issue for a while. Found that lxml.etree preserved order, and is overall friendlier for xml schema than Elementree. Our project was replacing urls with an xml sheet with new urls from a csv. There were probably easier ways to go about it, but it was a fun little adventure in Pandas.

from lxml import etree as et

ez pz, and the rest of our code using Elementree we left the same.

  • Since Python 3.8, ElementTree preserves the original attribute order: https://stackoverflow.com/a/60176826/407651 – mzjn Aug 27 '20 at 09:31