@@ -659,7 +659,7 @@ Functions
659659
660660
661661.. function :: tostring(element, encoding="us-ascii", method="xml", *, \
662- xml_declaration=None, default_namespace=None,
662+ xml_declaration=None, default_namespace=None, \
663663 short_empty_elements=True)
664664
665665 Generates a string representation of an XML element, including all
@@ -677,9 +677,13 @@ Functions
677677 .. versionadded :: 3.8
678678 The *xml_declaration * and *default_namespace * parameters.
679679
680+ .. versionchanged :: 3.8
681+ The :func: `tostring ` function now preserves the attribute order
682+ specified by the user.
683+
680684
681685.. function :: tostringlist(element, encoding="us-ascii", method="xml", *, \
682- xml_declaration=None, default_namespace=None,
686+ xml_declaration=None, default_namespace=None, \
683687 short_empty_elements=True)
684688
685689 Generates a string representation of an XML element, including all
@@ -700,6 +704,10 @@ Functions
700704 .. versionadded :: 3.8
701705 The *xml_declaration * and *default_namespace * parameters.
702706
707+ .. versionchanged :: 3.8
708+ The :func: `tostringlist ` function now preserves the attribute order
709+ specified by the user.
710+
703711
704712.. function :: XML(text, parser=None)
705713
@@ -930,6 +938,36 @@ Element Objects
930938 if element is None:
931939 print("element not found")
932940
941+ Prior to Python 3.8, the serialisation order of the XML attributes of
942+ elements was artificially made predictable by sorting the attributes by
943+ their name. Based on the now guaranteed ordering of dicts, this arbitrary
944+ reordering was removed in Python 3.8 to preserve the order in which
945+ attributes were originally parsed or created by user code.
946+
947+ In general, user code should try not to depend on a specific ordering of
948+ attributes, given that the `XML Information Set
949+ <https://www.w3.org/TR/xml-infoset/> `_ explicitly excludes the attribute
950+ order from conveying information. Code should be prepared to deal with
951+ any ordering on input. In cases where deterministic XML output is required,
952+ e.g. for cryptographic signing or test data sets, canonical serialisation
953+ is available with the :func: `canonicalize ` function.
954+
955+ In cases where canonical output is not applicable but a specific attribute
956+ order is still desirable on output, code should aim for creating the
957+ attributes directly in the desired order, to avoid perceptual mismatches
958+ for readers of the code. In cases where this is difficult to achieve, a
959+ recipe like the following can be applied prior to serialisation to enforce
960+ an order independently from the Element creation::
961+
962+ def reorder_attributes(root):
963+ for el in root.iter():
964+ attrib = el.attrib
965+ if len(attrib) > 1:
966+ # adjust attribute order, e.g. by sorting
967+ attribs = sorted(attrib.items())
968+ attrib.clear()
969+ attrib.update(attribs)
970+
933971
934972.. _elementtree-elementtree-objects :
935973
0 commit comments