# reorder XML attributes import sys from xml.sax import saxutils, handler, make_parser from StringIO import StringIO ParserSchemaOrderTable = [ u"xmlns:xsi", u"xsi:noNamespaceSchemaLocation", u"name", u"type", u"base", u"generate", u"value", u"size", u"sizeVar", u"indexBits", u"init", u"min", u"max", u"step", u"key", u"enumKeyType", u"enumKeySize", u"numBits", u"values", u"policy", u"toString", u"fromString", u"version", u"simple", u"constructable", u"constructible", u"template", u"usesdi", u"highPrecision", u"addGroupWidget", u"noInit", u"onUnknownType", u"userHandlesNull", u"onWidgetChanged" u"onPreLoad", u"onPostLoad", u"onPreSave", u"onPostSave", u"onPreAddWidgets", u"onPostAddWidget", u"onPreSet", u"onPostSet", u"preserveNames", u"ui_key", u"cond", u"hideFrom", u"hideWidgets", u"autoregister", u"platform", u"description", ] ParserSchemaOrderMap = dict([(str, idx) for (idx, str) in enumerate(ParserSchemaOrderTable)]) def ParserSchemaAttributeOrdering(attr1, attr2): name1 = attr1[0] name2 = attr2[0] order1 = ParserSchemaOrderMap.get(name1, 10000) order2 = ParserSchemaOrderMap.get(name2, 10000) if (order1 == order2): return cmp(name1, name2) return cmp(order1, order2) # based on roundtrip.py from http://mail.python.org/pipermail/python-dev/2000-October/009946.html class ContentGenerator(handler.ContentHandler): def __init__(self, out = sys.stdout): handler.ContentHandler.__init__(self) self._out = out self.justStartedElement = False self.inFakeComment = False # ContentHandler methods def startDocument(self): self._out.write('\n') def startElement(self, name, attrs): self._out.write('<' + name) sortedItems = sorted(attrs.items(), cmp=ParserSchemaAttributeOrdering) for (name, value) in sortedItems: self._out.write(' %s="%s"' % (name, saxutils.escape(value))) self.justStartedElement = True if name == "xml:fakecomment": self.inFakeComment = True self.justStartedElement = False self._out.write(">") if self.justStartedElement: self.justStartedElement = False self._out.write("/>") else: self._out.write('' % name) def characters(self, content): if self.justStartedElement: self.justStartedElement = False self._out.write(">") if self.inFakeComment: self._out.write(content) # do not escape, we're in a CDATA block else: self._out.write(saxutils.escape(content)) def ignorableWhitespace(self, content): if self.justStartedElement: self.justStartedElement = False self._out.write(">") self._out.write(content) def processingInstruction(self, target, data): if self.justStartedElement: self.justStartedElement = False self._out.write(">") self._out.write('' % (target, data)) ################################################################# fileData = file(sys.argv[1]).read() # make multiple passes over the file # convert all XML comments into XML tags (otherwise the sax parser will strip them) fileData = fileData.replace(r"", r"]]>") # reorder all attributes dataStream = StringIO(fileData) outStream = StringIO() parser = make_parser() parser.setContentHandler(ContentGenerator(outStream)) parser.parse(dataStream) outStream.seek(0) fileData = outStream.read() # un-convert the comments fileData = fileData.replace(r"", r"-->") sys.stderr.write(fileData) # done, write results outFile = file(sys.argv[2], "w") outFile.write(fileData) outFile.close()