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
21 from xml
.dom
import HierarchyRequestErr
, EMPTY_NAMESPACE
23 # localize the types, and allow support for Unicode values if available:
25 _TupleType
= types
.TupleType
27 _StringTypes
= (types
.StringType
, types
.UnicodeType
)
28 except AttributeError:
29 _StringTypes
= (types
.StringType
,)
37 def item(self
, index
):
38 if 0 <= index
< len(self
):
41 length
= property(lambda self
: len(self
),
42 doc
="The number of nodes in the NodeList.")
49 class Node(xml
.dom
.Node
):
55 namespaceURI
= None # this is non-null only for elements and attributes
60 self
.childNodes
= NodeList()
62 index
= repr(id(self
)) + repr(self
.__class
__)
63 Node
.allnodes
[index
] = repr(self
.__dict
__)
64 if Node
.debug
is None:
65 Node
.debug
= _get_StringIO()
66 #open("debug4.out", "w")
67 Node
.debug
.write("create %s\n" % index
)
69 def __nonzero__(self
):
73 writer
= _get_StringIO()
75 return writer
.getvalue()
77 def toprettyxml(self
, indent
="\t", newl
="\n"):
78 # indent = the indentation string to prepend, per level
79 # newl = the newline string to append
80 writer
= _get_StringIO()
81 self
.writexml(writer
, "", indent
, newl
)
82 return writer
.getvalue()
84 def hasChildNodes(self
):
90 def _get_firstChild(self
):
92 return self
.childNodes
[0]
94 def _get_lastChild(self
):
96 return self
.childNodes
[-1]
101 def __getattr__(self
, key
):
103 raise AttributeError, key
104 # getattr should never call getattr!
105 if self
.__dict
__.has_key("inGetAttr"):
107 raise AttributeError, key
109 prefix
, attrname
= key
[:5], key
[5:]
110 if prefix
== "_get_":
112 if hasattr(self
, attrname
):
114 return (lambda self
=self
, attrname
=attrname
:
115 getattr(self
, attrname
))
118 raise AttributeError, key
122 func
= getattr(self
, "_get_" + key
)
123 except AttributeError:
124 raise AttributeError, key
128 firstChild
= property(_get_firstChild
,
129 doc
="First child node, or None.")
130 lastChild
= property(_get_lastChild
,
131 doc
="Last child node, or None.")
133 def insertBefore(self
, newChild
, refChild
):
134 if newChild
.nodeType
== self
.DOCUMENT_FRAGMENT_NODE
:
135 for c
in tuple(newChild
.childNodes
):
136 self
.insertBefore(c
, refChild
)
137 ### The DOM does not clearly specify what to return in this case
139 if newChild
.nodeType
not in self
.childNodeTypes
:
140 raise HierarchyRequestErr
, \
141 "%s cannot be child of %s" % (repr(newChild
), repr(self
))
142 if newChild
.parentNode
is not None:
143 newChild
.parentNode
.removeChild(newChild
)
145 self
.appendChild(newChild
)
147 index
= self
.childNodes
.index(refChild
)
148 self
.childNodes
.insert(index
, newChild
)
149 newChild
.nextSibling
= refChild
150 refChild
.previousSibling
= newChild
152 node
= self
.childNodes
[index
-1]
153 node
.nextSibling
= newChild
154 newChild
.previousSibling
= node
156 newChild
.previousSibling
= None
157 if self
._makeParentNodes
:
158 newChild
.parentNode
= self
161 def appendChild(self
, node
):
162 if node
.nodeType
== self
.DOCUMENT_FRAGMENT_NODE
:
163 for c
in tuple(node
.childNodes
):
165 ### The DOM does not clearly specify what to return in this case
167 if node
.nodeType
not in self
.childNodeTypes
:
168 raise HierarchyRequestErr
, \
169 "%s cannot be child of %s" % (repr(node
), repr(self
))
170 if node
.parentNode
is not None:
171 node
.parentNode
.removeChild(node
)
173 last
= self
.lastChild
174 node
.previousSibling
= last
175 last
.nextSibling
= node
177 node
.previousSibling
= None
178 node
.nextSibling
= None
179 self
.childNodes
.append(node
)
180 if self
._makeParentNodes
:
181 node
.parentNode
= self
184 def replaceChild(self
, newChild
, oldChild
):
185 if newChild
.nodeType
== self
.DOCUMENT_FRAGMENT_NODE
:
186 refChild
= oldChild
.nextSibling
187 self
.removeChild(oldChild
)
188 return self
.insertBefore(newChild
, refChild
)
189 if newChild
.nodeType
not in self
.childNodeTypes
:
190 raise HierarchyRequestErr
, \
191 "%s cannot be child of %s" % (repr(newChild
), repr(self
))
192 if newChild
.parentNode
is not None:
193 newChild
.parentNode
.removeChild(newChild
)
194 if newChild
is oldChild
:
196 index
= self
.childNodes
.index(oldChild
)
197 self
.childNodes
[index
] = newChild
198 if self
._makeParentNodes
:
199 newChild
.parentNode
= self
200 oldChild
.parentNode
= None
201 newChild
.nextSibling
= oldChild
.nextSibling
202 newChild
.previousSibling
= oldChild
.previousSibling
203 oldChild
.nextSibling
= None
204 oldChild
.previousSibling
= None
205 if newChild
.previousSibling
:
206 newChild
.previousSibling
.nextSibling
= newChild
207 if newChild
.nextSibling
:
208 newChild
.nextSibling
.previousSibling
= newChild
211 def removeChild(self
, oldChild
):
212 self
.childNodes
.remove(oldChild
)
213 if oldChild
.nextSibling
is not None:
214 oldChild
.nextSibling
.previousSibling
= oldChild
.previousSibling
215 if oldChild
.previousSibling
is not None:
216 oldChild
.previousSibling
.nextSibling
= oldChild
.nextSibling
217 oldChild
.nextSibling
= oldChild
.previousSibling
= None
219 if self
._makeParentNodes
:
220 oldChild
.parentNode
= None
225 for child
in self
.childNodes
:
226 if child
.nodeType
== Node
.TEXT_NODE
:
228 if data
and L
and L
[-1].nodeType
== child
.nodeType
:
231 node
.data
= node
.nodeValue
= node
.data
+ child
.data
232 node
.nextSibling
= child
.nextSibling
236 L
[-1].nextSibling
= child
237 child
.previousSibling
= L
[-1]
239 child
.previousSibling
= None
242 # empty text node; discard
246 L
[-1].nextSibling
= child
247 child
.previousSibling
= L
[-1]
249 child
.previousSibling
= None
251 if child
.nodeType
== Node
.ELEMENT_NODE
:
253 self
.childNodes
[:] = L
255 def cloneNode(self
, deep
):
257 clone
= new
.instance(self
.__class
__, self
.__dict
__.copy())
258 if self
._makeParentNodes
:
259 clone
.parentNode
= None
260 clone
.childNodes
= NodeList()
262 for child
in self
.childNodes
:
263 clone
.appendChild(child
.cloneNode(1))
266 # DOM Level 3 (Working Draft 2001-Jan-26)
268 def isSameNode(self
, other
):
271 # minidom-specific API:
274 self
.parentNode
= self
.ownerDocument
= None
275 for child
in self
.childNodes
:
277 self
.childNodes
= None
278 self
.previousSibling
= None
279 self
.nextSibling
= None
281 index
= repr(id(self
)) + repr(self
.__class
__)
282 self
.debug
.write("Deleting: %s\n" % index
)
283 del Node
.allnodes
[index
]
285 def _write_data(writer
, data
):
286 "Writes datachars to writer."
287 replace
= _string
.replace
288 data
= replace(data
, "&", "&")
289 data
= replace(data
, "<", "<")
290 data
= replace(data
, "\"", """)
291 data
= replace(data
, ">", ">")
294 def _getElementsByTagNameHelper(parent
, name
, rc
):
295 for node
in parent
.childNodes
:
296 if node
.nodeType
== Node
.ELEMENT_NODE
and \
297 (name
== "*" or node
.tagName
== name
):
299 _getElementsByTagNameHelper(node
, name
, rc
)
302 def _getElementsByTagNameNSHelper(parent
, nsURI
, localName
, rc
):
303 for node
in parent
.childNodes
:
304 if node
.nodeType
== Node
.ELEMENT_NODE
:
305 if ((localName
== "*" or node
.localName
== localName
) and
306 (nsURI
== "*" or node
.namespaceURI
== nsURI
)):
308 _getElementsByTagNameNSHelper(node
, nsURI
, localName
, rc
)
311 class DocumentFragment(Node
):
312 nodeType
= Node
.DOCUMENT_FRAGMENT_NODE
313 nodeName
= "#document-fragment"
317 childNodeTypes
= (Node
.ELEMENT_NODE
,
319 Node
.CDATA_SECTION_NODE
,
320 Node
.ENTITY_REFERENCE_NODE
,
321 Node
.PROCESSING_INSTRUCTION_NODE
,
327 nodeType
= Node
.ATTRIBUTE_NODE
330 childNodeTypes
= (Node
.TEXT_NODE
, Node
.ENTITY_REFERENCE_NODE
)
332 def __init__(self
, qName
, namespaceURI
=EMPTY_NAMESPACE
, localName
=None, prefix
=None):
333 # skip setattr for performance
335 d
["localName"] = localName
or qName
336 d
["nodeName"] = d
["name"] = qName
337 d
["namespaceURI"] = namespaceURI
340 # nodeValue and value are set elsewhere
342 def __setattr__(self
, name
, value
):
344 if name
in ("value", "nodeValue"):
345 d
["value"] = d
["nodeValue"] = value
346 elif name
in ("name", "nodeName"):
347 d
["name"] = d
["nodeName"] = value
351 def cloneNode(self
, deep
):
352 clone
= Node
.cloneNode(self
, deep
)
353 if clone
.__dict
__.has_key("ownerElement"):
354 del clone
.ownerElement
359 """The attribute list is a transient interface to the underlying
360 dictionaries. Mutations here will change the underlying element's
363 Ordering is imposed artificially and does not reflect the order of
364 attributes as found in an input document.
367 def __init__(self
, attrs
, attrsNS
, ownerElement
):
369 self
._attrsNS
= attrsNS
370 self
._ownerElement
= ownerElement
375 def __getattr__(self
, name
):
377 return len(self
._attrs
)
378 raise AttributeError, name
380 length
= property(lambda self
: len(self
._attrs
),
381 doc
="Number of nodes in the NamedNodeMap.")
383 def item(self
, index
):
385 return self
[self
._attrs
.keys()[index
]]
391 for node
in self
._attrs
.values():
392 L
.append((node
.nodeName
, node
.value
))
397 for node
in self
._attrs
.values():
398 L
.append(((node
.namespaceURI
, node
.localName
), node
.value
))
402 return self
._attrs
.keys()
405 return self
._attrsNS
.keys()
408 return self
._attrs
.values()
410 def get(self
, name
, value
= None):
411 return self
._attrs
.get(name
, value
)
416 def __cmp__(self
, other
):
417 if self
._attrs
is getattr(other
, "_attrs", None):
420 return cmp(id(self
), id(other
))
422 #FIXME: is it appropriate to return .value?
423 def __getitem__(self
, attname_or_tuple
):
424 if type(attname_or_tuple
) is _TupleType
:
425 return self
._attrsNS
[attname_or_tuple
]
427 return self
._attrs
[attname_or_tuple
]
430 def __setitem__(self
, attname
, value
):
431 if type(value
) in _StringTypes
:
434 node
.ownerDocument
= self
._ownerElement
.ownerDocument
436 if not isinstance(value
, Attr
):
437 raise TypeError, "value must be a string or Attr object"
439 self
.setNamedItem(node
)
441 def setNamedItem(self
, node
):
442 if not isinstance(node
, Attr
):
443 raise HierarchyRequestErr
, \
444 "%s cannot be child of %s" % (repr(node
), repr(self
))
445 old
= self
._attrs
.get(node
.name
)
448 self
._attrs
[node
.name
] = node
449 self
._attrsNS
[(node
.namespaceURI
, node
.localName
)] = node
450 node
.ownerElement
= self
._ownerElement
453 def setNamedItemNS(self
, node
):
454 return self
.setNamedItem(node
)
456 def __delitem__(self
, attname_or_tuple
):
457 node
= self
[attname_or_tuple
]
459 del self
._attrs
[node
.name
]
460 del self
._attrsNS
[(node
.namespaceURI
, node
.localName
)]
461 self
.length
= len(self
._attrs
)
463 AttributeList
= NamedNodeMap
467 nodeType
= Node
.ELEMENT_NODE
469 previousSibling
= None
470 childNodeTypes
= (Node
.ELEMENT_NODE
, Node
.PROCESSING_INSTRUCTION_NODE
,
471 Node
.COMMENT_NODE
, Node
.TEXT_NODE
,
472 Node
.CDATA_SECTION_NODE
, Node
.ENTITY_REFERENCE_NODE
)
474 def __init__(self
, tagName
, namespaceURI
=EMPTY_NAMESPACE
, prefix
=None,
477 self
.tagName
= self
.nodeName
= tagName
478 self
.localName
= localName
or tagName
480 self
.namespaceURI
= namespaceURI
481 self
.nodeValue
= None
483 self
._attrs
= {} # attributes are double-indexed:
484 self
._attrsNS
= {} # tagName -> Attribute
485 # URI,localName -> Attribute
486 # in the future: consider lazy generation
487 # of attribute objects this is too tricky
488 # for now because of headaches with
491 def cloneNode(self
, deep
):
492 clone
= Node
.cloneNode(self
, deep
)
495 for attr
in self
._attrs
.values():
496 node
= attr
.cloneNode(1)
497 clone
._attrs
[node
.name
] = node
498 clone
._attrsNS
[(node
.namespaceURI
, node
.localName
)] = node
499 node
.ownerElement
= clone
503 for attr
in self
._attrs
.values():
509 def getAttribute(self
, attname
):
511 return self
._attrs
[attname
].value
515 def getAttributeNS(self
, namespaceURI
, localName
):
517 return self
._attrsNS
[(namespaceURI
, localName
)].value
521 def setAttribute(self
, attname
, value
):
525 d
["value"] = d
["nodeValue"] = value
526 d
["ownerDocument"] = self
.ownerDocument
527 self
.setAttributeNode(attr
)
529 def setAttributeNS(self
, namespaceURI
, qualifiedName
, value
):
530 prefix
, localname
= _nssplit(qualifiedName
)
532 attr
= Attr(qualifiedName
, namespaceURI
, localname
, prefix
)
534 d
["value"] = d
["nodeValue"] = value
535 d
["ownerDocument"] = self
.ownerDocument
536 self
.setAttributeNode(attr
)
538 def getAttributeNode(self
, attrname
):
539 return self
._attrs
.get(attrname
)
541 def getAttributeNodeNS(self
, namespaceURI
, localName
):
542 return self
._attrsNS
.get((namespaceURI
, localName
))
544 def setAttributeNode(self
, attr
):
545 if attr
.ownerElement
not in (None, self
):
546 raise xml
.dom
.InuseAttributeErr("attribute node already owned")
547 old
= self
._attrs
.get(attr
.name
, None)
550 self
._attrs
[attr
.name
] = attr
551 self
._attrsNS
[(attr
.namespaceURI
, attr
.localName
)] = attr
553 # This creates a circular reference, but Element.unlink()
554 # breaks the cycle since the references to the attribute
555 # dictionaries are tossed.
556 attr
.ownerElement
= self
559 # It might have already been part of this node, in which case
560 # it doesn't represent a change, and should not be returned.
563 setAttributeNodeNS
= setAttributeNode
565 def removeAttribute(self
, name
):
566 attr
= self
._attrs
[name
]
567 self
.removeAttributeNode(attr
)
569 def removeAttributeNS(self
, namespaceURI
, localName
):
570 attr
= self
._attrsNS
[(namespaceURI
, localName
)]
571 self
.removeAttributeNode(attr
)
573 def removeAttributeNode(self
, node
):
575 del self
._attrs
[node
.name
]
576 del self
._attrsNS
[(node
.namespaceURI
, node
.localName
)]
578 removeAttributeNodeNS
= removeAttributeNode
580 def hasAttribute(self
, name
):
581 return self
._attrs
.has_key(name
)
583 def hasAttributeNS(self
, namespaceURI
, localName
):
584 return self
._attrsNS
.has_key((namespaceURI
, localName
))
586 def getElementsByTagName(self
, name
):
587 return _getElementsByTagNameHelper(self
, name
, [])
589 def getElementsByTagNameNS(self
, namespaceURI
, localName
):
590 return _getElementsByTagNameNSHelper(self
, namespaceURI
, localName
, [])
593 return "<DOM Element: %s at %s>" % (self
.tagName
, id(self
))
595 def writexml(self
, writer
, indent
="", addindent
="", newl
=""):
596 # indent = current indentation
597 # addindent = indentation to add to higher levels
598 # newl = newline string
599 writer
.write(indent
+"<" + self
.tagName
)
601 attrs
= self
._get
_attributes
()
602 a_names
= attrs
.keys()
605 for a_name
in a_names
:
606 writer
.write(" %s=\"" % a_name
)
607 _write_data(writer
, attrs
[a_name
].value
)
610 writer
.write(">%s"%(newl))
611 for node
in self
.childNodes
:
612 node
.writexml(writer
,indent
+addindent
,addindent
,newl
)
613 writer
.write("%s</%s>%s" % (indent
,self
.tagName
,newl
))
615 writer
.write("/>%s"%(newl))
617 def _get_attributes(self
):
618 return NamedNodeMap(self
._attrs
, self
._attrsNS
, self
)
625 attributes
= property(_get_attributes
,
626 doc
="NamedNodeMap of attributes on the element.")
628 def hasAttributes(self
):
629 if self
._attrs
or self
._attrsNS
:
635 nodeType
= Node
.COMMENT_NODE
636 nodeName
= "#comment"
640 def __init__(self
, data
):
642 self
.data
= self
.nodeValue
= data
644 def writexml(self
, writer
, indent
="", addindent
="", newl
=""):
645 writer
.write("%s<!--%s-->%s" % (indent
,self
.data
,newl
))
647 class ProcessingInstruction(Node
):
648 nodeType
= Node
.PROCESSING_INSTRUCTION_NODE
652 def __init__(self
, target
, data
):
654 self
.target
= self
.nodeName
= target
655 self
.data
= self
.nodeValue
= data
657 def writexml(self
, writer
, indent
="", addindent
="", newl
=""):
658 writer
.write("%s<?%s %s?>%s" % (indent
,self
.target
, self
.data
, newl
))
660 class CharacterData(Node
):
661 def __init__(self
, data
):
662 if type(data
) not in _StringTypes
:
663 raise TypeError, "node contents must be a string"
665 self
.data
= self
.nodeValue
= data
666 self
.length
= len(data
)
669 if len(self
.data
) > 10:
673 return "<DOM %s node \"%s%s\">" % (
674 self
.__class
__.__name
__, self
.data
[0:10], dotdotdot
)
676 def substringData(self
, offset
, count
):
678 raise xml
.dom
.IndexSizeErr("offset cannot be negative")
679 if offset
>= len(self
.data
):
680 raise xml
.dom
.IndexSizeErr("offset cannot be beyond end of data")
682 raise xml
.dom
.IndexSizeErr("count cannot be negative")
683 return self
.data
[offset
:offset
+count
]
685 def appendData(self
, arg
):
686 self
.data
= self
.data
+ arg
687 self
.nodeValue
= self
.data
688 self
.length
= len(self
.data
)
690 def insertData(self
, offset
, arg
):
692 raise xml
.dom
.IndexSizeErr("offset cannot be negative")
693 if offset
>= len(self
.data
):
694 raise xml
.dom
.IndexSizeErr("offset cannot be beyond end of data")
696 self
.data
= "%s%s%s" % (
697 self
.data
[:offset
], arg
, self
.data
[offset
:])
698 self
.nodeValue
= self
.data
699 self
.length
= len(self
.data
)
701 def deleteData(self
, offset
, count
):
703 raise xml
.dom
.IndexSizeErr("offset cannot be negative")
704 if offset
>= len(self
.data
):
705 raise xml
.dom
.IndexSizeErr("offset cannot be beyond end of data")
707 raise xml
.dom
.IndexSizeErr("count cannot be negative")
709 self
.data
= self
.data
[:offset
] + self
.data
[offset
+count
:]
710 self
.nodeValue
= self
.data
711 self
.length
= len(self
.data
)
713 def replaceData(self
, offset
, count
, arg
):
715 raise xml
.dom
.IndexSizeErr("offset cannot be negative")
716 if offset
>= len(self
.data
):
717 raise xml
.dom
.IndexSizeErr("offset cannot be beyond end of data")
719 raise xml
.dom
.IndexSizeErr("count cannot be negative")
721 self
.data
= "%s%s%s" % (
722 self
.data
[:offset
], arg
, self
.data
[offset
+count
:])
723 self
.nodeValue
= self
.data
724 self
.length
= len(self
.data
)
726 class Text(CharacterData
):
727 nodeType
= Node
.TEXT_NODE
732 def splitText(self
, offset
):
733 if offset
< 0 or offset
> len(self
.data
):
734 raise xml
.dom
.IndexSizeErr("illegal offset value")
735 newText
= Text(self
.data
[offset
:])
736 next
= self
.nextSibling
737 if self
.parentNode
and self
in self
.parentNode
.childNodes
:
739 self
.parentNode
.appendChild(newText
)
741 self
.parentNode
.insertBefore(newText
, next
)
742 self
.data
= self
.data
[:offset
]
743 self
.nodeValue
= self
.data
744 self
.length
= len(self
.data
)
747 def writexml(self
, writer
, indent
="", addindent
="", newl
=""):
748 _write_data(writer
, "%s%s%s"%(indent
, self
.data
, newl
))
751 class CDATASection(Text
):
752 nodeType
= Node
.CDATA_SECTION_NODE
753 nodeName
= "#cdata-section"
755 def writexml(self
, writer
, indent
="", addindent
="", newl
=""):
756 writer
.write("<![CDATA[%s]]>" % self
.data
)
759 def _nssplit(qualifiedName
):
760 fields
= _string
.split(qualifiedName
, ':', 1)
763 elif len(fields
) == 1:
764 return (None, fields
[0])
767 class DocumentType(Node
):
768 nodeType
= Node
.DOCUMENT_TYPE_NODE
774 internalSubset
= None
778 def __init__(self
, qualifiedName
):
781 prefix
, localname
= _nssplit(qualifiedName
)
782 self
.name
= localname
785 class DOMImplementation
:
786 def hasFeature(self
, feature
, version
):
787 if version
not in ("1.0", "2.0"):
789 feature
= _string
.lower(feature
)
790 return feature
== "core"
792 def createDocument(self
, namespaceURI
, qualifiedName
, doctype
):
793 if doctype
and doctype
.parentNode
is not None:
794 raise xml
.dom
.WrongDocumentErr(
795 "doctype object owned by another DOM tree")
796 doc
= self
._createDocument
()
798 doctype
= self
.createDocumentType(qualifiedName
, None, None)
799 if not qualifiedName
:
800 # The spec is unclear what to raise here; SyntaxErr
801 # would be the other obvious candidate. Since Xerces raises
802 # InvalidCharacterErr, and since SyntaxErr is not listed
803 # for createDocument, that seems to be the better choice.
804 # XXX: need to check for illegal characters here and in
806 raise xml
.dom
.InvalidCharacterErr("Element with no name")
807 prefix
, localname
= _nssplit(qualifiedName
)
809 and namespaceURI
!= "http://www.w3.org/XML/1998/namespace":
810 raise xml
.dom
.NamespaceErr("illegal use of 'xml' prefix")
811 if prefix
and not namespaceURI
:
812 raise xml
.dom
.NamespaceErr(
813 "illegal use of prefix without namespaces")
814 element
= doc
.createElementNS(namespaceURI
, qualifiedName
)
815 doc
.appendChild(element
)
816 doctype
.parentNode
= doctype
.ownerDocument
= doc
817 doc
.doctype
= doctype
818 doc
.implementation
= self
821 def createDocumentType(self
, qualifiedName
, publicId
, systemId
):
822 doctype
= DocumentType(qualifiedName
)
823 doctype
.publicId
= publicId
824 doctype
.systemId
= systemId
828 def _createDocument(self
):
831 class Document(Node
):
832 nodeType
= Node
.DOCUMENT_NODE
833 nodeName
= "#document"
838 previousSibling
= nextSibling
= None
840 implementation
= DOMImplementation()
841 childNodeTypes
= (Node
.ELEMENT_NODE
, Node
.PROCESSING_INSTRUCTION_NODE
,
842 Node
.COMMENT_NODE
, Node
.DOCUMENT_TYPE_NODE
)
844 def appendChild(self
, node
):
845 if node
.nodeType
not in self
.childNodeTypes
:
846 raise HierarchyRequestErr
, \
847 "%s cannot be child of %s" % (repr(node
), repr(self
))
848 if node
.parentNode
is not None:
849 node
.parentNode
.removeChild(node
)
851 if node
.nodeType
== Node
.ELEMENT_NODE \
852 and self
._get
_documentElement
():
853 raise xml
.dom
.HierarchyRequestErr(
854 "two document elements disallowed")
855 return Node
.appendChild(self
, node
)
857 def removeChild(self
, oldChild
):
858 self
.childNodes
.remove(oldChild
)
859 oldChild
.nextSibling
= oldChild
.previousSibling
= None
860 oldChild
.parentNode
= None
861 if self
.documentElement
is oldChild
:
862 self
.documentElement
= None
866 def _get_documentElement(self
):
867 for node
in self
.childNodes
:
868 if node
.nodeType
== Node
.ELEMENT_NODE
:
876 documentElement
= property(_get_documentElement
,
877 doc
="Top-level element of this document.")
880 if self
.doctype
is not None:
881 self
.doctype
.unlink()
885 def createDocumentFragment(self
):
886 d
= DocumentFragment()
890 def createElement(self
, tagName
):
892 e
.ownerDocument
= self
895 def createTextNode(self
, data
):
897 t
.ownerDocument
= self
900 def createCDATASection(self
, data
):
901 c
= CDATASection(data
)
902 c
.ownerDocument
= self
905 def createComment(self
, data
):
907 c
.ownerDocument
= self
910 def createProcessingInstruction(self
, target
, data
):
911 p
= ProcessingInstruction(target
, data
)
912 p
.ownerDocument
= self
915 def createAttribute(self
, qName
):
917 a
.ownerDocument
= self
921 def createElementNS(self
, namespaceURI
, qualifiedName
):
922 prefix
, localName
= _nssplit(qualifiedName
)
923 e
= Element(qualifiedName
, namespaceURI
, prefix
, localName
)
924 e
.ownerDocument
= self
927 def createAttributeNS(self
, namespaceURI
, qualifiedName
):
928 prefix
, localName
= _nssplit(qualifiedName
)
929 a
= Attr(qualifiedName
, namespaceURI
, localName
, prefix
)
930 a
.ownerDocument
= self
934 def getElementsByTagName(self
, name
):
935 return _getElementsByTagNameHelper(self
, name
, [])
937 def getElementsByTagNameNS(self
, namespaceURI
, localName
):
938 return _getElementsByTagNameNSHelper(self
, namespaceURI
, localName
, [])
940 def writexml(self
, writer
, indent
="", addindent
="", newl
=""):
941 writer
.write('<?xml version="1.0" ?>\n')
942 for node
in self
.childNodes
:
943 node
.writexml(writer
, indent
, addindent
, newl
)
946 # we can't use cStringIO since it doesn't support Unicode strings
947 from StringIO
import StringIO
950 def _doparse(func
, args
, kwargs
):
951 events
= apply(func
, args
, kwargs
)
952 toktype
, rootNode
= events
.getEvent()
953 events
.expandNode(rootNode
)
957 def parse(*args
, **kwargs
):
958 """Parse a file into a DOM by filename or file object."""
959 from xml
.dom
import pulldom
960 return _doparse(pulldom
.parse
, args
, kwargs
)
962 def parseString(*args
, **kwargs
):
963 """Parse a file into a DOM from a string."""
964 from xml
.dom
import pulldom
965 return _doparse(pulldom
.parseString
, args
, kwargs
)
967 def getDOMImplementation():
968 return Document
.implementation