diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py
index 446bbe096bd19dc..c542eb10b2784d9 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
@@ -1277,6 +1278,52 @@ def testCloneElementDeep(self):
self.assertTrue(clone.toxml(), '')
dom.unlink()
+ def create_dom1_element(self):
+ # DOM Level 1 nodes have no namespace, but their names can contain
+ # a colon.
+ doc = Document()
+ root = doc.appendChild(doc.createElement("root"))
+ root.setAttribute("xmlns", "http://xml.python.org/default")
+ root.setAttribute("xmlns:xsi", "http://xml.python.org/xsi")
+ root.setAttribute("xsi:type", "t")
+ root.setAttributeNS("http://xml.python.org/ns", "p:a", "v")
+ root.appendChild(doc.createElement("svg:rect"))
+ root.appendChild(
+ doc.createElementNS("http://xml.python.org/ns", "p:b"))
+ return doc, root
+
+ def check_clone_names(self, clone, node):
+ for name in ("nodeName", "prefix", "localName", "namespaceURI"):
+ self.assertEqual(getattr(clone, name), getattr(node, name), name)
+
+ def check_clone_element(self, clone, elem, doc):
+ self.assertIs(clone.ownerDocument, doc)
+ self.assertIsNone(clone.parentNode)
+ self.check_clone_names(clone, elem)
+ self.assertEqual(len(clone.attributes), len(elem.attributes))
+ for attr in elem.attributes.values():
+ with self.subTest(attr=attr.name):
+ a = clone.getAttributeNode(attr.name)
+ self.check_clone_names(a, attr)
+ self.assertEqual(a.value, attr.value)
+ self.assertIs(a.ownerElement, clone)
+ self.assertEqual(len(clone.childNodes), len(elem.childNodes))
+ for c, child in zip(clone.childNodes, elem.childNodes):
+ self.check_clone_names(c, child)
+
+ def testCloneElementDOM1Names(self):
+ doc, root = self.create_dom1_element()
+ self.check_clone_element(root.cloneNode(True), root, doc)
+ doc.unlink()
+
+ def testCloneElementNoNamespaces(self):
+ doc = xml.dom.expatbuilder.parseString(
+ "",
+ namespaces=False)
+ root = doc.documentElement
+ self.check_clone_element(root.cloneNode(True), root, doc)
+ doc.unlink()
+
def testCloneDocumentShallow(self):
doc = parseString("\n"
""
@@ -1395,6 +1442,13 @@ def testImportDocumentTypeDeep(self):
self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
src.doctype, 1)
+ def testImportElementDOM1Names(self):
+ doc1, root = self.create_dom1_element()
+ doc2 = Document()
+ self.check_clone_element(doc2.importNode(root, True), root, doc2)
+ doc1.unlink()
+ doc2.unlink()
+
# Testing attribute clones uses a helper, and should always be deep,
# even if the argument to cloneNode is false.
def check_clone_attribute(self, deep, testName):
@@ -1417,6 +1471,24 @@ def testCloneAttributeShallow(self):
def testCloneAttributeDeep(self):
self.check_clone_attribute(1, "testCloneAttributeDeep")
+ def testCloneAttributeDOM1Names(self):
+ doc1 = Document()
+ attr = doc1.createAttribute("a:b")
+ attr.value = "v"
+ doc2 = Document()
+ for method, clone, owner in [
+ ("cloneNode", attr.cloneNode(True), doc1),
+ ("importNode", doc2.importNode(attr, True), doc2),
+ ]:
+ with self.subTest(method=method):
+ self.check_clone_names(clone, attr)
+ self.assertEqual(clone.value, "v")
+ self.assertTrue(clone.specified)
+ self.assertIsNone(clone.ownerElement)
+ self.assertIs(clone.ownerDocument, owner)
+ doc1.unlink()
+ doc2.unlink()
+
def check_clone_pi(self, deep, testName):
doc = parseString("")
pi = doc.firstChild
diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py
index 7cb652a323dcc22..f4d544e08bd3e94 100644
--- a/Lib/xml/dom/minidom.py
+++ b/Lib/xml/dom/minidom.py
@@ -2169,11 +2169,20 @@ def _clone_node(node, deep, newOwnerDocument):
else:
operation = xml.dom.UserDataHandler.NODE_IMPORTED
if node.nodeType == Node.ELEMENT_NODE:
- clone = newOwnerDocument.createElementNS(node.namespaceURI,
- node.nodeName)
+ if node.namespaceURI is None:
+ clone = newOwnerDocument.createElement(node.nodeName)
+ else:
+ clone = newOwnerDocument.createElementNS(node.namespaceURI,
+ node.nodeName)
for attr in node.attributes.values():
- clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value)
- a = clone.getAttributeNodeNS(attr.namespaceURI, attr.localName)
+ if attr.namespaceURI is None:
+ clone.setAttribute(attr.nodeName, attr.value)
+ a = clone.getAttributeNode(attr.nodeName)
+ else:
+ clone.setAttributeNS(attr.namespaceURI, attr.nodeName,
+ attr.value)
+ a = clone.getAttributeNodeNS(attr.namespaceURI,
+ attr.localName)
a.specified = attr.specified
if deep:
@@ -2200,8 +2209,11 @@ def _clone_node(node, deep, newOwnerDocument):
elif node.nodeType == Node.ENTITY_REFERENCE_NODE:
clone = newOwnerDocument.createEntityReference(node.nodeName)
elif node.nodeType == Node.ATTRIBUTE_NODE:
- clone = newOwnerDocument.createAttributeNS(node.namespaceURI,
- node.nodeName)
+ if node.namespaceURI is None:
+ clone = newOwnerDocument.createAttribute(node.nodeName)
+ else:
+ clone = newOwnerDocument.createAttributeNS(node.namespaceURI,
+ node.nodeName)
clone.specified = True
clone.value = node.value
elif node.nodeType == Node.DOCUMENT_TYPE_NODE: