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