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