]> git.proxmox.com Git - mirror_edk2.git/blobdiff - AppPkg/Applications/Python/Python-2.7.10/Lib/xml/dom/minidom.py
AppPkg/Applications/Python/Python-2.7.10: Initial Checkin part 4/5.
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.10 / Lib / xml / dom / minidom.py
diff --git a/AppPkg/Applications/Python/Python-2.7.10/Lib/xml/dom/minidom.py b/AppPkg/Applications/Python/Python-2.7.10/Lib/xml/dom/minidom.py
new file mode 100644 (file)
index 0000000..54b41c4
--- /dev/null
@@ -0,0 +1,1941 @@
+"""Simple implementation of the Level 1 DOM.\r
+\r
+Namespaces and other minor Level 2 features are also supported.\r
+\r
+parse("foo.xml")\r
+\r
+parseString("<foo><bar/></foo>")\r
+\r
+Todo:\r
+=====\r
+ * convenience methods for getting elements and text.\r
+ * more testing\r
+ * bring some of the writer and linearizer code into conformance with this\r
+        interface\r
+ * SAX 2 namespaces\r
+"""\r
+\r
+import xml.dom\r
+\r
+from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE, domreg\r
+from xml.dom.minicompat import *\r
+from xml.dom.xmlbuilder import DOMImplementationLS, DocumentLS\r
+\r
+# This is used by the ID-cache invalidation checks; the list isn't\r
+# actually complete, since the nodes being checked will never be the\r
+# DOCUMENT_NODE or DOCUMENT_FRAGMENT_NODE.  (The node being checked is\r
+# the node being added or removed, not the node being modified.)\r
+#\r
+_nodeTypes_with_children = (xml.dom.Node.ELEMENT_NODE,\r
+                            xml.dom.Node.ENTITY_REFERENCE_NODE)\r
+\r
+\r
+class Node(xml.dom.Node):\r
+    namespaceURI = None # this is non-null only for elements and attributes\r
+    parentNode = None\r
+    ownerDocument = None\r
+    nextSibling = None\r
+    previousSibling = None\r
+\r
+    prefix = EMPTY_PREFIX # non-null only for NS elements and attributes\r
+\r
+    def __nonzero__(self):\r
+        return True\r
+\r
+    def toxml(self, encoding = None):\r
+        return self.toprettyxml("", "", encoding)\r
+\r
+    def toprettyxml(self, indent="\t", newl="\n", encoding = None):\r
+        # indent = the indentation string to prepend, per level\r
+        # newl = the newline string to append\r
+        writer = _get_StringIO()\r
+        if encoding is not None:\r
+            import codecs\r
+            # Can't use codecs.getwriter to preserve 2.0 compatibility\r
+            writer = codecs.lookup(encoding)[3](writer)\r
+        if self.nodeType == Node.DOCUMENT_NODE:\r
+            # Can pass encoding only to document, to put it into XML header\r
+            self.writexml(writer, "", indent, newl, encoding)\r
+        else:\r
+            self.writexml(writer, "", indent, newl)\r
+        return writer.getvalue()\r
+\r
+    def hasChildNodes(self):\r
+        if self.childNodes:\r
+            return True\r
+        else:\r
+            return False\r
+\r
+    def _get_childNodes(self):\r
+        return self.childNodes\r
+\r
+    def _get_firstChild(self):\r
+        if self.childNodes:\r
+            return self.childNodes[0]\r
+\r
+    def _get_lastChild(self):\r
+        if self.childNodes:\r
+            return self.childNodes[-1]\r
+\r
+    def insertBefore(self, newChild, refChild):\r
+        if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:\r
+            for c in tuple(newChild.childNodes):\r
+                self.insertBefore(c, refChild)\r
+            ### The DOM does not clearly specify what to return in this case\r
+            return newChild\r
+        if newChild.nodeType not in self._child_node_types:\r
+            raise xml.dom.HierarchyRequestErr(\r
+                "%s cannot be child of %s" % (repr(newChild), repr(self)))\r
+        if newChild.parentNode is not None:\r
+            newChild.parentNode.removeChild(newChild)\r
+        if refChild is None:\r
+            self.appendChild(newChild)\r
+        else:\r
+            try:\r
+                index = self.childNodes.index(refChild)\r
+            except ValueError:\r
+                raise xml.dom.NotFoundErr()\r
+            if newChild.nodeType in _nodeTypes_with_children:\r
+                _clear_id_cache(self)\r
+            self.childNodes.insert(index, newChild)\r
+            newChild.nextSibling = refChild\r
+            refChild.previousSibling = newChild\r
+            if index:\r
+                node = self.childNodes[index-1]\r
+                node.nextSibling = newChild\r
+                newChild.previousSibling = node\r
+            else:\r
+                newChild.previousSibling = None\r
+            newChild.parentNode = self\r
+        return newChild\r
+\r
+    def appendChild(self, node):\r
+        if node.nodeType == self.DOCUMENT_FRAGMENT_NODE:\r
+            for c in tuple(node.childNodes):\r
+                self.appendChild(c)\r
+            ### The DOM does not clearly specify what to return in this case\r
+            return node\r
+        if node.nodeType not in self._child_node_types:\r
+            raise xml.dom.HierarchyRequestErr(\r
+                "%s cannot be child of %s" % (repr(node), repr(self)))\r
+        elif node.nodeType in _nodeTypes_with_children:\r
+            _clear_id_cache(self)\r
+        if node.parentNode is not None:\r
+            node.parentNode.removeChild(node)\r
+        _append_child(self, node)\r
+        node.nextSibling = None\r
+        return node\r
+\r
+    def replaceChild(self, newChild, oldChild):\r
+        if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:\r
+            refChild = oldChild.nextSibling\r
+            self.removeChild(oldChild)\r
+            return self.insertBefore(newChild, refChild)\r
+        if newChild.nodeType not in self._child_node_types:\r
+            raise xml.dom.HierarchyRequestErr(\r
+                "%s cannot be child of %s" % (repr(newChild), repr(self)))\r
+        if newChild is oldChild:\r
+            return\r
+        if newChild.parentNode is not None:\r
+            newChild.parentNode.removeChild(newChild)\r
+        try:\r
+            index = self.childNodes.index(oldChild)\r
+        except ValueError:\r
+            raise xml.dom.NotFoundErr()\r
+        self.childNodes[index] = newChild\r
+        newChild.parentNode = self\r
+        oldChild.parentNode = None\r
+        if (newChild.nodeType in _nodeTypes_with_children\r
+            or oldChild.nodeType in _nodeTypes_with_children):\r
+            _clear_id_cache(self)\r
+        newChild.nextSibling = oldChild.nextSibling\r
+        newChild.previousSibling = oldChild.previousSibling\r
+        oldChild.nextSibling = None\r
+        oldChild.previousSibling = None\r
+        if newChild.previousSibling:\r
+            newChild.previousSibling.nextSibling = newChild\r
+        if newChild.nextSibling:\r
+            newChild.nextSibling.previousSibling = newChild\r
+        return oldChild\r
+\r
+    def removeChild(self, oldChild):\r
+        try:\r
+            self.childNodes.remove(oldChild)\r
+        except ValueError:\r
+            raise xml.dom.NotFoundErr()\r
+        if oldChild.nextSibling is not None:\r
+            oldChild.nextSibling.previousSibling = oldChild.previousSibling\r
+        if oldChild.previousSibling is not None:\r
+            oldChild.previousSibling.nextSibling = oldChild.nextSibling\r
+        oldChild.nextSibling = oldChild.previousSibling = None\r
+        if oldChild.nodeType in _nodeTypes_with_children:\r
+            _clear_id_cache(self)\r
+\r
+        oldChild.parentNode = None\r
+        return oldChild\r
+\r
+    def normalize(self):\r
+        L = []\r
+        for child in self.childNodes:\r
+            if child.nodeType == Node.TEXT_NODE:\r
+                if not child.data:\r
+                    # empty text node; discard\r
+                    if L:\r
+                        L[-1].nextSibling = child.nextSibling\r
+                    if child.nextSibling:\r
+                        child.nextSibling.previousSibling = child.previousSibling\r
+                    child.unlink()\r
+                elif L and L[-1].nodeType == child.nodeType:\r
+                    # collapse text node\r
+                    node = L[-1]\r
+                    node.data = node.data + child.data\r
+                    node.nextSibling = child.nextSibling\r
+                    if child.nextSibling:\r
+                        child.nextSibling.previousSibling = node\r
+                    child.unlink()\r
+                else:\r
+                    L.append(child)\r
+            else:\r
+                L.append(child)\r
+                if child.nodeType == Node.ELEMENT_NODE:\r
+                    child.normalize()\r
+        self.childNodes[:] = L\r
+\r
+    def cloneNode(self, deep):\r
+        return _clone_node(self, deep, self.ownerDocument or self)\r
+\r
+    def isSupported(self, feature, version):\r
+        return self.ownerDocument.implementation.hasFeature(feature, version)\r
+\r
+    def _get_localName(self):\r
+        # Overridden in Element and Attr where localName can be Non-Null\r
+        return None\r
+\r
+    # Node interfaces from Level 3 (WD 9 April 2002)\r
+\r
+    def isSameNode(self, other):\r
+        return self is other\r
+\r
+    def getInterface(self, feature):\r
+        if self.isSupported(feature, None):\r
+            return self\r
+        else:\r
+            return None\r
+\r
+    # The "user data" functions use a dictionary that is only present\r
+    # if some user data has been set, so be careful not to assume it\r
+    # exists.\r
+\r
+    def getUserData(self, key):\r
+        try:\r
+            return self._user_data[key][0]\r
+        except (AttributeError, KeyError):\r
+            return None\r
+\r
+    def setUserData(self, key, data, handler):\r
+        old = None\r
+        try:\r
+            d = self._user_data\r
+        except AttributeError:\r
+            d = {}\r
+            self._user_data = d\r
+        if key in d:\r
+            old = d[key][0]\r
+        if data is None:\r
+            # ignore handlers passed for None\r
+            handler = None\r
+            if old is not None:\r
+                del d[key]\r
+        else:\r
+            d[key] = (data, handler)\r
+        return old\r
+\r
+    def _call_user_data_handler(self, operation, src, dst):\r
+        if hasattr(self, "_user_data"):\r
+            for key, (data, handler) in self._user_data.items():\r
+                if handler is not None:\r
+                    handler.handle(operation, key, data, src, dst)\r
+\r
+    # minidom-specific API:\r
+\r
+    def unlink(self):\r
+        self.parentNode = self.ownerDocument = None\r
+        if self.childNodes:\r
+            for child in self.childNodes:\r
+                child.unlink()\r
+            self.childNodes = NodeList()\r
+        self.previousSibling = None\r
+        self.nextSibling = None\r
+\r
+defproperty(Node, "firstChild", doc="First child node, or None.")\r
+defproperty(Node, "lastChild",  doc="Last child node, or None.")\r
+defproperty(Node, "localName",  doc="Namespace-local name of this node.")\r
+\r
+\r
+def _append_child(self, node):\r
+    # fast path with less checks; usable by DOM builders if careful\r
+    childNodes = self.childNodes\r
+    if childNodes:\r
+        last = childNodes[-1]\r
+        node.__dict__["previousSibling"] = last\r
+        last.__dict__["nextSibling"] = node\r
+    childNodes.append(node)\r
+    node.__dict__["parentNode"] = self\r
+\r
+def _in_document(node):\r
+    # return True iff node is part of a document tree\r
+    while node is not None:\r
+        if node.nodeType == Node.DOCUMENT_NODE:\r
+            return True\r
+        node = node.parentNode\r
+    return False\r
+\r
+def _write_data(writer, data):\r
+    "Writes datachars to writer."\r
+    if data:\r
+        data = data.replace("&", "&amp;").replace("<", "&lt;"). \\r
+                    replace("\"", "&quot;").replace(">", "&gt;")\r
+        writer.write(data)\r
+\r
+def _get_elements_by_tagName_helper(parent, name, rc):\r
+    for node in parent.childNodes:\r
+        if node.nodeType == Node.ELEMENT_NODE and \\r
+            (name == "*" or node.tagName == name):\r
+            rc.append(node)\r
+        _get_elements_by_tagName_helper(node, name, rc)\r
+    return rc\r
+\r
+def _get_elements_by_tagName_ns_helper(parent, nsURI, localName, rc):\r
+    for node in parent.childNodes:\r
+        if node.nodeType == Node.ELEMENT_NODE:\r
+            if ((localName == "*" or node.localName == localName) and\r
+                (nsURI == "*" or node.namespaceURI == nsURI)):\r
+                rc.append(node)\r
+            _get_elements_by_tagName_ns_helper(node, nsURI, localName, rc)\r
+    return rc\r
+\r
+class DocumentFragment(Node):\r
+    nodeType = Node.DOCUMENT_FRAGMENT_NODE\r
+    nodeName = "#document-fragment"\r
+    nodeValue = None\r
+    attributes = None\r
+    parentNode = None\r
+    _child_node_types = (Node.ELEMENT_NODE,\r
+                         Node.TEXT_NODE,\r
+                         Node.CDATA_SECTION_NODE,\r
+                         Node.ENTITY_REFERENCE_NODE,\r
+                         Node.PROCESSING_INSTRUCTION_NODE,\r
+                         Node.COMMENT_NODE,\r
+                         Node.NOTATION_NODE)\r
+\r
+    def __init__(self):\r
+        self.childNodes = NodeList()\r
+\r
+\r
+class Attr(Node):\r
+    nodeType = Node.ATTRIBUTE_NODE\r
+    attributes = None\r
+    ownerElement = None\r
+    specified = False\r
+    _is_id = False\r
+\r
+    _child_node_types = (Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE)\r
+\r
+    def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None,\r
+                 prefix=None):\r
+        # skip setattr for performance\r
+        d = self.__dict__\r
+        d["nodeName"] = d["name"] = qName\r
+        d["namespaceURI"] = namespaceURI\r
+        d["prefix"] = prefix\r
+        d['childNodes'] = NodeList()\r
+\r
+        # Add the single child node that represents the value of the attr\r
+        self.childNodes.append(Text())\r
+\r
+        # nodeValue and value are set elsewhere\r
+\r
+    def _get_localName(self):\r
+        return self.nodeName.split(":", 1)[-1]\r
+\r
+    def _get_specified(self):\r
+        return self.specified\r
+\r
+    def __setattr__(self, name, value):\r
+        d = self.__dict__\r
+        if name in ("value", "nodeValue"):\r
+            d["value"] = d["nodeValue"] = value\r
+            d2 = self.childNodes[0].__dict__\r
+            d2["data"] = d2["nodeValue"] = value\r
+            if self.ownerElement is not None:\r
+                _clear_id_cache(self.ownerElement)\r
+        elif name in ("name", "nodeName"):\r
+            d["name"] = d["nodeName"] = value\r
+            if self.ownerElement is not None:\r
+                _clear_id_cache(self.ownerElement)\r
+        else:\r
+            d[name] = value\r
+\r
+    def _set_prefix(self, prefix):\r
+        nsuri = self.namespaceURI\r
+        if prefix == "xmlns":\r
+            if nsuri and nsuri != XMLNS_NAMESPACE:\r
+                raise xml.dom.NamespaceErr(\r
+                    "illegal use of 'xmlns' prefix for the wrong namespace")\r
+        d = self.__dict__\r
+        d['prefix'] = prefix\r
+        if prefix is None:\r
+            newName = self.localName\r
+        else:\r
+            newName = "%s:%s" % (prefix, self.localName)\r
+        if self.ownerElement:\r
+            _clear_id_cache(self.ownerElement)\r
+        d['nodeName'] = d['name'] = newName\r
+\r
+    def _set_value(self, value):\r
+        d = self.__dict__\r
+        d['value'] = d['nodeValue'] = value\r
+        if self.ownerElement:\r
+            _clear_id_cache(self.ownerElement)\r
+        self.childNodes[0].data = value\r
+\r
+    def unlink(self):\r
+        # This implementation does not call the base implementation\r
+        # since most of that is not needed, and the expense of the\r
+        # method call is not warranted.  We duplicate the removal of\r
+        # children, but that's all we needed from the base class.\r
+        elem = self.ownerElement\r
+        if elem is not None:\r
+            del elem._attrs[self.nodeName]\r
+            del elem._attrsNS[(self.namespaceURI, self.localName)]\r
+            if self._is_id:\r
+                self._is_id = False\r
+                elem._magic_id_nodes -= 1\r
+                self.ownerDocument._magic_id_count -= 1\r
+        for child in self.childNodes:\r
+            child.unlink()\r
+        del self.childNodes[:]\r
+\r
+    def _get_isId(self):\r
+        if self._is_id:\r
+            return True\r
+        doc = self.ownerDocument\r
+        elem = self.ownerElement\r
+        if doc is None or elem is None:\r
+            return False\r
+\r
+        info = doc._get_elem_info(elem)\r
+        if info is None:\r
+            return False\r
+        if self.namespaceURI:\r
+            return info.isIdNS(self.namespaceURI, self.localName)\r
+        else:\r
+            return info.isId(self.nodeName)\r
+\r
+    def _get_schemaType(self):\r
+        doc = self.ownerDocument\r
+        elem = self.ownerElement\r
+        if doc is None or elem is None:\r
+            return _no_type\r
+\r
+        info = doc._get_elem_info(elem)\r
+        if info is None:\r
+            return _no_type\r
+        if self.namespaceURI:\r
+            return info.getAttributeTypeNS(self.namespaceURI, self.localName)\r
+        else:\r
+            return info.getAttributeType(self.nodeName)\r
+\r
+defproperty(Attr, "isId",       doc="True if this attribute is an ID.")\r
+defproperty(Attr, "localName",  doc="Namespace-local name of this attribute.")\r
+defproperty(Attr, "schemaType", doc="Schema type for this attribute.")\r
+\r
+\r
+class NamedNodeMap(object):\r
+    """The attribute list is a transient interface to the underlying\r
+    dictionaries.  Mutations here will change the underlying element's\r
+    dictionary.\r
+\r
+    Ordering is imposed artificially and does not reflect the order of\r
+    attributes as found in an input document.\r
+    """\r
+\r
+    __slots__ = ('_attrs', '_attrsNS', '_ownerElement')\r
+\r
+    def __init__(self, attrs, attrsNS, ownerElement):\r
+        self._attrs = attrs\r
+        self._attrsNS = attrsNS\r
+        self._ownerElement = ownerElement\r
+\r
+    def _get_length(self):\r
+        return len(self._attrs)\r
+\r
+    def item(self, index):\r
+        try:\r
+            return self[self._attrs.keys()[index]]\r
+        except IndexError:\r
+            return None\r
+\r
+    def items(self):\r
+        L = []\r
+        for node in self._attrs.values():\r
+            L.append((node.nodeName, node.value))\r
+        return L\r
+\r
+    def itemsNS(self):\r
+        L = []\r
+        for node in self._attrs.values():\r
+            L.append(((node.namespaceURI, node.localName), node.value))\r
+        return L\r
+\r
+    def has_key(self, key):\r
+        if isinstance(key, StringTypes):\r
+            return key in self._attrs\r
+        else:\r
+            return key in self._attrsNS\r
+\r
+    def keys(self):\r
+        return self._attrs.keys()\r
+\r
+    def keysNS(self):\r
+        return self._attrsNS.keys()\r
+\r
+    def values(self):\r
+        return self._attrs.values()\r
+\r
+    def get(self, name, value=None):\r
+        return self._attrs.get(name, value)\r
+\r
+    __len__ = _get_length\r
+\r
+    __hash__ = None # Mutable type can't be correctly hashed\r
+    def __cmp__(self, other):\r
+        if self._attrs is getattr(other, "_attrs", None):\r
+            return 0\r
+        else:\r
+            return cmp(id(self), id(other))\r
+\r
+    def __getitem__(self, attname_or_tuple):\r
+        if isinstance(attname_or_tuple, tuple):\r
+            return self._attrsNS[attname_or_tuple]\r
+        else:\r
+            return self._attrs[attname_or_tuple]\r
+\r
+    # same as set\r
+    def __setitem__(self, attname, value):\r
+        if isinstance(value, StringTypes):\r
+            try:\r
+                node = self._attrs[attname]\r
+            except KeyError:\r
+                node = Attr(attname)\r
+                node.ownerDocument = self._ownerElement.ownerDocument\r
+                self.setNamedItem(node)\r
+            node.value = value\r
+        else:\r
+            if not isinstance(value, Attr):\r
+                raise TypeError, "value must be a string or Attr object"\r
+            node = value\r
+            self.setNamedItem(node)\r
+\r
+    def getNamedItem(self, name):\r
+        try:\r
+            return self._attrs[name]\r
+        except KeyError:\r
+            return None\r
+\r
+    def getNamedItemNS(self, namespaceURI, localName):\r
+        try:\r
+            return self._attrsNS[(namespaceURI, localName)]\r
+        except KeyError:\r
+            return None\r
+\r
+    def removeNamedItem(self, name):\r
+        n = self.getNamedItem(name)\r
+        if n is not None:\r
+            _clear_id_cache(self._ownerElement)\r
+            del self._attrs[n.nodeName]\r
+            del self._attrsNS[(n.namespaceURI, n.localName)]\r
+            if 'ownerElement' in n.__dict__:\r
+                n.__dict__['ownerElement'] = None\r
+            return n\r
+        else:\r
+            raise xml.dom.NotFoundErr()\r
+\r
+    def removeNamedItemNS(self, namespaceURI, localName):\r
+        n = self.getNamedItemNS(namespaceURI, localName)\r
+        if n is not None:\r
+            _clear_id_cache(self._ownerElement)\r
+            del self._attrsNS[(n.namespaceURI, n.localName)]\r
+            del self._attrs[n.nodeName]\r
+            if 'ownerElement' in n.__dict__:\r
+                n.__dict__['ownerElement'] = None\r
+            return n\r
+        else:\r
+            raise xml.dom.NotFoundErr()\r
+\r
+    def setNamedItem(self, node):\r
+        if not isinstance(node, Attr):\r
+            raise xml.dom.HierarchyRequestErr(\r
+                "%s cannot be child of %s" % (repr(node), repr(self)))\r
+        old = self._attrs.get(node.name)\r
+        if old:\r
+            old.unlink()\r
+        self._attrs[node.name] = node\r
+        self._attrsNS[(node.namespaceURI, node.localName)] = node\r
+        node.ownerElement = self._ownerElement\r
+        _clear_id_cache(node.ownerElement)\r
+        return old\r
+\r
+    def setNamedItemNS(self, node):\r
+        return self.setNamedItem(node)\r
+\r
+    def __delitem__(self, attname_or_tuple):\r
+        node = self[attname_or_tuple]\r
+        _clear_id_cache(node.ownerElement)\r
+        node.unlink()\r
+\r
+    def __getstate__(self):\r
+        return self._attrs, self._attrsNS, self._ownerElement\r
+\r
+    def __setstate__(self, state):\r
+        self._attrs, self._attrsNS, self._ownerElement = state\r
+\r
+defproperty(NamedNodeMap, "length",\r
+            doc="Number of nodes in the NamedNodeMap.")\r
+\r
+AttributeList = NamedNodeMap\r
+\r
+\r
+class TypeInfo(object):\r
+    __slots__ = 'namespace', 'name'\r
+\r
+    def __init__(self, namespace, name):\r
+        self.namespace = namespace\r
+        self.name = name\r
+\r
+    def __repr__(self):\r
+        if self.namespace:\r
+            return "<TypeInfo %r (from %r)>" % (self.name, self.namespace)\r
+        else:\r
+            return "<TypeInfo %r>" % self.name\r
+\r
+    def _get_name(self):\r
+        return self.name\r
+\r
+    def _get_namespace(self):\r
+        return self.namespace\r
+\r
+_no_type = TypeInfo(None, None)\r
+\r
+class Element(Node):\r
+    nodeType = Node.ELEMENT_NODE\r
+    nodeValue = None\r
+    schemaType = _no_type\r
+\r
+    _magic_id_nodes = 0\r
+\r
+    _child_node_types = (Node.ELEMENT_NODE,\r
+                         Node.PROCESSING_INSTRUCTION_NODE,\r
+                         Node.COMMENT_NODE,\r
+                         Node.TEXT_NODE,\r
+                         Node.CDATA_SECTION_NODE,\r
+                         Node.ENTITY_REFERENCE_NODE)\r
+\r
+    def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None,\r
+                 localName=None):\r
+        self.tagName = self.nodeName = tagName\r
+        self.prefix = prefix\r
+        self.namespaceURI = namespaceURI\r
+        self.childNodes = NodeList()\r
+\r
+        self._attrs = {}   # attributes are double-indexed:\r
+        self._attrsNS = {} #    tagName -> Attribute\r
+                           #    URI,localName -> Attribute\r
+                           # in the future: consider lazy generation\r
+                           # of attribute objects this is too tricky\r
+                           # for now because of headaches with\r
+                           # namespaces.\r
+\r
+    def _get_localName(self):\r
+        return self.tagName.split(":", 1)[-1]\r
+\r
+    def _get_tagName(self):\r
+        return self.tagName\r
+\r
+    def unlink(self):\r
+        for attr in self._attrs.values():\r
+            attr.unlink()\r
+        self._attrs = None\r
+        self._attrsNS = None\r
+        Node.unlink(self)\r
+\r
+    def getAttribute(self, attname):\r
+        try:\r
+            return self._attrs[attname].value\r
+        except KeyError:\r
+            return ""\r
+\r
+    def getAttributeNS(self, namespaceURI, localName):\r
+        try:\r
+            return self._attrsNS[(namespaceURI, localName)].value\r
+        except KeyError:\r
+            return ""\r
+\r
+    def setAttribute(self, attname, value):\r
+        attr = self.getAttributeNode(attname)\r
+        if attr is None:\r
+            attr = Attr(attname)\r
+            # for performance\r
+            d = attr.__dict__\r
+            d["value"] = d["nodeValue"] = value\r
+            d["ownerDocument"] = self.ownerDocument\r
+            self.setAttributeNode(attr)\r
+        elif value != attr.value:\r
+            d = attr.__dict__\r
+            d["value"] = d["nodeValue"] = value\r
+            if attr.isId:\r
+                _clear_id_cache(self)\r
+\r
+    def setAttributeNS(self, namespaceURI, qualifiedName, value):\r
+        prefix, localname = _nssplit(qualifiedName)\r
+        attr = self.getAttributeNodeNS(namespaceURI, localname)\r
+        if attr is None:\r
+            # for performance\r
+            attr = Attr(qualifiedName, namespaceURI, localname, prefix)\r
+            d = attr.__dict__\r
+            d["prefix"] = prefix\r
+            d["nodeName"] = qualifiedName\r
+            d["value"] = d["nodeValue"] = value\r
+            d["ownerDocument"] = self.ownerDocument\r
+            self.setAttributeNode(attr)\r
+        else:\r
+            d = attr.__dict__\r
+            if value != attr.value:\r
+                d["value"] = d["nodeValue"] = value\r
+                if attr.isId:\r
+                    _clear_id_cache(self)\r
+            if attr.prefix != prefix:\r
+                d["prefix"] = prefix\r
+                d["nodeName"] = qualifiedName\r
+\r
+    def getAttributeNode(self, attrname):\r
+        return self._attrs.get(attrname)\r
+\r
+    def getAttributeNodeNS(self, namespaceURI, localName):\r
+        return self._attrsNS.get((namespaceURI, localName))\r
+\r
+    def setAttributeNode(self, attr):\r
+        if attr.ownerElement not in (None, self):\r
+            raise xml.dom.InuseAttributeErr("attribute node already owned")\r
+        old1 = self._attrs.get(attr.name, None)\r
+        if old1 is not None:\r
+            self.removeAttributeNode(old1)\r
+        old2 = self._attrsNS.get((attr.namespaceURI, attr.localName), None)\r
+        if old2 is not None and old2 is not old1:\r
+            self.removeAttributeNode(old2)\r
+        _set_attribute_node(self, attr)\r
+\r
+        if old1 is not attr:\r
+            # It might have already been part of this node, in which case\r
+            # it doesn't represent a change, and should not be returned.\r
+            return old1\r
+        if old2 is not attr:\r
+            return old2\r
+\r
+    setAttributeNodeNS = setAttributeNode\r
+\r
+    def removeAttribute(self, name):\r
+        try:\r
+            attr = self._attrs[name]\r
+        except KeyError:\r
+            raise xml.dom.NotFoundErr()\r
+        self.removeAttributeNode(attr)\r
+\r
+    def removeAttributeNS(self, namespaceURI, localName):\r
+        try:\r
+            attr = self._attrsNS[(namespaceURI, localName)]\r
+        except KeyError:\r
+            raise xml.dom.NotFoundErr()\r
+        self.removeAttributeNode(attr)\r
+\r
+    def removeAttributeNode(self, node):\r
+        if node is None:\r
+            raise xml.dom.NotFoundErr()\r
+        try:\r
+            self._attrs[node.name]\r
+        except KeyError:\r
+            raise xml.dom.NotFoundErr()\r
+        _clear_id_cache(self)\r
+        node.unlink()\r
+        # Restore this since the node is still useful and otherwise\r
+        # unlinked\r
+        node.ownerDocument = self.ownerDocument\r
+\r
+    removeAttributeNodeNS = removeAttributeNode\r
+\r
+    def hasAttribute(self, name):\r
+        return name in self._attrs\r
+\r
+    def hasAttributeNS(self, namespaceURI, localName):\r
+        return (namespaceURI, localName) in self._attrsNS\r
+\r
+    def getElementsByTagName(self, name):\r
+        return _get_elements_by_tagName_helper(self, name, NodeList())\r
+\r
+    def getElementsByTagNameNS(self, namespaceURI, localName):\r
+        return _get_elements_by_tagName_ns_helper(\r
+            self, namespaceURI, localName, NodeList())\r
+\r
+    def __repr__(self):\r
+        return "<DOM Element: %s at %#x>" % (self.tagName, id(self))\r
+\r
+    def writexml(self, writer, indent="", addindent="", newl=""):\r
+        # indent = current indentation\r
+        # addindent = indentation to add to higher levels\r
+        # newl = newline string\r
+        writer.write(indent+"<" + self.tagName)\r
+\r
+        attrs = self._get_attributes()\r
+        a_names = attrs.keys()\r
+        a_names.sort()\r
+\r
+        for a_name in a_names:\r
+            writer.write(" %s=\"" % a_name)\r
+            _write_data(writer, attrs[a_name].value)\r
+            writer.write("\"")\r
+        if self.childNodes:\r
+            writer.write(">")\r
+            if (len(self.childNodes) == 1 and\r
+                self.childNodes[0].nodeType == Node.TEXT_NODE):\r
+                self.childNodes[0].writexml(writer, '', '', '')\r
+            else:\r
+                writer.write(newl)\r
+                for node in self.childNodes:\r
+                    node.writexml(writer, indent+addindent, addindent, newl)\r
+                writer.write(indent)\r
+            writer.write("</%s>%s" % (self.tagName, newl))\r
+        else:\r
+            writer.write("/>%s"%(newl))\r
+\r
+    def _get_attributes(self):\r
+        return NamedNodeMap(self._attrs, self._attrsNS, self)\r
+\r
+    def hasAttributes(self):\r
+        if self._attrs:\r
+            return True\r
+        else:\r
+            return False\r
+\r
+    # DOM Level 3 attributes, based on the 22 Oct 2002 draft\r
+\r
+    def setIdAttribute(self, name):\r
+        idAttr = self.getAttributeNode(name)\r
+        self.setIdAttributeNode(idAttr)\r
+\r
+    def setIdAttributeNS(self, namespaceURI, localName):\r
+        idAttr = self.getAttributeNodeNS(namespaceURI, localName)\r
+        self.setIdAttributeNode(idAttr)\r
+\r
+    def setIdAttributeNode(self, idAttr):\r
+        if idAttr is None or not self.isSameNode(idAttr.ownerElement):\r
+            raise xml.dom.NotFoundErr()\r
+        if _get_containing_entref(self) is not None:\r
+            raise xml.dom.NoModificationAllowedErr()\r
+        if not idAttr._is_id:\r
+            idAttr.__dict__['_is_id'] = True\r
+            self._magic_id_nodes += 1\r
+            self.ownerDocument._magic_id_count += 1\r
+            _clear_id_cache(self)\r
+\r
+defproperty(Element, "attributes",\r
+            doc="NamedNodeMap of attributes on the element.")\r
+defproperty(Element, "localName",\r
+            doc="Namespace-local name of this element.")\r
+\r
+\r
+def _set_attribute_node(element, attr):\r
+    _clear_id_cache(element)\r
+    element._attrs[attr.name] = attr\r
+    element._attrsNS[(attr.namespaceURI, attr.localName)] = attr\r
+\r
+    # This creates a circular reference, but Element.unlink()\r
+    # breaks the cycle since the references to the attribute\r
+    # dictionaries are tossed.\r
+    attr.__dict__['ownerElement'] = element\r
+\r
+\r
+class Childless:\r
+    """Mixin that makes childless-ness easy to implement and avoids\r
+    the complexity of the Node methods that deal with children.\r
+    """\r
+\r
+    attributes = None\r
+    childNodes = EmptyNodeList()\r
+    firstChild = None\r
+    lastChild = None\r
+\r
+    def _get_firstChild(self):\r
+        return None\r
+\r
+    def _get_lastChild(self):\r
+        return None\r
+\r
+    def appendChild(self, node):\r
+        raise xml.dom.HierarchyRequestErr(\r
+            self.nodeName + " nodes cannot have children")\r
+\r
+    def hasChildNodes(self):\r
+        return False\r
+\r
+    def insertBefore(self, newChild, refChild):\r
+        raise xml.dom.HierarchyRequestErr(\r
+            self.nodeName + " nodes do not have children")\r
+\r
+    def removeChild(self, oldChild):\r
+        raise xml.dom.NotFoundErr(\r
+            self.nodeName + " nodes do not have children")\r
+\r
+    def normalize(self):\r
+        # For childless nodes, normalize() has nothing to do.\r
+        pass\r
+\r
+    def replaceChild(self, newChild, oldChild):\r
+        raise xml.dom.HierarchyRequestErr(\r
+            self.nodeName + " nodes do not have children")\r
+\r
+\r
+class ProcessingInstruction(Childless, Node):\r
+    nodeType = Node.PROCESSING_INSTRUCTION_NODE\r
+\r
+    def __init__(self, target, data):\r
+        self.target = self.nodeName = target\r
+        self.data = self.nodeValue = data\r
+\r
+    def _get_data(self):\r
+        return self.data\r
+    def _set_data(self, value):\r
+        d = self.__dict__\r
+        d['data'] = d['nodeValue'] = value\r
+\r
+    def _get_target(self):\r
+        return self.target\r
+    def _set_target(self, value):\r
+        d = self.__dict__\r
+        d['target'] = d['nodeName'] = value\r
+\r
+    def __setattr__(self, name, value):\r
+        if name == "data" or name == "nodeValue":\r
+            self.__dict__['data'] = self.__dict__['nodeValue'] = value\r
+        elif name == "target" or name == "nodeName":\r
+            self.__dict__['target'] = self.__dict__['nodeName'] = value\r
+        else:\r
+            self.__dict__[name] = value\r
+\r
+    def writexml(self, writer, indent="", addindent="", newl=""):\r
+        writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))\r
+\r
+\r
+class CharacterData(Childless, Node):\r
+    def _get_length(self):\r
+        return len(self.data)\r
+    __len__ = _get_length\r
+\r
+    def _get_data(self):\r
+        return self.__dict__['data']\r
+    def _set_data(self, data):\r
+        d = self.__dict__\r
+        d['data'] = d['nodeValue'] = data\r
+\r
+    _get_nodeValue = _get_data\r
+    _set_nodeValue = _set_data\r
+\r
+    def __setattr__(self, name, value):\r
+        if name == "data" or name == "nodeValue":\r
+            self.__dict__['data'] = self.__dict__['nodeValue'] = value\r
+        else:\r
+            self.__dict__[name] = value\r
+\r
+    def __repr__(self):\r
+        data = self.data\r
+        if len(data) > 10:\r
+            dotdotdot = "..."\r
+        else:\r
+            dotdotdot = ""\r
+        return '<DOM %s node "%r%s">' % (\r
+            self.__class__.__name__, data[0:10], dotdotdot)\r
+\r
+    def substringData(self, offset, count):\r
+        if offset < 0:\r
+            raise xml.dom.IndexSizeErr("offset cannot be negative")\r
+        if offset >= len(self.data):\r
+            raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")\r
+        if count < 0:\r
+            raise xml.dom.IndexSizeErr("count cannot be negative")\r
+        return self.data[offset:offset+count]\r
+\r
+    def appendData(self, arg):\r
+        self.data = self.data + arg\r
+\r
+    def insertData(self, offset, arg):\r
+        if offset < 0:\r
+            raise xml.dom.IndexSizeErr("offset cannot be negative")\r
+        if offset >= len(self.data):\r
+            raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")\r
+        if arg:\r
+            self.data = "%s%s%s" % (\r
+                self.data[:offset], arg, self.data[offset:])\r
+\r
+    def deleteData(self, offset, count):\r
+        if offset < 0:\r
+            raise xml.dom.IndexSizeErr("offset cannot be negative")\r
+        if offset >= len(self.data):\r
+            raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")\r
+        if count < 0:\r
+            raise xml.dom.IndexSizeErr("count cannot be negative")\r
+        if count:\r
+            self.data = self.data[:offset] + self.data[offset+count:]\r
+\r
+    def replaceData(self, offset, count, arg):\r
+        if offset < 0:\r
+            raise xml.dom.IndexSizeErr("offset cannot be negative")\r
+        if offset >= len(self.data):\r
+            raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")\r
+        if count < 0:\r
+            raise xml.dom.IndexSizeErr("count cannot be negative")\r
+        if count:\r
+            self.data = "%s%s%s" % (\r
+                self.data[:offset], arg, self.data[offset+count:])\r
+\r
+defproperty(CharacterData, "length", doc="Length of the string data.")\r
+\r
+\r
+class Text(CharacterData):\r
+    # Make sure we don't add an instance __dict__ if we don't already\r
+    # have one, at least when that's possible:\r
+    # XXX this does not work, CharacterData is an old-style class\r
+    # __slots__ = ()\r
+\r
+    nodeType = Node.TEXT_NODE\r
+    nodeName = "#text"\r
+    attributes = None\r
+\r
+    def splitText(self, offset):\r
+        if offset < 0 or offset > len(self.data):\r
+            raise xml.dom.IndexSizeErr("illegal offset value")\r
+        newText = self.__class__()\r
+        newText.data = self.data[offset:]\r
+        newText.ownerDocument = self.ownerDocument\r
+        next = self.nextSibling\r
+        if self.parentNode and self in self.parentNode.childNodes:\r
+            if next is None:\r
+                self.parentNode.appendChild(newText)\r
+            else:\r
+                self.parentNode.insertBefore(newText, next)\r
+        self.data = self.data[:offset]\r
+        return newText\r
+\r
+    def writexml(self, writer, indent="", addindent="", newl=""):\r
+        _write_data(writer, "%s%s%s" % (indent, self.data, newl))\r
+\r
+    # DOM Level 3 (WD 9 April 2002)\r
+\r
+    def _get_wholeText(self):\r
+        L = [self.data]\r
+        n = self.previousSibling\r
+        while n is not None:\r
+            if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):\r
+                L.insert(0, n.data)\r
+                n = n.previousSibling\r
+            else:\r
+                break\r
+        n = self.nextSibling\r
+        while n is not None:\r
+            if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):\r
+                L.append(n.data)\r
+                n = n.nextSibling\r
+            else:\r
+                break\r
+        return ''.join(L)\r
+\r
+    def replaceWholeText(self, content):\r
+        # XXX This needs to be seriously changed if minidom ever\r
+        # supports EntityReference nodes.\r
+        parent = self.parentNode\r
+        n = self.previousSibling\r
+        while n is not None:\r
+            if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):\r
+                next = n.previousSibling\r
+                parent.removeChild(n)\r
+                n = next\r
+            else:\r
+                break\r
+        n = self.nextSibling\r
+        if not content:\r
+            parent.removeChild(self)\r
+        while n is not None:\r
+            if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):\r
+                next = n.nextSibling\r
+                parent.removeChild(n)\r
+                n = next\r
+            else:\r
+                break\r
+        if content:\r
+            d = self.__dict__\r
+            d['data'] = content\r
+            d['nodeValue'] = content\r
+            return self\r
+        else:\r
+            return None\r
+\r
+    def _get_isWhitespaceInElementContent(self):\r
+        if self.data.strip():\r
+            return False\r
+        elem = _get_containing_element(self)\r
+        if elem is None:\r
+            return False\r
+        info = self.ownerDocument._get_elem_info(elem)\r
+        if info is None:\r
+            return False\r
+        else:\r
+            return info.isElementContent()\r
+\r
+defproperty(Text, "isWhitespaceInElementContent",\r
+            doc="True iff this text node contains only whitespace"\r
+                " and is in element content.")\r
+defproperty(Text, "wholeText",\r
+            doc="The text of all logically-adjacent text nodes.")\r
+\r
+\r
+def _get_containing_element(node):\r
+    c = node.parentNode\r
+    while c is not None:\r
+        if c.nodeType == Node.ELEMENT_NODE:\r
+            return c\r
+        c = c.parentNode\r
+    return None\r
+\r
+def _get_containing_entref(node):\r
+    c = node.parentNode\r
+    while c is not None:\r
+        if c.nodeType == Node.ENTITY_REFERENCE_NODE:\r
+            return c\r
+        c = c.parentNode\r
+    return None\r
+\r
+\r
+class Comment(Childless, CharacterData):\r
+    nodeType = Node.COMMENT_NODE\r
+    nodeName = "#comment"\r
+\r
+    def __init__(self, data):\r
+        self.data = self.nodeValue = data\r
+\r
+    def writexml(self, writer, indent="", addindent="", newl=""):\r
+        if "--" in self.data:\r
+            raise ValueError("'--' is not allowed in a comment node")\r
+        writer.write("%s<!--%s-->%s" % (indent, self.data, newl))\r
+\r
+\r
+class CDATASection(Text):\r
+    # Make sure we don't add an instance __dict__ if we don't already\r
+    # have one, at least when that's possible:\r
+    # XXX this does not work, Text is an old-style class\r
+    # __slots__ = ()\r
+\r
+    nodeType = Node.CDATA_SECTION_NODE\r
+    nodeName = "#cdata-section"\r
+\r
+    def writexml(self, writer, indent="", addindent="", newl=""):\r
+        if self.data.find("]]>") >= 0:\r
+            raise ValueError("']]>' not allowed in a CDATA section")\r
+        writer.write("<![CDATA[%s]]>" % self.data)\r
+\r
+\r
+class ReadOnlySequentialNamedNodeMap(object):\r
+    __slots__ = '_seq',\r
+\r
+    def __init__(self, seq=()):\r
+        # seq should be a list or tuple\r
+        self._seq = seq\r
+\r
+    def __len__(self):\r
+        return len(self._seq)\r
+\r
+    def _get_length(self):\r
+        return len(self._seq)\r
+\r
+    def getNamedItem(self, name):\r
+        for n in self._seq:\r
+            if n.nodeName == name:\r
+                return n\r
+\r
+    def getNamedItemNS(self, namespaceURI, localName):\r
+        for n in self._seq:\r
+            if n.namespaceURI == namespaceURI and n.localName == localName:\r
+                return n\r
+\r
+    def __getitem__(self, name_or_tuple):\r
+        if isinstance(name_or_tuple, tuple):\r
+            node = self.getNamedItemNS(*name_or_tuple)\r
+        else:\r
+            node = self.getNamedItem(name_or_tuple)\r
+        if node is None:\r
+            raise KeyError, name_or_tuple\r
+        return node\r
+\r
+    def item(self, index):\r
+        if index < 0:\r
+            return None\r
+        try:\r
+            return self._seq[index]\r
+        except IndexError:\r
+            return None\r
+\r
+    def removeNamedItem(self, name):\r
+        raise xml.dom.NoModificationAllowedErr(\r
+            "NamedNodeMap instance is read-only")\r
+\r
+    def removeNamedItemNS(self, namespaceURI, localName):\r
+        raise xml.dom.NoModificationAllowedErr(\r
+            "NamedNodeMap instance is read-only")\r
+\r
+    def setNamedItem(self, node):\r
+        raise xml.dom.NoModificationAllowedErr(\r
+            "NamedNodeMap instance is read-only")\r
+\r
+    def setNamedItemNS(self, node):\r
+        raise xml.dom.NoModificationAllowedErr(\r
+            "NamedNodeMap instance is read-only")\r
+\r
+    def __getstate__(self):\r
+        return [self._seq]\r
+\r
+    def __setstate__(self, state):\r
+        self._seq = state[0]\r
+\r
+defproperty(ReadOnlySequentialNamedNodeMap, "length",\r
+            doc="Number of entries in the NamedNodeMap.")\r
+\r
+\r
+class Identified:\r
+    """Mix-in class that supports the publicId and systemId attributes."""\r
+\r
+    # XXX this does not work, this is an old-style class\r
+    # __slots__ = 'publicId', 'systemId'\r
+\r
+    def _identified_mixin_init(self, publicId, systemId):\r
+        self.publicId = publicId\r
+        self.systemId = systemId\r
+\r
+    def _get_publicId(self):\r
+        return self.publicId\r
+\r
+    def _get_systemId(self):\r
+        return self.systemId\r
+\r
+class DocumentType(Identified, Childless, Node):\r
+    nodeType = Node.DOCUMENT_TYPE_NODE\r
+    nodeValue = None\r
+    name = None\r
+    publicId = None\r
+    systemId = None\r
+    internalSubset = None\r
+\r
+    def __init__(self, qualifiedName):\r
+        self.entities = ReadOnlySequentialNamedNodeMap()\r
+        self.notations = ReadOnlySequentialNamedNodeMap()\r
+        if qualifiedName:\r
+            prefix, localname = _nssplit(qualifiedName)\r
+            self.name = localname\r
+        self.nodeName = self.name\r
+\r
+    def _get_internalSubset(self):\r
+        return self.internalSubset\r
+\r
+    def cloneNode(self, deep):\r
+        if self.ownerDocument is None:\r
+            # it's ok\r
+            clone = DocumentType(None)\r
+            clone.name = self.name\r
+            clone.nodeName = self.name\r
+            operation = xml.dom.UserDataHandler.NODE_CLONED\r
+            if deep:\r
+                clone.entities._seq = []\r
+                clone.notations._seq = []\r
+                for n in self.notations._seq:\r
+                    notation = Notation(n.nodeName, n.publicId, n.systemId)\r
+                    clone.notations._seq.append(notation)\r
+                    n._call_user_data_handler(operation, n, notation)\r
+                for e in self.entities._seq:\r
+                    entity = Entity(e.nodeName, e.publicId, e.systemId,\r
+                                    e.notationName)\r
+                    entity.actualEncoding = e.actualEncoding\r
+                    entity.encoding = e.encoding\r
+                    entity.version = e.version\r
+                    clone.entities._seq.append(entity)\r
+                    e._call_user_data_handler(operation, n, entity)\r
+            self._call_user_data_handler(operation, self, clone)\r
+            return clone\r
+        else:\r
+            return None\r
+\r
+    def writexml(self, writer, indent="", addindent="", newl=""):\r
+        writer.write("<!DOCTYPE ")\r
+        writer.write(self.name)\r
+        if self.publicId:\r
+            writer.write("%s  PUBLIC '%s'%s  '%s'"\r
+                         % (newl, self.publicId, newl, self.systemId))\r
+        elif self.systemId:\r
+            writer.write("%s  SYSTEM '%s'" % (newl, self.systemId))\r
+        if self.internalSubset is not None:\r
+            writer.write(" [")\r
+            writer.write(self.internalSubset)\r
+            writer.write("]")\r
+        writer.write(">"+newl)\r
+\r
+class Entity(Identified, Node):\r
+    attributes = None\r
+    nodeType = Node.ENTITY_NODE\r
+    nodeValue = None\r
+\r
+    actualEncoding = None\r
+    encoding = None\r
+    version = None\r
+\r
+    def __init__(self, name, publicId, systemId, notation):\r
+        self.nodeName = name\r
+        self.notationName = notation\r
+        self.childNodes = NodeList()\r
+        self._identified_mixin_init(publicId, systemId)\r
+\r
+    def _get_actualEncoding(self):\r
+        return self.actualEncoding\r
+\r
+    def _get_encoding(self):\r
+        return self.encoding\r
+\r
+    def _get_version(self):\r
+        return self.version\r
+\r
+    def appendChild(self, newChild):\r
+        raise xml.dom.HierarchyRequestErr(\r
+            "cannot append children to an entity node")\r
+\r
+    def insertBefore(self, newChild, refChild):\r
+        raise xml.dom.HierarchyRequestErr(\r
+            "cannot insert children below an entity node")\r
+\r
+    def removeChild(self, oldChild):\r
+        raise xml.dom.HierarchyRequestErr(\r
+            "cannot remove children from an entity node")\r
+\r
+    def replaceChild(self, newChild, oldChild):\r
+        raise xml.dom.HierarchyRequestErr(\r
+            "cannot replace children of an entity node")\r
+\r
+class Notation(Identified, Childless, Node):\r
+    nodeType = Node.NOTATION_NODE\r
+    nodeValue = None\r
+\r
+    def __init__(self, name, publicId, systemId):\r
+        self.nodeName = name\r
+        self._identified_mixin_init(publicId, systemId)\r
+\r
+\r
+class DOMImplementation(DOMImplementationLS):\r
+    _features = [("core", "1.0"),\r
+                 ("core", "2.0"),\r
+                 ("core", None),\r
+                 ("xml", "1.0"),\r
+                 ("xml", "2.0"),\r
+                 ("xml", None),\r
+                 ("ls-load", "3.0"),\r
+                 ("ls-load", None),\r
+                 ]\r
+\r
+    def hasFeature(self, feature, version):\r
+        if version == "":\r
+            version = None\r
+        return (feature.lower(), version) in self._features\r
+\r
+    def createDocument(self, namespaceURI, qualifiedName, doctype):\r
+        if doctype and doctype.parentNode is not None:\r
+            raise xml.dom.WrongDocumentErr(\r
+                "doctype object owned by another DOM tree")\r
+        doc = self._create_document()\r
+\r
+        add_root_element = not (namespaceURI is None\r
+                                and qualifiedName is None\r
+                                and doctype is None)\r
+\r
+        if not qualifiedName and add_root_element:\r
+            # The spec is unclear what to raise here; SyntaxErr\r
+            # would be the other obvious candidate. Since Xerces raises\r
+            # InvalidCharacterErr, and since SyntaxErr is not listed\r
+            # for createDocument, that seems to be the better choice.\r
+            # XXX: need to check for illegal characters here and in\r
+            # createElement.\r
+\r
+            # DOM Level III clears this up when talking about the return value\r
+            # of this function.  If namespaceURI, qName and DocType are\r
+            # Null the document is returned without a document element\r
+            # Otherwise if doctype or namespaceURI are not None\r
+            # Then we go back to the above problem\r
+            raise xml.dom.InvalidCharacterErr("Element with no name")\r
+\r
+        if add_root_element:\r
+            prefix, localname = _nssplit(qualifiedName)\r
+            if prefix == "xml" \\r
+               and namespaceURI != "http://www.w3.org/XML/1998/namespace":\r
+                raise xml.dom.NamespaceErr("illegal use of 'xml' prefix")\r
+            if prefix and not namespaceURI:\r
+                raise xml.dom.NamespaceErr(\r
+                    "illegal use of prefix without namespaces")\r
+            element = doc.createElementNS(namespaceURI, qualifiedName)\r
+            if doctype:\r
+                doc.appendChild(doctype)\r
+            doc.appendChild(element)\r
+\r
+        if doctype:\r
+            doctype.parentNode = doctype.ownerDocument = doc\r
+\r
+        doc.doctype = doctype\r
+        doc.implementation = self\r
+        return doc\r
+\r
+    def createDocumentType(self, qualifiedName, publicId, systemId):\r
+        doctype = DocumentType(qualifiedName)\r
+        doctype.publicId = publicId\r
+        doctype.systemId = systemId\r
+        return doctype\r
+\r
+    # DOM Level 3 (WD 9 April 2002)\r
+\r
+    def getInterface(self, feature):\r
+        if self.hasFeature(feature, None):\r
+            return self\r
+        else:\r
+            return None\r
+\r
+    # internal\r
+    def _create_document(self):\r
+        return Document()\r
+\r
+class ElementInfo(object):\r
+    """Object that represents content-model information for an element.\r
+\r
+    This implementation is not expected to be used in practice; DOM\r
+    builders should provide implementations which do the right thing\r
+    using information available to it.\r
+\r
+    """\r
+\r
+    __slots__ = 'tagName',\r
+\r
+    def __init__(self, name):\r
+        self.tagName = name\r
+\r
+    def getAttributeType(self, aname):\r
+        return _no_type\r
+\r
+    def getAttributeTypeNS(self, namespaceURI, localName):\r
+        return _no_type\r
+\r
+    def isElementContent(self):\r
+        return False\r
+\r
+    def isEmpty(self):\r
+        """Returns true iff this element is declared to have an EMPTY\r
+        content model."""\r
+        return False\r
+\r
+    def isId(self, aname):\r
+        """Returns true iff the named attribute is a DTD-style ID."""\r
+        return False\r
+\r
+    def isIdNS(self, namespaceURI, localName):\r
+        """Returns true iff the identified attribute is a DTD-style ID."""\r
+        return False\r
+\r
+    def __getstate__(self):\r
+        return self.tagName\r
+\r
+    def __setstate__(self, state):\r
+        self.tagName = state\r
+\r
+def _clear_id_cache(node):\r
+    if node.nodeType == Node.DOCUMENT_NODE:\r
+        node._id_cache.clear()\r
+        node._id_search_stack = None\r
+    elif _in_document(node):\r
+        node.ownerDocument._id_cache.clear()\r
+        node.ownerDocument._id_search_stack= None\r
+\r
+class Document(Node, DocumentLS):\r
+    _child_node_types = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,\r
+                         Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)\r
+\r
+    nodeType = Node.DOCUMENT_NODE\r
+    nodeName = "#document"\r
+    nodeValue = None\r
+    attributes = None\r
+    doctype = None\r
+    parentNode = None\r
+    previousSibling = nextSibling = None\r
+\r
+    implementation = DOMImplementation()\r
+\r
+    # Document attributes from Level 3 (WD 9 April 2002)\r
+\r
+    actualEncoding = None\r
+    encoding = None\r
+    standalone = None\r
+    version = None\r
+    strictErrorChecking = False\r
+    errorHandler = None\r
+    documentURI = None\r
+\r
+    _magic_id_count = 0\r
+\r
+    def __init__(self):\r
+        self.childNodes = NodeList()\r
+        # mapping of (namespaceURI, localName) -> ElementInfo\r
+        #        and tagName -> ElementInfo\r
+        self._elem_info = {}\r
+        self._id_cache = {}\r
+        self._id_search_stack = None\r
+\r
+    def _get_elem_info(self, element):\r
+        if element.namespaceURI:\r
+            key = element.namespaceURI, element.localName\r
+        else:\r
+            key = element.tagName\r
+        return self._elem_info.get(key)\r
+\r
+    def _get_actualEncoding(self):\r
+        return self.actualEncoding\r
+\r
+    def _get_doctype(self):\r
+        return self.doctype\r
+\r
+    def _get_documentURI(self):\r
+        return self.documentURI\r
+\r
+    def _get_encoding(self):\r
+        return self.encoding\r
+\r
+    def _get_errorHandler(self):\r
+        return self.errorHandler\r
+\r
+    def _get_standalone(self):\r
+        return self.standalone\r
+\r
+    def _get_strictErrorChecking(self):\r
+        return self.strictErrorChecking\r
+\r
+    def _get_version(self):\r
+        return self.version\r
+\r
+    def appendChild(self, node):\r
+        if node.nodeType not in self._child_node_types:\r
+            raise xml.dom.HierarchyRequestErr(\r
+                "%s cannot be child of %s" % (repr(node), repr(self)))\r
+        if node.parentNode is not None:\r
+            # This needs to be done before the next test since this\r
+            # may *be* the document element, in which case it should\r
+            # end up re-ordered to the end.\r
+            node.parentNode.removeChild(node)\r
+\r
+        if node.nodeType == Node.ELEMENT_NODE \\r
+           and self._get_documentElement():\r
+            raise xml.dom.HierarchyRequestErr(\r
+                "two document elements disallowed")\r
+        return Node.appendChild(self, node)\r
+\r
+    def removeChild(self, oldChild):\r
+        try:\r
+            self.childNodes.remove(oldChild)\r
+        except ValueError:\r
+            raise xml.dom.NotFoundErr()\r
+        oldChild.nextSibling = oldChild.previousSibling = None\r
+        oldChild.parentNode = None\r
+        if self.documentElement is oldChild:\r
+            self.documentElement = None\r
+\r
+        return oldChild\r
+\r
+    def _get_documentElement(self):\r
+        for node in self.childNodes:\r
+            if node.nodeType == Node.ELEMENT_NODE:\r
+                return node\r
+\r
+    def unlink(self):\r
+        if self.doctype is not None:\r
+            self.doctype.unlink()\r
+            self.doctype = None\r
+        Node.unlink(self)\r
+\r
+    def cloneNode(self, deep):\r
+        if not deep:\r
+            return None\r
+        clone = self.implementation.createDocument(None, None, None)\r
+        clone.encoding = self.encoding\r
+        clone.standalone = self.standalone\r
+        clone.version = self.version\r
+        for n in self.childNodes:\r
+            childclone = _clone_node(n, deep, clone)\r
+            assert childclone.ownerDocument.isSameNode(clone)\r
+            clone.childNodes.append(childclone)\r
+            if childclone.nodeType == Node.DOCUMENT_NODE:\r
+                assert clone.documentElement is None\r
+            elif childclone.nodeType == Node.DOCUMENT_TYPE_NODE:\r
+                assert clone.doctype is None\r
+                clone.doctype = childclone\r
+            childclone.parentNode = clone\r
+        self._call_user_data_handler(xml.dom.UserDataHandler.NODE_CLONED,\r
+                                     self, clone)\r
+        return clone\r
+\r
+    def createDocumentFragment(self):\r
+        d = DocumentFragment()\r
+        d.ownerDocument = self\r
+        return d\r
+\r
+    def createElement(self, tagName):\r
+        e = Element(tagName)\r
+        e.ownerDocument = self\r
+        return e\r
+\r
+    def createTextNode(self, data):\r
+        if not isinstance(data, StringTypes):\r
+            raise TypeError, "node contents must be a string"\r
+        t = Text()\r
+        t.data = data\r
+        t.ownerDocument = self\r
+        return t\r
+\r
+    def createCDATASection(self, data):\r
+        if not isinstance(data, StringTypes):\r
+            raise TypeError, "node contents must be a string"\r
+        c = CDATASection()\r
+        c.data = data\r
+        c.ownerDocument = self\r
+        return c\r
+\r
+    def createComment(self, data):\r
+        c = Comment(data)\r
+        c.ownerDocument = self\r
+        return c\r
+\r
+    def createProcessingInstruction(self, target, data):\r
+        p = ProcessingInstruction(target, data)\r
+        p.ownerDocument = self\r
+        return p\r
+\r
+    def createAttribute(self, qName):\r
+        a = Attr(qName)\r
+        a.ownerDocument = self\r
+        a.value = ""\r
+        return a\r
+\r
+    def createElementNS(self, namespaceURI, qualifiedName):\r
+        prefix, localName = _nssplit(qualifiedName)\r
+        e = Element(qualifiedName, namespaceURI, prefix)\r
+        e.ownerDocument = self\r
+        return e\r
+\r
+    def createAttributeNS(self, namespaceURI, qualifiedName):\r
+        prefix, localName = _nssplit(qualifiedName)\r
+        a = Attr(qualifiedName, namespaceURI, localName, prefix)\r
+        a.ownerDocument = self\r
+        a.value = ""\r
+        return a\r
+\r
+    # A couple of implementation-specific helpers to create node types\r
+    # not supported by the W3C DOM specs:\r
+\r
+    def _create_entity(self, name, publicId, systemId, notationName):\r
+        e = Entity(name, publicId, systemId, notationName)\r
+        e.ownerDocument = self\r
+        return e\r
+\r
+    def _create_notation(self, name, publicId, systemId):\r
+        n = Notation(name, publicId, systemId)\r
+        n.ownerDocument = self\r
+        return n\r
+\r
+    def getElementById(self, id):\r
+        if id in self._id_cache:\r
+            return self._id_cache[id]\r
+        if not (self._elem_info or self._magic_id_count):\r
+            return None\r
+\r
+        stack = self._id_search_stack\r
+        if stack is None:\r
+            # we never searched before, or the cache has been cleared\r
+            stack = [self.documentElement]\r
+            self._id_search_stack = stack\r
+        elif not stack:\r
+            # Previous search was completed and cache is still valid;\r
+            # no matching node.\r
+            return None\r
+\r
+        result = None\r
+        while stack:\r
+            node = stack.pop()\r
+            # add child elements to stack for continued searching\r
+            stack.extend([child for child in node.childNodes\r
+                          if child.nodeType in _nodeTypes_with_children])\r
+            # check this node\r
+            info = self._get_elem_info(node)\r
+            if info:\r
+                # We have to process all ID attributes before\r
+                # returning in order to get all the attributes set to\r
+                # be IDs using Element.setIdAttribute*().\r
+                for attr in node.attributes.values():\r
+                    if attr.namespaceURI:\r
+                        if info.isIdNS(attr.namespaceURI, attr.localName):\r
+                            self._id_cache[attr.value] = node\r
+                            if attr.value == id:\r
+                                result = node\r
+                            elif not node._magic_id_nodes:\r
+                                break\r
+                    elif info.isId(attr.name):\r
+                        self._id_cache[attr.value] = node\r
+                        if attr.value == id:\r
+                            result = node\r
+                        elif not node._magic_id_nodes:\r
+                            break\r
+                    elif attr._is_id:\r
+                        self._id_cache[attr.value] = node\r
+                        if attr.value == id:\r
+                            result = node\r
+                        elif node._magic_id_nodes == 1:\r
+                            break\r
+            elif node._magic_id_nodes:\r
+                for attr in node.attributes.values():\r
+                    if attr._is_id:\r
+                        self._id_cache[attr.value] = node\r
+                        if attr.value == id:\r
+                            result = node\r
+            if result is not None:\r
+                break\r
+        return result\r
+\r
+    def getElementsByTagName(self, name):\r
+        return _get_elements_by_tagName_helper(self, name, NodeList())\r
+\r
+    def getElementsByTagNameNS(self, namespaceURI, localName):\r
+        return _get_elements_by_tagName_ns_helper(\r
+            self, namespaceURI, localName, NodeList())\r
+\r
+    def isSupported(self, feature, version):\r
+        return self.implementation.hasFeature(feature, version)\r
+\r
+    def importNode(self, node, deep):\r
+        if node.nodeType == Node.DOCUMENT_NODE:\r
+            raise xml.dom.NotSupportedErr("cannot import document nodes")\r
+        elif node.nodeType == Node.DOCUMENT_TYPE_NODE:\r
+            raise xml.dom.NotSupportedErr("cannot import document type nodes")\r
+        return _clone_node(node, deep, self)\r
+\r
+    def writexml(self, writer, indent="", addindent="", newl="",\r
+                 encoding = None):\r
+        if encoding is None:\r
+            writer.write('<?xml version="1.0" ?>'+newl)\r
+        else:\r
+            writer.write('<?xml version="1.0" encoding="%s"?>%s' % (encoding, newl))\r
+        for node in self.childNodes:\r
+            node.writexml(writer, indent, addindent, newl)\r
+\r
+    # DOM Level 3 (WD 9 April 2002)\r
+\r
+    def renameNode(self, n, namespaceURI, name):\r
+        if n.ownerDocument is not self:\r
+            raise xml.dom.WrongDocumentErr(\r
+                "cannot rename nodes from other documents;\n"\r
+                "expected %s,\nfound %s" % (self, n.ownerDocument))\r
+        if n.nodeType not in (Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE):\r
+            raise xml.dom.NotSupportedErr(\r
+                "renameNode() only applies to element and attribute nodes")\r
+        if namespaceURI != EMPTY_NAMESPACE:\r
+            if ':' in name:\r
+                prefix, localName = name.split(':', 1)\r
+                if (  prefix == "xmlns"\r
+                      and namespaceURI != xml.dom.XMLNS_NAMESPACE):\r
+                    raise xml.dom.NamespaceErr(\r
+                        "illegal use of 'xmlns' prefix")\r
+            else:\r
+                if (  name == "xmlns"\r
+                      and namespaceURI != xml.dom.XMLNS_NAMESPACE\r
+                      and n.nodeType == Node.ATTRIBUTE_NODE):\r
+                    raise xml.dom.NamespaceErr(\r
+                        "illegal use of the 'xmlns' attribute")\r
+                prefix = None\r
+                localName = name\r
+        else:\r
+            prefix = None\r
+            localName = None\r
+        if n.nodeType == Node.ATTRIBUTE_NODE:\r
+            element = n.ownerElement\r
+            if element is not None:\r
+                is_id = n._is_id\r
+                element.removeAttributeNode(n)\r
+        else:\r
+            element = None\r
+        # avoid __setattr__\r
+        d = n.__dict__\r
+        d['prefix'] = prefix\r
+        d['localName'] = localName\r
+        d['namespaceURI'] = namespaceURI\r
+        d['nodeName'] = name\r
+        if n.nodeType == Node.ELEMENT_NODE:\r
+            d['tagName'] = name\r
+        else:\r
+            # attribute node\r
+            d['name'] = name\r
+            if element is not None:\r
+                element.setAttributeNode(n)\r
+                if is_id:\r
+                    element.setIdAttributeNode(n)\r
+        # It's not clear from a semantic perspective whether we should\r
+        # call the user data handlers for the NODE_RENAMED event since\r
+        # we're re-using the existing node.  The draft spec has been\r
+        # interpreted as meaning "no, don't call the handler unless a\r
+        # new node is created."\r
+        return n\r
+\r
+defproperty(Document, "documentElement",\r
+            doc="Top-level element of this document.")\r
+\r
+\r
+def _clone_node(node, deep, newOwnerDocument):\r
+    """\r
+    Clone a node and give it the new owner document.\r
+    Called by Node.cloneNode and Document.importNode\r
+    """\r
+    if node.ownerDocument.isSameNode(newOwnerDocument):\r
+        operation = xml.dom.UserDataHandler.NODE_CLONED\r
+    else:\r
+        operation = xml.dom.UserDataHandler.NODE_IMPORTED\r
+    if node.nodeType == Node.ELEMENT_NODE:\r
+        clone = newOwnerDocument.createElementNS(node.namespaceURI,\r
+                                                 node.nodeName)\r
+        for attr in node.attributes.values():\r
+            clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value)\r
+            a = clone.getAttributeNodeNS(attr.namespaceURI, attr.localName)\r
+            a.specified = attr.specified\r
+\r
+        if deep:\r
+            for child in node.childNodes:\r
+                c = _clone_node(child, deep, newOwnerDocument)\r
+                clone.appendChild(c)\r
+\r
+    elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE:\r
+        clone = newOwnerDocument.createDocumentFragment()\r
+        if deep:\r
+            for child in node.childNodes:\r
+                c = _clone_node(child, deep, newOwnerDocument)\r
+                clone.appendChild(c)\r
+\r
+    elif node.nodeType == Node.TEXT_NODE:\r
+        clone = newOwnerDocument.createTextNode(node.data)\r
+    elif node.nodeType == Node.CDATA_SECTION_NODE:\r
+        clone = newOwnerDocument.createCDATASection(node.data)\r
+    elif node.nodeType == Node.PROCESSING_INSTRUCTION_NODE:\r
+        clone = newOwnerDocument.createProcessingInstruction(node.target,\r
+                                                             node.data)\r
+    elif node.nodeType == Node.COMMENT_NODE:\r
+        clone = newOwnerDocument.createComment(node.data)\r
+    elif node.nodeType == Node.ATTRIBUTE_NODE:\r
+        clone = newOwnerDocument.createAttributeNS(node.namespaceURI,\r
+                                                   node.nodeName)\r
+        clone.specified = True\r
+        clone.value = node.value\r
+    elif node.nodeType == Node.DOCUMENT_TYPE_NODE:\r
+        assert node.ownerDocument is not newOwnerDocument\r
+        operation = xml.dom.UserDataHandler.NODE_IMPORTED\r
+        clone = newOwnerDocument.implementation.createDocumentType(\r
+            node.name, node.publicId, node.systemId)\r
+        clone.ownerDocument = newOwnerDocument\r
+        if deep:\r
+            clone.entities._seq = []\r
+            clone.notations._seq = []\r
+            for n in node.notations._seq:\r
+                notation = Notation(n.nodeName, n.publicId, n.systemId)\r
+                notation.ownerDocument = newOwnerDocument\r
+                clone.notations._seq.append(notation)\r
+                if hasattr(n, '_call_user_data_handler'):\r
+                    n._call_user_data_handler(operation, n, notation)\r
+            for e in node.entities._seq:\r
+                entity = Entity(e.nodeName, e.publicId, e.systemId,\r
+                                e.notationName)\r
+                entity.actualEncoding = e.actualEncoding\r
+                entity.encoding = e.encoding\r
+                entity.version = e.version\r
+                entity.ownerDocument = newOwnerDocument\r
+                clone.entities._seq.append(entity)\r
+                if hasattr(e, '_call_user_data_handler'):\r
+                    e._call_user_data_handler(operation, n, entity)\r
+    else:\r
+        # Note the cloning of Document and DocumentType nodes is\r
+        # implementation specific.  minidom handles those cases\r
+        # directly in the cloneNode() methods.\r
+        raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node))\r
+\r
+    # Check for _call_user_data_handler() since this could conceivably\r
+    # used with other DOM implementations (one of the FourThought\r
+    # DOMs, perhaps?).\r
+    if hasattr(node, '_call_user_data_handler'):\r
+        node._call_user_data_handler(operation, node, clone)\r
+    return clone\r
+\r
+\r
+def _nssplit(qualifiedName):\r
+    fields = qualifiedName.split(':', 1)\r
+    if len(fields) == 2:\r
+        return fields\r
+    else:\r
+        return (None, fields[0])\r
+\r
+\r
+def _get_StringIO():\r
+    # we can't use cStringIO since it doesn't support Unicode strings\r
+    from StringIO import StringIO\r
+    return StringIO()\r
+\r
+def _do_pulldom_parse(func, args, kwargs):\r
+    events = func(*args, **kwargs)\r
+    toktype, rootNode = events.getEvent()\r
+    events.expandNode(rootNode)\r
+    events.clear()\r
+    return rootNode\r
+\r
+def parse(file, parser=None, bufsize=None):\r
+    """Parse a file into a DOM by filename or file object."""\r
+    if parser is None and not bufsize:\r
+        from xml.dom import expatbuilder\r
+        return expatbuilder.parse(file)\r
+    else:\r
+        from xml.dom import pulldom\r
+        return _do_pulldom_parse(pulldom.parse, (file,),\r
+            {'parser': parser, 'bufsize': bufsize})\r
+\r
+def parseString(string, parser=None):\r
+    """Parse a file into a DOM from a string."""\r
+    if parser is None:\r
+        from xml.dom import expatbuilder\r
+        return expatbuilder.parseString(string)\r
+    else:\r
+        from xml.dom import pulldom\r
+        return _do_pulldom_parse(pulldom.parseString, (string,),\r
+                                 {'parser': parser})\r
+\r
+def getDOMImplementation(features=None):\r
+    if features:\r
+        if isinstance(features, StringTypes):\r
+            features = domreg._parse_feature_string(features)\r
+        for f, v in features:\r
+            if not Document.implementation.hasFeature(f, v):\r
+                return None\r
+    return Document.implementation\r