PageRenderTime 95ms CodeModel.GetById 2ms app.highlight 82ms RepoModel.GetById 1ms app.codeStats 1ms

/Lib/test/test_minidom.py

http://unladen-swallow.googlecode.com/
Python | 1326 lines | 1249 code | 57 blank | 20 comment | 113 complexity | c4d50ed2dd5ee8aed9b9b68aa77b9d43 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file