Skip to content

Commit a3697db

Browse files
authored
bpo-34160: explain how to deal with attribute order in ElementTree (GH-14867)
* Fix the formatting in the documentation of the tostring() functions. * bpo-34160: Document that the tostring() and tostringlist() functions also preserve the attribute order now. * bpo-34160: Add an explanation of how users should deal with the attribute order.
1 parent c6cb4cd commit a3697db

File tree

1 file changed

+40
-2
lines changed

1 file changed

+40
-2
lines changed

Doc/library/xml.etree.elementtree.rst

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)