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