Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sort attributes when building xml.dom.minidom.Element objects #415

Merged
merged 1 commit into from
Jan 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions pyxform/tests_v1/pyxform_test_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ def check_content(content):
"Invalid parameter: 'body__contains'." "Use 'xml__contains' instead"
)

# preserve attribute ordering across all Python versions before writing to string
# guarantee that strings contain alphanumerically sorted attributes across Python versions
reorder_attributes(root)

for code in ["xml", "instance", "model", "itext"]:
Expand Down Expand Up @@ -337,17 +337,23 @@ def assertNotContains(self, content, text, msg_prefix=""):

def reorder_attributes(root):
"""
Forces alphabetical ordering of all XML attributes to match pre Python 3.8 behavior.
In general, we should not rely on ordering, but changing all the tests is not
realistic at this moment.
Forces alphabetical ordering of all XML attributes to match pre Python 3.8 behavior.
In general, we should not rely on ordering, but changing all the tests is not
realistic at this moment.

See bottom of https://docs.python.org/3/library/xml.etree.elementtree.html#element-objects and
https://github.com/python/cpython/commit/a3697db0102b9b6747fe36009e42f9b08f0c1ea8 for more information.
"""
See bottom of https://docs.python.org/3/library/xml.etree.elementtree.html#element-objects and
https://github.com/python/cpython/commit/a3697db0102b9b6747fe36009e42f9b08f0c1ea8 for more information.

NOTE: there's a similar ordering change made in utils.node. This one is also needed because in
assertPyxformXform, the survey is converted to XML and then read back in using ETree.fromstring. This
means that attribute ordering here is based on the attribute representation of xml.etree.ElementTree objects.
In utils.node, it is based on xml.dom.minidom.Element objects. See https://github.com/XLSForm/pyxform/issues/414.
"""
for el in root.iter():
attrib = el.attrib
if len(attrib) > 1:
# adjust attribute order, e.g. by sorting
# Sort attributes. Attributes are represented as {namespace}name so attributes with explicit
# namespaces will always sort after those without explicit namespaces.
attribs = sorted(attrib.items())
attrib.clear()
attrib.update(attribs)
8 changes: 5 additions & 3 deletions pyxform/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,11 @@ def node(*args, **kwargs):
unicode_args = [u for u in args if type(u) == unicode]
assert len(unicode_args) <= 1
parsed_string = False
# kwargs is an xml attribute dictionary,
# here we convert it to a xml.dom.minidom.Element
for k, v in iter(kwargs.items()):

# Convert the kwargs xml attribute dictionary to a xml.dom.minidom.Element. Sort the
# attributes to guarantee a consistent order across Python versions.
# See pyxform_test_case.reorder_attributes for details.
for k, v in iter(sorted(kwargs.items())):
if k in blocked_attributes:
continue
if k == "toParseString":
Expand Down