"""\
2 minidom.py -- a lightweight DOM implementation. 6 parseString("<foo><bar/></foo>") 10 * convenience methods for getting elements and text. 12 * bring some of the writer and linearizer code into conformance with this 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
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.) 28 _nodeTypes_with_children
= (xml
.dom
.Node
.ELEMENT_NODE,
29 xml
.dom
.Node
.ENTITY_REFERENCE_NODE)
32 class Node(xml
.dom
.Node):
33 namespaceURI
= None # this is non-null only for elements and attributes 37 previousSibling
= None 39 prefix
= EMPTY_PREFIX
# non-null only for NS elements and attributes 41 def __nonzero__(
self):
44 def toxml(
self, encoding
= None):
45 return self.toprettyxml(
"",
"", encoding)
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:
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)
59 self.writexml(writer,
"", indent, newl)
60 return writer
.getvalue()
62 def hasChildNodes(
self):
68 def _get_childNodes(
self):
69 return self.childNodes
71 def _get_firstChild(
self):
73 return self.childNodes[
0]
75 def _get_lastChild(
self):
77 return self.childNodes[
-1]
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 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)
91 self.appendChild(newChild)
94 index
= self.childNodes
.index(refChild)
96 raise xml
.dom
.NotFoundErr()
97 if newChild
.nodeType
in _nodeTypes_with_children:
99 self.childNodes
.insert(index, newChild)
100 newChild
.nextSibling
= refChild
101 refChild
.previousSibling
= newChild
103 node
= self.childNodes[index
-1]
104 node
.nextSibling
= newChild
105 newChild
.previousSibling
= node
107 newChild
.previousSibling
= None 108 newChild
.parentNode
= self 111 def appendChild(
self, node):
112 if node
.nodeType
== self.DOCUMENT_FRAGMENT_NODE:
113 for c
in tuple(node
.childNodes):
115 ### The DOM does not clearly specify what to return in this case 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 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:
138 if newChild
.parentNode
is not None:
139 newChild
.parentNode
.removeChild(newChild)
141 index
= self.childNodes
.index(oldChild)
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
160 def removeChild(
self, oldChild):
162 self.childNodes
.remove(oldChild)
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)
173 oldChild
.parentNode
= None 178 for child
in self.childNodes:
179 if child
.nodeType
== Node
.TEXT_NODE:
181 # empty text node; discard 183 L[
-1]
.nextSibling
= child
.nextSibling
184 if child
.nextSibling:
185 child
.nextSibling
.previousSibling
= child
.previousSibling
187 elif L
and L[
-1]
.nodeType
== child
.nodeType:
190 node
.data
= node
.data
+ child
.data
191 node
.nextSibling
= child
.nextSibling
192 if child
.nextSibling:
193 child
.nextSibling
.previousSibling
= node
199 if child
.nodeType
== Node
.ELEMENT_NODE:
201 self.childNodes[:]
= L
203 def cloneNode(
self, deep):
204 return _clone_node(
self, deep,
self.ownerDocument
or self)
206 def isSupported(
self, feature, version):
207 return self.ownerDocument
.implementation
.hasFeature(feature, version)
209 def _get_localName(
self):
210 # Overridden in Element and Attr where localName can be Non-Null 213 # Node interfaces from Level 3 (WD 9 April 2002) 215 def isSameNode(
self, other):
218 def getInterface(
self, feature):
219 if self.isSupported(feature,
None):
224 # The "user data" functions use a dictionary that is only present 225 # if some user data has been set, so be careful not to assume it 228 def getUserData(
self, key):
230 return self._user_data[key][
0]
231 except (
AttributeError,
KeyError):
234 def setUserData(
self, key, data, handler):
238 except AttributeError:
244 # ignore handlers passed for None 249 d[key]
= (data, handler)
252 def _call_user_data_handler(
self, operation, src, dst):
253 if hasattr(
self,
"_user_data"):
254 for key, (data, handler)
in self._user_data
.items():
255 if handler
is not None:
256 handler
.handle(operation, key, data, src, dst)
258 # minidom-specific API: 261 self.parentNode
= self.ownerDocument
= None 263 for child
in self.childNodes:
265 self.childNodes
= NodeList()
266 self.previousSibling
= None 267 self.nextSibling
= None 269 defproperty(Node,
"firstChild", doc
="First child node, or None.")
270 defproperty(Node,
"lastChild", doc
="Last child node, or None.")
271 defproperty(Node,
"localName", doc
="Namespace-local name of this node.")
274 def _append_child(
self, node):
275 # fast path with less checks; usable by DOM builders if careful 276 childNodes
= self.childNodes
278 last
= childNodes[
-1]
279 node
.__dict__[
"previousSibling"]
= last
280 last
.__dict__[
"nextSibling"]
= node
281 childNodes
.append(node)
282 node
.__dict__[
"parentNode"]
= self 284 def _in_document(node):
285 # return True iff node is part of a document tree 286 while node
is not None:
287 if node
.nodeType
== Node
.DOCUMENT_NODE:
289 node
= node
.parentNode
292 def _write_data(writer, data):
293 "Writes datachars to writer." 295 data
= data
.replace(
"&",
"&")
.replace(
"<",
"<")
. \
296 replace(
"\"",
""")
.replace(
">",
">")
299 def _get_elements_by_tagName_helper(parent, name, rc):
300 for node
in parent
.childNodes:
301 if node
.nodeType
== Node
.ELEMENT_NODE
and \
302 (name
== "*" or node
.tagName
== name):
304 _get_elements_by_tagName_helper(node, name, rc)
307 def _get_elements_by_tagName_ns_helper(parent, nsURI, localName, rc):
308 for node
in parent
.childNodes:
309 if node
.nodeType
== Node
.ELEMENT_NODE:
310 if ((localName
== "*" or node
.localName
== localName)
and 311 (nsURI
== "*" or node
.namespaceURI
== nsURI)):
313 _get_elements_by_tagName_ns_helper(node, nsURI, localName, rc)
316 class DocumentFragment(Node):
317 nodeType
= Node
.DOCUMENT_FRAGMENT_NODE
318 nodeName
= "#document-fragment" 322 _child_node_types
= (Node
.ELEMENT_NODE,
324 Node
.CDATA_SECTION_NODE,
325 Node
.ENTITY_REFERENCE_NODE,
326 Node
.PROCESSING_INSTRUCTION_NODE,
331 self.childNodes
= NodeList()
335 nodeType
= Node
.ATTRIBUTE_NODE
341 _child_node_types
= (Node
.TEXT_NODE, Node
.ENTITY_REFERENCE_NODE)
343 def __init__(
self, qName, namespaceURI
=EMPTY_NAMESPACE, localName
=None,
345 # skip setattr for performance 347 d[
"nodeName"]
= d[
"name"]
= qName
348 d[
"namespaceURI"]
= namespaceURI
350 d[
'childNodes']
= NodeList()
352 # Add the single child node that represents the value of the attr 353 self.childNodes
.append(Text())
355 # nodeValue and value are set elsewhere 357 def _get_localName(
self):
358 return self.nodeName
.split(
":",
1)[
-1]
363 def _get_specified(
self):
364 return self.specified
366 def __setattr__(
self, name, value):
368 if name
in (
"value",
"nodeValue"):
369 d[
"value"]
= d[
"nodeValue"]
= value
370 d2
= self.childNodes[
0]
.__dict__
371 d2[
"data"]
= d2[
"nodeValue"]
= value
372 if self.ownerElement
is not None:
373 _clear_id_cache(
self.ownerElement)
374 elif name
in (
"name",
"nodeName"):
375 d[
"name"]
= d[
"nodeName"]
= value
376 if self.ownerElement
is not None:
377 _clear_id_cache(
self.ownerElement)
381 def _set_prefix(
self, prefix):
382 nsuri
= self.namespaceURI
383 if prefix
== "xmlns":
384 if nsuri
and nsuri
!= XMLNS_NAMESPACE:
385 raise xml
.dom
.NamespaceErr(
386 "illegal use of 'xmlns' prefix for the wrong namespace")
390 newName
= self.localName
392 newName
= "%s:%s" % (prefix,
self.localName)
393 if self.ownerElement:
394 _clear_id_cache(
self.ownerElement)
395 d[
'nodeName']
= d[
'name']
= newName
397 def _set_value(
self, value):
399 d[
'value']
= d[
'nodeValue']
= value
400 if self.ownerElement:
401 _clear_id_cache(
self.ownerElement)
402 self.childNodes[
0]
.data
= value
405 # This implementation does not call the base implementation 406 # since most of that is not needed, and the expense of the 407 # method call is not warranted. We duplicate the removal of 408 # children, but that's all we needed from the base class. 409 elem
= self.ownerElement
411 del elem
._attrs[
self.nodeName]
412 del elem
._attrsNS[(
self.namespaceURI,
self.localName)]
415 elem
._magic_id_nodes
-= 1 416 self.ownerDocument
._magic_id_count
-= 1 417 for child
in self.childNodes:
419 del self.childNodes[:]
424 doc
= self.ownerDocument
425 elem
= self.ownerElement
426 if doc
is None or elem
is None:
429 info
= doc
._get_elem_info(elem)
432 if self.namespaceURI:
433 return info
.isIdNS(
self.namespaceURI,
self.localName)
435 return info
.isId(
self.nodeName)
437 def _get_schemaType(
self):
438 doc
= self.ownerDocument
439 elem
= self.ownerElement
440 if doc
is None or elem
is None:
443 info
= doc
._get_elem_info(elem)
446 if self.namespaceURI:
447 return info
.getAttributeTypeNS(
self.namespaceURI,
self.localName)
449 return info
.getAttributeType(
self.nodeName)
451 defproperty(Attr,
"isId", doc
="True if this attribute is an ID.")
452 defproperty(Attr,
"localName", doc
="Namespace-local name of this attribute.")
453 defproperty(Attr,
"schemaType", doc
="Schema type for this attribute.")
456 class NamedNodeMap(
object):
457 """The attribute list is a transient interface to the underlying 458 dictionaries. Mutations here will change the underlying element's 461 Ordering is imposed artificially and does not reflect the order of 462 attributes as found in an input document. 465 __slots__
= (
'_attrs',
'_attrsNS',
'_ownerElement')
467 def __init__(
self, attrs, attrsNS, ownerElement):
469 self._attrsNS
= attrsNS
470 self._ownerElement
= ownerElement
472 def _get_length(
self):
473 return len(
self._attrs)
475 def item(
self, index):
477 return self[
self._attrs
.keys()[index]]
483 for node
in self._attrs
.values():
484 L
.append((node
.nodeName, node
.value))
489 for node
in self._attrs
.values():
490 L
.append(((node
.namespaceURI, node
.localName), node
.value))
493 def has_key(
self, key):
494 if isinstance(key, StringTypes):
495 return key
in self._attrs
497 return key
in self._attrsNS
500 return self._attrs
.keys()
503 return self._attrsNS
.keys()
506 return self._attrs
.values()
508 def get(
self, name, value
=None):
509 return self._attrs
.get(name, value)
511 __len__
= _get_length
513 __hash__
= None # Mutable type can't be correctly hashed 514 def __cmp__(
self, other):
515 if self._attrs
is getattr(other,
"_attrs",
None):
518 return cmp(
id(
self),
id(other))
520 def __getitem__(
self, attname_or_tuple):
521 if isinstance(attname_or_tuple,
tuple):
522 return self._attrsNS[attname_or_tuple]
524 return self._attrs[attname_or_tuple]
527 def __setitem__(
self, attname, value):
528 if isinstance(value, StringTypes):
530 node
= self._attrs[attname]
533 node
.ownerDocument
= self._ownerElement
.ownerDocument
534 self.setNamedItem(node)
537 if not isinstance(value, Attr):
538 raise TypeError,
"value must be a string or Attr object" 540 self.setNamedItem(node)
542 def getNamedItem(
self, name):
544 return self._attrs[name]
548 def getNamedItemNS(
self, namespaceURI, localName):
550 return self._attrsNS[(namespaceURI, localName)]
554 def removeNamedItem(
self, name):
555 n
= self.getNamedItem(name)
557 _clear_id_cache(
self._ownerElement)
558 del self._attrs[n
.nodeName]
559 del self._attrsNS[(n
.namespaceURI, n
.localName)]
560 if 'ownerElement' in n
.__dict__:
561 n
.__dict__[
'ownerElement']
= None 564 raise xml
.dom
.NotFoundErr()
566 def removeNamedItemNS(
self, namespaceURI, localName):
567 n
= self.getNamedItemNS(namespaceURI, localName)
569 _clear_id_cache(
self._ownerElement)
570 del self._attrsNS[(n
.namespaceURI, n
.localName)]
571 del self._attrs[n
.nodeName]
572 if 'ownerElement' in n
.__dict__:
573 n
.__dict__[
'ownerElement']
= None 576 raise xml
.dom
.NotFoundErr()
578 def setNamedItem(
self, node):
579 if not isinstance(node, Attr):
580 raise xml
.dom
.HierarchyRequestErr(
581 "%s cannot be child of %s" % (
repr(node),
repr(
self)))
582 old
= self._attrs
.get(node
.name)
585 self._attrs[node
.name]
= node
586 self._attrsNS[(node
.namespaceURI, node
.localName)]
= node
587 node
.ownerElement
= self._ownerElement
588 _clear_id_cache(node
.ownerElement)
591 def setNamedItemNS(
self, node):
592 return self.setNamedItem(node)
594 def __delitem__(
self, attname_or_tuple):
595 node
= self[attname_or_tuple]
596 _clear_id_cache(node
.ownerElement)
599 def __getstate__(
self):
600 return self._attrs,
self._attrsNS,
self._ownerElement
602 def __setstate__(
self, state):
603 self._attrs,
self._attrsNS,
self._ownerElement
= state
605 defproperty(NamedNodeMap,
"length",
606 doc
="Number of nodes in the NamedNodeMap.")
608 AttributeList
= NamedNodeMap
611 class TypeInfo(
object):
612 __slots__
= 'namespace',
'name' 614 def __init__(
self, namespace, name):
615 self.namespace
= namespace
620 return "<TypeInfo %r (from %r)>" % (
self.name,
self.namespace)
622 return "<TypeInfo %r>" % self.name
627 def _get_namespace(
self):
628 return self.namespace
630 _no_type
= TypeInfo(
None,
None)
633 nodeType
= Node
.ELEMENT_NODE
635 schemaType
= _no_type
639 _child_node_types
= (Node
.ELEMENT_NODE,
640 Node
.PROCESSING_INSTRUCTION_NODE,
643 Node
.CDATA_SECTION_NODE,
644 Node
.ENTITY_REFERENCE_NODE)
646 def __init__(
self, tagName, namespaceURI
=EMPTY_NAMESPACE, prefix
=None,
648 self.tagName
= self.nodeName
= tagName
650 self.namespaceURI
= namespaceURI
651 self.childNodes
= NodeList()
653 self._attrs
= {}
# attributes are double-indexed: 654 self._attrsNS
= {}
# tagName -> Attribute 655 # URI,localName -> Attribute 656 # in the future: consider lazy generation 657 # of attribute objects this is too tricky 658 # for now because of headaches with 661 def _get_localName(
self):
662 return self.tagName
.split(
":",
1)[
-1]
664 def _get_tagName(
self):
668 for attr
in self._attrs
.values():
674 def getAttribute(
self, attname):
676 return self._attrs[attname]
.value
680 def getAttributeNS(
self, namespaceURI, localName):
682 return self._attrsNS[(namespaceURI, localName)]
.value
686 def setAttribute(
self, attname, value):
687 attr
= self.getAttributeNode(attname)
692 d[
"value"]
= d[
"nodeValue"]
= value
693 d[
"ownerDocument"]
= self.ownerDocument
694 self.setAttributeNode(attr)
695 elif value
!= attr
.value:
697 d[
"value"]
= d[
"nodeValue"]
= value
699 _clear_id_cache(
self)
701 def setAttributeNS(
self, namespaceURI, qualifiedName, value):
702 prefix, localname
= _nssplit(qualifiedName)
703 attr
= self.getAttributeNodeNS(namespaceURI, localname)
706 attr
= Attr(qualifiedName, namespaceURI, localname, prefix)
709 d[
"nodeName"]
= qualifiedName
710 d[
"value"]
= d[
"nodeValue"]
= value
711 d[
"ownerDocument"]
= self.ownerDocument
712 self.setAttributeNode(attr)
715 if value
!= attr
.value:
716 d[
"value"]
= d[
"nodeValue"]
= value
718 _clear_id_cache(
self)
719 if attr
.prefix
!= prefix:
721 d[
"nodeName"]
= qualifiedName
723 def getAttributeNode(
self, attrname):
724 return self._attrs
.get(attrname)
726 def getAttributeNodeNS(
self, namespaceURI, localName):
727 return self._attrsNS
.get((namespaceURI, localName))
729 def setAttributeNode(
self, attr):
730 if attr
.ownerElement
not in (
None,
self):
731 raise xml
.dom
.InuseAttributeErr(
"attribute node already owned")
732 old1
= self._attrs
.get(attr
.name,
None)
734 self.removeAttributeNode(old1)
735 old2
= self._attrsNS
.get((attr
.namespaceURI, attr
.localName),
None)
736 if old2
is not None and old2
is not old1:
737 self.removeAttributeNode(old2)
738 _set_attribute_node(
self, attr)
741 # It might have already been part of this node, in which case 742 # it doesn't represent a change, and should not be returned. 747 setAttributeNodeNS
= setAttributeNode
749 def removeAttribute(
self, name):
751 attr
= self._attrs[name]
753 raise xml
.dom
.NotFoundErr()
754 self.removeAttributeNode(attr)
756 def removeAttributeNS(
self, namespaceURI, localName):
758 attr
= self._attrsNS[(namespaceURI, localName)]
760 raise xml
.dom
.NotFoundErr()
761 self.removeAttributeNode(attr)
763 def removeAttributeNode(
self, node):
765 raise xml
.dom
.NotFoundErr()
767 self._attrs[node
.name]
769 raise xml
.dom
.NotFoundErr()
770 _clear_id_cache(
self)
772 # Restore this since the node is still useful and otherwise 774 node
.ownerDocument
= self.ownerDocument
776 removeAttributeNodeNS
= removeAttributeNode
778 def hasAttribute(
self, name):
779 return name
in self._attrs
781 def hasAttributeNS(
self, namespaceURI, localName):
782 return (namespaceURI, localName)
in self._attrsNS
784 def getElementsByTagName(
self, name):
785 return _get_elements_by_tagName_helper(
self, name, NodeList())
787 def getElementsByTagNameNS(
self, namespaceURI, localName):
788 return _get_elements_by_tagName_ns_helper(
789 self, namespaceURI, localName, NodeList())
792 return "<DOM Element: %s at %#x>" % (
self.tagName,
id(
self))
794 def writexml(
self, writer, indent
="", addindent
="", newl
=""):
795 # indent = current indentation 796 # addindent = indentation to add to higher levels 797 # newl = newline string 798 writer
.write(indent
+"<" + self.tagName)
800 attrs
= self._get_attributes()
801 a_names
= attrs
.keys()
804 for a_name
in a_names:
805 writer
.write(
" %s=\"" % a_name)
806 _write_data(writer, attrs[a_name]
.value)
810 if (
len(
self.childNodes)
== 1 and 811 self.childNodes[
0]
.nodeType
== Node
.TEXT_NODE):
812 self.childNodes[
0]
.writexml(writer,
'',
'',
'')
815 for node
in self.childNodes:
816 node
.writexml(writer, indent
+addindent, addindent, newl)
818 writer
.write(
"</%s>%s" % (
self.tagName, newl))
820 writer
.write(
"/>%s"%(newl))
822 def _get_attributes(
self):
823 return NamedNodeMap(
self._attrs,
self._attrsNS,
self)
825 def hasAttributes(
self):
831 # DOM Level 3 attributes, based on the 22 Oct 2002 draft 833 def setIdAttribute(
self, name):
834 idAttr
= self.getAttributeNode(name)
835 self.setIdAttributeNode(idAttr)
837 def setIdAttributeNS(
self, namespaceURI, localName):
838 idAttr
= self.getAttributeNodeNS(namespaceURI, localName)
839 self.setIdAttributeNode(idAttr)
841 def setIdAttributeNode(
self, idAttr):
842 if idAttr
is None or not self.isSameNode(idAttr
.ownerElement):
843 raise xml
.dom
.NotFoundErr()
844 if _get_containing_entref(
self)
is not None:
845 raise xml
.dom
.NoModificationAllowedErr()
846 if not idAttr
._is_id:
847 idAttr
.__dict__[
'_is_id']
= True 848 self._magic_id_nodes
+= 1 849 self.ownerDocument
._magic_id_count
+= 1 850 _clear_id_cache(
self)
852 defproperty(Element,
"attributes",
853 doc
="NamedNodeMap of attributes on the element.")
854 defproperty(Element,
"localName",
855 doc
="Namespace-local name of this element.")
858 def _set_attribute_node(element, attr):
859 _clear_id_cache(element)
860 element
._attrs[attr
.name]
= attr
861 element
._attrsNS[(attr
.namespaceURI, attr
.localName)]
= attr
863 # This creates a circular reference, but Element.unlink() 864 # breaks the cycle since the references to the attribute 865 # dictionaries are tossed. 866 attr
.__dict__[
'ownerElement']
= element
870 """Mixin that makes childless-ness easy to implement and avoids 871 the complexity of the Node methods that deal with children. 875 childNodes
= EmptyNodeList()
879 def _get_firstChild(
self):
882 def _get_lastChild(
self):
885 def appendChild(
self, node):
886 raise xml
.dom
.HierarchyRequestErr(
887 self.nodeName
+ " nodes cannot have children")
889 def hasChildNodes(
self):
892 def insertBefore(
self, newChild, refChild):
893 raise xml
.dom
.HierarchyRequestErr(
894 self.nodeName
+ " nodes do not have children")
896 def removeChild(
self, oldChild):
897 raise xml
.dom
.NotFoundErr(
898 self.nodeName
+ " nodes do not have children")
901 # For childless nodes, normalize() has nothing to do. 904 def replaceChild(
self, newChild, oldChild):
905 raise xml
.dom
.HierarchyRequestErr(
906 self.nodeName
+ " nodes do not have children")
909 class ProcessingInstruction(Childless, Node):
910 nodeType
= Node
.PROCESSING_INSTRUCTION_NODE
912 def __init__(
self, target, data):
913 self.target
= self.nodeName
= target
914 self.data
= self.nodeValue
= data
918 def _set_data(
self, value):
920 d[
'data']
= d[
'nodeValue']
= value
922 def _get_target(
self):
924 def _set_target(
self, value):
926 d[
'target']
= d[
'nodeName']
= value
928 def __setattr__(
self, name, value):
929 if name
== "data" or name
== "nodeValue":
930 self.__dict__[
'data']
= self.__dict__[
'nodeValue']
= value
931 elif name
== "target" or name
== "nodeName":
932 self.__dict__[
'target']
= self.__dict__[
'nodeName']
= value
934 self.__dict__[name]
= value
936 def writexml(
self, writer, indent
="", addindent
="", newl
=""):
937 writer
.write(
"%s<?%s %s?>%s" % (indent,
self.target,
self.data, newl))
940 class CharacterData(Childless, Node):
941 def _get_length(
self):
942 return len(
self.data)
943 __len__
= _get_length
946 return self.__dict__[
'data']
947 def _set_data(
self, data):
949 d[
'data']
= d[
'nodeValue']
= data
951 _get_nodeValue
= _get_data
952 _set_nodeValue
= _set_data
954 def __setattr__(
self, name, value):
955 if name
== "data" or name
== "nodeValue":
956 self.__dict__[
'data']
= self.__dict__[
'nodeValue']
= value
958 self.__dict__[name]
= value
966 return '<DOM %s node "%r%s">' % (
967 self.__class__
.__name__, data[
0:
10], dotdotdot)
969 def substringData(
self, offset, count):
971 raise xml
.dom
.IndexSizeErr(
"offset cannot be negative")
972 if offset
>= len(
self.data):
973 raise xml
.dom
.IndexSizeErr(
"offset cannot be beyond end of data")
975 raise xml
.dom
.IndexSizeErr(
"count cannot be negative")
976 return self.data[offset:offset
+count]
978 def appendData(
self, arg):
979 self.data
= self.data
+ arg
981 def insertData(
self, offset, arg):
983 raise xml
.dom
.IndexSizeErr(
"offset cannot be negative")
984 if offset
>= len(
self.data):
985 raise xml
.dom
.IndexSizeErr(
"offset cannot be beyond end of data")
987 self.data
= "%s%s%s" % (
988 self.data[:offset], arg,
self.data[offset:])
990 def deleteData(
self, offset, count):
992 raise xml
.dom
.IndexSizeErr(
"offset cannot be negative")
993 if offset
>= len(
self.data):
994 raise xml
.dom
.IndexSizeErr(
"offset cannot be beyond end of data")
996 raise xml
.dom
.IndexSizeErr(
"count cannot be negative")
998 self.data
= self.data[:offset]
+ self.data[offset
+count:]
1000 def replaceData(
self, offset, count, arg):
1002 raise xml
.dom
.IndexSizeErr(
"offset cannot be negative")
1003 if offset
>= len(
self.data):
1004 raise xml
.dom
.IndexSizeErr(
"offset cannot be beyond end of data")
1006 raise xml
.dom
.IndexSizeErr(
"count cannot be negative")
1008 self.data
= "%s%s%s" % (
1009 self.data[:offset], arg,
self.data[offset
+count:])
1011 defproperty(CharacterData,
"length", doc
="Length of the string data.")
1014 class Text(CharacterData):
1015 # Make sure we don't add an instance __dict__ if we don't already 1016 # have one, at least when that's possible: 1017 # XXX this does not work, CharacterData is an old-style class 1020 nodeType
= Node
.TEXT_NODE
1024 def splitText(
self, offset):
1025 if offset
< 0 or offset
> len(
self.data):
1026 raise xml
.dom
.IndexSizeErr(
"illegal offset value")
1027 newText
= self.__class__()
1028 newText
.data
= self.data[offset:]
1029 newText
.ownerDocument
= self.ownerDocument
1030 next = self.nextSibling
1031 if self.parentNode
and self in self.parentNode
.childNodes:
1033 self.parentNode
.appendChild(newText)
1035 self.parentNode
.insertBefore(newText,
next)
1036 self.data
= self.data[:offset]
1039 def writexml(
self, writer, indent
="", addindent
="", newl
=""):
1040 _write_data(writer,
"%s%s%s" % (indent,
self.data, newl))
1042 # DOM Level 3 (WD 9 April 2002) 1044 def _get_wholeText(
self):
1046 n
= self.previousSibling
1047 while n
is not None:
1048 if n
.nodeType
in (Node
.TEXT_NODE, Node
.CDATA_SECTION_NODE):
1050 n
= n
.previousSibling
1053 n
= self.nextSibling
1054 while n
is not None:
1055 if n
.nodeType
in (Node
.TEXT_NODE, Node
.CDATA_SECTION_NODE):
1062 def replaceWholeText(
self, content):
1063 # XXX This needs to be seriously changed if minidom ever 1064 # supports EntityReference nodes. 1065 parent
= self.parentNode
1066 n
= self.previousSibling
1067 while n
is not None:
1068 if n
.nodeType
in (Node
.TEXT_NODE, Node
.CDATA_SECTION_NODE):
1069 next = n
.previousSibling
1070 parent
.removeChild(n)
1074 n
= self.nextSibling
1076 parent
.removeChild(
self)
1077 while n
is not None:
1078 if n
.nodeType
in (Node
.TEXT_NODE, Node
.CDATA_SECTION_NODE):
1079 next = n
.nextSibling
1080 parent
.removeChild(n)
1087 d[
'nodeValue']
= content
1092 def _get_isWhitespaceInElementContent(
self):
1093 if self.data
.strip():
1095 elem
= _get_containing_element(
self)
1098 info
= self.ownerDocument
._get_elem_info(elem)
1102 return info
.isElementContent()
1104 defproperty(Text,
"isWhitespaceInElementContent",
1105 doc
="True iff this text node contains only whitespace" 1106 " and is in element content.")
1107 defproperty(Text,
"wholeText",
1108 doc
="The text of all logically-adjacent text nodes.")
1111 def _get_containing_element(node):
1113 while c
is not None:
1114 if c
.nodeType
== Node
.ELEMENT_NODE:
1119 def _get_containing_entref(node):
1121 while c
is not None:
1122 if c
.nodeType
== Node
.ENTITY_REFERENCE_NODE:
1128 class Comment(Childless, CharacterData):
1129 nodeType
= Node
.COMMENT_NODE
1130 nodeName
= "#comment" 1132 def __init__(
self, data):
1133 self.data
= self.nodeValue
= data
1135 def writexml(
self, writer, indent
="", addindent
="", newl
=""):
1136 if "--" in self.data:
1137 raise ValueError(
"'--' is not allowed in a comment node")
1138 writer
.write(
"%s<!--%s-->%s" % (indent,
self.data, newl))
1141 class CDATASection(Text):
1142 # Make sure we don't add an instance __dict__ if we don't already 1143 # have one, at least when that's possible: 1144 # XXX this does not work, Text is an old-style class 1147 nodeType
= Node
.CDATA_SECTION_NODE
1148 nodeName
= "#cdata-section" 1150 def writexml(
self, writer, indent
="", addindent
="", newl
=""):
1151 if self.data
.find(
"]]>")
>= 0:
1152 raise ValueError(
"']]>' not allowed in a CDATA section")
1153 writer
.write(
"<![CDATA[%s]]>" % self.data)
1156 class ReadOnlySequentialNamedNodeMap(
object):
1159 def __init__(
self, seq
=()):
1160 # seq should be a list or tuple 1164 return len(
self._seq)
1166 def _get_length(
self):
1167 return len(
self._seq)
1169 def getNamedItem(
self, name):
1171 if n
.nodeName
== name:
1174 def getNamedItemNS(
self, namespaceURI, localName):
1176 if n
.namespaceURI
== namespaceURI
and n
.localName
== localName:
1179 def __getitem__(
self, name_or_tuple):
1180 if isinstance(name_or_tuple,
tuple):
1181 node
= self.getNamedItemNS(
*name_or_tuple)
1183 node
= self.getNamedItem(name_or_tuple)
1185 raise KeyError, name_or_tuple
1188 def item(
self, index):
1192 return self._seq[index]
1196 def removeNamedItem(
self, name):
1197 raise xml
.dom
.NoModificationAllowedErr(
1198 "NamedNodeMap instance is read-only")
1200 def removeNamedItemNS(
self, namespaceURI, localName):
1201 raise xml
.dom
.NoModificationAllowedErr(
1202 "NamedNodeMap instance is read-only")
1204 def setNamedItem(
self, node):
1205 raise xml
.dom
.NoModificationAllowedErr(
1206 "NamedNodeMap instance is read-only")
1208 def setNamedItemNS(
self, node):
1209 raise xml
.dom
.NoModificationAllowedErr(
1210 "NamedNodeMap instance is read-only")
1212 def __getstate__(
self):
1215 def __setstate__(
self, state):
1216 self._seq
= state[
0]
1218 defproperty(ReadOnlySequentialNamedNodeMap,
"length",
1219 doc
="Number of entries in the NamedNodeMap.")
1223 """Mix-in class that supports the publicId and systemId attributes.""" 1225 # XXX this does not work, this is an old-style class 1226 # __slots__ = 'publicId', 'systemId' 1228 def _identified_mixin_init(
self, publicId, systemId):
1229 self.publicId
= publicId
1230 self.systemId
= systemId
1232 def _get_publicId(
self):
1233 return self.publicId
1235 def _get_systemId(
self):
1236 return self.systemId
1238 class DocumentType(Identified, Childless, Node):
1239 nodeType
= Node
.DOCUMENT_TYPE_NODE
1244 internalSubset
= None 1246 def __init__(
self, qualifiedName):
1247 self.entities
= ReadOnlySequentialNamedNodeMap()
1248 self.notations
= ReadOnlySequentialNamedNodeMap()
1250 prefix, localname
= _nssplit(qualifiedName)
1251 self.name
= localname
1252 self.nodeName
= self.name
1254 def _get_internalSubset(
self):
1255 return self.internalSubset
1257 def cloneNode(
self, deep):
1258 if self.ownerDocument
is None:
1260 clone
= DocumentType(
None)
1261 clone
.name
= self.name
1262 clone
.nodeName
= self.name
1263 operation
= xml
.dom
.UserDataHandler
.NODE_CLONED
1265 clone
.entities
._seq
= []
1266 clone
.notations
._seq
= []
1267 for n
in self.notations
._seq:
1268 notation
= Notation(n
.nodeName, n
.publicId, n
.systemId)
1269 clone
.notations
._seq
.append(notation)
1270 n
._call_user_data_handler(operation, n, notation)
1271 for e
in self.entities
._seq:
1272 entity
= Entity(e
.nodeName, e
.publicId, e
.systemId,
1274 entity
.actualEncoding
= e
.actualEncoding
1275 entity
.encoding
= e
.encoding
1276 entity
.version
= e
.version
1277 clone
.entities
._seq
.append(entity)
1278 e
._call_user_data_handler(operation, n, entity)
1279 self._call_user_data_handler(operation,
self, clone)
1284 def writexml(
self, writer, indent
="", addindent
="", newl
=""):
1285 writer
.write(
"<!DOCTYPE ")
1286 writer
.write(
self.name)
1288 writer
.write(
"%s PUBLIC '%s'%s '%s'" 1289 % (newl,
self.publicId, newl,
self.systemId))
1291 writer
.write(
"%s SYSTEM '%s'" % (newl,
self.systemId))
1292 if self.internalSubset
is not None:
1294 writer
.write(
self.internalSubset)
1296 writer
.write(
">"+newl)
1298 class Entity(Identified, Node):
1300 nodeType
= Node
.ENTITY_NODE
1303 actualEncoding
= None 1307 def __init__(
self, name, publicId, systemId, notation):
1308 self.nodeName
= name
1309 self.notationName
= notation
1310 self.childNodes
= NodeList()
1311 self._identified_mixin_init(publicId, systemId)
1313 def _get_actualEncoding(
self):
1314 return self.actualEncoding
1316 def _get_encoding(
self):
1317 return self.encoding
1319 def _get_version(
self):
1322 def appendChild(
self, newChild):
1323 raise xml
.dom
.HierarchyRequestErr(
1324 "cannot append children to an entity node")
1326 def insertBefore(
self, newChild, refChild):
1327 raise xml
.dom
.HierarchyRequestErr(
1328 "cannot insert children below an entity node")
1330 def removeChild(
self, oldChild):
1331 raise xml
.dom
.HierarchyRequestErr(
1332 "cannot remove children from an entity node")
1334 def replaceChild(
self, newChild, oldChild):
1335 raise xml
.dom
.HierarchyRequestErr(
1336 "cannot replace children of an entity node")
1338 class Notation(Identified, Childless, Node):
1339 nodeType
= Node
.NOTATION_NODE
1342 def __init__(
self, name, publicId, systemId):
1343 self.nodeName
= name
1344 self._identified_mixin_init(publicId, systemId)
1347 class DOMImplementation(DOMImplementationLS):
1348 _features
= [(
"core",
"1.0"),
1358 def hasFeature(
self, feature, version):
1361 return (feature
.lower(), version)
in self._features
1363 def createDocument(
self, namespaceURI, qualifiedName, doctype):
1364 if doctype
and doctype
.parentNode
is not None:
1365 raise xml
.dom
.WrongDocumentErr(
1366 "doctype object owned by another DOM tree")
1367 doc
= self._create_document()
1369 add_root_element
= not (namespaceURI
is None 1370 and qualifiedName
is None 1371 and doctype
is None)
1373 if not qualifiedName
and add_root_element:
1374 # The spec is unclear what to raise here; SyntaxErr 1375 # would be the other obvious candidate. Since Xerces raises 1376 # InvalidCharacterErr, and since SyntaxErr is not listed 1377 # for createDocument, that seems to be the better choice. 1378 # XXX: need to check for illegal characters here and in 1381 # DOM Level III clears this up when talking about the return value 1382 # of this function. If namespaceURI, qName and DocType are 1383 # Null the document is returned without a document element 1384 # Otherwise if doctype or namespaceURI are not None 1385 # Then we go back to the above problem 1386 raise xml
.dom
.InvalidCharacterErr(
"Element with no name")
1388 if add_root_element:
1389 prefix, localname
= _nssplit(qualifiedName)
1390 if prefix
== "xml" \
1391 and namespaceURI
!= "http://www.w3.org/XML/1998/namespace":
1392 raise xml
.dom
.NamespaceErr(
"illegal use of 'xml' prefix")
1393 if prefix
and not namespaceURI:
1394 raise xml
.dom
.NamespaceErr(
1395 "illegal use of prefix without namespaces")
1396 element
= doc
.createElementNS(namespaceURI, qualifiedName)
1398 doc
.appendChild(doctype)
1399 doc
.appendChild(element)
1402 doctype
.parentNode
= doctype
.ownerDocument
= doc
1404 doc
.doctype
= doctype
1405 doc
.implementation
= self 1408 def createDocumentType(
self, qualifiedName, publicId, systemId):
1409 doctype
= DocumentType(qualifiedName)
1410 doctype
.publicId
= publicId
1411 doctype
.systemId
= systemId
1414 # DOM Level 3 (WD 9 April 2002) 1416 def getInterface(
self, feature):
1417 if self.hasFeature(feature,
None):
1423 def _create_document(
self):
1426 class ElementInfo(
object):
1427 """Object that represents content-model information for an element. 1429 This implementation is not expected to be used in practice; DOM 1430 builders should provide implementations which do the right thing 1431 using information available to it. 1435 __slots__
= 'tagName',
1437 def __init__(
self, name):
1440 def getAttributeType(
self, aname):
1443 def getAttributeTypeNS(
self, namespaceURI, localName):
1446 def isElementContent(
self):
1450 """Returns true iff this element is declared to have an EMPTY 1454 def isId(
self, aname):
1455 """Returns true iff the named attribute is a DTD-style ID.""" 1458 def isIdNS(
self, namespaceURI, localName):
1459 """Returns true iff the identified attribute is a DTD-style ID.""" 1462 def __getstate__(
self):
1465 def __setstate__(
self, state):
1466 self.tagName
= state
1468 def _clear_id_cache(node):
1469 if node
.nodeType
== Node
.DOCUMENT_NODE:
1470 node
._id_cache
.clear()
1471 node
._id_search_stack
= None 1472 elif _in_document(node):
1473 node
.ownerDocument
._id_cache
.clear()
1474 node
.ownerDocument
._id_search_stack
= None 1476 class Document(Node, DocumentLS):
1477 _child_node_types
= (Node
.ELEMENT_NODE, Node
.PROCESSING_INSTRUCTION_NODE,
1478 Node
.COMMENT_NODE, Node
.DOCUMENT_TYPE_NODE)
1480 nodeType
= Node
.DOCUMENT_NODE
1481 nodeName
= "#document" 1486 previousSibling
= nextSibling
= None 1488 implementation
= DOMImplementation()
1490 # Document attributes from Level 3 (WD 9 April 2002) 1492 actualEncoding
= None 1496 strictErrorChecking
= False 1503 self.childNodes
= NodeList()
1504 # mapping of (namespaceURI, localName) -> ElementInfo 1505 # and tagName -> ElementInfo 1506 self._elem_info
= {}
1508 self._id_search_stack
= None 1510 def _get_elem_info(
self, element):
1511 if element
.namespaceURI:
1512 key
= element
.namespaceURI, element
.localName
1514 key
= element
.tagName
1515 return self._elem_info
.get(key)
1517 def _get_actualEncoding(
self):
1518 return self.actualEncoding
1520 def _get_doctype(
self):
1523 def _get_documentURI(
self):
1524 return self.documentURI
1526 def _get_encoding(
self):
1527 return self.encoding
1529 def _get_errorHandler(
self):
1530 return self.errorHandler
1532 def _get_standalone(
self):
1533 return self.standalone
1535 def _get_strictErrorChecking(
self):
1536 return self.strictErrorChecking
1538 def _get_version(
self):
1541 def appendChild(
self, node):
1542 if node
.nodeType
not in self._child_node_types:
1543 raise xml
.dom
.HierarchyRequestErr(
1544 "%s cannot be child of %s" % (
repr(node),
repr(
self)))
1545 if node
.parentNode
is not None:
1546 # This needs to be done before the next test since this 1547 # may *be* the document element, in which case it should 1548 # end up re-ordered to the end. 1549 node
.parentNode
.removeChild(node)
1551 if node
.nodeType
== Node
.ELEMENT_NODE \
1552 and self._get_documentElement():
1553 raise xml
.dom
.HierarchyRequestErr(
1554 "two document elements disallowed")
1555 return Node
.appendChild(
self, node)
1557 def removeChild(
self, oldChild):
1559 self.childNodes
.remove(oldChild)
1561 raise xml
.dom
.NotFoundErr()
1562 oldChild
.nextSibling
= oldChild
.previousSibling
= None 1563 oldChild
.parentNode
= None 1564 if self.documentElement
is oldChild:
1565 self.documentElement
= None 1569 def _get_documentElement(
self):
1570 for node
in self.childNodes:
1571 if node
.nodeType
== Node
.ELEMENT_NODE:
1575 if self.doctype
is not None:
1576 self.doctype
.unlink()
1580 def cloneNode(
self, deep):
1583 clone
= self.implementation
.createDocument(
None,
None,
None)
1584 clone
.encoding
= self.encoding
1585 clone
.standalone
= self.standalone
1586 clone
.version
= self.version
1587 for n
in self.childNodes:
1588 childclone
= _clone_node(n, deep, clone)
1589 assert childclone
.ownerDocument
.isSameNode(clone)
1590 clone
.childNodes
.append(childclone)
1591 if childclone
.nodeType
== Node
.DOCUMENT_NODE:
1592 assert clone
.documentElement
is None 1593 elif childclone
.nodeType
== Node
.DOCUMENT_TYPE_NODE:
1594 assert clone
.doctype
is None 1595 clone
.doctype
= childclone
1596 childclone
.parentNode
= clone
1597 self._call_user_data_handler(xml
.dom
.UserDataHandler
.NODE_CLONED,
1601 def createDocumentFragment(
self):
1602 d
= DocumentFragment()
1603 d
.ownerDocument
= self 1606 def createElement(
self, tagName):
1607 e
= Element(tagName)
1608 e
.ownerDocument
= self 1611 def createTextNode(
self, data):
1612 if not isinstance(data, StringTypes):
1613 raise TypeError,
"node contents must be a string" 1616 t
.ownerDocument
= self 1619 def createCDATASection(
self, data):
1620 if not isinstance(data, StringTypes):
1621 raise TypeError,
"node contents must be a string" 1624 c
.ownerDocument
= self 1627 def createComment(
self, data):
1629 c
.ownerDocument
= self 1632 def createProcessingInstruction(
self, target, data):
1633 p
= ProcessingInstruction(target, data)
1634 p
.ownerDocument
= self 1637 def createAttribute(
self, qName):
1639 a
.ownerDocument
= self 1643 def createElementNS(
self, namespaceURI, qualifiedName):
1644 prefix, localName
= _nssplit(qualifiedName)
1645 e
= Element(qualifiedName, namespaceURI, prefix)
1646 e
.ownerDocument
= self 1649 def createAttributeNS(
self, namespaceURI, qualifiedName):
1650 prefix, localName
= _nssplit(qualifiedName)
1651 a
= Attr(qualifiedName, namespaceURI, localName, prefix)
1652 a
.ownerDocument
= self 1656 # A couple of implementation-specific helpers to create node types 1657 # not supported by the W3C DOM specs: 1659 def _create_entity(
self, name, publicId, systemId, notationName):
1660 e
= Entity(name, publicId, systemId, notationName)
1661 e
.ownerDocument
= self 1664 def _create_notation(
self, name, publicId, systemId):
1665 n
= Notation(name, publicId, systemId)
1666 n
.ownerDocument
= self 1669 def getElementById(
self,
id):
1670 if id in self._id_cache:
1671 return self._id_cache[
id]
1672 if not (
self._elem_info
or self._magic_id_count):
1675 stack
= self._id_search_stack
1677 # we never searched before, or the cache has been cleared 1678 stack
= [
self.documentElement]
1679 self._id_search_stack
= stack
1681 # Previous search was completed and cache is still valid; 1688 # add child elements to stack for continued searching 1689 stack
.extend([child
for child
in node
.childNodes
1690 if child
.nodeType
in _nodeTypes_with_children])
1692 info
= self._get_elem_info(node)
1694 # We have to process all ID attributes before 1695 # returning in order to get all the attributes set to 1696 # be IDs using Element.setIdAttribute*(). 1697 for attr
in node
.attributes
.values():
1698 if attr
.namespaceURI:
1699 if info
.isIdNS(attr
.namespaceURI, attr
.localName):
1700 self._id_cache[attr
.value]
= node
1701 if attr
.value
== id:
1703 elif not node
._magic_id_nodes:
1705 elif info
.isId(attr
.name):
1706 self._id_cache[attr
.value]
= node
1707 if attr
.value
== id:
1709 elif not node
._magic_id_nodes:
1712 self._id_cache[attr
.value]
= node
1713 if attr
.value
== id:
1715 elif node
._magic_id_nodes
== 1:
1717 elif node
._magic_id_nodes:
1718 for attr
in node
.attributes
.values():
1720 self._id_cache[attr
.value]
= node
1721 if attr
.value
== id:
1723 if result
is not None:
1727 def getElementsByTagName(
self, name):
1728 return _get_elements_by_tagName_helper(
self, name, NodeList())
1730 def getElementsByTagNameNS(
self, namespaceURI, localName):
1731 return _get_elements_by_tagName_ns_helper(
1732 self, namespaceURI, localName, NodeList())
1734 def isSupported(
self, feature, version):
1735 return self.implementation
.hasFeature(feature, version)
1737 def importNode(
self, node, deep):
1738 if node
.nodeType
== Node
.DOCUMENT_NODE:
1739 raise xml
.dom
.NotSupportedErr(
"cannot import document nodes")
1740 elif node
.nodeType
== Node
.DOCUMENT_TYPE_NODE:
1741 raise xml
.dom
.NotSupportedErr(
"cannot import document type nodes")
1742 return _clone_node(node, deep,
self)
1744 def writexml(
self, writer, indent
="", addindent
="", newl
="",
1746 if encoding
is None:
1747 writer
.write(
'<?xml version="1.0" ?>'+newl)
1749 writer
.write(
'<?xml version="1.0" encoding="%s"?>%s' % (encoding, newl))
1750 for node
in self.childNodes:
1751 node
.writexml(writer, indent, addindent, newl)
1753 # DOM Level 3 (WD 9 April 2002) 1755 def renameNode(
self, n, namespaceURI, name):
1756 if n
.ownerDocument
is not self:
1757 raise xml
.dom
.WrongDocumentErr(
1758 "cannot rename nodes from other documents;\n" 1759 "expected %s,\nfound %s" % (
self, n
.ownerDocument))
1760 if n
.nodeType
not in (Node
.ELEMENT_NODE, Node
.ATTRIBUTE_NODE):
1761 raise xml
.dom
.NotSupportedErr(
1762 "renameNode() only applies to element and attribute nodes")
1763 if namespaceURI
!= EMPTY_NAMESPACE:
1765 prefix, localName
= name
.split(
':',
1)
1766 if ( prefix
== "xmlns" 1767 and namespaceURI
!= xml
.dom
.XMLNS_NAMESPACE):
1768 raise xml
.dom
.NamespaceErr(
1769 "illegal use of 'xmlns' prefix")
1771 if ( name
== "xmlns" 1772 and namespaceURI
!= xml
.dom
.XMLNS_NAMESPACE
1773 and n
.nodeType
== Node
.ATTRIBUTE_NODE):
1774 raise xml
.dom
.NamespaceErr(
1775 "illegal use of the 'xmlns' attribute")
1781 if n
.nodeType
== Node
.ATTRIBUTE_NODE:
1782 element
= n
.ownerElement
1783 if element
is not None:
1785 element
.removeAttributeNode(n)
1790 d[
'prefix']
= prefix
1791 d[
'localName']
= localName
1792 d[
'namespaceURI']
= namespaceURI
1793 d[
'nodeName']
= name
1794 if n
.nodeType
== Node
.ELEMENT_NODE:
1799 if element
is not None:
1800 element
.setAttributeNode(n)
1802 element
.setIdAttributeNode(n)
1803 # It's not clear from a semantic perspective whether we should 1804 # call the user data handlers for the NODE_RENAMED event since 1805 # we're re-using the existing node. The draft spec has been 1806 # interpreted as meaning "no, don't call the handler unless a 1807 # new node is created." 1810 defproperty(Document,
"documentElement",
1811 doc
="Top-level element of this document.")
1814 def _clone_node(node, deep, newOwnerDocument):
1816 Clone a node and give it the new owner document. 1817 Called by Node.cloneNode and Document.importNode 1819 if node
.ownerDocument
.isSameNode(newOwnerDocument):
1820 operation
= xml
.dom
.UserDataHandler
.NODE_CLONED
1822 operation
= xml
.dom
.UserDataHandler
.NODE_IMPORTED
1823 if node
.nodeType
== Node
.ELEMENT_NODE:
1824 clone
= newOwnerDocument
.createElementNS(node
.namespaceURI,
1826 for attr
in node
.attributes
.values():
1827 clone
.setAttributeNS(attr
.namespaceURI, attr
.nodeName, attr
.value)
1828 a
= clone
.getAttributeNodeNS(attr
.namespaceURI, attr
.localName)
1829 a
.specified
= attr
.specified
1832 for child
in node
.childNodes:
1833 c
= _clone_node(child, deep, newOwnerDocument)
1834 clone
.appendChild(c)
1836 elif node
.nodeType
== Node
.DOCUMENT_FRAGMENT_NODE:
1837 clone
= newOwnerDocument
.createDocumentFragment()
1839 for child
in node
.childNodes:
1840 c
= _clone_node(child, deep, newOwnerDocument)
1841 clone
.appendChild(c)
1843 elif node
.nodeType
== Node
.TEXT_NODE:
1844 clone
= newOwnerDocument
.createTextNode(node
.data)
1845 elif node
.nodeType
== Node
.CDATA_SECTION_NODE:
1846 clone
= newOwnerDocument
.createCDATASection(node
.data)
1847 elif node
.nodeType
== Node
.PROCESSING_INSTRUCTION_NODE:
1848 clone
= newOwnerDocument
.createProcessingInstruction(node
.target,
1850 elif node
.nodeType
== Node
.COMMENT_NODE:
1851 clone
= newOwnerDocument
.createComment(node
.data)
1852 elif node
.nodeType
== Node
.ATTRIBUTE_NODE:
1853 clone
= newOwnerDocument
.createAttributeNS(node
.namespaceURI,
1855 clone
.specified
= True 1856 clone
.value
= node
.value
1857 elif node
.nodeType
== Node
.DOCUMENT_TYPE_NODE:
1858 assert node
.ownerDocument
is not newOwnerDocument
1859 operation
= xml
.dom
.UserDataHandler
.NODE_IMPORTED
1860 clone
= newOwnerDocument
.implementation
.createDocumentType(
1861 node
.name, node
.publicId, node
.systemId)
1862 clone
.ownerDocument
= newOwnerDocument
1864 clone
.entities
._seq
= []
1865 clone
.notations
._seq
= []
1866 for n
in node
.notations
._seq:
1867 notation
= Notation(n
.nodeName, n
.publicId, n
.systemId)
1868 notation
.ownerDocument
= newOwnerDocument
1869 clone
.notations
._seq
.append(notation)
1870 if hasattr(n,
'_call_user_data_handler'):
1871 n
._call_user_data_handler(operation, n, notation)
1872 for e
in node
.entities
._seq:
1873 entity
= Entity(e
.nodeName, e
.publicId, e
.systemId,
1875 entity
.actualEncoding
= e
.actualEncoding
1876 entity
.encoding
= e
.encoding
1877 entity
.version
= e
.version
1878 entity
.ownerDocument
= newOwnerDocument
1879 clone
.entities
._seq
.append(entity)
1880 if hasattr(e,
'_call_user_data_handler'):
1881 e
._call_user_data_handler(operation, n, entity)
1883 # Note the cloning of Document and DocumentType nodes is 1884 # implementation specific. minidom handles those cases 1885 # directly in the cloneNode() methods. 1886 raise xml
.dom
.NotSupportedErr(
"Cannot clone node %s" % repr(node))
1888 # Check for _call_user_data_handler() since this could conceivably 1889 # used with other DOM implementations (one of the FourThought 1891 if hasattr(node,
'_call_user_data_handler'):
1892 node
._call_user_data_handler(operation, node, clone)
1896 def _nssplit(qualifiedName):
1897 fields
= qualifiedName
.split(
':',
1)
1898 if len(fields)
== 2:
1901 return (
None, fields[
0])
1904 def _get_StringIO():
1905 # we can't use cStringIO since it doesn't support Unicode strings 1906 from StringIO import StringIO
1909 def _do_pulldom_parse(func, args, kwargs):
1910 events
= func(
*args,
**kwargs)
1911 toktype, rootNode
= events
.getEvent()
1912 events
.expandNode(rootNode)
1916 def parse(
file, parser
=None, bufsize
=None):
1917 """Parse a file into a DOM by filename or file object.""" 1918 if parser
is None and not bufsize:
1919 from xml.dom import expatbuilder
1920 return expatbuilder
.parse(
file)
1922 from xml.dom import pulldom
1923 return _do_pulldom_parse(pulldom
.parse, (
file,),
1924 {
'parser': parser,
'bufsize': bufsize})
1926 def parseString(string, parser
=None):
1927 """Parse a file into a DOM from a string.""" 1929 from xml.dom import expatbuilder
1930 return expatbuilder
.parseString(string)
1932 from xml.dom import pulldom
1933 return _do_pulldom_parse(pulldom
.parseString, (string,),
1936 def getDOMImplementation(features
=None):
1938 if isinstance(features, StringTypes):
1939 features
= domreg
._parse_feature_string(features)
1940 for f, v
in features:
1941 if not Document
.implementation
.hasFeature(f, v):
1943 return Document
.implementation