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
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
,)
41 namespaceURI
= None # this is non-null only for elements and attributes
45 self
.parentNode
= self
.ownerDocument
= None
47 index
= repr(id(self
)) + repr(self
.__class
__)
48 Node
.allnodes
[index
] = repr(self
.__dict
__)
49 if Node
.debug
is None:
50 Node
.debug
= _get_StringIO()
51 #open("debug4.out", "w")
52 Node
.debug
.write("create %s\n" % index
)
54 def __getattr__(self
, key
):
56 raise AttributeError, key
57 # getattr should never call getattr!
58 if self
.__dict
__.has_key("inGetAttr"):
60 raise AttributeError, key
62 prefix
, attrname
= key
[:5], key
[5:]
65 if hasattr(self
, attrname
):
67 return (lambda self
=self
, attrname
=attrname
:
68 getattr(self
, attrname
))
71 raise AttributeError, key
75 func
= getattr(self
, "_get_" + key
)
76 except AttributeError:
77 raise AttributeError, key
81 def __nonzero__(self
):
85 writer
= _get_StringIO()
87 return writer
.getvalue()
89 def toprettyxml(self
, indent
="\t", newl
="\n"):
90 # indent = the indentation string to prepend, per level
91 # newl = the newline string to append
92 writer
= _get_StringIO()
93 self
.writexml(writer
, "", indent
, newl
)
94 return writer
.getvalue()
96 def hasChildNodes(self
):
102 def _get_firstChild(self
):
104 return self
.childNodes
[0]
106 def _get_lastChild(self
):
108 return self
.childNodes
[-1]
110 def insertBefore(self
, newChild
, refChild
):
111 if newChild
.nodeType
== self
.DOCUMENT_FRAGMENT_NODE
:
112 for c
in newChild
.childNodes
:
113 self
.insertBefore(c
, refChild
)
114 ### The DOM does not clearly specify what to return in this case
116 if newChild
.nodeType
not in self
.childNodeTypes
:
117 raise HierarchyRequestErr
, \
118 "%s cannot be child of %s" % (repr(newChild
), repr(self
))
119 if newChild
.parentNode
is not None:
120 newChild
.parentNode
.removeChild(newChild
)
122 self
.appendChild(newChild
)
124 index
= self
.childNodes
.index(refChild
)
125 self
.childNodes
.insert(index
, newChild
)
126 newChild
.nextSibling
= refChild
127 refChild
.previousSibling
= newChild
129 node
= self
.childNodes
[index
-1]
130 node
.nextSibling
= newChild
131 newChild
.previousSibling
= node
133 newChild
.previousSibling
= None
134 if self
._makeParentNodes
:
135 newChild
.parentNode
= self
138 def appendChild(self
, node
):
139 if node
.nodeType
== self
.DOCUMENT_FRAGMENT_NODE
:
140 for c
in node
.childNodes
:
142 ### The DOM does not clearly specify what to return in this case
144 if node
.nodeType
not in self
.childNodeTypes
:
145 raise HierarchyRequestErr
, \
146 "%s cannot be child of %s" % (repr(node
), repr(self
))
147 if node
.parentNode
is not None:
148 node
.parentNode
.removeChild(node
)
150 last
= self
.lastChild
151 node
.previousSibling
= last
152 last
.nextSibling
= node
154 node
.previousSibling
= None
155 node
.nextSibling
= None
156 self
.childNodes
.append(node
)
157 if self
._makeParentNodes
:
158 node
.parentNode
= self
161 def replaceChild(self
, newChild
, oldChild
):
162 if newChild
.nodeType
== self
.DOCUMENT_FRAGMENT_NODE
:
163 refChild
= oldChild
.nextSibling
164 self
.removeChild(oldChild
)
165 return self
.insertBefore(newChild
, refChild
)
166 if newChild
.nodeType
not in self
.childNodeTypes
:
167 raise HierarchyRequestErr
, \
168 "%s cannot be child of %s" % (repr(newChild
), repr(self
))
169 if newChild
.parentNode
is not None:
170 newChild
.parentNode
.removeChild(newChild
)
171 if newChild
is oldChild
:
173 index
= self
.childNodes
.index(oldChild
)
174 self
.childNodes
[index
] = newChild
175 if self
._makeParentNodes
:
176 newChild
.parentNode
= self
177 oldChild
.parentNode
= None
178 newChild
.nextSibling
= oldChild
.nextSibling
179 newChild
.previousSibling
= oldChild
.previousSibling
180 oldChild
.nextSibling
= None
181 oldChild
.previousSibling
= None
182 if newChild
.previousSibling
:
183 newChild
.previousSibling
.nextSibling
= newChild
184 if newChild
.nextSibling
:
185 newChild
.nextSibling
.previousSibling
= newChild
188 def removeChild(self
, oldChild
):
189 self
.childNodes
.remove(oldChild
)
190 if oldChild
.nextSibling
is not None:
191 oldChild
.nextSibling
.previousSibling
= oldChild
.previousSibling
192 if oldChild
.previousSibling
is not None:
193 oldChild
.previousSibling
.nextSibling
= oldChild
.nextSibling
194 oldChild
.nextSibling
= oldChild
.previousSibling
= None
196 if self
._makeParentNodes
:
197 oldChild
.parentNode
= None
202 for child
in self
.childNodes
:
203 if child
.nodeType
== Node
.TEXT_NODE
:
205 if data
and L
and L
[-1].nodeType
== child
.nodeType
:
208 node
.data
= node
.nodeValue
= node
.data
+ child
.data
209 node
.nextSibling
= child
.nextSibling
213 L
[-1].nextSibling
= child
214 child
.previousSibling
= L
[-1]
216 child
.previousSibling
= None
219 # empty text node; discard
223 L
[-1].nextSibling
= child
224 child
.previousSibling
= L
[-1]
226 child
.previousSibling
= None
228 if child
.nodeType
== Node
.ELEMENT_NODE
:
230 self
.childNodes
[:] = L
232 def cloneNode(self
, deep
):
234 clone
= new
.instance(self
.__class
__, self
.__dict
__.copy())
235 if self
._makeParentNodes
:
236 clone
.parentNode
= None
237 clone
.childNodes
= []
239 for child
in self
.childNodes
:
240 clone
.appendChild(child
.cloneNode(1))
243 # DOM Level 3 (Working Draft 2001-Jan-26)
245 def isSameNode(self
, other
):
248 # minidom-specific API:
251 self
.parentNode
= self
.ownerDocument
= None
252 for child
in self
.childNodes
:
254 self
.childNodes
= None
255 self
.previousSibling
= None
256 self
.nextSibling
= None
258 index
= repr(id(self
)) + repr(self
.__class
__)
259 self
.debug
.write("Deleting: %s\n" % index
)
260 del Node
.allnodes
[index
]
262 def _write_data(writer
, data
):
263 "Writes datachars to writer."
264 replace
= _string
.replace
265 data
= replace(data
, "&", "&")
266 data
= replace(data
, "<", "<")
267 data
= replace(data
, "\"", """)
268 data
= replace(data
, ">", ">")
271 def _getElementsByTagNameHelper(parent
, name
, rc
):
272 for node
in parent
.childNodes
:
273 if node
.nodeType
== Node
.ELEMENT_NODE
and \
274 (name
== "*" or node
.tagName
== name
):
276 _getElementsByTagNameHelper(node
, name
, rc
)
279 def _getElementsByTagNameNSHelper(parent
, nsURI
, localName
, rc
):
280 for node
in parent
.childNodes
:
281 if node
.nodeType
== Node
.ELEMENT_NODE
:
282 if ((localName
== "*" or node
.localName
== localName
) and
283 (nsURI
== "*" or node
.namespaceURI
== nsURI
)):
285 _getElementsByTagNameNSHelper(node
, nsURI
, localName
, rc
)
288 class DocumentFragment(Node
):
289 nodeType
= Node
.DOCUMENT_FRAGMENT_NODE
290 nodeName
= "#document-fragment"
294 childNodeTypes
= (Node
.ELEMENT_NODE
,
296 Node
.CDATA_SECTION_NODE
,
297 Node
.ENTITY_REFERENCE_NODE
,
298 Node
.PROCESSING_INSTRUCTION_NODE
,
304 nodeType
= Node
.ATTRIBUTE_NODE
307 childNodeTypes
= (Node
.TEXT_NODE
, Node
.ENTITY_REFERENCE_NODE
)
309 def __init__(self
, qName
, namespaceURI
="", localName
=None, prefix
=None):
310 # skip setattr for performance
312 d
["localName"] = localName
or qName
313 d
["nodeName"] = d
["name"] = qName
314 d
["namespaceURI"] = namespaceURI
317 # nodeValue and value are set elsewhere
319 def __setattr__(self
, name
, value
):
321 if name
in ("value", "nodeValue"):
322 d
["value"] = d
["nodeValue"] = value
323 elif name
in ("name", "nodeName"):
324 d
["name"] = d
["nodeName"] = value
328 def cloneNode(self
, deep
):
329 clone
= Node
.cloneNode(self
, deep
)
330 if clone
.__dict
__.has_key("ownerElement"):
331 del clone
.ownerElement
336 """The attribute list is a transient interface to the underlying
337 dictionaries. Mutations here will change the underlying element's
340 Ordering is imposed artificially and does not reflect the order of
341 attributes as found in an input document.
344 def __init__(self
, attrs
, attrsNS
):
346 self
._attrsNS
= attrsNS
348 def __getattr__(self
, name
):
350 return len(self
._attrs
)
351 raise AttributeError, name
353 def item(self
, index
):
355 return self
[self
._attrs
.keys()[index
]]
361 for node
in self
._attrs
.values():
362 L
.append((node
.nodeName
, node
.value
))
367 for node
in self
._attrs
.values():
368 L
.append(((node
.URI
, node
.localName
), node
.value
))
372 return self
._attrs
.keys()
375 return self
._attrsNS
.keys()
378 return self
._attrs
.values()
380 def get(self
, name
, value
= None):
381 return self
._attrs
.get(name
, value
)
386 def __cmp__(self
, other
):
387 if self
._attrs
is getattr(other
, "_attrs", None):
390 return cmp(id(self
), id(other
))
392 #FIXME: is it appropriate to return .value?
393 def __getitem__(self
, attname_or_tuple
):
394 if type(attname_or_tuple
) is _TupleType
:
395 return self
._attrsNS
[attname_or_tuple
]
397 return self
._attrs
[attname_or_tuple
]
400 def __setitem__(self
, attname
, value
):
401 if type(value
) in _StringTypes
:
405 if not isinstance(value
, Attr
):
406 raise TypeError, "value must be a string or Attr object"
408 self
.setNamedItem(node
)
410 def setNamedItem(self
, node
):
411 if not isinstance(node
, Attr
):
412 raise HierarchyRequestErr
, \
413 "%s cannot be child of %s" % (repr(node
), repr(self
))
414 old
= self
._attrs
.get(node
.name
)
417 self
._attrs
[node
.name
] = node
418 self
._attrsNS
[(node
.namespaceURI
, node
.localName
)] = node
421 def setNamedItemNS(self
, node
):
422 return self
.setNamedItem(node
)
424 def __delitem__(self
, attname_or_tuple
):
425 node
= self
[attname_or_tuple
]
427 del self
._attrs
[node
.name
]
428 del self
._attrsNS
[(node
.namespaceURI
, node
.localName
)]
429 self
.length
= len(self
._attrs
)
431 AttributeList
= NamedNodeMap
435 nodeType
= Node
.ELEMENT_NODE
437 previousSibling
= None
438 childNodeTypes
= (Node
.ELEMENT_NODE
, Node
.PROCESSING_INSTRUCTION_NODE
,
439 Node
.COMMENT_NODE
, Node
.TEXT_NODE
,
440 Node
.CDATA_SECTION_NODE
, Node
.ENTITY_REFERENCE_NODE
)
442 def __init__(self
, tagName
, namespaceURI
=None, prefix
="",
445 self
.tagName
= self
.nodeName
= tagName
446 self
.localName
= localName
or tagName
448 self
.namespaceURI
= namespaceURI
449 self
.nodeValue
= None
451 self
._attrs
= {} # attributes are double-indexed:
452 self
._attrsNS
= {} # tagName -> Attribute
453 # URI,localName -> Attribute
454 # in the future: consider lazy generation
455 # of attribute objects this is too tricky
456 # for now because of headaches with
459 def cloneNode(self
, deep
):
460 clone
= Node
.cloneNode(self
, deep
)
463 for attr
in self
._attrs
.values():
464 node
= attr
.cloneNode(1)
465 clone
._attrs
[node
.name
] = node
466 clone
._attrsNS
[(node
.namespaceURI
, node
.localName
)] = node
467 node
.ownerElement
= clone
471 for attr
in self
._attrs
.values():
477 def getAttribute(self
, attname
):
479 return self
._attrs
[attname
].value
483 def getAttributeNS(self
, namespaceURI
, localName
):
485 return self
._attrsNS
[(namespaceURI
, localName
)].value
489 def setAttribute(self
, attname
, value
):
492 attr
.__dict
__["value"] = attr
.__dict
__["nodeValue"] = value
493 self
.setAttributeNode(attr
)
495 def setAttributeNS(self
, namespaceURI
, qualifiedName
, value
):
496 prefix
, localname
= _nssplit(qualifiedName
)
498 attr
= Attr(qualifiedName
, namespaceURI
, localname
, prefix
)
499 attr
.__dict
__["value"] = attr
.__dict
__["nodeValue"] = value
500 self
.setAttributeNode(attr
)
502 def getAttributeNode(self
, attrname
):
503 return self
._attrs
.get(attrname
)
505 def getAttributeNodeNS(self
, namespaceURI
, localName
):
506 return self
._attrsNS
.get((namespaceURI
, localName
))
508 def setAttributeNode(self
, attr
):
509 if attr
.ownerElement
not in (None, self
):
510 raise xml
.dom
.InuseAttributeErr("attribute node already owned")
511 old
= self
._attrs
.get(attr
.name
, None)
514 self
._attrs
[attr
.name
] = attr
515 self
._attrsNS
[(attr
.namespaceURI
, attr
.localName
)] = attr
517 # This creates a circular reference, but Element.unlink()
518 # breaks the cycle since the references to the attribute
519 # dictionaries are tossed.
520 attr
.ownerElement
= self
523 # It might have already been part of this node, in which case
524 # it doesn't represent a change, and should not be returned.
527 setAttributeNodeNS
= setAttributeNode
529 def removeAttribute(self
, name
):
530 attr
= self
._attrs
[name
]
531 self
.removeAttributeNode(attr
)
533 def removeAttributeNS(self
, namespaceURI
, localName
):
534 attr
= self
._attrsNS
[(namespaceURI
, localName
)]
535 self
.removeAttributeNode(attr
)
537 def removeAttributeNode(self
, node
):
539 del self
._attrs
[node
.name
]
540 del self
._attrsNS
[(node
.namespaceURI
, node
.localName
)]
542 removeAttributeNodeNS
= removeAttributeNode
544 def hasAttribute(self
, name
):
545 return self
._attrs
.has_key(name
)
547 def hasAttributeNS(self
, namespaceURI
, localName
):
548 return self
._attrsNS
.has_key((namespaceURI
, localName
))
550 def getElementsByTagName(self
, name
):
551 return _getElementsByTagNameHelper(self
, name
, [])
553 def getElementsByTagNameNS(self
, namespaceURI
, localName
):
554 return _getElementsByTagNameNSHelper(self
, namespaceURI
, localName
, [])
557 return "<DOM Element: %s at %s>" % (self
.tagName
, id(self
))
559 def writexml(self
, writer
, indent
="", addindent
="", newl
=""):
560 # indent = current indentation
561 # addindent = indentation to add to higher levels
562 # newl = newline string
563 writer
.write(indent
+"<" + self
.tagName
)
565 attrs
= self
._get
_attributes
()
566 a_names
= attrs
.keys()
569 for a_name
in a_names
:
570 writer
.write(" %s=\"" % a_name
)
571 _write_data(writer
, attrs
[a_name
].value
)
574 writer
.write(">%s"%(newl))
575 for node
in self
.childNodes
:
576 node
.writexml(writer
,indent
+addindent
,addindent
,newl
)
577 writer
.write("%s</%s>%s" % (indent
,self
.tagName
,newl
))
579 writer
.write("/>%s"%(newl))
581 def _get_attributes(self
):
582 return AttributeList(self
._attrs
, self
._attrsNS
)
584 def hasAttributes(self
):
585 if self
._attrs
or self
._attrsNS
:
591 nodeType
= Node
.COMMENT_NODE
592 nodeName
= "#comment"
596 def __init__(self
, data
):
598 self
.data
= self
.nodeValue
= data
600 def writexml(self
, writer
, indent
="", addindent
="", newl
=""):
601 writer
.write("%s<!--%s-->%s" % (indent
,self
.data
,newl
))
603 class ProcessingInstruction(Node
):
604 nodeType
= Node
.PROCESSING_INSTRUCTION_NODE
608 def __init__(self
, target
, data
):
610 self
.target
= self
.nodeName
= target
611 self
.data
= self
.nodeValue
= data
613 def writexml(self
, writer
, indent
="", addindent
="", newl
=""):
614 writer
.write("%s<?%s %s?>%s" % (indent
,self
.target
, self
.data
, newl
))
616 class CharacterData(Node
):
617 def __init__(self
, data
):
618 if type(data
) not in _StringTypes
:
619 raise TypeError, "node contents must be a string"
621 self
.data
= self
.nodeValue
= data
622 self
.length
= len(data
)
625 if len(self
.data
) > 10:
629 return "<DOM %s node \"%s%s\">" % (
630 self
.__class
__.__name
__, self
.data
[0:10], dotdotdot
)
632 def substringData(self
, offset
, count
):
634 raise xml
.dom
.IndexSizeErr("offset cannot be negative")
635 if offset
>= len(self
.data
):
636 raise xml
.dom
.IndexSizeErr("offset cannot be beyond end of data")
638 raise xml
.dom
.IndexSizeErr("count cannot be negative")
639 return self
.data
[offset
:offset
+count
]
641 def appendData(self
, arg
):
642 self
.data
= self
.data
+ arg
643 self
.nodeValue
= self
.data
644 self
.length
= len(self
.data
)
646 def insertData(self
, offset
, arg
):
648 raise xml
.dom
.IndexSizeErr("offset cannot be negative")
649 if offset
>= len(self
.data
):
650 raise xml
.dom
.IndexSizeErr("offset cannot be beyond end of data")
652 self
.data
= "%s%s%s" % (
653 self
.data
[:offset
], arg
, self
.data
[offset
:])
654 self
.nodeValue
= self
.data
655 self
.length
= len(self
.data
)
657 def deleteData(self
, offset
, count
):
659 raise xml
.dom
.IndexSizeErr("offset cannot be negative")
660 if offset
>= len(self
.data
):
661 raise xml
.dom
.IndexSizeErr("offset cannot be beyond end of data")
663 raise xml
.dom
.IndexSizeErr("count cannot be negative")
665 self
.data
= self
.data
[:offset
] + self
.data
[offset
+count
:]
666 self
.nodeValue
= self
.data
667 self
.length
= len(self
.data
)
669 def replaceData(self
, offset
, count
, arg
):
671 raise xml
.dom
.IndexSizeErr("offset cannot be negative")
672 if offset
>= len(self
.data
):
673 raise xml
.dom
.IndexSizeErr("offset cannot be beyond end of data")
675 raise xml
.dom
.IndexSizeErr("count cannot be negative")
677 self
.data
= "%s%s%s" % (
678 self
.data
[:offset
], arg
, self
.data
[offset
+count
:])
679 self
.nodeValue
= self
.data
680 self
.length
= len(self
.data
)
682 class Text(CharacterData
):
683 nodeType
= Node
.TEXT_NODE
688 def splitText(self
, offset
):
689 if offset
< 0 or offset
> len(self
.data
):
690 raise xml
.dom
.IndexSizeErr("illegal offset value")
691 newText
= Text(self
.data
[offset
:])
692 next
= self
.nextSibling
693 if self
.parentNode
and self
in self
.parentNode
.childNodes
:
695 self
.parentNode
.appendChild(newText
)
697 self
.parentNode
.insertBefore(newText
, next
)
698 self
.data
= self
.data
[:offset
]
699 self
.nodeValue
= self
.data
700 self
.length
= len(self
.data
)
703 def writexml(self
, writer
, indent
="", addindent
="", newl
=""):
704 _write_data(writer
, "%s%s%s"%(indent
, self
.data
, newl
))
707 class CDATASection(Text
):
708 nodeType
= Node
.CDATA_SECTION_NODE
709 nodeName
= "#cdata-section"
711 def writexml(self
, writer
, indent
="", addindent
="", newl
=""):
712 _write_data(writer
, "<![CDATA[%s]]>" % self
.data
)
715 def _nssplit(qualifiedName
):
716 fields
= _string
.split(qualifiedName
, ':', 1)
719 elif len(fields
) == 1:
720 return ('', fields
[0])
723 class DocumentType(Node
):
724 nodeType
= Node
.DOCUMENT_TYPE_NODE
730 internalSubset
= None
734 def __init__(self
, qualifiedName
):
737 prefix
, localname
= _nssplit(qualifiedName
)
738 self
.name
= localname
741 class DOMImplementation
:
742 def hasFeature(self
, feature
, version
):
743 if version
not in ("1.0", "2.0"):
745 feature
= _string
.lower(feature
)
746 return feature
== "core"
748 def createDocument(self
, namespaceURI
, qualifiedName
, doctype
):
749 if doctype
and doctype
.parentNode
is not None:
750 raise xml
.dom
.WrongDocumentErr(
751 "doctype object owned by another DOM tree")
752 doc
= self
._createDocument
()
754 doctype
= self
.createDocumentType(qualifiedName
, None, None)
755 if not qualifiedName
:
756 # The spec is unclear what to raise here; SyntaxErr
757 # would be the other obvious candidate. Since Xerces raises
758 # InvalidCharacterErr, and since SyntaxErr is not listed
759 # for createDocument, that seems to be the better choice.
760 # XXX: need to check for illegal characters here and in
762 raise xml
.dom
.InvalidCharacterErr("Element with no name")
763 prefix
, localname
= _nssplit(qualifiedName
)
765 and namespaceURI
!= "http://www.w3.org/XML/1998/namespace":
766 raise xml
.dom
.NamespaceErr("illegal use of 'xml' prefix")
767 if prefix
and not namespaceURI
:
768 raise xml
.dom
.NamespaceErr(
769 "illegal use of prefix without namespaces")
770 element
= doc
.createElementNS(namespaceURI
, qualifiedName
)
771 doc
.appendChild(element
)
772 doctype
.parentNode
= doctype
.ownerDocument
= doc
773 doc
.doctype
= doctype
774 doc
.implementation
= self
777 def createDocumentType(self
, qualifiedName
, publicId
, systemId
):
778 doctype
= DocumentType(qualifiedName
)
779 doctype
.publicId
= publicId
780 doctype
.systemId
= systemId
784 def _createDocument(self
):
787 class Document(Node
):
788 nodeType
= Node
.DOCUMENT_NODE
789 nodeName
= "#document"
794 previousSibling
= nextSibling
= None
796 implementation
= DOMImplementation()
797 childNodeTypes
= (Node
.ELEMENT_NODE
, Node
.PROCESSING_INSTRUCTION_NODE
,
798 Node
.COMMENT_NODE
, Node
.DOCUMENT_TYPE_NODE
)
800 def appendChild(self
, node
):
801 if node
.nodeType
not in self
.childNodeTypes
:
802 raise HierarchyRequestErr
, \
803 "%s cannot be child of %s" % (repr(node
), repr(self
))
804 if node
.parentNode
is not None:
805 node
.parentNode
.removeChild(node
)
807 if node
.nodeType
== Node
.ELEMENT_NODE \
808 and self
._get
_documentElement
():
809 raise xml
.dom
.HierarchyRequestErr(
810 "two document elements disallowed")
811 return Node
.appendChild(self
, node
)
813 def removeChild(self
, oldChild
):
814 self
.childNodes
.remove(oldChild
)
815 oldChild
.nextSibling
= oldChild
.previousSibling
= None
816 oldChild
.parentNode
= None
817 if self
.documentElement
is oldChild
:
818 self
.documentElement
= None
822 def _get_documentElement(self
):
823 for node
in self
.childNodes
:
824 if node
.nodeType
== Node
.ELEMENT_NODE
:
828 if self
.doctype
is not None:
829 self
.doctype
.unlink()
833 def createDocumentFragment(self
):
834 d
= DocumentFragment()
838 def createElement(self
, tagName
):
840 e
.ownerDocument
= self
843 def createTextNode(self
, data
):
845 t
.ownerDocument
= self
848 def createCDATASection(self
, data
):
849 c
= CDATASection(data
)
850 c
.ownerDocument
= self
853 def createComment(self
, data
):
855 c
.ownerDocument
= self
858 def createProcessingInstruction(self
, target
, data
):
859 p
= ProcessingInstruction(target
, data
)
860 p
.ownerDocument
= self
863 def createAttribute(self
, qName
):
865 a
.ownerDocument
= self
869 def createElementNS(self
, namespaceURI
, qualifiedName
):
870 prefix
, localName
= _nssplit(qualifiedName
)
871 e
= Element(qualifiedName
, namespaceURI
, prefix
, localName
)
872 e
.ownerDocument
= self
875 def createAttributeNS(self
, namespaceURI
, qualifiedName
):
876 prefix
, localName
= _nssplit(qualifiedName
)
877 a
= Attr(qualifiedName
, namespaceURI
, localName
, prefix
)
878 a
.ownerDocument
= self
882 def getElementsByTagName(self
, name
):
883 return _getElementsByTagNameHelper(self
, name
, [])
885 def getElementsByTagNameNS(self
, namespaceURI
, localName
):
886 return _getElementsByTagNameNSHelper(self
, namespaceURI
, localName
, [])
888 def writexml(self
, writer
, indent
="", addindent
="", newl
=""):
889 writer
.write('<?xml version="1.0" ?>\n')
890 for node
in self
.childNodes
:
891 node
.writexml(writer
, indent
, addindent
, newl
)
894 # we can't use cStringIO since it doesn't support Unicode strings
895 from StringIO
import StringIO
898 def _doparse(func
, args
, kwargs
):
899 events
= apply(func
, args
, kwargs
)
900 toktype
, rootNode
= events
.getEvent()
901 events
.expandNode(rootNode
)
905 def parse(*args
, **kwargs
):
906 """Parse a file into a DOM by filename or file object."""
907 from xml
.dom
import pulldom
908 return _doparse(pulldom
.parse
, args
, kwargs
)
910 def parseString(*args
, **kwargs
):
911 """Parse a file into a DOM from a string."""
912 from xml
.dom
import pulldom
913 return _doparse(pulldom
.parseString
, args
, kwargs
)
915 def getDOMImplementation():
916 return Document
.implementation