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