symbian-qemu-0.9.1-12/python-win32-2.6.1/lib/xml/dom/minidom.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """\
       
     2 minidom.py -- a lightweight DOM implementation.
       
     3 
       
     4 parse("foo.xml")
       
     5 
       
     6 parseString("<foo><bar/></foo>")
       
     7 
       
     8 Todo:
       
     9 =====
       
    10  * convenience methods for getting elements and text.
       
    11  * more testing
       
    12  * bring some of the writer and linearizer code into conformance with this
       
    13         interface
       
    14  * SAX 2 namespaces
       
    15 """
       
    16 
       
    17 import xml.dom
       
    18 
       
    19 from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE, domreg
       
    20 from xml.dom.minicompat import *
       
    21 from xml.dom.xmlbuilder import DOMImplementationLS, DocumentLS
       
    22 
       
    23 # This is used by the ID-cache invalidation checks; the list isn't
       
    24 # actually complete, since the nodes being checked will never be the
       
    25 # DOCUMENT_NODE or DOCUMENT_FRAGMENT_NODE.  (The node being checked is
       
    26 # the node being added or removed, not the node being modified.)
       
    27 #
       
    28 _nodeTypes_with_children = (xml.dom.Node.ELEMENT_NODE,
       
    29                             xml.dom.Node.ENTITY_REFERENCE_NODE)
       
    30 
       
    31 
       
    32 class Node(xml.dom.Node):
       
    33     namespaceURI = None # this is non-null only for elements and attributes
       
    34     parentNode = None
       
    35     ownerDocument = None
       
    36     nextSibling = None
       
    37     previousSibling = None
       
    38 
       
    39     prefix = EMPTY_PREFIX # non-null only for NS elements and attributes
       
    40 
       
    41     def __nonzero__(self):
       
    42         return True
       
    43 
       
    44     def toxml(self, encoding = None):
       
    45         return self.toprettyxml("", "", encoding)
       
    46 
       
    47     def toprettyxml(self, indent="\t", newl="\n", encoding = None):
       
    48         # indent = the indentation string to prepend, per level
       
    49         # newl = the newline string to append
       
    50         writer = _get_StringIO()
       
    51         if encoding is not None:
       
    52             import codecs
       
    53             # Can't use codecs.getwriter to preserve 2.0 compatibility
       
    54             writer = codecs.lookup(encoding)[3](writer)
       
    55         if self.nodeType == Node.DOCUMENT_NODE:
       
    56             # Can pass encoding only to document, to put it into XML header
       
    57             self.writexml(writer, "", indent, newl, encoding)
       
    58         else:
       
    59             self.writexml(writer, "", indent, newl)
       
    60         return writer.getvalue()
       
    61 
       
    62     def hasChildNodes(self):
       
    63         if self.childNodes:
       
    64             return True
       
    65         else:
       
    66             return False
       
    67 
       
    68     def _get_childNodes(self):
       
    69         return self.childNodes
       
    70 
       
    71     def _get_firstChild(self):
       
    72         if self.childNodes:
       
    73             return self.childNodes[0]
       
    74 
       
    75     def _get_lastChild(self):
       
    76         if self.childNodes:
       
    77             return self.childNodes[-1]
       
    78 
       
    79     def insertBefore(self, newChild, refChild):
       
    80         if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
       
    81             for c in tuple(newChild.childNodes):
       
    82                 self.insertBefore(c, refChild)
       
    83             ### The DOM does not clearly specify what to return in this case
       
    84             return newChild
       
    85         if newChild.nodeType not in self._child_node_types:
       
    86             raise xml.dom.HierarchyRequestErr(
       
    87                 "%s cannot be child of %s" % (repr(newChild), repr(self)))
       
    88         if newChild.parentNode is not None:
       
    89             newChild.parentNode.removeChild(newChild)
       
    90         if refChild is None:
       
    91             self.appendChild(newChild)
       
    92         else:
       
    93             try:
       
    94                 index = self.childNodes.index(refChild)
       
    95             except ValueError:
       
    96                 raise xml.dom.NotFoundErr()
       
    97             if newChild.nodeType in _nodeTypes_with_children:
       
    98                 _clear_id_cache(self)
       
    99             self.childNodes.insert(index, newChild)
       
   100             newChild.nextSibling = refChild
       
   101             refChild.previousSibling = newChild
       
   102             if index:
       
   103                 node = self.childNodes[index-1]
       
   104                 node.nextSibling = newChild
       
   105                 newChild.previousSibling = node
       
   106             else:
       
   107                 newChild.previousSibling = None
       
   108             newChild.parentNode = self
       
   109         return newChild
       
   110 
       
   111     def appendChild(self, node):
       
   112         if node.nodeType == self.DOCUMENT_FRAGMENT_NODE:
       
   113             for c in tuple(node.childNodes):
       
   114                 self.appendChild(c)
       
   115             ### The DOM does not clearly specify what to return in this case
       
   116             return node
       
   117         if node.nodeType not in self._child_node_types:
       
   118             raise xml.dom.HierarchyRequestErr(
       
   119                 "%s cannot be child of %s" % (repr(node), repr(self)))
       
   120         elif node.nodeType in _nodeTypes_with_children:
       
   121             _clear_id_cache(self)
       
   122         if node.parentNode is not None:
       
   123             node.parentNode.removeChild(node)
       
   124         _append_child(self, node)
       
   125         node.nextSibling = None
       
   126         return node
       
   127 
       
   128     def replaceChild(self, newChild, oldChild):
       
   129         if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
       
   130             refChild = oldChild.nextSibling
       
   131             self.removeChild(oldChild)
       
   132             return self.insertBefore(newChild, refChild)
       
   133         if newChild.nodeType not in self._child_node_types:
       
   134             raise xml.dom.HierarchyRequestErr(
       
   135                 "%s cannot be child of %s" % (repr(newChild), repr(self)))
       
   136         if newChild is oldChild:
       
   137             return
       
   138         if newChild.parentNode is not None:
       
   139             newChild.parentNode.removeChild(newChild)
       
   140         try:
       
   141             index = self.childNodes.index(oldChild)
       
   142         except ValueError:
       
   143             raise xml.dom.NotFoundErr()
       
   144         self.childNodes[index] = newChild
       
   145         newChild.parentNode = self
       
   146         oldChild.parentNode = None
       
   147         if (newChild.nodeType in _nodeTypes_with_children
       
   148             or oldChild.nodeType in _nodeTypes_with_children):
       
   149             _clear_id_cache(self)
       
   150         newChild.nextSibling = oldChild.nextSibling
       
   151         newChild.previousSibling = oldChild.previousSibling
       
   152         oldChild.nextSibling = None
       
   153         oldChild.previousSibling = None
       
   154         if newChild.previousSibling:
       
   155             newChild.previousSibling.nextSibling = newChild
       
   156         if newChild.nextSibling:
       
   157             newChild.nextSibling.previousSibling = newChild
       
   158         return oldChild
       
   159 
       
   160     def removeChild(self, oldChild):
       
   161         try:
       
   162             self.childNodes.remove(oldChild)
       
   163         except ValueError:
       
   164             raise xml.dom.NotFoundErr()
       
   165         if oldChild.nextSibling is not None:
       
   166             oldChild.nextSibling.previousSibling = oldChild.previousSibling
       
   167         if oldChild.previousSibling is not None:
       
   168             oldChild.previousSibling.nextSibling = oldChild.nextSibling
       
   169         oldChild.nextSibling = oldChild.previousSibling = None
       
   170         if oldChild.nodeType in _nodeTypes_with_children:
       
   171             _clear_id_cache(self)
       
   172 
       
   173         oldChild.parentNode = None
       
   174         return oldChild
       
   175 
       
   176     def normalize(self):
       
   177         L = []
       
   178         for child in self.childNodes:
       
   179             if child.nodeType == Node.TEXT_NODE:
       
   180                 data = child.data
       
   181                 if data and L and L[-1].nodeType == child.nodeType:
       
   182                     # collapse text node
       
   183                     node = L[-1]
       
   184                     node.data = node.data + child.data
       
   185                     node.nextSibling = child.nextSibling
       
   186                     child.unlink()
       
   187                 elif data:
       
   188                     if L:
       
   189                         L[-1].nextSibling = child
       
   190                         child.previousSibling = L[-1]
       
   191                     else:
       
   192                         child.previousSibling = None
       
   193                     L.append(child)
       
   194                 else:
       
   195                     # empty text node; discard
       
   196                     child.unlink()
       
   197             else:
       
   198                 if L:
       
   199                     L[-1].nextSibling = child
       
   200                     child.previousSibling = L[-1]
       
   201                 else:
       
   202                     child.previousSibling = None
       
   203                 L.append(child)
       
   204                 if child.nodeType == Node.ELEMENT_NODE:
       
   205                     child.normalize()
       
   206         if L:
       
   207             L[-1].nextSibling = None
       
   208         self.childNodes[:] = L
       
   209 
       
   210     def cloneNode(self, deep):
       
   211         return _clone_node(self, deep, self.ownerDocument or self)
       
   212 
       
   213     def isSupported(self, feature, version):
       
   214         return self.ownerDocument.implementation.hasFeature(feature, version)
       
   215 
       
   216     def _get_localName(self):
       
   217         # Overridden in Element and Attr where localName can be Non-Null
       
   218         return None
       
   219 
       
   220     # Node interfaces from Level 3 (WD 9 April 2002)
       
   221 
       
   222     def isSameNode(self, other):
       
   223         return self is other
       
   224 
       
   225     def getInterface(self, feature):
       
   226         if self.isSupported(feature, None):
       
   227             return self
       
   228         else:
       
   229             return None
       
   230 
       
   231     # The "user data" functions use a dictionary that is only present
       
   232     # if some user data has been set, so be careful not to assume it
       
   233     # exists.
       
   234 
       
   235     def getUserData(self, key):
       
   236         try:
       
   237             return self._user_data[key][0]
       
   238         except (AttributeError, KeyError):
       
   239             return None
       
   240 
       
   241     def setUserData(self, key, data, handler):
       
   242         old = None
       
   243         try:
       
   244             d = self._user_data
       
   245         except AttributeError:
       
   246             d = {}
       
   247             self._user_data = d
       
   248         if key in d:
       
   249             old = d[key][0]
       
   250         if data is None:
       
   251             # ignore handlers passed for None
       
   252             handler = None
       
   253             if old is not None:
       
   254                 del d[key]
       
   255         else:
       
   256             d[key] = (data, handler)
       
   257         return old
       
   258 
       
   259     def _call_user_data_handler(self, operation, src, dst):
       
   260         if hasattr(self, "_user_data"):
       
   261             for key, (data, handler) in self._user_data.items():
       
   262                 if handler is not None:
       
   263                     handler.handle(operation, key, data, src, dst)
       
   264 
       
   265     # minidom-specific API:
       
   266 
       
   267     def unlink(self):
       
   268         self.parentNode = self.ownerDocument = None
       
   269         if self.childNodes:
       
   270             for child in self.childNodes:
       
   271                 child.unlink()
       
   272             self.childNodes = NodeList()
       
   273         self.previousSibling = None
       
   274         self.nextSibling = None
       
   275 
       
   276 defproperty(Node, "firstChild", doc="First child node, or None.")
       
   277 defproperty(Node, "lastChild",  doc="Last child node, or None.")
       
   278 defproperty(Node, "localName",  doc="Namespace-local name of this node.")
       
   279 
       
   280 
       
   281 def _append_child(self, node):
       
   282     # fast path with less checks; usable by DOM builders if careful
       
   283     childNodes = self.childNodes
       
   284     if childNodes:
       
   285         last = childNodes[-1]
       
   286         node.__dict__["previousSibling"] = last
       
   287         last.__dict__["nextSibling"] = node
       
   288     childNodes.append(node)
       
   289     node.__dict__["parentNode"] = self
       
   290 
       
   291 def _in_document(node):
       
   292     # return True iff node is part of a document tree
       
   293     while node is not None:
       
   294         if node.nodeType == Node.DOCUMENT_NODE:
       
   295             return True
       
   296         node = node.parentNode
       
   297     return False
       
   298 
       
   299 def _write_data(writer, data):
       
   300     "Writes datachars to writer."
       
   301     data = data.replace("&", "&amp;").replace("<", "&lt;")
       
   302     data = data.replace("\"", "&quot;").replace(">", "&gt;")
       
   303     writer.write(data)
       
   304 
       
   305 def _get_elements_by_tagName_helper(parent, name, rc):
       
   306     for node in parent.childNodes:
       
   307         if node.nodeType == Node.ELEMENT_NODE and \
       
   308             (name == "*" or node.tagName == name):
       
   309             rc.append(node)
       
   310         _get_elements_by_tagName_helper(node, name, rc)
       
   311     return rc
       
   312 
       
   313 def _get_elements_by_tagName_ns_helper(parent, nsURI, localName, rc):
       
   314     for node in parent.childNodes:
       
   315         if node.nodeType == Node.ELEMENT_NODE:
       
   316             if ((localName == "*" or node.localName == localName) and
       
   317                 (nsURI == "*" or node.namespaceURI == nsURI)):
       
   318                 rc.append(node)
       
   319             _get_elements_by_tagName_ns_helper(node, nsURI, localName, rc)
       
   320     return rc
       
   321 
       
   322 class DocumentFragment(Node):
       
   323     nodeType = Node.DOCUMENT_FRAGMENT_NODE
       
   324     nodeName = "#document-fragment"
       
   325     nodeValue = None
       
   326     attributes = None
       
   327     parentNode = None
       
   328     _child_node_types = (Node.ELEMENT_NODE,
       
   329                          Node.TEXT_NODE,
       
   330                          Node.CDATA_SECTION_NODE,
       
   331                          Node.ENTITY_REFERENCE_NODE,
       
   332                          Node.PROCESSING_INSTRUCTION_NODE,
       
   333                          Node.COMMENT_NODE,
       
   334                          Node.NOTATION_NODE)
       
   335 
       
   336     def __init__(self):
       
   337         self.childNodes = NodeList()
       
   338 
       
   339 
       
   340 class Attr(Node):
       
   341     nodeType = Node.ATTRIBUTE_NODE
       
   342     attributes = None
       
   343     ownerElement = None
       
   344     specified = False
       
   345     _is_id = False
       
   346 
       
   347     _child_node_types = (Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE)
       
   348 
       
   349     def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None,
       
   350                  prefix=None):
       
   351         # skip setattr for performance
       
   352         d = self.__dict__
       
   353         d["nodeName"] = d["name"] = qName
       
   354         d["namespaceURI"] = namespaceURI
       
   355         d["prefix"] = prefix
       
   356         d['childNodes'] = NodeList()
       
   357 
       
   358         # Add the single child node that represents the value of the attr
       
   359         self.childNodes.append(Text())
       
   360 
       
   361         # nodeValue and value are set elsewhere
       
   362 
       
   363     def _get_localName(self):
       
   364         return self.nodeName.split(":", 1)[-1]
       
   365 
       
   366     def _get_name(self):
       
   367         return self.name
       
   368 
       
   369     def _get_specified(self):
       
   370         return self.specified
       
   371 
       
   372     def __setattr__(self, name, value):
       
   373         d = self.__dict__
       
   374         if name in ("value", "nodeValue"):
       
   375             d["value"] = d["nodeValue"] = value
       
   376             d2 = self.childNodes[0].__dict__
       
   377             d2["data"] = d2["nodeValue"] = value
       
   378             if self.ownerElement is not None:
       
   379                 _clear_id_cache(self.ownerElement)
       
   380         elif name in ("name", "nodeName"):
       
   381             d["name"] = d["nodeName"] = value
       
   382             if self.ownerElement is not None:
       
   383                 _clear_id_cache(self.ownerElement)
       
   384         else:
       
   385             d[name] = value
       
   386 
       
   387     def _set_prefix(self, prefix):
       
   388         nsuri = self.namespaceURI
       
   389         if prefix == "xmlns":
       
   390             if nsuri and nsuri != XMLNS_NAMESPACE:
       
   391                 raise xml.dom.NamespaceErr(
       
   392                     "illegal use of 'xmlns' prefix for the wrong namespace")
       
   393         d = self.__dict__
       
   394         d['prefix'] = prefix
       
   395         if prefix is None:
       
   396             newName = self.localName
       
   397         else:
       
   398             newName = "%s:%s" % (prefix, self.localName)
       
   399         if self.ownerElement:
       
   400             _clear_id_cache(self.ownerElement)
       
   401         d['nodeName'] = d['name'] = newName
       
   402 
       
   403     def _set_value(self, value):
       
   404         d = self.__dict__
       
   405         d['value'] = d['nodeValue'] = value
       
   406         if self.ownerElement:
       
   407             _clear_id_cache(self.ownerElement)
       
   408         self.childNodes[0].data = value
       
   409 
       
   410     def unlink(self):
       
   411         # This implementation does not call the base implementation
       
   412         # since most of that is not needed, and the expense of the
       
   413         # method call is not warranted.  We duplicate the removal of
       
   414         # children, but that's all we needed from the base class.
       
   415         elem = self.ownerElement
       
   416         if elem is not None:
       
   417             del elem._attrs[self.nodeName]
       
   418             del elem._attrsNS[(self.namespaceURI, self.localName)]
       
   419             if self._is_id:
       
   420                 self._is_id = False
       
   421                 elem._magic_id_nodes -= 1
       
   422                 self.ownerDocument._magic_id_count -= 1
       
   423         for child in self.childNodes:
       
   424             child.unlink()
       
   425         del self.childNodes[:]
       
   426 
       
   427     def _get_isId(self):
       
   428         if self._is_id:
       
   429             return True
       
   430         doc = self.ownerDocument
       
   431         elem = self.ownerElement
       
   432         if doc is None or elem is None:
       
   433             return False
       
   434 
       
   435         info = doc._get_elem_info(elem)
       
   436         if info is None:
       
   437             return False
       
   438         if self.namespaceURI:
       
   439             return info.isIdNS(self.namespaceURI, self.localName)
       
   440         else:
       
   441             return info.isId(self.nodeName)
       
   442 
       
   443     def _get_schemaType(self):
       
   444         doc = self.ownerDocument
       
   445         elem = self.ownerElement
       
   446         if doc is None or elem is None:
       
   447             return _no_type
       
   448 
       
   449         info = doc._get_elem_info(elem)
       
   450         if info is None:
       
   451             return _no_type
       
   452         if self.namespaceURI:
       
   453             return info.getAttributeTypeNS(self.namespaceURI, self.localName)
       
   454         else:
       
   455             return info.getAttributeType(self.nodeName)
       
   456 
       
   457 defproperty(Attr, "isId",       doc="True if this attribute is an ID.")
       
   458 defproperty(Attr, "localName",  doc="Namespace-local name of this attribute.")
       
   459 defproperty(Attr, "schemaType", doc="Schema type for this attribute.")
       
   460 
       
   461 
       
   462 class NamedNodeMap(object):
       
   463     """The attribute list is a transient interface to the underlying
       
   464     dictionaries.  Mutations here will change the underlying element's
       
   465     dictionary.
       
   466 
       
   467     Ordering is imposed artificially and does not reflect the order of
       
   468     attributes as found in an input document.
       
   469     """
       
   470 
       
   471     __slots__ = ('_attrs', '_attrsNS', '_ownerElement')
       
   472 
       
   473     def __init__(self, attrs, attrsNS, ownerElement):
       
   474         self._attrs = attrs
       
   475         self._attrsNS = attrsNS
       
   476         self._ownerElement = ownerElement
       
   477 
       
   478     def _get_length(self):
       
   479         return len(self._attrs)
       
   480 
       
   481     def item(self, index):
       
   482         try:
       
   483             return self[self._attrs.keys()[index]]
       
   484         except IndexError:
       
   485             return None
       
   486 
       
   487     def items(self):
       
   488         L = []
       
   489         for node in self._attrs.values():
       
   490             L.append((node.nodeName, node.value))
       
   491         return L
       
   492 
       
   493     def itemsNS(self):
       
   494         L = []
       
   495         for node in self._attrs.values():
       
   496             L.append(((node.namespaceURI, node.localName), node.value))
       
   497         return L
       
   498 
       
   499     def has_key(self, key):
       
   500         if isinstance(key, StringTypes):
       
   501             return self._attrs.has_key(key)
       
   502         else:
       
   503             return self._attrsNS.has_key(key)
       
   504 
       
   505     def keys(self):
       
   506         return self._attrs.keys()
       
   507 
       
   508     def keysNS(self):
       
   509         return self._attrsNS.keys()
       
   510 
       
   511     def values(self):
       
   512         return self._attrs.values()
       
   513 
       
   514     def get(self, name, value=None):
       
   515         return self._attrs.get(name, value)
       
   516 
       
   517     __len__ = _get_length
       
   518 
       
   519     __hash__ = None # Mutable type can't be correctly hashed
       
   520     def __cmp__(self, other):
       
   521         if self._attrs is getattr(other, "_attrs", None):
       
   522             return 0
       
   523         else:
       
   524             return cmp(id(self), id(other))
       
   525 
       
   526     def __getitem__(self, attname_or_tuple):
       
   527         if isinstance(attname_or_tuple, tuple):
       
   528             return self._attrsNS[attname_or_tuple]
       
   529         else:
       
   530             return self._attrs[attname_or_tuple]
       
   531 
       
   532     # same as set
       
   533     def __setitem__(self, attname, value):
       
   534         if isinstance(value, StringTypes):
       
   535             try:
       
   536                 node = self._attrs[attname]
       
   537             except KeyError:
       
   538                 node = Attr(attname)
       
   539                 node.ownerDocument = self._ownerElement.ownerDocument
       
   540                 self.setNamedItem(node)
       
   541             node.value = value
       
   542         else:
       
   543             if not isinstance(value, Attr):
       
   544                 raise TypeError, "value must be a string or Attr object"
       
   545             node = value
       
   546             self.setNamedItem(node)
       
   547 
       
   548     def getNamedItem(self, name):
       
   549         try:
       
   550             return self._attrs[name]
       
   551         except KeyError:
       
   552             return None
       
   553 
       
   554     def getNamedItemNS(self, namespaceURI, localName):
       
   555         try:
       
   556             return self._attrsNS[(namespaceURI, localName)]
       
   557         except KeyError:
       
   558             return None
       
   559 
       
   560     def removeNamedItem(self, name):
       
   561         n = self.getNamedItem(name)
       
   562         if n is not None:
       
   563             _clear_id_cache(self._ownerElement)
       
   564             del self._attrs[n.nodeName]
       
   565             del self._attrsNS[(n.namespaceURI, n.localName)]
       
   566             if 'ownerElement' in n.__dict__:
       
   567                 n.__dict__['ownerElement'] = None
       
   568             return n
       
   569         else:
       
   570             raise xml.dom.NotFoundErr()
       
   571 
       
   572     def removeNamedItemNS(self, namespaceURI, localName):
       
   573         n = self.getNamedItemNS(namespaceURI, localName)
       
   574         if n is not None:
       
   575             _clear_id_cache(self._ownerElement)
       
   576             del self._attrsNS[(n.namespaceURI, n.localName)]
       
   577             del self._attrs[n.nodeName]
       
   578             if 'ownerElement' in n.__dict__:
       
   579                 n.__dict__['ownerElement'] = None
       
   580             return n
       
   581         else:
       
   582             raise xml.dom.NotFoundErr()
       
   583 
       
   584     def setNamedItem(self, node):
       
   585         if not isinstance(node, Attr):
       
   586             raise xml.dom.HierarchyRequestErr(
       
   587                 "%s cannot be child of %s" % (repr(node), repr(self)))
       
   588         old = self._attrs.get(node.name)
       
   589         if old:
       
   590             old.unlink()
       
   591         self._attrs[node.name] = node
       
   592         self._attrsNS[(node.namespaceURI, node.localName)] = node
       
   593         node.ownerElement = self._ownerElement
       
   594         _clear_id_cache(node.ownerElement)
       
   595         return old
       
   596 
       
   597     def setNamedItemNS(self, node):
       
   598         return self.setNamedItem(node)
       
   599 
       
   600     def __delitem__(self, attname_or_tuple):
       
   601         node = self[attname_or_tuple]
       
   602         _clear_id_cache(node.ownerElement)
       
   603         node.unlink()
       
   604 
       
   605     def __getstate__(self):
       
   606         return self._attrs, self._attrsNS, self._ownerElement
       
   607 
       
   608     def __setstate__(self, state):
       
   609         self._attrs, self._attrsNS, self._ownerElement = state
       
   610 
       
   611 defproperty(NamedNodeMap, "length",
       
   612             doc="Number of nodes in the NamedNodeMap.")
       
   613 
       
   614 AttributeList = NamedNodeMap
       
   615 
       
   616 
       
   617 class TypeInfo(object):
       
   618     __slots__ = 'namespace', 'name'
       
   619 
       
   620     def __init__(self, namespace, name):
       
   621         self.namespace = namespace
       
   622         self.name = name
       
   623 
       
   624     def __repr__(self):
       
   625         if self.namespace:
       
   626             return "<TypeInfo %r (from %r)>" % (self.name, self.namespace)
       
   627         else:
       
   628             return "<TypeInfo %r>" % self.name
       
   629 
       
   630     def _get_name(self):
       
   631         return self.name
       
   632 
       
   633     def _get_namespace(self):
       
   634         return self.namespace
       
   635 
       
   636 _no_type = TypeInfo(None, None)
       
   637 
       
   638 class Element(Node):
       
   639     nodeType = Node.ELEMENT_NODE
       
   640     nodeValue = None
       
   641     schemaType = _no_type
       
   642 
       
   643     _magic_id_nodes = 0
       
   644 
       
   645     _child_node_types = (Node.ELEMENT_NODE,
       
   646                          Node.PROCESSING_INSTRUCTION_NODE,
       
   647                          Node.COMMENT_NODE,
       
   648                          Node.TEXT_NODE,
       
   649                          Node.CDATA_SECTION_NODE,
       
   650                          Node.ENTITY_REFERENCE_NODE)
       
   651 
       
   652     def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None,
       
   653                  localName=None):
       
   654         self.tagName = self.nodeName = tagName
       
   655         self.prefix = prefix
       
   656         self.namespaceURI = namespaceURI
       
   657         self.childNodes = NodeList()
       
   658 
       
   659         self._attrs = {}   # attributes are double-indexed:
       
   660         self._attrsNS = {} #    tagName -> Attribute
       
   661                            #    URI,localName -> Attribute
       
   662                            # in the future: consider lazy generation
       
   663                            # of attribute objects this is too tricky
       
   664                            # for now because of headaches with
       
   665                            # namespaces.
       
   666 
       
   667     def _get_localName(self):
       
   668         return self.tagName.split(":", 1)[-1]
       
   669 
       
   670     def _get_tagName(self):
       
   671         return self.tagName
       
   672 
       
   673     def unlink(self):
       
   674         for attr in self._attrs.values():
       
   675             attr.unlink()
       
   676         self._attrs = None
       
   677         self._attrsNS = None
       
   678         Node.unlink(self)
       
   679 
       
   680     def getAttribute(self, attname):
       
   681         try:
       
   682             return self._attrs[attname].value
       
   683         except KeyError:
       
   684             return ""
       
   685 
       
   686     def getAttributeNS(self, namespaceURI, localName):
       
   687         try:
       
   688             return self._attrsNS[(namespaceURI, localName)].value
       
   689         except KeyError:
       
   690             return ""
       
   691 
       
   692     def setAttribute(self, attname, value):
       
   693         attr = self.getAttributeNode(attname)
       
   694         if attr is None:
       
   695             attr = Attr(attname)
       
   696             # for performance
       
   697             d = attr.__dict__
       
   698             d["value"] = d["nodeValue"] = value
       
   699             d["ownerDocument"] = self.ownerDocument
       
   700             self.setAttributeNode(attr)
       
   701         elif value != attr.value:
       
   702             d = attr.__dict__
       
   703             d["value"] = d["nodeValue"] = value
       
   704             if attr.isId:
       
   705                 _clear_id_cache(self)
       
   706 
       
   707     def setAttributeNS(self, namespaceURI, qualifiedName, value):
       
   708         prefix, localname = _nssplit(qualifiedName)
       
   709         attr = self.getAttributeNodeNS(namespaceURI, localname)
       
   710         if attr is None:
       
   711             # for performance
       
   712             attr = Attr(qualifiedName, namespaceURI, localname, prefix)
       
   713             d = attr.__dict__
       
   714             d["prefix"] = prefix
       
   715             d["nodeName"] = qualifiedName
       
   716             d["value"] = d["nodeValue"] = value
       
   717             d["ownerDocument"] = self.ownerDocument
       
   718             self.setAttributeNode(attr)
       
   719         else:
       
   720             d = attr.__dict__
       
   721             if value != attr.value:
       
   722                 d["value"] = d["nodeValue"] = value
       
   723                 if attr.isId:
       
   724                     _clear_id_cache(self)
       
   725             if attr.prefix != prefix:
       
   726                 d["prefix"] = prefix
       
   727                 d["nodeName"] = qualifiedName
       
   728 
       
   729     def getAttributeNode(self, attrname):
       
   730         return self._attrs.get(attrname)
       
   731 
       
   732     def getAttributeNodeNS(self, namespaceURI, localName):
       
   733         return self._attrsNS.get((namespaceURI, localName))
       
   734 
       
   735     def setAttributeNode(self, attr):
       
   736         if attr.ownerElement not in (None, self):
       
   737             raise xml.dom.InuseAttributeErr("attribute node already owned")
       
   738         old1 = self._attrs.get(attr.name, None)
       
   739         if old1 is not None:
       
   740             self.removeAttributeNode(old1)
       
   741         old2 = self._attrsNS.get((attr.namespaceURI, attr.localName), None)
       
   742         if old2 is not None and old2 is not old1:
       
   743             self.removeAttributeNode(old2)
       
   744         _set_attribute_node(self, attr)
       
   745 
       
   746         if old1 is not attr:
       
   747             # It might have already been part of this node, in which case
       
   748             # it doesn't represent a change, and should not be returned.
       
   749             return old1
       
   750         if old2 is not attr:
       
   751             return old2
       
   752 
       
   753     setAttributeNodeNS = setAttributeNode
       
   754 
       
   755     def removeAttribute(self, name):
       
   756         try:
       
   757             attr = self._attrs[name]
       
   758         except KeyError:
       
   759             raise xml.dom.NotFoundErr()
       
   760         self.removeAttributeNode(attr)
       
   761 
       
   762     def removeAttributeNS(self, namespaceURI, localName):
       
   763         try:
       
   764             attr = self._attrsNS[(namespaceURI, localName)]
       
   765         except KeyError:
       
   766             raise xml.dom.NotFoundErr()
       
   767         self.removeAttributeNode(attr)
       
   768 
       
   769     def removeAttributeNode(self, node):
       
   770         if node is None:
       
   771             raise xml.dom.NotFoundErr()
       
   772         try:
       
   773             self._attrs[node.name]
       
   774         except KeyError:
       
   775             raise xml.dom.NotFoundErr()
       
   776         _clear_id_cache(self)
       
   777         node.unlink()
       
   778         # Restore this since the node is still useful and otherwise
       
   779         # unlinked
       
   780         node.ownerDocument = self.ownerDocument
       
   781 
       
   782     removeAttributeNodeNS = removeAttributeNode
       
   783 
       
   784     def hasAttribute(self, name):
       
   785         return self._attrs.has_key(name)
       
   786 
       
   787     def hasAttributeNS(self, namespaceURI, localName):
       
   788         return self._attrsNS.has_key((namespaceURI, localName))
       
   789 
       
   790     def getElementsByTagName(self, name):
       
   791         return _get_elements_by_tagName_helper(self, name, NodeList())
       
   792 
       
   793     def getElementsByTagNameNS(self, namespaceURI, localName):
       
   794         return _get_elements_by_tagName_ns_helper(
       
   795             self, namespaceURI, localName, NodeList())
       
   796 
       
   797     def __repr__(self):
       
   798         return "<DOM Element: %s at %#x>" % (self.tagName, id(self))
       
   799 
       
   800     def writexml(self, writer, indent="", addindent="", newl=""):
       
   801         # indent = current indentation
       
   802         # addindent = indentation to add to higher levels
       
   803         # newl = newline string
       
   804         writer.write(indent+"<" + self.tagName)
       
   805 
       
   806         attrs = self._get_attributes()
       
   807         a_names = attrs.keys()
       
   808         a_names.sort()
       
   809 
       
   810         for a_name in a_names:
       
   811             writer.write(" %s=\"" % a_name)
       
   812             _write_data(writer, attrs[a_name].value)
       
   813             writer.write("\"")
       
   814         if self.childNodes:
       
   815             writer.write(">%s"%(newl))
       
   816             for node in self.childNodes:
       
   817                 node.writexml(writer,indent+addindent,addindent,newl)
       
   818             writer.write("%s</%s>%s" % (indent,self.tagName,newl))
       
   819         else:
       
   820             writer.write("/>%s"%(newl))
       
   821 
       
   822     def _get_attributes(self):
       
   823         return NamedNodeMap(self._attrs, self._attrsNS, self)
       
   824 
       
   825     def hasAttributes(self):
       
   826         if self._attrs:
       
   827             return True
       
   828         else:
       
   829             return False
       
   830 
       
   831     # DOM Level 3 attributes, based on the 22 Oct 2002 draft
       
   832 
       
   833     def setIdAttribute(self, name):
       
   834         idAttr = self.getAttributeNode(name)
       
   835         self.setIdAttributeNode(idAttr)
       
   836 
       
   837     def setIdAttributeNS(self, namespaceURI, localName):
       
   838         idAttr = self.getAttributeNodeNS(namespaceURI, localName)
       
   839         self.setIdAttributeNode(idAttr)
       
   840 
       
   841     def setIdAttributeNode(self, idAttr):
       
   842         if idAttr is None or not self.isSameNode(idAttr.ownerElement):
       
   843             raise xml.dom.NotFoundErr()
       
   844         if _get_containing_entref(self) is not None:
       
   845             raise xml.dom.NoModificationAllowedErr()
       
   846         if not idAttr._is_id:
       
   847             idAttr.__dict__['_is_id'] = True
       
   848             self._magic_id_nodes += 1
       
   849             self.ownerDocument._magic_id_count += 1
       
   850             _clear_id_cache(self)
       
   851 
       
   852 defproperty(Element, "attributes",
       
   853             doc="NamedNodeMap of attributes on the element.")
       
   854 defproperty(Element, "localName",
       
   855             doc="Namespace-local name of this element.")
       
   856 
       
   857 
       
   858 def _set_attribute_node(element, attr):
       
   859     _clear_id_cache(element)
       
   860     element._attrs[attr.name] = attr
       
   861     element._attrsNS[(attr.namespaceURI, attr.localName)] = attr
       
   862 
       
   863     # This creates a circular reference, but Element.unlink()
       
   864     # breaks the cycle since the references to the attribute
       
   865     # dictionaries are tossed.
       
   866     attr.__dict__['ownerElement'] = element
       
   867 
       
   868 
       
   869 class Childless:
       
   870     """Mixin that makes childless-ness easy to implement and avoids
       
   871     the complexity of the Node methods that deal with children.
       
   872     """
       
   873 
       
   874     attributes = None
       
   875     childNodes = EmptyNodeList()
       
   876     firstChild = None
       
   877     lastChild = None
       
   878 
       
   879     def _get_firstChild(self):
       
   880         return None
       
   881 
       
   882     def _get_lastChild(self):
       
   883         return None
       
   884 
       
   885     def appendChild(self, node):
       
   886         raise xml.dom.HierarchyRequestErr(
       
   887             self.nodeName + " nodes cannot have children")
       
   888 
       
   889     def hasChildNodes(self):
       
   890         return False
       
   891 
       
   892     def insertBefore(self, newChild, refChild):
       
   893         raise xml.dom.HierarchyRequestErr(
       
   894             self.nodeName + " nodes do not have children")
       
   895 
       
   896     def removeChild(self, oldChild):
       
   897         raise xml.dom.NotFoundErr(
       
   898             self.nodeName + " nodes do not have children")
       
   899 
       
   900     def replaceChild(self, newChild, oldChild):
       
   901         raise xml.dom.HierarchyRequestErr(
       
   902             self.nodeName + " nodes do not have children")
       
   903 
       
   904 
       
   905 class ProcessingInstruction(Childless, Node):
       
   906     nodeType = Node.PROCESSING_INSTRUCTION_NODE
       
   907 
       
   908     def __init__(self, target, data):
       
   909         self.target = self.nodeName = target
       
   910         self.data = self.nodeValue = data
       
   911 
       
   912     def _get_data(self):
       
   913         return self.data
       
   914     def _set_data(self, value):
       
   915         d = self.__dict__
       
   916         d['data'] = d['nodeValue'] = value
       
   917 
       
   918     def _get_target(self):
       
   919         return self.target
       
   920     def _set_target(self, value):
       
   921         d = self.__dict__
       
   922         d['target'] = d['nodeName'] = value
       
   923 
       
   924     def __setattr__(self, name, value):
       
   925         if name == "data" or name == "nodeValue":
       
   926             self.__dict__['data'] = self.__dict__['nodeValue'] = value
       
   927         elif name == "target" or name == "nodeName":
       
   928             self.__dict__['target'] = self.__dict__['nodeName'] = value
       
   929         else:
       
   930             self.__dict__[name] = value
       
   931 
       
   932     def writexml(self, writer, indent="", addindent="", newl=""):
       
   933         writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))
       
   934 
       
   935 
       
   936 class CharacterData(Childless, Node):
       
   937     def _get_length(self):
       
   938         return len(self.data)
       
   939     __len__ = _get_length
       
   940 
       
   941     def _get_data(self):
       
   942         return self.__dict__['data']
       
   943     def _set_data(self, data):
       
   944         d = self.__dict__
       
   945         d['data'] = d['nodeValue'] = data
       
   946 
       
   947     _get_nodeValue = _get_data
       
   948     _set_nodeValue = _set_data
       
   949 
       
   950     def __setattr__(self, name, value):
       
   951         if name == "data" or name == "nodeValue":
       
   952             self.__dict__['data'] = self.__dict__['nodeValue'] = value
       
   953         else:
       
   954             self.__dict__[name] = value
       
   955 
       
   956     def __repr__(self):
       
   957         data = self.data
       
   958         if len(data) > 10:
       
   959             dotdotdot = "..."
       
   960         else:
       
   961             dotdotdot = ""
       
   962         return '<DOM %s node "%r%s">' % (
       
   963             self.__class__.__name__, data[0:10], dotdotdot)
       
   964 
       
   965     def substringData(self, offset, count):
       
   966         if offset < 0:
       
   967             raise xml.dom.IndexSizeErr("offset cannot be negative")
       
   968         if offset >= len(self.data):
       
   969             raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
       
   970         if count < 0:
       
   971             raise xml.dom.IndexSizeErr("count cannot be negative")
       
   972         return self.data[offset:offset+count]
       
   973 
       
   974     def appendData(self, arg):
       
   975         self.data = self.data + arg
       
   976 
       
   977     def insertData(self, offset, arg):
       
   978         if offset < 0:
       
   979             raise xml.dom.IndexSizeErr("offset cannot be negative")
       
   980         if offset >= len(self.data):
       
   981             raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
       
   982         if arg:
       
   983             self.data = "%s%s%s" % (
       
   984                 self.data[:offset], arg, self.data[offset:])
       
   985 
       
   986     def deleteData(self, offset, count):
       
   987         if offset < 0:
       
   988             raise xml.dom.IndexSizeErr("offset cannot be negative")
       
   989         if offset >= len(self.data):
       
   990             raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
       
   991         if count < 0:
       
   992             raise xml.dom.IndexSizeErr("count cannot be negative")
       
   993         if count:
       
   994             self.data = self.data[:offset] + self.data[offset+count:]
       
   995 
       
   996     def replaceData(self, offset, count, arg):
       
   997         if offset < 0:
       
   998             raise xml.dom.IndexSizeErr("offset cannot be negative")
       
   999         if offset >= len(self.data):
       
  1000             raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
       
  1001         if count < 0:
       
  1002             raise xml.dom.IndexSizeErr("count cannot be negative")
       
  1003         if count:
       
  1004             self.data = "%s%s%s" % (
       
  1005                 self.data[:offset], arg, self.data[offset+count:])
       
  1006 
       
  1007 defproperty(CharacterData, "length", doc="Length of the string data.")
       
  1008 
       
  1009 
       
  1010 class Text(CharacterData):
       
  1011     # Make sure we don't add an instance __dict__ if we don't already
       
  1012     # have one, at least when that's possible:
       
  1013     # XXX this does not work, CharacterData is an old-style class
       
  1014     # __slots__ = ()
       
  1015 
       
  1016     nodeType = Node.TEXT_NODE
       
  1017     nodeName = "#text"
       
  1018     attributes = None
       
  1019 
       
  1020     def splitText(self, offset):
       
  1021         if offset < 0 or offset > len(self.data):
       
  1022             raise xml.dom.IndexSizeErr("illegal offset value")
       
  1023         newText = self.__class__()
       
  1024         newText.data = self.data[offset:]
       
  1025         newText.ownerDocument = self.ownerDocument
       
  1026         next = self.nextSibling
       
  1027         if self.parentNode and self in self.parentNode.childNodes:
       
  1028             if next is None:
       
  1029                 self.parentNode.appendChild(newText)
       
  1030             else:
       
  1031                 self.parentNode.insertBefore(newText, next)
       
  1032         self.data = self.data[:offset]
       
  1033         return newText
       
  1034 
       
  1035     def writexml(self, writer, indent="", addindent="", newl=""):
       
  1036         _write_data(writer, "%s%s%s"%(indent, self.data, newl))
       
  1037 
       
  1038     # DOM Level 3 (WD 9 April 2002)
       
  1039 
       
  1040     def _get_wholeText(self):
       
  1041         L = [self.data]
       
  1042         n = self.previousSibling
       
  1043         while n is not None:
       
  1044             if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
       
  1045                 L.insert(0, n.data)
       
  1046                 n = n.previousSibling
       
  1047             else:
       
  1048                 break
       
  1049         n = self.nextSibling
       
  1050         while n is not None:
       
  1051             if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
       
  1052                 L.append(n.data)
       
  1053                 n = n.nextSibling
       
  1054             else:
       
  1055                 break
       
  1056         return ''.join(L)
       
  1057 
       
  1058     def replaceWholeText(self, content):
       
  1059         # XXX This needs to be seriously changed if minidom ever
       
  1060         # supports EntityReference nodes.
       
  1061         parent = self.parentNode
       
  1062         n = self.previousSibling
       
  1063         while n is not None:
       
  1064             if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
       
  1065                 next = n.previousSibling
       
  1066                 parent.removeChild(n)
       
  1067                 n = next
       
  1068             else:
       
  1069                 break
       
  1070         n = self.nextSibling
       
  1071         if not content:
       
  1072             parent.removeChild(self)
       
  1073         while n is not None:
       
  1074             if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
       
  1075                 next = n.nextSibling
       
  1076                 parent.removeChild(n)
       
  1077                 n = next
       
  1078             else:
       
  1079                 break
       
  1080         if content:
       
  1081             d = self.__dict__
       
  1082             d['data'] = content
       
  1083             d['nodeValue'] = content
       
  1084             return self
       
  1085         else:
       
  1086             return None
       
  1087 
       
  1088     def _get_isWhitespaceInElementContent(self):
       
  1089         if self.data.strip():
       
  1090             return False
       
  1091         elem = _get_containing_element(self)
       
  1092         if elem is None:
       
  1093             return False
       
  1094         info = self.ownerDocument._get_elem_info(elem)
       
  1095         if info is None:
       
  1096             return False
       
  1097         else:
       
  1098             return info.isElementContent()
       
  1099 
       
  1100 defproperty(Text, "isWhitespaceInElementContent",
       
  1101             doc="True iff this text node contains only whitespace"
       
  1102                 " and is in element content.")
       
  1103 defproperty(Text, "wholeText",
       
  1104             doc="The text of all logically-adjacent text nodes.")
       
  1105 
       
  1106 
       
  1107 def _get_containing_element(node):
       
  1108     c = node.parentNode
       
  1109     while c is not None:
       
  1110         if c.nodeType == Node.ELEMENT_NODE:
       
  1111             return c
       
  1112         c = c.parentNode
       
  1113     return None
       
  1114 
       
  1115 def _get_containing_entref(node):
       
  1116     c = node.parentNode
       
  1117     while c is not None:
       
  1118         if c.nodeType == Node.ENTITY_REFERENCE_NODE:
       
  1119             return c
       
  1120         c = c.parentNode
       
  1121     return None
       
  1122 
       
  1123 
       
  1124 class Comment(Childless, CharacterData):
       
  1125     nodeType = Node.COMMENT_NODE
       
  1126     nodeName = "#comment"
       
  1127 
       
  1128     def __init__(self, data):
       
  1129         self.data = self.nodeValue = data
       
  1130 
       
  1131     def writexml(self, writer, indent="", addindent="", newl=""):
       
  1132         if "--" in self.data:
       
  1133             raise ValueError("'--' is not allowed in a comment node")
       
  1134         writer.write("%s<!--%s-->%s" % (indent, self.data, newl))
       
  1135 
       
  1136 
       
  1137 class CDATASection(Text):
       
  1138     # Make sure we don't add an instance __dict__ if we don't already
       
  1139     # have one, at least when that's possible:
       
  1140     # XXX this does not work, Text is an old-style class
       
  1141     # __slots__ = ()
       
  1142 
       
  1143     nodeType = Node.CDATA_SECTION_NODE
       
  1144     nodeName = "#cdata-section"
       
  1145 
       
  1146     def writexml(self, writer, indent="", addindent="", newl=""):
       
  1147         if self.data.find("]]>") >= 0:
       
  1148             raise ValueError("']]>' not allowed in a CDATA section")
       
  1149         writer.write("<![CDATA[%s]]>" % self.data)
       
  1150 
       
  1151 
       
  1152 class ReadOnlySequentialNamedNodeMap(object):
       
  1153     __slots__ = '_seq',
       
  1154 
       
  1155     def __init__(self, seq=()):
       
  1156         # seq should be a list or tuple
       
  1157         self._seq = seq
       
  1158 
       
  1159     def __len__(self):
       
  1160         return len(self._seq)
       
  1161 
       
  1162     def _get_length(self):
       
  1163         return len(self._seq)
       
  1164 
       
  1165     def getNamedItem(self, name):
       
  1166         for n in self._seq:
       
  1167             if n.nodeName == name:
       
  1168                 return n
       
  1169 
       
  1170     def getNamedItemNS(self, namespaceURI, localName):
       
  1171         for n in self._seq:
       
  1172             if n.namespaceURI == namespaceURI and n.localName == localName:
       
  1173                 return n
       
  1174 
       
  1175     def __getitem__(self, name_or_tuple):
       
  1176         if isinstance(name_or_tuple, tuple):
       
  1177             node = self.getNamedItemNS(*name_or_tuple)
       
  1178         else:
       
  1179             node = self.getNamedItem(name_or_tuple)
       
  1180         if node is None:
       
  1181             raise KeyError, name_or_tuple
       
  1182         return node
       
  1183 
       
  1184     def item(self, index):
       
  1185         if index < 0:
       
  1186             return None
       
  1187         try:
       
  1188             return self._seq[index]
       
  1189         except IndexError:
       
  1190             return None
       
  1191 
       
  1192     def removeNamedItem(self, name):
       
  1193         raise xml.dom.NoModificationAllowedErr(
       
  1194             "NamedNodeMap instance is read-only")
       
  1195 
       
  1196     def removeNamedItemNS(self, namespaceURI, localName):
       
  1197         raise xml.dom.NoModificationAllowedErr(
       
  1198             "NamedNodeMap instance is read-only")
       
  1199 
       
  1200     def setNamedItem(self, node):
       
  1201         raise xml.dom.NoModificationAllowedErr(
       
  1202             "NamedNodeMap instance is read-only")
       
  1203 
       
  1204     def setNamedItemNS(self, node):
       
  1205         raise xml.dom.NoModificationAllowedErr(
       
  1206             "NamedNodeMap instance is read-only")
       
  1207 
       
  1208     def __getstate__(self):
       
  1209         return [self._seq]
       
  1210 
       
  1211     def __setstate__(self, state):
       
  1212         self._seq = state[0]
       
  1213 
       
  1214 defproperty(ReadOnlySequentialNamedNodeMap, "length",
       
  1215             doc="Number of entries in the NamedNodeMap.")
       
  1216 
       
  1217 
       
  1218 class Identified:
       
  1219     """Mix-in class that supports the publicId and systemId attributes."""
       
  1220 
       
  1221     # XXX this does not work, this is an old-style class
       
  1222     # __slots__ = 'publicId', 'systemId'
       
  1223 
       
  1224     def _identified_mixin_init(self, publicId, systemId):
       
  1225         self.publicId = publicId
       
  1226         self.systemId = systemId
       
  1227 
       
  1228     def _get_publicId(self):
       
  1229         return self.publicId
       
  1230 
       
  1231     def _get_systemId(self):
       
  1232         return self.systemId
       
  1233 
       
  1234 class DocumentType(Identified, Childless, Node):
       
  1235     nodeType = Node.DOCUMENT_TYPE_NODE
       
  1236     nodeValue = None
       
  1237     name = None
       
  1238     publicId = None
       
  1239     systemId = None
       
  1240     internalSubset = None
       
  1241 
       
  1242     def __init__(self, qualifiedName):
       
  1243         self.entities = ReadOnlySequentialNamedNodeMap()
       
  1244         self.notations = ReadOnlySequentialNamedNodeMap()
       
  1245         if qualifiedName:
       
  1246             prefix, localname = _nssplit(qualifiedName)
       
  1247             self.name = localname
       
  1248         self.nodeName = self.name
       
  1249 
       
  1250     def _get_internalSubset(self):
       
  1251         return self.internalSubset
       
  1252 
       
  1253     def cloneNode(self, deep):
       
  1254         if self.ownerDocument is None:
       
  1255             # it's ok
       
  1256             clone = DocumentType(None)
       
  1257             clone.name = self.name
       
  1258             clone.nodeName = self.name
       
  1259             operation = xml.dom.UserDataHandler.NODE_CLONED
       
  1260             if deep:
       
  1261                 clone.entities._seq = []
       
  1262                 clone.notations._seq = []
       
  1263                 for n in self.notations._seq:
       
  1264                     notation = Notation(n.nodeName, n.publicId, n.systemId)
       
  1265                     clone.notations._seq.append(notation)
       
  1266                     n._call_user_data_handler(operation, n, notation)
       
  1267                 for e in self.entities._seq:
       
  1268                     entity = Entity(e.nodeName, e.publicId, e.systemId,
       
  1269                                     e.notationName)
       
  1270                     entity.actualEncoding = e.actualEncoding
       
  1271                     entity.encoding = e.encoding
       
  1272                     entity.version = e.version
       
  1273                     clone.entities._seq.append(entity)
       
  1274                     e._call_user_data_handler(operation, n, entity)
       
  1275             self._call_user_data_handler(operation, self, clone)
       
  1276             return clone
       
  1277         else:
       
  1278             return None
       
  1279 
       
  1280     def writexml(self, writer, indent="", addindent="", newl=""):
       
  1281         writer.write("<!DOCTYPE ")
       
  1282         writer.write(self.name)
       
  1283         if self.publicId:
       
  1284             writer.write("%s  PUBLIC '%s'%s  '%s'"
       
  1285                          % (newl, self.publicId, newl, self.systemId))
       
  1286         elif self.systemId:
       
  1287             writer.write("%s  SYSTEM '%s'" % (newl, self.systemId))
       
  1288         if self.internalSubset is not None:
       
  1289             writer.write(" [")
       
  1290             writer.write(self.internalSubset)
       
  1291             writer.write("]")
       
  1292         writer.write(">"+newl)
       
  1293 
       
  1294 class Entity(Identified, Node):
       
  1295     attributes = None
       
  1296     nodeType = Node.ENTITY_NODE
       
  1297     nodeValue = None
       
  1298 
       
  1299     actualEncoding = None
       
  1300     encoding = None
       
  1301     version = None
       
  1302 
       
  1303     def __init__(self, name, publicId, systemId, notation):
       
  1304         self.nodeName = name
       
  1305         self.notationName = notation
       
  1306         self.childNodes = NodeList()
       
  1307         self._identified_mixin_init(publicId, systemId)
       
  1308 
       
  1309     def _get_actualEncoding(self):
       
  1310         return self.actualEncoding
       
  1311 
       
  1312     def _get_encoding(self):
       
  1313         return self.encoding
       
  1314 
       
  1315     def _get_version(self):
       
  1316         return self.version
       
  1317 
       
  1318     def appendChild(self, newChild):
       
  1319         raise xml.dom.HierarchyRequestErr(
       
  1320             "cannot append children to an entity node")
       
  1321 
       
  1322     def insertBefore(self, newChild, refChild):
       
  1323         raise xml.dom.HierarchyRequestErr(
       
  1324             "cannot insert children below an entity node")
       
  1325 
       
  1326     def removeChild(self, oldChild):
       
  1327         raise xml.dom.HierarchyRequestErr(
       
  1328             "cannot remove children from an entity node")
       
  1329 
       
  1330     def replaceChild(self, newChild, oldChild):
       
  1331         raise xml.dom.HierarchyRequestErr(
       
  1332             "cannot replace children of an entity node")
       
  1333 
       
  1334 class Notation(Identified, Childless, Node):
       
  1335     nodeType = Node.NOTATION_NODE
       
  1336     nodeValue = None
       
  1337 
       
  1338     def __init__(self, name, publicId, systemId):
       
  1339         self.nodeName = name
       
  1340         self._identified_mixin_init(publicId, systemId)
       
  1341 
       
  1342 
       
  1343 class DOMImplementation(DOMImplementationLS):
       
  1344     _features = [("core", "1.0"),
       
  1345                  ("core", "2.0"),
       
  1346                  ("core", "3.0"),
       
  1347                  ("core", None),
       
  1348                  ("xml", "1.0"),
       
  1349                  ("xml", "2.0"),
       
  1350                  ("xml", "3.0"),
       
  1351                  ("xml", None),
       
  1352                  ("ls-load", "3.0"),
       
  1353                  ("ls-load", None),
       
  1354                  ]
       
  1355 
       
  1356     def hasFeature(self, feature, version):
       
  1357         if version == "":
       
  1358             version = None
       
  1359         return (feature.lower(), version) in self._features
       
  1360 
       
  1361     def createDocument(self, namespaceURI, qualifiedName, doctype):
       
  1362         if doctype and doctype.parentNode is not None:
       
  1363             raise xml.dom.WrongDocumentErr(
       
  1364                 "doctype object owned by another DOM tree")
       
  1365         doc = self._create_document()
       
  1366 
       
  1367         add_root_element = not (namespaceURI is None
       
  1368                                 and qualifiedName is None
       
  1369                                 and doctype is None)
       
  1370 
       
  1371         if not qualifiedName and add_root_element:
       
  1372             # The spec is unclear what to raise here; SyntaxErr
       
  1373             # would be the other obvious candidate. Since Xerces raises
       
  1374             # InvalidCharacterErr, and since SyntaxErr is not listed
       
  1375             # for createDocument, that seems to be the better choice.
       
  1376             # XXX: need to check for illegal characters here and in
       
  1377             # createElement.
       
  1378 
       
  1379             # DOM Level III clears this up when talking about the return value
       
  1380             # of this function.  If namespaceURI, qName and DocType are
       
  1381             # Null the document is returned without a document element
       
  1382             # Otherwise if doctype or namespaceURI are not None
       
  1383             # Then we go back to the above problem
       
  1384             raise xml.dom.InvalidCharacterErr("Element with no name")
       
  1385 
       
  1386         if add_root_element:
       
  1387             prefix, localname = _nssplit(qualifiedName)
       
  1388             if prefix == "xml" \
       
  1389                and namespaceURI != "http://www.w3.org/XML/1998/namespace":
       
  1390                 raise xml.dom.NamespaceErr("illegal use of 'xml' prefix")
       
  1391             if prefix and not namespaceURI:
       
  1392                 raise xml.dom.NamespaceErr(
       
  1393                     "illegal use of prefix without namespaces")
       
  1394             element = doc.createElementNS(namespaceURI, qualifiedName)
       
  1395             if doctype:
       
  1396                 doc.appendChild(doctype)
       
  1397             doc.appendChild(element)
       
  1398 
       
  1399         if doctype:
       
  1400             doctype.parentNode = doctype.ownerDocument = doc
       
  1401 
       
  1402         doc.doctype = doctype
       
  1403         doc.implementation = self
       
  1404         return doc
       
  1405 
       
  1406     def createDocumentType(self, qualifiedName, publicId, systemId):
       
  1407         doctype = DocumentType(qualifiedName)
       
  1408         doctype.publicId = publicId
       
  1409         doctype.systemId = systemId
       
  1410         return doctype
       
  1411 
       
  1412     # DOM Level 3 (WD 9 April 2002)
       
  1413 
       
  1414     def getInterface(self, feature):
       
  1415         if self.hasFeature(feature, None):
       
  1416             return self
       
  1417         else:
       
  1418             return None
       
  1419 
       
  1420     # internal
       
  1421     def _create_document(self):
       
  1422         return Document()
       
  1423 
       
  1424 class ElementInfo(object):
       
  1425     """Object that represents content-model information for an element.
       
  1426 
       
  1427     This implementation is not expected to be used in practice; DOM
       
  1428     builders should provide implementations which do the right thing
       
  1429     using information available to it.
       
  1430 
       
  1431     """
       
  1432 
       
  1433     __slots__ = 'tagName',
       
  1434 
       
  1435     def __init__(self, name):
       
  1436         self.tagName = name
       
  1437 
       
  1438     def getAttributeType(self, aname):
       
  1439         return _no_type
       
  1440 
       
  1441     def getAttributeTypeNS(self, namespaceURI, localName):
       
  1442         return _no_type
       
  1443 
       
  1444     def isElementContent(self):
       
  1445         return False
       
  1446 
       
  1447     def isEmpty(self):
       
  1448         """Returns true iff this element is declared to have an EMPTY
       
  1449         content model."""
       
  1450         return False
       
  1451 
       
  1452     def isId(self, aname):
       
  1453         """Returns true iff the named attribte is a DTD-style ID."""
       
  1454         return False
       
  1455 
       
  1456     def isIdNS(self, namespaceURI, localName):
       
  1457         """Returns true iff the identified attribute is a DTD-style ID."""
       
  1458         return False
       
  1459 
       
  1460     def __getstate__(self):
       
  1461         return self.tagName
       
  1462 
       
  1463     def __setstate__(self, state):
       
  1464         self.tagName = state
       
  1465 
       
  1466 def _clear_id_cache(node):
       
  1467     if node.nodeType == Node.DOCUMENT_NODE:
       
  1468         node._id_cache.clear()
       
  1469         node._id_search_stack = None
       
  1470     elif _in_document(node):
       
  1471         node.ownerDocument._id_cache.clear()
       
  1472         node.ownerDocument._id_search_stack= None
       
  1473 
       
  1474 class Document(Node, DocumentLS):
       
  1475     _child_node_types = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
       
  1476                          Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)
       
  1477 
       
  1478     nodeType = Node.DOCUMENT_NODE
       
  1479     nodeName = "#document"
       
  1480     nodeValue = None
       
  1481     attributes = None
       
  1482     doctype = None
       
  1483     parentNode = None
       
  1484     previousSibling = nextSibling = None
       
  1485 
       
  1486     implementation = DOMImplementation()
       
  1487 
       
  1488     # Document attributes from Level 3 (WD 9 April 2002)
       
  1489 
       
  1490     actualEncoding = None
       
  1491     encoding = None
       
  1492     standalone = None
       
  1493     version = None
       
  1494     strictErrorChecking = False
       
  1495     errorHandler = None
       
  1496     documentURI = None
       
  1497 
       
  1498     _magic_id_count = 0
       
  1499 
       
  1500     def __init__(self):
       
  1501         self.childNodes = NodeList()
       
  1502         # mapping of (namespaceURI, localName) -> ElementInfo
       
  1503         #        and tagName -> ElementInfo
       
  1504         self._elem_info = {}
       
  1505         self._id_cache = {}
       
  1506         self._id_search_stack = None
       
  1507 
       
  1508     def _get_elem_info(self, element):
       
  1509         if element.namespaceURI:
       
  1510             key = element.namespaceURI, element.localName
       
  1511         else:
       
  1512             key = element.tagName
       
  1513         return self._elem_info.get(key)
       
  1514 
       
  1515     def _get_actualEncoding(self):
       
  1516         return self.actualEncoding
       
  1517 
       
  1518     def _get_doctype(self):
       
  1519         return self.doctype
       
  1520 
       
  1521     def _get_documentURI(self):
       
  1522         return self.documentURI
       
  1523 
       
  1524     def _get_encoding(self):
       
  1525         return self.encoding
       
  1526 
       
  1527     def _get_errorHandler(self):
       
  1528         return self.errorHandler
       
  1529 
       
  1530     def _get_standalone(self):
       
  1531         return self.standalone
       
  1532 
       
  1533     def _get_strictErrorChecking(self):
       
  1534         return self.strictErrorChecking
       
  1535 
       
  1536     def _get_version(self):
       
  1537         return self.version
       
  1538 
       
  1539     def appendChild(self, node):
       
  1540         if node.nodeType not in self._child_node_types:
       
  1541             raise xml.dom.HierarchyRequestErr(
       
  1542                 "%s cannot be child of %s" % (repr(node), repr(self)))
       
  1543         if node.parentNode is not None:
       
  1544             # This needs to be done before the next test since this
       
  1545             # may *be* the document element, in which case it should
       
  1546             # end up re-ordered to the end.
       
  1547             node.parentNode.removeChild(node)
       
  1548 
       
  1549         if node.nodeType == Node.ELEMENT_NODE \
       
  1550            and self._get_documentElement():
       
  1551             raise xml.dom.HierarchyRequestErr(
       
  1552                 "two document elements disallowed")
       
  1553         return Node.appendChild(self, node)
       
  1554 
       
  1555     def removeChild(self, oldChild):
       
  1556         try:
       
  1557             self.childNodes.remove(oldChild)
       
  1558         except ValueError:
       
  1559             raise xml.dom.NotFoundErr()
       
  1560         oldChild.nextSibling = oldChild.previousSibling = None
       
  1561         oldChild.parentNode = None
       
  1562         if self.documentElement is oldChild:
       
  1563             self.documentElement = None
       
  1564 
       
  1565         return oldChild
       
  1566 
       
  1567     def _get_documentElement(self):
       
  1568         for node in self.childNodes:
       
  1569             if node.nodeType == Node.ELEMENT_NODE:
       
  1570                 return node
       
  1571 
       
  1572     def unlink(self):
       
  1573         if self.doctype is not None:
       
  1574             self.doctype.unlink()
       
  1575             self.doctype = None
       
  1576         Node.unlink(self)
       
  1577 
       
  1578     def cloneNode(self, deep):
       
  1579         if not deep:
       
  1580             return None
       
  1581         clone = self.implementation.createDocument(None, None, None)
       
  1582         clone.encoding = self.encoding
       
  1583         clone.standalone = self.standalone
       
  1584         clone.version = self.version
       
  1585         for n in self.childNodes:
       
  1586             childclone = _clone_node(n, deep, clone)
       
  1587             assert childclone.ownerDocument.isSameNode(clone)
       
  1588             clone.childNodes.append(childclone)
       
  1589             if childclone.nodeType == Node.DOCUMENT_NODE:
       
  1590                 assert clone.documentElement is None
       
  1591             elif childclone.nodeType == Node.DOCUMENT_TYPE_NODE:
       
  1592                 assert clone.doctype is None
       
  1593                 clone.doctype = childclone
       
  1594             childclone.parentNode = clone
       
  1595         self._call_user_data_handler(xml.dom.UserDataHandler.NODE_CLONED,
       
  1596                                      self, clone)
       
  1597         return clone
       
  1598 
       
  1599     def createDocumentFragment(self):
       
  1600         d = DocumentFragment()
       
  1601         d.ownerDocument = self
       
  1602         return d
       
  1603 
       
  1604     def createElement(self, tagName):
       
  1605         e = Element(tagName)
       
  1606         e.ownerDocument = self
       
  1607         return e
       
  1608 
       
  1609     def createTextNode(self, data):
       
  1610         if not isinstance(data, StringTypes):
       
  1611             raise TypeError, "node contents must be a string"
       
  1612         t = Text()
       
  1613         t.data = data
       
  1614         t.ownerDocument = self
       
  1615         return t
       
  1616 
       
  1617     def createCDATASection(self, data):
       
  1618         if not isinstance(data, StringTypes):
       
  1619             raise TypeError, "node contents must be a string"
       
  1620         c = CDATASection()
       
  1621         c.data = data
       
  1622         c.ownerDocument = self
       
  1623         return c
       
  1624 
       
  1625     def createComment(self, data):
       
  1626         c = Comment(data)
       
  1627         c.ownerDocument = self
       
  1628         return c
       
  1629 
       
  1630     def createProcessingInstruction(self, target, data):
       
  1631         p = ProcessingInstruction(target, data)
       
  1632         p.ownerDocument = self
       
  1633         return p
       
  1634 
       
  1635     def createAttribute(self, qName):
       
  1636         a = Attr(qName)
       
  1637         a.ownerDocument = self
       
  1638         a.value = ""
       
  1639         return a
       
  1640 
       
  1641     def createElementNS(self, namespaceURI, qualifiedName):
       
  1642         prefix, localName = _nssplit(qualifiedName)
       
  1643         e = Element(qualifiedName, namespaceURI, prefix)
       
  1644         e.ownerDocument = self
       
  1645         return e
       
  1646 
       
  1647     def createAttributeNS(self, namespaceURI, qualifiedName):
       
  1648         prefix, localName = _nssplit(qualifiedName)
       
  1649         a = Attr(qualifiedName, namespaceURI, localName, prefix)
       
  1650         a.ownerDocument = self
       
  1651         a.value = ""
       
  1652         return a
       
  1653 
       
  1654     # A couple of implementation-specific helpers to create node types
       
  1655     # not supported by the W3C DOM specs:
       
  1656 
       
  1657     def _create_entity(self, name, publicId, systemId, notationName):
       
  1658         e = Entity(name, publicId, systemId, notationName)
       
  1659         e.ownerDocument = self
       
  1660         return e
       
  1661 
       
  1662     def _create_notation(self, name, publicId, systemId):
       
  1663         n = Notation(name, publicId, systemId)
       
  1664         n.ownerDocument = self
       
  1665         return n
       
  1666 
       
  1667     def getElementById(self, id):
       
  1668         if id in self._id_cache:
       
  1669             return self._id_cache[id]
       
  1670         if not (self._elem_info or self._magic_id_count):
       
  1671             return None
       
  1672 
       
  1673         stack = self._id_search_stack
       
  1674         if stack is None:
       
  1675             # we never searched before, or the cache has been cleared
       
  1676             stack = [self.documentElement]
       
  1677             self._id_search_stack = stack
       
  1678         elif not stack:
       
  1679             # Previous search was completed and cache is still valid;
       
  1680             # no matching node.
       
  1681             return None
       
  1682 
       
  1683         result = None
       
  1684         while stack:
       
  1685             node = stack.pop()
       
  1686             # add child elements to stack for continued searching
       
  1687             stack.extend([child for child in node.childNodes
       
  1688                           if child.nodeType in _nodeTypes_with_children])
       
  1689             # check this node
       
  1690             info = self._get_elem_info(node)
       
  1691             if info:
       
  1692                 # We have to process all ID attributes before
       
  1693                 # returning in order to get all the attributes set to
       
  1694                 # be IDs using Element.setIdAttribute*().
       
  1695                 for attr in node.attributes.values():
       
  1696                     if attr.namespaceURI:
       
  1697                         if info.isIdNS(attr.namespaceURI, attr.localName):
       
  1698                             self._id_cache[attr.value] = node
       
  1699                             if attr.value == id:
       
  1700                                 result = node
       
  1701                             elif not node._magic_id_nodes:
       
  1702                                 break
       
  1703                     elif info.isId(attr.name):
       
  1704                         self._id_cache[attr.value] = node
       
  1705                         if attr.value == id:
       
  1706                             result = node
       
  1707                         elif not node._magic_id_nodes:
       
  1708                             break
       
  1709                     elif attr._is_id:
       
  1710                         self._id_cache[attr.value] = node
       
  1711                         if attr.value == id:
       
  1712                             result = node
       
  1713                         elif node._magic_id_nodes == 1:
       
  1714                             break
       
  1715             elif node._magic_id_nodes:
       
  1716                 for attr in node.attributes.values():
       
  1717                     if attr._is_id:
       
  1718                         self._id_cache[attr.value] = node
       
  1719                         if attr.value == id:
       
  1720                             result = node
       
  1721             if result is not None:
       
  1722                 break
       
  1723         return result
       
  1724 
       
  1725     def getElementsByTagName(self, name):
       
  1726         return _get_elements_by_tagName_helper(self, name, NodeList())
       
  1727 
       
  1728     def getElementsByTagNameNS(self, namespaceURI, localName):
       
  1729         return _get_elements_by_tagName_ns_helper(
       
  1730             self, namespaceURI, localName, NodeList())
       
  1731 
       
  1732     def isSupported(self, feature, version):
       
  1733         return self.implementation.hasFeature(feature, version)
       
  1734 
       
  1735     def importNode(self, node, deep):
       
  1736         if node.nodeType == Node.DOCUMENT_NODE:
       
  1737             raise xml.dom.NotSupportedErr("cannot import document nodes")
       
  1738         elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
       
  1739             raise xml.dom.NotSupportedErr("cannot import document type nodes")
       
  1740         return _clone_node(node, deep, self)
       
  1741 
       
  1742     def writexml(self, writer, indent="", addindent="", newl="",
       
  1743                  encoding = None):
       
  1744         if encoding is None:
       
  1745             writer.write('<?xml version="1.0" ?>'+newl)
       
  1746         else:
       
  1747             writer.write('<?xml version="1.0" encoding="%s"?>%s' % (encoding, newl))
       
  1748         for node in self.childNodes:
       
  1749             node.writexml(writer, indent, addindent, newl)
       
  1750 
       
  1751     # DOM Level 3 (WD 9 April 2002)
       
  1752 
       
  1753     def renameNode(self, n, namespaceURI, name):
       
  1754         if n.ownerDocument is not self:
       
  1755             raise xml.dom.WrongDocumentErr(
       
  1756                 "cannot rename nodes from other documents;\n"
       
  1757                 "expected %s,\nfound %s" % (self, n.ownerDocument))
       
  1758         if n.nodeType not in (Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE):
       
  1759             raise xml.dom.NotSupportedErr(
       
  1760                 "renameNode() only applies to element and attribute nodes")
       
  1761         if namespaceURI != EMPTY_NAMESPACE:
       
  1762             if ':' in name:
       
  1763                 prefix, localName = name.split(':', 1)
       
  1764                 if (  prefix == "xmlns"
       
  1765                       and namespaceURI != xml.dom.XMLNS_NAMESPACE):
       
  1766                     raise xml.dom.NamespaceErr(
       
  1767                         "illegal use of 'xmlns' prefix")
       
  1768             else:
       
  1769                 if (  name == "xmlns"
       
  1770                       and namespaceURI != xml.dom.XMLNS_NAMESPACE
       
  1771                       and n.nodeType == Node.ATTRIBUTE_NODE):
       
  1772                     raise xml.dom.NamespaceErr(
       
  1773                         "illegal use of the 'xmlns' attribute")
       
  1774                 prefix = None
       
  1775                 localName = name
       
  1776         else:
       
  1777             prefix = None
       
  1778             localName = None
       
  1779         if n.nodeType == Node.ATTRIBUTE_NODE:
       
  1780             element = n.ownerElement
       
  1781             if element is not None:
       
  1782                 is_id = n._is_id
       
  1783                 element.removeAttributeNode(n)
       
  1784         else:
       
  1785             element = None
       
  1786         # avoid __setattr__
       
  1787         d = n.__dict__
       
  1788         d['prefix'] = prefix
       
  1789         d['localName'] = localName
       
  1790         d['namespaceURI'] = namespaceURI
       
  1791         d['nodeName'] = name
       
  1792         if n.nodeType == Node.ELEMENT_NODE:
       
  1793             d['tagName'] = name
       
  1794         else:
       
  1795             # attribute node
       
  1796             d['name'] = name
       
  1797             if element is not None:
       
  1798                 element.setAttributeNode(n)
       
  1799                 if is_id:
       
  1800                     element.setIdAttributeNode(n)
       
  1801         # It's not clear from a semantic perspective whether we should
       
  1802         # call the user data handlers for the NODE_RENAMED event since
       
  1803         # we're re-using the existing node.  The draft spec has been
       
  1804         # interpreted as meaning "no, don't call the handler unless a
       
  1805         # new node is created."
       
  1806         return n
       
  1807 
       
  1808 defproperty(Document, "documentElement",
       
  1809             doc="Top-level element of this document.")
       
  1810 
       
  1811 
       
  1812 def _clone_node(node, deep, newOwnerDocument):
       
  1813     """
       
  1814     Clone a node and give it the new owner document.
       
  1815     Called by Node.cloneNode and Document.importNode
       
  1816     """
       
  1817     if node.ownerDocument.isSameNode(newOwnerDocument):
       
  1818         operation = xml.dom.UserDataHandler.NODE_CLONED
       
  1819     else:
       
  1820         operation = xml.dom.UserDataHandler.NODE_IMPORTED
       
  1821     if node.nodeType == Node.ELEMENT_NODE:
       
  1822         clone = newOwnerDocument.createElementNS(node.namespaceURI,
       
  1823                                                  node.nodeName)
       
  1824         for attr in node.attributes.values():
       
  1825             clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value)
       
  1826             a = clone.getAttributeNodeNS(attr.namespaceURI, attr.localName)
       
  1827             a.specified = attr.specified
       
  1828 
       
  1829         if deep:
       
  1830             for child in node.childNodes:
       
  1831                 c = _clone_node(child, deep, newOwnerDocument)
       
  1832                 clone.appendChild(c)
       
  1833 
       
  1834     elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
       
  1835         clone = newOwnerDocument.createDocumentFragment()
       
  1836         if deep:
       
  1837             for child in node.childNodes:
       
  1838                 c = _clone_node(child, deep, newOwnerDocument)
       
  1839                 clone.appendChild(c)
       
  1840 
       
  1841     elif node.nodeType == Node.TEXT_NODE:
       
  1842         clone = newOwnerDocument.createTextNode(node.data)
       
  1843     elif node.nodeType == Node.CDATA_SECTION_NODE:
       
  1844         clone = newOwnerDocument.createCDATASection(node.data)
       
  1845     elif node.nodeType == Node.PROCESSING_INSTRUCTION_NODE:
       
  1846         clone = newOwnerDocument.createProcessingInstruction(node.target,
       
  1847                                                              node.data)
       
  1848     elif node.nodeType == Node.COMMENT_NODE:
       
  1849         clone = newOwnerDocument.createComment(node.data)
       
  1850     elif node.nodeType == Node.ATTRIBUTE_NODE:
       
  1851         clone = newOwnerDocument.createAttributeNS(node.namespaceURI,
       
  1852                                                    node.nodeName)
       
  1853         clone.specified = True
       
  1854         clone.value = node.value
       
  1855     elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
       
  1856         assert node.ownerDocument is not newOwnerDocument
       
  1857         operation = xml.dom.UserDataHandler.NODE_IMPORTED
       
  1858         clone = newOwnerDocument.implementation.createDocumentType(
       
  1859             node.name, node.publicId, node.systemId)
       
  1860         clone.ownerDocument = newOwnerDocument
       
  1861         if deep:
       
  1862             clone.entities._seq = []
       
  1863             clone.notations._seq = []
       
  1864             for n in node.notations._seq:
       
  1865                 notation = Notation(n.nodeName, n.publicId, n.systemId)
       
  1866                 notation.ownerDocument = newOwnerDocument
       
  1867                 clone.notations._seq.append(notation)
       
  1868                 if hasattr(n, '_call_user_data_handler'):
       
  1869                     n._call_user_data_handler(operation, n, notation)
       
  1870             for e in node.entities._seq:
       
  1871                 entity = Entity(e.nodeName, e.publicId, e.systemId,
       
  1872                                 e.notationName)
       
  1873                 entity.actualEncoding = e.actualEncoding
       
  1874                 entity.encoding = e.encoding
       
  1875                 entity.version = e.version
       
  1876                 entity.ownerDocument = newOwnerDocument
       
  1877                 clone.entities._seq.append(entity)
       
  1878                 if hasattr(e, '_call_user_data_handler'):
       
  1879                     e._call_user_data_handler(operation, n, entity)
       
  1880     else:
       
  1881         # Note the cloning of Document and DocumentType nodes is
       
  1882         # implemenetation specific.  minidom handles those cases
       
  1883         # directly in the cloneNode() methods.
       
  1884         raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node))
       
  1885 
       
  1886     # Check for _call_user_data_handler() since this could conceivably
       
  1887     # used with other DOM implementations (one of the FourThought
       
  1888     # DOMs, perhaps?).
       
  1889     if hasattr(node, '_call_user_data_handler'):
       
  1890         node._call_user_data_handler(operation, node, clone)
       
  1891     return clone
       
  1892 
       
  1893 
       
  1894 def _nssplit(qualifiedName):
       
  1895     fields = qualifiedName.split(':', 1)
       
  1896     if len(fields) == 2:
       
  1897         return fields
       
  1898     else:
       
  1899         return (None, fields[0])
       
  1900 
       
  1901 
       
  1902 def _get_StringIO():
       
  1903     # we can't use cStringIO since it doesn't support Unicode strings
       
  1904     from StringIO import StringIO
       
  1905     return StringIO()
       
  1906 
       
  1907 def _do_pulldom_parse(func, args, kwargs):
       
  1908     events = func(*args, **kwargs)
       
  1909     toktype, rootNode = events.getEvent()
       
  1910     events.expandNode(rootNode)
       
  1911     events.clear()
       
  1912     return rootNode
       
  1913 
       
  1914 def parse(file, parser=None, bufsize=None):
       
  1915     """Parse a file into a DOM by filename or file object."""
       
  1916     if parser is None and not bufsize:
       
  1917         from xml.dom import expatbuilder
       
  1918         return expatbuilder.parse(file)
       
  1919     else:
       
  1920         from xml.dom import pulldom
       
  1921         return _do_pulldom_parse(pulldom.parse, (file,),
       
  1922             {'parser': parser, 'bufsize': bufsize})
       
  1923 
       
  1924 def parseString(string, parser=None):
       
  1925     """Parse a file into a DOM from a string."""
       
  1926     if parser is None:
       
  1927         from xml.dom import expatbuilder
       
  1928         return expatbuilder.parseString(string)
       
  1929     else:
       
  1930         from xml.dom import pulldom
       
  1931         return _do_pulldom_parse(pulldom.parseString, (string,),
       
  1932                                  {'parser': parser})
       
  1933 
       
  1934 def getDOMImplementation(features=None):
       
  1935     if features:
       
  1936         if isinstance(features, StringTypes):
       
  1937             features = domreg._parse_feature_string(features)
       
  1938         for f, v in features:
       
  1939             if not Document.implementation.hasFeature(f, v):
       
  1940                 return None
       
  1941     return Document.implementation