blob: ee8c04160ab706539da45d8545c78d041fc73988 [file] [log] [blame]
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001# test for xml.dom.minidom
Paul Prescod7993bcc2000-07-01 14:54:16 +00002
Serhiy Storchakac4722462015-11-26 23:49:42 +02003import copy
Martin v. Löwisfd6aaa12003-01-25 22:02:52 +00004import pickle
Zachary Ware38c707e2015-04-13 15:00:43 -05005from test.support import findfile
Guido van Rossumd8faa362007-04-27 19:54:29 +00006import unittest
Fred Drake17647f52000-07-03 16:37:42 +00007
Thomas Wouters0e3f5912006-08-11 14:57:12 +00008import xml.dom.minidom
Fred Drakec441f7b2002-07-19 22:16:41 +00009
Thomas Wouters0e3f5912006-08-11 14:57:12 +000010from xml.dom.minidom import parse, Node, Document, parseString
11from xml.dom.minidom import getDOMImplementation
Martin v. Löwisfd6aaa12003-01-25 22:02:52 +000012
Fred Drakec441f7b2002-07-19 22:16:41 +000013
Florent Xiclunaf15351d2010-03-13 23:24:31 +000014tstfile = findfile("test.xml", subdir="xmltestdata")
Serhiy Storchakac4722462015-11-26 23:49:42 +020015sample = ("<?xml version='1.0' encoding='us-ascii'?>\n"
16 "<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
17 " 'http://xml.python.org/system' [\n"
18 " <!ELEMENT e EMPTY>\n"
19 " <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n"
20 "]><doc attr='value'> text\n"
21 "<?pi sample?> <!-- comment --> <e/> </doc>")
Florent Xiclunaf15351d2010-03-13 23:24:31 +000022
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000023# The tests of DocumentType importing use these helpers to construct
24# the documents to work with, since not all DOM builders actually
25# create the DocumentType nodes.
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000026def create_doc_without_doctype(doctype=None):
27 return getDOMImplementation().createDocument(None, "doc", doctype)
28
29def create_nonempty_doctype():
30 doctype = getDOMImplementation().createDocumentType("doc", None, None)
31 doctype.entities._seq = []
32 doctype.notations._seq = []
Thomas Wouters0e3f5912006-08-11 14:57:12 +000033 notation = xml.dom.minidom.Notation("my-notation", None,
34 "http://xml.python.org/notations/my")
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000035 doctype.notations._seq.append(notation)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000036 entity = xml.dom.minidom.Entity("my-entity", None,
37 "http://xml.python.org/entities/my",
38 "my-notation")
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000039 entity.version = "1.0"
40 entity.encoding = "utf-8"
41 entity.actualEncoding = "us-ascii"
42 doctype.entities._seq.append(entity)
43 return doctype
44
45def create_doc_with_doctype():
46 doctype = create_nonempty_doctype()
47 doc = create_doc_without_doctype(doctype)
48 doctype.entities.item(0).ownerDocument = doc
49 doctype.notations.item(0).ownerDocument = doc
50 return doc
51
Guido van Rossumd8faa362007-04-27 19:54:29 +000052class MinidomTest(unittest.TestCase):
Guido van Rossumd8faa362007-04-27 19:54:29 +000053 def confirm(self, test, testname = "Test"):
54 self.assertTrue(test, testname)
55
56 def checkWholeText(self, node, s):
57 t = node.wholeText
Florent Xicluna313b2ad2011-12-10 21:14:53 +010058 self.confirm(t == s, "looking for %r, found %r" % (s, t))
Guido van Rossumd8faa362007-04-27 19:54:29 +000059
Yury Selivanov75445082015-05-11 22:57:16 -040060 def testDocumentAsyncAttr(self):
61 doc = Document()
62 self.assertFalse(doc.async_)
63 with self.assertWarns(DeprecationWarning):
64 self.assertFalse(getattr(doc, 'async', True))
65 with self.assertWarns(DeprecationWarning):
66 setattr(doc, 'async', True)
67 with self.assertWarns(DeprecationWarning):
68 self.assertTrue(getattr(doc, 'async', False))
69 self.assertTrue(doc.async_)
70
71 self.assertFalse(Document.async_)
72 with self.assertWarns(DeprecationWarning):
73 self.assertFalse(getattr(Document, 'async', True))
74
Serhiy Storchakaaa9563c2015-04-02 20:55:59 +030075 def testParseFromBinaryFile(self):
76 with open(tstfile, 'rb') as file:
77 dom = parse(file)
78 dom.unlink()
79 self.confirm(isinstance(dom, Document))
80
81 def testParseFromTextFile(self):
82 with open(tstfile, 'r', encoding='iso-8859-1') as file:
Brett Cannonc5246922010-10-30 00:14:59 +000083 dom = parse(file)
84 dom.unlink()
85 self.confirm(isinstance(dom, Document))
Guido van Rossumd8faa362007-04-27 19:54:29 +000086
87 def testGetElementsByTagName(self):
88 dom = parse(tstfile)
89 self.confirm(dom.getElementsByTagName("LI") == \
90 dom.documentElement.getElementsByTagName("LI"))
91 dom.unlink()
92
93 def testInsertBefore(self):
94 dom = parseString("<doc><foo/></doc>")
95 root = dom.documentElement
96 elem = root.childNodes[0]
97 nelem = dom.createElement("element")
98 root.insertBefore(nelem, elem)
99 self.confirm(len(root.childNodes) == 2
100 and root.childNodes.length == 2
101 and root.childNodes[0] is nelem
102 and root.childNodes.item(0) is nelem
103 and root.childNodes[1] is elem
104 and root.childNodes.item(1) is elem
105 and root.firstChild is nelem
106 and root.lastChild is elem
107 and root.toxml() == "<doc><element/><foo/></doc>"
108 , "testInsertBefore -- node properly placed in tree")
109 nelem = dom.createElement("element")
110 root.insertBefore(nelem, None)
111 self.confirm(len(root.childNodes) == 3
112 and root.childNodes.length == 3
113 and root.childNodes[1] is elem
114 and root.childNodes.item(1) is elem
115 and root.childNodes[2] is nelem
116 and root.childNodes.item(2) is nelem
117 and root.lastChild is nelem
118 and nelem.previousSibling is elem
119 and root.toxml() == "<doc><element/><foo/><element/></doc>"
120 , "testInsertBefore -- node properly placed in tree")
121 nelem2 = dom.createElement("bar")
122 root.insertBefore(nelem2, nelem)
123 self.confirm(len(root.childNodes) == 4
124 and root.childNodes.length == 4
125 and root.childNodes[2] is nelem2
126 and root.childNodes.item(2) is nelem2
127 and root.childNodes[3] is nelem
128 and root.childNodes.item(3) is nelem
129 and nelem2.nextSibling is nelem
130 and nelem.previousSibling is nelem2
131 and root.toxml() ==
132 "<doc><element/><foo/><bar/><element/></doc>"
133 , "testInsertBefore -- node properly placed in tree")
134 dom.unlink()
135
136 def _create_fragment_test_nodes(self):
137 dom = parseString("<doc/>")
138 orig = dom.createTextNode("original")
139 c1 = dom.createTextNode("foo")
140 c2 = dom.createTextNode("bar")
141 c3 = dom.createTextNode("bat")
142 dom.documentElement.appendChild(orig)
143 frag = dom.createDocumentFragment()
144 frag.appendChild(c1)
145 frag.appendChild(c2)
146 frag.appendChild(c3)
147 return dom, orig, c1, c2, c3, frag
148
149 def testInsertBeforeFragment(self):
150 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
151 dom.documentElement.insertBefore(frag, None)
152 self.confirm(tuple(dom.documentElement.childNodes) ==
153 (orig, c1, c2, c3),
154 "insertBefore(<fragment>, None)")
155 frag.unlink()
156 dom.unlink()
157
158 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
159 dom.documentElement.insertBefore(frag, orig)
160 self.confirm(tuple(dom.documentElement.childNodes) ==
161 (c1, c2, c3, orig),
162 "insertBefore(<fragment>, orig)")
163 frag.unlink()
164 dom.unlink()
165
166 def testAppendChild(self):
167 dom = parse(tstfile)
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000168 dom.documentElement.appendChild(dom.createComment("Hello"))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000169 self.confirm(dom.documentElement.childNodes[-1].nodeName == "#comment")
170 self.confirm(dom.documentElement.childNodes[-1].data == "Hello")
171 dom.unlink()
172
173 def testAppendChildFragment(self):
174 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
175 dom.documentElement.appendChild(frag)
176 self.confirm(tuple(dom.documentElement.childNodes) ==
177 (orig, c1, c2, c3),
178 "appendChild(<fragment>)")
179 frag.unlink()
180 dom.unlink()
181
182 def testReplaceChildFragment(self):
183 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
184 dom.documentElement.replaceChild(frag, orig)
185 orig.unlink()
186 self.confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3),
187 "replaceChild(<fragment>)")
188 frag.unlink()
189 dom.unlink()
190
191 def testLegalChildren(self):
192 dom = Document()
193 elem = dom.createElement('element')
194 text = dom.createTextNode('text')
195 self.assertRaises(xml.dom.HierarchyRequestErr, dom.appendChild, text)
196
197 dom.appendChild(elem)
198 self.assertRaises(xml.dom.HierarchyRequestErr, dom.insertBefore, text,
199 elem)
200 self.assertRaises(xml.dom.HierarchyRequestErr, dom.replaceChild, text,
201 elem)
202
203 nodemap = elem.attributes
204 self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItem,
205 text)
206 self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItemNS,
207 text)
208
209 elem.appendChild(text)
210 dom.unlink()
211
212 def testNamedNodeMapSetItem(self):
213 dom = Document()
214 elem = dom.createElement('element')
215 attrs = elem.attributes
216 attrs["foo"] = "bar"
217 a = attrs.item(0)
218 self.confirm(a.ownerDocument is dom,
219 "NamedNodeMap.__setitem__() sets ownerDocument")
220 self.confirm(a.ownerElement is elem,
221 "NamedNodeMap.__setitem__() sets ownerElement")
222 self.confirm(a.value == "bar",
223 "NamedNodeMap.__setitem__() sets value")
224 self.confirm(a.nodeValue == "bar",
225 "NamedNodeMap.__setitem__() sets nodeValue")
226 elem.unlink()
227 dom.unlink()
228
229 def testNonZero(self):
230 dom = parse(tstfile)
231 self.confirm(dom)# should not be zero
232 dom.appendChild(dom.createComment("foo"))
233 self.confirm(not dom.childNodes[-1].childNodes)
234 dom.unlink()
235
236 def testUnlink(self):
237 dom = parse(tstfile)
Kristján Valur Jónsson17173cf2010-06-09 08:13:42 +0000238 self.assertTrue(dom.childNodes)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000239 dom.unlink()
Kristján Valur Jónsson17173cf2010-06-09 08:13:42 +0000240 self.assertFalse(dom.childNodes)
241
242 def testContext(self):
243 with parse(tstfile) as dom:
244 self.assertTrue(dom.childNodes)
245 self.assertFalse(dom.childNodes)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000246
247 def testElement(self):
248 dom = Document()
249 dom.appendChild(dom.createElement("abc"))
250 self.confirm(dom.documentElement)
251 dom.unlink()
252
253 def testAAA(self):
254 dom = parseString("<abc/>")
255 el = dom.documentElement
256 el.setAttribute("spam", "jam2")
257 self.confirm(el.toxml() == '<abc spam="jam2"/>', "testAAA")
258 a = el.getAttributeNode("spam")
259 self.confirm(a.ownerDocument is dom,
260 "setAttribute() sets ownerDocument")
261 self.confirm(a.ownerElement is dom.documentElement,
262 "setAttribute() sets ownerElement")
263 dom.unlink()
264
265 def testAAB(self):
266 dom = parseString("<abc/>")
267 el = dom.documentElement
268 el.setAttribute("spam", "jam")
269 el.setAttribute("spam", "jam2")
270 self.confirm(el.toxml() == '<abc spam="jam2"/>', "testAAB")
271 dom.unlink()
272
273 def testAddAttr(self):
274 dom = Document()
275 child = dom.appendChild(dom.createElement("abc"))
276
277 child.setAttribute("def", "ghi")
278 self.confirm(child.getAttribute("def") == "ghi")
279 self.confirm(child.attributes["def"].value == "ghi")
280
281 child.setAttribute("jkl", "mno")
282 self.confirm(child.getAttribute("jkl") == "mno")
283 self.confirm(child.attributes["jkl"].value == "mno")
284
285 self.confirm(len(child.attributes) == 2)
286
287 child.setAttribute("def", "newval")
288 self.confirm(child.getAttribute("def") == "newval")
289 self.confirm(child.attributes["def"].value == "newval")
290
291 self.confirm(len(child.attributes) == 2)
292 dom.unlink()
293
294 def testDeleteAttr(self):
295 dom = Document()
296 child = dom.appendChild(dom.createElement("abc"))
297
298 self.confirm(len(child.attributes) == 0)
299 child.setAttribute("def", "ghi")
300 self.confirm(len(child.attributes) == 1)
301 del child.attributes["def"]
302 self.confirm(len(child.attributes) == 0)
303 dom.unlink()
304
305 def testRemoveAttr(self):
306 dom = Document()
307 child = dom.appendChild(dom.createElement("abc"))
308
309 child.setAttribute("def", "ghi")
310 self.confirm(len(child.attributes) == 1)
Raymond Hettinger06eef9c2011-06-25 15:54:52 +0200311 self.assertRaises(xml.dom.NotFoundErr, child.removeAttribute, "foo")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000312 child.removeAttribute("def")
313 self.confirm(len(child.attributes) == 0)
314 dom.unlink()
315
316 def testRemoveAttrNS(self):
317 dom = Document()
318 child = dom.appendChild(
319 dom.createElementNS("http://www.python.org", "python:abc"))
320 child.setAttributeNS("http://www.w3.org", "xmlns:python",
321 "http://www.python.org")
322 child.setAttributeNS("http://www.python.org", "python:abcattr", "foo")
Raymond Hettinger06eef9c2011-06-25 15:54:52 +0200323 self.assertRaises(xml.dom.NotFoundErr, child.removeAttributeNS,
324 "foo", "http://www.python.org")
Guido van Rossumd8faa362007-04-27 19:54:29 +0000325 self.confirm(len(child.attributes) == 2)
326 child.removeAttributeNS("http://www.python.org", "abcattr")
327 self.confirm(len(child.attributes) == 1)
328 dom.unlink()
329
330 def testRemoveAttributeNode(self):
331 dom = Document()
332 child = dom.appendChild(dom.createElement("foo"))
333 child.setAttribute("spam", "jam")
334 self.confirm(len(child.attributes) == 1)
335 node = child.getAttributeNode("spam")
Raymond Hettinger06eef9c2011-06-25 15:54:52 +0200336 self.assertRaises(xml.dom.NotFoundErr, child.removeAttributeNode,
337 None)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000338 child.removeAttributeNode(node)
339 self.confirm(len(child.attributes) == 0
340 and child.getAttributeNode("spam") is None)
Raymond Hettinger06eef9c2011-06-25 15:54:52 +0200341 dom2 = Document()
Ezio Melotti0f12be12013-08-10 18:30:29 +0300342 child2 = dom2.appendChild(dom2.createElement("foo"))
343 node2 = child2.getAttributeNode("spam")
344 self.assertRaises(xml.dom.NotFoundErr, child2.removeAttributeNode,
345 node2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000346 dom.unlink()
347
Raymond Hettinger06eef9c2011-06-25 15:54:52 +0200348 def testHasAttribute(self):
349 dom = Document()
350 child = dom.appendChild(dom.createElement("foo"))
351 child.setAttribute("spam", "jam")
352 self.confirm(child.hasAttribute("spam"))
353
Guido van Rossumd8faa362007-04-27 19:54:29 +0000354 def testChangeAttr(self):
355 dom = parseString("<abc/>")
356 el = dom.documentElement
357 el.setAttribute("spam", "jam")
358 self.confirm(len(el.attributes) == 1)
359 el.setAttribute("spam", "bam")
360 # Set this attribute to be an ID and make sure that doesn't change
361 # when changing the value:
362 el.setIdAttribute("spam")
363 self.confirm(len(el.attributes) == 1
364 and el.attributes["spam"].value == "bam"
365 and el.attributes["spam"].nodeValue == "bam"
366 and el.getAttribute("spam") == "bam"
367 and el.getAttributeNode("spam").isId)
368 el.attributes["spam"] = "ham"
369 self.confirm(len(el.attributes) == 1
370 and el.attributes["spam"].value == "ham"
371 and el.attributes["spam"].nodeValue == "ham"
372 and el.getAttribute("spam") == "ham"
373 and el.attributes["spam"].isId)
374 el.setAttribute("spam2", "bam")
375 self.confirm(len(el.attributes) == 2
376 and el.attributes["spam"].value == "ham"
377 and el.attributes["spam"].nodeValue == "ham"
378 and el.getAttribute("spam") == "ham"
379 and el.attributes["spam2"].value == "bam"
380 and el.attributes["spam2"].nodeValue == "bam"
381 and el.getAttribute("spam2") == "bam")
382 el.attributes["spam2"] = "bam2"
383 self.confirm(len(el.attributes) == 2
384 and el.attributes["spam"].value == "ham"
385 and el.attributes["spam"].nodeValue == "ham"
386 and el.getAttribute("spam") == "ham"
387 and el.attributes["spam2"].value == "bam2"
388 and el.attributes["spam2"].nodeValue == "bam2"
389 and el.getAttribute("spam2") == "bam2")
390 dom.unlink()
391
392 def testGetAttrList(self):
393 pass
394
Martin v. Löwis67245a62012-03-05 07:01:49 +0100395 def testGetAttrValues(self):
396 pass
Guido van Rossumd8faa362007-04-27 19:54:29 +0000397
Martin v. Löwis67245a62012-03-05 07:01:49 +0100398 def testGetAttrLength(self):
399 pass
Guido van Rossumd8faa362007-04-27 19:54:29 +0000400
Martin v. Löwis67245a62012-03-05 07:01:49 +0100401 def testGetAttribute(self):
402 dom = Document()
403 child = dom.appendChild(
404 dom.createElementNS("http://www.python.org", "python:abc"))
405 self.assertEqual(child.getAttribute('missing'), '')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000406
Raymond Hettinger06eef9c2011-06-25 15:54:52 +0200407 def testGetAttributeNS(self):
408 dom = Document()
409 child = dom.appendChild(
410 dom.createElementNS("http://www.python.org", "python:abc"))
411 child.setAttributeNS("http://www.w3.org", "xmlns:python",
412 "http://www.python.org")
413 self.assertEqual(child.getAttributeNS("http://www.w3.org", "python"),
414 'http://www.python.org')
415 self.assertEqual(child.getAttributeNS("http://www.w3.org", "other"),
416 '')
Martin v. Löwis67245a62012-03-05 07:01:49 +0100417 child2 = child.appendChild(dom.createElement('abc'))
418 self.assertEqual(child2.getAttributeNS("http://www.python.org", "missing"),
419 '')
Guido van Rossumd8faa362007-04-27 19:54:29 +0000420
421 def testGetAttributeNode(self): pass
422
423 def testGetElementsByTagNameNS(self):
424 d="""<foo xmlns:minidom='http://pyxml.sf.net/minidom'>
425 <minidom:myelem/>
426 </foo>"""
427 dom = parseString(d)
428 elems = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom",
429 "myelem")
430 self.confirm(len(elems) == 1
431 and elems[0].namespaceURI == "http://pyxml.sf.net/minidom"
432 and elems[0].localName == "myelem"
433 and elems[0].prefix == "minidom"
434 and elems[0].tagName == "minidom:myelem"
435 and elems[0].nodeName == "minidom:myelem")
436 dom.unlink()
437
438 def get_empty_nodelist_from_elements_by_tagName_ns_helper(self, doc, nsuri,
439 lname):
440 nodelist = doc.getElementsByTagNameNS(nsuri, lname)
441 self.confirm(len(nodelist) == 0)
442
443 def testGetEmptyNodeListFromElementsByTagNameNS(self):
444 doc = parseString('<doc/>')
445 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
446 doc, 'http://xml.python.org/namespaces/a', 'localname')
447 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
448 doc, '*', 'splat')
449 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
450 doc, 'http://xml.python.org/namespaces/a', '*')
451
452 doc = parseString('<doc xmlns="http://xml.python.org/splat"><e/></doc>')
453 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
454 doc, "http://xml.python.org/splat", "not-there")
455 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
456 doc, "*", "not-there")
457 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
458 doc, "http://somewhere.else.net/not-there", "e")
459
460 def testElementReprAndStr(self):
461 dom = Document()
462 el = dom.appendChild(dom.createElement("abc"))
463 string1 = repr(el)
464 string2 = str(el)
465 self.confirm(string1 == string2)
466 dom.unlink()
467
468 def testElementReprAndStrUnicode(self):
469 dom = Document()
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000470 el = dom.appendChild(dom.createElement("abc"))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000471 string1 = repr(el)
472 string2 = str(el)
473 self.confirm(string1 == string2)
474 dom.unlink()
475
476 def testElementReprAndStrUnicodeNS(self):
477 dom = Document()
478 el = dom.appendChild(
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000479 dom.createElementNS("http://www.slashdot.org", "slash:abc"))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000480 string1 = repr(el)
481 string2 = str(el)
482 self.confirm(string1 == string2)
Ezio Melotti7fb4da72010-03-18 12:29:13 +0000483 self.confirm("slash:abc" in string1)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000484 dom.unlink()
485
486 def testAttributeRepr(self):
487 dom = Document()
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000488 el = dom.appendChild(dom.createElement("abc"))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000489 node = el.setAttribute("abc", "def")
490 self.confirm(str(node) == repr(node))
491 dom.unlink()
492
493 def testTextNodeRepr(self): pass
494
495 def testWriteXML(self):
496 str = '<?xml version="1.0" ?><a b="c"/>'
497 dom = parseString(str)
498 domstr = dom.toxml()
499 dom.unlink()
500 self.confirm(str == domstr)
501
502 def testAltNewline(self):
503 str = '<?xml version="1.0" ?>\n<a b="c"/>\n'
504 dom = parseString(str)
505 domstr = dom.toprettyxml(newl="\r\n")
506 dom.unlink()
507 self.confirm(domstr == str.replace("\n", "\r\n"))
508
Ezio Melotti8008f2a2011-11-18 17:34:26 +0200509 def test_toprettyxml_with_text_nodes(self):
510 # see issue #4147, text nodes are not indented
511 decl = '<?xml version="1.0" ?>\n'
512 self.assertEqual(parseString('<B>A</B>').toprettyxml(),
513 decl + '<B>A</B>\n')
514 self.assertEqual(parseString('<C>A<B>A</B></C>').toprettyxml(),
515 decl + '<C>\n\tA\n\t<B>A</B>\n</C>\n')
516 self.assertEqual(parseString('<C><B>A</B>A</C>').toprettyxml(),
517 decl + '<C>\n\t<B>A</B>\n\tA\n</C>\n')
518 self.assertEqual(parseString('<C><B>A</B><B>A</B></C>').toprettyxml(),
519 decl + '<C>\n\t<B>A</B>\n\t<B>A</B>\n</C>\n')
520 self.assertEqual(parseString('<C><B>A</B>A<B>A</B></C>').toprettyxml(),
521 decl + '<C>\n\t<B>A</B>\n\tA\n\t<B>A</B>\n</C>\n')
522
523 def test_toprettyxml_with_adjacent_text_nodes(self):
524 # see issue #4147, adjacent text nodes are indented normally
525 dom = Document()
526 elem = dom.createElement('elem')
527 elem.appendChild(dom.createTextNode('TEXT'))
528 elem.appendChild(dom.createTextNode('TEXT'))
529 dom.appendChild(elem)
530 decl = '<?xml version="1.0" ?>\n'
531 self.assertEqual(dom.toprettyxml(),
532 decl + '<elem>\n\tTEXT\n\tTEXT\n</elem>\n')
533
Éric Araujo63ba97b2011-10-05 01:29:22 +0200534 def test_toprettyxml_preserves_content_of_text_node(self):
Ezio Melotti8008f2a2011-11-18 17:34:26 +0200535 # see issue #4147
536 for str in ('<B>A</B>', '<A><B>C</B></A>'):
537 dom = parseString(str)
538 dom2 = parseString(dom.toprettyxml())
539 self.assertEqual(
540 dom.getElementsByTagName('B')[0].childNodes[0].toxml(),
541 dom2.getElementsByTagName('B')[0].childNodes[0].toxml())
R David Murray791744b2011-10-01 16:19:51 -0400542
Guido van Rossumd8faa362007-04-27 19:54:29 +0000543 def testProcessingInstruction(self):
544 dom = parseString('<e><?mypi \t\n data \t\n ?></e>')
545 pi = dom.documentElement.firstChild
546 self.confirm(pi.target == "mypi"
547 and pi.data == "data \t\n "
548 and pi.nodeName == "mypi"
549 and pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE
550 and pi.attributes is None
551 and not pi.hasChildNodes()
552 and len(pi.childNodes) == 0
553 and pi.firstChild is None
554 and pi.lastChild is None
555 and pi.localName is None
556 and pi.namespaceURI == xml.dom.EMPTY_NAMESPACE)
557
558 def testProcessingInstructionRepr(self): pass
559
560 def testTextRepr(self): pass
561
562 def testWriteText(self): pass
563
564 def testDocumentElement(self): pass
565
566 def testTooManyDocumentElements(self):
567 doc = parseString("<doc/>")
568 elem = doc.createElement("extra")
569 # Should raise an exception when adding an extra document element.
570 self.assertRaises(xml.dom.HierarchyRequestErr, doc.appendChild, elem)
571 elem.unlink()
572 doc.unlink()
573
574 def testCreateElementNS(self): pass
575
576 def testCreateAttributeNS(self): pass
577
578 def testParse(self): pass
579
580 def testParseString(self): pass
581
582 def testComment(self): pass
583
584 def testAttrListItem(self): pass
585
586 def testAttrListItems(self): pass
587
588 def testAttrListItemNS(self): pass
589
590 def testAttrListKeys(self): pass
591
592 def testAttrListKeysNS(self): pass
593
594 def testRemoveNamedItem(self):
595 doc = parseString("<doc a=''/>")
596 e = doc.documentElement
597 attrs = e.attributes
598 a1 = e.getAttributeNode("a")
599 a2 = attrs.removeNamedItem("a")
600 self.confirm(a1.isSameNode(a2))
601 self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItem, "a")
602
603 def testRemoveNamedItemNS(self):
604 doc = parseString("<doc xmlns:a='http://xml.python.org/' a:b=''/>")
605 e = doc.documentElement
606 attrs = e.attributes
607 a1 = e.getAttributeNodeNS("http://xml.python.org/", "b")
608 a2 = attrs.removeNamedItemNS("http://xml.python.org/", "b")
609 self.confirm(a1.isSameNode(a2))
610 self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItemNS,
611 "http://xml.python.org/", "b")
612
613 def testAttrListValues(self): pass
614
615 def testAttrListLength(self): pass
616
617 def testAttrList__getitem__(self): pass
618
619 def testAttrList__setitem__(self): pass
620
621 def testSetAttrValueandNodeValue(self): pass
622
623 def testParseElement(self): pass
624
625 def testParseAttributes(self): pass
626
627 def testParseElementNamespaces(self): pass
628
629 def testParseAttributeNamespaces(self): pass
630
631 def testParseProcessingInstructions(self): pass
632
633 def testChildNodes(self): pass
634
635 def testFirstChild(self): pass
636
Raymond Hettinger06eef9c2011-06-25 15:54:52 +0200637 def testHasChildNodes(self):
638 dom = parseString("<doc><foo/></doc>")
639 doc = dom.documentElement
Ezio Melotti0f12be12013-08-10 18:30:29 +0300640 self.assertTrue(doc.hasChildNodes())
Raymond Hettinger06eef9c2011-06-25 15:54:52 +0200641 dom2 = parseString("<doc/>")
642 doc2 = dom2.documentElement
643 self.assertFalse(doc2.hasChildNodes())
Guido van Rossumd8faa362007-04-27 19:54:29 +0000644
645 def _testCloneElementCopiesAttributes(self, e1, e2, test):
646 attrs1 = e1.attributes
647 attrs2 = e2.attributes
648 keys1 = list(attrs1.keys())
649 keys2 = list(attrs2.keys())
650 keys1.sort()
651 keys2.sort()
652 self.confirm(keys1 == keys2, "clone of element has same attribute keys")
653 for i in range(len(keys1)):
654 a1 = attrs1.item(i)
655 a2 = attrs2.item(i)
656 self.confirm(a1 is not a2
657 and a1.value == a2.value
658 and a1.nodeValue == a2.nodeValue
659 and a1.namespaceURI == a2.namespaceURI
660 and a1.localName == a2.localName
661 , "clone of attribute node has proper attribute values")
662 self.confirm(a2.ownerElement is e2,
663 "clone of attribute node correctly owned")
664
665 def _setupCloneElement(self, deep):
666 dom = parseString("<doc attr='value'><foo/></doc>")
667 root = dom.documentElement
668 clone = root.cloneNode(deep)
669 self._testCloneElementCopiesAttributes(
670 root, clone, "testCloneElement" + (deep and "Deep" or "Shallow"))
671 # mutilate the original so shared data is detected
672 root.tagName = root.nodeName = "MODIFIED"
673 root.setAttribute("attr", "NEW VALUE")
674 root.setAttribute("added", "VALUE")
675 return dom, clone
676
677 def testCloneElementShallow(self):
678 dom, clone = self._setupCloneElement(0)
679 self.confirm(len(clone.childNodes) == 0
680 and clone.childNodes.length == 0
681 and clone.parentNode is None
682 and clone.toxml() == '<doc attr="value"/>'
683 , "testCloneElementShallow")
684 dom.unlink()
685
686 def testCloneElementDeep(self):
687 dom, clone = self._setupCloneElement(1)
688 self.confirm(len(clone.childNodes) == 1
689 and clone.childNodes.length == 1
690 and clone.parentNode is None
691 and clone.toxml() == '<doc attr="value"><foo/></doc>'
692 , "testCloneElementDeep")
693 dom.unlink()
694
695 def testCloneDocumentShallow(self):
696 doc = parseString("<?xml version='1.0'?>\n"
697 "<!-- comment -->"
698 "<!DOCTYPE doc [\n"
699 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
700 "]>\n"
701 "<doc attr='value'/>")
702 doc2 = doc.cloneNode(0)
703 self.confirm(doc2 is None,
704 "testCloneDocumentShallow:"
705 " shallow cloning of documents makes no sense!")
706
707 def testCloneDocumentDeep(self):
708 doc = parseString("<?xml version='1.0'?>\n"
709 "<!-- comment -->"
710 "<!DOCTYPE doc [\n"
711 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
712 "]>\n"
713 "<doc attr='value'/>")
714 doc2 = doc.cloneNode(1)
715 self.confirm(not (doc.isSameNode(doc2) or doc2.isSameNode(doc)),
716 "testCloneDocumentDeep: document objects not distinct")
717 self.confirm(len(doc.childNodes) == len(doc2.childNodes),
718 "testCloneDocumentDeep: wrong number of Document children")
719 self.confirm(doc2.documentElement.nodeType == Node.ELEMENT_NODE,
720 "testCloneDocumentDeep: documentElement not an ELEMENT_NODE")
721 self.confirm(doc2.documentElement.ownerDocument.isSameNode(doc2),
722 "testCloneDocumentDeep: documentElement owner is not new document")
723 self.confirm(not doc.documentElement.isSameNode(doc2.documentElement),
724 "testCloneDocumentDeep: documentElement should not be shared")
725 if doc.doctype is not None:
726 # check the doctype iff the original DOM maintained it
727 self.confirm(doc2.doctype.nodeType == Node.DOCUMENT_TYPE_NODE,
728 "testCloneDocumentDeep: doctype not a DOCUMENT_TYPE_NODE")
729 self.confirm(doc2.doctype.ownerDocument.isSameNode(doc2))
730 self.confirm(not doc.doctype.isSameNode(doc2.doctype))
731
732 def testCloneDocumentTypeDeepOk(self):
733 doctype = create_nonempty_doctype()
734 clone = doctype.cloneNode(1)
735 self.confirm(clone is not None
736 and clone.nodeName == doctype.nodeName
737 and clone.name == doctype.name
738 and clone.publicId == doctype.publicId
739 and clone.systemId == doctype.systemId
740 and len(clone.entities) == len(doctype.entities)
741 and clone.entities.item(len(clone.entities)) is None
742 and len(clone.notations) == len(doctype.notations)
743 and clone.notations.item(len(clone.notations)) is None
744 and len(clone.childNodes) == 0)
745 for i in range(len(doctype.entities)):
746 se = doctype.entities.item(i)
747 ce = clone.entities.item(i)
748 self.confirm((not se.isSameNode(ce))
749 and (not ce.isSameNode(se))
750 and ce.nodeName == se.nodeName
751 and ce.notationName == se.notationName
752 and ce.publicId == se.publicId
753 and ce.systemId == se.systemId
754 and ce.encoding == se.encoding
755 and ce.actualEncoding == se.actualEncoding
756 and ce.version == se.version)
757 for i in range(len(doctype.notations)):
758 sn = doctype.notations.item(i)
759 cn = clone.notations.item(i)
760 self.confirm((not sn.isSameNode(cn))
761 and (not cn.isSameNode(sn))
762 and cn.nodeName == sn.nodeName
763 and cn.publicId == sn.publicId
764 and cn.systemId == sn.systemId)
765
766 def testCloneDocumentTypeDeepNotOk(self):
767 doc = create_doc_with_doctype()
768 clone = doc.doctype.cloneNode(1)
769 self.confirm(clone is None, "testCloneDocumentTypeDeepNotOk")
770
771 def testCloneDocumentTypeShallowOk(self):
772 doctype = create_nonempty_doctype()
773 clone = doctype.cloneNode(0)
774 self.confirm(clone is not None
775 and clone.nodeName == doctype.nodeName
776 and clone.name == doctype.name
777 and clone.publicId == doctype.publicId
778 and clone.systemId == doctype.systemId
779 and len(clone.entities) == 0
780 and clone.entities.item(0) is None
781 and len(clone.notations) == 0
782 and clone.notations.item(0) is None
783 and len(clone.childNodes) == 0)
784
785 def testCloneDocumentTypeShallowNotOk(self):
786 doc = create_doc_with_doctype()
787 clone = doc.doctype.cloneNode(0)
788 self.confirm(clone is None, "testCloneDocumentTypeShallowNotOk")
789
790 def check_import_document(self, deep, testName):
791 doc1 = parseString("<doc/>")
792 doc2 = parseString("<doc/>")
793 self.assertRaises(xml.dom.NotSupportedErr, doc1.importNode, doc2, deep)
794
795 def testImportDocumentShallow(self):
796 self.check_import_document(0, "testImportDocumentShallow")
797
798 def testImportDocumentDeep(self):
799 self.check_import_document(1, "testImportDocumentDeep")
800
801 def testImportDocumentTypeShallow(self):
802 src = create_doc_with_doctype()
803 target = create_doc_without_doctype()
804 self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
805 src.doctype, 0)
806
807 def testImportDocumentTypeDeep(self):
808 src = create_doc_with_doctype()
809 target = create_doc_without_doctype()
810 self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
811 src.doctype, 1)
812
813 # Testing attribute clones uses a helper, and should always be deep,
814 # even if the argument to cloneNode is false.
815 def check_clone_attribute(self, deep, testName):
816 doc = parseString("<doc attr='value'/>")
817 attr = doc.documentElement.getAttributeNode("attr")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000818 self.assertNotEqual(attr, None)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000819 clone = attr.cloneNode(deep)
820 self.confirm(not clone.isSameNode(attr))
821 self.confirm(not attr.isSameNode(clone))
822 self.confirm(clone.ownerElement is None,
823 testName + ": ownerElement should be None")
824 self.confirm(clone.ownerDocument.isSameNode(attr.ownerDocument),
825 testName + ": ownerDocument does not match")
826 self.confirm(clone.specified,
827 testName + ": cloned attribute must have specified == True")
828
829 def testCloneAttributeShallow(self):
830 self.check_clone_attribute(0, "testCloneAttributeShallow")
831
832 def testCloneAttributeDeep(self):
833 self.check_clone_attribute(1, "testCloneAttributeDeep")
834
835 def check_clone_pi(self, deep, testName):
836 doc = parseString("<?target data?><doc/>")
837 pi = doc.firstChild
Ezio Melottib3aedd42010-11-20 19:04:17 +0000838 self.assertEqual(pi.nodeType, Node.PROCESSING_INSTRUCTION_NODE)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000839 clone = pi.cloneNode(deep)
840 self.confirm(clone.target == pi.target
841 and clone.data == pi.data)
842
843 def testClonePIShallow(self):
844 self.check_clone_pi(0, "testClonePIShallow")
845
846 def testClonePIDeep(self):
847 self.check_clone_pi(1, "testClonePIDeep")
848
849 def testNormalize(self):
850 doc = parseString("<doc/>")
851 root = doc.documentElement
852 root.appendChild(doc.createTextNode("first"))
853 root.appendChild(doc.createTextNode("second"))
854 self.confirm(len(root.childNodes) == 2
855 and root.childNodes.length == 2,
856 "testNormalize -- preparation")
857 doc.normalize()
858 self.confirm(len(root.childNodes) == 1
859 and root.childNodes.length == 1
860 and root.firstChild is root.lastChild
861 and root.firstChild.data == "firstsecond"
862 , "testNormalize -- result")
863 doc.unlink()
864
865 doc = parseString("<doc/>")
866 root = doc.documentElement
867 root.appendChild(doc.createTextNode(""))
868 doc.normalize()
869 self.confirm(len(root.childNodes) == 0
870 and root.childNodes.length == 0,
871 "testNormalize -- single empty node removed")
872 doc.unlink()
873
R. David Murraydc6da8a2009-04-09 22:16:43 +0000874 def testNormalizeCombineAndNextSibling(self):
875 doc = parseString("<doc/>")
876 root = doc.documentElement
877 root.appendChild(doc.createTextNode("first"))
878 root.appendChild(doc.createTextNode("second"))
879 root.appendChild(doc.createElement("i"))
880 self.confirm(len(root.childNodes) == 3
881 and root.childNodes.length == 3,
882 "testNormalizeCombineAndNextSibling -- preparation")
883 doc.normalize()
884 self.confirm(len(root.childNodes) == 2
885 and root.childNodes.length == 2
886 and root.firstChild.data == "firstsecond"
887 and root.firstChild is not root.lastChild
888 and root.firstChild.nextSibling is root.lastChild
889 and root.firstChild.previousSibling is None
890 and root.lastChild.previousSibling is root.firstChild
891 and root.lastChild.nextSibling is None
892 , "testNormalizeCombinedAndNextSibling -- result")
893 doc.unlink()
894
895 def testNormalizeDeleteWithPrevSibling(self):
896 doc = parseString("<doc/>")
897 root = doc.documentElement
898 root.appendChild(doc.createTextNode("first"))
899 root.appendChild(doc.createTextNode(""))
900 self.confirm(len(root.childNodes) == 2
901 and root.childNodes.length == 2,
902 "testNormalizeDeleteWithPrevSibling -- preparation")
903 doc.normalize()
904 self.confirm(len(root.childNodes) == 1
905 and root.childNodes.length == 1
906 and root.firstChild.data == "first"
907 and root.firstChild is root.lastChild
908 and root.firstChild.nextSibling is None
909 and root.firstChild.previousSibling is None
910 , "testNormalizeDeleteWithPrevSibling -- result")
911 doc.unlink()
912
913 def testNormalizeDeleteWithNextSibling(self):
914 doc = parseString("<doc/>")
915 root = doc.documentElement
916 root.appendChild(doc.createTextNode(""))
917 root.appendChild(doc.createTextNode("second"))
918 self.confirm(len(root.childNodes) == 2
919 and root.childNodes.length == 2,
920 "testNormalizeDeleteWithNextSibling -- preparation")
921 doc.normalize()
922 self.confirm(len(root.childNodes) == 1
923 and root.childNodes.length == 1
924 and root.firstChild.data == "second"
925 and root.firstChild is root.lastChild
926 and root.firstChild.nextSibling is None
927 and root.firstChild.previousSibling is None
928 , "testNormalizeDeleteWithNextSibling -- result")
929 doc.unlink()
930
931 def testNormalizeDeleteWithTwoNonTextSiblings(self):
932 doc = parseString("<doc/>")
933 root = doc.documentElement
934 root.appendChild(doc.createElement("i"))
935 root.appendChild(doc.createTextNode(""))
936 root.appendChild(doc.createElement("i"))
937 self.confirm(len(root.childNodes) == 3
938 and root.childNodes.length == 3,
939 "testNormalizeDeleteWithTwoSiblings -- preparation")
940 doc.normalize()
941 self.confirm(len(root.childNodes) == 2
942 and root.childNodes.length == 2
943 and root.firstChild is not root.lastChild
944 and root.firstChild.nextSibling is root.lastChild
945 and root.firstChild.previousSibling is None
946 and root.lastChild.previousSibling is root.firstChild
947 and root.lastChild.nextSibling is None
948 , "testNormalizeDeleteWithTwoSiblings -- result")
949 doc.unlink()
950
951 def testNormalizeDeleteAndCombine(self):
952 doc = parseString("<doc/>")
953 root = doc.documentElement
954 root.appendChild(doc.createTextNode(""))
955 root.appendChild(doc.createTextNode("second"))
956 root.appendChild(doc.createTextNode(""))
957 root.appendChild(doc.createTextNode("fourth"))
958 root.appendChild(doc.createTextNode(""))
959 self.confirm(len(root.childNodes) == 5
960 and root.childNodes.length == 5,
961 "testNormalizeDeleteAndCombine -- preparation")
962 doc.normalize()
963 self.confirm(len(root.childNodes) == 1
964 and root.childNodes.length == 1
965 and root.firstChild is root.lastChild
966 and root.firstChild.data == "secondfourth"
967 and root.firstChild.previousSibling is None
968 and root.firstChild.nextSibling is None
969 , "testNormalizeDeleteAndCombine -- result")
970 doc.unlink()
971
972 def testNormalizeRecursion(self):
973 doc = parseString("<doc>"
974 "<o>"
975 "<i/>"
976 "t"
977 #
978 #x
979 "</o>"
980 "<o>"
981 "<o>"
982 "t2"
983 #x2
984 "</o>"
985 "t3"
986 #x3
987 "</o>"
988 #
989 "</doc>")
990 root = doc.documentElement
991 root.childNodes[0].appendChild(doc.createTextNode(""))
992 root.childNodes[0].appendChild(doc.createTextNode("x"))
993 root.childNodes[1].childNodes[0].appendChild(doc.createTextNode("x2"))
994 root.childNodes[1].appendChild(doc.createTextNode("x3"))
995 root.appendChild(doc.createTextNode(""))
996 self.confirm(len(root.childNodes) == 3
997 and root.childNodes.length == 3
998 and len(root.childNodes[0].childNodes) == 4
999 and root.childNodes[0].childNodes.length == 4
1000 and len(root.childNodes[1].childNodes) == 3
1001 and root.childNodes[1].childNodes.length == 3
1002 and len(root.childNodes[1].childNodes[0].childNodes) == 2
1003 and root.childNodes[1].childNodes[0].childNodes.length == 2
1004 , "testNormalize2 -- preparation")
1005 doc.normalize()
1006 self.confirm(len(root.childNodes) == 2
1007 and root.childNodes.length == 2
1008 and len(root.childNodes[0].childNodes) == 2
1009 and root.childNodes[0].childNodes.length == 2
1010 and len(root.childNodes[1].childNodes) == 2
1011 and root.childNodes[1].childNodes.length == 2
1012 and len(root.childNodes[1].childNodes[0].childNodes) == 1
1013 and root.childNodes[1].childNodes[0].childNodes.length == 1
1014 , "testNormalize2 -- childNodes lengths")
1015 self.confirm(root.childNodes[0].childNodes[1].data == "tx"
1016 and root.childNodes[1].childNodes[0].childNodes[0].data == "t2x2"
1017 and root.childNodes[1].childNodes[1].data == "t3x3"
1018 , "testNormalize2 -- joined text fields")
1019 self.confirm(root.childNodes[0].childNodes[1].nextSibling is None
1020 and root.childNodes[0].childNodes[1].previousSibling
1021 is root.childNodes[0].childNodes[0]
1022 and root.childNodes[0].childNodes[0].previousSibling is None
1023 and root.childNodes[0].childNodes[0].nextSibling
1024 is root.childNodes[0].childNodes[1]
1025 and root.childNodes[1].childNodes[1].nextSibling is None
1026 and root.childNodes[1].childNodes[1].previousSibling
1027 is root.childNodes[1].childNodes[0]
1028 and root.childNodes[1].childNodes[0].previousSibling is None
1029 and root.childNodes[1].childNodes[0].nextSibling
1030 is root.childNodes[1].childNodes[1]
1031 , "testNormalize2 -- sibling pointers")
1032 doc.unlink()
1033
1034
Andrew M. Kuchling688b9e32010-07-25 23:38:47 +00001035 def testBug0777884(self):
1036 doc = parseString("<o>text</o>")
1037 text = doc.documentElement.childNodes[0]
Ezio Melottib3aedd42010-11-20 19:04:17 +00001038 self.assertEqual(text.nodeType, Node.TEXT_NODE)
Andrew M. Kuchling688b9e32010-07-25 23:38:47 +00001039 # Should run quietly, doing nothing.
1040 text.normalize()
1041 doc.unlink()
1042
Christian Heimes05e8be12008-02-23 18:30:17 +00001043 def testBug1433694(self):
1044 doc = parseString("<o><i/>t</o>")
1045 node = doc.documentElement
1046 node.childNodes[1].nodeValue = ""
1047 node.normalize()
Florent Xicluna9b86b9a2010-03-19 19:00:44 +00001048 self.confirm(node.childNodes[-1].nextSibling is None,
Christian Heimes05e8be12008-02-23 18:30:17 +00001049 "Final child's .nextSibling should be None")
1050
Guido van Rossumd8faa362007-04-27 19:54:29 +00001051 def testSiblings(self):
1052 doc = parseString("<doc><?pi?>text?<elm/></doc>")
1053 root = doc.documentElement
1054 (pi, text, elm) = root.childNodes
1055
1056 self.confirm(pi.nextSibling is text and
1057 pi.previousSibling is None and
1058 text.nextSibling is elm and
1059 text.previousSibling is pi and
1060 elm.nextSibling is None and
1061 elm.previousSibling is text, "testSiblings")
1062
1063 doc.unlink()
1064
1065 def testParents(self):
1066 doc = parseString(
1067 "<doc><elm1><elm2/><elm2><elm3/></elm2></elm1></doc>")
1068 root = doc.documentElement
1069 elm1 = root.childNodes[0]
1070 (elm2a, elm2b) = elm1.childNodes
1071 elm3 = elm2b.childNodes[0]
1072
1073 self.confirm(root.parentNode is doc and
1074 elm1.parentNode is root and
1075 elm2a.parentNode is elm1 and
1076 elm2b.parentNode is elm1 and
1077 elm3.parentNode is elm2b, "testParents")
1078 doc.unlink()
1079
1080 def testNodeListItem(self):
1081 doc = parseString("<doc><e/><e/></doc>")
1082 children = doc.childNodes
1083 docelem = children[0]
1084 self.confirm(children[0] is children.item(0)
1085 and children.item(1) is None
1086 and docelem.childNodes.item(0) is docelem.childNodes[0]
1087 and docelem.childNodes.item(1) is docelem.childNodes[1]
1088 and docelem.childNodes.item(0).childNodes.item(0) is None,
1089 "test NodeList.item()")
1090 doc.unlink()
1091
Guido van Rossumd8faa362007-04-27 19:54:29 +00001092 def testEncodings(self):
1093 doc = parseString('<foo>&#x20ac;</foo>')
Guido van Rossum3e1f85e2007-07-27 18:03:11 +00001094 self.assertEqual(doc.toxml(),
1095 '<?xml version="1.0" ?><foo>\u20ac</foo>')
1096 self.assertEqual(doc.toxml('utf-8'),
1097 b'<?xml version="1.0" encoding="utf-8"?><foo>\xe2\x82\xac</foo>')
1098 self.assertEqual(doc.toxml('iso-8859-15'),
1099 b'<?xml version="1.0" encoding="iso-8859-15"?><foo>\xa4</foo>')
Eli Bendersky8a805022012-07-13 09:52:39 +03001100 self.assertEqual(doc.toxml('us-ascii'),
1101 b'<?xml version="1.0" encoding="us-ascii"?><foo>&#8364;</foo>')
1102 self.assertEqual(doc.toxml('utf-16'),
1103 '<?xml version="1.0" encoding="utf-16"?>'
1104 '<foo>\u20ac</foo>'.encode('utf-16'))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001105
Andrew Svetlov737fb892012-12-18 21:14:22 +02001106 # Verify that character decoding errors raise exceptions instead
Guido van Rossumd8faa362007-04-27 19:54:29 +00001107 # of crashing
1108 self.assertRaises(UnicodeDecodeError, parseString,
Guido van Rossum3e1f85e2007-07-27 18:03:11 +00001109 b'<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')
Guido van Rossumd8faa362007-04-27 19:54:29 +00001110
1111 doc.unlink()
1112
1113 class UserDataHandler:
1114 called = 0
1115 def handle(self, operation, key, data, src, dst):
1116 dst.setUserData(key, data + 1, self)
1117 src.setUserData(key, None, None)
1118 self.called = 1
1119
1120 def testUserData(self):
1121 dom = Document()
1122 n = dom.createElement('e')
1123 self.confirm(n.getUserData("foo") is None)
1124 n.setUserData("foo", None, None)
1125 self.confirm(n.getUserData("foo") is None)
1126 n.setUserData("foo", 12, 12)
1127 n.setUserData("bar", 13, 13)
1128 self.confirm(n.getUserData("foo") == 12)
1129 self.confirm(n.getUserData("bar") == 13)
1130 n.setUserData("foo", None, None)
1131 self.confirm(n.getUserData("foo") is None)
1132 self.confirm(n.getUserData("bar") == 13)
1133
1134 handler = self.UserDataHandler()
1135 n.setUserData("bar", 12, handler)
1136 c = n.cloneNode(1)
1137 self.confirm(handler.called
1138 and n.getUserData("bar") is None
1139 and c.getUserData("bar") == 13)
1140 n.unlink()
1141 c.unlink()
1142 dom.unlink()
1143
1144 def checkRenameNodeSharedConstraints(self, doc, node):
1145 # Make sure illegal NS usage is detected:
1146 self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, node,
1147 "http://xml.python.org/ns", "xmlns:foo")
1148 doc2 = parseString("<doc/>")
1149 self.assertRaises(xml.dom.WrongDocumentErr, doc2.renameNode, node,
1150 xml.dom.EMPTY_NAMESPACE, "foo")
1151
1152 def testRenameAttribute(self):
1153 doc = parseString("<doc a='v'/>")
1154 elem = doc.documentElement
1155 attrmap = elem.attributes
1156 attr = elem.attributes['a']
1157
1158 # Simple renaming
1159 attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "b")
1160 self.confirm(attr.name == "b"
1161 and attr.nodeName == "b"
1162 and attr.localName is None
1163 and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
1164 and attr.prefix is None
1165 and attr.value == "v"
1166 and elem.getAttributeNode("a") is None
1167 and elem.getAttributeNode("b").isSameNode(attr)
1168 and attrmap["b"].isSameNode(attr)
1169 and attr.ownerDocument.isSameNode(doc)
1170 and attr.ownerElement.isSameNode(elem))
1171
1172 # Rename to have a namespace, no prefix
1173 attr = doc.renameNode(attr, "http://xml.python.org/ns", "c")
1174 self.confirm(attr.name == "c"
1175 and attr.nodeName == "c"
1176 and attr.localName == "c"
1177 and attr.namespaceURI == "http://xml.python.org/ns"
1178 and attr.prefix is None
1179 and attr.value == "v"
1180 and elem.getAttributeNode("a") is None
1181 and elem.getAttributeNode("b") is None
1182 and elem.getAttributeNode("c").isSameNode(attr)
1183 and elem.getAttributeNodeNS(
1184 "http://xml.python.org/ns", "c").isSameNode(attr)
1185 and attrmap["c"].isSameNode(attr)
1186 and attrmap[("http://xml.python.org/ns", "c")].isSameNode(attr))
1187
1188 # Rename to have a namespace, with prefix
1189 attr = doc.renameNode(attr, "http://xml.python.org/ns2", "p:d")
1190 self.confirm(attr.name == "p:d"
1191 and attr.nodeName == "p:d"
1192 and attr.localName == "d"
1193 and attr.namespaceURI == "http://xml.python.org/ns2"
1194 and attr.prefix == "p"
1195 and attr.value == "v"
1196 and elem.getAttributeNode("a") is None
1197 and elem.getAttributeNode("b") is None
1198 and elem.getAttributeNode("c") is None
1199 and elem.getAttributeNodeNS(
1200 "http://xml.python.org/ns", "c") is None
1201 and elem.getAttributeNode("p:d").isSameNode(attr)
1202 and elem.getAttributeNodeNS(
1203 "http://xml.python.org/ns2", "d").isSameNode(attr)
1204 and attrmap["p:d"].isSameNode(attr)
1205 and attrmap[("http://xml.python.org/ns2", "d")].isSameNode(attr))
1206
1207 # Rename back to a simple non-NS node
1208 attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "e")
1209 self.confirm(attr.name == "e"
1210 and attr.nodeName == "e"
1211 and attr.localName is None
1212 and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
1213 and attr.prefix is None
1214 and attr.value == "v"
1215 and elem.getAttributeNode("a") is None
1216 and elem.getAttributeNode("b") is None
1217 and elem.getAttributeNode("c") is None
1218 and elem.getAttributeNode("p:d") is None
1219 and elem.getAttributeNodeNS(
1220 "http://xml.python.org/ns", "c") is None
1221 and elem.getAttributeNode("e").isSameNode(attr)
1222 and attrmap["e"].isSameNode(attr))
1223
1224 self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, attr,
1225 "http://xml.python.org/ns", "xmlns")
1226 self.checkRenameNodeSharedConstraints(doc, attr)
1227 doc.unlink()
1228
1229 def testRenameElement(self):
1230 doc = parseString("<doc/>")
1231 elem = doc.documentElement
1232
1233 # Simple renaming
1234 elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "a")
1235 self.confirm(elem.tagName == "a"
1236 and elem.nodeName == "a"
1237 and elem.localName is None
1238 and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
1239 and elem.prefix is None
1240 and elem.ownerDocument.isSameNode(doc))
1241
1242 # Rename to have a namespace, no prefix
1243 elem = doc.renameNode(elem, "http://xml.python.org/ns", "b")
1244 self.confirm(elem.tagName == "b"
1245 and elem.nodeName == "b"
1246 and elem.localName == "b"
1247 and elem.namespaceURI == "http://xml.python.org/ns"
1248 and elem.prefix is None
1249 and elem.ownerDocument.isSameNode(doc))
1250
1251 # Rename to have a namespace, with prefix
1252 elem = doc.renameNode(elem, "http://xml.python.org/ns2", "p:c")
1253 self.confirm(elem.tagName == "p:c"
1254 and elem.nodeName == "p:c"
1255 and elem.localName == "c"
1256 and elem.namespaceURI == "http://xml.python.org/ns2"
1257 and elem.prefix == "p"
1258 and elem.ownerDocument.isSameNode(doc))
1259
1260 # Rename back to a simple non-NS node
1261 elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "d")
1262 self.confirm(elem.tagName == "d"
1263 and elem.nodeName == "d"
1264 and elem.localName is None
1265 and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
1266 and elem.prefix is None
1267 and elem.ownerDocument.isSameNode(doc))
1268
1269 self.checkRenameNodeSharedConstraints(doc, elem)
1270 doc.unlink()
1271
1272 def testRenameOther(self):
1273 # We have to create a comment node explicitly since not all DOM
1274 # builders used with minidom add comments to the DOM.
1275 doc = xml.dom.minidom.getDOMImplementation().createDocument(
1276 xml.dom.EMPTY_NAMESPACE, "e", None)
1277 node = doc.createComment("comment")
1278 self.assertRaises(xml.dom.NotSupportedErr, doc.renameNode, node,
1279 xml.dom.EMPTY_NAMESPACE, "foo")
1280 doc.unlink()
1281
1282 def testWholeText(self):
1283 doc = parseString("<doc>a</doc>")
1284 elem = doc.documentElement
1285 text = elem.childNodes[0]
Ezio Melottib3aedd42010-11-20 19:04:17 +00001286 self.assertEqual(text.nodeType, Node.TEXT_NODE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001287
1288 self.checkWholeText(text, "a")
1289 elem.appendChild(doc.createTextNode("b"))
1290 self.checkWholeText(text, "ab")
1291 elem.insertBefore(doc.createCDATASection("c"), text)
1292 self.checkWholeText(text, "cab")
1293
1294 # make sure we don't cross other nodes
1295 splitter = doc.createComment("comment")
1296 elem.appendChild(splitter)
1297 text2 = doc.createTextNode("d")
1298 elem.appendChild(text2)
1299 self.checkWholeText(text, "cab")
1300 self.checkWholeText(text2, "d")
1301
1302 x = doc.createElement("x")
1303 elem.replaceChild(x, splitter)
1304 splitter = x
1305 self.checkWholeText(text, "cab")
1306 self.checkWholeText(text2, "d")
1307
1308 x = doc.createProcessingInstruction("y", "z")
1309 elem.replaceChild(x, splitter)
1310 splitter = x
1311 self.checkWholeText(text, "cab")
1312 self.checkWholeText(text2, "d")
1313
1314 elem.removeChild(splitter)
1315 self.checkWholeText(text, "cabd")
1316 self.checkWholeText(text2, "cabd")
1317
1318 def testPatch1094164(self):
1319 doc = parseString("<doc><e/></doc>")
1320 elem = doc.documentElement
1321 e = elem.firstChild
1322 self.confirm(e.parentNode is elem, "Before replaceChild()")
1323 # Check that replacing a child with itself leaves the tree unchanged
1324 elem.replaceChild(e, e)
1325 self.confirm(e.parentNode is elem, "After replaceChild()")
1326
1327 def testReplaceWholeText(self):
1328 def setup():
1329 doc = parseString("<doc>a<e/>d</doc>")
1330 elem = doc.documentElement
1331 text1 = elem.firstChild
1332 text2 = elem.lastChild
1333 splitter = text1.nextSibling
1334 elem.insertBefore(doc.createTextNode("b"), splitter)
1335 elem.insertBefore(doc.createCDATASection("c"), text1)
1336 return doc, elem, text1, splitter, text2
1337
1338 doc, elem, text1, splitter, text2 = setup()
1339 text = text1.replaceWholeText("new content")
1340 self.checkWholeText(text, "new content")
1341 self.checkWholeText(text2, "d")
1342 self.confirm(len(elem.childNodes) == 3)
1343
1344 doc, elem, text1, splitter, text2 = setup()
1345 text = text2.replaceWholeText("new content")
1346 self.checkWholeText(text, "new content")
1347 self.checkWholeText(text1, "cab")
1348 self.confirm(len(elem.childNodes) == 5)
1349
1350 doc, elem, text1, splitter, text2 = setup()
1351 text = text1.replaceWholeText("")
1352 self.checkWholeText(text2, "d")
1353 self.confirm(text is None
1354 and len(elem.childNodes) == 2)
1355
1356 def testSchemaType(self):
1357 doc = parseString(
1358 "<!DOCTYPE doc [\n"
1359 " <!ENTITY e1 SYSTEM 'http://xml.python.org/e1'>\n"
1360 " <!ENTITY e2 SYSTEM 'http://xml.python.org/e2'>\n"
1361 " <!ATTLIST doc id ID #IMPLIED \n"
1362 " ref IDREF #IMPLIED \n"
1363 " refs IDREFS #IMPLIED \n"
1364 " enum (a|b) #IMPLIED \n"
1365 " ent ENTITY #IMPLIED \n"
1366 " ents ENTITIES #IMPLIED \n"
1367 " nm NMTOKEN #IMPLIED \n"
1368 " nms NMTOKENS #IMPLIED \n"
1369 " text CDATA #IMPLIED \n"
1370 " >\n"
1371 "]><doc id='name' notid='name' text='splat!' enum='b'"
1372 " ref='name' refs='name name' ent='e1' ents='e1 e2'"
1373 " nm='123' nms='123 abc' />")
1374 elem = doc.documentElement
1375 # We don't want to rely on any specific loader at this point, so
1376 # just make sure we can get to all the names, and that the
1377 # DTD-based namespace is right. The names can vary by loader
1378 # since each supports a different level of DTD information.
1379 t = elem.schemaType
1380 self.confirm(t.name is None
1381 and t.namespace == xml.dom.EMPTY_NAMESPACE)
1382 names = "id notid text enum ref refs ent ents nm nms".split()
1383 for name in names:
1384 a = elem.getAttributeNode(name)
1385 t = a.schemaType
1386 self.confirm(hasattr(t, "name")
1387 and t.namespace == xml.dom.EMPTY_NAMESPACE)
1388
1389 def testSetIdAttribute(self):
1390 doc = parseString("<doc a1='v' a2='w'/>")
1391 e = doc.documentElement
1392 a1 = e.getAttributeNode("a1")
1393 a2 = e.getAttributeNode("a2")
1394 self.confirm(doc.getElementById("v") is None
1395 and not a1.isId
1396 and not a2.isId)
1397 e.setIdAttribute("a1")
1398 self.confirm(e.isSameNode(doc.getElementById("v"))
1399 and a1.isId
1400 and not a2.isId)
1401 e.setIdAttribute("a2")
1402 self.confirm(e.isSameNode(doc.getElementById("v"))
1403 and e.isSameNode(doc.getElementById("w"))
1404 and a1.isId
1405 and a2.isId)
1406 # replace the a1 node; the new node should *not* be an ID
1407 a3 = doc.createAttribute("a1")
1408 a3.value = "v"
1409 e.setAttributeNode(a3)
1410 self.confirm(doc.getElementById("v") is None
1411 and e.isSameNode(doc.getElementById("w"))
1412 and not a1.isId
1413 and a2.isId
1414 and not a3.isId)
1415 # renaming an attribute should not affect its ID-ness:
1416 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1417 self.confirm(e.isSameNode(doc.getElementById("w"))
1418 and a2.isId)
1419
1420 def testSetIdAttributeNS(self):
1421 NS1 = "http://xml.python.org/ns1"
1422 NS2 = "http://xml.python.org/ns2"
1423 doc = parseString("<doc"
1424 " xmlns:ns1='" + NS1 + "'"
1425 " xmlns:ns2='" + NS2 + "'"
1426 " ns1:a1='v' ns2:a2='w'/>")
1427 e = doc.documentElement
1428 a1 = e.getAttributeNodeNS(NS1, "a1")
1429 a2 = e.getAttributeNodeNS(NS2, "a2")
1430 self.confirm(doc.getElementById("v") is None
1431 and not a1.isId
1432 and not a2.isId)
1433 e.setIdAttributeNS(NS1, "a1")
1434 self.confirm(e.isSameNode(doc.getElementById("v"))
1435 and a1.isId
1436 and not a2.isId)
1437 e.setIdAttributeNS(NS2, "a2")
1438 self.confirm(e.isSameNode(doc.getElementById("v"))
1439 and e.isSameNode(doc.getElementById("w"))
1440 and a1.isId
1441 and a2.isId)
1442 # replace the a1 node; the new node should *not* be an ID
1443 a3 = doc.createAttributeNS(NS1, "a1")
1444 a3.value = "v"
1445 e.setAttributeNode(a3)
1446 self.confirm(e.isSameNode(doc.getElementById("w")))
1447 self.confirm(not a1.isId)
1448 self.confirm(a2.isId)
1449 self.confirm(not a3.isId)
1450 self.confirm(doc.getElementById("v") is None)
1451 # renaming an attribute should not affect its ID-ness:
1452 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1453 self.confirm(e.isSameNode(doc.getElementById("w"))
1454 and a2.isId)
1455
1456 def testSetIdAttributeNode(self):
1457 NS1 = "http://xml.python.org/ns1"
1458 NS2 = "http://xml.python.org/ns2"
1459 doc = parseString("<doc"
1460 " xmlns:ns1='" + NS1 + "'"
1461 " xmlns:ns2='" + NS2 + "'"
1462 " ns1:a1='v' ns2:a2='w'/>")
1463 e = doc.documentElement
1464 a1 = e.getAttributeNodeNS(NS1, "a1")
1465 a2 = e.getAttributeNodeNS(NS2, "a2")
1466 self.confirm(doc.getElementById("v") is None
1467 and not a1.isId
1468 and not a2.isId)
1469 e.setIdAttributeNode(a1)
1470 self.confirm(e.isSameNode(doc.getElementById("v"))
1471 and a1.isId
1472 and not a2.isId)
1473 e.setIdAttributeNode(a2)
1474 self.confirm(e.isSameNode(doc.getElementById("v"))
1475 and e.isSameNode(doc.getElementById("w"))
1476 and a1.isId
1477 and a2.isId)
1478 # replace the a1 node; the new node should *not* be an ID
1479 a3 = doc.createAttributeNS(NS1, "a1")
1480 a3.value = "v"
1481 e.setAttributeNode(a3)
1482 self.confirm(e.isSameNode(doc.getElementById("w")))
1483 self.confirm(not a1.isId)
1484 self.confirm(a2.isId)
1485 self.confirm(not a3.isId)
1486 self.confirm(doc.getElementById("v") is None)
1487 # renaming an attribute should not affect its ID-ness:
1488 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1489 self.confirm(e.isSameNode(doc.getElementById("w"))
1490 and a2.isId)
1491
Serhiy Storchakac4722462015-11-26 23:49:42 +02001492 def assert_recursive_equal(self, doc, doc2):
1493 stack = [(doc, doc2)]
1494 while stack:
1495 n1, n2 = stack.pop()
1496 self.assertEqual(n1.nodeType, n2.nodeType)
1497 self.assertEqual(len(n1.childNodes), len(n2.childNodes))
1498 self.assertEqual(n1.nodeName, n2.nodeName)
1499 self.assertFalse(n1.isSameNode(n2))
1500 self.assertFalse(n2.isSameNode(n1))
1501 if n1.nodeType == Node.DOCUMENT_TYPE_NODE:
1502 len(n1.entities)
1503 len(n2.entities)
1504 len(n1.notations)
1505 len(n2.notations)
1506 self.assertEqual(len(n1.entities), len(n2.entities))
1507 self.assertEqual(len(n1.notations), len(n2.notations))
1508 for i in range(len(n1.notations)):
1509 # XXX this loop body doesn't seem to be executed?
1510 no1 = n1.notations.item(i)
1511 no2 = n1.notations.item(i)
1512 self.assertEqual(no1.name, no2.name)
1513 self.assertEqual(no1.publicId, no2.publicId)
1514 self.assertEqual(no1.systemId, no2.systemId)
1515 stack.append((no1, no2))
1516 for i in range(len(n1.entities)):
1517 e1 = n1.entities.item(i)
1518 e2 = n2.entities.item(i)
1519 self.assertEqual(e1.notationName, e2.notationName)
1520 self.assertEqual(e1.publicId, e2.publicId)
1521 self.assertEqual(e1.systemId, e2.systemId)
1522 stack.append((e1, e2))
1523 if n1.nodeType != Node.DOCUMENT_NODE:
1524 self.assertTrue(n1.ownerDocument.isSameNode(doc))
1525 self.assertTrue(n2.ownerDocument.isSameNode(doc2))
1526 for i in range(len(n1.childNodes)):
1527 stack.append((n1.childNodes[i], n2.childNodes[i]))
1528
Guido van Rossumd8faa362007-04-27 19:54:29 +00001529 def testPickledDocument(self):
Serhiy Storchakac4722462015-11-26 23:49:42 +02001530 doc = parseString(sample)
Serhiy Storchakabad12572014-12-15 14:03:42 +02001531 for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
1532 s = pickle.dumps(doc, proto)
1533 doc2 = pickle.loads(s)
Serhiy Storchakac4722462015-11-26 23:49:42 +02001534 self.assert_recursive_equal(doc, doc2)
1535
1536 def testDeepcopiedDocument(self):
1537 doc = parseString(sample)
1538 doc2 = copy.deepcopy(doc)
1539 self.assert_recursive_equal(doc, doc2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001540
Benjamin Peterson2b7411d2008-05-26 17:36:47 +00001541 def testSerializeCommentNodeWithDoubleHyphen(self):
1542 doc = create_doc_without_doctype()
1543 doc.appendChild(doc.createComment("foo--bar"))
1544 self.assertRaises(ValueError, doc.toxml)
1545
Benjamin Peterson863a0c32011-03-02 23:40:36 +00001546
Georg Brandlb9cd72a2010-10-15 17:58:45 +00001547 def testEmptyXMLNSValue(self):
1548 doc = parseString("<element xmlns=''>\n"
1549 "<foo/>\n</element>")
1550 doc2 = parseString(doc.toxml())
1551 self.confirm(doc2.namespaceURI == xml.dom.EMPTY_NAMESPACE)
1552
R David Murray9077d242014-04-20 00:46:05 -04001553 def testExceptionOnSpacesInXMLNSValue(self):
1554 with self.assertRaisesRegex(ValueError, 'Unsupported syntax'):
1555 parseString('<element xmlns:abc="http:abc.com/de f g/hi/j k"><abc:foo /></element>')
1556
Raymond Hettinger06eef9c2011-06-25 15:54:52 +02001557 def testDocRemoveChild(self):
1558 doc = parse(tstfile)
1559 title_tag = doc.documentElement.getElementsByTagName("TITLE")[0]
1560 self.assertRaises( xml.dom.NotFoundErr, doc.removeChild, title_tag)
1561 num_children_before = len(doc.childNodes)
1562 doc.removeChild(doc.childNodes[0])
1563 num_children_after = len(doc.childNodes)
1564 self.assertTrue(num_children_after == num_children_before - 1)
Georg Brandlb9cd72a2010-10-15 17:58:45 +00001565
Raymond Hettinger92a40552014-06-15 14:48:19 -07001566 def testProcessingInstructionNameError(self):
1567 # wrong variable in .nodeValue property will
1568 # lead to "NameError: name 'data' is not defined"
1569 doc = parse(tstfile)
1570 pi = doc.createProcessingInstruction("y", "z")
1571 pi.nodeValue = "crash"
1572
Guido van Rossumd8faa362007-04-27 19:54:29 +00001573if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -05001574 unittest.main()