blob: 0a6013664031d50b5fa47137cfefd34c08d3525c [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
R David Murray791744b2011-10-01 16:19:51 -0400470 def test_toPrettyXML_perserves_content_of_text_node(self):
471 str = '<A>B</A>'
472 dom = parseString(str)
473 dom2 = parseString(dom.toprettyxml())
474 self.assertEqual(dom.childNodes[0].childNodes[0].toxml(),
475 dom2.childNodes[0].childNodes[0].toxml())
476
Guido van Rossumd8faa362007-04-27 19:54:29 +0000477 def testProcessingInstruction(self):
478 dom = parseString('<e><?mypi \t\n data \t\n ?></e>')
479 pi = dom.documentElement.firstChild
480 self.confirm(pi.target == "mypi"
481 and pi.data == "data \t\n "
482 and pi.nodeName == "mypi"
483 and pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE
484 and pi.attributes is None
485 and not pi.hasChildNodes()
486 and len(pi.childNodes) == 0
487 and pi.firstChild is None
488 and pi.lastChild is None
489 and pi.localName is None
490 and pi.namespaceURI == xml.dom.EMPTY_NAMESPACE)
491
492 def testProcessingInstructionRepr(self): pass
493
494 def testTextRepr(self): pass
495
496 def testWriteText(self): pass
497
498 def testDocumentElement(self): pass
499
500 def testTooManyDocumentElements(self):
501 doc = parseString("<doc/>")
502 elem = doc.createElement("extra")
503 # Should raise an exception when adding an extra document element.
504 self.assertRaises(xml.dom.HierarchyRequestErr, doc.appendChild, elem)
505 elem.unlink()
506 doc.unlink()
507
508 def testCreateElementNS(self): pass
509
510 def testCreateAttributeNS(self): pass
511
512 def testParse(self): pass
513
514 def testParseString(self): pass
515
516 def testComment(self): pass
517
518 def testAttrListItem(self): pass
519
520 def testAttrListItems(self): pass
521
522 def testAttrListItemNS(self): pass
523
524 def testAttrListKeys(self): pass
525
526 def testAttrListKeysNS(self): pass
527
528 def testRemoveNamedItem(self):
529 doc = parseString("<doc a=''/>")
530 e = doc.documentElement
531 attrs = e.attributes
532 a1 = e.getAttributeNode("a")
533 a2 = attrs.removeNamedItem("a")
534 self.confirm(a1.isSameNode(a2))
535 self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItem, "a")
536
537 def testRemoveNamedItemNS(self):
538 doc = parseString("<doc xmlns:a='http://xml.python.org/' a:b=''/>")
539 e = doc.documentElement
540 attrs = e.attributes
541 a1 = e.getAttributeNodeNS("http://xml.python.org/", "b")
542 a2 = attrs.removeNamedItemNS("http://xml.python.org/", "b")
543 self.confirm(a1.isSameNode(a2))
544 self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItemNS,
545 "http://xml.python.org/", "b")
546
547 def testAttrListValues(self): pass
548
549 def testAttrListLength(self): pass
550
551 def testAttrList__getitem__(self): pass
552
553 def testAttrList__setitem__(self): pass
554
555 def testSetAttrValueandNodeValue(self): pass
556
557 def testParseElement(self): pass
558
559 def testParseAttributes(self): pass
560
561 def testParseElementNamespaces(self): pass
562
563 def testParseAttributeNamespaces(self): pass
564
565 def testParseProcessingInstructions(self): pass
566
567 def testChildNodes(self): pass
568
569 def testFirstChild(self): pass
570
Raymond Hettinger06eef9c2011-06-25 15:54:52 +0200571 def testHasChildNodes(self):
572 dom = parseString("<doc><foo/></doc>")
573 doc = dom.documentElement
574 self.assertTrue(dom.hasChildNodes())
575 dom2 = parseString("<doc/>")
576 doc2 = dom2.documentElement
577 self.assertFalse(doc2.hasChildNodes())
Guido van Rossumd8faa362007-04-27 19:54:29 +0000578
579 def _testCloneElementCopiesAttributes(self, e1, e2, test):
580 attrs1 = e1.attributes
581 attrs2 = e2.attributes
582 keys1 = list(attrs1.keys())
583 keys2 = list(attrs2.keys())
584 keys1.sort()
585 keys2.sort()
586 self.confirm(keys1 == keys2, "clone of element has same attribute keys")
587 for i in range(len(keys1)):
588 a1 = attrs1.item(i)
589 a2 = attrs2.item(i)
590 self.confirm(a1 is not a2
591 and a1.value == a2.value
592 and a1.nodeValue == a2.nodeValue
593 and a1.namespaceURI == a2.namespaceURI
594 and a1.localName == a2.localName
595 , "clone of attribute node has proper attribute values")
596 self.confirm(a2.ownerElement is e2,
597 "clone of attribute node correctly owned")
598
599 def _setupCloneElement(self, deep):
600 dom = parseString("<doc attr='value'><foo/></doc>")
601 root = dom.documentElement
602 clone = root.cloneNode(deep)
603 self._testCloneElementCopiesAttributes(
604 root, clone, "testCloneElement" + (deep and "Deep" or "Shallow"))
605 # mutilate the original so shared data is detected
606 root.tagName = root.nodeName = "MODIFIED"
607 root.setAttribute("attr", "NEW VALUE")
608 root.setAttribute("added", "VALUE")
609 return dom, clone
610
611 def testCloneElementShallow(self):
612 dom, clone = self._setupCloneElement(0)
613 self.confirm(len(clone.childNodes) == 0
614 and clone.childNodes.length == 0
615 and clone.parentNode is None
616 and clone.toxml() == '<doc attr="value"/>'
617 , "testCloneElementShallow")
618 dom.unlink()
619
620 def testCloneElementDeep(self):
621 dom, clone = self._setupCloneElement(1)
622 self.confirm(len(clone.childNodes) == 1
623 and clone.childNodes.length == 1
624 and clone.parentNode is None
625 and clone.toxml() == '<doc attr="value"><foo/></doc>'
626 , "testCloneElementDeep")
627 dom.unlink()
628
629 def testCloneDocumentShallow(self):
630 doc = parseString("<?xml version='1.0'?>\n"
631 "<!-- comment -->"
632 "<!DOCTYPE doc [\n"
633 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
634 "]>\n"
635 "<doc attr='value'/>")
636 doc2 = doc.cloneNode(0)
637 self.confirm(doc2 is None,
638 "testCloneDocumentShallow:"
639 " shallow cloning of documents makes no sense!")
640
641 def testCloneDocumentDeep(self):
642 doc = parseString("<?xml version='1.0'?>\n"
643 "<!-- comment -->"
644 "<!DOCTYPE doc [\n"
645 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
646 "]>\n"
647 "<doc attr='value'/>")
648 doc2 = doc.cloneNode(1)
649 self.confirm(not (doc.isSameNode(doc2) or doc2.isSameNode(doc)),
650 "testCloneDocumentDeep: document objects not distinct")
651 self.confirm(len(doc.childNodes) == len(doc2.childNodes),
652 "testCloneDocumentDeep: wrong number of Document children")
653 self.confirm(doc2.documentElement.nodeType == Node.ELEMENT_NODE,
654 "testCloneDocumentDeep: documentElement not an ELEMENT_NODE")
655 self.confirm(doc2.documentElement.ownerDocument.isSameNode(doc2),
656 "testCloneDocumentDeep: documentElement owner is not new document")
657 self.confirm(not doc.documentElement.isSameNode(doc2.documentElement),
658 "testCloneDocumentDeep: documentElement should not be shared")
659 if doc.doctype is not None:
660 # check the doctype iff the original DOM maintained it
661 self.confirm(doc2.doctype.nodeType == Node.DOCUMENT_TYPE_NODE,
662 "testCloneDocumentDeep: doctype not a DOCUMENT_TYPE_NODE")
663 self.confirm(doc2.doctype.ownerDocument.isSameNode(doc2))
664 self.confirm(not doc.doctype.isSameNode(doc2.doctype))
665
666 def testCloneDocumentTypeDeepOk(self):
667 doctype = create_nonempty_doctype()
668 clone = doctype.cloneNode(1)
669 self.confirm(clone is not None
670 and clone.nodeName == doctype.nodeName
671 and clone.name == doctype.name
672 and clone.publicId == doctype.publicId
673 and clone.systemId == doctype.systemId
674 and len(clone.entities) == len(doctype.entities)
675 and clone.entities.item(len(clone.entities)) is None
676 and len(clone.notations) == len(doctype.notations)
677 and clone.notations.item(len(clone.notations)) is None
678 and len(clone.childNodes) == 0)
679 for i in range(len(doctype.entities)):
680 se = doctype.entities.item(i)
681 ce = clone.entities.item(i)
682 self.confirm((not se.isSameNode(ce))
683 and (not ce.isSameNode(se))
684 and ce.nodeName == se.nodeName
685 and ce.notationName == se.notationName
686 and ce.publicId == se.publicId
687 and ce.systemId == se.systemId
688 and ce.encoding == se.encoding
689 and ce.actualEncoding == se.actualEncoding
690 and ce.version == se.version)
691 for i in range(len(doctype.notations)):
692 sn = doctype.notations.item(i)
693 cn = clone.notations.item(i)
694 self.confirm((not sn.isSameNode(cn))
695 and (not cn.isSameNode(sn))
696 and cn.nodeName == sn.nodeName
697 and cn.publicId == sn.publicId
698 and cn.systemId == sn.systemId)
699
700 def testCloneDocumentTypeDeepNotOk(self):
701 doc = create_doc_with_doctype()
702 clone = doc.doctype.cloneNode(1)
703 self.confirm(clone is None, "testCloneDocumentTypeDeepNotOk")
704
705 def testCloneDocumentTypeShallowOk(self):
706 doctype = create_nonempty_doctype()
707 clone = doctype.cloneNode(0)
708 self.confirm(clone is not None
709 and clone.nodeName == doctype.nodeName
710 and clone.name == doctype.name
711 and clone.publicId == doctype.publicId
712 and clone.systemId == doctype.systemId
713 and len(clone.entities) == 0
714 and clone.entities.item(0) is None
715 and len(clone.notations) == 0
716 and clone.notations.item(0) is None
717 and len(clone.childNodes) == 0)
718
719 def testCloneDocumentTypeShallowNotOk(self):
720 doc = create_doc_with_doctype()
721 clone = doc.doctype.cloneNode(0)
722 self.confirm(clone is None, "testCloneDocumentTypeShallowNotOk")
723
724 def check_import_document(self, deep, testName):
725 doc1 = parseString("<doc/>")
726 doc2 = parseString("<doc/>")
727 self.assertRaises(xml.dom.NotSupportedErr, doc1.importNode, doc2, deep)
728
729 def testImportDocumentShallow(self):
730 self.check_import_document(0, "testImportDocumentShallow")
731
732 def testImportDocumentDeep(self):
733 self.check_import_document(1, "testImportDocumentDeep")
734
735 def testImportDocumentTypeShallow(self):
736 src = create_doc_with_doctype()
737 target = create_doc_without_doctype()
738 self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
739 src.doctype, 0)
740
741 def testImportDocumentTypeDeep(self):
742 src = create_doc_with_doctype()
743 target = create_doc_without_doctype()
744 self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
745 src.doctype, 1)
746
747 # Testing attribute clones uses a helper, and should always be deep,
748 # even if the argument to cloneNode is false.
749 def check_clone_attribute(self, deep, testName):
750 doc = parseString("<doc attr='value'/>")
751 attr = doc.documentElement.getAttributeNode("attr")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000752 self.assertNotEqual(attr, None)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000753 clone = attr.cloneNode(deep)
754 self.confirm(not clone.isSameNode(attr))
755 self.confirm(not attr.isSameNode(clone))
756 self.confirm(clone.ownerElement is None,
757 testName + ": ownerElement should be None")
758 self.confirm(clone.ownerDocument.isSameNode(attr.ownerDocument),
759 testName + ": ownerDocument does not match")
760 self.confirm(clone.specified,
761 testName + ": cloned attribute must have specified == True")
762
763 def testCloneAttributeShallow(self):
764 self.check_clone_attribute(0, "testCloneAttributeShallow")
765
766 def testCloneAttributeDeep(self):
767 self.check_clone_attribute(1, "testCloneAttributeDeep")
768
769 def check_clone_pi(self, deep, testName):
770 doc = parseString("<?target data?><doc/>")
771 pi = doc.firstChild
Ezio Melottib3aedd42010-11-20 19:04:17 +0000772 self.assertEqual(pi.nodeType, Node.PROCESSING_INSTRUCTION_NODE)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000773 clone = pi.cloneNode(deep)
774 self.confirm(clone.target == pi.target
775 and clone.data == pi.data)
776
777 def testClonePIShallow(self):
778 self.check_clone_pi(0, "testClonePIShallow")
779
780 def testClonePIDeep(self):
781 self.check_clone_pi(1, "testClonePIDeep")
782
783 def testNormalize(self):
784 doc = parseString("<doc/>")
785 root = doc.documentElement
786 root.appendChild(doc.createTextNode("first"))
787 root.appendChild(doc.createTextNode("second"))
788 self.confirm(len(root.childNodes) == 2
789 and root.childNodes.length == 2,
790 "testNormalize -- preparation")
791 doc.normalize()
792 self.confirm(len(root.childNodes) == 1
793 and root.childNodes.length == 1
794 and root.firstChild is root.lastChild
795 and root.firstChild.data == "firstsecond"
796 , "testNormalize -- result")
797 doc.unlink()
798
799 doc = parseString("<doc/>")
800 root = doc.documentElement
801 root.appendChild(doc.createTextNode(""))
802 doc.normalize()
803 self.confirm(len(root.childNodes) == 0
804 and root.childNodes.length == 0,
805 "testNormalize -- single empty node removed")
806 doc.unlink()
807
R. David Murraydc6da8a2009-04-09 22:16:43 +0000808 def testNormalizeCombineAndNextSibling(self):
809 doc = parseString("<doc/>")
810 root = doc.documentElement
811 root.appendChild(doc.createTextNode("first"))
812 root.appendChild(doc.createTextNode("second"))
813 root.appendChild(doc.createElement("i"))
814 self.confirm(len(root.childNodes) == 3
815 and root.childNodes.length == 3,
816 "testNormalizeCombineAndNextSibling -- preparation")
817 doc.normalize()
818 self.confirm(len(root.childNodes) == 2
819 and root.childNodes.length == 2
820 and root.firstChild.data == "firstsecond"
821 and root.firstChild is not root.lastChild
822 and root.firstChild.nextSibling is root.lastChild
823 and root.firstChild.previousSibling is None
824 and root.lastChild.previousSibling is root.firstChild
825 and root.lastChild.nextSibling is None
826 , "testNormalizeCombinedAndNextSibling -- result")
827 doc.unlink()
828
829 def testNormalizeDeleteWithPrevSibling(self):
830 doc = parseString("<doc/>")
831 root = doc.documentElement
832 root.appendChild(doc.createTextNode("first"))
833 root.appendChild(doc.createTextNode(""))
834 self.confirm(len(root.childNodes) == 2
835 and root.childNodes.length == 2,
836 "testNormalizeDeleteWithPrevSibling -- preparation")
837 doc.normalize()
838 self.confirm(len(root.childNodes) == 1
839 and root.childNodes.length == 1
840 and root.firstChild.data == "first"
841 and root.firstChild is root.lastChild
842 and root.firstChild.nextSibling is None
843 and root.firstChild.previousSibling is None
844 , "testNormalizeDeleteWithPrevSibling -- result")
845 doc.unlink()
846
847 def testNormalizeDeleteWithNextSibling(self):
848 doc = parseString("<doc/>")
849 root = doc.documentElement
850 root.appendChild(doc.createTextNode(""))
851 root.appendChild(doc.createTextNode("second"))
852 self.confirm(len(root.childNodes) == 2
853 and root.childNodes.length == 2,
854 "testNormalizeDeleteWithNextSibling -- preparation")
855 doc.normalize()
856 self.confirm(len(root.childNodes) == 1
857 and root.childNodes.length == 1
858 and root.firstChild.data == "second"
859 and root.firstChild is root.lastChild
860 and root.firstChild.nextSibling is None
861 and root.firstChild.previousSibling is None
862 , "testNormalizeDeleteWithNextSibling -- result")
863 doc.unlink()
864
865 def testNormalizeDeleteWithTwoNonTextSiblings(self):
866 doc = parseString("<doc/>")
867 root = doc.documentElement
868 root.appendChild(doc.createElement("i"))
869 root.appendChild(doc.createTextNode(""))
870 root.appendChild(doc.createElement("i"))
871 self.confirm(len(root.childNodes) == 3
872 and root.childNodes.length == 3,
873 "testNormalizeDeleteWithTwoSiblings -- preparation")
874 doc.normalize()
875 self.confirm(len(root.childNodes) == 2
876 and root.childNodes.length == 2
877 and root.firstChild is not root.lastChild
878 and root.firstChild.nextSibling is root.lastChild
879 and root.firstChild.previousSibling is None
880 and root.lastChild.previousSibling is root.firstChild
881 and root.lastChild.nextSibling is None
882 , "testNormalizeDeleteWithTwoSiblings -- result")
883 doc.unlink()
884
885 def testNormalizeDeleteAndCombine(self):
886 doc = parseString("<doc/>")
887 root = doc.documentElement
888 root.appendChild(doc.createTextNode(""))
889 root.appendChild(doc.createTextNode("second"))
890 root.appendChild(doc.createTextNode(""))
891 root.appendChild(doc.createTextNode("fourth"))
892 root.appendChild(doc.createTextNode(""))
893 self.confirm(len(root.childNodes) == 5
894 and root.childNodes.length == 5,
895 "testNormalizeDeleteAndCombine -- preparation")
896 doc.normalize()
897 self.confirm(len(root.childNodes) == 1
898 and root.childNodes.length == 1
899 and root.firstChild is root.lastChild
900 and root.firstChild.data == "secondfourth"
901 and root.firstChild.previousSibling is None
902 and root.firstChild.nextSibling is None
903 , "testNormalizeDeleteAndCombine -- result")
904 doc.unlink()
905
906 def testNormalizeRecursion(self):
907 doc = parseString("<doc>"
908 "<o>"
909 "<i/>"
910 "t"
911 #
912 #x
913 "</o>"
914 "<o>"
915 "<o>"
916 "t2"
917 #x2
918 "</o>"
919 "t3"
920 #x3
921 "</o>"
922 #
923 "</doc>")
924 root = doc.documentElement
925 root.childNodes[0].appendChild(doc.createTextNode(""))
926 root.childNodes[0].appendChild(doc.createTextNode("x"))
927 root.childNodes[1].childNodes[0].appendChild(doc.createTextNode("x2"))
928 root.childNodes[1].appendChild(doc.createTextNode("x3"))
929 root.appendChild(doc.createTextNode(""))
930 self.confirm(len(root.childNodes) == 3
931 and root.childNodes.length == 3
932 and len(root.childNodes[0].childNodes) == 4
933 and root.childNodes[0].childNodes.length == 4
934 and len(root.childNodes[1].childNodes) == 3
935 and root.childNodes[1].childNodes.length == 3
936 and len(root.childNodes[1].childNodes[0].childNodes) == 2
937 and root.childNodes[1].childNodes[0].childNodes.length == 2
938 , "testNormalize2 -- preparation")
939 doc.normalize()
940 self.confirm(len(root.childNodes) == 2
941 and root.childNodes.length == 2
942 and len(root.childNodes[0].childNodes) == 2
943 and root.childNodes[0].childNodes.length == 2
944 and len(root.childNodes[1].childNodes) == 2
945 and root.childNodes[1].childNodes.length == 2
946 and len(root.childNodes[1].childNodes[0].childNodes) == 1
947 and root.childNodes[1].childNodes[0].childNodes.length == 1
948 , "testNormalize2 -- childNodes lengths")
949 self.confirm(root.childNodes[0].childNodes[1].data == "tx"
950 and root.childNodes[1].childNodes[0].childNodes[0].data == "t2x2"
951 and root.childNodes[1].childNodes[1].data == "t3x3"
952 , "testNormalize2 -- joined text fields")
953 self.confirm(root.childNodes[0].childNodes[1].nextSibling is None
954 and root.childNodes[0].childNodes[1].previousSibling
955 is root.childNodes[0].childNodes[0]
956 and root.childNodes[0].childNodes[0].previousSibling is None
957 and root.childNodes[0].childNodes[0].nextSibling
958 is root.childNodes[0].childNodes[1]
959 and root.childNodes[1].childNodes[1].nextSibling is None
960 and root.childNodes[1].childNodes[1].previousSibling
961 is root.childNodes[1].childNodes[0]
962 and root.childNodes[1].childNodes[0].previousSibling is None
963 and root.childNodes[1].childNodes[0].nextSibling
964 is root.childNodes[1].childNodes[1]
965 , "testNormalize2 -- sibling pointers")
966 doc.unlink()
967
968
Andrew M. Kuchling688b9e32010-07-25 23:38:47 +0000969 def testBug0777884(self):
970 doc = parseString("<o>text</o>")
971 text = doc.documentElement.childNodes[0]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000972 self.assertEqual(text.nodeType, Node.TEXT_NODE)
Andrew M. Kuchling688b9e32010-07-25 23:38:47 +0000973 # Should run quietly, doing nothing.
974 text.normalize()
975 doc.unlink()
976
Christian Heimes05e8be12008-02-23 18:30:17 +0000977 def testBug1433694(self):
978 doc = parseString("<o><i/>t</o>")
979 node = doc.documentElement
980 node.childNodes[1].nodeValue = ""
981 node.normalize()
Florent Xicluna9b86b9a2010-03-19 19:00:44 +0000982 self.confirm(node.childNodes[-1].nextSibling is None,
Christian Heimes05e8be12008-02-23 18:30:17 +0000983 "Final child's .nextSibling should be None")
984
Guido van Rossumd8faa362007-04-27 19:54:29 +0000985 def testSiblings(self):
986 doc = parseString("<doc><?pi?>text?<elm/></doc>")
987 root = doc.documentElement
988 (pi, text, elm) = root.childNodes
989
990 self.confirm(pi.nextSibling is text and
991 pi.previousSibling is None and
992 text.nextSibling is elm and
993 text.previousSibling is pi and
994 elm.nextSibling is None and
995 elm.previousSibling is text, "testSiblings")
996
997 doc.unlink()
998
999 def testParents(self):
1000 doc = parseString(
1001 "<doc><elm1><elm2/><elm2><elm3/></elm2></elm1></doc>")
1002 root = doc.documentElement
1003 elm1 = root.childNodes[0]
1004 (elm2a, elm2b) = elm1.childNodes
1005 elm3 = elm2b.childNodes[0]
1006
1007 self.confirm(root.parentNode is doc and
1008 elm1.parentNode is root and
1009 elm2a.parentNode is elm1 and
1010 elm2b.parentNode is elm1 and
1011 elm3.parentNode is elm2b, "testParents")
1012 doc.unlink()
1013
1014 def testNodeListItem(self):
1015 doc = parseString("<doc><e/><e/></doc>")
1016 children = doc.childNodes
1017 docelem = children[0]
1018 self.confirm(children[0] is children.item(0)
1019 and children.item(1) is None
1020 and docelem.childNodes.item(0) is docelem.childNodes[0]
1021 and docelem.childNodes.item(1) is docelem.childNodes[1]
1022 and docelem.childNodes.item(0).childNodes.item(0) is None,
1023 "test NodeList.item()")
1024 doc.unlink()
1025
Guido van Rossumd8faa362007-04-27 19:54:29 +00001026 def testEncodings(self):
1027 doc = parseString('<foo>&#x20ac;</foo>')
Guido van Rossum3e1f85e2007-07-27 18:03:11 +00001028 self.assertEqual(doc.toxml(),
1029 '<?xml version="1.0" ?><foo>\u20ac</foo>')
1030 self.assertEqual(doc.toxml('utf-8'),
1031 b'<?xml version="1.0" encoding="utf-8"?><foo>\xe2\x82\xac</foo>')
1032 self.assertEqual(doc.toxml('iso-8859-15'),
1033 b'<?xml version="1.0" encoding="iso-8859-15"?><foo>\xa4</foo>')
Guido van Rossumd8faa362007-04-27 19:54:29 +00001034
1035 # Verify that character decoding errors throw exceptions instead
1036 # of crashing
1037 self.assertRaises(UnicodeDecodeError, parseString,
Guido van Rossum3e1f85e2007-07-27 18:03:11 +00001038 b'<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')
Guido van Rossumd8faa362007-04-27 19:54:29 +00001039
1040 doc.unlink()
1041
1042 class UserDataHandler:
1043 called = 0
1044 def handle(self, operation, key, data, src, dst):
1045 dst.setUserData(key, data + 1, self)
1046 src.setUserData(key, None, None)
1047 self.called = 1
1048
1049 def testUserData(self):
1050 dom = Document()
1051 n = dom.createElement('e')
1052 self.confirm(n.getUserData("foo") is None)
1053 n.setUserData("foo", None, None)
1054 self.confirm(n.getUserData("foo") is None)
1055 n.setUserData("foo", 12, 12)
1056 n.setUserData("bar", 13, 13)
1057 self.confirm(n.getUserData("foo") == 12)
1058 self.confirm(n.getUserData("bar") == 13)
1059 n.setUserData("foo", None, None)
1060 self.confirm(n.getUserData("foo") is None)
1061 self.confirm(n.getUserData("bar") == 13)
1062
1063 handler = self.UserDataHandler()
1064 n.setUserData("bar", 12, handler)
1065 c = n.cloneNode(1)
1066 self.confirm(handler.called
1067 and n.getUserData("bar") is None
1068 and c.getUserData("bar") == 13)
1069 n.unlink()
1070 c.unlink()
1071 dom.unlink()
1072
1073 def checkRenameNodeSharedConstraints(self, doc, node):
1074 # Make sure illegal NS usage is detected:
1075 self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, node,
1076 "http://xml.python.org/ns", "xmlns:foo")
1077 doc2 = parseString("<doc/>")
1078 self.assertRaises(xml.dom.WrongDocumentErr, doc2.renameNode, node,
1079 xml.dom.EMPTY_NAMESPACE, "foo")
1080
1081 def testRenameAttribute(self):
1082 doc = parseString("<doc a='v'/>")
1083 elem = doc.documentElement
1084 attrmap = elem.attributes
1085 attr = elem.attributes['a']
1086
1087 # Simple renaming
1088 attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "b")
1089 self.confirm(attr.name == "b"
1090 and attr.nodeName == "b"
1091 and attr.localName is None
1092 and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
1093 and attr.prefix is None
1094 and attr.value == "v"
1095 and elem.getAttributeNode("a") is None
1096 and elem.getAttributeNode("b").isSameNode(attr)
1097 and attrmap["b"].isSameNode(attr)
1098 and attr.ownerDocument.isSameNode(doc)
1099 and attr.ownerElement.isSameNode(elem))
1100
1101 # Rename to have a namespace, no prefix
1102 attr = doc.renameNode(attr, "http://xml.python.org/ns", "c")
1103 self.confirm(attr.name == "c"
1104 and attr.nodeName == "c"
1105 and attr.localName == "c"
1106 and attr.namespaceURI == "http://xml.python.org/ns"
1107 and attr.prefix is None
1108 and attr.value == "v"
1109 and elem.getAttributeNode("a") is None
1110 and elem.getAttributeNode("b") is None
1111 and elem.getAttributeNode("c").isSameNode(attr)
1112 and elem.getAttributeNodeNS(
1113 "http://xml.python.org/ns", "c").isSameNode(attr)
1114 and attrmap["c"].isSameNode(attr)
1115 and attrmap[("http://xml.python.org/ns", "c")].isSameNode(attr))
1116
1117 # Rename to have a namespace, with prefix
1118 attr = doc.renameNode(attr, "http://xml.python.org/ns2", "p:d")
1119 self.confirm(attr.name == "p:d"
1120 and attr.nodeName == "p:d"
1121 and attr.localName == "d"
1122 and attr.namespaceURI == "http://xml.python.org/ns2"
1123 and attr.prefix == "p"
1124 and attr.value == "v"
1125 and elem.getAttributeNode("a") is None
1126 and elem.getAttributeNode("b") is None
1127 and elem.getAttributeNode("c") is None
1128 and elem.getAttributeNodeNS(
1129 "http://xml.python.org/ns", "c") is None
1130 and elem.getAttributeNode("p:d").isSameNode(attr)
1131 and elem.getAttributeNodeNS(
1132 "http://xml.python.org/ns2", "d").isSameNode(attr)
1133 and attrmap["p:d"].isSameNode(attr)
1134 and attrmap[("http://xml.python.org/ns2", "d")].isSameNode(attr))
1135
1136 # Rename back to a simple non-NS node
1137 attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "e")
1138 self.confirm(attr.name == "e"
1139 and attr.nodeName == "e"
1140 and attr.localName is None
1141 and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
1142 and attr.prefix is None
1143 and attr.value == "v"
1144 and elem.getAttributeNode("a") is None
1145 and elem.getAttributeNode("b") is None
1146 and elem.getAttributeNode("c") is None
1147 and elem.getAttributeNode("p:d") is None
1148 and elem.getAttributeNodeNS(
1149 "http://xml.python.org/ns", "c") is None
1150 and elem.getAttributeNode("e").isSameNode(attr)
1151 and attrmap["e"].isSameNode(attr))
1152
1153 self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, attr,
1154 "http://xml.python.org/ns", "xmlns")
1155 self.checkRenameNodeSharedConstraints(doc, attr)
1156 doc.unlink()
1157
1158 def testRenameElement(self):
1159 doc = parseString("<doc/>")
1160 elem = doc.documentElement
1161
1162 # Simple renaming
1163 elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "a")
1164 self.confirm(elem.tagName == "a"
1165 and elem.nodeName == "a"
1166 and elem.localName is None
1167 and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
1168 and elem.prefix is None
1169 and elem.ownerDocument.isSameNode(doc))
1170
1171 # Rename to have a namespace, no prefix
1172 elem = doc.renameNode(elem, "http://xml.python.org/ns", "b")
1173 self.confirm(elem.tagName == "b"
1174 and elem.nodeName == "b"
1175 and elem.localName == "b"
1176 and elem.namespaceURI == "http://xml.python.org/ns"
1177 and elem.prefix is None
1178 and elem.ownerDocument.isSameNode(doc))
1179
1180 # Rename to have a namespace, with prefix
1181 elem = doc.renameNode(elem, "http://xml.python.org/ns2", "p:c")
1182 self.confirm(elem.tagName == "p:c"
1183 and elem.nodeName == "p:c"
1184 and elem.localName == "c"
1185 and elem.namespaceURI == "http://xml.python.org/ns2"
1186 and elem.prefix == "p"
1187 and elem.ownerDocument.isSameNode(doc))
1188
1189 # Rename back to a simple non-NS node
1190 elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "d")
1191 self.confirm(elem.tagName == "d"
1192 and elem.nodeName == "d"
1193 and elem.localName is None
1194 and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
1195 and elem.prefix is None
1196 and elem.ownerDocument.isSameNode(doc))
1197
1198 self.checkRenameNodeSharedConstraints(doc, elem)
1199 doc.unlink()
1200
1201 def testRenameOther(self):
1202 # We have to create a comment node explicitly since not all DOM
1203 # builders used with minidom add comments to the DOM.
1204 doc = xml.dom.minidom.getDOMImplementation().createDocument(
1205 xml.dom.EMPTY_NAMESPACE, "e", None)
1206 node = doc.createComment("comment")
1207 self.assertRaises(xml.dom.NotSupportedErr, doc.renameNode, node,
1208 xml.dom.EMPTY_NAMESPACE, "foo")
1209 doc.unlink()
1210
1211 def testWholeText(self):
1212 doc = parseString("<doc>a</doc>")
1213 elem = doc.documentElement
1214 text = elem.childNodes[0]
Ezio Melottib3aedd42010-11-20 19:04:17 +00001215 self.assertEqual(text.nodeType, Node.TEXT_NODE)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001216
1217 self.checkWholeText(text, "a")
1218 elem.appendChild(doc.createTextNode("b"))
1219 self.checkWholeText(text, "ab")
1220 elem.insertBefore(doc.createCDATASection("c"), text)
1221 self.checkWholeText(text, "cab")
1222
1223 # make sure we don't cross other nodes
1224 splitter = doc.createComment("comment")
1225 elem.appendChild(splitter)
1226 text2 = doc.createTextNode("d")
1227 elem.appendChild(text2)
1228 self.checkWholeText(text, "cab")
1229 self.checkWholeText(text2, "d")
1230
1231 x = doc.createElement("x")
1232 elem.replaceChild(x, splitter)
1233 splitter = x
1234 self.checkWholeText(text, "cab")
1235 self.checkWholeText(text2, "d")
1236
1237 x = doc.createProcessingInstruction("y", "z")
1238 elem.replaceChild(x, splitter)
1239 splitter = x
1240 self.checkWholeText(text, "cab")
1241 self.checkWholeText(text2, "d")
1242
1243 elem.removeChild(splitter)
1244 self.checkWholeText(text, "cabd")
1245 self.checkWholeText(text2, "cabd")
1246
1247 def testPatch1094164(self):
1248 doc = parseString("<doc><e/></doc>")
1249 elem = doc.documentElement
1250 e = elem.firstChild
1251 self.confirm(e.parentNode is elem, "Before replaceChild()")
1252 # Check that replacing a child with itself leaves the tree unchanged
1253 elem.replaceChild(e, e)
1254 self.confirm(e.parentNode is elem, "After replaceChild()")
1255
1256 def testReplaceWholeText(self):
1257 def setup():
1258 doc = parseString("<doc>a<e/>d</doc>")
1259 elem = doc.documentElement
1260 text1 = elem.firstChild
1261 text2 = elem.lastChild
1262 splitter = text1.nextSibling
1263 elem.insertBefore(doc.createTextNode("b"), splitter)
1264 elem.insertBefore(doc.createCDATASection("c"), text1)
1265 return doc, elem, text1, splitter, text2
1266
1267 doc, elem, text1, splitter, text2 = setup()
1268 text = text1.replaceWholeText("new content")
1269 self.checkWholeText(text, "new content")
1270 self.checkWholeText(text2, "d")
1271 self.confirm(len(elem.childNodes) == 3)
1272
1273 doc, elem, text1, splitter, text2 = setup()
1274 text = text2.replaceWholeText("new content")
1275 self.checkWholeText(text, "new content")
1276 self.checkWholeText(text1, "cab")
1277 self.confirm(len(elem.childNodes) == 5)
1278
1279 doc, elem, text1, splitter, text2 = setup()
1280 text = text1.replaceWholeText("")
1281 self.checkWholeText(text2, "d")
1282 self.confirm(text is None
1283 and len(elem.childNodes) == 2)
1284
1285 def testSchemaType(self):
1286 doc = parseString(
1287 "<!DOCTYPE doc [\n"
1288 " <!ENTITY e1 SYSTEM 'http://xml.python.org/e1'>\n"
1289 " <!ENTITY e2 SYSTEM 'http://xml.python.org/e2'>\n"
1290 " <!ATTLIST doc id ID #IMPLIED \n"
1291 " ref IDREF #IMPLIED \n"
1292 " refs IDREFS #IMPLIED \n"
1293 " enum (a|b) #IMPLIED \n"
1294 " ent ENTITY #IMPLIED \n"
1295 " ents ENTITIES #IMPLIED \n"
1296 " nm NMTOKEN #IMPLIED \n"
1297 " nms NMTOKENS #IMPLIED \n"
1298 " text CDATA #IMPLIED \n"
1299 " >\n"
1300 "]><doc id='name' notid='name' text='splat!' enum='b'"
1301 " ref='name' refs='name name' ent='e1' ents='e1 e2'"
1302 " nm='123' nms='123 abc' />")
1303 elem = doc.documentElement
1304 # We don't want to rely on any specific loader at this point, so
1305 # just make sure we can get to all the names, and that the
1306 # DTD-based namespace is right. The names can vary by loader
1307 # since each supports a different level of DTD information.
1308 t = elem.schemaType
1309 self.confirm(t.name is None
1310 and t.namespace == xml.dom.EMPTY_NAMESPACE)
1311 names = "id notid text enum ref refs ent ents nm nms".split()
1312 for name in names:
1313 a = elem.getAttributeNode(name)
1314 t = a.schemaType
1315 self.confirm(hasattr(t, "name")
1316 and t.namespace == xml.dom.EMPTY_NAMESPACE)
1317
1318 def testSetIdAttribute(self):
1319 doc = parseString("<doc a1='v' a2='w'/>")
1320 e = doc.documentElement
1321 a1 = e.getAttributeNode("a1")
1322 a2 = e.getAttributeNode("a2")
1323 self.confirm(doc.getElementById("v") is None
1324 and not a1.isId
1325 and not a2.isId)
1326 e.setIdAttribute("a1")
1327 self.confirm(e.isSameNode(doc.getElementById("v"))
1328 and a1.isId
1329 and not a2.isId)
1330 e.setIdAttribute("a2")
1331 self.confirm(e.isSameNode(doc.getElementById("v"))
1332 and e.isSameNode(doc.getElementById("w"))
1333 and a1.isId
1334 and a2.isId)
1335 # replace the a1 node; the new node should *not* be an ID
1336 a3 = doc.createAttribute("a1")
1337 a3.value = "v"
1338 e.setAttributeNode(a3)
1339 self.confirm(doc.getElementById("v") is None
1340 and e.isSameNode(doc.getElementById("w"))
1341 and not a1.isId
1342 and a2.isId
1343 and not a3.isId)
1344 # renaming an attribute should not affect its ID-ness:
1345 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1346 self.confirm(e.isSameNode(doc.getElementById("w"))
1347 and a2.isId)
1348
1349 def testSetIdAttributeNS(self):
1350 NS1 = "http://xml.python.org/ns1"
1351 NS2 = "http://xml.python.org/ns2"
1352 doc = parseString("<doc"
1353 " xmlns:ns1='" + NS1 + "'"
1354 " xmlns:ns2='" + NS2 + "'"
1355 " ns1:a1='v' ns2:a2='w'/>")
1356 e = doc.documentElement
1357 a1 = e.getAttributeNodeNS(NS1, "a1")
1358 a2 = e.getAttributeNodeNS(NS2, "a2")
1359 self.confirm(doc.getElementById("v") is None
1360 and not a1.isId
1361 and not a2.isId)
1362 e.setIdAttributeNS(NS1, "a1")
1363 self.confirm(e.isSameNode(doc.getElementById("v"))
1364 and a1.isId
1365 and not a2.isId)
1366 e.setIdAttributeNS(NS2, "a2")
1367 self.confirm(e.isSameNode(doc.getElementById("v"))
1368 and e.isSameNode(doc.getElementById("w"))
1369 and a1.isId
1370 and a2.isId)
1371 # replace the a1 node; the new node should *not* be an ID
1372 a3 = doc.createAttributeNS(NS1, "a1")
1373 a3.value = "v"
1374 e.setAttributeNode(a3)
1375 self.confirm(e.isSameNode(doc.getElementById("w")))
1376 self.confirm(not a1.isId)
1377 self.confirm(a2.isId)
1378 self.confirm(not a3.isId)
1379 self.confirm(doc.getElementById("v") is None)
1380 # renaming an attribute should not affect its ID-ness:
1381 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1382 self.confirm(e.isSameNode(doc.getElementById("w"))
1383 and a2.isId)
1384
1385 def testSetIdAttributeNode(self):
1386 NS1 = "http://xml.python.org/ns1"
1387 NS2 = "http://xml.python.org/ns2"
1388 doc = parseString("<doc"
1389 " xmlns:ns1='" + NS1 + "'"
1390 " xmlns:ns2='" + NS2 + "'"
1391 " ns1:a1='v' ns2:a2='w'/>")
1392 e = doc.documentElement
1393 a1 = e.getAttributeNodeNS(NS1, "a1")
1394 a2 = e.getAttributeNodeNS(NS2, "a2")
1395 self.confirm(doc.getElementById("v") is None
1396 and not a1.isId
1397 and not a2.isId)
1398 e.setIdAttributeNode(a1)
1399 self.confirm(e.isSameNode(doc.getElementById("v"))
1400 and a1.isId
1401 and not a2.isId)
1402 e.setIdAttributeNode(a2)
1403 self.confirm(e.isSameNode(doc.getElementById("v"))
1404 and e.isSameNode(doc.getElementById("w"))
1405 and a1.isId
1406 and a2.isId)
1407 # replace the a1 node; the new node should *not* be an ID
1408 a3 = doc.createAttributeNS(NS1, "a1")
1409 a3.value = "v"
1410 e.setAttributeNode(a3)
1411 self.confirm(e.isSameNode(doc.getElementById("w")))
1412 self.confirm(not a1.isId)
1413 self.confirm(a2.isId)
1414 self.confirm(not a3.isId)
1415 self.confirm(doc.getElementById("v") is None)
1416 # renaming an attribute should not affect its ID-ness:
1417 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1418 self.confirm(e.isSameNode(doc.getElementById("w"))
1419 and a2.isId)
1420
1421 def testPickledDocument(self):
1422 doc = parseString("<?xml version='1.0' encoding='us-ascii'?>\n"
1423 "<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
1424 " 'http://xml.python.org/system' [\n"
1425 " <!ELEMENT e EMPTY>\n"
1426 " <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n"
1427 "]><doc attr='value'> text\n"
1428 "<?pi sample?> <!-- comment --> <e/> </doc>")
1429 s = pickle.dumps(doc)
1430 doc2 = pickle.loads(s)
1431 stack = [(doc, doc2)]
1432 while stack:
1433 n1, n2 = stack.pop()
1434 self.confirm(n1.nodeType == n2.nodeType
1435 and len(n1.childNodes) == len(n2.childNodes)
1436 and n1.nodeName == n2.nodeName
1437 and not n1.isSameNode(n2)
1438 and not n2.isSameNode(n1))
1439 if n1.nodeType == Node.DOCUMENT_TYPE_NODE:
1440 len(n1.entities)
1441 len(n2.entities)
1442 len(n1.notations)
1443 len(n2.notations)
1444 self.confirm(len(n1.entities) == len(n2.entities)
1445 and len(n1.notations) == len(n2.notations))
1446 for i in range(len(n1.notations)):
Georg Brandl89fad142010-03-14 10:23:39 +00001447 # XXX this loop body doesn't seem to be executed?
Guido van Rossumd8faa362007-04-27 19:54:29 +00001448 no1 = n1.notations.item(i)
1449 no2 = n1.notations.item(i)
1450 self.confirm(no1.name == no2.name
1451 and no1.publicId == no2.publicId
1452 and no1.systemId == no2.systemId)
Georg Brandl89fad142010-03-14 10:23:39 +00001453 stack.append((no1, no2))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001454 for i in range(len(n1.entities)):
1455 e1 = n1.entities.item(i)
1456 e2 = n2.entities.item(i)
1457 self.confirm(e1.notationName == e2.notationName
1458 and e1.publicId == e2.publicId
1459 and e1.systemId == e2.systemId)
1460 stack.append((e1, e2))
1461 if n1.nodeType != Node.DOCUMENT_NODE:
1462 self.confirm(n1.ownerDocument.isSameNode(doc)
1463 and n2.ownerDocument.isSameNode(doc2))
1464 for i in range(len(n1.childNodes)):
1465 stack.append((n1.childNodes[i], n2.childNodes[i]))
1466
Benjamin Peterson2b7411d2008-05-26 17:36:47 +00001467 def testSerializeCommentNodeWithDoubleHyphen(self):
1468 doc = create_doc_without_doctype()
1469 doc.appendChild(doc.createComment("foo--bar"))
1470 self.assertRaises(ValueError, doc.toxml)
1471
Benjamin Peterson863a0c32011-03-02 23:40:36 +00001472
Georg Brandlb9cd72a2010-10-15 17:58:45 +00001473 def testEmptyXMLNSValue(self):
1474 doc = parseString("<element xmlns=''>\n"
1475 "<foo/>\n</element>")
1476 doc2 = parseString(doc.toxml())
1477 self.confirm(doc2.namespaceURI == xml.dom.EMPTY_NAMESPACE)
1478
Raymond Hettinger06eef9c2011-06-25 15:54:52 +02001479 def testDocRemoveChild(self):
1480 doc = parse(tstfile)
1481 title_tag = doc.documentElement.getElementsByTagName("TITLE")[0]
1482 self.assertRaises( xml.dom.NotFoundErr, doc.removeChild, title_tag)
1483 num_children_before = len(doc.childNodes)
1484 doc.removeChild(doc.childNodes[0])
1485 num_children_after = len(doc.childNodes)
1486 self.assertTrue(num_children_after == num_children_before - 1)
Georg Brandlb9cd72a2010-10-15 17:58:45 +00001487
Guido van Rossumd8faa362007-04-27 19:54:29 +00001488def test_main():
1489 run_unittest(MinidomTest)
1490
1491if __name__ == "__main__":
1492 test_main()