Skip to content

bpo-35052: Fix handler on xml.dom.minidom.cloneNode() #11061

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 10, 2018
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.