summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_minidom.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_minidom.py')
-rw-r--r--Lib/test/test_minidom.py756
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()