blob: b6d88d2581e74023797adc6ba5277ad6dfb53aed [file] [log] [blame]
Fred Drakefbdeaad2006-07-29 16:56:15 +00001# test for xml.dom.minidom
Paul Prescod7993bcc2000-07-01 14:54:16 +00002
Serhiy Storchaka9baa5682015-11-26 23:48:30 +02003import copy
Martin v. Löwisfd6aaa12003-01-25 22:02:52 +00004import pickle
Martin v. Löwisfd6aaa12003-01-25 22:02:52 +00005from StringIO import StringIO
Florent Xicluna1b51c3d2010-03-13 12:41:48 +00006from test.test_support import verbose, run_unittest, findfile
Collin Winterd28fcbc2007-03-28 23:34:06 +00007import unittest
Fred Drake17647f52000-07-03 16:37:42 +00008
Fred Drakefbdeaad2006-07-29 16:56:15 +00009import xml.dom
10import xml.dom.minidom
11import xml.parsers.expat
Fred Drakec441f7b2002-07-19 22:16:41 +000012
Fred Drakefbdeaad2006-07-29 16:56:15 +000013from xml.dom.minidom import parse, Node, Document, parseString
14from xml.dom.minidom import getDOMImplementation
Martin v. Löwisfd6aaa12003-01-25 22:02:52 +000015
Fred Drakec441f7b2002-07-19 22:16:41 +000016
Florent Xicluna1b51c3d2010-03-13 12:41:48 +000017tstfile = findfile("test.xml", subdir="xmltestdata")
Serhiy Storchaka9baa5682015-11-26 23:48:30 +020018sample = ("<?xml version='1.0' encoding='us-ascii'?>\n"
19 "<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
20 " 'http://xml.python.org/system' [\n"
21 " <!ELEMENT e EMPTY>\n"
22 " <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n"
23 "]><doc attr='value'> text\n"
24 "<?pi sample?> <!-- comment --> <e/> </doc>")
Paul Prescod7993bcc2000-07-01 14:54:16 +000025
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000026# The tests of DocumentType importing use these helpers to construct
27# the documents to work with, since not all DOM builders actually
28# create the DocumentType nodes.
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000029def create_doc_without_doctype(doctype=None):
30 return getDOMImplementation().createDocument(None, "doc", doctype)
31
32def create_nonempty_doctype():
33 doctype = getDOMImplementation().createDocumentType("doc", None, None)
34 doctype.entities._seq = []
35 doctype.notations._seq = []
Fred Drakefbdeaad2006-07-29 16:56:15 +000036 notation = xml.dom.minidom.Notation("my-notation", None,
37 "http://xml.python.org/notations/my")
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000038 doctype.notations._seq.append(notation)
Fred Drakefbdeaad2006-07-29 16:56:15 +000039 entity = xml.dom.minidom.Entity("my-entity", None,
40 "http://xml.python.org/entities/my",
41 "my-notation")
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000042 entity.version = "1.0"
43 entity.encoding = "utf-8"
44 entity.actualEncoding = "us-ascii"
45 doctype.entities._seq.append(entity)
46 return doctype
47
48def create_doc_with_doctype():
49 doctype = create_nonempty_doctype()
50 doc = create_doc_without_doctype(doctype)
51 doctype.entities.item(0).ownerDocument = doc
52 doctype.notations.item(0).ownerDocument = doc
53 return doc
54
Collin Winterd28fcbc2007-03-28 23:34:06 +000055class MinidomTest(unittest.TestCase):
Collin Winterd28fcbc2007-03-28 23:34:06 +000056 def confirm(self, test, testname = "Test"):
57 self.assertTrue(test, testname)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000058
Collin Winterd28fcbc2007-03-28 23:34:06 +000059 def checkWholeText(self, node, s):
60 t = node.wholeText
61 self.confirm(t == s, "looking for %s, found %s" % (repr(s), repr(t)))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000062
Collin Winterd28fcbc2007-03-28 23:34:06 +000063 def testParseFromFile(self):
64 dom = parse(StringIO(open(tstfile).read()))
65 dom.unlink()
66 self.confirm(isinstance(dom,Document))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000067
Collin Winterd28fcbc2007-03-28 23:34:06 +000068 def testGetElementsByTagName(self):
69 dom = parse(tstfile)
70 self.confirm(dom.getElementsByTagName("LI") == \
71 dom.documentElement.getElementsByTagName("LI"))
72 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000073
Collin Winterd28fcbc2007-03-28 23:34:06 +000074 def testInsertBefore(self):
75 dom = parseString("<doc><foo/></doc>")
76 root = dom.documentElement
77 elem = root.childNodes[0]
78 nelem = dom.createElement("element")
79 root.insertBefore(nelem, elem)
80 self.confirm(len(root.childNodes) == 2
81 and root.childNodes.length == 2
82 and root.childNodes[0] is nelem
83 and root.childNodes.item(0) is nelem
84 and root.childNodes[1] is elem
85 and root.childNodes.item(1) is elem
86 and root.firstChild is nelem
87 and root.lastChild is elem
88 and root.toxml() == "<doc><element/><foo/></doc>"
89 , "testInsertBefore -- node properly placed in tree")
90 nelem = dom.createElement("element")
91 root.insertBefore(nelem, None)
92 self.confirm(len(root.childNodes) == 3
93 and root.childNodes.length == 3
94 and root.childNodes[1] is elem
95 and root.childNodes.item(1) is elem
96 and root.childNodes[2] is nelem
97 and root.childNodes.item(2) is nelem
98 and root.lastChild is nelem
99 and nelem.previousSibling is elem
100 and root.toxml() == "<doc><element/><foo/><element/></doc>"
101 , "testInsertBefore -- node properly placed in tree")
102 nelem2 = dom.createElement("bar")
103 root.insertBefore(nelem2, nelem)
104 self.confirm(len(root.childNodes) == 4
105 and root.childNodes.length == 4
106 and root.childNodes[2] is nelem2
107 and root.childNodes.item(2) is nelem2
108 and root.childNodes[3] is nelem
109 and root.childNodes.item(3) is nelem
110 and nelem2.nextSibling is nelem
111 and nelem.previousSibling is nelem2
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000112 and root.toxml() ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000113 "<doc><element/><foo/><bar/><element/></doc>"
114 , "testInsertBefore -- node properly placed in tree")
115 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000116
Collin Winterd28fcbc2007-03-28 23:34:06 +0000117 def _create_fragment_test_nodes(self):
118 dom = parseString("<doc/>")
119 orig = dom.createTextNode("original")
120 c1 = dom.createTextNode("foo")
121 c2 = dom.createTextNode("bar")
122 c3 = dom.createTextNode("bat")
123 dom.documentElement.appendChild(orig)
124 frag = dom.createDocumentFragment()
125 frag.appendChild(c1)
126 frag.appendChild(c2)
127 frag.appendChild(c3)
128 return dom, orig, c1, c2, c3, frag
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000129
Collin Winterd28fcbc2007-03-28 23:34:06 +0000130 def testInsertBeforeFragment(self):
131 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
132 dom.documentElement.insertBefore(frag, None)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000133 self.confirm(tuple(dom.documentElement.childNodes) ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000134 (orig, c1, c2, c3),
135 "insertBefore(<fragment>, None)")
136 frag.unlink()
137 dom.unlink()
Paul Prescod10d27662000-09-18 19:07:26 +0000138
Collin Winterd28fcbc2007-03-28 23:34:06 +0000139 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
140 dom.documentElement.insertBefore(frag, orig)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000141 self.confirm(tuple(dom.documentElement.childNodes) ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000142 (c1, c2, c3, orig),
143 "insertBefore(<fragment>, orig)")
144 frag.unlink()
145 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000146
Collin Winterd28fcbc2007-03-28 23:34:06 +0000147 def testAppendChild(self):
148 dom = parse(tstfile)
149 dom.documentElement.appendChild(dom.createComment(u"Hello"))
150 self.confirm(dom.documentElement.childNodes[-1].nodeName == "#comment")
151 self.confirm(dom.documentElement.childNodes[-1].data == "Hello")
152 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000153
Collin Winterd28fcbc2007-03-28 23:34:06 +0000154 def testAppendChildFragment(self):
155 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
156 dom.documentElement.appendChild(frag)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000157 self.confirm(tuple(dom.documentElement.childNodes) ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000158 (orig, c1, c2, c3),
159 "appendChild(<fragment>)")
160 frag.unlink()
161 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000162
Collin Winterd28fcbc2007-03-28 23:34:06 +0000163 def testReplaceChildFragment(self):
164 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
165 dom.documentElement.replaceChild(frag, orig)
166 orig.unlink()
167 self.confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3),
168 "replaceChild(<fragment>)")
169 frag.unlink()
170 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000171
Collin Winterd28fcbc2007-03-28 23:34:06 +0000172 def testLegalChildren(self):
173 dom = Document()
174 elem = dom.createElement('element')
175 text = dom.createTextNode('text')
176 self.assertRaises(xml.dom.HierarchyRequestErr, dom.appendChild, text)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000177
Collin Winterd28fcbc2007-03-28 23:34:06 +0000178 dom.appendChild(elem)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000179 self.assertRaises(xml.dom.HierarchyRequestErr, dom.insertBefore, text,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000180 elem)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000181 self.assertRaises(xml.dom.HierarchyRequestErr, dom.replaceChild, text,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000182 elem)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000183
Collin Winterd28fcbc2007-03-28 23:34:06 +0000184 nodemap = elem.attributes
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000185 self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItem,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000186 text)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000187 self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItemNS,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000188 text)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000189
Collin Winterd28fcbc2007-03-28 23:34:06 +0000190 elem.appendChild(text)
191 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000192
Collin Winterd28fcbc2007-03-28 23:34:06 +0000193 def testNamedNodeMapSetItem(self):
194 dom = Document()
195 elem = dom.createElement('element')
196 attrs = elem.attributes
197 attrs["foo"] = "bar"
198 a = attrs.item(0)
199 self.confirm(a.ownerDocument is dom,
200 "NamedNodeMap.__setitem__() sets ownerDocument")
201 self.confirm(a.ownerElement is elem,
202 "NamedNodeMap.__setitem__() sets ownerElement")
203 self.confirm(a.value == "bar",
204 "NamedNodeMap.__setitem__() sets value")
205 self.confirm(a.nodeValue == "bar",
206 "NamedNodeMap.__setitem__() sets nodeValue")
207 elem.unlink()
208 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000209
Collin Winterd28fcbc2007-03-28 23:34:06 +0000210 def testNonZero(self):
211 dom = parse(tstfile)
212 self.confirm(dom)# should not be zero
213 dom.appendChild(dom.createComment("foo"))
214 self.confirm(not dom.childNodes[-1].childNodes)
215 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000216
Collin Winterd28fcbc2007-03-28 23:34:06 +0000217 def testUnlink(self):
218 dom = parse(tstfile)
219 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000220
Collin Winterd28fcbc2007-03-28 23:34:06 +0000221 def testElement(self):
222 dom = Document()
223 dom.appendChild(dom.createElement("abc"))
224 self.confirm(dom.documentElement)
225 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000226
Collin Winterd28fcbc2007-03-28 23:34:06 +0000227 def testAAA(self):
228 dom = parseString("<abc/>")
229 el = dom.documentElement
230 el.setAttribute("spam", "jam2")
231 self.confirm(el.toxml() == '<abc spam="jam2"/>', "testAAA")
232 a = el.getAttributeNode("spam")
233 self.confirm(a.ownerDocument is dom,
234 "setAttribute() sets ownerDocument")
235 self.confirm(a.ownerElement is dom.documentElement,
236 "setAttribute() sets ownerElement")
237 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000238
Collin Winterd28fcbc2007-03-28 23:34:06 +0000239 def testAAB(self):
240 dom = parseString("<abc/>")
241 el = dom.documentElement
242 el.setAttribute("spam", "jam")
243 el.setAttribute("spam", "jam2")
244 self.confirm(el.toxml() == '<abc spam="jam2"/>', "testAAB")
245 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000246
Collin Winterd28fcbc2007-03-28 23:34:06 +0000247 def testAddAttr(self):
248 dom = Document()
249 child = dom.appendChild(dom.createElement("abc"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000250
Collin Winterd28fcbc2007-03-28 23:34:06 +0000251 child.setAttribute("def", "ghi")
252 self.confirm(child.getAttribute("def") == "ghi")
253 self.confirm(child.attributes["def"].value == "ghi")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000254
Collin Winterd28fcbc2007-03-28 23:34:06 +0000255 child.setAttribute("jkl", "mno")
256 self.confirm(child.getAttribute("jkl") == "mno")
257 self.confirm(child.attributes["jkl"].value == "mno")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000258
Collin Winterd28fcbc2007-03-28 23:34:06 +0000259 self.confirm(len(child.attributes) == 2)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000260
Collin Winterd28fcbc2007-03-28 23:34:06 +0000261 child.setAttribute("def", "newval")
262 self.confirm(child.getAttribute("def") == "newval")
263 self.confirm(child.attributes["def"].value == "newval")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000264
Collin Winterd28fcbc2007-03-28 23:34:06 +0000265 self.confirm(len(child.attributes) == 2)
266 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000267
Collin Winterd28fcbc2007-03-28 23:34:06 +0000268 def testDeleteAttr(self):
269 dom = Document()
270 child = dom.appendChild(dom.createElement("abc"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000271
Collin Winterd28fcbc2007-03-28 23:34:06 +0000272 self.confirm(len(child.attributes) == 0)
273 child.setAttribute("def", "ghi")
274 self.confirm(len(child.attributes) == 1)
275 del child.attributes["def"]
276 self.confirm(len(child.attributes) == 0)
277 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000278
Collin Winterd28fcbc2007-03-28 23:34:06 +0000279 def testRemoveAttr(self):
280 dom = Document()
281 child = dom.appendChild(dom.createElement("abc"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000282
Collin Winterd28fcbc2007-03-28 23:34:06 +0000283 child.setAttribute("def", "ghi")
284 self.confirm(len(child.attributes) == 1)
285 child.removeAttribute("def")
286 self.confirm(len(child.attributes) == 0)
287 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000288
Collin Winterd28fcbc2007-03-28 23:34:06 +0000289 def testRemoveAttrNS(self):
290 dom = Document()
291 child = dom.appendChild(
292 dom.createElementNS("http://www.python.org", "python:abc"))
293 child.setAttributeNS("http://www.w3.org", "xmlns:python",
294 "http://www.python.org")
295 child.setAttributeNS("http://www.python.org", "python:abcattr", "foo")
296 self.confirm(len(child.attributes) == 2)
297 child.removeAttributeNS("http://www.python.org", "abcattr")
298 self.confirm(len(child.attributes) == 1)
299 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000300
Collin Winterd28fcbc2007-03-28 23:34:06 +0000301 def testRemoveAttributeNode(self):
302 dom = Document()
303 child = dom.appendChild(dom.createElement("foo"))
304 child.setAttribute("spam", "jam")
305 self.confirm(len(child.attributes) == 1)
306 node = child.getAttributeNode("spam")
307 child.removeAttributeNode(node)
308 self.confirm(len(child.attributes) == 0
309 and child.getAttributeNode("spam") is None)
310 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000311
Collin Winterd28fcbc2007-03-28 23:34:06 +0000312 def testChangeAttr(self):
313 dom = parseString("<abc/>")
314 el = dom.documentElement
315 el.setAttribute("spam", "jam")
316 self.confirm(len(el.attributes) == 1)
317 el.setAttribute("spam", "bam")
318 # Set this attribute to be an ID and make sure that doesn't change
319 # when changing the value:
320 el.setIdAttribute("spam")
321 self.confirm(len(el.attributes) == 1
322 and el.attributes["spam"].value == "bam"
323 and el.attributes["spam"].nodeValue == "bam"
324 and el.getAttribute("spam") == "bam"
325 and el.getAttributeNode("spam").isId)
326 el.attributes["spam"] = "ham"
327 self.confirm(len(el.attributes) == 1
328 and el.attributes["spam"].value == "ham"
329 and el.attributes["spam"].nodeValue == "ham"
330 and el.getAttribute("spam") == "ham"
331 and el.attributes["spam"].isId)
332 el.setAttribute("spam2", "bam")
333 self.confirm(len(el.attributes) == 2
334 and el.attributes["spam"].value == "ham"
335 and el.attributes["spam"].nodeValue == "ham"
336 and el.getAttribute("spam") == "ham"
337 and el.attributes["spam2"].value == "bam"
338 and el.attributes["spam2"].nodeValue == "bam"
339 and el.getAttribute("spam2") == "bam")
340 el.attributes["spam2"] = "bam2"
341 self.confirm(len(el.attributes) == 2
342 and el.attributes["spam"].value == "ham"
343 and el.attributes["spam"].nodeValue == "ham"
344 and el.getAttribute("spam") == "ham"
345 and el.attributes["spam2"].value == "bam2"
346 and el.attributes["spam2"].nodeValue == "bam2"
347 and el.getAttribute("spam2") == "bam2")
348 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000349
Collin Winterd28fcbc2007-03-28 23:34:06 +0000350 def testGetElementsByTagNameNS(self):
351 d="""<foo xmlns:minidom='http://pyxml.sf.net/minidom'>
352 <minidom:myelem/>
353 </foo>"""
354 dom = parseString(d)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000355 elems = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom",
Collin Winterd28fcbc2007-03-28 23:34:06 +0000356 "myelem")
357 self.confirm(len(elems) == 1
358 and elems[0].namespaceURI == "http://pyxml.sf.net/minidom"
359 and elems[0].localName == "myelem"
360 and elems[0].prefix == "minidom"
361 and elems[0].tagName == "minidom:myelem"
362 and elems[0].nodeName == "minidom:myelem")
363 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000364
365 def get_empty_nodelist_from_elements_by_tagName_ns_helper(self, doc, nsuri,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000366 lname):
367 nodelist = doc.getElementsByTagNameNS(nsuri, lname)
368 self.confirm(len(nodelist) == 0)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000369
Collin Winterd28fcbc2007-03-28 23:34:06 +0000370 def testGetEmptyNodeListFromElementsByTagNameNS(self):
371 doc = parseString('<doc/>')
372 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
373 doc, 'http://xml.python.org/namespaces/a', 'localname')
374 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
375 doc, '*', 'splat')
376 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
377 doc, 'http://xml.python.org/namespaces/a', '*')
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000378
Collin Winterd28fcbc2007-03-28 23:34:06 +0000379 doc = parseString('<doc xmlns="http://xml.python.org/splat"><e/></doc>')
380 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
381 doc, "http://xml.python.org/splat", "not-there")
382 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
383 doc, "*", "not-there")
384 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
385 doc, "http://somewhere.else.net/not-there", "e")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000386
Collin Winterd28fcbc2007-03-28 23:34:06 +0000387 def testElementReprAndStr(self):
388 dom = Document()
389 el = dom.appendChild(dom.createElement("abc"))
390 string1 = repr(el)
391 string2 = str(el)
392 self.confirm(string1 == string2)
393 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000394
Collin Winterd28fcbc2007-03-28 23:34:06 +0000395 def testElementReprAndStrUnicode(self):
396 dom = Document()
397 el = dom.appendChild(dom.createElement(u"abc"))
398 string1 = repr(el)
399 string2 = str(el)
400 self.confirm(string1 == string2)
401 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000402
Collin Winterd28fcbc2007-03-28 23:34:06 +0000403 def testElementReprAndStrUnicodeNS(self):
404 dom = Document()
405 el = dom.appendChild(
406 dom.createElementNS(u"http://www.slashdot.org", u"slash:abc"))
407 string1 = repr(el)
408 string2 = str(el)
409 self.confirm(string1 == string2)
Ezio Melotti187f93d2010-03-17 14:22:34 +0000410 self.confirm("slash:abc" in string1)
Collin Winterd28fcbc2007-03-28 23:34:06 +0000411 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000412
Collin Winterd28fcbc2007-03-28 23:34:06 +0000413 def testAttributeRepr(self):
414 dom = Document()
415 el = dom.appendChild(dom.createElement(u"abc"))
416 node = el.setAttribute("abc", "def")
417 self.confirm(str(node) == repr(node))
418 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000419
Collin Winterd28fcbc2007-03-28 23:34:06 +0000420 def testWriteXML(self):
421 str = '<?xml version="1.0" ?><a b="c"/>'
422 dom = parseString(str)
423 domstr = dom.toxml()
424 dom.unlink()
425 self.confirm(str == domstr)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000426
Collin Winterd28fcbc2007-03-28 23:34:06 +0000427 def testAltNewline(self):
428 str = '<?xml version="1.0" ?>\n<a b="c"/>\n'
429 dom = parseString(str)
430 domstr = dom.toprettyxml(newl="\r\n")
431 dom.unlink()
432 self.confirm(domstr == str.replace("\n", "\r\n"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000433
Ezio Melotti93bbb6a2011-11-18 17:30:28 +0200434 def test_toprettyxml_with_text_nodes(self):
435 # see issue #4147, text nodes are not indented
436 decl = '<?xml version="1.0" ?>\n'
437 self.assertEqual(parseString('<B>A</B>').toprettyxml(),
438 decl + '<B>A</B>\n')
439 self.assertEqual(parseString('<C>A<B>A</B></C>').toprettyxml(),
440 decl + '<C>\n\tA\n\t<B>A</B>\n</C>\n')
441 self.assertEqual(parseString('<C><B>A</B>A</C>').toprettyxml(),
442 decl + '<C>\n\t<B>A</B>\n\tA\n</C>\n')
443 self.assertEqual(parseString('<C><B>A</B><B>A</B></C>').toprettyxml(),
444 decl + '<C>\n\t<B>A</B>\n\t<B>A</B>\n</C>\n')
445 self.assertEqual(parseString('<C><B>A</B>A<B>A</B></C>').toprettyxml(),
446 decl + '<C>\n\t<B>A</B>\n\tA\n\t<B>A</B>\n</C>\n')
447
448 def test_toprettyxml_with_adjacent_text_nodes(self):
449 # see issue #4147, adjacent text nodes are indented normally
450 dom = Document()
451 elem = dom.createElement(u'elem')
452 elem.appendChild(dom.createTextNode(u'TEXT'))
453 elem.appendChild(dom.createTextNode(u'TEXT'))
454 dom.appendChild(elem)
455 decl = '<?xml version="1.0" ?>\n'
456 self.assertEqual(dom.toprettyxml(),
457 decl + '<elem>\n\tTEXT\n\tTEXT\n</elem>\n')
458
Éric Araujo2710bc42011-10-05 02:35:09 +0200459 def test_toprettyxml_preserves_content_of_text_node(self):
Ezio Melotti93bbb6a2011-11-18 17:30:28 +0200460 # see issue #4147
461 for str in ('<B>A</B>', '<A><B>C</B></A>'):
462 dom = parseString(str)
463 dom2 = parseString(dom.toprettyxml())
464 self.assertEqual(
465 dom.getElementsByTagName('B')[0].childNodes[0].toxml(),
466 dom2.getElementsByTagName('B')[0].childNodes[0].toxml())
R David Murrayc8faf9b2011-10-01 16:49:25 -0400467
Collin Winterd28fcbc2007-03-28 23:34:06 +0000468 def testProcessingInstruction(self):
469 dom = parseString('<e><?mypi \t\n data \t\n ?></e>')
470 pi = dom.documentElement.firstChild
471 self.confirm(pi.target == "mypi"
472 and pi.data == "data \t\n "
473 and pi.nodeName == "mypi"
474 and pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE
475 and pi.attributes is None
476 and not pi.hasChildNodes()
477 and len(pi.childNodes) == 0
478 and pi.firstChild is None
479 and pi.lastChild is None
480 and pi.localName is None
481 and pi.namespaceURI == xml.dom.EMPTY_NAMESPACE)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000482
Collin Winterd28fcbc2007-03-28 23:34:06 +0000483 def testTooManyDocumentElements(self):
484 doc = parseString("<doc/>")
485 elem = doc.createElement("extra")
486 # Should raise an exception when adding an extra document element.
487 self.assertRaises(xml.dom.HierarchyRequestErr, doc.appendChild, elem)
488 elem.unlink()
489 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000490
Collin Winterd28fcbc2007-03-28 23:34:06 +0000491 def testRemoveNamedItem(self):
492 doc = parseString("<doc a=''/>")
493 e = doc.documentElement
494 attrs = e.attributes
495 a1 = e.getAttributeNode("a")
496 a2 = attrs.removeNamedItem("a")
497 self.confirm(a1.isSameNode(a2))
498 self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItem, "a")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000499
Collin Winterd28fcbc2007-03-28 23:34:06 +0000500 def testRemoveNamedItemNS(self):
501 doc = parseString("<doc xmlns:a='http://xml.python.org/' a:b=''/>")
502 e = doc.documentElement
503 attrs = e.attributes
504 a1 = e.getAttributeNodeNS("http://xml.python.org/", "b")
505 a2 = attrs.removeNamedItemNS("http://xml.python.org/", "b")
506 self.confirm(a1.isSameNode(a2))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000507 self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItemNS,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000508 "http://xml.python.org/", "b")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000509
Collin Winterd28fcbc2007-03-28 23:34:06 +0000510 def _testCloneElementCopiesAttributes(self, e1, e2, test):
511 attrs1 = e1.attributes
512 attrs2 = e2.attributes
513 keys1 = attrs1.keys()
514 keys2 = attrs2.keys()
515 keys1.sort()
516 keys2.sort()
517 self.confirm(keys1 == keys2, "clone of element has same attribute keys")
518 for i in range(len(keys1)):
519 a1 = attrs1.item(i)
520 a2 = attrs2.item(i)
521 self.confirm(a1 is not a2
522 and a1.value == a2.value
523 and a1.nodeValue == a2.nodeValue
524 and a1.namespaceURI == a2.namespaceURI
525 and a1.localName == a2.localName
526 , "clone of attribute node has proper attribute values")
527 self.confirm(a2.ownerElement is e2,
528 "clone of attribute node correctly owned")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000529
Collin Winterd28fcbc2007-03-28 23:34:06 +0000530 def _setupCloneElement(self, deep):
531 dom = parseString("<doc attr='value'><foo/></doc>")
532 root = dom.documentElement
533 clone = root.cloneNode(deep)
534 self._testCloneElementCopiesAttributes(
535 root, clone, "testCloneElement" + (deep and "Deep" or "Shallow"))
536 # mutilate the original so shared data is detected
537 root.tagName = root.nodeName = "MODIFIED"
538 root.setAttribute("attr", "NEW VALUE")
539 root.setAttribute("added", "VALUE")
540 return dom, clone
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000541
Collin Winterd28fcbc2007-03-28 23:34:06 +0000542 def testCloneElementShallow(self):
543 dom, clone = self._setupCloneElement(0)
544 self.confirm(len(clone.childNodes) == 0
545 and clone.childNodes.length == 0
546 and clone.parentNode is None
547 and clone.toxml() == '<doc attr="value"/>'
548 , "testCloneElementShallow")
549 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000550
Collin Winterd28fcbc2007-03-28 23:34:06 +0000551 def testCloneElementDeep(self):
552 dom, clone = self._setupCloneElement(1)
553 self.confirm(len(clone.childNodes) == 1
554 and clone.childNodes.length == 1
555 and clone.parentNode is None
556 and clone.toxml() == '<doc attr="value"><foo/></doc>'
557 , "testCloneElementDeep")
558 dom.unlink()
559
560 def testCloneDocumentShallow(self):
561 doc = parseString("<?xml version='1.0'?>\n"
562 "<!-- comment -->"
563 "<!DOCTYPE doc [\n"
564 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
565 "]>\n"
566 "<doc attr='value'/>")
567 doc2 = doc.cloneNode(0)
568 self.confirm(doc2 is None,
569 "testCloneDocumentShallow:"
570 " shallow cloning of documents makes no sense!")
571
572 def testCloneDocumentDeep(self):
573 doc = parseString("<?xml version='1.0'?>\n"
574 "<!-- comment -->"
575 "<!DOCTYPE doc [\n"
576 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
577 "]>\n"
578 "<doc attr='value'/>")
579 doc2 = doc.cloneNode(1)
580 self.confirm(not (doc.isSameNode(doc2) or doc2.isSameNode(doc)),
581 "testCloneDocumentDeep: document objects not distinct")
582 self.confirm(len(doc.childNodes) == len(doc2.childNodes),
583 "testCloneDocumentDeep: wrong number of Document children")
584 self.confirm(doc2.documentElement.nodeType == Node.ELEMENT_NODE,
585 "testCloneDocumentDeep: documentElement not an ELEMENT_NODE")
586 self.confirm(doc2.documentElement.ownerDocument.isSameNode(doc2),
587 "testCloneDocumentDeep: documentElement owner is not new document")
588 self.confirm(not doc.documentElement.isSameNode(doc2.documentElement),
589 "testCloneDocumentDeep: documentElement should not be shared")
590 if doc.doctype is not None:
591 # check the doctype iff the original DOM maintained it
592 self.confirm(doc2.doctype.nodeType == Node.DOCUMENT_TYPE_NODE,
593 "testCloneDocumentDeep: doctype not a DOCUMENT_TYPE_NODE")
594 self.confirm(doc2.doctype.ownerDocument.isSameNode(doc2))
595 self.confirm(not doc.doctype.isSameNode(doc2.doctype))
596
597 def testCloneDocumentTypeDeepOk(self):
598 doctype = create_nonempty_doctype()
599 clone = doctype.cloneNode(1)
600 self.confirm(clone is not None
601 and clone.nodeName == doctype.nodeName
602 and clone.name == doctype.name
603 and clone.publicId == doctype.publicId
604 and clone.systemId == doctype.systemId
605 and len(clone.entities) == len(doctype.entities)
606 and clone.entities.item(len(clone.entities)) is None
607 and len(clone.notations) == len(doctype.notations)
608 and clone.notations.item(len(clone.notations)) is None
609 and len(clone.childNodes) == 0)
610 for i in range(len(doctype.entities)):
611 se = doctype.entities.item(i)
612 ce = clone.entities.item(i)
613 self.confirm((not se.isSameNode(ce))
614 and (not ce.isSameNode(se))
615 and ce.nodeName == se.nodeName
616 and ce.notationName == se.notationName
617 and ce.publicId == se.publicId
618 and ce.systemId == se.systemId
619 and ce.encoding == se.encoding
620 and ce.actualEncoding == se.actualEncoding
621 and ce.version == se.version)
622 for i in range(len(doctype.notations)):
623 sn = doctype.notations.item(i)
624 cn = clone.notations.item(i)
625 self.confirm((not sn.isSameNode(cn))
626 and (not cn.isSameNode(sn))
627 and cn.nodeName == sn.nodeName
628 and cn.publicId == sn.publicId
629 and cn.systemId == sn.systemId)
630
631 def testCloneDocumentTypeDeepNotOk(self):
632 doc = create_doc_with_doctype()
633 clone = doc.doctype.cloneNode(1)
634 self.confirm(clone is None, "testCloneDocumentTypeDeepNotOk")
635
636 def testCloneDocumentTypeShallowOk(self):
637 doctype = create_nonempty_doctype()
638 clone = doctype.cloneNode(0)
639 self.confirm(clone is not None
640 and clone.nodeName == doctype.nodeName
641 and clone.name == doctype.name
642 and clone.publicId == doctype.publicId
643 and clone.systemId == doctype.systemId
644 and len(clone.entities) == 0
645 and clone.entities.item(0) is None
646 and len(clone.notations) == 0
647 and clone.notations.item(0) is None
648 and len(clone.childNodes) == 0)
649
650 def testCloneDocumentTypeShallowNotOk(self):
651 doc = create_doc_with_doctype()
652 clone = doc.doctype.cloneNode(0)
653 self.confirm(clone is None, "testCloneDocumentTypeShallowNotOk")
654
655 def check_import_document(self, deep, testName):
656 doc1 = parseString("<doc/>")
657 doc2 = parseString("<doc/>")
658 self.assertRaises(xml.dom.NotSupportedErr, doc1.importNode, doc2, deep)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000659
Collin Winterd28fcbc2007-03-28 23:34:06 +0000660 def testImportDocumentShallow(self):
661 self.check_import_document(0, "testImportDocumentShallow")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000662
Collin Winterd28fcbc2007-03-28 23:34:06 +0000663 def testImportDocumentDeep(self):
664 self.check_import_document(1, "testImportDocumentDeep")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000665
Collin Winterd28fcbc2007-03-28 23:34:06 +0000666 def testImportDocumentTypeShallow(self):
667 src = create_doc_with_doctype()
668 target = create_doc_without_doctype()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000669 self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000670 src.doctype, 0)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000671
Collin Winterd28fcbc2007-03-28 23:34:06 +0000672 def testImportDocumentTypeDeep(self):
673 src = create_doc_with_doctype()
674 target = create_doc_without_doctype()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000675 self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000676 src.doctype, 1)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000677
Collin Winterd28fcbc2007-03-28 23:34:06 +0000678 # Testing attribute clones uses a helper, and should always be deep,
679 # even if the argument to cloneNode is false.
680 def check_clone_attribute(self, deep, testName):
681 doc = parseString("<doc attr='value'/>")
682 attr = doc.documentElement.getAttributeNode("attr")
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000683 self.assertNotEqual(attr, None)
Collin Winterd28fcbc2007-03-28 23:34:06 +0000684 clone = attr.cloneNode(deep)
685 self.confirm(not clone.isSameNode(attr))
686 self.confirm(not attr.isSameNode(clone))
687 self.confirm(clone.ownerElement is None,
688 testName + ": ownerElement should be None")
689 self.confirm(clone.ownerDocument.isSameNode(attr.ownerDocument),
690 testName + ": ownerDocument does not match")
691 self.confirm(clone.specified,
692 testName + ": cloned attribute must have specified == True")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000693
Collin Winterd28fcbc2007-03-28 23:34:06 +0000694 def testCloneAttributeShallow(self):
695 self.check_clone_attribute(0, "testCloneAttributeShallow")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000696
Collin Winterd28fcbc2007-03-28 23:34:06 +0000697 def testCloneAttributeDeep(self):
698 self.check_clone_attribute(1, "testCloneAttributeDeep")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000699
Collin Winterd28fcbc2007-03-28 23:34:06 +0000700 def check_clone_pi(self, deep, testName):
701 doc = parseString("<?target data?><doc/>")
702 pi = doc.firstChild
Ezio Melotti2623a372010-11-21 13:34:58 +0000703 self.assertEqual(pi.nodeType, Node.PROCESSING_INSTRUCTION_NODE)
Collin Winterd28fcbc2007-03-28 23:34:06 +0000704 clone = pi.cloneNode(deep)
705 self.confirm(clone.target == pi.target
706 and clone.data == pi.data)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000707
Collin Winterd28fcbc2007-03-28 23:34:06 +0000708 def testClonePIShallow(self):
709 self.check_clone_pi(0, "testClonePIShallow")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000710
Collin Winterd28fcbc2007-03-28 23:34:06 +0000711 def testClonePIDeep(self):
712 self.check_clone_pi(1, "testClonePIDeep")
713
714 def testNormalize(self):
715 doc = parseString("<doc/>")
716 root = doc.documentElement
717 root.appendChild(doc.createTextNode("first"))
718 root.appendChild(doc.createTextNode("second"))
719 self.confirm(len(root.childNodes) == 2
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000720 and root.childNodes.length == 2,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000721 "testNormalize -- preparation")
722 doc.normalize()
723 self.confirm(len(root.childNodes) == 1
724 and root.childNodes.length == 1
725 and root.firstChild is root.lastChild
726 and root.firstChild.data == "firstsecond"
727 , "testNormalize -- result")
728 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000729
Collin Winterd28fcbc2007-03-28 23:34:06 +0000730 doc = parseString("<doc/>")
731 root = doc.documentElement
732 root.appendChild(doc.createTextNode(""))
733 doc.normalize()
734 self.confirm(len(root.childNodes) == 0
735 and root.childNodes.length == 0,
736 "testNormalize -- single empty node removed")
737 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000738
R. David Murray0374a822009-04-09 21:54:50 +0000739 def testNormalizeCombineAndNextSibling(self):
740 doc = parseString("<doc/>")
741 root = doc.documentElement
742 root.appendChild(doc.createTextNode("first"))
743 root.appendChild(doc.createTextNode("second"))
744 root.appendChild(doc.createElement("i"))
745 self.confirm(len(root.childNodes) == 3
746 and root.childNodes.length == 3,
747 "testNormalizeCombineAndNextSibling -- preparation")
748 doc.normalize()
749 self.confirm(len(root.childNodes) == 2
750 and root.childNodes.length == 2
751 and root.firstChild.data == "firstsecond"
752 and root.firstChild is not root.lastChild
753 and root.firstChild.nextSibling is root.lastChild
754 and root.firstChild.previousSibling is None
755 and root.lastChild.previousSibling is root.firstChild
756 and root.lastChild.nextSibling is None
757 , "testNormalizeCombinedAndNextSibling -- result")
758 doc.unlink()
759
760 def testNormalizeDeleteWithPrevSibling(self):
761 doc = parseString("<doc/>")
762 root = doc.documentElement
763 root.appendChild(doc.createTextNode("first"))
764 root.appendChild(doc.createTextNode(""))
765 self.confirm(len(root.childNodes) == 2
766 and root.childNodes.length == 2,
767 "testNormalizeDeleteWithPrevSibling -- preparation")
768 doc.normalize()
769 self.confirm(len(root.childNodes) == 1
770 and root.childNodes.length == 1
771 and root.firstChild.data == "first"
772 and root.firstChild is root.lastChild
773 and root.firstChild.nextSibling is None
774 and root.firstChild.previousSibling is None
775 , "testNormalizeDeleteWithPrevSibling -- result")
776 doc.unlink()
777
778 def testNormalizeDeleteWithNextSibling(self):
779 doc = parseString("<doc/>")
780 root = doc.documentElement
781 root.appendChild(doc.createTextNode(""))
782 root.appendChild(doc.createTextNode("second"))
783 self.confirm(len(root.childNodes) == 2
784 and root.childNodes.length == 2,
785 "testNormalizeDeleteWithNextSibling -- preparation")
786 doc.normalize()
787 self.confirm(len(root.childNodes) == 1
788 and root.childNodes.length == 1
789 and root.firstChild.data == "second"
790 and root.firstChild is root.lastChild
791 and root.firstChild.nextSibling is None
792 and root.firstChild.previousSibling is None
793 , "testNormalizeDeleteWithNextSibling -- result")
794 doc.unlink()
795
796 def testNormalizeDeleteWithTwoNonTextSiblings(self):
797 doc = parseString("<doc/>")
798 root = doc.documentElement
799 root.appendChild(doc.createElement("i"))
800 root.appendChild(doc.createTextNode(""))
801 root.appendChild(doc.createElement("i"))
802 self.confirm(len(root.childNodes) == 3
803 and root.childNodes.length == 3,
804 "testNormalizeDeleteWithTwoSiblings -- preparation")
805 doc.normalize()
806 self.confirm(len(root.childNodes) == 2
807 and root.childNodes.length == 2
808 and root.firstChild is not root.lastChild
809 and root.firstChild.nextSibling is root.lastChild
810 and root.firstChild.previousSibling is None
811 and root.lastChild.previousSibling is root.firstChild
812 and root.lastChild.nextSibling is None
813 , "testNormalizeDeleteWithTwoSiblings -- result")
814 doc.unlink()
815
816 def testNormalizeDeleteAndCombine(self):
817 doc = parseString("<doc/>")
818 root = doc.documentElement
819 root.appendChild(doc.createTextNode(""))
820 root.appendChild(doc.createTextNode("second"))
821 root.appendChild(doc.createTextNode(""))
822 root.appendChild(doc.createTextNode("fourth"))
823 root.appendChild(doc.createTextNode(""))
824 self.confirm(len(root.childNodes) == 5
825 and root.childNodes.length == 5,
826 "testNormalizeDeleteAndCombine -- preparation")
827 doc.normalize()
828 self.confirm(len(root.childNodes) == 1
829 and root.childNodes.length == 1
830 and root.firstChild is root.lastChild
831 and root.firstChild.data == "secondfourth"
832 and root.firstChild.previousSibling is None
833 and root.firstChild.nextSibling is None
834 , "testNormalizeDeleteAndCombine -- result")
835 doc.unlink()
836
837 def testNormalizeRecursion(self):
838 doc = parseString("<doc>"
839 "<o>"
840 "<i/>"
841 "t"
842 #
843 #x
844 "</o>"
845 "<o>"
846 "<o>"
847 "t2"
848 #x2
849 "</o>"
850 "t3"
851 #x3
852 "</o>"
853 #
854 "</doc>")
855 root = doc.documentElement
856 root.childNodes[0].appendChild(doc.createTextNode(""))
857 root.childNodes[0].appendChild(doc.createTextNode("x"))
858 root.childNodes[1].childNodes[0].appendChild(doc.createTextNode("x2"))
859 root.childNodes[1].appendChild(doc.createTextNode("x3"))
860 root.appendChild(doc.createTextNode(""))
861 self.confirm(len(root.childNodes) == 3
862 and root.childNodes.length == 3
863 and len(root.childNodes[0].childNodes) == 4
864 and root.childNodes[0].childNodes.length == 4
865 and len(root.childNodes[1].childNodes) == 3
866 and root.childNodes[1].childNodes.length == 3
867 and len(root.childNodes[1].childNodes[0].childNodes) == 2
868 and root.childNodes[1].childNodes[0].childNodes.length == 2
869 , "testNormalize2 -- preparation")
870 doc.normalize()
871 self.confirm(len(root.childNodes) == 2
872 and root.childNodes.length == 2
873 and len(root.childNodes[0].childNodes) == 2
874 and root.childNodes[0].childNodes.length == 2
875 and len(root.childNodes[1].childNodes) == 2
876 and root.childNodes[1].childNodes.length == 2
877 and len(root.childNodes[1].childNodes[0].childNodes) == 1
878 and root.childNodes[1].childNodes[0].childNodes.length == 1
879 , "testNormalize2 -- childNodes lengths")
880 self.confirm(root.childNodes[0].childNodes[1].data == "tx"
881 and root.childNodes[1].childNodes[0].childNodes[0].data == "t2x2"
882 and root.childNodes[1].childNodes[1].data == "t3x3"
883 , "testNormalize2 -- joined text fields")
884 self.confirm(root.childNodes[0].childNodes[1].nextSibling is None
885 and root.childNodes[0].childNodes[1].previousSibling
886 is root.childNodes[0].childNodes[0]
887 and root.childNodes[0].childNodes[0].previousSibling is None
888 and root.childNodes[0].childNodes[0].nextSibling
889 is root.childNodes[0].childNodes[1]
890 and root.childNodes[1].childNodes[1].nextSibling is None
891 and root.childNodes[1].childNodes[1].previousSibling
892 is root.childNodes[1].childNodes[0]
893 and root.childNodes[1].childNodes[0].previousSibling is None
894 and root.childNodes[1].childNodes[0].nextSibling
895 is root.childNodes[1].childNodes[1]
896 , "testNormalize2 -- sibling pointers")
897 doc.unlink()
898
899
Andrew M. Kuchling53f94d02010-07-25 23:49:57 +0000900 def testBug0777884(self):
901 doc = parseString("<o>text</o>")
902 text = doc.documentElement.childNodes[0]
Ezio Melotti2623a372010-11-21 13:34:58 +0000903 self.assertEqual(text.nodeType, Node.TEXT_NODE)
Andrew M. Kuchling53f94d02010-07-25 23:49:57 +0000904 # Should run quietly, doing nothing.
905 text.normalize()
906 doc.unlink()
907
Andrew M. Kuchling19aff0c2008-02-23 17:10:46 +0000908 def testBug1433694(self):
909 doc = parseString("<o><i/>t</o>")
910 node = doc.documentElement
911 node.childNodes[1].nodeValue = ""
912 node.normalize()
Florent Xiclunabc27c6a2010-03-19 18:34:55 +0000913 self.confirm(node.childNodes[-1].nextSibling is None,
Andrew M. Kuchling19aff0c2008-02-23 17:10:46 +0000914 "Final child's .nextSibling should be None")
915
Collin Winterd28fcbc2007-03-28 23:34:06 +0000916 def testSiblings(self):
917 doc = parseString("<doc><?pi?>text?<elm/></doc>")
918 root = doc.documentElement
919 (pi, text, elm) = root.childNodes
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000920
Collin Winterd28fcbc2007-03-28 23:34:06 +0000921 self.confirm(pi.nextSibling is text and
922 pi.previousSibling is None and
923 text.nextSibling is elm and
924 text.previousSibling is pi and
925 elm.nextSibling is None and
926 elm.previousSibling is text, "testSiblings")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000927
Collin Winterd28fcbc2007-03-28 23:34:06 +0000928 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000929
Collin Winterd28fcbc2007-03-28 23:34:06 +0000930 def testParents(self):
931 doc = parseString(
932 "<doc><elm1><elm2/><elm2><elm3/></elm2></elm1></doc>")
933 root = doc.documentElement
934 elm1 = root.childNodes[0]
935 (elm2a, elm2b) = elm1.childNodes
936 elm3 = elm2b.childNodes[0]
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000937
Collin Winterd28fcbc2007-03-28 23:34:06 +0000938 self.confirm(root.parentNode is doc and
939 elm1.parentNode is root and
940 elm2a.parentNode is elm1 and
941 elm2b.parentNode is elm1 and
942 elm3.parentNode is elm2b, "testParents")
943 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000944
Collin Winterd28fcbc2007-03-28 23:34:06 +0000945 def testNodeListItem(self):
946 doc = parseString("<doc><e/><e/></doc>")
947 children = doc.childNodes
948 docelem = children[0]
949 self.confirm(children[0] is children.item(0)
950 and children.item(1) is None
951 and docelem.childNodes.item(0) is docelem.childNodes[0]
952 and docelem.childNodes.item(1) is docelem.childNodes[1]
953 and docelem.childNodes.item(0).childNodes.item(0) is None,
954 "test NodeList.item()")
955 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000956
Collin Winterd28fcbc2007-03-28 23:34:06 +0000957 def testSAX2DOM(self):
958 from xml.dom import pulldom
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000959
Collin Winterd28fcbc2007-03-28 23:34:06 +0000960 sax2dom = pulldom.SAX2DOM()
961 sax2dom.startDocument()
962 sax2dom.startElement("doc", {})
963 sax2dom.characters("text")
964 sax2dom.startElement("subelm", {})
965 sax2dom.characters("text")
966 sax2dom.endElement("subelm")
967 sax2dom.characters("text")
968 sax2dom.endElement("doc")
969 sax2dom.endDocument()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000970
Collin Winterd28fcbc2007-03-28 23:34:06 +0000971 doc = sax2dom.document
972 root = doc.documentElement
973 (text1, elm1, text2) = root.childNodes
974 text3 = elm1.childNodes[0]
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000975
Collin Winterd28fcbc2007-03-28 23:34:06 +0000976 self.confirm(text1.previousSibling is None and
977 text1.nextSibling is elm1 and
978 elm1.previousSibling is text1 and
979 elm1.nextSibling is text2 and
980 text2.previousSibling is elm1 and
981 text2.nextSibling is None and
982 text3.previousSibling is None and
983 text3.nextSibling is None, "testSAX2DOM - siblings")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000984
Collin Winterd28fcbc2007-03-28 23:34:06 +0000985 self.confirm(root.parentNode is doc and
986 text1.parentNode is root and
987 elm1.parentNode is root and
988 text2.parentNode is root and
989 text3.parentNode is elm1, "testSAX2DOM - parents")
990 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000991
Collin Winterd28fcbc2007-03-28 23:34:06 +0000992 def testEncodings(self):
993 doc = parseString('<foo>&#x20ac;</foo>')
994 self.confirm(doc.toxml() == u'<?xml version="1.0" ?><foo>\u20ac</foo>'
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000995 and doc.toxml('utf-8') ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000996 '<?xml version="1.0" encoding="utf-8"?><foo>\xe2\x82\xac</foo>'
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000997 and doc.toxml('iso-8859-15') ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000998 '<?xml version="1.0" encoding="iso-8859-15"?><foo>\xa4</foo>',
999 "testEncodings - encoding EURO SIGN")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001000
Andrew Svetlov4bb142b2012-12-18 21:27:37 +02001001 # Verify that character decoding errors raise exceptions instead
Collin Winterd28fcbc2007-03-28 23:34:06 +00001002 # of crashing
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001003 self.assertRaises(UnicodeDecodeError, parseString,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001004 '<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001005
Collin Winterd28fcbc2007-03-28 23:34:06 +00001006 doc.unlink()
1007
1008 class UserDataHandler:
1009 called = 0
1010 def handle(self, operation, key, data, src, dst):
1011 dst.setUserData(key, data + 1, self)
1012 src.setUserData(key, None, None)
1013 self.called = 1
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001014
Collin Winterd28fcbc2007-03-28 23:34:06 +00001015 def testUserData(self):
1016 dom = Document()
1017 n = dom.createElement('e')
1018 self.confirm(n.getUserData("foo") is None)
1019 n.setUserData("foo", None, None)
1020 self.confirm(n.getUserData("foo") is None)
1021 n.setUserData("foo", 12, 12)
1022 n.setUserData("bar", 13, 13)
1023 self.confirm(n.getUserData("foo") == 12)
1024 self.confirm(n.getUserData("bar") == 13)
1025 n.setUserData("foo", None, None)
1026 self.confirm(n.getUserData("foo") is None)
1027 self.confirm(n.getUserData("bar") == 13)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001028
Collin Winterd28fcbc2007-03-28 23:34:06 +00001029 handler = self.UserDataHandler()
1030 n.setUserData("bar", 12, handler)
1031 c = n.cloneNode(1)
1032 self.confirm(handler.called
1033 and n.getUserData("bar") is None
1034 and c.getUserData("bar") == 13)
1035 n.unlink()
1036 c.unlink()
1037 dom.unlink()
1038
1039 def checkRenameNodeSharedConstraints(self, doc, node):
1040 # Make sure illegal NS usage is detected:
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001041 self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, node,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001042 "http://xml.python.org/ns", "xmlns:foo")
1043 doc2 = parseString("<doc/>")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001044 self.assertRaises(xml.dom.WrongDocumentErr, doc2.renameNode, node,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001045 xml.dom.EMPTY_NAMESPACE, "foo")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001046
Collin Winterd28fcbc2007-03-28 23:34:06 +00001047 def testRenameAttribute(self):
1048 doc = parseString("<doc a='v'/>")
1049 elem = doc.documentElement
1050 attrmap = elem.attributes
1051 attr = elem.attributes['a']
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001052
Collin Winterd28fcbc2007-03-28 23:34:06 +00001053 # Simple renaming
1054 attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "b")
1055 self.confirm(attr.name == "b"
1056 and attr.nodeName == "b"
1057 and attr.localName is None
1058 and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
1059 and attr.prefix is None
1060 and attr.value == "v"
1061 and elem.getAttributeNode("a") is None
1062 and elem.getAttributeNode("b").isSameNode(attr)
1063 and attrmap["b"].isSameNode(attr)
1064 and attr.ownerDocument.isSameNode(doc)
1065 and attr.ownerElement.isSameNode(elem))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001066
Collin Winterd28fcbc2007-03-28 23:34:06 +00001067 # Rename to have a namespace, no prefix
1068 attr = doc.renameNode(attr, "http://xml.python.org/ns", "c")
1069 self.confirm(attr.name == "c"
1070 and attr.nodeName == "c"
1071 and attr.localName == "c"
1072 and attr.namespaceURI == "http://xml.python.org/ns"
1073 and attr.prefix is None
1074 and attr.value == "v"
1075 and elem.getAttributeNode("a") is None
1076 and elem.getAttributeNode("b") is None
1077 and elem.getAttributeNode("c").isSameNode(attr)
1078 and elem.getAttributeNodeNS(
1079 "http://xml.python.org/ns", "c").isSameNode(attr)
1080 and attrmap["c"].isSameNode(attr)
1081 and attrmap[("http://xml.python.org/ns", "c")].isSameNode(attr))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001082
Collin Winterd28fcbc2007-03-28 23:34:06 +00001083 # Rename to have a namespace, with prefix
1084 attr = doc.renameNode(attr, "http://xml.python.org/ns2", "p:d")
1085 self.confirm(attr.name == "p:d"
1086 and attr.nodeName == "p:d"
1087 and attr.localName == "d"
1088 and attr.namespaceURI == "http://xml.python.org/ns2"
1089 and attr.prefix == "p"
1090 and attr.value == "v"
1091 and elem.getAttributeNode("a") is None
1092 and elem.getAttributeNode("b") is None
1093 and elem.getAttributeNode("c") is None
1094 and elem.getAttributeNodeNS(
1095 "http://xml.python.org/ns", "c") is None
1096 and elem.getAttributeNode("p:d").isSameNode(attr)
1097 and elem.getAttributeNodeNS(
1098 "http://xml.python.org/ns2", "d").isSameNode(attr)
1099 and attrmap["p:d"].isSameNode(attr)
1100 and attrmap[("http://xml.python.org/ns2", "d")].isSameNode(attr))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001101
Collin Winterd28fcbc2007-03-28 23:34:06 +00001102 # Rename back to a simple non-NS node
1103 attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "e")
1104 self.confirm(attr.name == "e"
1105 and attr.nodeName == "e"
1106 and attr.localName is None
1107 and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
1108 and attr.prefix is None
1109 and attr.value == "v"
1110 and elem.getAttributeNode("a") is None
1111 and elem.getAttributeNode("b") is None
1112 and elem.getAttributeNode("c") is None
1113 and elem.getAttributeNode("p:d") is None
1114 and elem.getAttributeNodeNS(
1115 "http://xml.python.org/ns", "c") is None
1116 and elem.getAttributeNode("e").isSameNode(attr)
1117 and attrmap["e"].isSameNode(attr))
1118
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001119 self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, attr,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001120 "http://xml.python.org/ns", "xmlns")
1121 self.checkRenameNodeSharedConstraints(doc, attr)
1122 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001123
Collin Winterd28fcbc2007-03-28 23:34:06 +00001124 def testRenameElement(self):
1125 doc = parseString("<doc/>")
1126 elem = doc.documentElement
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001127
Collin Winterd28fcbc2007-03-28 23:34:06 +00001128 # Simple renaming
1129 elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "a")
1130 self.confirm(elem.tagName == "a"
1131 and elem.nodeName == "a"
1132 and elem.localName is None
1133 and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
1134 and elem.prefix is None
1135 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001136
Collin Winterd28fcbc2007-03-28 23:34:06 +00001137 # Rename to have a namespace, no prefix
1138 elem = doc.renameNode(elem, "http://xml.python.org/ns", "b")
1139 self.confirm(elem.tagName == "b"
1140 and elem.nodeName == "b"
1141 and elem.localName == "b"
1142 and elem.namespaceURI == "http://xml.python.org/ns"
1143 and elem.prefix is None
1144 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001145
Collin Winterd28fcbc2007-03-28 23:34:06 +00001146 # Rename to have a namespace, with prefix
1147 elem = doc.renameNode(elem, "http://xml.python.org/ns2", "p:c")
1148 self.confirm(elem.tagName == "p:c"
1149 and elem.nodeName == "p:c"
1150 and elem.localName == "c"
1151 and elem.namespaceURI == "http://xml.python.org/ns2"
1152 and elem.prefix == "p"
1153 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001154
Collin Winterd28fcbc2007-03-28 23:34:06 +00001155 # Rename back to a simple non-NS node
1156 elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "d")
1157 self.confirm(elem.tagName == "d"
1158 and elem.nodeName == "d"
1159 and elem.localName is None
1160 and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
1161 and elem.prefix is None
1162 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001163
Collin Winterd28fcbc2007-03-28 23:34:06 +00001164 self.checkRenameNodeSharedConstraints(doc, elem)
1165 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001166
Collin Winterd28fcbc2007-03-28 23:34:06 +00001167 def testRenameOther(self):
1168 # We have to create a comment node explicitly since not all DOM
1169 # builders used with minidom add comments to the DOM.
1170 doc = xml.dom.minidom.getDOMImplementation().createDocument(
1171 xml.dom.EMPTY_NAMESPACE, "e", None)
1172 node = doc.createComment("comment")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001173 self.assertRaises(xml.dom.NotSupportedErr, doc.renameNode, node,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001174 xml.dom.EMPTY_NAMESPACE, "foo")
1175 doc.unlink()
1176
1177 def testWholeText(self):
1178 doc = parseString("<doc>a</doc>")
1179 elem = doc.documentElement
1180 text = elem.childNodes[0]
Ezio Melotti2623a372010-11-21 13:34:58 +00001181 self.assertEqual(text.nodeType, Node.TEXT_NODE)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001182
Collin Winterd28fcbc2007-03-28 23:34:06 +00001183 self.checkWholeText(text, "a")
1184 elem.appendChild(doc.createTextNode("b"))
1185 self.checkWholeText(text, "ab")
1186 elem.insertBefore(doc.createCDATASection("c"), text)
1187 self.checkWholeText(text, "cab")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001188
Collin Winterd28fcbc2007-03-28 23:34:06 +00001189 # make sure we don't cross other nodes
1190 splitter = doc.createComment("comment")
1191 elem.appendChild(splitter)
1192 text2 = doc.createTextNode("d")
1193 elem.appendChild(text2)
1194 self.checkWholeText(text, "cab")
1195 self.checkWholeText(text2, "d")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001196
Collin Winterd28fcbc2007-03-28 23:34:06 +00001197 x = doc.createElement("x")
1198 elem.replaceChild(x, splitter)
1199 splitter = x
1200 self.checkWholeText(text, "cab")
1201 self.checkWholeText(text2, "d")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001202
Collin Winterd28fcbc2007-03-28 23:34:06 +00001203 x = doc.createProcessingInstruction("y", "z")
1204 elem.replaceChild(x, splitter)
1205 splitter = x
1206 self.checkWholeText(text, "cab")
1207 self.checkWholeText(text2, "d")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001208
Collin Winterd28fcbc2007-03-28 23:34:06 +00001209 elem.removeChild(splitter)
1210 self.checkWholeText(text, "cabd")
1211 self.checkWholeText(text2, "cabd")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001212
Collin Winterd28fcbc2007-03-28 23:34:06 +00001213 def testPatch1094164(self):
1214 doc = parseString("<doc><e/></doc>")
1215 elem = doc.documentElement
1216 e = elem.firstChild
1217 self.confirm(e.parentNode is elem, "Before replaceChild()")
1218 # Check that replacing a child with itself leaves the tree unchanged
1219 elem.replaceChild(e, e)
1220 self.confirm(e.parentNode is elem, "After replaceChild()")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001221
Collin Winterd28fcbc2007-03-28 23:34:06 +00001222 def testReplaceWholeText(self):
1223 def setup():
1224 doc = parseString("<doc>a<e/>d</doc>")
1225 elem = doc.documentElement
1226 text1 = elem.firstChild
1227 text2 = elem.lastChild
1228 splitter = text1.nextSibling
1229 elem.insertBefore(doc.createTextNode("b"), splitter)
1230 elem.insertBefore(doc.createCDATASection("c"), text1)
1231 return doc, elem, text1, splitter, text2
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001232
Collin Winterd28fcbc2007-03-28 23:34:06 +00001233 doc, elem, text1, splitter, text2 = setup()
1234 text = text1.replaceWholeText("new content")
1235 self.checkWholeText(text, "new content")
1236 self.checkWholeText(text2, "d")
1237 self.confirm(len(elem.childNodes) == 3)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001238
Collin Winterd28fcbc2007-03-28 23:34:06 +00001239 doc, elem, text1, splitter, text2 = setup()
1240 text = text2.replaceWholeText("new content")
1241 self.checkWholeText(text, "new content")
1242 self.checkWholeText(text1, "cab")
1243 self.confirm(len(elem.childNodes) == 5)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001244
Collin Winterd28fcbc2007-03-28 23:34:06 +00001245 doc, elem, text1, splitter, text2 = setup()
1246 text = text1.replaceWholeText("")
1247 self.checkWholeText(text2, "d")
1248 self.confirm(text is None
1249 and len(elem.childNodes) == 2)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001250
Collin Winterd28fcbc2007-03-28 23:34:06 +00001251 def testSchemaType(self):
1252 doc = parseString(
1253 "<!DOCTYPE doc [\n"
1254 " <!ENTITY e1 SYSTEM 'http://xml.python.org/e1'>\n"
1255 " <!ENTITY e2 SYSTEM 'http://xml.python.org/e2'>\n"
1256 " <!ATTLIST doc id ID #IMPLIED \n"
1257 " ref IDREF #IMPLIED \n"
1258 " refs IDREFS #IMPLIED \n"
1259 " enum (a|b) #IMPLIED \n"
1260 " ent ENTITY #IMPLIED \n"
1261 " ents ENTITIES #IMPLIED \n"
1262 " nm NMTOKEN #IMPLIED \n"
1263 " nms NMTOKENS #IMPLIED \n"
1264 " text CDATA #IMPLIED \n"
1265 " >\n"
1266 "]><doc id='name' notid='name' text='splat!' enum='b'"
1267 " ref='name' refs='name name' ent='e1' ents='e1 e2'"
1268 " nm='123' nms='123 abc' />")
1269 elem = doc.documentElement
1270 # We don't want to rely on any specific loader at this point, so
1271 # just make sure we can get to all the names, and that the
1272 # DTD-based namespace is right. The names can vary by loader
1273 # since each supports a different level of DTD information.
1274 t = elem.schemaType
1275 self.confirm(t.name is None
1276 and t.namespace == xml.dom.EMPTY_NAMESPACE)
1277 names = "id notid text enum ref refs ent ents nm nms".split()
1278 for name in names:
1279 a = elem.getAttributeNode(name)
1280 t = a.schemaType
1281 self.confirm(hasattr(t, "name")
1282 and t.namespace == xml.dom.EMPTY_NAMESPACE)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001283
Collin Winterd28fcbc2007-03-28 23:34:06 +00001284 def testSetIdAttribute(self):
1285 doc = parseString("<doc a1='v' a2='w'/>")
1286 e = doc.documentElement
1287 a1 = e.getAttributeNode("a1")
1288 a2 = e.getAttributeNode("a2")
1289 self.confirm(doc.getElementById("v") is None
1290 and not a1.isId
1291 and not a2.isId)
1292 e.setIdAttribute("a1")
1293 self.confirm(e.isSameNode(doc.getElementById("v"))
1294 and a1.isId
1295 and not a2.isId)
1296 e.setIdAttribute("a2")
1297 self.confirm(e.isSameNode(doc.getElementById("v"))
1298 and e.isSameNode(doc.getElementById("w"))
1299 and a1.isId
1300 and a2.isId)
1301 # replace the a1 node; the new node should *not* be an ID
1302 a3 = doc.createAttribute("a1")
1303 a3.value = "v"
1304 e.setAttributeNode(a3)
1305 self.confirm(doc.getElementById("v") is None
1306 and e.isSameNode(doc.getElementById("w"))
1307 and not a1.isId
1308 and a2.isId
1309 and not a3.isId)
1310 # renaming an attribute should not affect its ID-ness:
1311 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1312 self.confirm(e.isSameNode(doc.getElementById("w"))
1313 and a2.isId)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001314
Collin Winterd28fcbc2007-03-28 23:34:06 +00001315 def testSetIdAttributeNS(self):
1316 NS1 = "http://xml.python.org/ns1"
1317 NS2 = "http://xml.python.org/ns2"
1318 doc = parseString("<doc"
1319 " xmlns:ns1='" + NS1 + "'"
1320 " xmlns:ns2='" + NS2 + "'"
1321 " ns1:a1='v' ns2:a2='w'/>")
1322 e = doc.documentElement
1323 a1 = e.getAttributeNodeNS(NS1, "a1")
1324 a2 = e.getAttributeNodeNS(NS2, "a2")
1325 self.confirm(doc.getElementById("v") is None
1326 and not a1.isId
1327 and not a2.isId)
1328 e.setIdAttributeNS(NS1, "a1")
1329 self.confirm(e.isSameNode(doc.getElementById("v"))
1330 and a1.isId
1331 and not a2.isId)
1332 e.setIdAttributeNS(NS2, "a2")
1333 self.confirm(e.isSameNode(doc.getElementById("v"))
1334 and e.isSameNode(doc.getElementById("w"))
1335 and a1.isId
1336 and a2.isId)
1337 # replace the a1 node; the new node should *not* be an ID
1338 a3 = doc.createAttributeNS(NS1, "a1")
1339 a3.value = "v"
1340 e.setAttributeNode(a3)
1341 self.confirm(e.isSameNode(doc.getElementById("w")))
1342 self.confirm(not a1.isId)
1343 self.confirm(a2.isId)
1344 self.confirm(not a3.isId)
1345 self.confirm(doc.getElementById("v") is None)
1346 # renaming an attribute should not affect its ID-ness:
1347 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1348 self.confirm(e.isSameNode(doc.getElementById("w"))
1349 and a2.isId)
1350
1351 def testSetIdAttributeNode(self):
1352 NS1 = "http://xml.python.org/ns1"
1353 NS2 = "http://xml.python.org/ns2"
1354 doc = parseString("<doc"
1355 " xmlns:ns1='" + NS1 + "'"
1356 " xmlns:ns2='" + NS2 + "'"
1357 " ns1:a1='v' ns2:a2='w'/>")
1358 e = doc.documentElement
1359 a1 = e.getAttributeNodeNS(NS1, "a1")
1360 a2 = e.getAttributeNodeNS(NS2, "a2")
1361 self.confirm(doc.getElementById("v") is None
1362 and not a1.isId
1363 and not a2.isId)
1364 e.setIdAttributeNode(a1)
1365 self.confirm(e.isSameNode(doc.getElementById("v"))
1366 and a1.isId
1367 and not a2.isId)
1368 e.setIdAttributeNode(a2)
1369 self.confirm(e.isSameNode(doc.getElementById("v"))
1370 and e.isSameNode(doc.getElementById("w"))
1371 and a1.isId
1372 and a2.isId)
1373 # replace the a1 node; the new node should *not* be an ID
1374 a3 = doc.createAttributeNS(NS1, "a1")
1375 a3.value = "v"
1376 e.setAttributeNode(a3)
1377 self.confirm(e.isSameNode(doc.getElementById("w")))
1378 self.confirm(not a1.isId)
1379 self.confirm(a2.isId)
1380 self.confirm(not a3.isId)
1381 self.confirm(doc.getElementById("v") is None)
1382 # renaming an attribute should not affect its ID-ness:
1383 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1384 self.confirm(e.isSameNode(doc.getElementById("w"))
1385 and a2.isId)
1386
Serhiy Storchaka9baa5682015-11-26 23:48:30 +02001387 def assert_recursive_equal(self, doc, doc2):
1388 stack = [(doc, doc2)]
1389 while stack:
1390 n1, n2 = stack.pop()
1391 self.assertEqual(n1.nodeType, n2.nodeType)
1392 self.assertEqual(len(n1.childNodes), len(n2.childNodes))
1393 self.assertEqual(n1.nodeName, n2.nodeName)
1394 self.assertFalse(n1.isSameNode(n2))
1395 self.assertFalse(n2.isSameNode(n1))
1396 if n1.nodeType == Node.DOCUMENT_TYPE_NODE:
1397 len(n1.entities)
1398 len(n2.entities)
1399 len(n1.notations)
1400 len(n2.notations)
1401 self.assertEqual(len(n1.entities), len(n2.entities))
1402 self.assertEqual(len(n1.notations), len(n2.notations))
1403 for i in range(len(n1.notations)):
1404 # XXX this loop body doesn't seem to be executed?
1405 no1 = n1.notations.item(i)
1406 no2 = n1.notations.item(i)
1407 self.assertEqual(no1.name, no2.name)
1408 self.assertEqual(no1.publicId, no2.publicId)
1409 self.assertEqual(no1.systemId, no2.systemId)
1410 stack.append((no1, no2))
1411 for i in range(len(n1.entities)):
1412 e1 = n1.entities.item(i)
1413 e2 = n2.entities.item(i)
1414 self.assertEqual(e1.notationName, e2.notationName)
1415 self.assertEqual(e1.publicId, e2.publicId)
1416 self.assertEqual(e1.systemId, e2.systemId)
1417 stack.append((e1, e2))
1418 if n1.nodeType != Node.DOCUMENT_NODE:
1419 self.assertTrue(n1.ownerDocument.isSameNode(doc))
1420 self.assertTrue(n2.ownerDocument.isSameNode(doc2))
1421 for i in range(len(n1.childNodes)):
1422 stack.append((n1.childNodes[i], n2.childNodes[i]))
1423
Collin Winterd28fcbc2007-03-28 23:34:06 +00001424 def testPickledDocument(self):
Serhiy Storchaka9baa5682015-11-26 23:48:30 +02001425 doc = parseString(sample)
1426 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
Serhiy Storchaka655720e2014-12-15 14:02:43 +02001427 s = pickle.dumps(doc, proto)
1428 doc2 = pickle.loads(s)
Serhiy Storchaka9baa5682015-11-26 23:48:30 +02001429 self.assert_recursive_equal(doc, doc2)
1430
1431 def testDeepcopiedDocument(self):
1432 doc = parseString(sample)
1433 doc2 = copy.deepcopy(doc)
1434 self.assert_recursive_equal(doc, doc2)
Collin Winterd28fcbc2007-03-28 23:34:06 +00001435
Martin v. Löwis27e4a172008-05-23 15:18:28 +00001436 def testSerializeCommentNodeWithDoubleHyphen(self):
1437 doc = create_doc_without_doctype()
1438 doc.appendChild(doc.createComment("foo--bar"))
1439 self.assertRaises(ValueError, doc.toxml)
1440
Georg Brandl5ded7912010-11-26 07:35:31 +00001441 def testEmptyXMLNSValue(self):
1442 doc = parseString("<element xmlns=''>\n"
1443 "<foo/>\n</element>")
1444 doc2 = parseString(doc.toxml())
1445 self.confirm(doc2.namespaceURI == xml.dom.EMPTY_NAMESPACE)
1446
1447
Collin Winterd28fcbc2007-03-28 23:34:06 +00001448def test_main():
1449 run_unittest(MinidomTest)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001450
Collin Winterd28fcbc2007-03-28 23:34:06 +00001451if __name__ == "__main__":
1452 test_main()