Skip to content
Merged
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
55 changes: 53 additions & 2 deletions Lib/test/test_minidom.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import copy
import pickle
import io
from test.support import findfile
from test import support
import unittest

import xml.dom.minidom
Expand All @@ -12,7 +12,7 @@
from xml.dom.minidom import getDOMImplementation


tstfile = findfile("test.xml", subdir="xmltestdata")
tstfile = support.findfile("test.xml", subdir="xmltestdata")
sample = ("<?xml version='1.0' encoding='us-ascii'?>\n"
"<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
" 'http://xml.python.org/system' [\n"
Expand Down Expand Up @@ -837,6 +837,57 @@ def testClonePIShallow(self):
def testClonePIDeep(self):
self.check_clone_pi(1, "testClonePIDeep")

def check_clone_node_entity(self, clone_document):
# bpo-35052: Test user data handler in cloneNode() on a document with
# an entity
document = xml.dom.minidom.parseString("""
<?xml version="1.0" ?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd"
[ <!ENTITY smile "☺"> ]
>
<doc>Don't let entities make you frown &smile;</doc>
""".strip())

class Handler:
def handle(self, operation, key, data, src, dst):
self.operation = operation
self.key = key
self.data = data
self.src = src
self.dst = dst

handler = Handler()
doctype = document.doctype
entity = doctype.entities['smile']
entity.setUserData("key", "data", handler)

if clone_document:
# clone Document
clone = document.cloneNode(deep=True)

self.assertEqual(clone.documentElement.firstChild.wholeText,
"Don't let entities make you frown ☺")
operation = xml.dom.UserDataHandler.NODE_IMPORTED
dst = clone.doctype.entities['smile']
else:
# clone DocumentType
with support.swap_attr(doctype, 'ownerDocument', None):
clone = doctype.cloneNode(deep=True)

operation = xml.dom.UserDataHandler.NODE_CLONED
dst = clone.entities['smile']

self.assertEqual(handler.operation, operation)
self.assertEqual(handler.key, "key")
self.assertEqual(handler.data, "data")
self.assertIs(handler.src, entity)
self.assertIs(handler.dst, dst)

def testCloneNodeEntity(self):
self.check_clone_node_entity(False)
self.check_clone_node_entity(True)

def testNormalize(self):
doc = parseString("<doc/>")
root = doc.documentElement
Expand Down
4 changes: 2 additions & 2 deletions Lib/xml/dom/minidom.py
Original file line number Diff line number Diff line change
Expand Up @@ -1318,7 +1318,7 @@ def cloneNode(self, deep):
entity.encoding = e.encoding
entity.version = e.version
clone.entities._seq.append(entity)
e._call_user_data_handler(operation, n, entity)
e._call_user_data_handler(operation, e, entity)
self._call_user_data_handler(operation, self, clone)
return clone
else:
Expand Down Expand Up @@ -1921,7 +1921,7 @@ def _clone_node(node, deep, newOwnerDocument):
entity.ownerDocument = newOwnerDocument
clone.entities._seq.append(entity)
if hasattr(e, '_call_user_data_handler'):
e._call_user_data_handler(operation, n, entity)
e._call_user_data_handler(operation, e, entity)
else:
# Note the cloning of Document and DocumentType nodes is
# implementation specific. minidom handles those cases
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix xml.dom.minidom cloneNode() on a document with an entity: pass the
correct arguments to the user data handler of an entity.