Skip to content

Commit 30eb429

Browse files
committed
gh-159637: Fix renaming an attribute to a prefixed name in minidom
Document.renameNode() set the new prefix of an attribute before its new namespace, so the prefix was validated against the old namespace. Renaming an attribute with no namespace to a prefixed name in a namespace raised NamespaceErr after the attribute had been removed from its element. Set the namespace first, and check the prefix before removing the attribute, so that a rejected rename leaves the element unchanged.
1 parent e5ef47e commit 30eb429

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

‎Lib/test/test_minidom.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,6 +1880,28 @@ def testRenameAttribute(self):
18801880
self.checkRenameNodeSharedConstraints(doc, attr)
18811881
doc.unlink()
18821882

1883+
def testRenameAttributeToPrefixedName(self):
1884+
doc = parseString("<doc a='v' b='w'/>")
1885+
elem = doc.documentElement
1886+
attr = elem.getAttributeNode("a")
1887+
attr = doc.renameNode(attr, "http://xml.python.org/ns", "p:c")
1888+
self.assertEqual(attr.name, "p:c")
1889+
self.assertEqual(attr.prefix, "p")
1890+
self.assertEqual(attr.localName, "c")
1891+
self.assertEqual(attr.namespaceURI, "http://xml.python.org/ns")
1892+
self.assertIsNone(elem.getAttributeNode("a"))
1893+
self.assertIs(elem.getAttributeNodeNS("http://xml.python.org/ns", "c"),
1894+
attr)
1895+
1896+
# A rejected rename leaves the attribute on its element.
1897+
attr = elem.getAttributeNode("b")
1898+
self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, attr,
1899+
"http://xml.python.org/ns", "xml:lang")
1900+
self.assertEqual(attr.name, "b")
1901+
self.assertIsNone(attr.namespaceURI)
1902+
self.assertIs(elem.getAttributeNode("b"), attr)
1903+
doc.unlink()
1904+
18831905
def testRenameElement(self):
18841906
doc = parseString("<doc/>")
18851907
elem = doc.documentElement

‎Lib/xml/dom/minidom.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2129,15 +2129,17 @@ def renameNode(self, n, namespaceURI, name):
21292129
prefix = None
21302130
localName = None
21312131
if n.nodeType == Node.ATTRIBUTE_NODE:
2132+
if prefix is not None:
2133+
_check_prefix(prefix, namespaceURI, True)
21322134
element = n.ownerElement
21332135
if element is not None:
21342136
is_id = n._is_id
21352137
element.removeAttributeNode(n)
21362138
else:
21372139
element = None
2140+
n.namespaceURI = namespaceURI
21382141
n.prefix = prefix
21392142
n._localName = localName
2140-
n.namespaceURI = namespaceURI
21412143
n.nodeName = name
21422144
if n.nodeType == Node.ELEMENT_NODE:
21432145
n.tagName = name

0 commit comments

Comments
 (0)