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