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