blob: efb924076709f590bfa8ac5f7ba6a3059072fb88 [file] [log] [blame]
Fred Drakefbdeaad2006-07-29 16:56:15 +00001# test for xml.dom.minidom
Paul Prescod7993bcc2000-07-01 14:54:16 +00002
Martin v. Löwisfd6aaa12003-01-25 22:02:52 +00003import pickle
Martin v. Löwisfd6aaa12003-01-25 22:02:52 +00004from StringIO import StringIO
Florent Xicluna1b51c3d2010-03-13 12:41:48 +00005from test.test_support import verbose, run_unittest, findfile
Collin Winterd28fcbc2007-03-28 23:34:06 +00006import unittest
Fred Drake17647f52000-07-03 16:37:42 +00007
Fred Drakefbdeaad2006-07-29 16:56:15 +00008import xml.dom
9import xml.dom.minidom
10import xml.parsers.expat
Fred Drakec441f7b2002-07-19 22:16:41 +000011
Fred Drakefbdeaad2006-07-29 16:56:15 +000012from xml.dom.minidom import parse, Node, Document, parseString
13from xml.dom.minidom import getDOMImplementation
Martin v. Löwisfd6aaa12003-01-25 22:02:52 +000014
Fred Drakec441f7b2002-07-19 22:16:41 +000015
Florent Xicluna1b51c3d2010-03-13 12:41:48 +000016tstfile = findfile("test.xml", subdir="xmltestdata")
17
Paul Prescod7993bcc2000-07-01 14:54:16 +000018
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000019# 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.
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000022def 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 = []
Fred Drakefbdeaad2006-07-29 16:56:15 +000029 notation = xml.dom.minidom.Notation("my-notation", None,
30 "http://xml.python.org/notations/my")
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000031 doctype.notations._seq.append(notation)
Fred Drakefbdeaad2006-07-29 16:56:15 +000032 entity = xml.dom.minidom.Entity("my-entity", None,
33 "http://xml.python.org/entities/my",
34 "my-notation")
Martin v. Löwisaa5af8d2003-01-25 21:39:09 +000035 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
Collin Winterd28fcbc2007-03-28 23:34:06 +000048class MinidomTest(unittest.TestCase):
49 def tearDown(self):
Paul Prescod7993bcc2000-07-01 14:54:16 +000050 try:
Collin Winterd28fcbc2007-03-28 23:34:06 +000051 Node.allnodes
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.
55 pass
56 else:
57 self.confirm(len(Node.allnodes) == 0,
58 "assertion: len(Node.allnodes) == 0")
59 if len(Node.allnodes):
60 print "Garbage left over:"
61 if verbose:
62 print Node.allnodes.items()[0:10]
63 else:
64 # Don't print specific nodes if repeatable results
65 # are needed
66 print len(Node.allnodes)
Jeremy Hylton3b0c6002000-10-12 17:31:36 +000067 Node.allnodes = {}
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000068
Collin Winterd28fcbc2007-03-28 23:34:06 +000069 def confirm(self, test, testname = "Test"):
70 self.assertTrue(test, testname)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000071
Collin Winterd28fcbc2007-03-28 23:34:06 +000072 def checkWholeText(self, node, s):
73 t = node.wholeText
74 self.confirm(t == s, "looking for %s, found %s" % (repr(s), repr(t)))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000075
Collin Winterd28fcbc2007-03-28 23:34:06 +000076 def testParseFromFile(self):
77 dom = parse(StringIO(open(tstfile).read()))
78 dom.unlink()
79 self.confirm(isinstance(dom,Document))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000080
Collin Winterd28fcbc2007-03-28 23:34:06 +000081 def testGetElementsByTagName(self):
82 dom = parse(tstfile)
83 self.confirm(dom.getElementsByTagName("LI") == \
84 dom.documentElement.getElementsByTagName("LI"))
85 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000086
Collin Winterd28fcbc2007-03-28 23:34:06 +000087 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
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000125 and root.toxml() ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000126 "<doc><element/><foo/><bar/><element/></doc>"
127 , "testInsertBefore -- node properly placed in tree")
128 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000129
Collin Winterd28fcbc2007-03-28 23:34:06 +0000130 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()
138 frag.appendChild(c1)
139 frag.appendChild(c2)
140 frag.appendChild(c3)
141 return dom, orig, c1, c2, c3, frag
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000142
Collin Winterd28fcbc2007-03-28 23:34:06 +0000143 def testInsertBeforeFragment(self):
144 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
145 dom.documentElement.insertBefore(frag, None)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000146 self.confirm(tuple(dom.documentElement.childNodes) ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000147 (orig, c1, c2, c3),
148 "insertBefore(<fragment>, None)")
149 frag.unlink()
150 dom.unlink()
Paul Prescod10d27662000-09-18 19:07:26 +0000151
Collin Winterd28fcbc2007-03-28 23:34:06 +0000152 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
153 dom.documentElement.insertBefore(frag, orig)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000154 self.confirm(tuple(dom.documentElement.childNodes) ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000155 (c1, c2, c3, orig),
156 "insertBefore(<fragment>, orig)")
157 frag.unlink()
158 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000159
Collin Winterd28fcbc2007-03-28 23:34:06 +0000160 def testAppendChild(self):
161 dom = parse(tstfile)
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")
165 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000166
Collin Winterd28fcbc2007-03-28 23:34:06 +0000167 def testAppendChildFragment(self):
168 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
169 dom.documentElement.appendChild(frag)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000170 self.confirm(tuple(dom.documentElement.childNodes) ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000171 (orig, c1, c2, c3),
172 "appendChild(<fragment>)")
173 frag.unlink()
174 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000175
Collin Winterd28fcbc2007-03-28 23:34:06 +0000176 def testReplaceChildFragment(self):
177 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
178 dom.documentElement.replaceChild(frag, orig)
179 orig.unlink()
180 self.confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3),
181 "replaceChild(<fragment>)")
182 frag.unlink()
183 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000184
Collin Winterd28fcbc2007-03-28 23:34:06 +0000185 def testLegalChildren(self):
186 dom = Document()
187 elem = dom.createElement('element')
188 text = dom.createTextNode('text')
189 self.assertRaises(xml.dom.HierarchyRequestErr, dom.appendChild, text)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000190
Collin Winterd28fcbc2007-03-28 23:34:06 +0000191 dom.appendChild(elem)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000192 self.assertRaises(xml.dom.HierarchyRequestErr, dom.insertBefore, text,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000193 elem)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000194 self.assertRaises(xml.dom.HierarchyRequestErr, dom.replaceChild, text,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000195 elem)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000196
Collin Winterd28fcbc2007-03-28 23:34:06 +0000197 nodemap = elem.attributes
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000198 self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItem,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000199 text)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000200 self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItemNS,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000201 text)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000202
Collin Winterd28fcbc2007-03-28 23:34:06 +0000203 elem.appendChild(text)
204 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000205
Collin Winterd28fcbc2007-03-28 23:34:06 +0000206 def testNamedNodeMapSetItem(self):
207 dom = Document()
208 elem = dom.createElement('element')
209 attrs = elem.attributes
210 attrs["foo"] = "bar"
211 a = attrs.item(0)
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")
220 elem.unlink()
221 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000222
Collin Winterd28fcbc2007-03-28 23:34:06 +0000223 def testNonZero(self):
224 dom = parse(tstfile)
225 self.confirm(dom)# should not be zero
226 dom.appendChild(dom.createComment("foo"))
227 self.confirm(not dom.childNodes[-1].childNodes)
228 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000229
Collin Winterd28fcbc2007-03-28 23:34:06 +0000230 def testUnlink(self):
231 dom = parse(tstfile)
232 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000233
Collin Winterd28fcbc2007-03-28 23:34:06 +0000234 def testElement(self):
235 dom = Document()
236 dom.appendChild(dom.createElement("abc"))
237 self.confirm(dom.documentElement)
238 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000239
Collin Winterd28fcbc2007-03-28 23:34:06 +0000240 def testAAA(self):
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")
250 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000251
Collin Winterd28fcbc2007-03-28 23:34:06 +0000252 def testAAB(self):
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")
258 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000259
Collin Winterd28fcbc2007-03-28 23:34:06 +0000260 def testAddAttr(self):
261 dom = Document()
262 child = dom.appendChild(dom.createElement("abc"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000263
Collin Winterd28fcbc2007-03-28 23:34:06 +0000264 child.setAttribute("def", "ghi")
265 self.confirm(child.getAttribute("def") == "ghi")
266 self.confirm(child.attributes["def"].value == "ghi")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000267
Collin Winterd28fcbc2007-03-28 23:34:06 +0000268 child.setAttribute("jkl", "mno")
269 self.confirm(child.getAttribute("jkl") == "mno")
270 self.confirm(child.attributes["jkl"].value == "mno")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000271
Collin Winterd28fcbc2007-03-28 23:34:06 +0000272 self.confirm(len(child.attributes) == 2)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000273
Collin Winterd28fcbc2007-03-28 23:34:06 +0000274 child.setAttribute("def", "newval")
275 self.confirm(child.getAttribute("def") == "newval")
276 self.confirm(child.attributes["def"].value == "newval")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000277
Collin Winterd28fcbc2007-03-28 23:34:06 +0000278 self.confirm(len(child.attributes) == 2)
279 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000280
Collin Winterd28fcbc2007-03-28 23:34:06 +0000281 def testDeleteAttr(self):
282 dom = Document()
283 child = dom.appendChild(dom.createElement("abc"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000284
Collin Winterd28fcbc2007-03-28 23:34:06 +0000285 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)
290 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000291
Collin Winterd28fcbc2007-03-28 23:34:06 +0000292 def testRemoveAttr(self):
293 dom = Document()
294 child = dom.appendChild(dom.createElement("abc"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000295
Collin Winterd28fcbc2007-03-28 23:34:06 +0000296 child.setAttribute("def", "ghi")
297 self.confirm(len(child.attributes) == 1)
298 child.removeAttribute("def")
299 self.confirm(len(child.attributes) == 0)
300 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000301
Collin Winterd28fcbc2007-03-28 23:34:06 +0000302 def testRemoveAttrNS(self):
303 dom = Document()
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)
312 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000313
Collin Winterd28fcbc2007-03-28 23:34:06 +0000314 def testRemoveAttributeNode(self):
315 dom = Document()
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)
323 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000324
Collin Winterd28fcbc2007-03-28 23:34:06 +0000325 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")
361 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000362
Collin Winterd28fcbc2007-03-28 23:34:06 +0000363 def testGetAttrList(self):
364 pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000365
Collin Winterd28fcbc2007-03-28 23:34:06 +0000366 def testGetAttrValues(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000367
Collin Winterd28fcbc2007-03-28 23:34:06 +0000368 def testGetAttrLength(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000369
Collin Winterd28fcbc2007-03-28 23:34:06 +0000370 def testGetAttribute(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000371
Collin Winterd28fcbc2007-03-28 23:34:06 +0000372 def testGetAttributeNS(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000373
Collin Winterd28fcbc2007-03-28 23:34:06 +0000374 def testGetAttributeNode(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000375
Collin Winterd28fcbc2007-03-28 23:34:06 +0000376 def testGetElementsByTagNameNS(self):
377 d="""<foo xmlns:minidom='http://pyxml.sf.net/minidom'>
378 <minidom:myelem/>
379 </foo>"""
380 dom = parseString(d)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000381 elems = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom",
Collin Winterd28fcbc2007-03-28 23:34:06 +0000382 "myelem")
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")
389 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000390
391 def get_empty_nodelist_from_elements_by_tagName_ns_helper(self, doc, nsuri,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000392 lname):
393 nodelist = doc.getElementsByTagNameNS(nsuri, lname)
394 self.confirm(len(nodelist) == 0)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000395
Collin Winterd28fcbc2007-03-28 23:34:06 +0000396 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(
401 doc, '*', 'splat')
402 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
403 doc, 'http://xml.python.org/namespaces/a', '*')
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000404
Collin Winterd28fcbc2007-03-28 23:34:06 +0000405 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")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000412
Collin Winterd28fcbc2007-03-28 23:34:06 +0000413 def testElementReprAndStr(self):
414 dom = Document()
415 el = dom.appendChild(dom.createElement("abc"))
416 string1 = repr(el)
417 string2 = str(el)
418 self.confirm(string1 == string2)
419 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000420
Collin Winterd28fcbc2007-03-28 23:34:06 +0000421 def testElementReprAndStrUnicode(self):
422 dom = Document()
423 el = dom.appendChild(dom.createElement(u"abc"))
424 string1 = repr(el)
425 string2 = str(el)
426 self.confirm(string1 == string2)
427 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000428
Collin Winterd28fcbc2007-03-28 23:34:06 +0000429 def testElementReprAndStrUnicodeNS(self):
430 dom = Document()
431 el = dom.appendChild(
432 dom.createElementNS(u"http://www.slashdot.org", u"slash:abc"))
433 string1 = repr(el)
434 string2 = str(el)
435 self.confirm(string1 == string2)
Ezio Melotti187f93d2010-03-17 14:22:34 +0000436 self.confirm("slash:abc" in string1)
Collin Winterd28fcbc2007-03-28 23:34:06 +0000437 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000438
Collin Winterd28fcbc2007-03-28 23:34:06 +0000439 def testAttributeRepr(self):
440 dom = Document()
441 el = dom.appendChild(dom.createElement(u"abc"))
442 node = el.setAttribute("abc", "def")
443 self.confirm(str(node) == repr(node))
444 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000445
Collin Winterd28fcbc2007-03-28 23:34:06 +0000446 def testTextNodeRepr(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000447
Collin Winterd28fcbc2007-03-28 23:34:06 +0000448 def testWriteXML(self):
449 str = '<?xml version="1.0" ?><a b="c"/>'
450 dom = parseString(str)
451 domstr = dom.toxml()
452 dom.unlink()
453 self.confirm(str == domstr)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000454
Collin Winterd28fcbc2007-03-28 23:34:06 +0000455 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")
459 dom.unlink()
460 self.confirm(domstr == str.replace("\n", "\r\n"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000461
Collin Winterd28fcbc2007-03-28 23:34:06 +0000462 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)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000476
Collin Winterd28fcbc2007-03-28 23:34:06 +0000477 def testProcessingInstructionRepr(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000478
Collin Winterd28fcbc2007-03-28 23:34:06 +0000479 def testTextRepr(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000480
Collin Winterd28fcbc2007-03-28 23:34:06 +0000481 def testWriteText(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000482
Collin Winterd28fcbc2007-03-28 23:34:06 +0000483 def testDocumentElement(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000484
Collin Winterd28fcbc2007-03-28 23:34:06 +0000485 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)
490 elem.unlink()
491 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000492
Collin Winterd28fcbc2007-03-28 23:34:06 +0000493 def testCreateElementNS(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000494
Collin Winterd28fcbc2007-03-28 23:34:06 +0000495 def testCreateAttributeNS(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000496
Collin Winterd28fcbc2007-03-28 23:34:06 +0000497 def testParse(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000498
Collin Winterd28fcbc2007-03-28 23:34:06 +0000499 def testParseString(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000500
Collin Winterd28fcbc2007-03-28 23:34:06 +0000501 def testComment(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000502
Collin Winterd28fcbc2007-03-28 23:34:06 +0000503 def testAttrListItem(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000504
Collin Winterd28fcbc2007-03-28 23:34:06 +0000505 def testAttrListItems(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000506
Collin Winterd28fcbc2007-03-28 23:34:06 +0000507 def testAttrListItemNS(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000508
Collin Winterd28fcbc2007-03-28 23:34:06 +0000509 def testAttrListKeys(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000510
Collin Winterd28fcbc2007-03-28 23:34:06 +0000511 def testAttrListKeysNS(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000512
Collin Winterd28fcbc2007-03-28 23:34:06 +0000513 def testRemoveNamedItem(self):
514 doc = parseString("<doc a=''/>")
515 e = doc.documentElement
516 attrs = e.attributes
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")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000521
Collin Winterd28fcbc2007-03-28 23:34:06 +0000522 def testRemoveNamedItemNS(self):
523 doc = parseString("<doc xmlns:a='http://xml.python.org/' a:b=''/>")
524 e = doc.documentElement
525 attrs = e.attributes
526 a1 = e.getAttributeNodeNS("http://xml.python.org/", "b")
527 a2 = attrs.removeNamedItemNS("http://xml.python.org/", "b")
528 self.confirm(a1.isSameNode(a2))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000529 self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItemNS,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000530 "http://xml.python.org/", "b")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000531
Collin Winterd28fcbc2007-03-28 23:34:06 +0000532 def testAttrListValues(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000533
Collin Winterd28fcbc2007-03-28 23:34:06 +0000534 def testAttrListLength(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000535
Collin Winterd28fcbc2007-03-28 23:34:06 +0000536 def testAttrList__getitem__(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000537
Collin Winterd28fcbc2007-03-28 23:34:06 +0000538 def testAttrList__setitem__(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000539
Collin Winterd28fcbc2007-03-28 23:34:06 +0000540 def testSetAttrValueandNodeValue(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000541
Collin Winterd28fcbc2007-03-28 23:34:06 +0000542 def testParseElement(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000543
Collin Winterd28fcbc2007-03-28 23:34:06 +0000544 def testParseAttributes(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000545
Collin Winterd28fcbc2007-03-28 23:34:06 +0000546 def testParseElementNamespaces(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000547
Collin Winterd28fcbc2007-03-28 23:34:06 +0000548 def testParseAttributeNamespaces(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000549
Collin Winterd28fcbc2007-03-28 23:34:06 +0000550 def testParseProcessingInstructions(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000551
Collin Winterd28fcbc2007-03-28 23:34:06 +0000552 def testChildNodes(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000553
Collin Winterd28fcbc2007-03-28 23:34:06 +0000554 def testFirstChild(self): pass
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000555
Collin Winterd28fcbc2007-03-28 23:34:06 +0000556 def testHasChildNodes(self): pass
557
558 def _testCloneElementCopiesAttributes(self, e1, e2, test):
559 attrs1 = e1.attributes
560 attrs2 = e2.attributes
561 keys1 = attrs1.keys()
562 keys2 = attrs2.keys()
563 keys1.sort()
564 keys2.sort()
565 self.confirm(keys1 == keys2, "clone of element has same attribute keys")
566 for i in range(len(keys1)):
567 a1 = attrs1.item(i)
568 a2 = attrs2.item(i)
569 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")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000577
Collin Winterd28fcbc2007-03-28 23:34:06 +0000578 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")
588 return dom, clone
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000589
Collin Winterd28fcbc2007-03-28 23:34:06 +0000590 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")
597 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000598
Collin Winterd28fcbc2007-03-28 23:34:06 +0000599 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")
606 dom.unlink()
607
608 def testCloneDocumentShallow(self):
609 doc = parseString("<?xml version='1.0'?>\n"
610 "<!-- comment -->"
611 "<!DOCTYPE doc [\n"
612 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
613 "]>\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!")
619
620 def testCloneDocumentDeep(self):
621 doc = parseString("<?xml version='1.0'?>\n"
622 "<!-- comment -->"
623 "<!DOCTYPE doc [\n"
624 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
625 "]>\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))
644
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)
678
679 def testCloneDocumentTypeDeepNotOk(self):
680 doc = create_doc_with_doctype()
681 clone = doc.doctype.cloneNode(1)
682 self.confirm(clone is None, "testCloneDocumentTypeDeepNotOk")
683
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)
697
698 def testCloneDocumentTypeShallowNotOk(self):
699 doc = create_doc_with_doctype()
700 clone = doc.doctype.cloneNode(0)
701 self.confirm(clone is None, "testCloneDocumentTypeShallowNotOk")
702
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)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000707
Collin Winterd28fcbc2007-03-28 23:34:06 +0000708 def testImportDocumentShallow(self):
709 self.check_import_document(0, "testImportDocumentShallow")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000710
Collin Winterd28fcbc2007-03-28 23:34:06 +0000711 def testImportDocumentDeep(self):
712 self.check_import_document(1, "testImportDocumentDeep")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000713
Collin Winterd28fcbc2007-03-28 23:34:06 +0000714 def testImportDocumentTypeShallow(self):
715 src = create_doc_with_doctype()
716 target = create_doc_without_doctype()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000717 self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000718 src.doctype, 0)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000719
Collin Winterd28fcbc2007-03-28 23:34:06 +0000720 def testImportDocumentTypeDeep(self):
721 src = create_doc_with_doctype()
722 target = create_doc_without_doctype()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000723 self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000724 src.doctype, 1)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000725
Collin Winterd28fcbc2007-03-28 23:34:06 +0000726 # 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")
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000731 self.assertNotEqual(attr, None)
Collin Winterd28fcbc2007-03-28 23:34:06 +0000732 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")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000741
Collin Winterd28fcbc2007-03-28 23:34:06 +0000742 def testCloneAttributeShallow(self):
743 self.check_clone_attribute(0, "testCloneAttributeShallow")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000744
Collin Winterd28fcbc2007-03-28 23:34:06 +0000745 def testCloneAttributeDeep(self):
746 self.check_clone_attribute(1, "testCloneAttributeDeep")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000747
Collin Winterd28fcbc2007-03-28 23:34:06 +0000748 def check_clone_pi(self, deep, testName):
749 doc = parseString("<?target data?><doc/>")
750 pi = doc.firstChild
Ezio Melotti2623a372010-11-21 13:34:58 +0000751 self.assertEqual(pi.nodeType, Node.PROCESSING_INSTRUCTION_NODE)
Collin Winterd28fcbc2007-03-28 23:34:06 +0000752 clone = pi.cloneNode(deep)
753 self.confirm(clone.target == pi.target
754 and clone.data == pi.data)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000755
Collin Winterd28fcbc2007-03-28 23:34:06 +0000756 def testClonePIShallow(self):
757 self.check_clone_pi(0, "testClonePIShallow")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000758
Collin Winterd28fcbc2007-03-28 23:34:06 +0000759 def testClonePIDeep(self):
760 self.check_clone_pi(1, "testClonePIDeep")
761
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
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000768 and root.childNodes.length == 2,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000769 "testNormalize -- preparation")
770 doc.normalize()
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")
776 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000777
Collin Winterd28fcbc2007-03-28 23:34:06 +0000778 doc = parseString("<doc/>")
779 root = doc.documentElement
780 root.appendChild(doc.createTextNode(""))
781 doc.normalize()
782 self.confirm(len(root.childNodes) == 0
783 and root.childNodes.length == 0,
784 "testNormalize -- single empty node removed")
785 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000786
R. David Murray0374a822009-04-09 21:54:50 +0000787 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")
796 doc.normalize()
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")
806 doc.unlink()
807
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")
816 doc.normalize()
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")
824 doc.unlink()
825
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")
834 doc.normalize()
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")
842 doc.unlink()
843
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")
853 doc.normalize()
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")
862 doc.unlink()
863
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")
875 doc.normalize()
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")
883 doc.unlink()
884
885 def testNormalizeRecursion(self):
886 doc = parseString("<doc>"
887 "<o>"
888 "<i/>"
889 "t"
890 #
891 #x
892 "</o>"
893 "<o>"
894 "<o>"
895 "t2"
896 #x2
897 "</o>"
898 "t3"
899 #x3
900 "</o>"
901 #
902 "</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")
918 doc.normalize()
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")
945 doc.unlink()
946
947
Andrew M. Kuchling53f94d02010-07-25 23:49:57 +0000948 def testBug0777884(self):
949 doc = parseString("<o>text</o>")
950 text = doc.documentElement.childNodes[0]
Ezio Melotti2623a372010-11-21 13:34:58 +0000951 self.assertEqual(text.nodeType, Node.TEXT_NODE)
Andrew M. Kuchling53f94d02010-07-25 23:49:57 +0000952 # Should run quietly, doing nothing.
953 text.normalize()
954 doc.unlink()
955
Andrew M. Kuchling19aff0c2008-02-23 17:10:46 +0000956 def testBug1433694(self):
957 doc = parseString("<o><i/>t</o>")
958 node = doc.documentElement
959 node.childNodes[1].nodeValue = ""
960 node.normalize()
Florent Xiclunabc27c6a2010-03-19 18:34:55 +0000961 self.confirm(node.childNodes[-1].nextSibling is None,
Andrew M. Kuchling19aff0c2008-02-23 17:10:46 +0000962 "Final child's .nextSibling should be None")
963
Collin Winterd28fcbc2007-03-28 23:34:06 +0000964 def testSiblings(self):
965 doc = parseString("<doc><?pi?>text?<elm/></doc>")
966 root = doc.documentElement
967 (pi, text, elm) = root.childNodes
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000968
Collin Winterd28fcbc2007-03-28 23:34:06 +0000969 self.confirm(pi.nextSibling is text and
970 pi.previousSibling is None and
971 text.nextSibling is elm and
972 text.previousSibling is pi and
973 elm.nextSibling is None and
974 elm.previousSibling is text, "testSiblings")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000975
Collin Winterd28fcbc2007-03-28 23:34:06 +0000976 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000977
Collin Winterd28fcbc2007-03-28 23:34:06 +0000978 def testParents(self):
979 doc = parseString(
980 "<doc><elm1><elm2/><elm2><elm3/></elm2></elm1></doc>")
981 root = doc.documentElement
982 elm1 = root.childNodes[0]
983 (elm2a, elm2b) = elm1.childNodes
984 elm3 = elm2b.childNodes[0]
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000985
Collin Winterd28fcbc2007-03-28 23:34:06 +0000986 self.confirm(root.parentNode is doc and
987 elm1.parentNode is root and
988 elm2a.parentNode is elm1 and
989 elm2b.parentNode is elm1 and
990 elm3.parentNode is elm2b, "testParents")
991 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000992
Collin Winterd28fcbc2007-03-28 23:34:06 +0000993 def testNodeListItem(self):
994 doc = parseString("<doc><e/><e/></doc>")
995 children = doc.childNodes
996 docelem = children[0]
997 self.confirm(children[0] is children.item(0)
998 and children.item(1) is None
999 and docelem.childNodes.item(0) is docelem.childNodes[0]
1000 and docelem.childNodes.item(1) is docelem.childNodes[1]
1001 and docelem.childNodes.item(0).childNodes.item(0) is None,
1002 "test NodeList.item()")
1003 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001004
Collin Winterd28fcbc2007-03-28 23:34:06 +00001005 def testSAX2DOM(self):
1006 from xml.dom import pulldom
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001007
Collin Winterd28fcbc2007-03-28 23:34:06 +00001008 sax2dom = pulldom.SAX2DOM()
1009 sax2dom.startDocument()
1010 sax2dom.startElement("doc", {})
1011 sax2dom.characters("text")
1012 sax2dom.startElement("subelm", {})
1013 sax2dom.characters("text")
1014 sax2dom.endElement("subelm")
1015 sax2dom.characters("text")
1016 sax2dom.endElement("doc")
1017 sax2dom.endDocument()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001018
Collin Winterd28fcbc2007-03-28 23:34:06 +00001019 doc = sax2dom.document
1020 root = doc.documentElement
1021 (text1, elm1, text2) = root.childNodes
1022 text3 = elm1.childNodes[0]
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001023
Collin Winterd28fcbc2007-03-28 23:34:06 +00001024 self.confirm(text1.previousSibling is None and
1025 text1.nextSibling is elm1 and
1026 elm1.previousSibling is text1 and
1027 elm1.nextSibling is text2 and
1028 text2.previousSibling is elm1 and
1029 text2.nextSibling is None and
1030 text3.previousSibling is None and
1031 text3.nextSibling is None, "testSAX2DOM - siblings")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001032
Collin Winterd28fcbc2007-03-28 23:34:06 +00001033 self.confirm(root.parentNode is doc and
1034 text1.parentNode is root and
1035 elm1.parentNode is root and
1036 text2.parentNode is root and
1037 text3.parentNode is elm1, "testSAX2DOM - parents")
1038 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001039
Collin Winterd28fcbc2007-03-28 23:34:06 +00001040 def testEncodings(self):
1041 doc = parseString('<foo>&#x20ac;</foo>')
1042 self.confirm(doc.toxml() == u'<?xml version="1.0" ?><foo>\u20ac</foo>'
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001043 and doc.toxml('utf-8') ==
Collin Winterd28fcbc2007-03-28 23:34:06 +00001044 '<?xml version="1.0" encoding="utf-8"?><foo>\xe2\x82\xac</foo>'
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001045 and doc.toxml('iso-8859-15') ==
Collin Winterd28fcbc2007-03-28 23:34:06 +00001046 '<?xml version="1.0" encoding="iso-8859-15"?><foo>\xa4</foo>',
1047 "testEncodings - encoding EURO SIGN")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001048
1049 # Verify that character decoding errors throw exceptions instead
Collin Winterd28fcbc2007-03-28 23:34:06 +00001050 # of crashing
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001051 self.assertRaises(UnicodeDecodeError, parseString,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001052 '<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001053
Collin Winterd28fcbc2007-03-28 23:34:06 +00001054 doc.unlink()
1055
1056 class UserDataHandler:
1057 called = 0
1058 def handle(self, operation, key, data, src, dst):
1059 dst.setUserData(key, data + 1, self)
1060 src.setUserData(key, None, None)
1061 self.called = 1
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001062
Collin Winterd28fcbc2007-03-28 23:34:06 +00001063 def testUserData(self):
1064 dom = Document()
1065 n = dom.createElement('e')
1066 self.confirm(n.getUserData("foo") is None)
1067 n.setUserData("foo", None, None)
1068 self.confirm(n.getUserData("foo") is None)
1069 n.setUserData("foo", 12, 12)
1070 n.setUserData("bar", 13, 13)
1071 self.confirm(n.getUserData("foo") == 12)
1072 self.confirm(n.getUserData("bar") == 13)
1073 n.setUserData("foo", None, None)
1074 self.confirm(n.getUserData("foo") is None)
1075 self.confirm(n.getUserData("bar") == 13)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001076
Collin Winterd28fcbc2007-03-28 23:34:06 +00001077 handler = self.UserDataHandler()
1078 n.setUserData("bar", 12, handler)
1079 c = n.cloneNode(1)
1080 self.confirm(handler.called
1081 and n.getUserData("bar") is None
1082 and c.getUserData("bar") == 13)
1083 n.unlink()
1084 c.unlink()
1085 dom.unlink()
1086
1087 def checkRenameNodeSharedConstraints(self, doc, node):
1088 # Make sure illegal NS usage is detected:
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001089 self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, node,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001090 "http://xml.python.org/ns", "xmlns:foo")
1091 doc2 = parseString("<doc/>")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001092 self.assertRaises(xml.dom.WrongDocumentErr, doc2.renameNode, node,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001093 xml.dom.EMPTY_NAMESPACE, "foo")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001094
Collin Winterd28fcbc2007-03-28 23:34:06 +00001095 def testRenameAttribute(self):
1096 doc = parseString("<doc a='v'/>")
1097 elem = doc.documentElement
1098 attrmap = elem.attributes
1099 attr = elem.attributes['a']
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001100
Collin Winterd28fcbc2007-03-28 23:34:06 +00001101 # Simple renaming
1102 attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "b")
1103 self.confirm(attr.name == "b"
1104 and attr.nodeName == "b"
1105 and attr.localName is None
1106 and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
1107 and attr.prefix is None
1108 and attr.value == "v"
1109 and elem.getAttributeNode("a") is None
1110 and elem.getAttributeNode("b").isSameNode(attr)
1111 and attrmap["b"].isSameNode(attr)
1112 and attr.ownerDocument.isSameNode(doc)
1113 and attr.ownerElement.isSameNode(elem))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001114
Collin Winterd28fcbc2007-03-28 23:34:06 +00001115 # Rename to have a namespace, no prefix
1116 attr = doc.renameNode(attr, "http://xml.python.org/ns", "c")
1117 self.confirm(attr.name == "c"
1118 and attr.nodeName == "c"
1119 and attr.localName == "c"
1120 and attr.namespaceURI == "http://xml.python.org/ns"
1121 and attr.prefix is None
1122 and attr.value == "v"
1123 and elem.getAttributeNode("a") is None
1124 and elem.getAttributeNode("b") is None
1125 and elem.getAttributeNode("c").isSameNode(attr)
1126 and elem.getAttributeNodeNS(
1127 "http://xml.python.org/ns", "c").isSameNode(attr)
1128 and attrmap["c"].isSameNode(attr)
1129 and attrmap[("http://xml.python.org/ns", "c")].isSameNode(attr))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001130
Collin Winterd28fcbc2007-03-28 23:34:06 +00001131 # Rename to have a namespace, with prefix
1132 attr = doc.renameNode(attr, "http://xml.python.org/ns2", "p:d")
1133 self.confirm(attr.name == "p:d"
1134 and attr.nodeName == "p:d"
1135 and attr.localName == "d"
1136 and attr.namespaceURI == "http://xml.python.org/ns2"
1137 and attr.prefix == "p"
1138 and attr.value == "v"
1139 and elem.getAttributeNode("a") is None
1140 and elem.getAttributeNode("b") is None
1141 and elem.getAttributeNode("c") is None
1142 and elem.getAttributeNodeNS(
1143 "http://xml.python.org/ns", "c") is None
1144 and elem.getAttributeNode("p:d").isSameNode(attr)
1145 and elem.getAttributeNodeNS(
1146 "http://xml.python.org/ns2", "d").isSameNode(attr)
1147 and attrmap["p:d"].isSameNode(attr)
1148 and attrmap[("http://xml.python.org/ns2", "d")].isSameNode(attr))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001149
Collin Winterd28fcbc2007-03-28 23:34:06 +00001150 # Rename back to a simple non-NS node
1151 attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "e")
1152 self.confirm(attr.name == "e"
1153 and attr.nodeName == "e"
1154 and attr.localName is None
1155 and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
1156 and attr.prefix is None
1157 and attr.value == "v"
1158 and elem.getAttributeNode("a") is None
1159 and elem.getAttributeNode("b") is None
1160 and elem.getAttributeNode("c") is None
1161 and elem.getAttributeNode("p:d") is None
1162 and elem.getAttributeNodeNS(
1163 "http://xml.python.org/ns", "c") is None
1164 and elem.getAttributeNode("e").isSameNode(attr)
1165 and attrmap["e"].isSameNode(attr))
1166
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001167 self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, attr,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001168 "http://xml.python.org/ns", "xmlns")
1169 self.checkRenameNodeSharedConstraints(doc, attr)
1170 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001171
Collin Winterd28fcbc2007-03-28 23:34:06 +00001172 def testRenameElement(self):
1173 doc = parseString("<doc/>")
1174 elem = doc.documentElement
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001175
Collin Winterd28fcbc2007-03-28 23:34:06 +00001176 # Simple renaming
1177 elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "a")
1178 self.confirm(elem.tagName == "a"
1179 and elem.nodeName == "a"
1180 and elem.localName is None
1181 and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
1182 and elem.prefix is None
1183 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001184
Collin Winterd28fcbc2007-03-28 23:34:06 +00001185 # Rename to have a namespace, no prefix
1186 elem = doc.renameNode(elem, "http://xml.python.org/ns", "b")
1187 self.confirm(elem.tagName == "b"
1188 and elem.nodeName == "b"
1189 and elem.localName == "b"
1190 and elem.namespaceURI == "http://xml.python.org/ns"
1191 and elem.prefix is None
1192 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001193
Collin Winterd28fcbc2007-03-28 23:34:06 +00001194 # Rename to have a namespace, with prefix
1195 elem = doc.renameNode(elem, "http://xml.python.org/ns2", "p:c")
1196 self.confirm(elem.tagName == "p:c"
1197 and elem.nodeName == "p:c"
1198 and elem.localName == "c"
1199 and elem.namespaceURI == "http://xml.python.org/ns2"
1200 and elem.prefix == "p"
1201 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001202
Collin Winterd28fcbc2007-03-28 23:34:06 +00001203 # Rename back to a simple non-NS node
1204 elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "d")
1205 self.confirm(elem.tagName == "d"
1206 and elem.nodeName == "d"
1207 and elem.localName is None
1208 and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
1209 and elem.prefix is None
1210 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001211
Collin Winterd28fcbc2007-03-28 23:34:06 +00001212 self.checkRenameNodeSharedConstraints(doc, elem)
1213 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001214
Collin Winterd28fcbc2007-03-28 23:34:06 +00001215 def testRenameOther(self):
1216 # We have to create a comment node explicitly since not all DOM
1217 # builders used with minidom add comments to the DOM.
1218 doc = xml.dom.minidom.getDOMImplementation().createDocument(
1219 xml.dom.EMPTY_NAMESPACE, "e", None)
1220 node = doc.createComment("comment")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001221 self.assertRaises(xml.dom.NotSupportedErr, doc.renameNode, node,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001222 xml.dom.EMPTY_NAMESPACE, "foo")
1223 doc.unlink()
1224
1225 def testWholeText(self):
1226 doc = parseString("<doc>a</doc>")
1227 elem = doc.documentElement
1228 text = elem.childNodes[0]
Ezio Melotti2623a372010-11-21 13:34:58 +00001229 self.assertEqual(text.nodeType, Node.TEXT_NODE)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001230
Collin Winterd28fcbc2007-03-28 23:34:06 +00001231 self.checkWholeText(text, "a")
1232 elem.appendChild(doc.createTextNode("b"))
1233 self.checkWholeText(text, "ab")
1234 elem.insertBefore(doc.createCDATASection("c"), text)
1235 self.checkWholeText(text, "cab")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001236
Collin Winterd28fcbc2007-03-28 23:34:06 +00001237 # make sure we don't cross other nodes
1238 splitter = doc.createComment("comment")
1239 elem.appendChild(splitter)
1240 text2 = doc.createTextNode("d")
1241 elem.appendChild(text2)
1242 self.checkWholeText(text, "cab")
1243 self.checkWholeText(text2, "d")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001244
Collin Winterd28fcbc2007-03-28 23:34:06 +00001245 x = doc.createElement("x")
1246 elem.replaceChild(x, splitter)
1247 splitter = x
1248 self.checkWholeText(text, "cab")
1249 self.checkWholeText(text2, "d")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001250
Collin Winterd28fcbc2007-03-28 23:34:06 +00001251 x = doc.createProcessingInstruction("y", "z")
1252 elem.replaceChild(x, splitter)
1253 splitter = x
1254 self.checkWholeText(text, "cab")
1255 self.checkWholeText(text2, "d")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001256
Collin Winterd28fcbc2007-03-28 23:34:06 +00001257 elem.removeChild(splitter)
1258 self.checkWholeText(text, "cabd")
1259 self.checkWholeText(text2, "cabd")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001260
Collin Winterd28fcbc2007-03-28 23:34:06 +00001261 def testPatch1094164(self):
1262 doc = parseString("<doc><e/></doc>")
1263 elem = doc.documentElement
1264 e = elem.firstChild
1265 self.confirm(e.parentNode is elem, "Before replaceChild()")
1266 # Check that replacing a child with itself leaves the tree unchanged
1267 elem.replaceChild(e, e)
1268 self.confirm(e.parentNode is elem, "After replaceChild()")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001269
Collin Winterd28fcbc2007-03-28 23:34:06 +00001270 def testReplaceWholeText(self):
1271 def setup():
1272 doc = parseString("<doc>a<e/>d</doc>")
1273 elem = doc.documentElement
1274 text1 = elem.firstChild
1275 text2 = elem.lastChild
1276 splitter = text1.nextSibling
1277 elem.insertBefore(doc.createTextNode("b"), splitter)
1278 elem.insertBefore(doc.createCDATASection("c"), text1)
1279 return doc, elem, text1, splitter, text2
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001280
Collin Winterd28fcbc2007-03-28 23:34:06 +00001281 doc, elem, text1, splitter, text2 = setup()
1282 text = text1.replaceWholeText("new content")
1283 self.checkWholeText(text, "new content")
1284 self.checkWholeText(text2, "d")
1285 self.confirm(len(elem.childNodes) == 3)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001286
Collin Winterd28fcbc2007-03-28 23:34:06 +00001287 doc, elem, text1, splitter, text2 = setup()
1288 text = text2.replaceWholeText("new content")
1289 self.checkWholeText(text, "new content")
1290 self.checkWholeText(text1, "cab")
1291 self.confirm(len(elem.childNodes) == 5)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001292
Collin Winterd28fcbc2007-03-28 23:34:06 +00001293 doc, elem, text1, splitter, text2 = setup()
1294 text = text1.replaceWholeText("")
1295 self.checkWholeText(text2, "d")
1296 self.confirm(text is None
1297 and len(elem.childNodes) == 2)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001298
Collin Winterd28fcbc2007-03-28 23:34:06 +00001299 def testSchemaType(self):
1300 doc = parseString(
1301 "<!DOCTYPE doc [\n"
1302 " <!ENTITY e1 SYSTEM 'http://xml.python.org/e1'>\n"
1303 " <!ENTITY e2 SYSTEM 'http://xml.python.org/e2'>\n"
1304 " <!ATTLIST doc id ID #IMPLIED \n"
1305 " ref IDREF #IMPLIED \n"
1306 " refs IDREFS #IMPLIED \n"
1307 " enum (a|b) #IMPLIED \n"
1308 " ent ENTITY #IMPLIED \n"
1309 " ents ENTITIES #IMPLIED \n"
1310 " nm NMTOKEN #IMPLIED \n"
1311 " nms NMTOKENS #IMPLIED \n"
1312 " text CDATA #IMPLIED \n"
1313 " >\n"
1314 "]><doc id='name' notid='name' text='splat!' enum='b'"
1315 " ref='name' refs='name name' ent='e1' ents='e1 e2'"
1316 " nm='123' nms='123 abc' />")
1317 elem = doc.documentElement
1318 # We don't want to rely on any specific loader at this point, so
1319 # just make sure we can get to all the names, and that the
1320 # DTD-based namespace is right. The names can vary by loader
1321 # since each supports a different level of DTD information.
1322 t = elem.schemaType
1323 self.confirm(t.name is None
1324 and t.namespace == xml.dom.EMPTY_NAMESPACE)
1325 names = "id notid text enum ref refs ent ents nm nms".split()
1326 for name in names:
1327 a = elem.getAttributeNode(name)
1328 t = a.schemaType
1329 self.confirm(hasattr(t, "name")
1330 and t.namespace == xml.dom.EMPTY_NAMESPACE)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001331
Collin Winterd28fcbc2007-03-28 23:34:06 +00001332 def testSetIdAttribute(self):
1333 doc = parseString("<doc a1='v' a2='w'/>")
1334 e = doc.documentElement
1335 a1 = e.getAttributeNode("a1")
1336 a2 = e.getAttributeNode("a2")
1337 self.confirm(doc.getElementById("v") is None
1338 and not a1.isId
1339 and not a2.isId)
1340 e.setIdAttribute("a1")
1341 self.confirm(e.isSameNode(doc.getElementById("v"))
1342 and a1.isId
1343 and not a2.isId)
1344 e.setIdAttribute("a2")
1345 self.confirm(e.isSameNode(doc.getElementById("v"))
1346 and e.isSameNode(doc.getElementById("w"))
1347 and a1.isId
1348 and a2.isId)
1349 # replace the a1 node; the new node should *not* be an ID
1350 a3 = doc.createAttribute("a1")
1351 a3.value = "v"
1352 e.setAttributeNode(a3)
1353 self.confirm(doc.getElementById("v") is None
1354 and e.isSameNode(doc.getElementById("w"))
1355 and not a1.isId
1356 and a2.isId
1357 and not a3.isId)
1358 # renaming an attribute should not affect its ID-ness:
1359 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1360 self.confirm(e.isSameNode(doc.getElementById("w"))
1361 and a2.isId)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001362
Collin Winterd28fcbc2007-03-28 23:34:06 +00001363 def testSetIdAttributeNS(self):
1364 NS1 = "http://xml.python.org/ns1"
1365 NS2 = "http://xml.python.org/ns2"
1366 doc = parseString("<doc"
1367 " xmlns:ns1='" + NS1 + "'"
1368 " xmlns:ns2='" + NS2 + "'"
1369 " ns1:a1='v' ns2:a2='w'/>")
1370 e = doc.documentElement
1371 a1 = e.getAttributeNodeNS(NS1, "a1")
1372 a2 = e.getAttributeNodeNS(NS2, "a2")
1373 self.confirm(doc.getElementById("v") is None
1374 and not a1.isId
1375 and not a2.isId)
1376 e.setIdAttributeNS(NS1, "a1")
1377 self.confirm(e.isSameNode(doc.getElementById("v"))
1378 and a1.isId
1379 and not a2.isId)
1380 e.setIdAttributeNS(NS2, "a2")
1381 self.confirm(e.isSameNode(doc.getElementById("v"))
1382 and e.isSameNode(doc.getElementById("w"))
1383 and a1.isId
1384 and a2.isId)
1385 # replace the a1 node; the new node should *not* be an ID
1386 a3 = doc.createAttributeNS(NS1, "a1")
1387 a3.value = "v"
1388 e.setAttributeNode(a3)
1389 self.confirm(e.isSameNode(doc.getElementById("w")))
1390 self.confirm(not a1.isId)
1391 self.confirm(a2.isId)
1392 self.confirm(not a3.isId)
1393 self.confirm(doc.getElementById("v") is None)
1394 # renaming an attribute should not affect its ID-ness:
1395 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1396 self.confirm(e.isSameNode(doc.getElementById("w"))
1397 and a2.isId)
1398
1399 def testSetIdAttributeNode(self):
1400 NS1 = "http://xml.python.org/ns1"
1401 NS2 = "http://xml.python.org/ns2"
1402 doc = parseString("<doc"
1403 " xmlns:ns1='" + NS1 + "'"
1404 " xmlns:ns2='" + NS2 + "'"
1405 " ns1:a1='v' ns2:a2='w'/>")
1406 e = doc.documentElement
1407 a1 = e.getAttributeNodeNS(NS1, "a1")
1408 a2 = e.getAttributeNodeNS(NS2, "a2")
1409 self.confirm(doc.getElementById("v") is None
1410 and not a1.isId
1411 and not a2.isId)
1412 e.setIdAttributeNode(a1)
1413 self.confirm(e.isSameNode(doc.getElementById("v"))
1414 and a1.isId
1415 and not a2.isId)
1416 e.setIdAttributeNode(a2)
1417 self.confirm(e.isSameNode(doc.getElementById("v"))
1418 and e.isSameNode(doc.getElementById("w"))
1419 and a1.isId
1420 and a2.isId)
1421 # replace the a1 node; the new node should *not* be an ID
1422 a3 = doc.createAttributeNS(NS1, "a1")
1423 a3.value = "v"
1424 e.setAttributeNode(a3)
1425 self.confirm(e.isSameNode(doc.getElementById("w")))
1426 self.confirm(not a1.isId)
1427 self.confirm(a2.isId)
1428 self.confirm(not a3.isId)
1429 self.confirm(doc.getElementById("v") is None)
1430 # renaming an attribute should not affect its ID-ness:
1431 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1432 self.confirm(e.isSameNode(doc.getElementById("w"))
1433 and a2.isId)
1434
1435 def testPickledDocument(self):
1436 doc = parseString("<?xml version='1.0' encoding='us-ascii'?>\n"
1437 "<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
1438 " 'http://xml.python.org/system' [\n"
1439 " <!ELEMENT e EMPTY>\n"
1440 " <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n"
1441 "]><doc attr='value'> text\n"
1442 "<?pi sample?> <!-- comment --> <e/> </doc>")
1443 s = pickle.dumps(doc)
1444 doc2 = pickle.loads(s)
1445 stack = [(doc, doc2)]
1446 while stack:
1447 n1, n2 = stack.pop()
1448 self.confirm(n1.nodeType == n2.nodeType
1449 and len(n1.childNodes) == len(n2.childNodes)
1450 and n1.nodeName == n2.nodeName
1451 and not n1.isSameNode(n2)
1452 and not n2.isSameNode(n1))
1453 if n1.nodeType == Node.DOCUMENT_TYPE_NODE:
1454 len(n1.entities)
1455 len(n2.entities)
1456 len(n1.notations)
1457 len(n2.notations)
1458 self.confirm(len(n1.entities) == len(n2.entities)
1459 and len(n1.notations) == len(n2.notations))
1460 for i in range(len(n1.notations)):
Georg Brandlcd4a21b2010-02-06 23:34:10 +00001461 # XXX this loop body doesn't seem to be executed?
Collin Winterd28fcbc2007-03-28 23:34:06 +00001462 no1 = n1.notations.item(i)
1463 no2 = n1.notations.item(i)
1464 self.confirm(no1.name == no2.name
1465 and no1.publicId == no2.publicId
1466 and no1.systemId == no2.systemId)
Georg Brandlcd4a21b2010-02-06 23:34:10 +00001467 stack.append((no1, no2))
Collin Winterd28fcbc2007-03-28 23:34:06 +00001468 for i in range(len(n1.entities)):
1469 e1 = n1.entities.item(i)
1470 e2 = n2.entities.item(i)
1471 self.confirm(e1.notationName == e2.notationName
1472 and e1.publicId == e2.publicId
1473 and e1.systemId == e2.systemId)
1474 stack.append((e1, e2))
1475 if n1.nodeType != Node.DOCUMENT_NODE:
1476 self.confirm(n1.ownerDocument.isSameNode(doc)
1477 and n2.ownerDocument.isSameNode(doc2))
1478 for i in range(len(n1.childNodes)):
1479 stack.append((n1.childNodes[i], n2.childNodes[i]))
1480
Martin v. Löwis27e4a172008-05-23 15:18:28 +00001481 def testSerializeCommentNodeWithDoubleHyphen(self):
1482 doc = create_doc_without_doctype()
1483 doc.appendChild(doc.createComment("foo--bar"))
1484 self.assertRaises(ValueError, doc.toxml)
1485
Georg Brandl5ded7912010-11-26 07:35:31 +00001486 def testEmptyXMLNSValue(self):
1487 doc = parseString("<element xmlns=''>\n"
1488 "<foo/>\n</element>")
1489 doc2 = parseString(doc.toxml())
1490 self.confirm(doc2.namespaceURI == xml.dom.EMPTY_NAMESPACE)
1491
1492
Collin Winterd28fcbc2007-03-28 23:34:06 +00001493def test_main():
1494 run_unittest(MinidomTest)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001495
Collin Winterd28fcbc2007-03-28 23:34:06 +00001496if __name__ == "__main__":
1497 test_main()