Can ElementTree be told to preserve the order of attributes?
Question: I've written a fairly simple filter in python using ElementTree to munge the
contexts of some xml files. And it works, more or less.

But it reorders the attributes of various tags, and I'd like it to not do
that.

Does anyone know a switch I can throw to make it keep them in specified order?

## Context for this

I'm working with and on a particle physics tool that has a complex, but oddly
limited configuration system based on xml files. Among the many things setup
that way are the paths to various static data files. These paths are hardcoded
into the existing xml and there are no facilities for setting or varying them
based on environment variables, and in our local installation they are
necessarily in a different place.

This isn't a disaster because the combined source- and build-control tool
we're using allows us to shadow certain files with local copies. But even
thought the data fields are static the xml isn't, so I've written a script for
fixing the paths, but with the attribute rearrangement diffs between the local
and master versions are harder to read than necessary.

* * *

This is my first time taking ElementTree for a spin (and only my fifth or
sixth python project) so maybe I'm just doing it wrong.

Abstracted for simplicity the code looks like this:

    
    
    tree = elementtree.ElementTree.parse(inputfile)
    i = tree.getiterator()
    for e in i:
        e.text = filter(e.text)
    tree.write(outputfile)
    

Reasonable or dumb?

* * *

Related links:

  * [How can I get the order of an element attribute list using Python xml.sax?](http://stackoverflow.com/questions/998514/how-can-i-get-the-order-of-an-element-attribute-list-using-python-xml-sax)
  * [Preserve order of attributes when modifying with minidom](http://stackoverflow.com/questions/662624/preserve-order-of-attributes-when-modifying-with-minidom)


Answer: Nope. ElementTree uses a dictionary to store attribute values, so it's
inherently unordered.

Even DOM doesn't guarantee you attribute ordering, and DOM exposes a lot more
detail of the XML infoset than ElementTree does. (There are some DOMs that do
offer it as a feature, but it's not standard.)

Can it be fixed? Maybe. Here's a stab at it that replaces the dictionary when
parsing with an ordered one
([`collections.OrderedDict()`](https://docs.python.org/2/library/collections.html#ordereddict-
objects)).

    
    
    from xml.etree import ElementTree
    from collections import OrderedDict
    import StringIO
    
    class OrderedXMLTreeBuilder(ElementTree.XMLTreeBuilder):
        def _start_list(self, tag, attrib_in):
            fixname = self._fixname
            tag = fixname(tag)
            attrib = OrderedDict()
            if attrib_in:
                for i in range(0, len(attrib_in), 2):
                    attrib[fixname(attrib_in[i])] = self._fixtext(attrib_in[i+1])
            return self._target.start(tag, attrib)
    
    >>> xmlf = StringIO.StringIO('<a b="c" d="e" f="g" j="k" h="i"/>')
    
    >>> tree = ElementTree.ElementTree()
    >>> root = tree.parse(xmlf, OrderedXMLTreeBuilder())
    >>> root.attrib
    OrderedDict([('b', 'c'), ('d', 'e'), ('f', 'g'), ('j', 'k'), ('h', 'i')])
    

Looks potentially promising.

    
    
    >>> s = StringIO.StringIO()
    >>> tree.write(s)
    >>> s.getvalue()
    '<a b="c" d="e" f="g" h="i" j="k" />'
    

Bah, the serialiser outputs them in canonical order.

This looks like the line to blame, in `ElementTree._write`:

    
    
                items.sort() # lexical order
    

Subclassing or monkey-patching that is going to be annoying as it's right in
the middle of a big method.

Unless you did something nasty like subclass `OrderedDict` and hack `items` to
return a special subclass of `list` that ignores calls to `sort()`. Nah,
probably that's even worse and I should go to bed before I come up with
anything more horrible than that.

