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