blob: 7b7524a1225ca463db6ee95de43ca78f43d0a463 [file] [log] [blame]
Fred Drakefbdeaad2006-07-29 16:56:15 +00001# test for xml.dom.minidom
Paul Prescod7993bcc2000-07-01 14:54:16 +00002
Martin v. Löwisfd6aaa12003-01-25 22:02:52 +00003import pickle
Martin v. Löwisfd6aaa12003-01-25 22:02:52 +00004from StringIO import StringIO
Florent Xicluna1b51c3d2010-03-13 12:41:48 +00005from test.test_support import verbose, run_unittest, findfile
Collin Winterd28fcbc2007-03-28 23:34:06 +00006import unittest
Fred Drake17647f52000-07-03 16:37:42 +00007
Fred Drakefbdeaad2006-07-29 16:56:15 +00008import xml.dom
9import xml.dom.minidom
10import xml.parsers.expat
Fred Drakec441f7b2002-07-19 22:16:41 +000011
Fred Drakefbdeaad2006-07-29 16:56:15 +000012from xml.dom.minidom import parse, Node, Document, parseString
13from xml.dom.minidom import getDOMImplementation
Martin v. Löwisfd6aaa12003-01-25 22:02:52 +000014
Fred Drakec441f7b2002-07-19 22:16:41 +000015
Florent Xicluna1b51c3d2010-03-13 12:41:48 +000016tstfile = findfile("test.xml", subdir="xmltestdata")
17
Paul Prescod7993bcc2000-07-01 14:54:16 +000018
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000019# The tests of DocumentType importing use these helpers to construct
20# the documents to work with, since not all DOM builders actually
21# create the DocumentType nodes.
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000022def create_doc_without_doctype(doctype=None):
23 return getDOMImplementation().createDocument(None, "doc", doctype)
24
25def create_nonempty_doctype():
26 doctype = getDOMImplementation().createDocumentType("doc", None, None)
27 doctype.entities._seq = []
28 doctype.notations._seq = []
Fred Drakefbdeaad2006-07-29 16:56:15 +000029 notation = xml.dom.minidom.Notation("my-notation", None,
30 "http://xml.python.org/notations/my")
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000031 doctype.notations._seq.append(notation)
Fred Drakefbdeaad2006-07-29 16:56:15 +000032 entity = xml.dom.minidom.Entity("my-entity", None,
33 "http://xml.python.org/entities/my",
34 "my-notation")
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000035 entity.version = "1.0"
36 entity.encoding = "utf-8"
37 entity.actualEncoding = "us-ascii"
38 doctype.entities._seq.append(entity)
39 return doctype
40
41def create_doc_with_doctype():
42 doctype = create_nonempty_doctype()
43 doc = create_doc_without_doctype(doctype)
44 doctype.entities.item(0).ownerDocument = doc
45 doctype.notations.item(0).ownerDocument = doc
46 return doc
47
Collin Winterd28fcbc2007-03-28 23:34:06 +000048class MinidomTest(unittest.TestCase):
Collin Winterd28fcbc2007-03-28 23:34:06 +000049 def confirm(self, test, testname = "Test"):
50 self.assertTrue(test, testname)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000051
Collin Winterd28fcbc2007-03-28 23:34:06 +000052 def checkWholeText(self, node, s):
53 t = node.wholeText
54 self.confirm(t == s, "looking for %s, found %s" % (repr(s), repr(t)))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000055
Collin Winterd28fcbc2007-03-28 23:34:06 +000056 def testParseFromFile(self):
57 dom = parse(StringIO(open(tstfile).read()))
58 dom.unlink()
59 self.confirm(isinstance(dom,Document))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000060
Collin Winterd28fcbc2007-03-28 23:34:06 +000061 def testGetElementsByTagName(self):
62 dom = parse(tstfile)
63 self.confirm(dom.getElementsByTagName("LI") == \
64 dom.documentElement.getElementsByTagName("LI"))
65 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000066
Collin Winterd28fcbc2007-03-28 23:34:06 +000067 def testInsertBefore(self):
68 dom = parseString("<doc><foo/></doc>")
69 root = dom.documentElement
70 elem = root.childNodes[0]
71 nelem = dom.createElement("element")
72 root.insertBefore(nelem, elem)
73 self.confirm(len(root.childNodes) == 2
74 and root.childNodes.length == 2
75 and root.childNodes[0] is nelem
76 and root.childNodes.item(0) is nelem
77 and root.childNodes[1] is elem
78 and root.childNodes.item(1) is elem
79 and root.firstChild is nelem
80 and root.lastChild is elem
81 and root.toxml() == "<doc><element/><foo/></doc>"
82 , "testInsertBefore -- node properly placed in tree")
83 nelem = dom.createElement("element")
84 root.insertBefore(nelem, None)
85 self.confirm(len(root.childNodes) == 3
86 and root.childNodes.length == 3
87 and root.childNodes[1] is elem
88 and root.childNodes.item(1) is elem
89 and root.childNodes[2] is nelem
90 and root.childNodes.item(2) is nelem
91 and root.lastChild is nelem
92 and nelem.previousSibling is elem
93 and root.toxml() == "<doc><element/><foo/><element/></doc>"
94 , "testInsertBefore -- node properly placed in tree")
95 nelem2 = dom.createElement("bar")
96 root.insertBefore(nelem2, nelem)
97 self.confirm(len(root.childNodes) == 4
98 and root.childNodes.length == 4
99 and root.childNodes[2] is nelem2
100 and root.childNodes.item(2) is nelem2
101 and root.childNodes[3] is nelem
102 and root.childNodes.item(3) is nelem
103 and nelem2.nextSibling is nelem
104 and nelem.previousSibling is nelem2
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000105 and root.toxml() ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000106 "<doc><element/><foo/><bar/><element/></doc>"
107 , "testInsertBefore -- node properly placed in tree")
108 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000109
Collin Winterd28fcbc2007-03-28 23:34:06 +0000110 def _create_fragment_test_nodes(self):
111 dom = parseString("<doc/>")
112 orig = dom.createTextNode("original")
113 c1 = dom.createTextNode("foo")
114 c2 = dom.createTextNode("bar")
115 c3 = dom.createTextNode("bat")
116 dom.documentElement.appendChild(orig)
117 frag = dom.createDocumentFragment()
118 frag.appendChild(c1)
119 frag.appendChild(c2)
120 frag.appendChild(c3)
121 return dom, orig, c1, c2, c3, frag
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000122
Collin Winterd28fcbc2007-03-28 23:34:06 +0000123 def testInsertBeforeFragment(self):
124 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
125 dom.documentElement.insertBefore(frag, None)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000126 self.confirm(tuple(dom.documentElement.childNodes) ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000127 (orig, c1, c2, c3),
128 "insertBefore(<fragment>, None)")
129 frag.unlink()
130 dom.unlink()
Paul Prescod10d27662000-09-18 19:07:26 +0000131
Collin Winterd28fcbc2007-03-28 23:34:06 +0000132 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
133 dom.documentElement.insertBefore(frag, orig)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000134 self.confirm(tuple(dom.documentElement.childNodes) ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000135 (c1, c2, c3, orig),
136 "insertBefore(<fragment>, orig)")
137 frag.unlink()
138 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000139
Collin Winterd28fcbc2007-03-28 23:34:06 +0000140 def testAppendChild(self):
141 dom = parse(tstfile)
142 dom.documentElement.appendChild(dom.createComment(u"Hello"))
143 self.confirm(dom.documentElement.childNodes[-1].nodeName == "#comment")
144 self.confirm(dom.documentElement.childNodes[-1].data == "Hello")
145 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000146
Collin Winterd28fcbc2007-03-28 23:34:06 +0000147 def testAppendChildFragment(self):
148 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
149 dom.documentElement.appendChild(frag)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000150 self.confirm(tuple(dom.documentElement.childNodes) ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000151 (orig, c1, c2, c3),
152 "appendChild(<fragment>)")
153 frag.unlink()
154 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000155
Collin Winterd28fcbc2007-03-28 23:34:06 +0000156 def testReplaceChildFragment(self):
157 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
158 dom.documentElement.replaceChild(frag, orig)
159 orig.unlink()
160 self.confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3),
161 "replaceChild(<fragment>)")
162 frag.unlink()
163 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000164
Collin Winterd28fcbc2007-03-28 23:34:06 +0000165 def testLegalChildren(self):
166 dom = Document()
167 elem = dom.createElement('element')
168 text = dom.createTextNode('text')
169 self.assertRaises(xml.dom.HierarchyRequestErr, dom.appendChild, text)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000170
Collin Winterd28fcbc2007-03-28 23:34:06 +0000171 dom.appendChild(elem)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000172 self.assertRaises(xml.dom.HierarchyRequestErr, dom.insertBefore, text,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000173 elem)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000174 self.assertRaises(xml.dom.HierarchyRequestErr, dom.replaceChild, text,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000175 elem)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000176
Collin Winterd28fcbc2007-03-28 23:34:06 +0000177 nodemap = elem.attributes
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000178 self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItem,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000179 text)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000180 self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItemNS,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000181 text)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000182
Collin Winterd28fcbc2007-03-28 23:34:06 +0000183 elem.appendChild(text)
184 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000185
Collin Winterd28fcbc2007-03-28 23:34:06 +0000186 def testNamedNodeMapSetItem(self):
187 dom = Document()
188 elem = dom.createElement('element')
189 attrs = elem.attributes
190 attrs["foo"] = "bar"
191 a = attrs.item(0)
192 self.confirm(a.ownerDocument is dom,
193 "NamedNodeMap.__setitem__() sets ownerDocument")
194 self.confirm(a.ownerElement is elem,
195 "NamedNodeMap.__setitem__() sets ownerElement")
196 self.confirm(a.value == "bar",
197 "NamedNodeMap.__setitem__() sets value")
198 self.confirm(a.nodeValue == "bar",
199 "NamedNodeMap.__setitem__() sets nodeValue")
200 elem.unlink()
201 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000202
Collin Winterd28fcbc2007-03-28 23:34:06 +0000203 def testNonZero(self):
204 dom = parse(tstfile)
205 self.confirm(dom)# should not be zero
206 dom.appendChild(dom.createComment("foo"))
207 self.confirm(not dom.childNodes[-1].childNodes)
208 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000209
Collin Winterd28fcbc2007-03-28 23:34:06 +0000210 def testUnlink(self):
211 dom = parse(tstfile)
212 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000213
Collin Winterd28fcbc2007-03-28 23:34:06 +0000214 def testElement(self):
215 dom = Document()
216 dom.appendChild(dom.createElement("abc"))
217 self.confirm(dom.documentElement)
218 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000219
Collin Winterd28fcbc2007-03-28 23:34:06 +0000220 def testAAA(self):
221 dom = parseString("<abc/>")
222 el = dom.documentElement
223 el.setAttribute("spam", "jam2")
224 self.confirm(el.toxml() == '<abc spam="jam2"/>', "testAAA")
225 a = el.getAttributeNode("spam")
226 self.confirm(a.ownerDocument is dom,
227 "setAttribute() sets ownerDocument")
228 self.confirm(a.ownerElement is dom.documentElement,
229 "setAttribute() sets ownerElement")
230 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000231
Collin Winterd28fcbc2007-03-28 23:34:06 +0000232 def testAAB(self):
233 dom = parseString("<abc/>")
234 el = dom.documentElement
235 el.setAttribute("spam", "jam")
236 el.setAttribute("spam", "jam2")
237 self.confirm(el.toxml() == '<abc spam="jam2"/>', "testAAB")
238 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000239
Collin Winterd28fcbc2007-03-28 23:34:06 +0000240 def testAddAttr(self):
241 dom = Document()
242 child = dom.appendChild(dom.createElement("abc"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000243
Collin Winterd28fcbc2007-03-28 23:34:06 +0000244 child.setAttribute("def", "ghi")
245 self.confirm(child.getAttribute("def") == "ghi")
246 self.confirm(child.attributes["def"].value == "ghi")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000247
Collin Winterd28fcbc2007-03-28 23:34:06 +0000248 child.setAttribute("jkl", "mno")
249 self.confirm(child.getAttribute("jkl") == "mno")
250 self.confirm(child.attributes["jkl"].value == "mno")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000251
Collin Winterd28fcbc2007-03-28 23:34:06 +0000252 self.confirm(len(child.attributes) == 2)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000253
Collin Winterd28fcbc2007-03-28 23:34:06 +0000254 child.setAttribute("def", "newval")
255 self.confirm(child.getAttribute("def") == "newval")
256 self.confirm(child.attributes["def"].value == "newval")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000257
Collin Winterd28fcbc2007-03-28 23:34:06 +0000258 self.confirm(len(child.attributes) == 2)
259 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000260
Collin Winterd28fcbc2007-03-28 23:34:06 +0000261 def testDeleteAttr(self):
262 dom = Document()
263 child = dom.appendChild(dom.createElement("abc"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000264
Collin Winterd28fcbc2007-03-28 23:34:06 +0000265 self.confirm(len(child.attributes) == 0)
266 child.setAttribute("def", "ghi")
267 self.confirm(len(child.attributes) == 1)
268 del child.attributes["def"]
269 self.confirm(len(child.attributes) == 0)
270 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000271
Collin Winterd28fcbc2007-03-28 23:34:06 +0000272 def testRemoveAttr(self):
273 dom = Document()
274 child = dom.appendChild(dom.createElement("abc"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000275
Collin Winterd28fcbc2007-03-28 23:34:06 +0000276 child.setAttribute("def", "ghi")
277 self.confirm(len(child.attributes) == 1)
278 child.removeAttribute("def")
279 self.confirm(len(child.attributes) == 0)
280 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000281
Collin Winterd28fcbc2007-03-28 23:34:06 +0000282 def testRemoveAttrNS(self):
283 dom = Document()
284 child = dom.appendChild(
285 dom.createElementNS("http://www.python.org", "python:abc"))
286 child.setAttributeNS("http://www.w3.org", "xmlns:python",
287 "http://www.python.org")
288 child.setAttributeNS("http://www.python.org", "python:abcattr", "foo")
289 self.confirm(len(child.attributes) == 2)
290 child.removeAttributeNS("http://www.python.org", "abcattr")
291 self.confirm(len(child.attributes) == 1)
292 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000293
Collin Winterd28fcbc2007-03-28 23:34:06 +0000294 def testRemoveAttributeNode(self):
295 dom = Document()
296 child = dom.appendChild(dom.createElement("foo"))
297 child.setAttribute("spam", "jam")
298 self.confirm(len(child.attributes) == 1)
299 node = child.getAttributeNode("spam")
300 child.removeAttributeNode(node)
301 self.confirm(len(child.attributes) == 0
302 and child.getAttributeNode("spam") is None)
303 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000304
Collin Winterd28fcbc2007-03-28 23:34:06 +0000305 def testChangeAttr(self):
306 dom = parseString("<abc/>")
307 el = dom.documentElement
308 el.setAttribute("spam", "jam")
309 self.confirm(len(el.attributes) == 1)
310 el.setAttribute("spam", "bam")
311 # Set this attribute to be an ID and make sure that doesn't change
312 # when changing the value:
313 el.setIdAttribute("spam")
314 self.confirm(len(el.attributes) == 1
315 and el.attributes["spam"].value == "bam"
316 and el.attributes["spam"].nodeValue == "bam"
317 and el.getAttribute("spam") == "bam"
318 and el.getAttributeNode("spam").isId)
319 el.attributes["spam"] = "ham"
320 self.confirm(len(el.attributes) == 1
321 and el.attributes["spam"].value == "ham"
322 and el.attributes["spam"].nodeValue == "ham"
323 and el.getAttribute("spam") == "ham"
324 and el.attributes["spam"].isId)
325 el.setAttribute("spam2", "bam")
326 self.confirm(len(el.attributes) == 2
327 and el.attributes["spam"].value == "ham"
328 and el.attributes["spam"].nodeValue == "ham"
329 and el.getAttribute("spam") == "ham"
330 and el.attributes["spam2"].value == "bam"
331 and el.attributes["spam2"].nodeValue == "bam"
332 and el.getAttribute("spam2") == "bam")
333 el.attributes["spam2"] = "bam2"
334 self.confirm(len(el.attributes) == 2
335 and el.attributes["spam"].value == "ham"
336 and el.attributes["spam"].nodeValue == "ham"
337 and el.getAttribute("spam") == "ham"
338 and el.attributes["spam2"].value == "bam2"
339 and el.attributes["spam2"].nodeValue == "bam2"
340 and el.getAttribute("spam2") == "bam2")
341 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000342
Collin Winterd28fcbc2007-03-28 23:34:06 +0000343 def testGetAttrList(self):
344 pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000345
Collin Winterd28fcbc2007-03-28 23:34:06 +0000346 def testGetAttrValues(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000347
Collin Winterd28fcbc2007-03-28 23:34:06 +0000348 def testGetAttrLength(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000349
Collin Winterd28fcbc2007-03-28 23:34:06 +0000350 def testGetAttribute(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000351
Collin Winterd28fcbc2007-03-28 23:34:06 +0000352 def testGetAttributeNS(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000353
Collin Winterd28fcbc2007-03-28 23:34:06 +0000354 def testGetAttributeNode(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000355
Collin Winterd28fcbc2007-03-28 23:34:06 +0000356 def testGetElementsByTagNameNS(self):
357 d="""<foo xmlns:minidom='http://pyxml.sf.net/minidom'>
358 <minidom:myelem/>
359 </foo>"""
360 dom = parseString(d)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000361 elems = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom",
Collin Winterd28fcbc2007-03-28 23:34:06 +0000362 "myelem")
363 self.confirm(len(elems) == 1
364 and elems[0].namespaceURI == "http://pyxml.sf.net/minidom"
365 and elems[0].localName == "myelem"
366 and elems[0].prefix == "minidom"
367 and elems[0].tagName == "minidom:myelem"
368 and elems[0].nodeName == "minidom:myelem")
369 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000370
371 def get_empty_nodelist_from_elements_by_tagName_ns_helper(self, doc, nsuri,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000372 lname):
373 nodelist = doc.getElementsByTagNameNS(nsuri, lname)
374 self.confirm(len(nodelist) == 0)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000375
Collin Winterd28fcbc2007-03-28 23:34:06 +0000376 def testGetEmptyNodeListFromElementsByTagNameNS(self):
377 doc = parseString('<doc/>')
378 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
379 doc, 'http://xml.python.org/namespaces/a', 'localname')
380 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
381 doc, '*', 'splat')
382 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
383 doc, 'http://xml.python.org/namespaces/a', '*')
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000384
Collin Winterd28fcbc2007-03-28 23:34:06 +0000385 doc = parseString('<doc xmlns="http://xml.python.org/splat"><e/></doc>')
386 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
387 doc, "http://xml.python.org/splat", "not-there")
388 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
389 doc, "*", "not-there")
390 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
391 doc, "http://somewhere.else.net/not-there", "e")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000392
Collin Winterd28fcbc2007-03-28 23:34:06 +0000393 def testElementReprAndStr(self):
394 dom = Document()
395 el = dom.appendChild(dom.createElement("abc"))
396 string1 = repr(el)
397 string2 = str(el)
398 self.confirm(string1 == string2)
399 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000400
Collin Winterd28fcbc2007-03-28 23:34:06 +0000401 def testElementReprAndStrUnicode(self):
402 dom = Document()
403 el = dom.appendChild(dom.createElement(u"abc"))
404 string1 = repr(el)
405 string2 = str(el)
406 self.confirm(string1 == string2)
407 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000408
Collin Winterd28fcbc2007-03-28 23:34:06 +0000409 def testElementReprAndStrUnicodeNS(self):
410 dom = Document()
411 el = dom.appendChild(
412 dom.createElementNS(u"http://www.slashdot.org", u"slash:abc"))
413 string1 = repr(el)
414 string2 = str(el)
415 self.confirm(string1 == string2)
Ezio Melotti187f93d2010-03-17 14:22:34 +0000416 self.confirm("slash:abc" in string1)
Collin Winterd28fcbc2007-03-28 23:34:06 +0000417 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000418
Collin Winterd28fcbc2007-03-28 23:34:06 +0000419 def testAttributeRepr(self):
420 dom = Document()
421 el = dom.appendChild(dom.createElement(u"abc"))
422 node = el.setAttribute("abc", "def")
423 self.confirm(str(node) == repr(node))
424 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000425
Collin Winterd28fcbc2007-03-28 23:34:06 +0000426 def testTextNodeRepr(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000427
Collin Winterd28fcbc2007-03-28 23:34:06 +0000428 def testWriteXML(self):
429 str = '<?xml version="1.0" ?><a b="c"/>'
430 dom = parseString(str)
431 domstr = dom.toxml()
432 dom.unlink()
433 self.confirm(str == domstr)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000434
Collin Winterd28fcbc2007-03-28 23:34:06 +0000435 def testAltNewline(self):
436 str = '<?xml version="1.0" ?>\n<a b="c"/>\n'
437 dom = parseString(str)
438 domstr = dom.toprettyxml(newl="\r\n")
439 dom.unlink()
440 self.confirm(domstr == str.replace("\n", "\r\n"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000441
Collin Winterd28fcbc2007-03-28 23:34:06 +0000442 def testProcessingInstruction(self):
443 dom = parseString('<e><?mypi \t\n data \t\n ?></e>')
444 pi = dom.documentElement.firstChild
445 self.confirm(pi.target == "mypi"
446 and pi.data == "data \t\n "
447 and pi.nodeName == "mypi"
448 and pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE
449 and pi.attributes is None
450 and not pi.hasChildNodes()
451 and len(pi.childNodes) == 0
452 and pi.firstChild is None
453 and pi.lastChild is None
454 and pi.localName is None
455 and pi.namespaceURI == xml.dom.EMPTY_NAMESPACE)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000456
Collin Winterd28fcbc2007-03-28 23:34:06 +0000457 def testProcessingInstructionRepr(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000458
Collin Winterd28fcbc2007-03-28 23:34:06 +0000459 def testTextRepr(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000460
Collin Winterd28fcbc2007-03-28 23:34:06 +0000461 def testWriteText(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000462
Collin Winterd28fcbc2007-03-28 23:34:06 +0000463 def testDocumentElement(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000464
Collin Winterd28fcbc2007-03-28 23:34:06 +0000465 def testTooManyDocumentElements(self):
466 doc = parseString("<doc/>")
467 elem = doc.createElement("extra")
468 # Should raise an exception when adding an extra document element.
469 self.assertRaises(xml.dom.HierarchyRequestErr, doc.appendChild, elem)
470 elem.unlink()
471 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000472
Collin Winterd28fcbc2007-03-28 23:34:06 +0000473 def testCreateElementNS(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000474
Collin Winterd28fcbc2007-03-28 23:34:06 +0000475 def testCreateAttributeNS(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000476
Collin Winterd28fcbc2007-03-28 23:34:06 +0000477 def testParse(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000478
Collin Winterd28fcbc2007-03-28 23:34:06 +0000479 def testParseString(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000480
Collin Winterd28fcbc2007-03-28 23:34:06 +0000481 def testComment(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000482
Collin Winterd28fcbc2007-03-28 23:34:06 +0000483 def testAttrListItem(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000484
Collin Winterd28fcbc2007-03-28 23:34:06 +0000485 def testAttrListItems(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000486
Collin Winterd28fcbc2007-03-28 23:34:06 +0000487 def testAttrListItemNS(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000488
Collin Winterd28fcbc2007-03-28 23:34:06 +0000489 def testAttrListKeys(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000490
Collin Winterd28fcbc2007-03-28 23:34:06 +0000491 def testAttrListKeysNS(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000492
Collin Winterd28fcbc2007-03-28 23:34:06 +0000493 def testRemoveNamedItem(self):
494 doc = parseString("<doc a=''/>")
495 e = doc.documentElement
496 attrs = e.attributes
497 a1 = e.getAttributeNode("a")
498 a2 = attrs.removeNamedItem("a")
499 self.confirm(a1.isSameNode(a2))
500 self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItem, "a")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000501
Collin Winterd28fcbc2007-03-28 23:34:06 +0000502 def testRemoveNamedItemNS(self):
503 doc = parseString("<doc xmlns:a='http://xml.python.org/' a:b=''/>")
504 e = doc.documentElement
505 attrs = e.attributes
506 a1 = e.getAttributeNodeNS("http://xml.python.org/", "b")
507 a2 = attrs.removeNamedItemNS("http://xml.python.org/", "b")
508 self.confirm(a1.isSameNode(a2))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000509 self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItemNS,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000510 "http://xml.python.org/", "b")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000511
Collin Winterd28fcbc2007-03-28 23:34:06 +0000512 def testAttrListValues(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000513
Collin Winterd28fcbc2007-03-28 23:34:06 +0000514 def testAttrListLength(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000515
Collin Winterd28fcbc2007-03-28 23:34:06 +0000516 def testAttrList__getitem__(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000517
Collin Winterd28fcbc2007-03-28 23:34:06 +0000518 def testAttrList__setitem__(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000519
Collin Winterd28fcbc2007-03-28 23:34:06 +0000520 def testSetAttrValueandNodeValue(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000521
Collin Winterd28fcbc2007-03-28 23:34:06 +0000522 def testParseElement(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000523
Collin Winterd28fcbc2007-03-28 23:34:06 +0000524 def testParseAttributes(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000525
Collin Winterd28fcbc2007-03-28 23:34:06 +0000526 def testParseElementNamespaces(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000527
Collin Winterd28fcbc2007-03-28 23:34:06 +0000528 def testParseAttributeNamespaces(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000529
Collin Winterd28fcbc2007-03-28 23:34:06 +0000530 def testParseProcessingInstructions(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000531
Collin Winterd28fcbc2007-03-28 23:34:06 +0000532 def testChildNodes(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000533
Collin Winterd28fcbc2007-03-28 23:34:06 +0000534 def testFirstChild(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000535
Collin Winterd28fcbc2007-03-28 23:34:06 +0000536 def testHasChildNodes(self): pass
537
538 def _testCloneElementCopiesAttributes(self, e1, e2, test):
539 attrs1 = e1.attributes
540 attrs2 = e2.attributes
541 keys1 = attrs1.keys()
542 keys2 = attrs2.keys()
543 keys1.sort()
544 keys2.sort()
545 self.confirm(keys1 == keys2, "clone of element has same attribute keys")
546 for i in range(len(keys1)):
547 a1 = attrs1.item(i)
548 a2 = attrs2.item(i)
549 self.confirm(a1 is not a2
550 and a1.value == a2.value
551 and a1.nodeValue == a2.nodeValue
552 and a1.namespaceURI == a2.namespaceURI
553 and a1.localName == a2.localName
554 , "clone of attribute node has proper attribute values")
555 self.confirm(a2.ownerElement is e2,
556 "clone of attribute node correctly owned")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000557
Collin Winterd28fcbc2007-03-28 23:34:06 +0000558 def _setupCloneElement(self, deep):
559 dom = parseString("<doc attr='value'><foo/></doc>")
560 root = dom.documentElement
561 clone = root.cloneNode(deep)
562 self._testCloneElementCopiesAttributes(
563 root, clone, "testCloneElement" + (deep and "Deep" or "Shallow"))
564 # mutilate the original so shared data is detected
565 root.tagName = root.nodeName = "MODIFIED"
566 root.setAttribute("attr", "NEW VALUE")
567 root.setAttribute("added", "VALUE")
568 return dom, clone
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000569
Collin Winterd28fcbc2007-03-28 23:34:06 +0000570 def testCloneElementShallow(self):
571 dom, clone = self._setupCloneElement(0)
572 self.confirm(len(clone.childNodes) == 0
573 and clone.childNodes.length == 0
574 and clone.parentNode is None
575 and clone.toxml() == '<doc attr="value"/>'
576 , "testCloneElementShallow")
577 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000578
Collin Winterd28fcbc2007-03-28 23:34:06 +0000579 def testCloneElementDeep(self):
580 dom, clone = self._setupCloneElement(1)
581 self.confirm(len(clone.childNodes) == 1
582 and clone.childNodes.length == 1
583 and clone.parentNode is None
584 and clone.toxml() == '<doc attr="value"><foo/></doc>'
585 , "testCloneElementDeep")
586 dom.unlink()
587
588 def testCloneDocumentShallow(self):
589 doc = parseString("<?xml version='1.0'?>\n"
590 "<!-- comment -->"
591 "<!DOCTYPE doc [\n"
592 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
593 "]>\n"
594 "<doc attr='value'/>")
595 doc2 = doc.cloneNode(0)
596 self.confirm(doc2 is None,
597 "testCloneDocumentShallow:"
598 " shallow cloning of documents makes no sense!")
599
600 def testCloneDocumentDeep(self):
601 doc = parseString("<?xml version='1.0'?>\n"
602 "<!-- comment -->"
603 "<!DOCTYPE doc [\n"
604 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
605 "]>\n"
606 "<doc attr='value'/>")
607 doc2 = doc.cloneNode(1)
608 self.confirm(not (doc.isSameNode(doc2) or doc2.isSameNode(doc)),
609 "testCloneDocumentDeep: document objects not distinct")
610 self.confirm(len(doc.childNodes) == len(doc2.childNodes),
611 "testCloneDocumentDeep: wrong number of Document children")
612 self.confirm(doc2.documentElement.nodeType == Node.ELEMENT_NODE,
613 "testCloneDocumentDeep: documentElement not an ELEMENT_NODE")
614 self.confirm(doc2.documentElement.ownerDocument.isSameNode(doc2),
615 "testCloneDocumentDeep: documentElement owner is not new document")
616 self.confirm(not doc.documentElement.isSameNode(doc2.documentElement),
617 "testCloneDocumentDeep: documentElement should not be shared")
618 if doc.doctype is not None:
619 # check the doctype iff the original DOM maintained it
620 self.confirm(doc2.doctype.nodeType == Node.DOCUMENT_TYPE_NODE,
621 "testCloneDocumentDeep: doctype not a DOCUMENT_TYPE_NODE")
622 self.confirm(doc2.doctype.ownerDocument.isSameNode(doc2))
623 self.confirm(not doc.doctype.isSameNode(doc2.doctype))
624
625 def testCloneDocumentTypeDeepOk(self):
626 doctype = create_nonempty_doctype()
627 clone = doctype.cloneNode(1)
628 self.confirm(clone is not None
629 and clone.nodeName == doctype.nodeName
630 and clone.name == doctype.name
631 and clone.publicId == doctype.publicId
632 and clone.systemId == doctype.systemId
633 and len(clone.entities) == len(doctype.entities)
634 and clone.entities.item(len(clone.entities)) is None
635 and len(clone.notations) == len(doctype.notations)
636 and clone.notations.item(len(clone.notations)) is None
637 and len(clone.childNodes) == 0)
638 for i in range(len(doctype.entities)):
639 se = doctype.entities.item(i)
640 ce = clone.entities.item(i)
641 self.confirm((not se.isSameNode(ce))
642 and (not ce.isSameNode(se))
643 and ce.nodeName == se.nodeName
644 and ce.notationName == se.notationName
645 and ce.publicId == se.publicId
646 and ce.systemId == se.systemId
647 and ce.encoding == se.encoding
648 and ce.actualEncoding == se.actualEncoding
649 and ce.version == se.version)
650 for i in range(len(doctype.notations)):
651 sn = doctype.notations.item(i)
652 cn = clone.notations.item(i)
653 self.confirm((not sn.isSameNode(cn))
654 and (not cn.isSameNode(sn))
655 and cn.nodeName == sn.nodeName
656 and cn.publicId == sn.publicId
657 and cn.systemId == sn.systemId)
658
659 def testCloneDocumentTypeDeepNotOk(self):
660 doc = create_doc_with_doctype()
661 clone = doc.doctype.cloneNode(1)
662 self.confirm(clone is None, "testCloneDocumentTypeDeepNotOk")
663
664 def testCloneDocumentTypeShallowOk(self):
665 doctype = create_nonempty_doctype()
666 clone = doctype.cloneNode(0)
667 self.confirm(clone is not None
668 and clone.nodeName == doctype.nodeName
669 and clone.name == doctype.name
670 and clone.publicId == doctype.publicId
671 and clone.systemId == doctype.systemId
672 and len(clone.entities) == 0
673 and clone.entities.item(0) is None
674 and len(clone.notations) == 0
675 and clone.notations.item(0) is None
676 and len(clone.childNodes) == 0)
677
678 def testCloneDocumentTypeShallowNotOk(self):
679 doc = create_doc_with_doctype()
680 clone = doc.doctype.cloneNode(0)
681 self.confirm(clone is None, "testCloneDocumentTypeShallowNotOk")
682
683 def check_import_document(self, deep, testName):
684 doc1 = parseString("<doc/>")
685 doc2 = parseString("<doc/>")
686 self.assertRaises(xml.dom.NotSupportedErr, doc1.importNode, doc2, deep)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000687
Collin Winterd28fcbc2007-03-28 23:34:06 +0000688 def testImportDocumentShallow(self):
689 self.check_import_document(0, "testImportDocumentShallow")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000690
Collin Winterd28fcbc2007-03-28 23:34:06 +0000691 def testImportDocumentDeep(self):
692 self.check_import_document(1, "testImportDocumentDeep")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000693
Collin Winterd28fcbc2007-03-28 23:34:06 +0000694 def testImportDocumentTypeShallow(self):
695 src = create_doc_with_doctype()
696 target = create_doc_without_doctype()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000697 self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000698 src.doctype, 0)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000699
Collin Winterd28fcbc2007-03-28 23:34:06 +0000700 def testImportDocumentTypeDeep(self):
701 src = create_doc_with_doctype()
702 target = create_doc_without_doctype()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000703 self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000704 src.doctype, 1)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000705
Collin Winterd28fcbc2007-03-28 23:34:06 +0000706 # Testing attribute clones uses a helper, and should always be deep,
707 # even if the argument to cloneNode is false.
708 def check_clone_attribute(self, deep, testName):
709 doc = parseString("<doc attr='value'/>")
710 attr = doc.documentElement.getAttributeNode("attr")
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000711 self.assertNotEqual(attr, None)
Collin Winterd28fcbc2007-03-28 23:34:06 +0000712 clone = attr.cloneNode(deep)
713 self.confirm(not clone.isSameNode(attr))
714 self.confirm(not attr.isSameNode(clone))
715 self.confirm(clone.ownerElement is None,
716 testName + ": ownerElement should be None")
717 self.confirm(clone.ownerDocument.isSameNode(attr.ownerDocument),
718 testName + ": ownerDocument does not match")
719 self.confirm(clone.specified,
720 testName + ": cloned attribute must have specified == True")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000721
Collin Winterd28fcbc2007-03-28 23:34:06 +0000722 def testCloneAttributeShallow(self):
723 self.check_clone_attribute(0, "testCloneAttributeShallow")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000724
Collin Winterd28fcbc2007-03-28 23:34:06 +0000725 def testCloneAttributeDeep(self):
726 self.check_clone_attribute(1, "testCloneAttributeDeep")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000727
Collin Winterd28fcbc2007-03-28 23:34:06 +0000728 def check_clone_pi(self, deep, testName):
729 doc = parseString("<?target data?><doc/>")
730 pi = doc.firstChild
Ezio Melotti2623a372010-11-21 13:34:58 +0000731 self.assertEqual(pi.nodeType, Node.PROCESSING_INSTRUCTION_NODE)
Collin Winterd28fcbc2007-03-28 23:34:06 +0000732 clone = pi.cloneNode(deep)
733 self.confirm(clone.target == pi.target
734 and clone.data == pi.data)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000735
Collin Winterd28fcbc2007-03-28 23:34:06 +0000736 def testClonePIShallow(self):
737 self.check_clone_pi(0, "testClonePIShallow")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000738
Collin Winterd28fcbc2007-03-28 23:34:06 +0000739 def testClonePIDeep(self):
740 self.check_clone_pi(1, "testClonePIDeep")
741
742 def testNormalize(self):
743 doc = parseString("<doc/>")
744 root = doc.documentElement
745 root.appendChild(doc.createTextNode("first"))
746 root.appendChild(doc.createTextNode("second"))
747 self.confirm(len(root.childNodes) == 2
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000748 and root.childNodes.length == 2,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000749 "testNormalize -- preparation")
750 doc.normalize()
751 self.confirm(len(root.childNodes) == 1
752 and root.childNodes.length == 1
753 and root.firstChild is root.lastChild
754 and root.firstChild.data == "firstsecond"
755 , "testNormalize -- result")
756 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000757
Collin Winterd28fcbc2007-03-28 23:34:06 +0000758 doc = parseString("<doc/>")
759 root = doc.documentElement
760 root.appendChild(doc.createTextNode(""))
761 doc.normalize()
762 self.confirm(len(root.childNodes) == 0
763 and root.childNodes.length == 0,
764 "testNormalize -- single empty node removed")
765 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000766
R. David Murray0374a822009-04-09 21:54:50 +0000767 def testNormalizeCombineAndNextSibling(self):
768 doc = parseString("<doc/>")
769 root = doc.documentElement
770 root.appendChild(doc.createTextNode("first"))
771 root.appendChild(doc.createTextNode("second"))
772 root.appendChild(doc.createElement("i"))
773 self.confirm(len(root.childNodes) == 3
774 and root.childNodes.length == 3,
775 "testNormalizeCombineAndNextSibling -- preparation")
776 doc.normalize()
777 self.confirm(len(root.childNodes) == 2
778 and root.childNodes.length == 2
779 and root.firstChild.data == "firstsecond"
780 and root.firstChild is not root.lastChild
781 and root.firstChild.nextSibling is root.lastChild
782 and root.firstChild.previousSibling is None
783 and root.lastChild.previousSibling is root.firstChild
784 and root.lastChild.nextSibling is None
785 , "testNormalizeCombinedAndNextSibling -- result")
786 doc.unlink()
787
788 def testNormalizeDeleteWithPrevSibling(self):
789 doc = parseString("<doc/>")
790 root = doc.documentElement
791 root.appendChild(doc.createTextNode("first"))
792 root.appendChild(doc.createTextNode(""))
793 self.confirm(len(root.childNodes) == 2
794 and root.childNodes.length == 2,
795 "testNormalizeDeleteWithPrevSibling -- preparation")
796 doc.normalize()
797 self.confirm(len(root.childNodes) == 1
798 and root.childNodes.length == 1
799 and root.firstChild.data == "first"
800 and root.firstChild is root.lastChild
801 and root.firstChild.nextSibling is None
802 and root.firstChild.previousSibling is None
803 , "testNormalizeDeleteWithPrevSibling -- result")
804 doc.unlink()
805
806 def testNormalizeDeleteWithNextSibling(self):
807 doc = parseString("<doc/>")
808 root = doc.documentElement
809 root.appendChild(doc.createTextNode(""))
810 root.appendChild(doc.createTextNode("second"))
811 self.confirm(len(root.childNodes) == 2
812 and root.childNodes.length == 2,
813 "testNormalizeDeleteWithNextSibling -- preparation")
814 doc.normalize()
815 self.confirm(len(root.childNodes) == 1
816 and root.childNodes.length == 1
817 and root.firstChild.data == "second"
818 and root.firstChild is root.lastChild
819 and root.firstChild.nextSibling is None
820 and root.firstChild.previousSibling is None
821 , "testNormalizeDeleteWithNextSibling -- result")
822 doc.unlink()
823
824 def testNormalizeDeleteWithTwoNonTextSiblings(self):
825 doc = parseString("<doc/>")
826 root = doc.documentElement
827 root.appendChild(doc.createElement("i"))
828 root.appendChild(doc.createTextNode(""))
829 root.appendChild(doc.createElement("i"))
830 self.confirm(len(root.childNodes) == 3
831 and root.childNodes.length == 3,
832 "testNormalizeDeleteWithTwoSiblings -- preparation")
833 doc.normalize()
834 self.confirm(len(root.childNodes) == 2
835 and root.childNodes.length == 2
836 and root.firstChild is not root.lastChild
837 and root.firstChild.nextSibling is root.lastChild
838 and root.firstChild.previousSibling is None
839 and root.lastChild.previousSibling is root.firstChild
840 and root.lastChild.nextSibling is None
841 , "testNormalizeDeleteWithTwoSiblings -- result")
842 doc.unlink()
843
844 def testNormalizeDeleteAndCombine(self):
845 doc = parseString("<doc/>")
846 root = doc.documentElement
847 root.appendChild(doc.createTextNode(""))
848 root.appendChild(doc.createTextNode("second"))
849 root.appendChild(doc.createTextNode(""))
850 root.appendChild(doc.createTextNode("fourth"))
851 root.appendChild(doc.createTextNode(""))
852 self.confirm(len(root.childNodes) == 5
853 and root.childNodes.length == 5,
854 "testNormalizeDeleteAndCombine -- preparation")
855 doc.normalize()
856 self.confirm(len(root.childNodes) == 1
857 and root.childNodes.length == 1
858 and root.firstChild is root.lastChild
859 and root.firstChild.data == "secondfourth"
860 and root.firstChild.previousSibling is None
861 and root.firstChild.nextSibling is None
862 , "testNormalizeDeleteAndCombine -- result")
863 doc.unlink()
864
865 def testNormalizeRecursion(self):
866 doc = parseString("<doc>"
867 "<o>"
868 "<i/>"
869 "t"
870 #
871 #x
872 "</o>"
873 "<o>"
874 "<o>"
875 "t2"
876 #x2
877 "</o>"
878 "t3"
879 #x3
880 "</o>"
881 #
882 "</doc>")
883 root = doc.documentElement
884 root.childNodes[0].appendChild(doc.createTextNode(""))
885 root.childNodes[0].appendChild(doc.createTextNode("x"))
886 root.childNodes[1].childNodes[0].appendChild(doc.createTextNode("x2"))
887 root.childNodes[1].appendChild(doc.createTextNode("x3"))
888 root.appendChild(doc.createTextNode(""))
889 self.confirm(len(root.childNodes) == 3
890 and root.childNodes.length == 3
891 and len(root.childNodes[0].childNodes) == 4
892 and root.childNodes[0].childNodes.length == 4
893 and len(root.childNodes[1].childNodes) == 3
894 and root.childNodes[1].childNodes.length == 3
895 and len(root.childNodes[1].childNodes[0].childNodes) == 2
896 and root.childNodes[1].childNodes[0].childNodes.length == 2
897 , "testNormalize2 -- preparation")
898 doc.normalize()
899 self.confirm(len(root.childNodes) == 2
900 and root.childNodes.length == 2
901 and len(root.childNodes[0].childNodes) == 2
902 and root.childNodes[0].childNodes.length == 2
903 and len(root.childNodes[1].childNodes) == 2
904 and root.childNodes[1].childNodes.length == 2
905 and len(root.childNodes[1].childNodes[0].childNodes) == 1
906 and root.childNodes[1].childNodes[0].childNodes.length == 1
907 , "testNormalize2 -- childNodes lengths")
908 self.confirm(root.childNodes[0].childNodes[1].data == "tx"
909 and root.childNodes[1].childNodes[0].childNodes[0].data == "t2x2"
910 and root.childNodes[1].childNodes[1].data == "t3x3"
911 , "testNormalize2 -- joined text fields")
912 self.confirm(root.childNodes[0].childNodes[1].nextSibling is None
913 and root.childNodes[0].childNodes[1].previousSibling
914 is root.childNodes[0].childNodes[0]
915 and root.childNodes[0].childNodes[0].previousSibling is None
916 and root.childNodes[0].childNodes[0].nextSibling
917 is root.childNodes[0].childNodes[1]
918 and root.childNodes[1].childNodes[1].nextSibling is None
919 and root.childNodes[1].childNodes[1].previousSibling
920 is root.childNodes[1].childNodes[0]
921 and root.childNodes[1].childNodes[0].previousSibling is None
922 and root.childNodes[1].childNodes[0].nextSibling
923 is root.childNodes[1].childNodes[1]
924 , "testNormalize2 -- sibling pointers")
925 doc.unlink()
926
927
Andrew M. Kuchling53f94d02010-07-25 23:49:57 +0000928 def testBug0777884(self):
929 doc = parseString("<o>text</o>")
930 text = doc.documentElement.childNodes[0]
Ezio Melotti2623a372010-11-21 13:34:58 +0000931 self.assertEqual(text.nodeType, Node.TEXT_NODE)
Andrew M. Kuchling53f94d02010-07-25 23:49:57 +0000932 # Should run quietly, doing nothing.
933 text.normalize()
934 doc.unlink()
935
Andrew M. Kuchling19aff0c2008-02-23 17:10:46 +0000936 def testBug1433694(self):
937 doc = parseString("<o><i/>t</o>")
938 node = doc.documentElement
939 node.childNodes[1].nodeValue = ""
940 node.normalize()
Florent Xiclunabc27c6a2010-03-19 18:34:55 +0000941 self.confirm(node.childNodes[-1].nextSibling is None,
Andrew M. Kuchling19aff0c2008-02-23 17:10:46 +0000942 "Final child's .nextSibling should be None")
943
Collin Winterd28fcbc2007-03-28 23:34:06 +0000944 def testSiblings(self):
945 doc = parseString("<doc><?pi?>text?<elm/></doc>")
946 root = doc.documentElement
947 (pi, text, elm) = root.childNodes
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000948
Collin Winterd28fcbc2007-03-28 23:34:06 +0000949 self.confirm(pi.nextSibling is text and
950 pi.previousSibling is None and
951 text.nextSibling is elm and
952 text.previousSibling is pi and
953 elm.nextSibling is None and
954 elm.previousSibling is text, "testSiblings")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000955
Collin Winterd28fcbc2007-03-28 23:34:06 +0000956 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000957
Collin Winterd28fcbc2007-03-28 23:34:06 +0000958 def testParents(self):
959 doc = parseString(
960 "<doc><elm1><elm2/><elm2><elm3/></elm2></elm1></doc>")
961 root = doc.documentElement
962 elm1 = root.childNodes[0]
963 (elm2a, elm2b) = elm1.childNodes
964 elm3 = elm2b.childNodes[0]
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000965
Collin Winterd28fcbc2007-03-28 23:34:06 +0000966 self.confirm(root.parentNode is doc and
967 elm1.parentNode is root and
968 elm2a.parentNode is elm1 and
969 elm2b.parentNode is elm1 and
970 elm3.parentNode is elm2b, "testParents")
971 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000972
Collin Winterd28fcbc2007-03-28 23:34:06 +0000973 def testNodeListItem(self):
974 doc = parseString("<doc><e/><e/></doc>")
975 children = doc.childNodes
976 docelem = children[0]
977 self.confirm(children[0] is children.item(0)
978 and children.item(1) is None
979 and docelem.childNodes.item(0) is docelem.childNodes[0]
980 and docelem.childNodes.item(1) is docelem.childNodes[1]
981 and docelem.childNodes.item(0).childNodes.item(0) is None,
982 "test NodeList.item()")
983 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000984
Collin Winterd28fcbc2007-03-28 23:34:06 +0000985 def testSAX2DOM(self):
986 from xml.dom import pulldom
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000987
Collin Winterd28fcbc2007-03-28 23:34:06 +0000988 sax2dom = pulldom.SAX2DOM()
989 sax2dom.startDocument()
990 sax2dom.startElement("doc", {})
991 sax2dom.characters("text")
992 sax2dom.startElement("subelm", {})
993 sax2dom.characters("text")
994 sax2dom.endElement("subelm")
995 sax2dom.characters("text")
996 sax2dom.endElement("doc")
997 sax2dom.endDocument()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000998
Collin Winterd28fcbc2007-03-28 23:34:06 +0000999 doc = sax2dom.document
1000 root = doc.documentElement
1001 (text1, elm1, text2) = root.childNodes
1002 text3 = elm1.childNodes[0]
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001003
Collin Winterd28fcbc2007-03-28 23:34:06 +00001004 self.confirm(text1.previousSibling is None and
1005 text1.nextSibling is elm1 and
1006 elm1.previousSibling is text1 and
1007 elm1.nextSibling is text2 and
1008 text2.previousSibling is elm1 and
1009 text2.nextSibling is None and
1010 text3.previousSibling is None and
1011 text3.nextSibling is None, "testSAX2DOM - siblings")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001012
Collin Winterd28fcbc2007-03-28 23:34:06 +00001013 self.confirm(root.parentNode is doc and
1014 text1.parentNode is root and
1015 elm1.parentNode is root and
1016 text2.parentNode is root and
1017 text3.parentNode is elm1, "testSAX2DOM - parents")
1018 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001019
Collin Winterd28fcbc2007-03-28 23:34:06 +00001020 def testEncodings(self):
1021 doc = parseString('<foo>&#x20ac;</foo>')
1022 self.confirm(doc.toxml() == u'<?xml version="1.0" ?><foo>\u20ac</foo>'
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001023 and doc.toxml('utf-8') ==
Collin Winterd28fcbc2007-03-28 23:34:06 +00001024 '<?xml version="1.0" encoding="utf-8"?><foo>\xe2\x82\xac</foo>'
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001025 and doc.toxml('iso-8859-15') ==
Collin Winterd28fcbc2007-03-28 23:34:06 +00001026 '<?xml version="1.0" encoding="iso-8859-15"?><foo>\xa4</foo>',
1027 "testEncodings - encoding EURO SIGN")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001028
1029 # Verify that character decoding errors throw exceptions instead
Collin Winterd28fcbc2007-03-28 23:34:06 +00001030 # of crashing
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001031 self.assertRaises(UnicodeDecodeError, parseString,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001032 '<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001033
Collin Winterd28fcbc2007-03-28 23:34:06 +00001034 doc.unlink()
1035
1036 class UserDataHandler:
1037 called = 0
1038 def handle(self, operation, key, data, src, dst):
1039 dst.setUserData(key, data + 1, self)
1040 src.setUserData(key, None, None)
1041 self.called = 1
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001042
Collin Winterd28fcbc2007-03-28 23:34:06 +00001043 def testUserData(self):
1044 dom = Document()
1045 n = dom.createElement('e')
1046 self.confirm(n.getUserData("foo") is None)
1047 n.setUserData("foo", None, None)
1048 self.confirm(n.getUserData("foo") is None)
1049 n.setUserData("foo", 12, 12)
1050 n.setUserData("bar", 13, 13)
1051 self.confirm(n.getUserData("foo") == 12)
1052 self.confirm(n.getUserData("bar") == 13)
1053 n.setUserData("foo", None, None)
1054 self.confirm(n.getUserData("foo") is None)
1055 self.confirm(n.getUserData("bar") == 13)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001056
Collin Winterd28fcbc2007-03-28 23:34:06 +00001057 handler = self.UserDataHandler()
1058 n.setUserData("bar", 12, handler)
1059 c = n.cloneNode(1)
1060 self.confirm(handler.called
1061 and n.getUserData("bar") is None
1062 and c.getUserData("bar") == 13)
1063 n.unlink()
1064 c.unlink()
1065 dom.unlink()
1066
1067 def checkRenameNodeSharedConstraints(self, doc, node):
1068 # Make sure illegal NS usage is detected:
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001069 self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, node,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001070 "http://xml.python.org/ns", "xmlns:foo")
1071 doc2 = parseString("<doc/>")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001072 self.assertRaises(xml.dom.WrongDocumentErr, doc2.renameNode, node,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001073 xml.dom.EMPTY_NAMESPACE, "foo")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001074
Collin Winterd28fcbc2007-03-28 23:34:06 +00001075 def testRenameAttribute(self):
1076 doc = parseString("<doc a='v'/>")
1077 elem = doc.documentElement
1078 attrmap = elem.attributes
1079 attr = elem.attributes['a']
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001080
Collin Winterd28fcbc2007-03-28 23:34:06 +00001081 # Simple renaming
1082 attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "b")
1083 self.confirm(attr.name == "b"
1084 and attr.nodeName == "b"
1085 and attr.localName is None
1086 and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
1087 and attr.prefix is None
1088 and attr.value == "v"
1089 and elem.getAttributeNode("a") is None
1090 and elem.getAttributeNode("b").isSameNode(attr)
1091 and attrmap["b"].isSameNode(attr)
1092 and attr.ownerDocument.isSameNode(doc)
1093 and attr.ownerElement.isSameNode(elem))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001094
Collin Winterd28fcbc2007-03-28 23:34:06 +00001095 # Rename to have a namespace, no prefix
1096 attr = doc.renameNode(attr, "http://xml.python.org/ns", "c")
1097 self.confirm(attr.name == "c"
1098 and attr.nodeName == "c"
1099 and attr.localName == "c"
1100 and attr.namespaceURI == "http://xml.python.org/ns"
1101 and attr.prefix is None
1102 and attr.value == "v"
1103 and elem.getAttributeNode("a") is None
1104 and elem.getAttributeNode("b") is None
1105 and elem.getAttributeNode("c").isSameNode(attr)
1106 and elem.getAttributeNodeNS(
1107 "http://xml.python.org/ns", "c").isSameNode(attr)
1108 and attrmap["c"].isSameNode(attr)
1109 and attrmap[("http://xml.python.org/ns", "c")].isSameNode(attr))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001110
Collin Winterd28fcbc2007-03-28 23:34:06 +00001111 # Rename to have a namespace, with prefix
1112 attr = doc.renameNode(attr, "http://xml.python.org/ns2", "p:d")
1113 self.confirm(attr.name == "p:d"
1114 and attr.nodeName == "p:d"
1115 and attr.localName == "d"
1116 and attr.namespaceURI == "http://xml.python.org/ns2"
1117 and attr.prefix == "p"
1118 and attr.value == "v"
1119 and elem.getAttributeNode("a") is None
1120 and elem.getAttributeNode("b") is None
1121 and elem.getAttributeNode("c") is None
1122 and elem.getAttributeNodeNS(
1123 "http://xml.python.org/ns", "c") is None
1124 and elem.getAttributeNode("p:d").isSameNode(attr)
1125 and elem.getAttributeNodeNS(
1126 "http://xml.python.org/ns2", "d").isSameNode(attr)
1127 and attrmap["p:d"].isSameNode(attr)
1128 and attrmap[("http://xml.python.org/ns2", "d")].isSameNode(attr))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001129
Collin Winterd28fcbc2007-03-28 23:34:06 +00001130 # Rename back to a simple non-NS node
1131 attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "e")
1132 self.confirm(attr.name == "e"
1133 and attr.nodeName == "e"
1134 and attr.localName is None
1135 and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
1136 and attr.prefix is None
1137 and attr.value == "v"
1138 and elem.getAttributeNode("a") is None
1139 and elem.getAttributeNode("b") is None
1140 and elem.getAttributeNode("c") is None
1141 and elem.getAttributeNode("p:d") is None
1142 and elem.getAttributeNodeNS(
1143 "http://xml.python.org/ns", "c") is None
1144 and elem.getAttributeNode("e").isSameNode(attr)
1145 and attrmap["e"].isSameNode(attr))
1146
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001147 self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, attr,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001148 "http://xml.python.org/ns", "xmlns")
1149 self.checkRenameNodeSharedConstraints(doc, attr)
1150 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001151
Collin Winterd28fcbc2007-03-28 23:34:06 +00001152 def testRenameElement(self):
1153 doc = parseString("<doc/>")
1154 elem = doc.documentElement
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001155
Collin Winterd28fcbc2007-03-28 23:34:06 +00001156 # Simple renaming
1157 elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "a")
1158 self.confirm(elem.tagName == "a"
1159 and elem.nodeName == "a"
1160 and elem.localName is None
1161 and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
1162 and elem.prefix is None
1163 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001164
Collin Winterd28fcbc2007-03-28 23:34:06 +00001165 # Rename to have a namespace, no prefix
1166 elem = doc.renameNode(elem, "http://xml.python.org/ns", "b")
1167 self.confirm(elem.tagName == "b"
1168 and elem.nodeName == "b"
1169 and elem.localName == "b"
1170 and elem.namespaceURI == "http://xml.python.org/ns"
1171 and elem.prefix is None
1172 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001173
Collin Winterd28fcbc2007-03-28 23:34:06 +00001174 # Rename to have a namespace, with prefix
1175 elem = doc.renameNode(elem, "http://xml.python.org/ns2", "p:c")
1176 self.confirm(elem.tagName == "p:c"
1177 and elem.nodeName == "p:c"
1178 and elem.localName == "c"
1179 and elem.namespaceURI == "http://xml.python.org/ns2"
1180 and elem.prefix == "p"
1181 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001182
Collin Winterd28fcbc2007-03-28 23:34:06 +00001183 # Rename back to a simple non-NS node
1184 elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "d")
1185 self.confirm(elem.tagName == "d"
1186 and elem.nodeName == "d"
1187 and elem.localName is None
1188 and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
1189 and elem.prefix is None
1190 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001191
Collin Winterd28fcbc2007-03-28 23:34:06 +00001192 self.checkRenameNodeSharedConstraints(doc, elem)
1193 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001194
Collin Winterd28fcbc2007-03-28 23:34:06 +00001195 def testRenameOther(self):
1196 # We have to create a comment node explicitly since not all DOM
1197 # builders used with minidom add comments to the DOM.
1198 doc = xml.dom.minidom.getDOMImplementation().createDocument(
1199 xml.dom.EMPTY_NAMESPACE, "e", None)
1200 node = doc.createComment("comment")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001201 self.assertRaises(xml.dom.NotSupportedErr, doc.renameNode, node,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001202 xml.dom.EMPTY_NAMESPACE, "foo")
1203 doc.unlink()
1204
1205 def testWholeText(self):
1206 doc = parseString("<doc>a</doc>")
1207 elem = doc.documentElement
1208 text = elem.childNodes[0]
Ezio Melotti2623a372010-11-21 13:34:58 +00001209 self.assertEqual(text.nodeType, Node.TEXT_NODE)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001210
Collin Winterd28fcbc2007-03-28 23:34:06 +00001211 self.checkWholeText(text, "a")
1212 elem.appendChild(doc.createTextNode("b"))
1213 self.checkWholeText(text, "ab")
1214 elem.insertBefore(doc.createCDATASection("c"), text)
1215 self.checkWholeText(text, "cab")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001216
Collin Winterd28fcbc2007-03-28 23:34:06 +00001217 # make sure we don't cross other nodes
1218 splitter = doc.createComment("comment")
1219 elem.appendChild(splitter)
1220 text2 = doc.createTextNode("d")
1221 elem.appendChild(text2)
1222 self.checkWholeText(text, "cab")
1223 self.checkWholeText(text2, "d")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001224
Collin Winterd28fcbc2007-03-28 23:34:06 +00001225 x = doc.createElement("x")
1226 elem.replaceChild(x, splitter)
1227 splitter = x
1228 self.checkWholeText(text, "cab")
1229 self.checkWholeText(text2, "d")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001230
Collin Winterd28fcbc2007-03-28 23:34:06 +00001231 x = doc.createProcessingInstruction("y", "z")
1232 elem.replaceChild(x, splitter)
1233 splitter = x
1234 self.checkWholeText(text, "cab")
1235 self.checkWholeText(text2, "d")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001236
Collin Winterd28fcbc2007-03-28 23:34:06 +00001237 elem.removeChild(splitter)
1238 self.checkWholeText(text, "cabd")
1239 self.checkWholeText(text2, "cabd")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001240
Collin Winterd28fcbc2007-03-28 23:34:06 +00001241 def testPatch1094164(self):
1242 doc = parseString("<doc><e/></doc>")
1243 elem = doc.documentElement
1244 e = elem.firstChild
1245 self.confirm(e.parentNode is elem, "Before replaceChild()")
1246 # Check that replacing a child with itself leaves the tree unchanged
1247 elem.replaceChild(e, e)
1248 self.confirm(e.parentNode is elem, "After replaceChild()")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001249
Collin Winterd28fcbc2007-03-28 23:34:06 +00001250 def testReplaceWholeText(self):
1251 def setup():
1252 doc = parseString("<doc>a<e/>d</doc>")
1253 elem = doc.documentElement
1254 text1 = elem.firstChild
1255 text2 = elem.lastChild
1256 splitter = text1.nextSibling
1257 elem.insertBefore(doc.createTextNode("b"), splitter)
1258 elem.insertBefore(doc.createCDATASection("c"), text1)
1259 return doc, elem, text1, splitter, text2
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001260
Collin Winterd28fcbc2007-03-28 23:34:06 +00001261 doc, elem, text1, splitter, text2 = setup()
1262 text = text1.replaceWholeText("new content")
1263 self.checkWholeText(text, "new content")
1264 self.checkWholeText(text2, "d")
1265 self.confirm(len(elem.childNodes) == 3)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001266
Collin Winterd28fcbc2007-03-28 23:34:06 +00001267 doc, elem, text1, splitter, text2 = setup()
1268 text = text2.replaceWholeText("new content")
1269 self.checkWholeText(text, "new content")
1270 self.checkWholeText(text1, "cab")
1271 self.confirm(len(elem.childNodes) == 5)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001272
Collin Winterd28fcbc2007-03-28 23:34:06 +00001273 doc, elem, text1, splitter, text2 = setup()
1274 text = text1.replaceWholeText("")
1275 self.checkWholeText(text2, "d")
1276 self.confirm(text is None
1277 and len(elem.childNodes) == 2)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001278
Collin Winterd28fcbc2007-03-28 23:34:06 +00001279 def testSchemaType(self):
1280 doc = parseString(
1281 "<!DOCTYPE doc [\n"
1282 " <!ENTITY e1 SYSTEM 'http://xml.python.org/e1'>\n"
1283 " <!ENTITY e2 SYSTEM 'http://xml.python.org/e2'>\n"
1284 " <!ATTLIST doc id ID #IMPLIED \n"
1285 " ref IDREF #IMPLIED \n"
1286 " refs IDREFS #IMPLIED \n"
1287 " enum (a|b) #IMPLIED \n"
1288 " ent ENTITY #IMPLIED \n"
1289 " ents ENTITIES #IMPLIED \n"
1290 " nm NMTOKEN #IMPLIED \n"
1291 " nms NMTOKENS #IMPLIED \n"
1292 " text CDATA #IMPLIED \n"
1293 " >\n"
1294 "]><doc id='name' notid='name' text='splat!' enum='b'"
1295 " ref='name' refs='name name' ent='e1' ents='e1 e2'"
1296 " nm='123' nms='123 abc' />")
1297 elem = doc.documentElement
1298 # We don't want to rely on any specific loader at this point, so
1299 # just make sure we can get to all the names, and that the
1300 # DTD-based namespace is right. The names can vary by loader
1301 # since each supports a different level of DTD information.
1302 t = elem.schemaType
1303 self.confirm(t.name is None
1304 and t.namespace == xml.dom.EMPTY_NAMESPACE)
1305 names = "id notid text enum ref refs ent ents nm nms".split()
1306 for name in names:
1307 a = elem.getAttributeNode(name)
1308 t = a.schemaType
1309 self.confirm(hasattr(t, "name")
1310 and t.namespace == xml.dom.EMPTY_NAMESPACE)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001311
Collin Winterd28fcbc2007-03-28 23:34:06 +00001312 def testSetIdAttribute(self):
1313 doc = parseString("<doc a1='v' a2='w'/>")
1314 e = doc.documentElement
1315 a1 = e.getAttributeNode("a1")
1316 a2 = e.getAttributeNode("a2")
1317 self.confirm(doc.getElementById("v") is None
1318 and not a1.isId
1319 and not a2.isId)
1320 e.setIdAttribute("a1")
1321 self.confirm(e.isSameNode(doc.getElementById("v"))
1322 and a1.isId
1323 and not a2.isId)
1324 e.setIdAttribute("a2")
1325 self.confirm(e.isSameNode(doc.getElementById("v"))
1326 and e.isSameNode(doc.getElementById("w"))
1327 and a1.isId
1328 and a2.isId)
1329 # replace the a1 node; the new node should *not* be an ID
1330 a3 = doc.createAttribute("a1")
1331 a3.value = "v"
1332 e.setAttributeNode(a3)
1333 self.confirm(doc.getElementById("v") is None
1334 and e.isSameNode(doc.getElementById("w"))
1335 and not a1.isId
1336 and a2.isId
1337 and not a3.isId)
1338 # renaming an attribute should not affect its ID-ness:
1339 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1340 self.confirm(e.isSameNode(doc.getElementById("w"))
1341 and a2.isId)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001342
Collin Winterd28fcbc2007-03-28 23:34:06 +00001343 def testSetIdAttributeNS(self):
1344 NS1 = "http://xml.python.org/ns1"
1345 NS2 = "http://xml.python.org/ns2"
1346 doc = parseString("<doc"
1347 " xmlns:ns1='" + NS1 + "'"
1348 " xmlns:ns2='" + NS2 + "'"
1349 " ns1:a1='v' ns2:a2='w'/>")
1350 e = doc.documentElement
1351 a1 = e.getAttributeNodeNS(NS1, "a1")
1352 a2 = e.getAttributeNodeNS(NS2, "a2")
1353 self.confirm(doc.getElementById("v") is None
1354 and not a1.isId
1355 and not a2.isId)
1356 e.setIdAttributeNS(NS1, "a1")
1357 self.confirm(e.isSameNode(doc.getElementById("v"))
1358 and a1.isId
1359 and not a2.isId)
1360 e.setIdAttributeNS(NS2, "a2")
1361 self.confirm(e.isSameNode(doc.getElementById("v"))
1362 and e.isSameNode(doc.getElementById("w"))
1363 and a1.isId
1364 and a2.isId)
1365 # replace the a1 node; the new node should *not* be an ID
1366 a3 = doc.createAttributeNS(NS1, "a1")
1367 a3.value = "v"
1368 e.setAttributeNode(a3)
1369 self.confirm(e.isSameNode(doc.getElementById("w")))
1370 self.confirm(not a1.isId)
1371 self.confirm(a2.isId)
1372 self.confirm(not a3.isId)
1373 self.confirm(doc.getElementById("v") is None)
1374 # renaming an attribute should not affect its ID-ness:
1375 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1376 self.confirm(e.isSameNode(doc.getElementById("w"))
1377 and a2.isId)
1378
1379 def testSetIdAttributeNode(self):
1380 NS1 = "http://xml.python.org/ns1"
1381 NS2 = "http://xml.python.org/ns2"
1382 doc = parseString("<doc"
1383 " xmlns:ns1='" + NS1 + "'"
1384 " xmlns:ns2='" + NS2 + "'"
1385 " ns1:a1='v' ns2:a2='w'/>")
1386 e = doc.documentElement
1387 a1 = e.getAttributeNodeNS(NS1, "a1")
1388 a2 = e.getAttributeNodeNS(NS2, "a2")
1389 self.confirm(doc.getElementById("v") is None
1390 and not a1.isId
1391 and not a2.isId)
1392 e.setIdAttributeNode(a1)
1393 self.confirm(e.isSameNode(doc.getElementById("v"))
1394 and a1.isId
1395 and not a2.isId)
1396 e.setIdAttributeNode(a2)
1397 self.confirm(e.isSameNode(doc.getElementById("v"))
1398 and e.isSameNode(doc.getElementById("w"))
1399 and a1.isId
1400 and a2.isId)
1401 # replace the a1 node; the new node should *not* be an ID
1402 a3 = doc.createAttributeNS(NS1, "a1")
1403 a3.value = "v"
1404 e.setAttributeNode(a3)
1405 self.confirm(e.isSameNode(doc.getElementById("w")))
1406 self.confirm(not a1.isId)
1407 self.confirm(a2.isId)
1408 self.confirm(not a3.isId)
1409 self.confirm(doc.getElementById("v") is None)
1410 # renaming an attribute should not affect its ID-ness:
1411 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1412 self.confirm(e.isSameNode(doc.getElementById("w"))
1413 and a2.isId)
1414
1415 def testPickledDocument(self):
1416 doc = parseString("<?xml version='1.0' encoding='us-ascii'?>\n"
1417 "<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
1418 " 'http://xml.python.org/system' [\n"
1419 " <!ELEMENT e EMPTY>\n"
1420 " <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n"
1421 "]><doc attr='value'> text\n"
1422 "<?pi sample?> <!-- comment --> <e/> </doc>")
1423 s = pickle.dumps(doc)
1424 doc2 = pickle.loads(s)
1425 stack = [(doc, doc2)]
1426 while stack:
1427 n1, n2 = stack.pop()
1428 self.confirm(n1.nodeType == n2.nodeType
1429 and len(n1.childNodes) == len(n2.childNodes)
1430 and n1.nodeName == n2.nodeName
1431 and not n1.isSameNode(n2)
1432 and not n2.isSameNode(n1))
1433 if n1.nodeType == Node.DOCUMENT_TYPE_NODE:
1434 len(n1.entities)
1435 len(n2.entities)
1436 len(n1.notations)
1437 len(n2.notations)
1438 self.confirm(len(n1.entities) == len(n2.entities)
1439 and len(n1.notations) == len(n2.notations))
1440 for i in range(len(n1.notations)):
Georg Brandlcd4a21b2010-02-06 23:34:10 +00001441 # XXX this loop body doesn't seem to be executed?
Collin Winterd28fcbc2007-03-28 23:34:06 +00001442 no1 = n1.notations.item(i)
1443 no2 = n1.notations.item(i)
1444 self.confirm(no1.name == no2.name
1445 and no1.publicId == no2.publicId
1446 and no1.systemId == no2.systemId)
Georg Brandlcd4a21b2010-02-06 23:34:10 +00001447 stack.append((no1, no2))
Collin Winterd28fcbc2007-03-28 23:34:06 +00001448 for i in range(len(n1.entities)):
1449 e1 = n1.entities.item(i)
1450 e2 = n2.entities.item(i)
1451 self.confirm(e1.notationName == e2.notationName
1452 and e1.publicId == e2.publicId
1453 and e1.systemId == e2.systemId)
1454 stack.append((e1, e2))
1455 if n1.nodeType != Node.DOCUMENT_NODE:
1456 self.confirm(n1.ownerDocument.isSameNode(doc)
1457 and n2.ownerDocument.isSameNode(doc2))
1458 for i in range(len(n1.childNodes)):
1459 stack.append((n1.childNodes[i], n2.childNodes[i]))
1460
Martin v. Löwis27e4a172008-05-23 15:18:28 +00001461 def testSerializeCommentNodeWithDoubleHyphen(self):
1462 doc = create_doc_without_doctype()
1463 doc.appendChild(doc.createComment("foo--bar"))
1464 self.assertRaises(ValueError, doc.toxml)
1465
Georg Brandl5ded7912010-11-26 07:35:31 +00001466 def testEmptyXMLNSValue(self):
1467 doc = parseString("<element xmlns=''>\n"
1468 "<foo/>\n</element>")
1469 doc2 = parseString(doc.toxml())
1470 self.confirm(doc2.namespaceURI == xml.dom.EMPTY_NAMESPACE)
1471
1472
Collin Winterd28fcbc2007-03-28 23:34:06 +00001473def test_main():
1474 run_unittest(MinidomTest)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001475
Collin Winterd28fcbc2007-03-28 23:34:06 +00001476if __name__ == "__main__":
1477 test_main()