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