diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst index af09ea98c818211..5acfdc03a55536a 100644 --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -132,7 +132,7 @@ module documentation. This section lists the differences between the API and ... # Work with dom. -.. method:: Node.writexml(writer, indent="", addindent="", newl="") +.. method:: Node.writexml(writer, indent="", addindent="", newl="", sort=False) Write XML to the writer object. The writer should have a :meth:`write` method which matches that of the file object interface. The *indent* parameter is the @@ -147,6 +147,11 @@ module documentation. This section lists the differences between the API and The :meth:`writexml` method now preserves the attribute order specified by the user. + .. versionadded:: 3.8 + The *sort* parameter sorts the XML attributes of the tags. For the + :class:`Document` node, an additional keyword argument *sort* can be used + to specify the sort of the attributes. + .. method:: Node.toxml(encoding=None) Return a string or byte string containing the XML represented by diff --git a/Doc/library/xml.dom.rst b/Doc/library/xml.dom.rst index 18519a75a546115..38011fe1ea72a7d 100644 --- a/Doc/library/xml.dom.rst +++ b/Doc/library/xml.dom.rst @@ -576,6 +576,23 @@ inherits properties from :class:`Node`. particular namespace URI and localname. The localname is the part of the namespace after the prefix. +.. method:: Document.writexml(self, writer, indent="", addindent="", newl="", encoding=None, sort=False) + + Write XML to the writer object. The writer should have a :meth:`write` method + which matches that of the file object interface. The *indent* parameter is the + indentation of the current node. The *addindent* parameter is the incremental + indentation to use for subnodes of the current one. The *newl* parameter + specifies the string to use to terminate newlines. + + The keyword argument *encoding* can be used to specify the encoding field of + the XML header. + + .. versionchanged:: 3.8 + The :meth:`writexml` method now preserves the attribute order specified + by the user. + + .. versionadded:: 3.8 + The *sort* parameter sorts the XML attributes of the tags. .. _dom-element-objects: diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py index f3ef958b535373f..41970855455509f 100644 --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -1612,6 +1612,14 @@ def testProcessingInstructionNameError(self): pi = doc.createProcessingInstruction("y", "z") pi.nodeValue = "crash" + def test_minidom_attribute_sorted(self): + xml_str = '' + sorted_xml_str = '' + doc = parseString(xml_str) + output = io.StringIO() + doc.writexml(output, sort=True) + self.assertEqual(output.getvalue(), sorted_xml_str) + def test_minidom_attribute_order(self): xml_str = '' doc = parseString(xml_str) diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py index 43569ddcbeacd9d..c97d548e3715fc4 100644 --- a/Lib/xml/dom/minidom.py +++ b/Lib/xml/dom/minidom.py @@ -847,7 +847,7 @@ def getElementsByTagNameNS(self, namespaceURI, localName): def __repr__(self): return "" % (self.tagName, id(self)) - def writexml(self, writer, indent="", addindent="", newl=""): + def writexml(self, writer, indent="", addindent="", newl="", sort=False): # indent = current indentation # addindent = indentation to add to higher levels # newl = newline string @@ -855,7 +855,11 @@ def writexml(self, writer, indent="", addindent="", newl=""): attrs = self._get_attributes() - for a_name in attrs.keys(): + attribute_names = attrs.keys() + if sort: + attribute_names = sorted(attribute_names) + + for a_name in attribute_names: writer.write(" %s=\"" % a_name) _write_data(writer, attrs[a_name].value) writer.write("\"") @@ -863,11 +867,11 @@ def writexml(self, writer, indent="", addindent="", newl=""): writer.write(">") if (len(self.childNodes) == 1 and self.childNodes[0].nodeType == Node.TEXT_NODE): - self.childNodes[0].writexml(writer, '', '', '') + self.childNodes[0].writexml(writer, '', '', '', sort=sort) else: writer.write(newl) for node in self.childNodes: - node.writexml(writer, indent+addindent, addindent, newl) + node.writexml(writer, indent+addindent, addindent, newl, sort=sort) writer.write(indent) writer.write("%s" % (self.tagName, newl)) else: @@ -984,8 +988,8 @@ def _set_nodeName(self, value): self.target = value nodeName = property(_get_nodeName, _set_nodeName) - def writexml(self, writer, indent="", addindent="", newl=""): - writer.write("%s%s" % (indent,self.target, self.data, newl)) + def writexml(self, writer, indent="", addindent="", newl="", sort=False): + writer.write("%s%s" % (indent,self.target, self.data, newl), sort=sort) class CharacterData(Childless, Node): @@ -1084,7 +1088,7 @@ def splitText(self, offset): self.data = self.data[:offset] return newText - def writexml(self, writer, indent="", addindent="", newl=""): + def writexml(self, writer, indent="", addindent="", newl="", sort=False): _write_data(writer, "%s%s%s" % (indent, self.data, newl)) # DOM Level 3 (WD 9 April 2002) @@ -1179,10 +1183,10 @@ def __init__(self, data): CharacterData.__init__(self) self._data = data - def writexml(self, writer, indent="", addindent="", newl=""): + def writexml(self, writer, indent="", addindent="", newl="", sort=False): if "--" in self.data: raise ValueError("'--' is not allowed in a comment node") - writer.write("%s%s" % (indent, self.data, newl)) + writer.write("%s%s" % (indent, self.data, newl), sort=sort) class CDATASection(Text): @@ -1191,7 +1195,7 @@ class CDATASection(Text): nodeType = Node.CDATA_SECTION_NODE nodeName = "#cdata-section" - def writexml(self, writer, indent="", addindent="", newl=""): + def writexml(self, writer, indent="", addindent="", newl="", sort=False): if self.data.find("]]>") >= 0: raise ValueError("']]>' not allowed in a CDATA section") writer.write("" % self.data) @@ -1324,7 +1328,7 @@ def cloneNode(self, deep): else: return None - def writexml(self, writer, indent="", addindent="", newl=""): + def writexml(self, writer, indent="", addindent="", newl="", sort=False): writer.write("'+newl) else: writer.write('%s' % ( encoding, newl)) for node in self.childNodes: - node.writexml(writer, indent, addindent, newl) + node.writexml(writer, indent, addindent, newl, sort=sort) # DOM Level 3 (WD 9 April 2002) diff --git a/Misc/NEWS.d/next/Library/2019-03-15-19-08-36.bpo-34160.aDomJL.rst b/Misc/NEWS.d/next/Library/2019-03-15-19-08-36.bpo-34160.aDomJL.rst new file mode 100644 index 000000000000000..1b12543b1d1398d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-03-15-19-08-36.bpo-34160.aDomJL.rst @@ -0,0 +1,5 @@ +Add the *sort* attribute to the :meth:`xml.dom.minidom.Node.writexml` method +allowing to sort the attributes by name (``True``) or by the attribute order +specified by the user (by default ``False``). Document +:meth:`xml.dom.minidom.Document.writexml` method. Contributed by Stéphane +Wirtel.