Skip to content
Open
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
15 changes: 15 additions & 0 deletions Lib/test/test_minidom.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,21 @@ def testWriteXMLDefaultNamespace(self):
'<child/><nons xmlns=""/></root>')
dom.unlink()

def testWriteXMLNoDuplicateXmlns(self):
# gh-158208: setting an explicit xmlns attribute must not
# result in a duplicate xmlns declaration in the output.
dom = Document()
svg = dom.appendChild(dom.createElement("svg"))
svg.setAttribute("xmlns", "https://www.w3.org/2000/svg")
xml = dom.toxml()
self.assertEqual(
xml,
'<?xml version="1.0" ?><svg xmlns="https://www.w3.org/2000/svg"/>'
)
# The result must be well-formed XML.
parseString(xml)
dom.unlink()

def testWriteXMLAttributeNamespacePrefix(self):
dom = Document()
root = dom.appendChild(dom.createElement("root"))
Expand Down
7 changes: 6 additions & 1 deletion Lib/xml/dom/minidom.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ def _fixup_namespaces(element, nsmap):
declarations = []
# (name, value, namespace URI, attribute) of the attributes to write.
entries = []
has_own_xmlns = False
if attrs:
for attr in attrs.values():
name = attr.name
Expand All @@ -435,6 +436,8 @@ def _fixup_namespaces(element, nsmap):
nsmap, inherited,
attr.localName if attr.prefix else None, attr.value)
attr_uri = None
if name == "xmlns":
has_own_xmlns = True
elif attr_uri == XML_NAMESPACE:
# The xml prefix is bound by definition.
attr_uri = None
Expand All @@ -446,8 +449,10 @@ def _fixup_namespaces(element, nsmap):
if nsmap.get(prefix) != uri:
nsmap = _bind_namespace(nsmap, inherited, prefix, uri)
declarations.append(("xmlns:" + prefix if prefix else "xmlns", uri))
elif nsmap.get(None) and ':' not in element.tagName:
elif (nsmap.get(None) and ':' not in element.tagName
and not has_own_xmlns):
# The element is in no namespace, undeclare the default one.
# Don't undeclare if the element itself declared xmlns.
nsmap = _bind_namespace(nsmap, inherited, None, None)
declarations.append(("xmlns", ""))

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix :mod:`xml.dom.minidom` to not write a duplicate ``xmlns`` attribute
when an element has an explicit ``xmlns`` attribute set with
:meth:`~xml.dom.Element.setAttribute`.
Loading