From 9d69f54464511bceaf4ed068b23f0196caeaebb6 Mon Sep 17 00:00:00 2001 From: sricursion Date: Thu, 8 Oct 2026 01:29:28 +0530 Subject: [PATCH] gh-158984: Fix xmlns:prefix attributes set with setAttribute() in minidom Take the prefix of an existing namespace declaration from the attribute name instead of Attr.prefix, which is None for attributes created with the DOM Level 1 API. --- Lib/test/test_minidom.py | 49 ++++++++++++++++++++++++++++++++++++++++ Lib/xml/dom/minidom.py | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py index 446bbe096bd19d..ee31fd24bdaec4 100644 --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -6,6 +6,7 @@ from test import support import unittest +import xml.dom.expatbuilder import xml.dom.minidom from xml.dom.minidom import parse, Attr, Node, Document, Element, parseString @@ -683,6 +684,54 @@ def testWriteXMLExistingNamespaceDeclarations(self): self.assertEqual(dom.documentElement.toxml(), str) dom.unlink() + def testWriteXMLDOM1PrefixDeclaration(self): + # setAttribute() does not set the prefix of the attribute, + # but "xmlns:p" still declares the prefix "p". + dom = Document() + root = dom.appendChild( + dom.createElementNS("http://xml.python.org/ns", "p:root")) + root.setAttribute("xmlns:p", "http://xml.python.org/ns") + domstr = dom.documentElement.toxml() + dom.unlink() + self.assertEqual(domstr, + '') + dom = parseString(domstr) + self.assertEqual(dom.documentElement.namespaceURI, + "http://xml.python.org/ns") + dom.unlink() + + def testWriteXMLDOM1PrefixDeclarationNoNamespace(self): + # A prefix declaration is not a declaration of the default namespace. + dom = Document() + root = dom.appendChild(dom.createElement("root")) + root.setAttribute("xmlns:xsi", "http://xml.python.org/ns") + self.assertEqual(dom.documentElement.toxml(), + '') + dom.unlink() + + def testWriteXMLDOM1PrefixDeclarationDefaultNamespace(self): + # The element still needs a declaration of its own default namespace. + dom = Document() + root = dom.appendChild( + dom.createElementNS("http://xml.python.org/ns", "root")) + root.setAttribute("xmlns:x", "http://xml.python.org/ns") + domstr = dom.documentElement.toxml() + dom.unlink() + self.assertEqual(domstr, + '') + dom = parseString(domstr) + self.assertEqual(dom.documentElement.namespaceURI, + "http://xml.python.org/ns") + dom.unlink() + + def testWriteXMLParsedWithoutNamespaces(self): + src = ('' + '') + dom = xml.dom.expatbuilder.parseString(src, namespaces=False) + self.assertEqual(dom.documentElement.toxml(), src) + dom.unlink() + def testWriteXMLNotANamespaceDeclaration(self): # an attribute whose name only starts with "xmlns" is not one dom = parseString('' diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py index 7cb652a323dcc2..253934eecfaaa5 100644 --- a/Lib/xml/dom/minidom.py +++ b/Lib/xml/dom/minidom.py @@ -433,7 +433,7 @@ def _fixup_namespaces(element, nsmap): # Declarations already present in the document take precedence. nsmap = _bind_namespace( nsmap, inherited, - attr.localName if attr.prefix else None, attr.value) + attr.localName if ":" in name else None, attr.value) attr_uri = None elif attr_uri == XML_NAMESPACE: # The xml prefix is bound by definition.