1 # test for xml.dom.minidom
4 from StringIO
import StringIO
5 from test
.test_support
import verbose
, run_unittest
, findfile
10 import xml
.parsers
.expat
12 from xml
.dom
.minidom
import parse
, Node
, Document
, parseString
13 from xml
.dom
.minidom
import getDOMImplementation
16 tstfile
= findfile("test.xml", subdir
="xmltestdata")
19 # The tests of DocumentType importing use these helpers to construct
20 # the documents to work with, since not all DOM builders actually
21 # create the DocumentType nodes.
22 def create_doc_without_doctype(doctype
=None):
23 return getDOMImplementation().createDocument(None, "doc", doctype
)
25 def create_nonempty_doctype():
26 doctype
= getDOMImplementation().createDocumentType("doc", None, None)
27 doctype
.entities
._seq
= []
28 doctype
.notations
._seq
= []
29 notation
= xml
.dom
.minidom
.Notation("my-notation", None,
30 "http://xml.python.org/notations/my")
31 doctype
.notations
._seq
.append(notation
)
32 entity
= xml
.dom
.minidom
.Entity("my-entity", None,
33 "http://xml.python.org/entities/my",
35 entity
.version
= "1.0"
36 entity
.encoding
= "utf-8"
37 entity
.actualEncoding
= "us-ascii"
38 doctype
.entities
._seq
.append(entity
)
41 def create_doc_with_doctype():
42 doctype
= create_nonempty_doctype()
43 doc
= create_doc_without_doctype(doctype
)
44 doctype
.entities
.item(0).ownerDocument
= doc
45 doctype
.notations
.item(0).ownerDocument
= doc
48 class MinidomTest(unittest
.TestCase
):
52 except AttributeError:
53 # We don't actually have the minidom from the standard library,
54 # but are picking up the PyXML version from site-packages.
57 self
.confirm(len(Node
.allnodes
) == 0,
58 "assertion: len(Node.allnodes) == 0")
59 if len(Node
.allnodes
):
60 print "Garbage left over:"
62 print Node
.allnodes
.items()[0:10]
64 # Don't print specific nodes if repeatable results
66 print len(Node
.allnodes
)
69 def confirm(self
, test
, testname
= "Test"):
70 self
.assertTrue(test
, testname
)
72 def checkWholeText(self
, node
, s
):
74 self
.confirm(t
== s
, "looking for %s, found %s" % (repr(s
), repr(t
)))
76 def testParseFromFile(self
):
77 dom
= parse(StringIO(open(tstfile
).read()))
79 self
.confirm(isinstance(dom
,Document
))
81 def testGetElementsByTagName(self
):
83 self
.confirm(dom
.getElementsByTagName("LI") == \
84 dom
.documentElement
.getElementsByTagName("LI"))
87 def testInsertBefore(self
):
88 dom
= parseString("<doc><foo/></doc>")
89 root
= dom
.documentElement
90 elem
= root
.childNodes
[0]
91 nelem
= dom
.createElement("element")
92 root
.insertBefore(nelem
, elem
)
93 self
.confirm(len(root
.childNodes
) == 2
94 and root
.childNodes
.length
== 2
95 and root
.childNodes
[0] is nelem
96 and root
.childNodes
.item(0) is nelem
97 and root
.childNodes
[1] is elem
98 and root
.childNodes
.item(1) is elem
99 and root
.firstChild
is nelem
100 and root
.lastChild
is elem
101 and root
.toxml() == "<doc><element/><foo/></doc>"
102 , "testInsertBefore -- node properly placed in tree")
103 nelem
= dom
.createElement("element")
104 root
.insertBefore(nelem
, None)
105 self
.confirm(len(root
.childNodes
) == 3
106 and root
.childNodes
.length
== 3
107 and root
.childNodes
[1] is elem
108 and root
.childNodes
.item(1) is elem
109 and root
.childNodes
[2] is nelem
110 and root
.childNodes
.item(2) is nelem
111 and root
.lastChild
is nelem
112 and nelem
.previousSibling
is elem
113 and root
.toxml() == "<doc><element/><foo/><element/></doc>"
114 , "testInsertBefore -- node properly placed in tree")
115 nelem2
= dom
.createElement("bar")
116 root
.insertBefore(nelem2
, nelem
)
117 self
.confirm(len(root
.childNodes
) == 4
118 and root
.childNodes
.length
== 4
119 and root
.childNodes
[2] is nelem2
120 and root
.childNodes
.item(2) is nelem2
121 and root
.childNodes
[3] is nelem
122 and root
.childNodes
.item(3) is nelem
123 and nelem2
.nextSibling
is nelem
124 and nelem
.previousSibling
is nelem2
126 "<doc><element/><foo/><bar/><element/></doc>"
127 , "testInsertBefore -- node properly placed in tree")
130 def _create_fragment_test_nodes(self
):
131 dom
= parseString("<doc/>")
132 orig
= dom
.createTextNode("original")
133 c1
= dom
.createTextNode("foo")
134 c2
= dom
.createTextNode("bar")
135 c3
= dom
.createTextNode("bat")
136 dom
.documentElement
.appendChild(orig
)
137 frag
= dom
.createDocumentFragment()
141 return dom
, orig
, c1
, c2
, c3
, frag
143 def testInsertBeforeFragment(self
):
144 dom
, orig
, c1
, c2
, c3
, frag
= self
._create
_fragment
_test
_nodes
()
145 dom
.documentElement
.insertBefore(frag
, None)
146 self
.confirm(tuple(dom
.documentElement
.childNodes
) ==
148 "insertBefore(<fragment>, None)")
152 dom
, orig
, c1
, c2
, c3
, frag
= self
._create
_fragment
_test
_nodes
()
153 dom
.documentElement
.insertBefore(frag
, orig
)
154 self
.confirm(tuple(dom
.documentElement
.childNodes
) ==
156 "insertBefore(<fragment>, orig)")
160 def testAppendChild(self
):
162 dom
.documentElement
.appendChild(dom
.createComment(u
"Hello"))
163 self
.confirm(dom
.documentElement
.childNodes
[-1].nodeName
== "#comment")
164 self
.confirm(dom
.documentElement
.childNodes
[-1].data
== "Hello")
167 def testAppendChildFragment(self
):
168 dom
, orig
, c1
, c2
, c3
, frag
= self
._create
_fragment
_test
_nodes
()
169 dom
.documentElement
.appendChild(frag
)
170 self
.confirm(tuple(dom
.documentElement
.childNodes
) ==
172 "appendChild(<fragment>)")
176 def testReplaceChildFragment(self
):
177 dom
, orig
, c1
, c2
, c3
, frag
= self
._create
_fragment
_test
_nodes
()
178 dom
.documentElement
.replaceChild(frag
, orig
)
180 self
.confirm(tuple(dom
.documentElement
.childNodes
) == (c1
, c2
, c3
),
181 "replaceChild(<fragment>)")
185 def testLegalChildren(self
):
187 elem
= dom
.createElement('element')
188 text
= dom
.createTextNode('text')
189 self
.assertRaises(xml
.dom
.HierarchyRequestErr
, dom
.appendChild
, text
)
191 dom
.appendChild(elem
)
192 self
.assertRaises(xml
.dom
.HierarchyRequestErr
, dom
.insertBefore
, text
,
194 self
.assertRaises(xml
.dom
.HierarchyRequestErr
, dom
.replaceChild
, text
,
197 nodemap
= elem
.attributes
198 self
.assertRaises(xml
.dom
.HierarchyRequestErr
, nodemap
.setNamedItem
,
200 self
.assertRaises(xml
.dom
.HierarchyRequestErr
, nodemap
.setNamedItemNS
,
203 elem
.appendChild(text
)
206 def testNamedNodeMapSetItem(self
):
208 elem
= dom
.createElement('element')
209 attrs
= elem
.attributes
212 self
.confirm(a
.ownerDocument
is dom
,
213 "NamedNodeMap.__setitem__() sets ownerDocument")
214 self
.confirm(a
.ownerElement
is elem
,
215 "NamedNodeMap.__setitem__() sets ownerElement")
216 self
.confirm(a
.value
== "bar",
217 "NamedNodeMap.__setitem__() sets value")
218 self
.confirm(a
.nodeValue
== "bar",
219 "NamedNodeMap.__setitem__() sets nodeValue")
223 def testNonZero(self
):
225 self
.confirm(dom
)# should not be zero
226 dom
.appendChild(dom
.createComment("foo"))
227 self
.confirm(not dom
.childNodes
[-1].childNodes
)
230 def testUnlink(self
):
234 def testElement(self
):
236 dom
.appendChild(dom
.createElement("abc"))
237 self
.confirm(dom
.documentElement
)
241 dom
= parseString("<abc/>")
242 el
= dom
.documentElement
243 el
.setAttribute("spam", "jam2")
244 self
.confirm(el
.toxml() == '<abc spam="jam2"/>', "testAAA")
245 a
= el
.getAttributeNode("spam")
246 self
.confirm(a
.ownerDocument
is dom
,
247 "setAttribute() sets ownerDocument")
248 self
.confirm(a
.ownerElement
is dom
.documentElement
,
249 "setAttribute() sets ownerElement")
253 dom
= parseString("<abc/>")
254 el
= dom
.documentElement
255 el
.setAttribute("spam", "jam")
256 el
.setAttribute("spam", "jam2")
257 self
.confirm(el
.toxml() == '<abc spam="jam2"/>', "testAAB")
260 def testAddAttr(self
):
262 child
= dom
.appendChild(dom
.createElement("abc"))
264 child
.setAttribute("def", "ghi")
265 self
.confirm(child
.getAttribute("def") == "ghi")
266 self
.confirm(child
.attributes
["def"].value
== "ghi")
268 child
.setAttribute("jkl", "mno")
269 self
.confirm(child
.getAttribute("jkl") == "mno")
270 self
.confirm(child
.attributes
["jkl"].value
== "mno")
272 self
.confirm(len(child
.attributes
) == 2)
274 child
.setAttribute("def", "newval")
275 self
.confirm(child
.getAttribute("def") == "newval")
276 self
.confirm(child
.attributes
["def"].value
== "newval")
278 self
.confirm(len(child
.attributes
) == 2)
281 def testDeleteAttr(self
):
283 child
= dom
.appendChild(dom
.createElement("abc"))
285 self
.confirm(len(child
.attributes
) == 0)
286 child
.setAttribute("def", "ghi")
287 self
.confirm(len(child
.attributes
) == 1)
288 del child
.attributes
["def"]
289 self
.confirm(len(child
.attributes
) == 0)
292 def testRemoveAttr(self
):
294 child
= dom
.appendChild(dom
.createElement("abc"))
296 child
.setAttribute("def", "ghi")
297 self
.confirm(len(child
.attributes
) == 1)
298 child
.removeAttribute("def")
299 self
.confirm(len(child
.attributes
) == 0)
302 def testRemoveAttrNS(self
):
304 child
= dom
.appendChild(
305 dom
.createElementNS("http://www.python.org", "python:abc"))
306 child
.setAttributeNS("http://www.w3.org", "xmlns:python",
307 "http://www.python.org")
308 child
.setAttributeNS("http://www.python.org", "python:abcattr", "foo")
309 self
.confirm(len(child
.attributes
) == 2)
310 child
.removeAttributeNS("http://www.python.org", "abcattr")
311 self
.confirm(len(child
.attributes
) == 1)
314 def testRemoveAttributeNode(self
):
316 child
= dom
.appendChild(dom
.createElement("foo"))
317 child
.setAttribute("spam", "jam")
318 self
.confirm(len(child
.attributes
) == 1)
319 node
= child
.getAttributeNode("spam")
320 child
.removeAttributeNode(node
)
321 self
.confirm(len(child
.attributes
) == 0
322 and child
.getAttributeNode("spam") is None)
325 def testChangeAttr(self
):
326 dom
= parseString("<abc/>")
327 el
= dom
.documentElement
328 el
.setAttribute("spam", "jam")
329 self
.confirm(len(el
.attributes
) == 1)
330 el
.setAttribute("spam", "bam")
331 # Set this attribute to be an ID and make sure that doesn't change
332 # when changing the value:
333 el
.setIdAttribute("spam")
334 self
.confirm(len(el
.attributes
) == 1
335 and el
.attributes
["spam"].value
== "bam"
336 and el
.attributes
["spam"].nodeValue
== "bam"
337 and el
.getAttribute("spam") == "bam"
338 and el
.getAttributeNode("spam").isId
)
339 el
.attributes
["spam"] = "ham"
340 self
.confirm(len(el
.attributes
) == 1
341 and el
.attributes
["spam"].value
== "ham"
342 and el
.attributes
["spam"].nodeValue
== "ham"
343 and el
.getAttribute("spam") == "ham"
344 and el
.attributes
["spam"].isId
)
345 el
.setAttribute("spam2", "bam")
346 self
.confirm(len(el
.attributes
) == 2
347 and el
.attributes
["spam"].value
== "ham"
348 and el
.attributes
["spam"].nodeValue
== "ham"
349 and el
.getAttribute("spam") == "ham"
350 and el
.attributes
["spam2"].value
== "bam"
351 and el
.attributes
["spam2"].nodeValue
== "bam"
352 and el
.getAttribute("spam2") == "bam")
353 el
.attributes
["spam2"] = "bam2"
354 self
.confirm(len(el
.attributes
) == 2
355 and el
.attributes
["spam"].value
== "ham"
356 and el
.attributes
["spam"].nodeValue
== "ham"
357 and el
.getAttribute("spam") == "ham"
358 and el
.attributes
["spam2"].value
== "bam2"
359 and el
.attributes
["spam2"].nodeValue
== "bam2"
360 and el
.getAttribute("spam2") == "bam2")
363 def testGetAttrList(self
):
366 def testGetAttrValues(self
): pass
368 def testGetAttrLength(self
): pass
370 def testGetAttribute(self
): pass
372 def testGetAttributeNS(self
): pass
374 def testGetAttributeNode(self
): pass
376 def testGetElementsByTagNameNS(self
):
377 d
="""<foo xmlns:minidom='http://pyxml.sf.net/minidom'>
381 elems
= dom
.getElementsByTagNameNS("http://pyxml.sf.net/minidom",
383 self
.confirm(len(elems
) == 1
384 and elems
[0].namespaceURI
== "http://pyxml.sf.net/minidom"
385 and elems
[0].localName
== "myelem"
386 and elems
[0].prefix
== "minidom"
387 and elems
[0].tagName
== "minidom:myelem"
388 and elems
[0].nodeName
== "minidom:myelem")
391 def get_empty_nodelist_from_elements_by_tagName_ns_helper(self
, doc
, nsuri
,
393 nodelist
= doc
.getElementsByTagNameNS(nsuri
, lname
)
394 self
.confirm(len(nodelist
) == 0)
396 def testGetEmptyNodeListFromElementsByTagNameNS(self
):
397 doc
= parseString('<doc/>')
398 self
.get_empty_nodelist_from_elements_by_tagName_ns_helper(
399 doc
, 'http://xml.python.org/namespaces/a', 'localname')
400 self
.get_empty_nodelist_from_elements_by_tagName_ns_helper(
402 self
.get_empty_nodelist_from_elements_by_tagName_ns_helper(
403 doc
, 'http://xml.python.org/namespaces/a', '*')
405 doc
= parseString('<doc xmlns="http://xml.python.org/splat"><e/></doc>')
406 self
.get_empty_nodelist_from_elements_by_tagName_ns_helper(
407 doc
, "http://xml.python.org/splat", "not-there")
408 self
.get_empty_nodelist_from_elements_by_tagName_ns_helper(
409 doc
, "*", "not-there")
410 self
.get_empty_nodelist_from_elements_by_tagName_ns_helper(
411 doc
, "http://somewhere.else.net/not-there", "e")
413 def testElementReprAndStr(self
):
415 el
= dom
.appendChild(dom
.createElement("abc"))
418 self
.confirm(string1
== string2
)
421 def testElementReprAndStrUnicode(self
):
423 el
= dom
.appendChild(dom
.createElement(u
"abc"))
426 self
.confirm(string1
== string2
)
429 def testElementReprAndStrUnicodeNS(self
):
431 el
= dom
.appendChild(
432 dom
.createElementNS(u
"http://www.slashdot.org", u
"slash:abc"))
435 self
.confirm(string1
== string2
)
436 self
.confirm("slash:abc" in string1
)
439 def testAttributeRepr(self
):
441 el
= dom
.appendChild(dom
.createElement(u
"abc"))
442 node
= el
.setAttribute("abc", "def")
443 self
.confirm(str(node
) == repr(node
))
446 def testTextNodeRepr(self
): pass
448 def testWriteXML(self
):
449 str = '<?xml version="1.0" ?><a b="c"/>'
450 dom
= parseString(str)
453 self
.confirm(str == domstr
)
455 def testAltNewline(self
):
456 str = '<?xml version="1.0" ?>\n<a b="c"/>\n'
457 dom
= parseString(str)
458 domstr
= dom
.toprettyxml(newl
="\r\n")
460 self
.confirm(domstr
== str.replace("\n", "\r\n"))
462 def testProcessingInstruction(self
):
463 dom
= parseString('<e><?mypi \t\n data \t\n ?></e>')
464 pi
= dom
.documentElement
.firstChild
465 self
.confirm(pi
.target
== "mypi"
466 and pi
.data
== "data \t\n "
467 and pi
.nodeName
== "mypi"
468 and pi
.nodeType
== Node
.PROCESSING_INSTRUCTION_NODE
469 and pi
.attributes
is None
470 and not pi
.hasChildNodes()
471 and len(pi
.childNodes
) == 0
472 and pi
.firstChild
is None
473 and pi
.lastChild
is None
474 and pi
.localName
is None
475 and pi
.namespaceURI
== xml
.dom
.EMPTY_NAMESPACE
)
477 def testProcessingInstructionRepr(self
): pass
479 def testTextRepr(self
): pass
481 def testWriteText(self
): pass
483 def testDocumentElement(self
): pass
485 def testTooManyDocumentElements(self
):
486 doc
= parseString("<doc/>")
487 elem
= doc
.createElement("extra")
488 # Should raise an exception when adding an extra document element.
489 self
.assertRaises(xml
.dom
.HierarchyRequestErr
, doc
.appendChild
, elem
)
493 def testCreateElementNS(self
): pass
495 def testCreateAttributeNS(self
): pass
497 def testParse(self
): pass
499 def testParseString(self
): pass
501 def testComment(self
): pass
503 def testAttrListItem(self
): pass
505 def testAttrListItems(self
): pass
507 def testAttrListItemNS(self
): pass
509 def testAttrListKeys(self
): pass
511 def testAttrListKeysNS(self
): pass
513 def testRemoveNamedItem(self
):
514 doc
= parseString("<doc a=''/>")
515 e
= doc
.documentElement
517 a1
= e
.getAttributeNode("a")
518 a2
= attrs
.removeNamedItem("a")
519 self
.confirm(a1
.isSameNode(a2
))
520 self
.assertRaises(xml
.dom
.NotFoundErr
, attrs
.removeNamedItem
, "a")
522 def testRemoveNamedItemNS(self
):
523 doc
= parseString("<doc xmlns:a='http://xml.python.org/' a:b=''/>")
524 e
= doc
.documentElement
526 a1
= e
.getAttributeNodeNS("http://xml.python.org/", "b")
527 a2
= attrs
.removeNamedItemNS("http://xml.python.org/", "b")
528 self
.confirm(a1
.isSameNode(a2
))
529 self
.assertRaises(xml
.dom
.NotFoundErr
, attrs
.removeNamedItemNS
,
530 "http://xml.python.org/", "b")
532 def testAttrListValues(self
): pass
534 def testAttrListLength(self
): pass
536 def testAttrList__getitem__(self
): pass
538 def testAttrList__setitem__(self
): pass
540 def testSetAttrValueandNodeValue(self
): pass
542 def testParseElement(self
): pass
544 def testParseAttributes(self
): pass
546 def testParseElementNamespaces(self
): pass
548 def testParseAttributeNamespaces(self
): pass
550 def testParseProcessingInstructions(self
): pass
552 def testChildNodes(self
): pass
554 def testFirstChild(self
): pass
556 def testHasChildNodes(self
): pass
558 def _testCloneElementCopiesAttributes(self
, e1
, e2
, test
):
559 attrs1
= e1
.attributes
560 attrs2
= e2
.attributes
561 keys1
= attrs1
.keys()
562 keys2
= attrs2
.keys()
565 self
.confirm(keys1
== keys2
, "clone of element has same attribute keys")
566 for i
in range(len(keys1
)):
569 self
.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 self
.confirm(a2
.ownerElement
is e2
,
576 "clone of attribute node correctly owned")
578 def _setupCloneElement(self
, deep
):
579 dom
= parseString("<doc attr='value'><foo/></doc>")
580 root
= dom
.documentElement
581 clone
= root
.cloneNode(deep
)
582 self
._testCloneElementCopiesAttributes
(
583 root
, clone
, "testCloneElement" + (deep
and "Deep" or "Shallow"))
584 # mutilate the original so shared data is detected
585 root
.tagName
= root
.nodeName
= "MODIFIED"
586 root
.setAttribute("attr", "NEW VALUE")
587 root
.setAttribute("added", "VALUE")
590 def testCloneElementShallow(self
):
591 dom
, clone
= self
._setupCloneElement
(0)
592 self
.confirm(len(clone
.childNodes
) == 0
593 and clone
.childNodes
.length
== 0
594 and clone
.parentNode
is None
595 and clone
.toxml() == '<doc attr="value"/>'
596 , "testCloneElementShallow")
599 def testCloneElementDeep(self
):
600 dom
, clone
= self
._setupCloneElement
(1)
601 self
.confirm(len(clone
.childNodes
) == 1
602 and clone
.childNodes
.length
== 1
603 and clone
.parentNode
is None
604 and clone
.toxml() == '<doc attr="value"><foo/></doc>'
605 , "testCloneElementDeep")
608 def testCloneDocumentShallow(self
):
609 doc
= parseString("<?xml version='1.0'?>\n"
612 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
614 "<doc attr='value'/>")
615 doc2
= doc
.cloneNode(0)
616 self
.confirm(doc2
is None,
617 "testCloneDocumentShallow:"
618 " shallow cloning of documents makes no sense!")
620 def testCloneDocumentDeep(self
):
621 doc
= parseString("<?xml version='1.0'?>\n"
624 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
626 "<doc attr='value'/>")
627 doc2
= doc
.cloneNode(1)
628 self
.confirm(not (doc
.isSameNode(doc2
) or doc2
.isSameNode(doc
)),
629 "testCloneDocumentDeep: document objects not distinct")
630 self
.confirm(len(doc
.childNodes
) == len(doc2
.childNodes
),
631 "testCloneDocumentDeep: wrong number of Document children")
632 self
.confirm(doc2
.documentElement
.nodeType
== Node
.ELEMENT_NODE
,
633 "testCloneDocumentDeep: documentElement not an ELEMENT_NODE")
634 self
.confirm(doc2
.documentElement
.ownerDocument
.isSameNode(doc2
),
635 "testCloneDocumentDeep: documentElement owner is not new document")
636 self
.confirm(not doc
.documentElement
.isSameNode(doc2
.documentElement
),
637 "testCloneDocumentDeep: documentElement should not be shared")
638 if doc
.doctype
is not None:
639 # check the doctype iff the original DOM maintained it
640 self
.confirm(doc2
.doctype
.nodeType
== Node
.DOCUMENT_TYPE_NODE
,
641 "testCloneDocumentDeep: doctype not a DOCUMENT_TYPE_NODE")
642 self
.confirm(doc2
.doctype
.ownerDocument
.isSameNode(doc2
))
643 self
.confirm(not doc
.doctype
.isSameNode(doc2
.doctype
))
645 def testCloneDocumentTypeDeepOk(self
):
646 doctype
= create_nonempty_doctype()
647 clone
= doctype
.cloneNode(1)
648 self
.confirm(clone
is not None
649 and clone
.nodeName
== doctype
.nodeName
650 and clone
.name
== doctype
.name
651 and clone
.publicId
== doctype
.publicId
652 and clone
.systemId
== doctype
.systemId
653 and len(clone
.entities
) == len(doctype
.entities
)
654 and clone
.entities
.item(len(clone
.entities
)) is None
655 and len(clone
.notations
) == len(doctype
.notations
)
656 and clone
.notations
.item(len(clone
.notations
)) is None
657 and len(clone
.childNodes
) == 0)
658 for i
in range(len(doctype
.entities
)):
659 se
= doctype
.entities
.item(i
)
660 ce
= clone
.entities
.item(i
)
661 self
.confirm((not se
.isSameNode(ce
))
662 and (not ce
.isSameNode(se
))
663 and ce
.nodeName
== se
.nodeName
664 and ce
.notationName
== se
.notationName
665 and ce
.publicId
== se
.publicId
666 and ce
.systemId
== se
.systemId
667 and ce
.encoding
== se
.encoding
668 and ce
.actualEncoding
== se
.actualEncoding
669 and ce
.version
== se
.version
)
670 for i
in range(len(doctype
.notations
)):
671 sn
= doctype
.notations
.item(i
)
672 cn
= clone
.notations
.item(i
)
673 self
.confirm((not sn
.isSameNode(cn
))
674 and (not cn
.isSameNode(sn
))
675 and cn
.nodeName
== sn
.nodeName
676 and cn
.publicId
== sn
.publicId
677 and cn
.systemId
== sn
.systemId
)
679 def testCloneDocumentTypeDeepNotOk(self
):
680 doc
= create_doc_with_doctype()
681 clone
= doc
.doctype
.cloneNode(1)
682 self
.confirm(clone
is None, "testCloneDocumentTypeDeepNotOk")
684 def testCloneDocumentTypeShallowOk(self
):
685 doctype
= create_nonempty_doctype()
686 clone
= doctype
.cloneNode(0)
687 self
.confirm(clone
is not None
688 and clone
.nodeName
== doctype
.nodeName
689 and clone
.name
== doctype
.name
690 and clone
.publicId
== doctype
.publicId
691 and clone
.systemId
== doctype
.systemId
692 and len(clone
.entities
) == 0
693 and clone
.entities
.item(0) is None
694 and len(clone
.notations
) == 0
695 and clone
.notations
.item(0) is None
696 and len(clone
.childNodes
) == 0)
698 def testCloneDocumentTypeShallowNotOk(self
):
699 doc
= create_doc_with_doctype()
700 clone
= doc
.doctype
.cloneNode(0)
701 self
.confirm(clone
is None, "testCloneDocumentTypeShallowNotOk")
703 def check_import_document(self
, deep
, testName
):
704 doc1
= parseString("<doc/>")
705 doc2
= parseString("<doc/>")
706 self
.assertRaises(xml
.dom
.NotSupportedErr
, doc1
.importNode
, doc2
, deep
)
708 def testImportDocumentShallow(self
):
709 self
.check_import_document(0, "testImportDocumentShallow")
711 def testImportDocumentDeep(self
):
712 self
.check_import_document(1, "testImportDocumentDeep")
714 def testImportDocumentTypeShallow(self
):
715 src
= create_doc_with_doctype()
716 target
= create_doc_without_doctype()
717 self
.assertRaises(xml
.dom
.NotSupportedErr
, target
.importNode
,
720 def testImportDocumentTypeDeep(self
):
721 src
= create_doc_with_doctype()
722 target
= create_doc_without_doctype()
723 self
.assertRaises(xml
.dom
.NotSupportedErr
, target
.importNode
,
726 # Testing attribute clones uses a helper, and should always be deep,
727 # even if the argument to cloneNode is false.
728 def check_clone_attribute(self
, deep
, testName
):
729 doc
= parseString("<doc attr='value'/>")
730 attr
= doc
.documentElement
.getAttributeNode("attr")
731 self
.assertNotEqual(attr
, None)
732 clone
= attr
.cloneNode(deep
)
733 self
.confirm(not clone
.isSameNode(attr
))
734 self
.confirm(not attr
.isSameNode(clone
))
735 self
.confirm(clone
.ownerElement
is None,
736 testName
+ ": ownerElement should be None")
737 self
.confirm(clone
.ownerDocument
.isSameNode(attr
.ownerDocument
),
738 testName
+ ": ownerDocument does not match")
739 self
.confirm(clone
.specified
,
740 testName
+ ": cloned attribute must have specified == True")
742 def testCloneAttributeShallow(self
):
743 self
.check_clone_attribute(0, "testCloneAttributeShallow")
745 def testCloneAttributeDeep(self
):
746 self
.check_clone_attribute(1, "testCloneAttributeDeep")
748 def check_clone_pi(self
, deep
, testName
):
749 doc
= parseString("<?target data?><doc/>")
751 self
.assertEquals(pi
.nodeType
, Node
.PROCESSING_INSTRUCTION_NODE
)
752 clone
= pi
.cloneNode(deep
)
753 self
.confirm(clone
.target
== pi
.target
754 and clone
.data
== pi
.data
)
756 def testClonePIShallow(self
):
757 self
.check_clone_pi(0, "testClonePIShallow")
759 def testClonePIDeep(self
):
760 self
.check_clone_pi(1, "testClonePIDeep")
762 def testNormalize(self
):
763 doc
= parseString("<doc/>")
764 root
= doc
.documentElement
765 root
.appendChild(doc
.createTextNode("first"))
766 root
.appendChild(doc
.createTextNode("second"))
767 self
.confirm(len(root
.childNodes
) == 2
768 and root
.childNodes
.length
== 2,
769 "testNormalize -- preparation")
771 self
.confirm(len(root
.childNodes
) == 1
772 and root
.childNodes
.length
== 1
773 and root
.firstChild
is root
.lastChild
774 and root
.firstChild
.data
== "firstsecond"
775 , "testNormalize -- result")
778 doc
= parseString("<doc/>")
779 root
= doc
.documentElement
780 root
.appendChild(doc
.createTextNode(""))
782 self
.confirm(len(root
.childNodes
) == 0
783 and root
.childNodes
.length
== 0,
784 "testNormalize -- single empty node removed")
787 def testNormalizeCombineAndNextSibling(self
):
788 doc
= parseString("<doc/>")
789 root
= doc
.documentElement
790 root
.appendChild(doc
.createTextNode("first"))
791 root
.appendChild(doc
.createTextNode("second"))
792 root
.appendChild(doc
.createElement("i"))
793 self
.confirm(len(root
.childNodes
) == 3
794 and root
.childNodes
.length
== 3,
795 "testNormalizeCombineAndNextSibling -- preparation")
797 self
.confirm(len(root
.childNodes
) == 2
798 and root
.childNodes
.length
== 2
799 and root
.firstChild
.data
== "firstsecond"
800 and root
.firstChild
is not root
.lastChild
801 and root
.firstChild
.nextSibling
is root
.lastChild
802 and root
.firstChild
.previousSibling
is None
803 and root
.lastChild
.previousSibling
is root
.firstChild
804 and root
.lastChild
.nextSibling
is None
805 , "testNormalizeCombinedAndNextSibling -- result")
808 def testNormalizeDeleteWithPrevSibling(self
):
809 doc
= parseString("<doc/>")
810 root
= doc
.documentElement
811 root
.appendChild(doc
.createTextNode("first"))
812 root
.appendChild(doc
.createTextNode(""))
813 self
.confirm(len(root
.childNodes
) == 2
814 and root
.childNodes
.length
== 2,
815 "testNormalizeDeleteWithPrevSibling -- preparation")
817 self
.confirm(len(root
.childNodes
) == 1
818 and root
.childNodes
.length
== 1
819 and root
.firstChild
.data
== "first"
820 and root
.firstChild
is root
.lastChild
821 and root
.firstChild
.nextSibling
is None
822 and root
.firstChild
.previousSibling
is None
823 , "testNormalizeDeleteWithPrevSibling -- result")
826 def testNormalizeDeleteWithNextSibling(self
):
827 doc
= parseString("<doc/>")
828 root
= doc
.documentElement
829 root
.appendChild(doc
.createTextNode(""))
830 root
.appendChild(doc
.createTextNode("second"))
831 self
.confirm(len(root
.childNodes
) == 2
832 and root
.childNodes
.length
== 2,
833 "testNormalizeDeleteWithNextSibling -- preparation")
835 self
.confirm(len(root
.childNodes
) == 1
836 and root
.childNodes
.length
== 1
837 and root
.firstChild
.data
== "second"
838 and root
.firstChild
is root
.lastChild
839 and root
.firstChild
.nextSibling
is None
840 and root
.firstChild
.previousSibling
is None
841 , "testNormalizeDeleteWithNextSibling -- result")
844 def testNormalizeDeleteWithTwoNonTextSiblings(self
):
845 doc
= parseString("<doc/>")
846 root
= doc
.documentElement
847 root
.appendChild(doc
.createElement("i"))
848 root
.appendChild(doc
.createTextNode(""))
849 root
.appendChild(doc
.createElement("i"))
850 self
.confirm(len(root
.childNodes
) == 3
851 and root
.childNodes
.length
== 3,
852 "testNormalizeDeleteWithTwoSiblings -- preparation")
854 self
.confirm(len(root
.childNodes
) == 2
855 and root
.childNodes
.length
== 2
856 and root
.firstChild
is not root
.lastChild
857 and root
.firstChild
.nextSibling
is root
.lastChild
858 and root
.firstChild
.previousSibling
is None
859 and root
.lastChild
.previousSibling
is root
.firstChild
860 and root
.lastChild
.nextSibling
is None
861 , "testNormalizeDeleteWithTwoSiblings -- result")
864 def testNormalizeDeleteAndCombine(self
):
865 doc
= parseString("<doc/>")
866 root
= doc
.documentElement
867 root
.appendChild(doc
.createTextNode(""))
868 root
.appendChild(doc
.createTextNode("second"))
869 root
.appendChild(doc
.createTextNode(""))
870 root
.appendChild(doc
.createTextNode("fourth"))
871 root
.appendChild(doc
.createTextNode(""))
872 self
.confirm(len(root
.childNodes
) == 5
873 and root
.childNodes
.length
== 5,
874 "testNormalizeDeleteAndCombine -- preparation")
876 self
.confirm(len(root
.childNodes
) == 1
877 and root
.childNodes
.length
== 1
878 and root
.firstChild
is root
.lastChild
879 and root
.firstChild
.data
== "secondfourth"
880 and root
.firstChild
.previousSibling
is None
881 and root
.firstChild
.nextSibling
is None
882 , "testNormalizeDeleteAndCombine -- result")
885 def testNormalizeRecursion(self
):
886 doc
= parseString("<doc>"
903 root
= doc
.documentElement
904 root
.childNodes
[0].appendChild(doc
.createTextNode(""))
905 root
.childNodes
[0].appendChild(doc
.createTextNode("x"))
906 root
.childNodes
[1].childNodes
[0].appendChild(doc
.createTextNode("x2"))
907 root
.childNodes
[1].appendChild(doc
.createTextNode("x3"))
908 root
.appendChild(doc
.createTextNode(""))
909 self
.confirm(len(root
.childNodes
) == 3
910 and root
.childNodes
.length
== 3
911 and len(root
.childNodes
[0].childNodes
) == 4
912 and root
.childNodes
[0].childNodes
.length
== 4
913 and len(root
.childNodes
[1].childNodes
) == 3
914 and root
.childNodes
[1].childNodes
.length
== 3
915 and len(root
.childNodes
[1].childNodes
[0].childNodes
) == 2
916 and root
.childNodes
[1].childNodes
[0].childNodes
.length
== 2
917 , "testNormalize2 -- preparation")
919 self
.confirm(len(root
.childNodes
) == 2
920 and root
.childNodes
.length
== 2
921 and len(root
.childNodes
[0].childNodes
) == 2
922 and root
.childNodes
[0].childNodes
.length
== 2
923 and len(root
.childNodes
[1].childNodes
) == 2
924 and root
.childNodes
[1].childNodes
.length
== 2
925 and len(root
.childNodes
[1].childNodes
[0].childNodes
) == 1
926 and root
.childNodes
[1].childNodes
[0].childNodes
.length
== 1
927 , "testNormalize2 -- childNodes lengths")
928 self
.confirm(root
.childNodes
[0].childNodes
[1].data
== "tx"
929 and root
.childNodes
[1].childNodes
[0].childNodes
[0].data
== "t2x2"
930 and root
.childNodes
[1].childNodes
[1].data
== "t3x3"
931 , "testNormalize2 -- joined text fields")
932 self
.confirm(root
.childNodes
[0].childNodes
[1].nextSibling
is None
933 and root
.childNodes
[0].childNodes
[1].previousSibling
934 is root
.childNodes
[0].childNodes
[0]
935 and root
.childNodes
[0].childNodes
[0].previousSibling
is None
936 and root
.childNodes
[0].childNodes
[0].nextSibling
937 is root
.childNodes
[0].childNodes
[1]
938 and root
.childNodes
[1].childNodes
[1].nextSibling
is None
939 and root
.childNodes
[1].childNodes
[1].previousSibling
940 is root
.childNodes
[1].childNodes
[0]
941 and root
.childNodes
[1].childNodes
[0].previousSibling
is None
942 and root
.childNodes
[1].childNodes
[0].nextSibling
943 is root
.childNodes
[1].childNodes
[1]
944 , "testNormalize2 -- sibling pointers")
948 def testBug1433694(self
):
949 doc
= parseString("<o><i/>t</o>")
950 node
= doc
.documentElement
951 node
.childNodes
[1].nodeValue
= ""
953 self
.confirm(node
.childNodes
[-1].nextSibling
is None,
954 "Final child's .nextSibling should be None")
956 def testSiblings(self
):
957 doc
= parseString("<doc><?pi?>text?<elm/></doc>")
958 root
= doc
.documentElement
959 (pi
, text
, elm
) = root
.childNodes
961 self
.confirm(pi
.nextSibling
is text
and
962 pi
.previousSibling
is None and
963 text
.nextSibling
is elm
and
964 text
.previousSibling
is pi
and
965 elm
.nextSibling
is None and
966 elm
.previousSibling
is text
, "testSiblings")
970 def testParents(self
):
972 "<doc><elm1><elm2/><elm2><elm3/></elm2></elm1></doc>")
973 root
= doc
.documentElement
974 elm1
= root
.childNodes
[0]
975 (elm2a
, elm2b
) = elm1
.childNodes
976 elm3
= elm2b
.childNodes
[0]
978 self
.confirm(root
.parentNode
is doc
and
979 elm1
.parentNode
is root
and
980 elm2a
.parentNode
is elm1
and
981 elm2b
.parentNode
is elm1
and
982 elm3
.parentNode
is elm2b
, "testParents")
985 def testNodeListItem(self
):
986 doc
= parseString("<doc><e/><e/></doc>")
987 children
= doc
.childNodes
988 docelem
= children
[0]
989 self
.confirm(children
[0] is children
.item(0)
990 and children
.item(1) is None
991 and docelem
.childNodes
.item(0) is docelem
.childNodes
[0]
992 and docelem
.childNodes
.item(1) is docelem
.childNodes
[1]
993 and docelem
.childNodes
.item(0).childNodes
.item(0) is None,
994 "test NodeList.item()")
997 def testSAX2DOM(self
):
998 from xml
.dom
import pulldom
1000 sax2dom
= pulldom
.SAX2DOM()
1001 sax2dom
.startDocument()
1002 sax2dom
.startElement("doc", {})
1003 sax2dom
.characters("text")
1004 sax2dom
.startElement("subelm", {})
1005 sax2dom
.characters("text")
1006 sax2dom
.endElement("subelm")
1007 sax2dom
.characters("text")
1008 sax2dom
.endElement("doc")
1009 sax2dom
.endDocument()
1011 doc
= sax2dom
.document
1012 root
= doc
.documentElement
1013 (text1
, elm1
, text2
) = root
.childNodes
1014 text3
= elm1
.childNodes
[0]
1016 self
.confirm(text1
.previousSibling
is None and
1017 text1
.nextSibling
is elm1
and
1018 elm1
.previousSibling
is text1
and
1019 elm1
.nextSibling
is text2
and
1020 text2
.previousSibling
is elm1
and
1021 text2
.nextSibling
is None and
1022 text3
.previousSibling
is None and
1023 text3
.nextSibling
is None, "testSAX2DOM - siblings")
1025 self
.confirm(root
.parentNode
is doc
and
1026 text1
.parentNode
is root
and
1027 elm1
.parentNode
is root
and
1028 text2
.parentNode
is root
and
1029 text3
.parentNode
is elm1
, "testSAX2DOM - parents")
1032 def testEncodings(self
):
1033 doc
= parseString('<foo>€</foo>')
1034 self
.confirm(doc
.toxml() == u
'<?xml version="1.0" ?><foo>\u20ac</foo>'
1035 and doc
.toxml('utf-8') ==
1036 '<?xml version="1.0" encoding="utf-8"?><foo>\xe2\x82\xac</foo>'
1037 and doc
.toxml('iso-8859-15') ==
1038 '<?xml version="1.0" encoding="iso-8859-15"?><foo>\xa4</foo>',
1039 "testEncodings - encoding EURO SIGN")
1041 # Verify that character decoding errors throw exceptions instead
1043 self
.assertRaises(UnicodeDecodeError, parseString
,
1044 '<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')
1048 class UserDataHandler
:
1050 def handle(self
, operation
, key
, data
, src
, dst
):
1051 dst
.setUserData(key
, data
+ 1, self
)
1052 src
.setUserData(key
, None, None)
1055 def testUserData(self
):
1057 n
= dom
.createElement('e')
1058 self
.confirm(n
.getUserData("foo") is None)
1059 n
.setUserData("foo", None, None)
1060 self
.confirm(n
.getUserData("foo") is None)
1061 n
.setUserData("foo", 12, 12)
1062 n
.setUserData("bar", 13, 13)
1063 self
.confirm(n
.getUserData("foo") == 12)
1064 self
.confirm(n
.getUserData("bar") == 13)
1065 n
.setUserData("foo", None, None)
1066 self
.confirm(n
.getUserData("foo") is None)
1067 self
.confirm(n
.getUserData("bar") == 13)
1069 handler
= self
.UserDataHandler()
1070 n
.setUserData("bar", 12, handler
)
1072 self
.confirm(handler
.called
1073 and n
.getUserData("bar") is None
1074 and c
.getUserData("bar") == 13)
1079 def checkRenameNodeSharedConstraints(self
, doc
, node
):
1080 # Make sure illegal NS usage is detected:
1081 self
.assertRaises(xml
.dom
.NamespaceErr
, doc
.renameNode
, node
,
1082 "http://xml.python.org/ns", "xmlns:foo")
1083 doc2
= parseString("<doc/>")
1084 self
.assertRaises(xml
.dom
.WrongDocumentErr
, doc2
.renameNode
, node
,
1085 xml
.dom
.EMPTY_NAMESPACE
, "foo")
1087 def testRenameAttribute(self
):
1088 doc
= parseString("<doc a='v'/>")
1089 elem
= doc
.documentElement
1090 attrmap
= elem
.attributes
1091 attr
= elem
.attributes
['a']
1094 attr
= doc
.renameNode(attr
, xml
.dom
.EMPTY_NAMESPACE
, "b")
1095 self
.confirm(attr
.name
== "b"
1096 and attr
.nodeName
== "b"
1097 and attr
.localName
is None
1098 and attr
.namespaceURI
== xml
.dom
.EMPTY_NAMESPACE
1099 and attr
.prefix
is None
1100 and attr
.value
== "v"
1101 and elem
.getAttributeNode("a") is None
1102 and elem
.getAttributeNode("b").isSameNode(attr
)
1103 and attrmap
["b"].isSameNode(attr
)
1104 and attr
.ownerDocument
.isSameNode(doc
)
1105 and attr
.ownerElement
.isSameNode(elem
))
1107 # Rename to have a namespace, no prefix
1108 attr
= doc
.renameNode(attr
, "http://xml.python.org/ns", "c")
1109 self
.confirm(attr
.name
== "c"
1110 and attr
.nodeName
== "c"
1111 and attr
.localName
== "c"
1112 and attr
.namespaceURI
== "http://xml.python.org/ns"
1113 and attr
.prefix
is None
1114 and attr
.value
== "v"
1115 and elem
.getAttributeNode("a") is None
1116 and elem
.getAttributeNode("b") is None
1117 and elem
.getAttributeNode("c").isSameNode(attr
)
1118 and elem
.getAttributeNodeNS(
1119 "http://xml.python.org/ns", "c").isSameNode(attr
)
1120 and attrmap
["c"].isSameNode(attr
)
1121 and attrmap
[("http://xml.python.org/ns", "c")].isSameNode(attr
))
1123 # Rename to have a namespace, with prefix
1124 attr
= doc
.renameNode(attr
, "http://xml.python.org/ns2", "p:d")
1125 self
.confirm(attr
.name
== "p:d"
1126 and attr
.nodeName
== "p:d"
1127 and attr
.localName
== "d"
1128 and attr
.namespaceURI
== "http://xml.python.org/ns2"
1129 and attr
.prefix
== "p"
1130 and attr
.value
== "v"
1131 and elem
.getAttributeNode("a") is None
1132 and elem
.getAttributeNode("b") is None
1133 and elem
.getAttributeNode("c") is None
1134 and elem
.getAttributeNodeNS(
1135 "http://xml.python.org/ns", "c") is None
1136 and elem
.getAttributeNode("p:d").isSameNode(attr
)
1137 and elem
.getAttributeNodeNS(
1138 "http://xml.python.org/ns2", "d").isSameNode(attr
)
1139 and attrmap
["p:d"].isSameNode(attr
)
1140 and attrmap
[("http://xml.python.org/ns2", "d")].isSameNode(attr
))
1142 # Rename back to a simple non-NS node
1143 attr
= doc
.renameNode(attr
, xml
.dom
.EMPTY_NAMESPACE
, "e")
1144 self
.confirm(attr
.name
== "e"
1145 and attr
.nodeName
== "e"
1146 and attr
.localName
is None
1147 and attr
.namespaceURI
== xml
.dom
.EMPTY_NAMESPACE
1148 and attr
.prefix
is None
1149 and attr
.value
== "v"
1150 and elem
.getAttributeNode("a") is None
1151 and elem
.getAttributeNode("b") is None
1152 and elem
.getAttributeNode("c") is None
1153 and elem
.getAttributeNode("p:d") is None
1154 and elem
.getAttributeNodeNS(
1155 "http://xml.python.org/ns", "c") is None
1156 and elem
.getAttributeNode("e").isSameNode(attr
)
1157 and attrmap
["e"].isSameNode(attr
))
1159 self
.assertRaises(xml
.dom
.NamespaceErr
, doc
.renameNode
, attr
,
1160 "http://xml.python.org/ns", "xmlns")
1161 self
.checkRenameNodeSharedConstraints(doc
, attr
)
1164 def testRenameElement(self
):
1165 doc
= parseString("<doc/>")
1166 elem
= doc
.documentElement
1169 elem
= doc
.renameNode(elem
, xml
.dom
.EMPTY_NAMESPACE
, "a")
1170 self
.confirm(elem
.tagName
== "a"
1171 and elem
.nodeName
== "a"
1172 and elem
.localName
is None
1173 and elem
.namespaceURI
== xml
.dom
.EMPTY_NAMESPACE
1174 and elem
.prefix
is None
1175 and elem
.ownerDocument
.isSameNode(doc
))
1177 # Rename to have a namespace, no prefix
1178 elem
= doc
.renameNode(elem
, "http://xml.python.org/ns", "b")
1179 self
.confirm(elem
.tagName
== "b"
1180 and elem
.nodeName
== "b"
1181 and elem
.localName
== "b"
1182 and elem
.namespaceURI
== "http://xml.python.org/ns"
1183 and elem
.prefix
is None
1184 and elem
.ownerDocument
.isSameNode(doc
))
1186 # Rename to have a namespace, with prefix
1187 elem
= doc
.renameNode(elem
, "http://xml.python.org/ns2", "p:c")
1188 self
.confirm(elem
.tagName
== "p:c"
1189 and elem
.nodeName
== "p:c"
1190 and elem
.localName
== "c"
1191 and elem
.namespaceURI
== "http://xml.python.org/ns2"
1192 and elem
.prefix
== "p"
1193 and elem
.ownerDocument
.isSameNode(doc
))
1195 # Rename back to a simple non-NS node
1196 elem
= doc
.renameNode(elem
, xml
.dom
.EMPTY_NAMESPACE
, "d")
1197 self
.confirm(elem
.tagName
== "d"
1198 and elem
.nodeName
== "d"
1199 and elem
.localName
is None
1200 and elem
.namespaceURI
== xml
.dom
.EMPTY_NAMESPACE
1201 and elem
.prefix
is None
1202 and elem
.ownerDocument
.isSameNode(doc
))
1204 self
.checkRenameNodeSharedConstraints(doc
, elem
)
1207 def testRenameOther(self
):
1208 # We have to create a comment node explicitly since not all DOM
1209 # builders used with minidom add comments to the DOM.
1210 doc
= xml
.dom
.minidom
.getDOMImplementation().createDocument(
1211 xml
.dom
.EMPTY_NAMESPACE
, "e", None)
1212 node
= doc
.createComment("comment")
1213 self
.assertRaises(xml
.dom
.NotSupportedErr
, doc
.renameNode
, node
,
1214 xml
.dom
.EMPTY_NAMESPACE
, "foo")
1217 def testWholeText(self
):
1218 doc
= parseString("<doc>a</doc>")
1219 elem
= doc
.documentElement
1220 text
= elem
.childNodes
[0]
1221 self
.assertEquals(text
.nodeType
, Node
.TEXT_NODE
)
1223 self
.checkWholeText(text
, "a")
1224 elem
.appendChild(doc
.createTextNode("b"))
1225 self
.checkWholeText(text
, "ab")
1226 elem
.insertBefore(doc
.createCDATASection("c"), text
)
1227 self
.checkWholeText(text
, "cab")
1229 # make sure we don't cross other nodes
1230 splitter
= doc
.createComment("comment")
1231 elem
.appendChild(splitter
)
1232 text2
= doc
.createTextNode("d")
1233 elem
.appendChild(text2
)
1234 self
.checkWholeText(text
, "cab")
1235 self
.checkWholeText(text2
, "d")
1237 x
= doc
.createElement("x")
1238 elem
.replaceChild(x
, splitter
)
1240 self
.checkWholeText(text
, "cab")
1241 self
.checkWholeText(text2
, "d")
1243 x
= doc
.createProcessingInstruction("y", "z")
1244 elem
.replaceChild(x
, splitter
)
1246 self
.checkWholeText(text
, "cab")
1247 self
.checkWholeText(text2
, "d")
1249 elem
.removeChild(splitter
)
1250 self
.checkWholeText(text
, "cabd")
1251 self
.checkWholeText(text2
, "cabd")
1253 def testPatch1094164(self
):
1254 doc
= parseString("<doc><e/></doc>")
1255 elem
= doc
.documentElement
1257 self
.confirm(e
.parentNode
is elem
, "Before replaceChild()")
1258 # Check that replacing a child with itself leaves the tree unchanged
1259 elem
.replaceChild(e
, e
)
1260 self
.confirm(e
.parentNode
is elem
, "After replaceChild()")
1262 def testReplaceWholeText(self
):
1264 doc
= parseString("<doc>a<e/>d</doc>")
1265 elem
= doc
.documentElement
1266 text1
= elem
.firstChild
1267 text2
= elem
.lastChild
1268 splitter
= text1
.nextSibling
1269 elem
.insertBefore(doc
.createTextNode("b"), splitter
)
1270 elem
.insertBefore(doc
.createCDATASection("c"), text1
)
1271 return doc
, elem
, text1
, splitter
, text2
1273 doc
, elem
, text1
, splitter
, text2
= setup()
1274 text
= text1
.replaceWholeText("new content")
1275 self
.checkWholeText(text
, "new content")
1276 self
.checkWholeText(text2
, "d")
1277 self
.confirm(len(elem
.childNodes
) == 3)
1279 doc
, elem
, text1
, splitter
, text2
= setup()
1280 text
= text2
.replaceWholeText("new content")
1281 self
.checkWholeText(text
, "new content")
1282 self
.checkWholeText(text1
, "cab")
1283 self
.confirm(len(elem
.childNodes
) == 5)
1285 doc
, elem
, text1
, splitter
, text2
= setup()
1286 text
= text1
.replaceWholeText("")
1287 self
.checkWholeText(text2
, "d")
1288 self
.confirm(text
is None
1289 and len(elem
.childNodes
) == 2)
1291 def testSchemaType(self
):
1294 " <!ENTITY e1 SYSTEM 'http://xml.python.org/e1'>\n"
1295 " <!ENTITY e2 SYSTEM 'http://xml.python.org/e2'>\n"
1296 " <!ATTLIST doc id ID #IMPLIED \n"
1297 " ref IDREF #IMPLIED \n"
1298 " refs IDREFS #IMPLIED \n"
1299 " enum (a|b) #IMPLIED \n"
1300 " ent ENTITY #IMPLIED \n"
1301 " ents ENTITIES #IMPLIED \n"
1302 " nm NMTOKEN #IMPLIED \n"
1303 " nms NMTOKENS #IMPLIED \n"
1304 " text CDATA #IMPLIED \n"
1306 "]><doc id='name' notid='name' text='splat!' enum='b'"
1307 " ref='name' refs='name name' ent='e1' ents='e1 e2'"
1308 " nm='123' nms='123 abc' />")
1309 elem
= doc
.documentElement
1310 # We don't want to rely on any specific loader at this point, so
1311 # just make sure we can get to all the names, and that the
1312 # DTD-based namespace is right. The names can vary by loader
1313 # since each supports a different level of DTD information.
1315 self
.confirm(t
.name
is None
1316 and t
.namespace
== xml
.dom
.EMPTY_NAMESPACE
)
1317 names
= "id notid text enum ref refs ent ents nm nms".split()
1319 a
= elem
.getAttributeNode(name
)
1321 self
.confirm(hasattr(t
, "name")
1322 and t
.namespace
== xml
.dom
.EMPTY_NAMESPACE
)
1324 def testSetIdAttribute(self
):
1325 doc
= parseString("<doc a1='v' a2='w'/>")
1326 e
= doc
.documentElement
1327 a1
= e
.getAttributeNode("a1")
1328 a2
= e
.getAttributeNode("a2")
1329 self
.confirm(doc
.getElementById("v") is None
1332 e
.setIdAttribute("a1")
1333 self
.confirm(e
.isSameNode(doc
.getElementById("v"))
1336 e
.setIdAttribute("a2")
1337 self
.confirm(e
.isSameNode(doc
.getElementById("v"))
1338 and e
.isSameNode(doc
.getElementById("w"))
1341 # replace the a1 node; the new node should *not* be an ID
1342 a3
= doc
.createAttribute("a1")
1344 e
.setAttributeNode(a3
)
1345 self
.confirm(doc
.getElementById("v") is None
1346 and e
.isSameNode(doc
.getElementById("w"))
1350 # renaming an attribute should not affect its ID-ness:
1351 doc
.renameNode(a2
, xml
.dom
.EMPTY_NAMESPACE
, "an")
1352 self
.confirm(e
.isSameNode(doc
.getElementById("w"))
1355 def testSetIdAttributeNS(self
):
1356 NS1
= "http://xml.python.org/ns1"
1357 NS2
= "http://xml.python.org/ns2"
1358 doc
= parseString("<doc"
1359 " xmlns:ns1='" + NS1
+ "'"
1360 " xmlns:ns2='" + NS2
+ "'"
1361 " ns1:a1='v' ns2:a2='w'/>")
1362 e
= doc
.documentElement
1363 a1
= e
.getAttributeNodeNS(NS1
, "a1")
1364 a2
= e
.getAttributeNodeNS(NS2
, "a2")
1365 self
.confirm(doc
.getElementById("v") is None
1368 e
.setIdAttributeNS(NS1
, "a1")
1369 self
.confirm(e
.isSameNode(doc
.getElementById("v"))
1372 e
.setIdAttributeNS(NS2
, "a2")
1373 self
.confirm(e
.isSameNode(doc
.getElementById("v"))
1374 and e
.isSameNode(doc
.getElementById("w"))
1377 # replace the a1 node; the new node should *not* be an ID
1378 a3
= doc
.createAttributeNS(NS1
, "a1")
1380 e
.setAttributeNode(a3
)
1381 self
.confirm(e
.isSameNode(doc
.getElementById("w")))
1382 self
.confirm(not a1
.isId
)
1383 self
.confirm(a2
.isId
)
1384 self
.confirm(not a3
.isId
)
1385 self
.confirm(doc
.getElementById("v") is None)
1386 # renaming an attribute should not affect its ID-ness:
1387 doc
.renameNode(a2
, xml
.dom
.EMPTY_NAMESPACE
, "an")
1388 self
.confirm(e
.isSameNode(doc
.getElementById("w"))
1391 def testSetIdAttributeNode(self
):
1392 NS1
= "http://xml.python.org/ns1"
1393 NS2
= "http://xml.python.org/ns2"
1394 doc
= parseString("<doc"
1395 " xmlns:ns1='" + NS1
+ "'"
1396 " xmlns:ns2='" + NS2
+ "'"
1397 " ns1:a1='v' ns2:a2='w'/>")
1398 e
= doc
.documentElement
1399 a1
= e
.getAttributeNodeNS(NS1
, "a1")
1400 a2
= e
.getAttributeNodeNS(NS2
, "a2")
1401 self
.confirm(doc
.getElementById("v") is None
1404 e
.setIdAttributeNode(a1
)
1405 self
.confirm(e
.isSameNode(doc
.getElementById("v"))
1408 e
.setIdAttributeNode(a2
)
1409 self
.confirm(e
.isSameNode(doc
.getElementById("v"))
1410 and e
.isSameNode(doc
.getElementById("w"))
1413 # replace the a1 node; the new node should *not* be an ID
1414 a3
= doc
.createAttributeNS(NS1
, "a1")
1416 e
.setAttributeNode(a3
)
1417 self
.confirm(e
.isSameNode(doc
.getElementById("w")))
1418 self
.confirm(not a1
.isId
)
1419 self
.confirm(a2
.isId
)
1420 self
.confirm(not a3
.isId
)
1421 self
.confirm(doc
.getElementById("v") is None)
1422 # renaming an attribute should not affect its ID-ness:
1423 doc
.renameNode(a2
, xml
.dom
.EMPTY_NAMESPACE
, "an")
1424 self
.confirm(e
.isSameNode(doc
.getElementById("w"))
1427 def testPickledDocument(self
):
1428 doc
= parseString("<?xml version='1.0' encoding='us-ascii'?>\n"
1429 "<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
1430 " 'http://xml.python.org/system' [\n"
1431 " <!ELEMENT e EMPTY>\n"
1432 " <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n"
1433 "]><doc attr='value'> text\n"
1434 "<?pi sample?> <!-- comment --> <e/> </doc>")
1435 s
= pickle
.dumps(doc
)
1436 doc2
= pickle
.loads(s
)
1437 stack
= [(doc
, doc2
)]
1439 n1
, n2
= stack
.pop()
1440 self
.confirm(n1
.nodeType
== n2
.nodeType
1441 and len(n1
.childNodes
) == len(n2
.childNodes
)
1442 and n1
.nodeName
== n2
.nodeName
1443 and not n1
.isSameNode(n2
)
1444 and not n2
.isSameNode(n1
))
1445 if n1
.nodeType
== Node
.DOCUMENT_TYPE_NODE
:
1450 self
.confirm(len(n1
.entities
) == len(n2
.entities
)
1451 and len(n1
.notations
) == len(n2
.notations
))
1452 for i
in range(len(n1
.notations
)):
1453 # XXX this loop body doesn't seem to be executed?
1454 no1
= n1
.notations
.item(i
)
1455 no2
= n1
.notations
.item(i
)
1456 self
.confirm(no1
.name
== no2
.name
1457 and no1
.publicId
== no2
.publicId
1458 and no1
.systemId
== no2
.systemId
)
1459 stack
.append((no1
, no2
))
1460 for i
in range(len(n1
.entities
)):
1461 e1
= n1
.entities
.item(i
)
1462 e2
= n2
.entities
.item(i
)
1463 self
.confirm(e1
.notationName
== e2
.notationName
1464 and e1
.publicId
== e2
.publicId
1465 and e1
.systemId
== e2
.systemId
)
1466 stack
.append((e1
, e2
))
1467 if n1
.nodeType
!= Node
.DOCUMENT_NODE
:
1468 self
.confirm(n1
.ownerDocument
.isSameNode(doc
)
1469 and n2
.ownerDocument
.isSameNode(doc2
))
1470 for i
in range(len(n1
.childNodes
)):
1471 stack
.append((n1
.childNodes
[i
], n2
.childNodes
[i
]))
1473 def testSerializeCommentNodeWithDoubleHyphen(self
):
1474 doc
= create_doc_without_doctype()
1475 doc
.appendChild(doc
.createComment("foo--bar"))
1476 self
.assertRaises(ValueError, doc
.toxml
)
1479 run_unittest(MinidomTest
)
1481 if __name__
== "__main__":