diff options
Diffstat (limited to 'Lib/test/test_minidom.py')
-rw-r--r-- | Lib/test/test_minidom.py | 756 |
1 files changed, 732 insertions, 24 deletions
diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py index 0791bbf..c39c616 100644 --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -23,8 +23,6 @@ def confirm(test, testname = "Test"): print "Failed " + testname raise Exception -Node._debug = 1 - def testParseFromFile(): from StringIO import StringIO dom = parse(StringIO(open(tstfile).read())) @@ -283,7 +281,8 @@ def testRemoveAttributeNode(): confirm(len(child.attributes) == 1) node = child.getAttributeNode("spam") child.removeAttributeNode(node) - confirm(len(child.attributes) == 0) + confirm(len(child.attributes) == 0 + and child.getAttributeNode("spam") is None) dom.unlink() @@ -293,13 +292,36 @@ def testChangeAttr(): el.setAttribute("spam", "jam") confirm(len(el.attributes) == 1) el.setAttribute("spam", "bam") - confirm(len(el.attributes) == 1) + # Set this attribute to be an ID and make sure that doesn't change + # when changing the value: + el.setIdAttribute("spam") + confirm(len(el.attributes) == 1 + and el.attributes["spam"].value == "bam" + and el.attributes["spam"].nodeValue == "bam" + and el.getAttribute("spam") == "bam" + and el.getAttributeNode("spam").isId) el.attributes["spam"] = "ham" - confirm(len(el.attributes) == 1) + confirm(len(el.attributes) == 1 + and el.attributes["spam"].value == "ham" + and el.attributes["spam"].nodeValue == "ham" + and el.getAttribute("spam") == "ham" + and el.attributes["spam"].isId) el.setAttribute("spam2", "bam") - confirm(len(el.attributes) == 2) - el.attributes[ "spam2"] = "bam2" - confirm(len(el.attributes) == 2) + confirm(len(el.attributes) == 2 + and el.attributes["spam"].value == "ham" + and el.attributes["spam"].nodeValue == "ham" + and el.getAttribute("spam") == "ham" + and el.attributes["spam2"].value == "bam" + and el.attributes["spam2"].nodeValue == "bam" + and el.getAttribute("spam2") == "bam") + el.attributes["spam2"] = "bam2" + confirm(len(el.attributes) == 2 + and el.attributes["spam"].value == "ham" + and el.attributes["spam"].nodeValue == "ham" + and el.getAttribute("spam") == "ham" + and el.attributes["spam2"].value == "bam2" + and el.attributes["spam2"].nodeValue == "bam2" + and el.getAttribute("spam2") == "bam2") dom.unlink() def testGetAttrList(): @@ -316,15 +338,39 @@ def testGetAttributeNS(): pass def testGetAttributeNode(): pass def testGetElementsByTagNameNS(): - d="""<foo xmlns:minidom="http://pyxml.sf.net/minidom"> + d="""<foo xmlns:minidom='http://pyxml.sf.net/minidom'> <minidom:myelem/> </foo>""" dom = parseString(d) - elem = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom","myelem") - confirm(len(elem) == 1) + elems = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom", "myelem") + confirm(len(elems) == 1 + and elems[0].namespaceURI == "http://pyxml.sf.net/minidom" + and elems[0].localName == "myelem" + and elems[0].prefix == "minidom" + and elems[0].tagName == "minidom:myelem" + and elems[0].nodeName == "minidom:myelem") dom.unlink() -def testGetEmptyNodeListFromElementsByTagNameNS(): pass +def get_empty_nodelist_from_elements_by_tagName_ns_helper(doc, nsuri, lname): + nodelist = doc.getElementsByTagNameNS(nsuri, lname) + confirm(len(nodelist) == 0) + +def testGetEmptyNodeListFromElementsByTagNameNS(): + doc = parseString('<doc/>') + get_empty_nodelist_from_elements_by_tagName_ns_helper( + doc, 'http://xml.python.org/namespaces/a', 'localname') + get_empty_nodelist_from_elements_by_tagName_ns_helper( + doc, '*', 'splat') + get_empty_nodelist_from_elements_by_tagName_ns_helper( + doc, 'http://xml.python.org/namespaces/a', '*') + + doc = parseString('<doc xmlns="http://xml.python.org/splat"><e/></doc>') + get_empty_nodelist_from_elements_by_tagName_ns_helper( + doc, "http://xml.python.org/splat", "not-there") + get_empty_nodelist_from_elements_by_tagName_ns_helper( + doc, "*", "not-there") + get_empty_nodelist_from_elements_by_tagName_ns_helper( + doc, "http://somewhere.else.net/not-there", "e") def testElementReprAndStr(): dom = Document() @@ -370,7 +416,20 @@ def testWriteXML(): dom.unlink() confirm(str == domstr) -def testProcessingInstruction(): pass +def testProcessingInstruction(): + dom = parseString('<e><?mypi \t\n data \t\n ?></e>') + pi = dom.documentElement.firstChild + confirm(pi.target == "mypi" + and pi.data == "data \t\n " + and pi.nodeName == "mypi" + and pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE + and pi.attributes is None + and not pi.hasChildNodes() + and len(pi.childNodes) == 0 + and pi.firstChild is None + and pi.lastChild is None + and pi.localName is None + and pi.namespaceURI == xml.dom.EMPTY_NAMESPACE) def testProcessingInstructionRepr(): pass @@ -413,6 +472,30 @@ def testAttrListKeys(): pass def testAttrListKeysNS(): pass +def testRemoveNamedItem(): + doc = parseString("<doc a=''/>") + e = doc.documentElement + attrs = e.attributes + a1 = e.getAttributeNode("a") + a2 = attrs.removeNamedItem("a") + confirm(a1.isSameNode(a2)) + try: + attrs.removeNamedItem("a") + except xml.dom.NotFoundErr: + pass + +def testRemoveNamedItemNS(): + doc = parseString("<doc xmlns:a='http://xml.python.org/' a:b=''/>") + e = doc.documentElement + attrs = e.attributes + a1 = e.getAttributeNodeNS("http://xml.python.org/", "b") + a2 = attrs.removeNamedItemNS("http://xml.python.org/", "b") + confirm(a1.isSameNode(a2)) + try: + attrs.removeNamedItemNS("http://xml.python.org/", "b") + except xml.dom.NotFoundErr: + pass + def testAttrListValues(): pass def testAttrListLength(): pass @@ -489,18 +572,205 @@ def _testCloneElementCopiesAttributes(e1, e2, test): confirm(a2.ownerElement is e2, "clone of attribute node correctly owned") +def testCloneDocumentShallow(): + doc = parseString("<?xml version='1.0'?>\n" + "<!-- comment -->" + "<!DOCTYPE doc [\n" + "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n" + "]>\n" + "<doc attr='value'/>") + doc2 = doc.cloneNode(0) + confirm(doc2 is None, + "testCloneDocumentShallow:" + " shallow cloning of documents makes no sense!") + +def testCloneDocumentDeep(): + doc = parseString("<?xml version='1.0'?>\n" + "<!-- comment -->" + "<!DOCTYPE doc [\n" + "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n" + "]>\n" + "<doc attr='value'/>") + doc2 = doc.cloneNode(1) + confirm(not (doc.isSameNode(doc2) or doc2.isSameNode(doc)), + "testCloneDocumentDeep: document objects not distinct") + confirm(len(doc.childNodes) == len(doc2.childNodes), + "testCloneDocumentDeep: wrong number of Document children") + confirm(doc2.documentElement.nodeType == Node.ELEMENT_NODE, + "testCloneDocumentDeep: documentElement not an ELEMENT_NODE") + confirm(doc2.documentElement.ownerDocument.isSameNode(doc2), + "testCloneDocumentDeep: documentElement owner is not new document") + confirm(not doc.documentElement.isSameNode(doc2.documentElement), + "testCloneDocumentDeep: documentElement should not be shared") + if doc.doctype is not None: + # check the doctype iff the original DOM maintained it + confirm(doc2.doctype.nodeType == Node.DOCUMENT_TYPE_NODE, + "testCloneDocumentDeep: doctype not a DOCUMENT_TYPE_NODE") + confirm(doc2.doctype.ownerDocument.isSameNode(doc2)) + confirm(not doc.doctype.isSameNode(doc2.doctype)) + +def testCloneDocumentTypeDeepOk(): + doctype = create_nonempty_doctype() + clone = doctype.cloneNode(1) + confirm(clone is not None + and clone.nodeName == doctype.nodeName + and clone.name == doctype.name + and clone.publicId == doctype.publicId + and clone.systemId == doctype.systemId + and len(clone.entities) == len(doctype.entities) + and clone.entities.item(len(clone.entities)) is None + and len(clone.notations) == len(doctype.notations) + and clone.notations.item(len(clone.notations)) is None + and len(clone.childNodes) == 0) + for i in range(len(doctype.entities)): + se = doctype.entities.item(i) + ce = clone.entities.item(i) + confirm((not se.isSameNode(ce)) + and (not ce.isSameNode(se)) + and ce.nodeName == se.nodeName + and ce.notationName == se.notationName + and ce.publicId == se.publicId + and ce.systemId == se.systemId + and ce.encoding == se.encoding + and ce.actualEncoding == se.actualEncoding + and ce.version == se.version) + for i in range(len(doctype.notations)): + sn = doctype.notations.item(i) + cn = clone.notations.item(i) + confirm((not sn.isSameNode(cn)) + and (not cn.isSameNode(sn)) + and cn.nodeName == sn.nodeName + and cn.publicId == sn.publicId + and cn.systemId == sn.systemId) + +def testCloneDocumentTypeDeepNotOk(): + doc = create_doc_with_doctype() + clone = doc.doctype.cloneNode(1) + confirm(clone is None, "testCloneDocumentTypeDeepNotOk") + +def testCloneDocumentTypeShallowOk(): + doctype = create_nonempty_doctype() + clone = doctype.cloneNode(0) + confirm(clone is not None + and clone.nodeName == doctype.nodeName + and clone.name == doctype.name + and clone.publicId == doctype.publicId + and clone.systemId == doctype.systemId + and len(clone.entities) == 0 + and clone.entities.item(0) is None + and len(clone.notations) == 0 + and clone.notations.item(0) is None + and len(clone.childNodes) == 0) + +def testCloneDocumentTypeShallowNotOk(): + doc = create_doc_with_doctype() + clone = doc.doctype.cloneNode(0) + confirm(clone is None, "testCloneDocumentTypeShallowNotOk") + +def check_import_document(deep, testName): + doc1 = parseString("<doc/>") + doc2 = parseString("<doc/>") + try: + doc1.importNode(doc2, deep) + except xml.dom.NotSupportedErr: + pass + else: + raise Exception(testName + + ": expected NotSupportedErr when importing a document") + +def testImportDocumentShallow(): + check_import_document(0, "testImportDocumentShallow") + +def testImportDocumentDeep(): + check_import_document(1, "testImportDocumentDeep") + +# The tests of DocumentType importing use these helpers to construct +# the documents to work with, since not all DOM builders actually +# create the DocumentType nodes. + +def create_doc_without_doctype(doctype=None): + return getDOMImplementation().createDocument(None, "doc", doctype) + +def create_nonempty_doctype(): + doctype = getDOMImplementation().createDocumentType("doc", None, None) + doctype.entities._seq = [] + doctype.notations._seq = [] + notation = xml.dom.minidom.Notation("my-notation", None, + "http://xml.python.org/notations/my") + doctype.notations._seq.append(notation) + entity = xml.dom.minidom.Entity("my-entity", None, + "http://xml.python.org/entities/my", + "my-notation") + entity.version = "1.0" + entity.encoding = "utf-8" + entity.actualEncoding = "us-ascii" + doctype.entities._seq.append(entity) + return doctype + +def create_doc_with_doctype(): + doctype = create_nonempty_doctype() + doc = create_doc_without_doctype(doctype) + doctype.entities.item(0).ownerDocument = doc + doctype.notations.item(0).ownerDocument = doc + return doc + +def testImportDocumentTypeShallow(): + src = create_doc_with_doctype() + target = create_doc_without_doctype() + try: + imported = target.importNode(src.doctype, 0) + except xml.dom.NotSupportedErr: + pass + else: + raise Exception( + "testImportDocumentTypeShallow: expected NotSupportedErr") -def testCloneDocumentShallow(): pass - -def testCloneDocumentDeep(): pass - -def testCloneAttributeShallow(): pass - -def testCloneAttributeDeep(): pass - -def testClonePIShallow(): pass - -def testClonePIDeep(): pass +def testImportDocumentTypeDeep(): + src = create_doc_with_doctype() + target = create_doc_without_doctype() + try: + imported = target.importNode(src.doctype, 1) + except xml.dom.NotSupportedErr: + pass + else: + raise Exception( + "testImportDocumentTypeDeep: expected NotSupportedErr") + +# Testing attribute clones uses a helper, and should always be deep, +# even if the argument to cloneNode is false. +def check_clone_attribute(deep, testName): + doc = parseString("<doc attr='value'/>") + attr = doc.documentElement.getAttributeNode("attr") + assert attr is not None + clone = attr.cloneNode(deep) + confirm(not clone.isSameNode(attr)) + confirm(not attr.isSameNode(clone)) + confirm(clone.ownerElement is None, + testName + ": ownerElement should be None") + confirm(clone.ownerDocument.isSameNode(attr.ownerDocument), + testName + ": ownerDocument does not match") + confirm(clone.specified, + testName + ": cloned attribute must have specified == True") + +def testCloneAttributeShallow(): + check_clone_attribute(0, "testCloneAttributeShallow") + +def testCloneAttributeDeep(): + check_clone_attribute(1, "testCloneAttributeDeep") + +def check_clone_pi(deep, testName): + doc = parseString("<?target data?><doc/>") + pi = doc.firstChild + assert pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE + clone = pi.cloneNode(deep) + confirm(clone.target == pi.target + and clone.data == pi.data) + +def testClonePIShallow(): + check_clone_pi(0, "testClonePIShallow") + +def testClonePIDeep(): + check_clone_pi(1, "testClonePIDeep") def testNormalize(): doc = parseString("<doc/>") @@ -611,6 +881,444 @@ def testEncodings(): "testEncodings - encoding EURO SIGN") doc.unlink() +class UserDataHandler: + called = 0 + def handle(self, operation, key, data, src, dst): + dst.setUserData(key, data + 1, self) + src.setUserData(key, None, None) + self.called = 1 + +def testUserData(): + dom = Document() + n = dom.createElement('e') + confirm(n.getUserData("foo") is None) + n.setUserData("foo", None, None) + confirm(n.getUserData("foo") is None) + n.setUserData("foo", 12, 12) + n.setUserData("bar", 13, 13) + confirm(n.getUserData("foo") == 12) + confirm(n.getUserData("bar") == 13) + n.setUserData("foo", None, None) + confirm(n.getUserData("foo") is None) + confirm(n.getUserData("bar") == 13) + + handler = UserDataHandler() + n.setUserData("bar", 12, handler) + c = n.cloneNode(1) + confirm(handler.called + and n.getUserData("bar") is None + and c.getUserData("bar") == 13) + n.unlink() + c.unlink() + dom.unlink() + +def testRenameAttribute(): + doc = parseString("<doc a='v'/>") + elem = doc.documentElement + attrmap = elem.attributes + attr = elem.attributes['a'] + + # Simple renaming + attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "b") + confirm(attr.name == "b" + and attr.nodeName == "b" + and attr.localName is None + and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE + and attr.prefix is None + and attr.value == "v" + and elem.getAttributeNode("a") is None + and elem.getAttributeNode("b").isSameNode(attr) + and attrmap["b"].isSameNode(attr) + and attr.ownerDocument.isSameNode(doc) + and attr.ownerElement.isSameNode(elem)) + + # Rename to have a namespace, no prefix + attr = doc.renameNode(attr, "http://xml.python.org/ns", "c") + confirm(attr.name == "c" + and attr.nodeName == "c" + and attr.localName == "c" + and attr.namespaceURI == "http://xml.python.org/ns" + and attr.prefix is None + and attr.value == "v" + and elem.getAttributeNode("a") is None + and elem.getAttributeNode("b") is None + and elem.getAttributeNode("c").isSameNode(attr) + and elem.getAttributeNodeNS( + "http://xml.python.org/ns", "c").isSameNode(attr) + and attrmap["c"].isSameNode(attr) + and attrmap[("http://xml.python.org/ns", "c")].isSameNode(attr)) + + # Rename to have a namespace, with prefix + attr = doc.renameNode(attr, "http://xml.python.org/ns2", "p:d") + confirm(attr.name == "p:d" + and attr.nodeName == "p:d" + and attr.localName == "d" + and attr.namespaceURI == "http://xml.python.org/ns2" + and attr.prefix == "p" + and attr.value == "v" + and elem.getAttributeNode("a") is None + and elem.getAttributeNode("b") is None + and elem.getAttributeNode("c") is None + and elem.getAttributeNodeNS( + "http://xml.python.org/ns", "c") is None + and elem.getAttributeNode("p:d").isSameNode(attr) + and elem.getAttributeNodeNS( + "http://xml.python.org/ns2", "d").isSameNode(attr) + and attrmap["p:d"].isSameNode(attr) + and attrmap[("http://xml.python.org/ns2", "d")].isSameNode(attr)) + + # Rename back to a simple non-NS node + attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "e") + confirm(attr.name == "e" + and attr.nodeName == "e" + and attr.localName is None + and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE + and attr.prefix is None + and attr.value == "v" + and elem.getAttributeNode("a") is None + and elem.getAttributeNode("b") is None + and elem.getAttributeNode("c") is None + and elem.getAttributeNode("p:d") is None + and elem.getAttributeNodeNS( + "http://xml.python.org/ns", "c") is None + and elem.getAttributeNode("e").isSameNode(attr) + and attrmap["e"].isSameNode(attr)) + + try: + doc.renameNode(attr, "http://xml.python.org/ns", "xmlns") + except xml.dom.NamespaceErr: + pass + else: + print "expected NamespaceErr" + + checkRenameNodeSharedConstraints(doc, attr) + doc.unlink() + +def testRenameElement(): + doc = parseString("<doc/>") + elem = doc.documentElement + + # Simple renaming + elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "a") + confirm(elem.tagName == "a" + and elem.nodeName == "a" + and elem.localName is None + and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE + and elem.prefix is None + and elem.ownerDocument.isSameNode(doc)) + + # Rename to have a namespace, no prefix + elem = doc.renameNode(elem, "http://xml.python.org/ns", "b") + confirm(elem.tagName == "b" + and elem.nodeName == "b" + and elem.localName == "b" + and elem.namespaceURI == "http://xml.python.org/ns" + and elem.prefix is None + and elem.ownerDocument.isSameNode(doc)) + + # Rename to have a namespace, with prefix + elem = doc.renameNode(elem, "http://xml.python.org/ns2", "p:c") + confirm(elem.tagName == "p:c" + and elem.nodeName == "p:c" + and elem.localName == "c" + and elem.namespaceURI == "http://xml.python.org/ns2" + and elem.prefix == "p" + and elem.ownerDocument.isSameNode(doc)) + + # Rename back to a simple non-NS node + elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "d") + confirm(elem.tagName == "d" + and elem.nodeName == "d" + and elem.localName is None + and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE + and elem.prefix is None + and elem.ownerDocument.isSameNode(doc)) + + checkRenameNodeSharedConstraints(doc, elem) + doc.unlink() + +def checkRenameNodeSharedConstraints(doc, node): + # Make sure illegal NS usage is detected: + try: + doc.renameNode(node, "http://xml.python.org/ns", "xmlns:foo") + except xml.dom.NamespaceErr: + pass + else: + print "expected NamespaceErr" + + doc2 = parseString("<doc/>") + try: + doc2.renameNode(node, xml.dom.EMPTY_NAMESPACE, "foo") + except xml.dom.WrongDocumentErr: + pass + else: + print "expected WrongDocumentErr" + +def testRenameOther(): + # We have to create a comment node explicitly since not all DOM + # builders used with minidom add comments to the DOM. + doc = xml.dom.minidom.getDOMImplementation().createDocument( + xml.dom.EMPTY_NAMESPACE, "e", None) + node = doc.createComment("comment") + try: + doc.renameNode(node, xml.dom.EMPTY_NAMESPACE, "foo") + except xml.dom.NotSupportedErr: + pass + else: + print "expected NotSupportedErr when renaming comment node" + doc.unlink() + +def checkWholeText(node, s): + t = node.wholeText + confirm(t == s, "looking for %s, found %s" % (repr(s), repr(t))) + +def testWholeText(): + doc = parseString("<doc>a</doc>") + elem = doc.documentElement + text = elem.childNodes[0] + assert text.nodeType == Node.TEXT_NODE + + checkWholeText(text, "a") + elem.appendChild(doc.createTextNode("b")) + checkWholeText(text, "ab") + elem.insertBefore(doc.createCDATASection("c"), text) + checkWholeText(text, "cab") + + # make sure we don't cross other nodes + splitter = doc.createComment("comment") + elem.appendChild(splitter) + text2 = doc.createTextNode("d") + elem.appendChild(text2) + checkWholeText(text, "cab") + checkWholeText(text2, "d") + + x = doc.createElement("x") + elem.replaceChild(x, splitter) + splitter = x + checkWholeText(text, "cab") + checkWholeText(text2, "d") + + x = doc.createProcessingInstruction("y", "z") + elem.replaceChild(x, splitter) + splitter = x + checkWholeText(text, "cab") + checkWholeText(text2, "d") + + elem.removeChild(splitter) + checkWholeText(text, "cabd") + checkWholeText(text2, "cabd") + +def testReplaceWholeText(): + def setup(): + doc = parseString("<doc>a<e/>d</doc>") + elem = doc.documentElement + text1 = elem.firstChild + text2 = elem.lastChild + splitter = text1.nextSibling + elem.insertBefore(doc.createTextNode("b"), splitter) + elem.insertBefore(doc.createCDATASection("c"), text1) + return doc, elem, text1, splitter, text2 + + doc, elem, text1, splitter, text2 = setup() + text = text1.replaceWholeText("new content") + checkWholeText(text, "new content") + checkWholeText(text2, "d") + confirm(len(elem.childNodes) == 3) + + doc, elem, text1, splitter, text2 = setup() + text = text2.replaceWholeText("new content") + checkWholeText(text, "new content") + checkWholeText(text1, "cab") + confirm(len(elem.childNodes) == 5) + + doc, elem, text1, splitter, text2 = setup() + text = text1.replaceWholeText("") + checkWholeText(text2, "d") + confirm(text is None + and len(elem.childNodes) == 2) + +def testSchemaType(): + doc = parseString( + "<!DOCTYPE doc [\n" + " <!ENTITY e1 SYSTEM 'http://xml.python.org/e1'>\n" + " <!ENTITY e2 SYSTEM 'http://xml.python.org/e2'>\n" + " <!ATTLIST doc id ID #IMPLIED \n" + " ref IDREF #IMPLIED \n" + " refs IDREFS #IMPLIED \n" + " enum (a|b) #IMPLIED \n" + " ent ENTITY #IMPLIED \n" + " ents ENTITIES #IMPLIED \n" + " nm NMTOKEN #IMPLIED \n" + " nms NMTOKENS #IMPLIED \n" + " text CDATA #IMPLIED \n" + " >\n" + "]><doc id='name' notid='name' text='splat!' enum='b'" + " ref='name' refs='name name' ent='e1' ents='e1 e2'" + " nm='123' nms='123 abc' />") + elem = doc.documentElement + # We don't want to rely on any specific loader at this point, so + # just make sure we can get to all the names, and that the + # DTD-based namespace is right. The names can vary by loader + # since each supports a different level of DTD information. + t = elem.schemaType + confirm(t.name is None + and t.namespace == xml.dom.EMPTY_NAMESPACE) + names = "id notid text enum ref refs ent ents nm nms".split() + for name in names: + a = elem.getAttributeNode(name) + t = a.schemaType + confirm(hasattr(t, "name") + and t.namespace == xml.dom.EMPTY_NAMESPACE) + +def testSetIdAttribute(): + doc = parseString("<doc a1='v' a2='w'/>") + e = doc.documentElement + a1 = e.getAttributeNode("a1") + a2 = e.getAttributeNode("a2") + confirm(doc.getElementById("v") is None + and not a1.isId + and not a2.isId) + e.setIdAttribute("a1") + confirm(e.isSameNode(doc.getElementById("v")) + and a1.isId + and not a2.isId) + e.setIdAttribute("a2") + confirm(e.isSameNode(doc.getElementById("v")) + and e.isSameNode(doc.getElementById("w")) + and a1.isId + and a2.isId) + # replace the a1 node; the new node should *not* be an ID + a3 = doc.createAttribute("a1") + a3.value = "v" + e.setAttributeNode(a3) + confirm(doc.getElementById("v") is None + and e.isSameNode(doc.getElementById("w")) + and not a1.isId + and a2.isId + and not a3.isId) + # renaming an attribute should not affect it's ID-ness: + doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an") + confirm(e.isSameNode(doc.getElementById("w")) + and a2.isId) + +def testSetIdAttributeNS(): + NS1 = "http://xml.python.org/ns1" + NS2 = "http://xml.python.org/ns2" + doc = parseString("<doc" + " xmlns:ns1='" + NS1 + "'" + " xmlns:ns2='" + NS2 + "'" + " ns1:a1='v' ns2:a2='w'/>") + e = doc.documentElement + a1 = e.getAttributeNodeNS(NS1, "a1") + a2 = e.getAttributeNodeNS(NS2, "a2") + confirm(doc.getElementById("v") is None + and not a1.isId + and not a2.isId) + e.setIdAttributeNS(NS1, "a1") + confirm(e.isSameNode(doc.getElementById("v")) + and a1.isId + and not a2.isId) + e.setIdAttributeNS(NS2, "a2") + confirm(e.isSameNode(doc.getElementById("v")) + and e.isSameNode(doc.getElementById("w")) + and a1.isId + and a2.isId) + # replace the a1 node; the new node should *not* be an ID + a3 = doc.createAttributeNS(NS1, "a1") + a3.value = "v" + e.setAttributeNode(a3) + confirm(e.isSameNode(doc.getElementById("w"))) + confirm(not a1.isId) + confirm(a2.isId) + confirm(not a3.isId) + confirm(doc.getElementById("v") is None) + # renaming an attribute should not affect it's ID-ness: + doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an") + confirm(e.isSameNode(doc.getElementById("w")) + and a2.isId) + +def testSetIdAttributeNode(): + NS1 = "http://xml.python.org/ns1" + NS2 = "http://xml.python.org/ns2" + doc = parseString("<doc" + " xmlns:ns1='" + NS1 + "'" + " xmlns:ns2='" + NS2 + "'" + " ns1:a1='v' ns2:a2='w'/>") + e = doc.documentElement + a1 = e.getAttributeNodeNS(NS1, "a1") + a2 = e.getAttributeNodeNS(NS2, "a2") + confirm(doc.getElementById("v") is None + and not a1.isId + and not a2.isId) + e.setIdAttributeNode(a1) + confirm(e.isSameNode(doc.getElementById("v")) + and a1.isId + and not a2.isId) + e.setIdAttributeNode(a2) + confirm(e.isSameNode(doc.getElementById("v")) + and e.isSameNode(doc.getElementById("w")) + and a1.isId + and a2.isId) + # replace the a1 node; the new node should *not* be an ID + a3 = doc.createAttributeNS(NS1, "a1") + a3.value = "v" + e.setAttributeNode(a3) + confirm(e.isSameNode(doc.getElementById("w"))) + confirm(not a1.isId) + confirm(a2.isId) + confirm(not a3.isId) + confirm(doc.getElementById("v") is None) + # renaming an attribute should not affect it's ID-ness: + doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an") + confirm(e.isSameNode(doc.getElementById("w")) + and a2.isId) + +def testPickledDocument(): + doc = parseString("<?xml version='1.0' encoding='us-ascii'?>\n" + "<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'" + " 'http://xml.python.org/system' [\n" + " <!ELEMENT e EMPTY>\n" + " <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n" + "]><doc attr='value'> text\n" + "<?pi sample?> <!-- comment --> <e/> </doc>") + s = pickle.dumps(doc) + doc2 = pickle.loads(s) + stack = [(doc, doc2)] + while stack: + n1, n2 = stack.pop() + confirm(n1.nodeType == n2.nodeType + and len(n1.childNodes) == len(n2.childNodes) + and n1.nodeName == n2.nodeName + and not n1.isSameNode(n2) + and not n2.isSameNode(n1)) + if n1.nodeType == Node.DOCUMENT_TYPE_NODE: + len(n1.entities) + len(n2.entities) + len(n1.notations) + len(n2.notations) + confirm(len(n1.entities) == len(n2.entities) + and len(n1.notations) == len(n2.notations)) + for i in range(len(n1.notations)): + no1 = n1.notations.item(i) + no2 = n1.notations.item(i) + confirm(no1.name == no2.name + and no1.publicId == no2.publicId + and no1.systemId == no2.systemId) + statck.append((no1, no2)) + for i in range(len(n1.entities)): + e1 = n1.entities.item(i) + e2 = n2.entities.item(i) + confirm(e1.notationName == e2.notationName + and e1.publicId == e2.publicId + and e1.systemId == e2.systemId) + stack.append((e1, e2)) + if n1.nodeType != Node.DOCUMENT_NODE: + confirm(n1.ownerDocument.isSameNode(doc) + and n2.ownerDocument.isSameNode(doc2)) + for i in range(len(n1.childNodes)): + stack.append((n1.childNodes[i], n2.childNodes[i])) + + # --- MAIN PROGRAM names = globals().keys() |