Skip to content

Commit 9d69f54

Browse files
committed
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.
1 parent 9d22a53 commit 9d69f54

2 files changed

Lines changed: 50 additions & 1 deletion

File tree

‎Lib/test/test_minidom.py‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from test import support
77
import unittest
88

9+
import xml.dom.expatbuilder
910
import xml.dom.minidom
1011

1112
from xml.dom.minidom import parse, Attr, Node, Document, Element, parseString
@@ -683,6 +684,54 @@ def testWriteXMLExistingNamespaceDeclarations(self):
683684
self.assertEqual(dom.documentElement.toxml(), str)
684685
dom.unlink()
685686

687+
def testWriteXMLDOM1PrefixDeclaration(self):
688+
# setAttribute() does not set the prefix of the attribute,
689+
# but "xmlns:p" still declares the prefix "p".
690+
dom = Document()
691+
root = dom.appendChild(
692+
dom.createElementNS("http://xml.python.org/ns", "p:root"))
693+
root.setAttribute("xmlns:p", "http://xml.python.org/ns")
694+
domstr = dom.documentElement.toxml()
695+
dom.unlink()
696+
self.assertEqual(domstr,
697+
'<p:root xmlns:p="http://xml.python.org/ns"/>')
698+
dom = parseString(domstr)
699+
self.assertEqual(dom.documentElement.namespaceURI,
700+
"http://xml.python.org/ns")
701+
dom.unlink()
702+
703+
def testWriteXMLDOM1PrefixDeclarationNoNamespace(self):
704+
# A prefix declaration is not a declaration of the default namespace.
705+
dom = Document()
706+
root = dom.appendChild(dom.createElement("root"))
707+
root.setAttribute("xmlns:xsi", "http://xml.python.org/ns")
708+
self.assertEqual(dom.documentElement.toxml(),
709+
'<root xmlns:xsi="http://xml.python.org/ns"/>')
710+
dom.unlink()
711+
712+
def testWriteXMLDOM1PrefixDeclarationDefaultNamespace(self):
713+
# The element still needs a declaration of its own default namespace.
714+
dom = Document()
715+
root = dom.appendChild(
716+
dom.createElementNS("http://xml.python.org/ns", "root"))
717+
root.setAttribute("xmlns:x", "http://xml.python.org/ns")
718+
domstr = dom.documentElement.toxml()
719+
dom.unlink()
720+
self.assertEqual(domstr,
721+
'<root xmlns="http://xml.python.org/ns" '
722+
'xmlns:x="http://xml.python.org/ns"/>')
723+
dom = parseString(domstr)
724+
self.assertEqual(dom.documentElement.namespaceURI,
725+
"http://xml.python.org/ns")
726+
dom.unlink()
727+
728+
def testWriteXMLParsedWithoutNamespaces(self):
729+
src = ('<root xmlns:p="http://xml.python.org/ns">'
730+
'<p:child/><other/></root>')
731+
dom = xml.dom.expatbuilder.parseString(src, namespaces=False)
732+
self.assertEqual(dom.documentElement.toxml(), src)
733+
dom.unlink()
734+
686735
def testWriteXMLNotANamespaceDeclaration(self):
687736
# an attribute whose name only starts with "xmlns" is not one
688737
dom = parseString('<root xmlns="http://xml.python.org/ns">'

‎Lib/xml/dom/minidom.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ def _fixup_namespaces(element, nsmap):
433433
# Declarations already present in the document take precedence.
434434
nsmap = _bind_namespace(
435435
nsmap, inherited,
436-
attr.localName if attr.prefix else None, attr.value)
436+
attr.localName if ":" in name else None, attr.value)
437437
attr_uri = None
438438
elif attr_uri == XML_NAMESPACE:
439439
# The xml prefix is bound by definition.

0 commit comments

Comments
 (0)