blob: 66973ed8a8d7d51c03ccb11e103ff8e4583c6e25 [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):
Collin Winterd28fcbc2007-03-28 23:34:06 +000049 def confirm(self, test, testname = "Test"):
50 self.assertTrue(test, testname)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000051
Collin Winterd28fcbc2007-03-28 23:34:06 +000052 def checkWholeText(self, node, s):
53 t = node.wholeText
54 self.confirm(t == s, "looking for %s, found %s" % (repr(s), repr(t)))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000055
Collin Winterd28fcbc2007-03-28 23:34:06 +000056 def testParseFromFile(self):
57 dom = parse(StringIO(open(tstfile).read()))
58 dom.unlink()
59 self.confirm(isinstance(dom,Document))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000060
Collin Winterd28fcbc2007-03-28 23:34:06 +000061 def testGetElementsByTagName(self):
62 dom = parse(tstfile)
63 self.confirm(dom.getElementsByTagName("LI") == \
64 dom.documentElement.getElementsByTagName("LI"))
65 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000066
Collin Winterd28fcbc2007-03-28 23:34:06 +000067 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
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000105 and root.toxml() ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000106 "<doc><element/><foo/><bar/><element/></doc>"
107 , "testInsertBefore -- node properly placed in tree")
108 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000109
Collin Winterd28fcbc2007-03-28 23:34:06 +0000110 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
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000122
Collin Winterd28fcbc2007-03-28 23:34:06 +0000123 def testInsertBeforeFragment(self):
124 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
125 dom.documentElement.insertBefore(frag, None)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000126 self.confirm(tuple(dom.documentElement.childNodes) ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000127 (orig, c1, c2, c3),
128 "insertBefore(<fragment>, None)")
129 frag.unlink()
130 dom.unlink()
Paul Prescod10d27662000-09-18 19:07:26 +0000131
Collin Winterd28fcbc2007-03-28 23:34:06 +0000132 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
133 dom.documentElement.insertBefore(frag, orig)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000134 self.confirm(tuple(dom.documentElement.childNodes) ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000135 (c1, c2, c3, orig),
136 "insertBefore(<fragment>, orig)")
137 frag.unlink()
138 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000139
Collin Winterd28fcbc2007-03-28 23:34:06 +0000140 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()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000146
Collin Winterd28fcbc2007-03-28 23:34:06 +0000147 def testAppendChildFragment(self):
148 dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
149 dom.documentElement.appendChild(frag)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000150 self.confirm(tuple(dom.documentElement.childNodes) ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000151 (orig, c1, c2, c3),
152 "appendChild(<fragment>)")
153 frag.unlink()
154 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000155
Collin Winterd28fcbc2007-03-28 23:34:06 +0000156 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()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000164
Collin Winterd28fcbc2007-03-28 23:34:06 +0000165 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)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000170
Collin Winterd28fcbc2007-03-28 23:34:06 +0000171 dom.appendChild(elem)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000172 self.assertRaises(xml.dom.HierarchyRequestErr, dom.insertBefore, text,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000173 elem)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000174 self.assertRaises(xml.dom.HierarchyRequestErr, dom.replaceChild, text,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000175 elem)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000176
Collin Winterd28fcbc2007-03-28 23:34:06 +0000177 nodemap = elem.attributes
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000178 self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItem,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000179 text)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000180 self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItemNS,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000181 text)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000182
Collin Winterd28fcbc2007-03-28 23:34:06 +0000183 elem.appendChild(text)
184 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000185
Collin Winterd28fcbc2007-03-28 23:34:06 +0000186 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()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000202
Collin Winterd28fcbc2007-03-28 23:34:06 +0000203 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()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000209
Collin Winterd28fcbc2007-03-28 23:34:06 +0000210 def testUnlink(self):
211 dom = parse(tstfile)
212 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000213
Collin Winterd28fcbc2007-03-28 23:34:06 +0000214 def testElement(self):
215 dom = Document()
216 dom.appendChild(dom.createElement("abc"))
217 self.confirm(dom.documentElement)
218 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000219
Collin Winterd28fcbc2007-03-28 23:34:06 +0000220 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()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000231
Collin Winterd28fcbc2007-03-28 23:34:06 +0000232 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()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000239
Collin Winterd28fcbc2007-03-28 23:34:06 +0000240 def testAddAttr(self):
241 dom = Document()
242 child = dom.appendChild(dom.createElement("abc"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000243
Collin Winterd28fcbc2007-03-28 23:34:06 +0000244 child.setAttribute("def", "ghi")
245 self.confirm(child.getAttribute("def") == "ghi")
246 self.confirm(child.attributes["def"].value == "ghi")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000247
Collin Winterd28fcbc2007-03-28 23:34:06 +0000248 child.setAttribute("jkl", "mno")
249 self.confirm(child.getAttribute("jkl") == "mno")
250 self.confirm(child.attributes["jkl"].value == "mno")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000251
Collin Winterd28fcbc2007-03-28 23:34:06 +0000252 self.confirm(len(child.attributes) == 2)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000253
Collin Winterd28fcbc2007-03-28 23:34:06 +0000254 child.setAttribute("def", "newval")
255 self.confirm(child.getAttribute("def") == "newval")
256 self.confirm(child.attributes["def"].value == "newval")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000257
Collin Winterd28fcbc2007-03-28 23:34:06 +0000258 self.confirm(len(child.attributes) == 2)
259 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000260
Collin Winterd28fcbc2007-03-28 23:34:06 +0000261 def testDeleteAttr(self):
262 dom = Document()
263 child = dom.appendChild(dom.createElement("abc"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000264
Collin Winterd28fcbc2007-03-28 23:34:06 +0000265 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()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000271
Collin Winterd28fcbc2007-03-28 23:34:06 +0000272 def testRemoveAttr(self):
273 dom = Document()
274 child = dom.appendChild(dom.createElement("abc"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000275
Collin Winterd28fcbc2007-03-28 23:34:06 +0000276 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()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000281
Collin Winterd28fcbc2007-03-28 23:34:06 +0000282 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()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000293
Collin Winterd28fcbc2007-03-28 23:34:06 +0000294 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()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000304
Collin Winterd28fcbc2007-03-28 23:34:06 +0000305 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()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000342
Collin Winterd28fcbc2007-03-28 23:34:06 +0000343 def testGetElementsByTagNameNS(self):
344 d="""<foo xmlns:minidom='http://pyxml.sf.net/minidom'>
345 <minidom:myelem/>
346 </foo>"""
347 dom = parseString(d)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000348 elems = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom",
Collin Winterd28fcbc2007-03-28 23:34:06 +0000349 "myelem")
350 self.confirm(len(elems) == 1
351 and elems[0].namespaceURI == "http://pyxml.sf.net/minidom"
352 and elems[0].localName == "myelem"
353 and elems[0].prefix == "minidom"
354 and elems[0].tagName == "minidom:myelem"
355 and elems[0].nodeName == "minidom:myelem")
356 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000357
358 def get_empty_nodelist_from_elements_by_tagName_ns_helper(self, doc, nsuri,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000359 lname):
360 nodelist = doc.getElementsByTagNameNS(nsuri, lname)
361 self.confirm(len(nodelist) == 0)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000362
Collin Winterd28fcbc2007-03-28 23:34:06 +0000363 def testGetEmptyNodeListFromElementsByTagNameNS(self):
364 doc = parseString('<doc/>')
365 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
366 doc, 'http://xml.python.org/namespaces/a', 'localname')
367 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
368 doc, '*', 'splat')
369 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
370 doc, 'http://xml.python.org/namespaces/a', '*')
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000371
Collin Winterd28fcbc2007-03-28 23:34:06 +0000372 doc = parseString('<doc xmlns="http://xml.python.org/splat"><e/></doc>')
373 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
374 doc, "http://xml.python.org/splat", "not-there")
375 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
376 doc, "*", "not-there")
377 self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
378 doc, "http://somewhere.else.net/not-there", "e")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000379
Collin Winterd28fcbc2007-03-28 23:34:06 +0000380 def testElementReprAndStr(self):
381 dom = Document()
382 el = dom.appendChild(dom.createElement("abc"))
383 string1 = repr(el)
384 string2 = str(el)
385 self.confirm(string1 == string2)
386 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000387
Collin Winterd28fcbc2007-03-28 23:34:06 +0000388 def testElementReprAndStrUnicode(self):
389 dom = Document()
390 el = dom.appendChild(dom.createElement(u"abc"))
391 string1 = repr(el)
392 string2 = str(el)
393 self.confirm(string1 == string2)
394 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000395
Collin Winterd28fcbc2007-03-28 23:34:06 +0000396 def testElementReprAndStrUnicodeNS(self):
397 dom = Document()
398 el = dom.appendChild(
399 dom.createElementNS(u"http://www.slashdot.org", u"slash:abc"))
400 string1 = repr(el)
401 string2 = str(el)
402 self.confirm(string1 == string2)
Ezio Melotti187f93d2010-03-17 14:22:34 +0000403 self.confirm("slash:abc" in string1)
Collin Winterd28fcbc2007-03-28 23:34:06 +0000404 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000405
Collin Winterd28fcbc2007-03-28 23:34:06 +0000406 def testAttributeRepr(self):
407 dom = Document()
408 el = dom.appendChild(dom.createElement(u"abc"))
409 node = el.setAttribute("abc", "def")
410 self.confirm(str(node) == repr(node))
411 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000412
Collin Winterd28fcbc2007-03-28 23:34:06 +0000413 def testWriteXML(self):
414 str = '<?xml version="1.0" ?><a b="c"/>'
415 dom = parseString(str)
416 domstr = dom.toxml()
417 dom.unlink()
418 self.confirm(str == domstr)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000419
Collin Winterd28fcbc2007-03-28 23:34:06 +0000420 def testAltNewline(self):
421 str = '<?xml version="1.0" ?>\n<a b="c"/>\n'
422 dom = parseString(str)
423 domstr = dom.toprettyxml(newl="\r\n")
424 dom.unlink()
425 self.confirm(domstr == str.replace("\n", "\r\n"))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000426
Ezio Melotti93bbb6a2011-11-18 17:30:28 +0200427 def test_toprettyxml_with_text_nodes(self):
428 # see issue #4147, text nodes are not indented
429 decl = '<?xml version="1.0" ?>\n'
430 self.assertEqual(parseString('<B>A</B>').toprettyxml(),
431 decl + '<B>A</B>\n')
432 self.assertEqual(parseString('<C>A<B>A</B></C>').toprettyxml(),
433 decl + '<C>\n\tA\n\t<B>A</B>\n</C>\n')
434 self.assertEqual(parseString('<C><B>A</B>A</C>').toprettyxml(),
435 decl + '<C>\n\t<B>A</B>\n\tA\n</C>\n')
436 self.assertEqual(parseString('<C><B>A</B><B>A</B></C>').toprettyxml(),
437 decl + '<C>\n\t<B>A</B>\n\t<B>A</B>\n</C>\n')
438 self.assertEqual(parseString('<C><B>A</B>A<B>A</B></C>').toprettyxml(),
439 decl + '<C>\n\t<B>A</B>\n\tA\n\t<B>A</B>\n</C>\n')
440
441 def test_toprettyxml_with_adjacent_text_nodes(self):
442 # see issue #4147, adjacent text nodes are indented normally
443 dom = Document()
444 elem = dom.createElement(u'elem')
445 elem.appendChild(dom.createTextNode(u'TEXT'))
446 elem.appendChild(dom.createTextNode(u'TEXT'))
447 dom.appendChild(elem)
448 decl = '<?xml version="1.0" ?>\n'
449 self.assertEqual(dom.toprettyxml(),
450 decl + '<elem>\n\tTEXT\n\tTEXT\n</elem>\n')
451
Éric Araujo2710bc42011-10-05 02:35:09 +0200452 def test_toprettyxml_preserves_content_of_text_node(self):
Ezio Melotti93bbb6a2011-11-18 17:30:28 +0200453 # see issue #4147
454 for str in ('<B>A</B>', '<A><B>C</B></A>'):
455 dom = parseString(str)
456 dom2 = parseString(dom.toprettyxml())
457 self.assertEqual(
458 dom.getElementsByTagName('B')[0].childNodes[0].toxml(),
459 dom2.getElementsByTagName('B')[0].childNodes[0].toxml())
R David Murrayc8faf9b2011-10-01 16:49:25 -0400460
Collin Winterd28fcbc2007-03-28 23:34:06 +0000461 def testProcessingInstruction(self):
462 dom = parseString('<e><?mypi \t\n data \t\n ?></e>')
463 pi = dom.documentElement.firstChild
464 self.confirm(pi.target == "mypi"
465 and pi.data == "data \t\n "
466 and pi.nodeName == "mypi"
467 and pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE
468 and pi.attributes is None
469 and not pi.hasChildNodes()
470 and len(pi.childNodes) == 0
471 and pi.firstChild is None
472 and pi.lastChild is None
473 and pi.localName is None
474 and pi.namespaceURI == xml.dom.EMPTY_NAMESPACE)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000475
Collin Winterd28fcbc2007-03-28 23:34:06 +0000476 def testTooManyDocumentElements(self):
477 doc = parseString("<doc/>")
478 elem = doc.createElement("extra")
479 # Should raise an exception when adding an extra document element.
480 self.assertRaises(xml.dom.HierarchyRequestErr, doc.appendChild, elem)
481 elem.unlink()
482 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000483
Collin Winterd28fcbc2007-03-28 23:34:06 +0000484 def testRemoveNamedItem(self):
485 doc = parseString("<doc a=''/>")
486 e = doc.documentElement
487 attrs = e.attributes
488 a1 = e.getAttributeNode("a")
489 a2 = attrs.removeNamedItem("a")
490 self.confirm(a1.isSameNode(a2))
491 self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItem, "a")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000492
Collin Winterd28fcbc2007-03-28 23:34:06 +0000493 def testRemoveNamedItemNS(self):
494 doc = parseString("<doc xmlns:a='http://xml.python.org/' a:b=''/>")
495 e = doc.documentElement
496 attrs = e.attributes
497 a1 = e.getAttributeNodeNS("http://xml.python.org/", "b")
498 a2 = attrs.removeNamedItemNS("http://xml.python.org/", "b")
499 self.confirm(a1.isSameNode(a2))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000500 self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItemNS,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000501 "http://xml.python.org/", "b")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000502
Collin Winterd28fcbc2007-03-28 23:34:06 +0000503 def _testCloneElementCopiesAttributes(self, e1, e2, test):
504 attrs1 = e1.attributes
505 attrs2 = e2.attributes
506 keys1 = attrs1.keys()
507 keys2 = attrs2.keys()
508 keys1.sort()
509 keys2.sort()
510 self.confirm(keys1 == keys2, "clone of element has same attribute keys")
511 for i in range(len(keys1)):
512 a1 = attrs1.item(i)
513 a2 = attrs2.item(i)
514 self.confirm(a1 is not a2
515 and a1.value == a2.value
516 and a1.nodeValue == a2.nodeValue
517 and a1.namespaceURI == a2.namespaceURI
518 and a1.localName == a2.localName
519 , "clone of attribute node has proper attribute values")
520 self.confirm(a2.ownerElement is e2,
521 "clone of attribute node correctly owned")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000522
Collin Winterd28fcbc2007-03-28 23:34:06 +0000523 def _setupCloneElement(self, deep):
524 dom = parseString("<doc attr='value'><foo/></doc>")
525 root = dom.documentElement
526 clone = root.cloneNode(deep)
527 self._testCloneElementCopiesAttributes(
528 root, clone, "testCloneElement" + (deep and "Deep" or "Shallow"))
529 # mutilate the original so shared data is detected
530 root.tagName = root.nodeName = "MODIFIED"
531 root.setAttribute("attr", "NEW VALUE")
532 root.setAttribute("added", "VALUE")
533 return dom, clone
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000534
Collin Winterd28fcbc2007-03-28 23:34:06 +0000535 def testCloneElementShallow(self):
536 dom, clone = self._setupCloneElement(0)
537 self.confirm(len(clone.childNodes) == 0
538 and clone.childNodes.length == 0
539 and clone.parentNode is None
540 and clone.toxml() == '<doc attr="value"/>'
541 , "testCloneElementShallow")
542 dom.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000543
Collin Winterd28fcbc2007-03-28 23:34:06 +0000544 def testCloneElementDeep(self):
545 dom, clone = self._setupCloneElement(1)
546 self.confirm(len(clone.childNodes) == 1
547 and clone.childNodes.length == 1
548 and clone.parentNode is None
549 and clone.toxml() == '<doc attr="value"><foo/></doc>'
550 , "testCloneElementDeep")
551 dom.unlink()
552
553 def testCloneDocumentShallow(self):
554 doc = parseString("<?xml version='1.0'?>\n"
555 "<!-- comment -->"
556 "<!DOCTYPE doc [\n"
557 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
558 "]>\n"
559 "<doc attr='value'/>")
560 doc2 = doc.cloneNode(0)
561 self.confirm(doc2 is None,
562 "testCloneDocumentShallow:"
563 " shallow cloning of documents makes no sense!")
564
565 def testCloneDocumentDeep(self):
566 doc = parseString("<?xml version='1.0'?>\n"
567 "<!-- comment -->"
568 "<!DOCTYPE doc [\n"
569 "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
570 "]>\n"
571 "<doc attr='value'/>")
572 doc2 = doc.cloneNode(1)
573 self.confirm(not (doc.isSameNode(doc2) or doc2.isSameNode(doc)),
574 "testCloneDocumentDeep: document objects not distinct")
575 self.confirm(len(doc.childNodes) == len(doc2.childNodes),
576 "testCloneDocumentDeep: wrong number of Document children")
577 self.confirm(doc2.documentElement.nodeType == Node.ELEMENT_NODE,
578 "testCloneDocumentDeep: documentElement not an ELEMENT_NODE")
579 self.confirm(doc2.documentElement.ownerDocument.isSameNode(doc2),
580 "testCloneDocumentDeep: documentElement owner is not new document")
581 self.confirm(not doc.documentElement.isSameNode(doc2.documentElement),
582 "testCloneDocumentDeep: documentElement should not be shared")
583 if doc.doctype is not None:
584 # check the doctype iff the original DOM maintained it
585 self.confirm(doc2.doctype.nodeType == Node.DOCUMENT_TYPE_NODE,
586 "testCloneDocumentDeep: doctype not a DOCUMENT_TYPE_NODE")
587 self.confirm(doc2.doctype.ownerDocument.isSameNode(doc2))
588 self.confirm(not doc.doctype.isSameNode(doc2.doctype))
589
590 def testCloneDocumentTypeDeepOk(self):
591 doctype = create_nonempty_doctype()
592 clone = doctype.cloneNode(1)
593 self.confirm(clone is not None
594 and clone.nodeName == doctype.nodeName
595 and clone.name == doctype.name
596 and clone.publicId == doctype.publicId
597 and clone.systemId == doctype.systemId
598 and len(clone.entities) == len(doctype.entities)
599 and clone.entities.item(len(clone.entities)) is None
600 and len(clone.notations) == len(doctype.notations)
601 and clone.notations.item(len(clone.notations)) is None
602 and len(clone.childNodes) == 0)
603 for i in range(len(doctype.entities)):
604 se = doctype.entities.item(i)
605 ce = clone.entities.item(i)
606 self.confirm((not se.isSameNode(ce))
607 and (not ce.isSameNode(se))
608 and ce.nodeName == se.nodeName
609 and ce.notationName == se.notationName
610 and ce.publicId == se.publicId
611 and ce.systemId == se.systemId
612 and ce.encoding == se.encoding
613 and ce.actualEncoding == se.actualEncoding
614 and ce.version == se.version)
615 for i in range(len(doctype.notations)):
616 sn = doctype.notations.item(i)
617 cn = clone.notations.item(i)
618 self.confirm((not sn.isSameNode(cn))
619 and (not cn.isSameNode(sn))
620 and cn.nodeName == sn.nodeName
621 and cn.publicId == sn.publicId
622 and cn.systemId == sn.systemId)
623
624 def testCloneDocumentTypeDeepNotOk(self):
625 doc = create_doc_with_doctype()
626 clone = doc.doctype.cloneNode(1)
627 self.confirm(clone is None, "testCloneDocumentTypeDeepNotOk")
628
629 def testCloneDocumentTypeShallowOk(self):
630 doctype = create_nonempty_doctype()
631 clone = doctype.cloneNode(0)
632 self.confirm(clone is not None
633 and clone.nodeName == doctype.nodeName
634 and clone.name == doctype.name
635 and clone.publicId == doctype.publicId
636 and clone.systemId == doctype.systemId
637 and len(clone.entities) == 0
638 and clone.entities.item(0) is None
639 and len(clone.notations) == 0
640 and clone.notations.item(0) is None
641 and len(clone.childNodes) == 0)
642
643 def testCloneDocumentTypeShallowNotOk(self):
644 doc = create_doc_with_doctype()
645 clone = doc.doctype.cloneNode(0)
646 self.confirm(clone is None, "testCloneDocumentTypeShallowNotOk")
647
648 def check_import_document(self, deep, testName):
649 doc1 = parseString("<doc/>")
650 doc2 = parseString("<doc/>")
651 self.assertRaises(xml.dom.NotSupportedErr, doc1.importNode, doc2, deep)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000652
Collin Winterd28fcbc2007-03-28 23:34:06 +0000653 def testImportDocumentShallow(self):
654 self.check_import_document(0, "testImportDocumentShallow")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000655
Collin Winterd28fcbc2007-03-28 23:34:06 +0000656 def testImportDocumentDeep(self):
657 self.check_import_document(1, "testImportDocumentDeep")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000658
Collin Winterd28fcbc2007-03-28 23:34:06 +0000659 def testImportDocumentTypeShallow(self):
660 src = create_doc_with_doctype()
661 target = create_doc_without_doctype()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000662 self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000663 src.doctype, 0)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000664
Collin Winterd28fcbc2007-03-28 23:34:06 +0000665 def testImportDocumentTypeDeep(self):
666 src = create_doc_with_doctype()
667 target = create_doc_without_doctype()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000668 self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000669 src.doctype, 1)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000670
Collin Winterd28fcbc2007-03-28 23:34:06 +0000671 # Testing attribute clones uses a helper, and should always be deep,
672 # even if the argument to cloneNode is false.
673 def check_clone_attribute(self, deep, testName):
674 doc = parseString("<doc attr='value'/>")
675 attr = doc.documentElement.getAttributeNode("attr")
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000676 self.assertNotEqual(attr, None)
Collin Winterd28fcbc2007-03-28 23:34:06 +0000677 clone = attr.cloneNode(deep)
678 self.confirm(not clone.isSameNode(attr))
679 self.confirm(not attr.isSameNode(clone))
680 self.confirm(clone.ownerElement is None,
681 testName + ": ownerElement should be None")
682 self.confirm(clone.ownerDocument.isSameNode(attr.ownerDocument),
683 testName + ": ownerDocument does not match")
684 self.confirm(clone.specified,
685 testName + ": cloned attribute must have specified == True")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000686
Collin Winterd28fcbc2007-03-28 23:34:06 +0000687 def testCloneAttributeShallow(self):
688 self.check_clone_attribute(0, "testCloneAttributeShallow")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000689
Collin Winterd28fcbc2007-03-28 23:34:06 +0000690 def testCloneAttributeDeep(self):
691 self.check_clone_attribute(1, "testCloneAttributeDeep")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000692
Collin Winterd28fcbc2007-03-28 23:34:06 +0000693 def check_clone_pi(self, deep, testName):
694 doc = parseString("<?target data?><doc/>")
695 pi = doc.firstChild
Ezio Melotti2623a372010-11-21 13:34:58 +0000696 self.assertEqual(pi.nodeType, Node.PROCESSING_INSTRUCTION_NODE)
Collin Winterd28fcbc2007-03-28 23:34:06 +0000697 clone = pi.cloneNode(deep)
698 self.confirm(clone.target == pi.target
699 and clone.data == pi.data)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000700
Collin Winterd28fcbc2007-03-28 23:34:06 +0000701 def testClonePIShallow(self):
702 self.check_clone_pi(0, "testClonePIShallow")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000703
Collin Winterd28fcbc2007-03-28 23:34:06 +0000704 def testClonePIDeep(self):
705 self.check_clone_pi(1, "testClonePIDeep")
706
707 def testNormalize(self):
708 doc = parseString("<doc/>")
709 root = doc.documentElement
710 root.appendChild(doc.createTextNode("first"))
711 root.appendChild(doc.createTextNode("second"))
712 self.confirm(len(root.childNodes) == 2
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000713 and root.childNodes.length == 2,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000714 "testNormalize -- preparation")
715 doc.normalize()
716 self.confirm(len(root.childNodes) == 1
717 and root.childNodes.length == 1
718 and root.firstChild is root.lastChild
719 and root.firstChild.data == "firstsecond"
720 , "testNormalize -- result")
721 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000722
Collin Winterd28fcbc2007-03-28 23:34:06 +0000723 doc = parseString("<doc/>")
724 root = doc.documentElement
725 root.appendChild(doc.createTextNode(""))
726 doc.normalize()
727 self.confirm(len(root.childNodes) == 0
728 and root.childNodes.length == 0,
729 "testNormalize -- single empty node removed")
730 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000731
R. David Murray0374a822009-04-09 21:54:50 +0000732 def testNormalizeCombineAndNextSibling(self):
733 doc = parseString("<doc/>")
734 root = doc.documentElement
735 root.appendChild(doc.createTextNode("first"))
736 root.appendChild(doc.createTextNode("second"))
737 root.appendChild(doc.createElement("i"))
738 self.confirm(len(root.childNodes) == 3
739 and root.childNodes.length == 3,
740 "testNormalizeCombineAndNextSibling -- preparation")
741 doc.normalize()
742 self.confirm(len(root.childNodes) == 2
743 and root.childNodes.length == 2
744 and root.firstChild.data == "firstsecond"
745 and root.firstChild is not root.lastChild
746 and root.firstChild.nextSibling is root.lastChild
747 and root.firstChild.previousSibling is None
748 and root.lastChild.previousSibling is root.firstChild
749 and root.lastChild.nextSibling is None
750 , "testNormalizeCombinedAndNextSibling -- result")
751 doc.unlink()
752
753 def testNormalizeDeleteWithPrevSibling(self):
754 doc = parseString("<doc/>")
755 root = doc.documentElement
756 root.appendChild(doc.createTextNode("first"))
757 root.appendChild(doc.createTextNode(""))
758 self.confirm(len(root.childNodes) == 2
759 and root.childNodes.length == 2,
760 "testNormalizeDeleteWithPrevSibling -- preparation")
761 doc.normalize()
762 self.confirm(len(root.childNodes) == 1
763 and root.childNodes.length == 1
764 and root.firstChild.data == "first"
765 and root.firstChild is root.lastChild
766 and root.firstChild.nextSibling is None
767 and root.firstChild.previousSibling is None
768 , "testNormalizeDeleteWithPrevSibling -- result")
769 doc.unlink()
770
771 def testNormalizeDeleteWithNextSibling(self):
772 doc = parseString("<doc/>")
773 root = doc.documentElement
774 root.appendChild(doc.createTextNode(""))
775 root.appendChild(doc.createTextNode("second"))
776 self.confirm(len(root.childNodes) == 2
777 and root.childNodes.length == 2,
778 "testNormalizeDeleteWithNextSibling -- preparation")
779 doc.normalize()
780 self.confirm(len(root.childNodes) == 1
781 and root.childNodes.length == 1
782 and root.firstChild.data == "second"
783 and root.firstChild is root.lastChild
784 and root.firstChild.nextSibling is None
785 and root.firstChild.previousSibling is None
786 , "testNormalizeDeleteWithNextSibling -- result")
787 doc.unlink()
788
789 def testNormalizeDeleteWithTwoNonTextSiblings(self):
790 doc = parseString("<doc/>")
791 root = doc.documentElement
792 root.appendChild(doc.createElement("i"))
793 root.appendChild(doc.createTextNode(""))
794 root.appendChild(doc.createElement("i"))
795 self.confirm(len(root.childNodes) == 3
796 and root.childNodes.length == 3,
797 "testNormalizeDeleteWithTwoSiblings -- preparation")
798 doc.normalize()
799 self.confirm(len(root.childNodes) == 2
800 and root.childNodes.length == 2
801 and root.firstChild is not root.lastChild
802 and root.firstChild.nextSibling is root.lastChild
803 and root.firstChild.previousSibling is None
804 and root.lastChild.previousSibling is root.firstChild
805 and root.lastChild.nextSibling is None
806 , "testNormalizeDeleteWithTwoSiblings -- result")
807 doc.unlink()
808
809 def testNormalizeDeleteAndCombine(self):
810 doc = parseString("<doc/>")
811 root = doc.documentElement
812 root.appendChild(doc.createTextNode(""))
813 root.appendChild(doc.createTextNode("second"))
814 root.appendChild(doc.createTextNode(""))
815 root.appendChild(doc.createTextNode("fourth"))
816 root.appendChild(doc.createTextNode(""))
817 self.confirm(len(root.childNodes) == 5
818 and root.childNodes.length == 5,
819 "testNormalizeDeleteAndCombine -- preparation")
820 doc.normalize()
821 self.confirm(len(root.childNodes) == 1
822 and root.childNodes.length == 1
823 and root.firstChild is root.lastChild
824 and root.firstChild.data == "secondfourth"
825 and root.firstChild.previousSibling is None
826 and root.firstChild.nextSibling is None
827 , "testNormalizeDeleteAndCombine -- result")
828 doc.unlink()
829
830 def testNormalizeRecursion(self):
831 doc = parseString("<doc>"
832 "<o>"
833 "<i/>"
834 "t"
835 #
836 #x
837 "</o>"
838 "<o>"
839 "<o>"
840 "t2"
841 #x2
842 "</o>"
843 "t3"
844 #x3
845 "</o>"
846 #
847 "</doc>")
848 root = doc.documentElement
849 root.childNodes[0].appendChild(doc.createTextNode(""))
850 root.childNodes[0].appendChild(doc.createTextNode("x"))
851 root.childNodes[1].childNodes[0].appendChild(doc.createTextNode("x2"))
852 root.childNodes[1].appendChild(doc.createTextNode("x3"))
853 root.appendChild(doc.createTextNode(""))
854 self.confirm(len(root.childNodes) == 3
855 and root.childNodes.length == 3
856 and len(root.childNodes[0].childNodes) == 4
857 and root.childNodes[0].childNodes.length == 4
858 and len(root.childNodes[1].childNodes) == 3
859 and root.childNodes[1].childNodes.length == 3
860 and len(root.childNodes[1].childNodes[0].childNodes) == 2
861 and root.childNodes[1].childNodes[0].childNodes.length == 2
862 , "testNormalize2 -- preparation")
863 doc.normalize()
864 self.confirm(len(root.childNodes) == 2
865 and root.childNodes.length == 2
866 and len(root.childNodes[0].childNodes) == 2
867 and root.childNodes[0].childNodes.length == 2
868 and len(root.childNodes[1].childNodes) == 2
869 and root.childNodes[1].childNodes.length == 2
870 and len(root.childNodes[1].childNodes[0].childNodes) == 1
871 and root.childNodes[1].childNodes[0].childNodes.length == 1
872 , "testNormalize2 -- childNodes lengths")
873 self.confirm(root.childNodes[0].childNodes[1].data == "tx"
874 and root.childNodes[1].childNodes[0].childNodes[0].data == "t2x2"
875 and root.childNodes[1].childNodes[1].data == "t3x3"
876 , "testNormalize2 -- joined text fields")
877 self.confirm(root.childNodes[0].childNodes[1].nextSibling is None
878 and root.childNodes[0].childNodes[1].previousSibling
879 is root.childNodes[0].childNodes[0]
880 and root.childNodes[0].childNodes[0].previousSibling is None
881 and root.childNodes[0].childNodes[0].nextSibling
882 is root.childNodes[0].childNodes[1]
883 and root.childNodes[1].childNodes[1].nextSibling is None
884 and root.childNodes[1].childNodes[1].previousSibling
885 is root.childNodes[1].childNodes[0]
886 and root.childNodes[1].childNodes[0].previousSibling is None
887 and root.childNodes[1].childNodes[0].nextSibling
888 is root.childNodes[1].childNodes[1]
889 , "testNormalize2 -- sibling pointers")
890 doc.unlink()
891
892
Andrew M. Kuchling53f94d02010-07-25 23:49:57 +0000893 def testBug0777884(self):
894 doc = parseString("<o>text</o>")
895 text = doc.documentElement.childNodes[0]
Ezio Melotti2623a372010-11-21 13:34:58 +0000896 self.assertEqual(text.nodeType, Node.TEXT_NODE)
Andrew M. Kuchling53f94d02010-07-25 23:49:57 +0000897 # Should run quietly, doing nothing.
898 text.normalize()
899 doc.unlink()
900
Andrew M. Kuchling19aff0c2008-02-23 17:10:46 +0000901 def testBug1433694(self):
902 doc = parseString("<o><i/>t</o>")
903 node = doc.documentElement
904 node.childNodes[1].nodeValue = ""
905 node.normalize()
Florent Xiclunabc27c6a2010-03-19 18:34:55 +0000906 self.confirm(node.childNodes[-1].nextSibling is None,
Andrew M. Kuchling19aff0c2008-02-23 17:10:46 +0000907 "Final child's .nextSibling should be None")
908
Collin Winterd28fcbc2007-03-28 23:34:06 +0000909 def testSiblings(self):
910 doc = parseString("<doc><?pi?>text?<elm/></doc>")
911 root = doc.documentElement
912 (pi, text, elm) = root.childNodes
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000913
Collin Winterd28fcbc2007-03-28 23:34:06 +0000914 self.confirm(pi.nextSibling is text and
915 pi.previousSibling is None and
916 text.nextSibling is elm and
917 text.previousSibling is pi and
918 elm.nextSibling is None and
919 elm.previousSibling is text, "testSiblings")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000920
Collin Winterd28fcbc2007-03-28 23:34:06 +0000921 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000922
Collin Winterd28fcbc2007-03-28 23:34:06 +0000923 def testParents(self):
924 doc = parseString(
925 "<doc><elm1><elm2/><elm2><elm3/></elm2></elm1></doc>")
926 root = doc.documentElement
927 elm1 = root.childNodes[0]
928 (elm2a, elm2b) = elm1.childNodes
929 elm3 = elm2b.childNodes[0]
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000930
Collin Winterd28fcbc2007-03-28 23:34:06 +0000931 self.confirm(root.parentNode is doc and
932 elm1.parentNode is root and
933 elm2a.parentNode is elm1 and
934 elm2b.parentNode is elm1 and
935 elm3.parentNode is elm2b, "testParents")
936 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000937
Collin Winterd28fcbc2007-03-28 23:34:06 +0000938 def testNodeListItem(self):
939 doc = parseString("<doc><e/><e/></doc>")
940 children = doc.childNodes
941 docelem = children[0]
942 self.confirm(children[0] is children.item(0)
943 and children.item(1) is None
944 and docelem.childNodes.item(0) is docelem.childNodes[0]
945 and docelem.childNodes.item(1) is docelem.childNodes[1]
946 and docelem.childNodes.item(0).childNodes.item(0) is None,
947 "test NodeList.item()")
948 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000949
Collin Winterd28fcbc2007-03-28 23:34:06 +0000950 def testSAX2DOM(self):
951 from xml.dom import pulldom
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000952
Collin Winterd28fcbc2007-03-28 23:34:06 +0000953 sax2dom = pulldom.SAX2DOM()
954 sax2dom.startDocument()
955 sax2dom.startElement("doc", {})
956 sax2dom.characters("text")
957 sax2dom.startElement("subelm", {})
958 sax2dom.characters("text")
959 sax2dom.endElement("subelm")
960 sax2dom.characters("text")
961 sax2dom.endElement("doc")
962 sax2dom.endDocument()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000963
Collin Winterd28fcbc2007-03-28 23:34:06 +0000964 doc = sax2dom.document
965 root = doc.documentElement
966 (text1, elm1, text2) = root.childNodes
967 text3 = elm1.childNodes[0]
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000968
Collin Winterd28fcbc2007-03-28 23:34:06 +0000969 self.confirm(text1.previousSibling is None and
970 text1.nextSibling is elm1 and
971 elm1.previousSibling is text1 and
972 elm1.nextSibling is text2 and
973 text2.previousSibling is elm1 and
974 text2.nextSibling is None and
975 text3.previousSibling is None and
976 text3.nextSibling is None, "testSAX2DOM - siblings")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000977
Collin Winterd28fcbc2007-03-28 23:34:06 +0000978 self.confirm(root.parentNode is doc and
979 text1.parentNode is root and
980 elm1.parentNode is root and
981 text2.parentNode is root and
982 text3.parentNode is elm1, "testSAX2DOM - parents")
983 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000984
Collin Winterd28fcbc2007-03-28 23:34:06 +0000985 def testEncodings(self):
986 doc = parseString('<foo>&#x20ac;</foo>')
987 self.confirm(doc.toxml() == u'<?xml version="1.0" ?><foo>\u20ac</foo>'
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000988 and doc.toxml('utf-8') ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000989 '<?xml version="1.0" encoding="utf-8"?><foo>\xe2\x82\xac</foo>'
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000990 and doc.toxml('iso-8859-15') ==
Collin Winterd28fcbc2007-03-28 23:34:06 +0000991 '<?xml version="1.0" encoding="iso-8859-15"?><foo>\xa4</foo>',
992 "testEncodings - encoding EURO SIGN")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000993
Andrew Svetlov4bb142b2012-12-18 21:27:37 +0200994 # Verify that character decoding errors raise exceptions instead
Collin Winterd28fcbc2007-03-28 23:34:06 +0000995 # of crashing
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000996 self.assertRaises(UnicodeDecodeError, parseString,
Collin Winterd28fcbc2007-03-28 23:34:06 +0000997 '<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000998
Collin Winterd28fcbc2007-03-28 23:34:06 +0000999 doc.unlink()
1000
1001 class UserDataHandler:
1002 called = 0
1003 def handle(self, operation, key, data, src, dst):
1004 dst.setUserData(key, data + 1, self)
1005 src.setUserData(key, None, None)
1006 self.called = 1
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001007
Collin Winterd28fcbc2007-03-28 23:34:06 +00001008 def testUserData(self):
1009 dom = Document()
1010 n = dom.createElement('e')
1011 self.confirm(n.getUserData("foo") is None)
1012 n.setUserData("foo", None, None)
1013 self.confirm(n.getUserData("foo") is None)
1014 n.setUserData("foo", 12, 12)
1015 n.setUserData("bar", 13, 13)
1016 self.confirm(n.getUserData("foo") == 12)
1017 self.confirm(n.getUserData("bar") == 13)
1018 n.setUserData("foo", None, None)
1019 self.confirm(n.getUserData("foo") is None)
1020 self.confirm(n.getUserData("bar") == 13)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001021
Collin Winterd28fcbc2007-03-28 23:34:06 +00001022 handler = self.UserDataHandler()
1023 n.setUserData("bar", 12, handler)
1024 c = n.cloneNode(1)
1025 self.confirm(handler.called
1026 and n.getUserData("bar") is None
1027 and c.getUserData("bar") == 13)
1028 n.unlink()
1029 c.unlink()
1030 dom.unlink()
1031
1032 def checkRenameNodeSharedConstraints(self, doc, node):
1033 # Make sure illegal NS usage is detected:
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001034 self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, node,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001035 "http://xml.python.org/ns", "xmlns:foo")
1036 doc2 = parseString("<doc/>")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001037 self.assertRaises(xml.dom.WrongDocumentErr, doc2.renameNode, node,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001038 xml.dom.EMPTY_NAMESPACE, "foo")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001039
Collin Winterd28fcbc2007-03-28 23:34:06 +00001040 def testRenameAttribute(self):
1041 doc = parseString("<doc a='v'/>")
1042 elem = doc.documentElement
1043 attrmap = elem.attributes
1044 attr = elem.attributes['a']
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001045
Collin Winterd28fcbc2007-03-28 23:34:06 +00001046 # Simple renaming
1047 attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "b")
1048 self.confirm(attr.name == "b"
1049 and attr.nodeName == "b"
1050 and attr.localName is None
1051 and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
1052 and attr.prefix is None
1053 and attr.value == "v"
1054 and elem.getAttributeNode("a") is None
1055 and elem.getAttributeNode("b").isSameNode(attr)
1056 and attrmap["b"].isSameNode(attr)
1057 and attr.ownerDocument.isSameNode(doc)
1058 and attr.ownerElement.isSameNode(elem))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001059
Collin Winterd28fcbc2007-03-28 23:34:06 +00001060 # Rename to have a namespace, no prefix
1061 attr = doc.renameNode(attr, "http://xml.python.org/ns", "c")
1062 self.confirm(attr.name == "c"
1063 and attr.nodeName == "c"
1064 and attr.localName == "c"
1065 and attr.namespaceURI == "http://xml.python.org/ns"
1066 and attr.prefix is None
1067 and attr.value == "v"
1068 and elem.getAttributeNode("a") is None
1069 and elem.getAttributeNode("b") is None
1070 and elem.getAttributeNode("c").isSameNode(attr)
1071 and elem.getAttributeNodeNS(
1072 "http://xml.python.org/ns", "c").isSameNode(attr)
1073 and attrmap["c"].isSameNode(attr)
1074 and attrmap[("http://xml.python.org/ns", "c")].isSameNode(attr))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001075
Collin Winterd28fcbc2007-03-28 23:34:06 +00001076 # Rename to have a namespace, with prefix
1077 attr = doc.renameNode(attr, "http://xml.python.org/ns2", "p:d")
1078 self.confirm(attr.name == "p:d"
1079 and attr.nodeName == "p:d"
1080 and attr.localName == "d"
1081 and attr.namespaceURI == "http://xml.python.org/ns2"
1082 and attr.prefix == "p"
1083 and attr.value == "v"
1084 and elem.getAttributeNode("a") is None
1085 and elem.getAttributeNode("b") is None
1086 and elem.getAttributeNode("c") is None
1087 and elem.getAttributeNodeNS(
1088 "http://xml.python.org/ns", "c") is None
1089 and elem.getAttributeNode("p:d").isSameNode(attr)
1090 and elem.getAttributeNodeNS(
1091 "http://xml.python.org/ns2", "d").isSameNode(attr)
1092 and attrmap["p:d"].isSameNode(attr)
1093 and attrmap[("http://xml.python.org/ns2", "d")].isSameNode(attr))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001094
Collin Winterd28fcbc2007-03-28 23:34:06 +00001095 # Rename back to a simple non-NS node
1096 attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "e")
1097 self.confirm(attr.name == "e"
1098 and attr.nodeName == "e"
1099 and attr.localName is None
1100 and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
1101 and attr.prefix is None
1102 and attr.value == "v"
1103 and elem.getAttributeNode("a") is None
1104 and elem.getAttributeNode("b") is None
1105 and elem.getAttributeNode("c") is None
1106 and elem.getAttributeNode("p:d") is None
1107 and elem.getAttributeNodeNS(
1108 "http://xml.python.org/ns", "c") is None
1109 and elem.getAttributeNode("e").isSameNode(attr)
1110 and attrmap["e"].isSameNode(attr))
1111
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001112 self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, attr,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001113 "http://xml.python.org/ns", "xmlns")
1114 self.checkRenameNodeSharedConstraints(doc, attr)
1115 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001116
Collin Winterd28fcbc2007-03-28 23:34:06 +00001117 def testRenameElement(self):
1118 doc = parseString("<doc/>")
1119 elem = doc.documentElement
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001120
Collin Winterd28fcbc2007-03-28 23:34:06 +00001121 # Simple renaming
1122 elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "a")
1123 self.confirm(elem.tagName == "a"
1124 and elem.nodeName == "a"
1125 and elem.localName is None
1126 and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
1127 and elem.prefix is None
1128 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001129
Collin Winterd28fcbc2007-03-28 23:34:06 +00001130 # Rename to have a namespace, no prefix
1131 elem = doc.renameNode(elem, "http://xml.python.org/ns", "b")
1132 self.confirm(elem.tagName == "b"
1133 and elem.nodeName == "b"
1134 and elem.localName == "b"
1135 and elem.namespaceURI == "http://xml.python.org/ns"
1136 and elem.prefix is None
1137 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001138
Collin Winterd28fcbc2007-03-28 23:34:06 +00001139 # Rename to have a namespace, with prefix
1140 elem = doc.renameNode(elem, "http://xml.python.org/ns2", "p:c")
1141 self.confirm(elem.tagName == "p:c"
1142 and elem.nodeName == "p:c"
1143 and elem.localName == "c"
1144 and elem.namespaceURI == "http://xml.python.org/ns2"
1145 and elem.prefix == "p"
1146 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001147
Collin Winterd28fcbc2007-03-28 23:34:06 +00001148 # Rename back to a simple non-NS node
1149 elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "d")
1150 self.confirm(elem.tagName == "d"
1151 and elem.nodeName == "d"
1152 and elem.localName is None
1153 and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
1154 and elem.prefix is None
1155 and elem.ownerDocument.isSameNode(doc))
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001156
Collin Winterd28fcbc2007-03-28 23:34:06 +00001157 self.checkRenameNodeSharedConstraints(doc, elem)
1158 doc.unlink()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001159
Collin Winterd28fcbc2007-03-28 23:34:06 +00001160 def testRenameOther(self):
1161 # We have to create a comment node explicitly since not all DOM
1162 # builders used with minidom add comments to the DOM.
1163 doc = xml.dom.minidom.getDOMImplementation().createDocument(
1164 xml.dom.EMPTY_NAMESPACE, "e", None)
1165 node = doc.createComment("comment")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001166 self.assertRaises(xml.dom.NotSupportedErr, doc.renameNode, node,
Collin Winterd28fcbc2007-03-28 23:34:06 +00001167 xml.dom.EMPTY_NAMESPACE, "foo")
1168 doc.unlink()
1169
1170 def testWholeText(self):
1171 doc = parseString("<doc>a</doc>")
1172 elem = doc.documentElement
1173 text = elem.childNodes[0]
Ezio Melotti2623a372010-11-21 13:34:58 +00001174 self.assertEqual(text.nodeType, Node.TEXT_NODE)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001175
Collin Winterd28fcbc2007-03-28 23:34:06 +00001176 self.checkWholeText(text, "a")
1177 elem.appendChild(doc.createTextNode("b"))
1178 self.checkWholeText(text, "ab")
1179 elem.insertBefore(doc.createCDATASection("c"), text)
1180 self.checkWholeText(text, "cab")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001181
Collin Winterd28fcbc2007-03-28 23:34:06 +00001182 # make sure we don't cross other nodes
1183 splitter = doc.createComment("comment")
1184 elem.appendChild(splitter)
1185 text2 = doc.createTextNode("d")
1186 elem.appendChild(text2)
1187 self.checkWholeText(text, "cab")
1188 self.checkWholeText(text2, "d")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001189
Collin Winterd28fcbc2007-03-28 23:34:06 +00001190 x = doc.createElement("x")
1191 elem.replaceChild(x, splitter)
1192 splitter = x
1193 self.checkWholeText(text, "cab")
1194 self.checkWholeText(text2, "d")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001195
Collin Winterd28fcbc2007-03-28 23:34:06 +00001196 x = doc.createProcessingInstruction("y", "z")
1197 elem.replaceChild(x, splitter)
1198 splitter = x
1199 self.checkWholeText(text, "cab")
1200 self.checkWholeText(text2, "d")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001201
Collin Winterd28fcbc2007-03-28 23:34:06 +00001202 elem.removeChild(splitter)
1203 self.checkWholeText(text, "cabd")
1204 self.checkWholeText(text2, "cabd")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001205
Collin Winterd28fcbc2007-03-28 23:34:06 +00001206 def testPatch1094164(self):
1207 doc = parseString("<doc><e/></doc>")
1208 elem = doc.documentElement
1209 e = elem.firstChild
1210 self.confirm(e.parentNode is elem, "Before replaceChild()")
1211 # Check that replacing a child with itself leaves the tree unchanged
1212 elem.replaceChild(e, e)
1213 self.confirm(e.parentNode is elem, "After replaceChild()")
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001214
Collin Winterd28fcbc2007-03-28 23:34:06 +00001215 def testReplaceWholeText(self):
1216 def setup():
1217 doc = parseString("<doc>a<e/>d</doc>")
1218 elem = doc.documentElement
1219 text1 = elem.firstChild
1220 text2 = elem.lastChild
1221 splitter = text1.nextSibling
1222 elem.insertBefore(doc.createTextNode("b"), splitter)
1223 elem.insertBefore(doc.createCDATASection("c"), text1)
1224 return doc, elem, text1, splitter, text2
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001225
Collin Winterd28fcbc2007-03-28 23:34:06 +00001226 doc, elem, text1, splitter, text2 = setup()
1227 text = text1.replaceWholeText("new content")
1228 self.checkWholeText(text, "new content")
1229 self.checkWholeText(text2, "d")
1230 self.confirm(len(elem.childNodes) == 3)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001231
Collin Winterd28fcbc2007-03-28 23:34:06 +00001232 doc, elem, text1, splitter, text2 = setup()
1233 text = text2.replaceWholeText("new content")
1234 self.checkWholeText(text, "new content")
1235 self.checkWholeText(text1, "cab")
1236 self.confirm(len(elem.childNodes) == 5)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001237
Collin Winterd28fcbc2007-03-28 23:34:06 +00001238 doc, elem, text1, splitter, text2 = setup()
1239 text = text1.replaceWholeText("")
1240 self.checkWholeText(text2, "d")
1241 self.confirm(text is None
1242 and len(elem.childNodes) == 2)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001243
Collin Winterd28fcbc2007-03-28 23:34:06 +00001244 def testSchemaType(self):
1245 doc = parseString(
1246 "<!DOCTYPE doc [\n"
1247 " <!ENTITY e1 SYSTEM 'http://xml.python.org/e1'>\n"
1248 " <!ENTITY e2 SYSTEM 'http://xml.python.org/e2'>\n"
1249 " <!ATTLIST doc id ID #IMPLIED \n"
1250 " ref IDREF #IMPLIED \n"
1251 " refs IDREFS #IMPLIED \n"
1252 " enum (a|b) #IMPLIED \n"
1253 " ent ENTITY #IMPLIED \n"
1254 " ents ENTITIES #IMPLIED \n"
1255 " nm NMTOKEN #IMPLIED \n"
1256 " nms NMTOKENS #IMPLIED \n"
1257 " text CDATA #IMPLIED \n"
1258 " >\n"
1259 "]><doc id='name' notid='name' text='splat!' enum='b'"
1260 " ref='name' refs='name name' ent='e1' ents='e1 e2'"
1261 " nm='123' nms='123 abc' />")
1262 elem = doc.documentElement
1263 # We don't want to rely on any specific loader at this point, so
1264 # just make sure we can get to all the names, and that the
1265 # DTD-based namespace is right. The names can vary by loader
1266 # since each supports a different level of DTD information.
1267 t = elem.schemaType
1268 self.confirm(t.name is None
1269 and t.namespace == xml.dom.EMPTY_NAMESPACE)
1270 names = "id notid text enum ref refs ent ents nm nms".split()
1271 for name in names:
1272 a = elem.getAttributeNode(name)
1273 t = a.schemaType
1274 self.confirm(hasattr(t, "name")
1275 and t.namespace == xml.dom.EMPTY_NAMESPACE)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001276
Collin Winterd28fcbc2007-03-28 23:34:06 +00001277 def testSetIdAttribute(self):
1278 doc = parseString("<doc a1='v' a2='w'/>")
1279 e = doc.documentElement
1280 a1 = e.getAttributeNode("a1")
1281 a2 = e.getAttributeNode("a2")
1282 self.confirm(doc.getElementById("v") is None
1283 and not a1.isId
1284 and not a2.isId)
1285 e.setIdAttribute("a1")
1286 self.confirm(e.isSameNode(doc.getElementById("v"))
1287 and a1.isId
1288 and not a2.isId)
1289 e.setIdAttribute("a2")
1290 self.confirm(e.isSameNode(doc.getElementById("v"))
1291 and e.isSameNode(doc.getElementById("w"))
1292 and a1.isId
1293 and a2.isId)
1294 # replace the a1 node; the new node should *not* be an ID
1295 a3 = doc.createAttribute("a1")
1296 a3.value = "v"
1297 e.setAttributeNode(a3)
1298 self.confirm(doc.getElementById("v") is None
1299 and e.isSameNode(doc.getElementById("w"))
1300 and not a1.isId
1301 and a2.isId
1302 and not a3.isId)
1303 # renaming an attribute should not affect its ID-ness:
1304 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1305 self.confirm(e.isSameNode(doc.getElementById("w"))
1306 and a2.isId)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001307
Collin Winterd28fcbc2007-03-28 23:34:06 +00001308 def testSetIdAttributeNS(self):
1309 NS1 = "http://xml.python.org/ns1"
1310 NS2 = "http://xml.python.org/ns2"
1311 doc = parseString("<doc"
1312 " xmlns:ns1='" + NS1 + "'"
1313 " xmlns:ns2='" + NS2 + "'"
1314 " ns1:a1='v' ns2:a2='w'/>")
1315 e = doc.documentElement
1316 a1 = e.getAttributeNodeNS(NS1, "a1")
1317 a2 = e.getAttributeNodeNS(NS2, "a2")
1318 self.confirm(doc.getElementById("v") is None
1319 and not a1.isId
1320 and not a2.isId)
1321 e.setIdAttributeNS(NS1, "a1")
1322 self.confirm(e.isSameNode(doc.getElementById("v"))
1323 and a1.isId
1324 and not a2.isId)
1325 e.setIdAttributeNS(NS2, "a2")
1326 self.confirm(e.isSameNode(doc.getElementById("v"))
1327 and e.isSameNode(doc.getElementById("w"))
1328 and a1.isId
1329 and a2.isId)
1330 # replace the a1 node; the new node should *not* be an ID
1331 a3 = doc.createAttributeNS(NS1, "a1")
1332 a3.value = "v"
1333 e.setAttributeNode(a3)
1334 self.confirm(e.isSameNode(doc.getElementById("w")))
1335 self.confirm(not a1.isId)
1336 self.confirm(a2.isId)
1337 self.confirm(not a3.isId)
1338 self.confirm(doc.getElementById("v") is None)
1339 # renaming an attribute should not affect its ID-ness:
1340 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1341 self.confirm(e.isSameNode(doc.getElementById("w"))
1342 and a2.isId)
1343
1344 def testSetIdAttributeNode(self):
1345 NS1 = "http://xml.python.org/ns1"
1346 NS2 = "http://xml.python.org/ns2"
1347 doc = parseString("<doc"
1348 " xmlns:ns1='" + NS1 + "'"
1349 " xmlns:ns2='" + NS2 + "'"
1350 " ns1:a1='v' ns2:a2='w'/>")
1351 e = doc.documentElement
1352 a1 = e.getAttributeNodeNS(NS1, "a1")
1353 a2 = e.getAttributeNodeNS(NS2, "a2")
1354 self.confirm(doc.getElementById("v") is None
1355 and not a1.isId
1356 and not a2.isId)
1357 e.setIdAttributeNode(a1)
1358 self.confirm(e.isSameNode(doc.getElementById("v"))
1359 and a1.isId
1360 and not a2.isId)
1361 e.setIdAttributeNode(a2)
1362 self.confirm(e.isSameNode(doc.getElementById("v"))
1363 and e.isSameNode(doc.getElementById("w"))
1364 and a1.isId
1365 and a2.isId)
1366 # replace the a1 node; the new node should *not* be an ID
1367 a3 = doc.createAttributeNS(NS1, "a1")
1368 a3.value = "v"
1369 e.setAttributeNode(a3)
1370 self.confirm(e.isSameNode(doc.getElementById("w")))
1371 self.confirm(not a1.isId)
1372 self.confirm(a2.isId)
1373 self.confirm(not a3.isId)
1374 self.confirm(doc.getElementById("v") is None)
1375 # renaming an attribute should not affect its ID-ness:
1376 doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
1377 self.confirm(e.isSameNode(doc.getElementById("w"))
1378 and a2.isId)
1379
1380 def testPickledDocument(self):
1381 doc = parseString("<?xml version='1.0' encoding='us-ascii'?>\n"
1382 "<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
1383 " 'http://xml.python.org/system' [\n"
1384 " <!ELEMENT e EMPTY>\n"
1385 " <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n"
1386 "]><doc attr='value'> text\n"
1387 "<?pi sample?> <!-- comment --> <e/> </doc>")
1388 s = pickle.dumps(doc)
1389 doc2 = pickle.loads(s)
1390 stack = [(doc, doc2)]
1391 while stack:
1392 n1, n2 = stack.pop()
1393 self.confirm(n1.nodeType == n2.nodeType
1394 and len(n1.childNodes) == len(n2.childNodes)
1395 and n1.nodeName == n2.nodeName
1396 and not n1.isSameNode(n2)
1397 and not n2.isSameNode(n1))
1398 if n1.nodeType == Node.DOCUMENT_TYPE_NODE:
1399 len(n1.entities)
1400 len(n2.entities)
1401 len(n1.notations)
1402 len(n2.notations)
1403 self.confirm(len(n1.entities) == len(n2.entities)
1404 and len(n1.notations) == len(n2.notations))
1405 for i in range(len(n1.notations)):
Georg Brandlcd4a21b2010-02-06 23:34:10 +00001406 # XXX this loop body doesn't seem to be executed?
Collin Winterd28fcbc2007-03-28 23:34:06 +00001407 no1 = n1.notations.item(i)
1408 no2 = n1.notations.item(i)
1409 self.confirm(no1.name == no2.name
1410 and no1.publicId == no2.publicId
1411 and no1.systemId == no2.systemId)
Georg Brandlcd4a21b2010-02-06 23:34:10 +00001412 stack.append((no1, no2))
Collin Winterd28fcbc2007-03-28 23:34:06 +00001413 for i in range(len(n1.entities)):
1414 e1 = n1.entities.item(i)
1415 e2 = n2.entities.item(i)
1416 self.confirm(e1.notationName == e2.notationName
1417 and e1.publicId == e2.publicId
1418 and e1.systemId == e2.systemId)
1419 stack.append((e1, e2))
1420 if n1.nodeType != Node.DOCUMENT_NODE:
1421 self.confirm(n1.ownerDocument.isSameNode(doc)
1422 and n2.ownerDocument.isSameNode(doc2))
1423 for i in range(len(n1.childNodes)):
1424 stack.append((n1.childNodes[i], n2.childNodes[i]))
1425
Martin v. Löwis27e4a172008-05-23 15:18:28 +00001426 def testSerializeCommentNodeWithDoubleHyphen(self):
1427 doc = create_doc_without_doctype()
1428 doc.appendChild(doc.createComment("foo--bar"))
1429 self.assertRaises(ValueError, doc.toxml)
1430
Georg Brandl5ded7912010-11-26 07:35:31 +00001431 def testEmptyXMLNSValue(self):
1432 doc = parseString("<element xmlns=''>\n"
1433 "<foo/>\n</element>")
1434 doc2 = parseString(doc.toxml())
1435 self.confirm(doc2.namespaceURI == xml.dom.EMPTY_NAMESPACE)
1436
1437
Collin Winterd28fcbc2007-03-28 23:34:06 +00001438def test_main():
1439 run_unittest(MinidomTest)
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00001440
Collin Winterd28fcbc2007-03-28 23:34:06 +00001441if __name__ == "__main__":
1442 test_main()