source: python/trunk/Lib/test/test_minidom.py

Last change on this file was 391, checked in by dmik, 11 years ago

python: Merge vendor 2.7.6 to trunk.

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