blob: 3a35781622f0ea8571118535635afa8d27bb9ecb [file] [log] [blame]
Fred Drake1f549022000-09-24 05:21:58 +00001"""\
Fred Drakef7cf40d2000-12-14 18:16:11 +00002minidom.py -- a lightweight DOM implementation.
Fred Drake55c38192000-06-29 19:39:57 +00003
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00004parse("foo.xml")
Paul Prescod623511b2000-07-21 22:05:49 +00005
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00006parseString("<foo><bar/></foo>")
Paul Prescod623511b2000-07-21 22:05:49 +00007
Fred Drake55c38192000-06-29 19:39:57 +00008Todo:
9=====
10 * convenience methods for getting elements and text.
11 * more testing
12 * bring some of the writer and linearizer code into conformance with this
13 interface
14 * SAX 2 namespaces
15"""
16
Thomas Wouters0e3f5912006-08-11 14:57:12 +000017import xml.dom
Fred Drake55c38192000-06-29 19:39:57 +000018
Thomas Wouters0e3f5912006-08-11 14:57:12 +000019from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE, domreg
20from xml.dom.minicompat import *
21from xml.dom.xmlbuilder import DOMImplementationLS, DocumentLS
Fred Drake3ac6a092001-09-28 04:33:06 +000022
Martin v. Löwis787354c2003-01-25 15:28:29 +000023# This is used by the ID-cache invalidation checks; the list isn't
24# actually complete, since the nodes being checked will never be the
25# DOCUMENT_NODE or DOCUMENT_FRAGMENT_NODE. (The node being checked is
26# the node being added or removed, not the node being modified.)
27#
Thomas Wouters0e3f5912006-08-11 14:57:12 +000028_nodeTypes_with_children = (xml.dom.Node.ELEMENT_NODE,
29 xml.dom.Node.ENTITY_REFERENCE_NODE)
Martin v. Löwis95700f72002-03-15 13:51:59 +000030
Fred Drake3ac6a092001-09-28 04:33:06 +000031
Thomas Wouters0e3f5912006-08-11 14:57:12 +000032class Node(xml.dom.Node):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000033 namespaceURI = None # this is non-null only for elements and attributes
Fred Drake575712e2001-09-28 20:25:45 +000034 parentNode = None
35 ownerDocument = None
Martin v. Löwis787354c2003-01-25 15:28:29 +000036 nextSibling = None
37 previousSibling = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +000038
Martin v. Löwis787354c2003-01-25 15:28:29 +000039 prefix = EMPTY_PREFIX # non-null only for NS elements and attributes
Fred Drake55c38192000-06-29 19:39:57 +000040
Fred Drake1f549022000-09-24 05:21:58 +000041 def __nonzero__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +000042 return True
Fred Drake55c38192000-06-29 19:39:57 +000043
Martin v. Löwis7d650ca2002-06-30 15:05:00 +000044 def toxml(self, encoding = None):
45 return self.toprettyxml("", "", encoding)
Fred Drake55c38192000-06-29 19:39:57 +000046
Martin v. Löwis7d650ca2002-06-30 15:05:00 +000047 def toprettyxml(self, indent="\t", newl="\n", encoding = None):
Martin v. Löwiscb67ea12001-03-31 16:30:40 +000048 # indent = the indentation string to prepend, per level
49 # newl = the newline string to append
50 writer = _get_StringIO()
Martin v. Löwis7d650ca2002-06-30 15:05:00 +000051 if encoding is not None:
52 import codecs
53 # Can't use codecs.getwriter to preserve 2.0 compatibility
54 writer = codecs.lookup(encoding)[3](writer)
55 if self.nodeType == Node.DOCUMENT_NODE:
56 # Can pass encoding only to document, to put it into XML header
57 self.writexml(writer, "", indent, newl, encoding)
58 else:
59 self.writexml(writer, "", indent, newl)
Martin v. Löwiscb67ea12001-03-31 16:30:40 +000060 return writer.getvalue()
Martin v. Löwis46fa39a2001-02-06 00:14:08 +000061
Fred Drake1f549022000-09-24 05:21:58 +000062 def hasChildNodes(self):
63 if self.childNodes:
Martin v. Löwis787354c2003-01-25 15:28:29 +000064 return True
Fred Drake1f549022000-09-24 05:21:58 +000065 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +000066 return False
67
68 def _get_childNodes(self):
69 return self.childNodes
Fred Drake55c38192000-06-29 19:39:57 +000070
Fred Drake1f549022000-09-24 05:21:58 +000071 def _get_firstChild(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +000072 if self.childNodes:
73 return self.childNodes[0]
Paul Prescod73678da2000-07-01 04:58:47 +000074
Fred Drake1f549022000-09-24 05:21:58 +000075 def _get_lastChild(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +000076 if self.childNodes:
77 return self.childNodes[-1]
Paul Prescod73678da2000-07-01 04:58:47 +000078
Fred Drake1f549022000-09-24 05:21:58 +000079 def insertBefore(self, newChild, refChild):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000080 if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
Fred Drakee50959a2001-12-06 04:32:18 +000081 for c in tuple(newChild.childNodes):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000082 self.insertBefore(c, refChild)
83 ### The DOM does not clearly specify what to return in this case
84 return newChild
Martin v. Löwis787354c2003-01-25 15:28:29 +000085 if newChild.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000086 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +000087 "%s cannot be child of %s" % (repr(newChild), repr(self)))
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +000088 if newChild.parentNode is not None:
89 newChild.parentNode.removeChild(newChild)
Fred Drake4ccf4a12000-11-21 22:02:22 +000090 if refChild is None:
91 self.appendChild(newChild)
92 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +000093 try:
94 index = self.childNodes.index(refChild)
95 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000096 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +000097 if newChild.nodeType in _nodeTypes_with_children:
98 _clear_id_cache(self)
Fred Drake4ccf4a12000-11-21 22:02:22 +000099 self.childNodes.insert(index, newChild)
100 newChild.nextSibling = refChild
101 refChild.previousSibling = newChild
102 if index:
103 node = self.childNodes[index-1]
104 node.nextSibling = newChild
105 newChild.previousSibling = node
106 else:
107 newChild.previousSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000108 newChild.parentNode = self
Fred Drake4ccf4a12000-11-21 22:02:22 +0000109 return newChild
Fred Drake55c38192000-06-29 19:39:57 +0000110
Fred Drake1f549022000-09-24 05:21:58 +0000111 def appendChild(self, node):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000112 if node.nodeType == self.DOCUMENT_FRAGMENT_NODE:
Fred Drakee50959a2001-12-06 04:32:18 +0000113 for c in tuple(node.childNodes):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000114 self.appendChild(c)
115 ### The DOM does not clearly specify what to return in this case
116 return node
Martin v. Löwis787354c2003-01-25 15:28:29 +0000117 if node.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000118 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000119 "%s cannot be child of %s" % (repr(node), repr(self)))
120 elif node.nodeType in _nodeTypes_with_children:
121 _clear_id_cache(self)
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000122 if node.parentNode is not None:
123 node.parentNode.removeChild(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000124 _append_child(self, node)
Fred Drake13a30692000-10-09 20:04:16 +0000125 node.nextSibling = None
Paul Prescod73678da2000-07-01 04:58:47 +0000126 return node
127
Fred Drake1f549022000-09-24 05:21:58 +0000128 def replaceChild(self, newChild, oldChild):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000129 if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
130 refChild = oldChild.nextSibling
131 self.removeChild(oldChild)
132 return self.insertBefore(newChild, refChild)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000133 if newChild.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000134 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000135 "%s cannot be child of %s" % (repr(newChild), repr(self)))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000136 if newChild is oldChild:
137 return
Andrew M. Kuchling841d25e2005-11-22 19:03:16 +0000138 if newChild.parentNode is not None:
139 newChild.parentNode.removeChild(newChild)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000140 try:
141 index = self.childNodes.index(oldChild)
142 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000143 raise xml.dom.NotFoundErr()
Fred Drake4ccf4a12000-11-21 22:02:22 +0000144 self.childNodes[index] = newChild
Martin v. Löwis787354c2003-01-25 15:28:29 +0000145 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)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000150 newChild.nextSibling = oldChild.nextSibling
151 newChild.previousSibling = oldChild.previousSibling
Martin v. Löwis156c3372000-12-28 18:40:56 +0000152 oldChild.nextSibling = None
Fred Drake4ccf4a12000-11-21 22:02:22 +0000153 oldChild.previousSibling = None
Martin v. Löwis156c3372000-12-28 18:40:56 +0000154 if newChild.previousSibling:
155 newChild.previousSibling.nextSibling = newChild
156 if newChild.nextSibling:
157 newChild.nextSibling.previousSibling = newChild
Fred Drake4ccf4a12000-11-21 22:02:22 +0000158 return oldChild
Paul Prescod73678da2000-07-01 04:58:47 +0000159
Fred Drake1f549022000-09-24 05:21:58 +0000160 def removeChild(self, oldChild):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000161 try:
162 self.childNodes.remove(oldChild)
163 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000164 raise xml.dom.NotFoundErr()
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000165 if oldChild.nextSibling is not None:
166 oldChild.nextSibling.previousSibling = oldChild.previousSibling
167 if oldChild.previousSibling is not None:
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000168 oldChild.previousSibling.nextSibling = oldChild.nextSibling
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000169 oldChild.nextSibling = oldChild.previousSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000170 if oldChild.nodeType in _nodeTypes_with_children:
171 _clear_id_cache(self)
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000172
Martin v. Löwis787354c2003-01-25 15:28:29 +0000173 oldChild.parentNode = None
Fred Drake4ccf4a12000-11-21 22:02:22 +0000174 return oldChild
175
176 def normalize(self):
Fred Drakef7cf40d2000-12-14 18:16:11 +0000177 L = []
178 for child in self.childNodes:
179 if child.nodeType == Node.TEXT_NODE:
180 data = child.data
181 if data and L and L[-1].nodeType == child.nodeType:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000182 # collapse text node
183 node = L[-1]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000184 node.data = node.data + child.data
Fred Drake4ccf4a12000-11-21 22:02:22 +0000185 node.nextSibling = child.nextSibling
186 child.unlink()
Fred Drakef7cf40d2000-12-14 18:16:11 +0000187 elif data:
188 if L:
189 L[-1].nextSibling = child
190 child.previousSibling = L[-1]
191 else:
192 child.previousSibling = None
193 L.append(child)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000194 else:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000195 # empty text node; discard
196 child.unlink()
197 else:
198 if L:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000199 L[-1].nextSibling = child
200 child.previousSibling = L[-1]
Fred Drakef7cf40d2000-12-14 18:16:11 +0000201 else:
202 child.previousSibling = None
203 L.append(child)
204 if child.nodeType == Node.ELEMENT_NODE:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000205 child.normalize()
Fred Drakef7cf40d2000-12-14 18:16:11 +0000206 self.childNodes[:] = L
Paul Prescod73678da2000-07-01 04:58:47 +0000207
Fred Drake1f549022000-09-24 05:21:58 +0000208 def cloneNode(self, deep):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000209 return _clone_node(self, deep, self.ownerDocument or self)
Fred Drake55c38192000-06-29 19:39:57 +0000210
Martin v. Löwis787354c2003-01-25 15:28:29 +0000211 def isSupported(self, feature, version):
212 return self.ownerDocument.implementation.hasFeature(feature, version)
213
214 def _get_localName(self):
215 # Overridden in Element and Attr where localName can be Non-Null
216 return None
217
218 # Node interfaces from Level 3 (WD 9 April 2002)
Fred Drake25239772001-02-02 19:40:19 +0000219
220 def isSameNode(self, other):
221 return self is other
222
Martin v. Löwis787354c2003-01-25 15:28:29 +0000223 def getInterface(self, feature):
224 if self.isSupported(feature, None):
225 return self
226 else:
227 return None
228
229 # The "user data" functions use a dictionary that is only present
230 # if some user data has been set, so be careful not to assume it
231 # exists.
232
233 def getUserData(self, key):
234 try:
235 return self._user_data[key][0]
236 except (AttributeError, KeyError):
237 return None
238
239 def setUserData(self, key, data, handler):
240 old = None
241 try:
242 d = self._user_data
243 except AttributeError:
244 d = {}
245 self._user_data = d
246 if d.has_key(key):
247 old = d[key][0]
248 if data is None:
249 # ignore handlers passed for None
250 handler = None
251 if old is not None:
252 del d[key]
253 else:
254 d[key] = (data, handler)
255 return old
256
257 def _call_user_data_handler(self, operation, src, dst):
258 if hasattr(self, "_user_data"):
259 for key, (data, handler) in self._user_data.items():
260 if handler is not None:
261 handler.handle(operation, key, data, src, dst)
262
Fred Drake25239772001-02-02 19:40:19 +0000263 # minidom-specific API:
264
Fred Drake1f549022000-09-24 05:21:58 +0000265 def unlink(self):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000266 self.parentNode = self.ownerDocument = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000267 if self.childNodes:
268 for child in self.childNodes:
269 child.unlink()
270 self.childNodes = NodeList()
Paul Prescod4221ff02000-10-13 20:11:42 +0000271 self.previousSibling = None
272 self.nextSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000273
274defproperty(Node, "firstChild", doc="First child node, or None.")
275defproperty(Node, "lastChild", doc="Last child node, or None.")
276defproperty(Node, "localName", doc="Namespace-local name of this node.")
277
278
279def _append_child(self, node):
280 # fast path with less checks; usable by DOM builders if careful
281 childNodes = self.childNodes
282 if childNodes:
283 last = childNodes[-1]
284 node.__dict__["previousSibling"] = last
285 last.__dict__["nextSibling"] = node
286 childNodes.append(node)
287 node.__dict__["parentNode"] = self
288
289def _in_document(node):
290 # return True iff node is part of a document tree
291 while node is not None:
292 if node.nodeType == Node.DOCUMENT_NODE:
293 return True
294 node = node.parentNode
295 return False
Fred Drake55c38192000-06-29 19:39:57 +0000296
Fred Drake1f549022000-09-24 05:21:58 +0000297def _write_data(writer, data):
Fred Drake55c38192000-06-29 19:39:57 +0000298 "Writes datachars to writer."
Martin v. Löwis787354c2003-01-25 15:28:29 +0000299 data = data.replace("&", "&amp;").replace("<", "&lt;")
300 data = data.replace("\"", "&quot;").replace(">", "&gt;")
Fred Drake55c38192000-06-29 19:39:57 +0000301 writer.write(data)
302
Martin v. Löwis787354c2003-01-25 15:28:29 +0000303def _get_elements_by_tagName_helper(parent, name, rc):
Fred Drake55c38192000-06-29 19:39:57 +0000304 for node in parent.childNodes:
Fred Drake1f549022000-09-24 05:21:58 +0000305 if node.nodeType == Node.ELEMENT_NODE and \
306 (name == "*" or node.tagName == name):
307 rc.append(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000308 _get_elements_by_tagName_helper(node, name, rc)
Fred Drake55c38192000-06-29 19:39:57 +0000309 return rc
310
Martin v. Löwis787354c2003-01-25 15:28:29 +0000311def _get_elements_by_tagName_ns_helper(parent, nsURI, localName, rc):
Fred Drake55c38192000-06-29 19:39:57 +0000312 for node in parent.childNodes:
Fred Drake1f549022000-09-24 05:21:58 +0000313 if node.nodeType == Node.ELEMENT_NODE:
Martin v. Löwised525fb2001-06-03 14:06:42 +0000314 if ((localName == "*" or node.localName == localName) and
Fred Drake1f549022000-09-24 05:21:58 +0000315 (nsURI == "*" or node.namespaceURI == nsURI)):
316 rc.append(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000317 _get_elements_by_tagName_ns_helper(node, nsURI, localName, rc)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000318 return rc
Fred Drake55c38192000-06-29 19:39:57 +0000319
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000320class DocumentFragment(Node):
321 nodeType = Node.DOCUMENT_FRAGMENT_NODE
322 nodeName = "#document-fragment"
323 nodeValue = None
324 attributes = None
325 parentNode = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000326 _child_node_types = (Node.ELEMENT_NODE,
327 Node.TEXT_NODE,
328 Node.CDATA_SECTION_NODE,
329 Node.ENTITY_REFERENCE_NODE,
330 Node.PROCESSING_INSTRUCTION_NODE,
331 Node.COMMENT_NODE,
332 Node.NOTATION_NODE)
333
334 def __init__(self):
335 self.childNodes = NodeList()
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000336
337
Fred Drake55c38192000-06-29 19:39:57 +0000338class Attr(Node):
Fred Drake1f549022000-09-24 05:21:58 +0000339 nodeType = Node.ATTRIBUTE_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +0000340 attributes = None
341 ownerElement = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000342 specified = False
343 _is_id = False
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000344
Martin v. Löwis787354c2003-01-25 15:28:29 +0000345 _child_node_types = (Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE)
346
347 def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None,
348 prefix=None):
Fred Drake55c38192000-06-29 19:39:57 +0000349 # skip setattr for performance
Fred Drake4ccf4a12000-11-21 22:02:22 +0000350 d = self.__dict__
Fred Drake4ccf4a12000-11-21 22:02:22 +0000351 d["nodeName"] = d["name"] = qName
352 d["namespaceURI"] = namespaceURI
353 d["prefix"] = prefix
Martin v. Löwis787354c2003-01-25 15:28:29 +0000354 d['childNodes'] = NodeList()
355
356 # Add the single child node that represents the value of the attr
357 self.childNodes.append(Text())
358
Paul Prescod73678da2000-07-01 04:58:47 +0000359 # nodeValue and value are set elsewhere
Fred Drake55c38192000-06-29 19:39:57 +0000360
Martin v. Löwis787354c2003-01-25 15:28:29 +0000361 def _get_localName(self):
362 return self.nodeName.split(":", 1)[-1]
363
364 def _get_name(self):
365 return self.name
366
367 def _get_specified(self):
368 return self.specified
369
Fred Drake1f549022000-09-24 05:21:58 +0000370 def __setattr__(self, name, value):
Fred Drakef7cf40d2000-12-14 18:16:11 +0000371 d = self.__dict__
Fred Drake1f549022000-09-24 05:21:58 +0000372 if name in ("value", "nodeValue"):
Fred Drakef7cf40d2000-12-14 18:16:11 +0000373 d["value"] = d["nodeValue"] = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000374 d2 = self.childNodes[0].__dict__
375 d2["data"] = d2["nodeValue"] = value
376 if self.ownerElement is not None:
377 _clear_id_cache(self.ownerElement)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000378 elif name in ("name", "nodeName"):
379 d["name"] = d["nodeName"] = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000380 if self.ownerElement is not None:
381 _clear_id_cache(self.ownerElement)
Fred Drake55c38192000-06-29 19:39:57 +0000382 else:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000383 d[name] = value
Fred Drake55c38192000-06-29 19:39:57 +0000384
Martin v. Löwis995359c2003-01-26 08:59:32 +0000385 def _set_prefix(self, prefix):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000386 nsuri = self.namespaceURI
Martin v. Löwis995359c2003-01-26 08:59:32 +0000387 if prefix == "xmlns":
388 if nsuri and nsuri != XMLNS_NAMESPACE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000389 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000390 "illegal use of 'xmlns' prefix for the wrong namespace")
391 d = self.__dict__
392 d['prefix'] = prefix
393 if prefix is None:
394 newName = self.localName
395 else:
Martin v. Löwis995359c2003-01-26 08:59:32 +0000396 newName = "%s:%s" % (prefix, self.localName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000397 if self.ownerElement:
398 _clear_id_cache(self.ownerElement)
399 d['nodeName'] = d['name'] = newName
400
401 def _set_value(self, value):
402 d = self.__dict__
403 d['value'] = d['nodeValue'] = value
404 if self.ownerElement:
405 _clear_id_cache(self.ownerElement)
406 self.childNodes[0].data = value
407
408 def unlink(self):
409 # This implementation does not call the base implementation
410 # since most of that is not needed, and the expense of the
411 # method call is not warranted. We duplicate the removal of
412 # children, but that's all we needed from the base class.
413 elem = self.ownerElement
414 if elem is not None:
415 del elem._attrs[self.nodeName]
416 del elem._attrsNS[(self.namespaceURI, self.localName)]
417 if self._is_id:
418 self._is_id = False
419 elem._magic_id_nodes -= 1
420 self.ownerDocument._magic_id_count -= 1
421 for child in self.childNodes:
422 child.unlink()
423 del self.childNodes[:]
424
425 def _get_isId(self):
426 if self._is_id:
427 return True
428 doc = self.ownerDocument
429 elem = self.ownerElement
430 if doc is None or elem is None:
431 return False
432
433 info = doc._get_elem_info(elem)
434 if info is None:
435 return False
436 if self.namespaceURI:
437 return info.isIdNS(self.namespaceURI, self.localName)
438 else:
439 return info.isId(self.nodeName)
440
441 def _get_schemaType(self):
442 doc = self.ownerDocument
443 elem = self.ownerElement
444 if doc is None or elem is None:
445 return _no_type
446
447 info = doc._get_elem_info(elem)
448 if info is None:
449 return _no_type
450 if self.namespaceURI:
451 return info.getAttributeTypeNS(self.namespaceURI, self.localName)
452 else:
453 return info.getAttributeType(self.nodeName)
454
455defproperty(Attr, "isId", doc="True if this attribute is an ID.")
456defproperty(Attr, "localName", doc="Namespace-local name of this attribute.")
457defproperty(Attr, "schemaType", doc="Schema type for this attribute.")
Fred Drake4ccf4a12000-11-21 22:02:22 +0000458
Fred Drakef7cf40d2000-12-14 18:16:11 +0000459
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000460class NamedNodeMap(object):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000461 """The attribute list is a transient interface to the underlying
462 dictionaries. Mutations here will change the underlying element's
Fred Drakef7cf40d2000-12-14 18:16:11 +0000463 dictionary.
464
465 Ordering is imposed artificially and does not reflect the order of
466 attributes as found in an input document.
467 """
Fred Drake4ccf4a12000-11-21 22:02:22 +0000468
Martin v. Löwis787354c2003-01-25 15:28:29 +0000469 __slots__ = ('_attrs', '_attrsNS', '_ownerElement')
470
Fred Drake2998a552001-12-06 18:27:48 +0000471 def __init__(self, attrs, attrsNS, ownerElement):
Fred Drake1f549022000-09-24 05:21:58 +0000472 self._attrs = attrs
473 self._attrsNS = attrsNS
Fred Drake2998a552001-12-06 18:27:48 +0000474 self._ownerElement = ownerElement
Fred Drakef7cf40d2000-12-14 18:16:11 +0000475
Martin v. Löwis787354c2003-01-25 15:28:29 +0000476 def _get_length(self):
477 return len(self._attrs)
Fred Drake55c38192000-06-29 19:39:57 +0000478
Fred Drake1f549022000-09-24 05:21:58 +0000479 def item(self, index):
Fred Drake55c38192000-06-29 19:39:57 +0000480 try:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000481 return self[self._attrs.keys()[index]]
Fred Drake55c38192000-06-29 19:39:57 +0000482 except IndexError:
483 return None
Fred Drake55c38192000-06-29 19:39:57 +0000484
Fred Drake1f549022000-09-24 05:21:58 +0000485 def items(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000486 L = []
487 for node in self._attrs.values():
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000488 L.append((node.nodeName, node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000489 return L
Fred Drake1f549022000-09-24 05:21:58 +0000490
491 def itemsNS(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000492 L = []
493 for node in self._attrs.values():
Fred Drake49a5d032001-11-30 22:21:58 +0000494 L.append(((node.namespaceURI, node.localName), node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000495 return L
Fred Drake16f63292000-10-23 18:09:50 +0000496
Martin v. Löwis787354c2003-01-25 15:28:29 +0000497 def has_key(self, key):
498 if isinstance(key, StringTypes):
499 return self._attrs.has_key(key)
500 else:
501 return self._attrsNS.has_key(key)
502
Fred Drake1f549022000-09-24 05:21:58 +0000503 def keys(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000504 return self._attrs.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000505
Fred Drake1f549022000-09-24 05:21:58 +0000506 def keysNS(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000507 return self._attrsNS.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000508
Fred Drake1f549022000-09-24 05:21:58 +0000509 def values(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000510 return self._attrs.values()
Fred Drake55c38192000-06-29 19:39:57 +0000511
Martin v. Löwis787354c2003-01-25 15:28:29 +0000512 def get(self, name, value=None):
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000513 return self._attrs.get(name, value)
514
Martin v. Löwis787354c2003-01-25 15:28:29 +0000515 __len__ = _get_length
Fred Drake55c38192000-06-29 19:39:57 +0000516
Fred Drake1f549022000-09-24 05:21:58 +0000517 def __cmp__(self, other):
518 if self._attrs is getattr(other, "_attrs", None):
Fred Drake55c38192000-06-29 19:39:57 +0000519 return 0
Fred Drake16f63292000-10-23 18:09:50 +0000520 else:
Fred Drake1f549022000-09-24 05:21:58 +0000521 return cmp(id(self), id(other))
Fred Drake55c38192000-06-29 19:39:57 +0000522
Fred Drake1f549022000-09-24 05:21:58 +0000523 def __getitem__(self, attname_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000524 if isinstance(attname_or_tuple, tuple):
Paul Prescod73678da2000-07-01 04:58:47 +0000525 return self._attrsNS[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000526 else:
Paul Prescod73678da2000-07-01 04:58:47 +0000527 return self._attrs[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000528
Paul Prescod1e688272000-07-01 19:21:47 +0000529 # same as set
Fred Drake1f549022000-09-24 05:21:58 +0000530 def __setitem__(self, attname, value):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000531 if isinstance(value, StringTypes):
532 try:
533 node = self._attrs[attname]
534 except KeyError:
535 node = Attr(attname)
536 node.ownerDocument = self._ownerElement.ownerDocument
Martin v. Löwis995359c2003-01-26 08:59:32 +0000537 self.setNamedItem(node)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000538 node.value = value
Paul Prescod1e688272000-07-01 19:21:47 +0000539 else:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000540 if not isinstance(value, Attr):
541 raise TypeError, "value must be a string or Attr object"
Fred Drake1f549022000-09-24 05:21:58 +0000542 node = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000543 self.setNamedItem(node)
544
545 def getNamedItem(self, name):
546 try:
547 return self._attrs[name]
548 except KeyError:
549 return None
550
551 def getNamedItemNS(self, namespaceURI, localName):
552 try:
553 return self._attrsNS[(namespaceURI, localName)]
554 except KeyError:
555 return None
556
557 def removeNamedItem(self, name):
558 n = self.getNamedItem(name)
559 if n is not None:
560 _clear_id_cache(self._ownerElement)
561 del self._attrs[n.nodeName]
562 del self._attrsNS[(n.namespaceURI, n.localName)]
563 if n.__dict__.has_key('ownerElement'):
564 n.__dict__['ownerElement'] = None
565 return n
566 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000567 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000568
569 def removeNamedItemNS(self, namespaceURI, localName):
570 n = self.getNamedItemNS(namespaceURI, localName)
571 if n is not None:
572 _clear_id_cache(self._ownerElement)
573 del self._attrsNS[(n.namespaceURI, n.localName)]
574 del self._attrs[n.nodeName]
575 if n.__dict__.has_key('ownerElement'):
576 n.__dict__['ownerElement'] = None
577 return n
578 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000579 raise xml.dom.NotFoundErr()
Fred Drakef7cf40d2000-12-14 18:16:11 +0000580
581 def setNamedItem(self, node):
Andrew M. Kuchlingbc8f72c2001-02-21 01:30:26 +0000582 if not isinstance(node, Attr):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000583 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000584 "%s cannot be child of %s" % (repr(node), repr(self)))
Fred Drakef7cf40d2000-12-14 18:16:11 +0000585 old = self._attrs.get(node.name)
Paul Prescod1e688272000-07-01 19:21:47 +0000586 if old:
587 old.unlink()
Fred Drake1f549022000-09-24 05:21:58 +0000588 self._attrs[node.name] = node
589 self._attrsNS[(node.namespaceURI, node.localName)] = node
Fred Drake2998a552001-12-06 18:27:48 +0000590 node.ownerElement = self._ownerElement
Martin v. Löwis787354c2003-01-25 15:28:29 +0000591 _clear_id_cache(node.ownerElement)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000592 return old
593
594 def setNamedItemNS(self, node):
595 return self.setNamedItem(node)
Paul Prescod73678da2000-07-01 04:58:47 +0000596
Fred Drake1f549022000-09-24 05:21:58 +0000597 def __delitem__(self, attname_or_tuple):
598 node = self[attname_or_tuple]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000599 _clear_id_cache(node.ownerElement)
Paul Prescod73678da2000-07-01 04:58:47 +0000600 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000601
602 def __getstate__(self):
603 return self._attrs, self._attrsNS, self._ownerElement
604
605 def __setstate__(self, state):
606 self._attrs, self._attrsNS, self._ownerElement = state
607
608defproperty(NamedNodeMap, "length",
609 doc="Number of nodes in the NamedNodeMap.")
Fred Drakef7cf40d2000-12-14 18:16:11 +0000610
611AttributeList = NamedNodeMap
612
Fred Drake1f549022000-09-24 05:21:58 +0000613
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000614class TypeInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000615 __slots__ = 'namespace', 'name'
616
617 def __init__(self, namespace, name):
618 self.namespace = namespace
619 self.name = name
620
621 def __repr__(self):
622 if self.namespace:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000623 return "<TypeInfo %r (from %r)>" % (self.name, self.namespace)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000624 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000625 return "<TypeInfo %r>" % self.name
Martin v. Löwis787354c2003-01-25 15:28:29 +0000626
627 def _get_name(self):
628 return self.name
629
630 def _get_namespace(self):
631 return self.namespace
632
633_no_type = TypeInfo(None, None)
634
Martin v. Löwisa2fda0d2000-10-07 12:10:28 +0000635class Element(Node):
Fred Drake1f549022000-09-24 05:21:58 +0000636 nodeType = Node.ELEMENT_NODE
Martin v. Löwis787354c2003-01-25 15:28:29 +0000637 nodeValue = None
638 schemaType = _no_type
639
640 _magic_id_nodes = 0
641
642 _child_node_types = (Node.ELEMENT_NODE,
643 Node.PROCESSING_INSTRUCTION_NODE,
644 Node.COMMENT_NODE,
645 Node.TEXT_NODE,
646 Node.CDATA_SECTION_NODE,
647 Node.ENTITY_REFERENCE_NODE)
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000648
Fred Drake49a5d032001-11-30 22:21:58 +0000649 def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None,
Fred Drake1f549022000-09-24 05:21:58 +0000650 localName=None):
Fred Drake55c38192000-06-29 19:39:57 +0000651 self.tagName = self.nodeName = tagName
Fred Drake1f549022000-09-24 05:21:58 +0000652 self.prefix = prefix
653 self.namespaceURI = namespaceURI
Martin v. Löwis787354c2003-01-25 15:28:29 +0000654 self.childNodes = NodeList()
Fred Drake55c38192000-06-29 19:39:57 +0000655
Fred Drake4ccf4a12000-11-21 22:02:22 +0000656 self._attrs = {} # attributes are double-indexed:
657 self._attrsNS = {} # tagName -> Attribute
658 # URI,localName -> Attribute
659 # in the future: consider lazy generation
660 # of attribute objects this is too tricky
661 # for now because of headaches with
662 # namespaces.
663
Martin v. Löwis787354c2003-01-25 15:28:29 +0000664 def _get_localName(self):
665 return self.tagName.split(":", 1)[-1]
666
667 def _get_tagName(self):
668 return self.tagName
Fred Drake4ccf4a12000-11-21 22:02:22 +0000669
670 def unlink(self):
671 for attr in self._attrs.values():
672 attr.unlink()
673 self._attrs = None
674 self._attrsNS = None
675 Node.unlink(self)
Fred Drake55c38192000-06-29 19:39:57 +0000676
Fred Drake1f549022000-09-24 05:21:58 +0000677 def getAttribute(self, attname):
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000678 try:
679 return self._attrs[attname].value
680 except KeyError:
681 return ""
Fred Drake55c38192000-06-29 19:39:57 +0000682
Fred Drake1f549022000-09-24 05:21:58 +0000683 def getAttributeNS(self, namespaceURI, localName):
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000684 try:
685 return self._attrsNS[(namespaceURI, localName)].value
686 except KeyError:
687 return ""
Fred Drake1f549022000-09-24 05:21:58 +0000688
689 def setAttribute(self, attname, value):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000690 attr = self.getAttributeNode(attname)
691 if attr is None:
692 attr = Attr(attname)
693 # for performance
694 d = attr.__dict__
695 d["value"] = d["nodeValue"] = value
696 d["ownerDocument"] = self.ownerDocument
697 self.setAttributeNode(attr)
698 elif value != attr.value:
699 d = attr.__dict__
700 d["value"] = d["nodeValue"] = value
701 if attr.isId:
702 _clear_id_cache(self)
Fred Drake55c38192000-06-29 19:39:57 +0000703
Fred Drake1f549022000-09-24 05:21:58 +0000704 def setAttributeNS(self, namespaceURI, qualifiedName, value):
705 prefix, localname = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000706 attr = self.getAttributeNodeNS(namespaceURI, localname)
707 if attr is None:
708 # for performance
709 attr = Attr(qualifiedName, namespaceURI, localname, prefix)
710 d = attr.__dict__
711 d["prefix"] = prefix
712 d["nodeName"] = qualifiedName
713 d["value"] = d["nodeValue"] = value
714 d["ownerDocument"] = self.ownerDocument
715 self.setAttributeNode(attr)
716 else:
717 d = attr.__dict__
718 if value != attr.value:
719 d["value"] = d["nodeValue"] = value
720 if attr.isId:
721 _clear_id_cache(self)
722 if attr.prefix != prefix:
723 d["prefix"] = prefix
724 d["nodeName"] = qualifiedName
Fred Drake55c38192000-06-29 19:39:57 +0000725
Fred Drake1f549022000-09-24 05:21:58 +0000726 def getAttributeNode(self, attrname):
727 return self._attrs.get(attrname)
Paul Prescod73678da2000-07-01 04:58:47 +0000728
Fred Drake1f549022000-09-24 05:21:58 +0000729 def getAttributeNodeNS(self, namespaceURI, localName):
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000730 return self._attrsNS.get((namespaceURI, localName))
Paul Prescod73678da2000-07-01 04:58:47 +0000731
Fred Drake1f549022000-09-24 05:21:58 +0000732 def setAttributeNode(self, attr):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000733 if attr.ownerElement not in (None, self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000734 raise xml.dom.InuseAttributeErr("attribute node already owned")
Martin v. Löwis787354c2003-01-25 15:28:29 +0000735 old1 = self._attrs.get(attr.name, None)
736 if old1 is not None:
737 self.removeAttributeNode(old1)
738 old2 = self._attrsNS.get((attr.namespaceURI, attr.localName), None)
739 if old2 is not None and old2 is not old1:
740 self.removeAttributeNode(old2)
741 _set_attribute_node(self, attr)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000742
Martin v. Löwis787354c2003-01-25 15:28:29 +0000743 if old1 is not attr:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000744 # It might have already been part of this node, in which case
745 # it doesn't represent a change, and should not be returned.
Martin v. Löwis787354c2003-01-25 15:28:29 +0000746 return old1
747 if old2 is not attr:
748 return old2
Fred Drake55c38192000-06-29 19:39:57 +0000749
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000750 setAttributeNodeNS = setAttributeNode
751
Fred Drake1f549022000-09-24 05:21:58 +0000752 def removeAttribute(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000753 try:
754 attr = self._attrs[name]
755 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000756 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000757 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000758
Fred Drake1f549022000-09-24 05:21:58 +0000759 def removeAttributeNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000760 try:
761 attr = self._attrsNS[(namespaceURI, localName)]
762 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000763 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000764 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000765
Fred Drake1f549022000-09-24 05:21:58 +0000766 def removeAttributeNode(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000767 if node is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000768 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000769 try:
770 self._attrs[node.name]
771 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000772 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000773 _clear_id_cache(self)
Paul Prescod73678da2000-07-01 04:58:47 +0000774 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000775 # Restore this since the node is still useful and otherwise
776 # unlinked
777 node.ownerDocument = self.ownerDocument
Fred Drake16f63292000-10-23 18:09:50 +0000778
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000779 removeAttributeNodeNS = removeAttributeNode
780
Martin v. Löwis156c3372000-12-28 18:40:56 +0000781 def hasAttribute(self, name):
782 return self._attrs.has_key(name)
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000783
Martin v. Löwis156c3372000-12-28 18:40:56 +0000784 def hasAttributeNS(self, namespaceURI, localName):
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000785 return self._attrsNS.has_key((namespaceURI, localName))
786
Fred Drake1f549022000-09-24 05:21:58 +0000787 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000788 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000789
Fred Drake1f549022000-09-24 05:21:58 +0000790 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000791 return _get_elements_by_tagName_ns_helper(
792 self, namespaceURI, localName, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000793
Fred Drake1f549022000-09-24 05:21:58 +0000794 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000795 return "<DOM Element: %s at %#x>" % (self.tagName, id(self))
Fred Drake55c38192000-06-29 19:39:57 +0000796
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000797 def writexml(self, writer, indent="", addindent="", newl=""):
798 # indent = current indentation
799 # addindent = indentation to add to higher levels
800 # newl = newline string
801 writer.write(indent+"<" + self.tagName)
Fred Drake16f63292000-10-23 18:09:50 +0000802
Fred Drake4ccf4a12000-11-21 22:02:22 +0000803 attrs = self._get_attributes()
804 a_names = attrs.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000805 a_names.sort()
806
807 for a_name in a_names:
Fred Drake1f549022000-09-24 05:21:58 +0000808 writer.write(" %s=\"" % a_name)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000809 _write_data(writer, attrs[a_name].value)
Fred Drake55c38192000-06-29 19:39:57 +0000810 writer.write("\"")
811 if self.childNodes:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000812 writer.write(">%s"%(newl))
Fred Drake55c38192000-06-29 19:39:57 +0000813 for node in self.childNodes:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000814 node.writexml(writer,indent+addindent,addindent,newl)
815 writer.write("%s</%s>%s" % (indent,self.tagName,newl))
Fred Drake55c38192000-06-29 19:39:57 +0000816 else:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000817 writer.write("/>%s"%(newl))
Fred Drake55c38192000-06-29 19:39:57 +0000818
Fred Drake1f549022000-09-24 05:21:58 +0000819 def _get_attributes(self):
Fred Drake2998a552001-12-06 18:27:48 +0000820 return NamedNodeMap(self._attrs, self._attrsNS, self)
Fred Drake55c38192000-06-29 19:39:57 +0000821
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000822 def hasAttributes(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000823 if self._attrs:
824 return True
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000825 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000826 return False
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000827
Martin v. Löwis787354c2003-01-25 15:28:29 +0000828 # DOM Level 3 attributes, based on the 22 Oct 2002 draft
829
830 def setIdAttribute(self, name):
831 idAttr = self.getAttributeNode(name)
832 self.setIdAttributeNode(idAttr)
833
834 def setIdAttributeNS(self, namespaceURI, localName):
835 idAttr = self.getAttributeNodeNS(namespaceURI, localName)
836 self.setIdAttributeNode(idAttr)
837
838 def setIdAttributeNode(self, idAttr):
839 if idAttr is None or not self.isSameNode(idAttr.ownerElement):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000840 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000841 if _get_containing_entref(self) is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000842 raise xml.dom.NoModificationAllowedErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000843 if not idAttr._is_id:
844 idAttr.__dict__['_is_id'] = True
845 self._magic_id_nodes += 1
846 self.ownerDocument._magic_id_count += 1
847 _clear_id_cache(self)
848
849defproperty(Element, "attributes",
850 doc="NamedNodeMap of attributes on the element.")
851defproperty(Element, "localName",
852 doc="Namespace-local name of this element.")
853
854
855def _set_attribute_node(element, attr):
856 _clear_id_cache(element)
857 element._attrs[attr.name] = attr
858 element._attrsNS[(attr.namespaceURI, attr.localName)] = attr
859
860 # This creates a circular reference, but Element.unlink()
861 # breaks the cycle since the references to the attribute
862 # dictionaries are tossed.
863 attr.__dict__['ownerElement'] = element
864
865
866class Childless:
867 """Mixin that makes childless-ness easy to implement and avoids
868 the complexity of the Node methods that deal with children.
869 """
870
Fred Drake4ccf4a12000-11-21 22:02:22 +0000871 attributes = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000872 childNodes = EmptyNodeList()
873 firstChild = None
874 lastChild = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000875
Martin v. Löwis787354c2003-01-25 15:28:29 +0000876 def _get_firstChild(self):
877 return None
Fred Drake55c38192000-06-29 19:39:57 +0000878
Martin v. Löwis787354c2003-01-25 15:28:29 +0000879 def _get_lastChild(self):
880 return None
Fred Drake1f549022000-09-24 05:21:58 +0000881
Martin v. Löwis787354c2003-01-25 15:28:29 +0000882 def appendChild(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000883 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000884 self.nodeName + " nodes cannot have children")
885
886 def hasChildNodes(self):
887 return False
888
889 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000890 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000891 self.nodeName + " nodes do not have children")
892
893 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000894 raise xml.dom.NotFoundErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000895 self.nodeName + " nodes do not have children")
896
897 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000898 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000899 self.nodeName + " nodes do not have children")
900
901
902class ProcessingInstruction(Childless, Node):
Fred Drake1f549022000-09-24 05:21:58 +0000903 nodeType = Node.PROCESSING_INSTRUCTION_NODE
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000904
Fred Drake1f549022000-09-24 05:21:58 +0000905 def __init__(self, target, data):
Fred Drake55c38192000-06-29 19:39:57 +0000906 self.target = self.nodeName = target
907 self.data = self.nodeValue = data
Fred Drake55c38192000-06-29 19:39:57 +0000908
Martin v. Löwis787354c2003-01-25 15:28:29 +0000909 def _get_data(self):
910 return self.data
911 def _set_data(self, value):
912 d = self.__dict__
913 d['data'] = d['nodeValue'] = value
914
915 def _get_target(self):
916 return self.target
917 def _set_target(self, value):
918 d = self.__dict__
919 d['target'] = d['nodeName'] = value
920
921 def __setattr__(self, name, value):
922 if name == "data" or name == "nodeValue":
923 self.__dict__['data'] = self.__dict__['nodeValue'] = value
924 elif name == "target" or name == "nodeName":
925 self.__dict__['target'] = self.__dict__['nodeName'] = value
926 else:
927 self.__dict__[name] = value
928
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000929 def writexml(self, writer, indent="", addindent="", newl=""):
930 writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))
Fred Drake55c38192000-06-29 19:39:57 +0000931
Martin v. Löwis787354c2003-01-25 15:28:29 +0000932
933class CharacterData(Childless, Node):
934 def _get_length(self):
935 return len(self.data)
936 __len__ = _get_length
937
938 def _get_data(self):
939 return self.__dict__['data']
940 def _set_data(self, data):
941 d = self.__dict__
942 d['data'] = d['nodeValue'] = data
943
944 _get_nodeValue = _get_data
945 _set_nodeValue = _set_data
946
947 def __setattr__(self, name, value):
948 if name == "data" or name == "nodeValue":
949 self.__dict__['data'] = self.__dict__['nodeValue'] = value
950 else:
951 self.__dict__[name] = value
Fred Drake87432f42001-04-04 14:09:46 +0000952
Fred Drake55c38192000-06-29 19:39:57 +0000953 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000954 data = self.data
955 if len(data) > 10:
Fred Drake1f549022000-09-24 05:21:58 +0000956 dotdotdot = "..."
Fred Drake55c38192000-06-29 19:39:57 +0000957 else:
Fred Drake1f549022000-09-24 05:21:58 +0000958 dotdotdot = ""
Fred Drake87432f42001-04-04 14:09:46 +0000959 return "<DOM %s node \"%s%s\">" % (
Martin v. Löwis787354c2003-01-25 15:28:29 +0000960 self.__class__.__name__, data[0:10], dotdotdot)
Fred Drake87432f42001-04-04 14:09:46 +0000961
962 def substringData(self, offset, count):
963 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000964 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +0000965 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000966 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +0000967 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000968 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +0000969 return self.data[offset:offset+count]
970
971 def appendData(self, arg):
972 self.data = self.data + arg
Fred Drake87432f42001-04-04 14:09:46 +0000973
974 def insertData(self, offset, arg):
975 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000976 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +0000977 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000978 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +0000979 if arg:
980 self.data = "%s%s%s" % (
981 self.data[:offset], arg, self.data[offset:])
Fred Drake87432f42001-04-04 14:09:46 +0000982
983 def deleteData(self, offset, count):
984 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000985 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +0000986 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000987 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +0000988 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000989 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +0000990 if count:
991 self.data = self.data[:offset] + self.data[offset+count:]
Fred Drake87432f42001-04-04 14:09:46 +0000992
993 def replaceData(self, offset, count, arg):
994 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000995 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +0000996 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000997 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +0000998 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000999 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001000 if count:
1001 self.data = "%s%s%s" % (
1002 self.data[:offset], arg, self.data[offset+count:])
Martin v. Löwis787354c2003-01-25 15:28:29 +00001003
1004defproperty(CharacterData, "length", doc="Length of the string data.")
1005
Fred Drake87432f42001-04-04 14:09:46 +00001006
1007class Text(CharacterData):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001008 # Make sure we don't add an instance __dict__ if we don't already
1009 # have one, at least when that's possible:
Martin v. Löwis995359c2003-01-26 08:59:32 +00001010 # XXX this does not work, CharacterData is an old-style class
1011 # __slots__ = ()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001012
Fred Drake87432f42001-04-04 14:09:46 +00001013 nodeType = Node.TEXT_NODE
1014 nodeName = "#text"
1015 attributes = None
Fred Drake55c38192000-06-29 19:39:57 +00001016
Fred Drakef7cf40d2000-12-14 18:16:11 +00001017 def splitText(self, offset):
1018 if offset < 0 or offset > len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001019 raise xml.dom.IndexSizeErr("illegal offset value")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001020 newText = self.__class__()
1021 newText.data = self.data[offset:]
1022 newText.ownerDocument = self.ownerDocument
Fred Drakef7cf40d2000-12-14 18:16:11 +00001023 next = self.nextSibling
1024 if self.parentNode and self in self.parentNode.childNodes:
1025 if next is None:
1026 self.parentNode.appendChild(newText)
1027 else:
1028 self.parentNode.insertBefore(newText, next)
1029 self.data = self.data[:offset]
1030 return newText
1031
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001032 def writexml(self, writer, indent="", addindent="", newl=""):
1033 _write_data(writer, "%s%s%s"%(indent, self.data, newl))
Fred Drake55c38192000-06-29 19:39:57 +00001034
Martin v. Löwis787354c2003-01-25 15:28:29 +00001035 # DOM Level 3 (WD 9 April 2002)
1036
1037 def _get_wholeText(self):
1038 L = [self.data]
1039 n = self.previousSibling
1040 while n is not None:
1041 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1042 L.insert(0, n.data)
1043 n = n.previousSibling
1044 else:
1045 break
1046 n = self.nextSibling
1047 while n is not None:
1048 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1049 L.append(n.data)
1050 n = n.nextSibling
1051 else:
1052 break
1053 return ''.join(L)
1054
1055 def replaceWholeText(self, content):
1056 # XXX This needs to be seriously changed if minidom ever
1057 # supports EntityReference nodes.
1058 parent = self.parentNode
1059 n = self.previousSibling
1060 while n is not None:
1061 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1062 next = n.previousSibling
1063 parent.removeChild(n)
1064 n = next
1065 else:
1066 break
1067 n = self.nextSibling
1068 if not content:
1069 parent.removeChild(self)
1070 while n is not None:
1071 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1072 next = n.nextSibling
1073 parent.removeChild(n)
1074 n = next
1075 else:
1076 break
1077 if content:
1078 d = self.__dict__
1079 d['data'] = content
1080 d['nodeValue'] = content
1081 return self
1082 else:
1083 return None
1084
1085 def _get_isWhitespaceInElementContent(self):
1086 if self.data.strip():
1087 return False
1088 elem = _get_containing_element(self)
1089 if elem is None:
1090 return False
1091 info = self.ownerDocument._get_elem_info(elem)
1092 if info is None:
1093 return False
1094 else:
1095 return info.isElementContent()
1096
1097defproperty(Text, "isWhitespaceInElementContent",
1098 doc="True iff this text node contains only whitespace"
1099 " and is in element content.")
1100defproperty(Text, "wholeText",
1101 doc="The text of all logically-adjacent text nodes.")
1102
1103
1104def _get_containing_element(node):
1105 c = node.parentNode
1106 while c is not None:
1107 if c.nodeType == Node.ELEMENT_NODE:
1108 return c
1109 c = c.parentNode
1110 return None
1111
1112def _get_containing_entref(node):
1113 c = node.parentNode
1114 while c is not None:
1115 if c.nodeType == Node.ENTITY_REFERENCE_NODE:
1116 return c
1117 c = c.parentNode
1118 return None
1119
1120
1121class Comment(Childless, CharacterData):
1122 nodeType = Node.COMMENT_NODE
1123 nodeName = "#comment"
1124
1125 def __init__(self, data):
1126 self.data = self.nodeValue = data
1127
1128 def writexml(self, writer, indent="", addindent="", newl=""):
1129 writer.write("%s<!--%s-->%s" % (indent, self.data, newl))
1130
Fred Drake87432f42001-04-04 14:09:46 +00001131
1132class CDATASection(Text):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001133 # Make sure we don't add an instance __dict__ if we don't already
1134 # have one, at least when that's possible:
Martin v. Löwis995359c2003-01-26 08:59:32 +00001135 # XXX this does not work, Text is an old-style class
1136 # __slots__ = ()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001137
Fred Drake87432f42001-04-04 14:09:46 +00001138 nodeType = Node.CDATA_SECTION_NODE
1139 nodeName = "#cdata-section"
1140
1141 def writexml(self, writer, indent="", addindent="", newl=""):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001142 if self.data.find("]]>") >= 0:
1143 raise ValueError("']]>' not allowed in a CDATA section")
Guido van Rossum5b5e0b92001-09-19 13:28:25 +00001144 writer.write("<![CDATA[%s]]>" % self.data)
Fred Drake87432f42001-04-04 14:09:46 +00001145
1146
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001147class ReadOnlySequentialNamedNodeMap(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001148 __slots__ = '_seq',
1149
1150 def __init__(self, seq=()):
1151 # seq should be a list or tuple
1152 self._seq = seq
1153
1154 def __len__(self):
1155 return len(self._seq)
1156
1157 def _get_length(self):
1158 return len(self._seq)
1159
1160 def getNamedItem(self, name):
1161 for n in self._seq:
1162 if n.nodeName == name:
1163 return n
1164
1165 def getNamedItemNS(self, namespaceURI, localName):
1166 for n in self._seq:
1167 if n.namespaceURI == namespaceURI and n.localName == localName:
1168 return n
1169
1170 def __getitem__(self, name_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001171 if isinstance(name_or_tuple, tuple):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001172 node = self.getNamedItemNS(*name_or_tuple)
1173 else:
1174 node = self.getNamedItem(name_or_tuple)
1175 if node is None:
1176 raise KeyError, name_or_tuple
1177 return node
1178
1179 def item(self, index):
1180 if index < 0:
1181 return None
1182 try:
1183 return self._seq[index]
1184 except IndexError:
1185 return None
1186
1187 def removeNamedItem(self, name):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001188 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001189 "NamedNodeMap instance is read-only")
1190
1191 def removeNamedItemNS(self, namespaceURI, localName):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001192 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001193 "NamedNodeMap instance is read-only")
1194
1195 def setNamedItem(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001196 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001197 "NamedNodeMap instance is read-only")
1198
1199 def setNamedItemNS(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001200 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001201 "NamedNodeMap instance is read-only")
1202
1203 def __getstate__(self):
1204 return [self._seq]
1205
1206 def __setstate__(self, state):
1207 self._seq = state[0]
1208
1209defproperty(ReadOnlySequentialNamedNodeMap, "length",
1210 doc="Number of entries in the NamedNodeMap.")
Paul Prescod73678da2000-07-01 04:58:47 +00001211
Fred Drakef7cf40d2000-12-14 18:16:11 +00001212
Martin v. Löwis787354c2003-01-25 15:28:29 +00001213class Identified:
1214 """Mix-in class that supports the publicId and systemId attributes."""
1215
Martin v. Löwis995359c2003-01-26 08:59:32 +00001216 # XXX this does not work, this is an old-style class
1217 # __slots__ = 'publicId', 'systemId'
Martin v. Löwis787354c2003-01-25 15:28:29 +00001218
1219 def _identified_mixin_init(self, publicId, systemId):
1220 self.publicId = publicId
1221 self.systemId = systemId
1222
1223 def _get_publicId(self):
1224 return self.publicId
1225
1226 def _get_systemId(self):
1227 return self.systemId
1228
1229class DocumentType(Identified, Childless, Node):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001230 nodeType = Node.DOCUMENT_TYPE_NODE
1231 nodeValue = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001232 name = None
1233 publicId = None
1234 systemId = None
Fred Drakedc806702001-04-05 14:41:30 +00001235 internalSubset = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001236
1237 def __init__(self, qualifiedName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001238 self.entities = ReadOnlySequentialNamedNodeMap()
1239 self.notations = ReadOnlySequentialNamedNodeMap()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001240 if qualifiedName:
1241 prefix, localname = _nssplit(qualifiedName)
1242 self.name = localname
Martin v. Löwis787354c2003-01-25 15:28:29 +00001243 self.nodeName = self.name
1244
1245 def _get_internalSubset(self):
1246 return self.internalSubset
1247
1248 def cloneNode(self, deep):
1249 if self.ownerDocument is None:
1250 # it's ok
1251 clone = DocumentType(None)
1252 clone.name = self.name
1253 clone.nodeName = self.name
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001254 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001255 if deep:
1256 clone.entities._seq = []
1257 clone.notations._seq = []
1258 for n in self.notations._seq:
1259 notation = Notation(n.nodeName, n.publicId, n.systemId)
1260 clone.notations._seq.append(notation)
1261 n._call_user_data_handler(operation, n, notation)
1262 for e in self.entities._seq:
1263 entity = Entity(e.nodeName, e.publicId, e.systemId,
1264 e.notationName)
1265 entity.actualEncoding = e.actualEncoding
1266 entity.encoding = e.encoding
1267 entity.version = e.version
1268 clone.entities._seq.append(entity)
1269 e._call_user_data_handler(operation, n, entity)
1270 self._call_user_data_handler(operation, self, clone)
1271 return clone
1272 else:
1273 return None
1274
1275 def writexml(self, writer, indent="", addindent="", newl=""):
1276 writer.write("<!DOCTYPE ")
1277 writer.write(self.name)
1278 if self.publicId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001279 writer.write("%s PUBLIC '%s'%s '%s'"
1280 % (newl, self.publicId, newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001281 elif self.systemId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001282 writer.write("%s SYSTEM '%s'" % (newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001283 if self.internalSubset is not None:
1284 writer.write(" [")
1285 writer.write(self.internalSubset)
1286 writer.write("]")
Georg Brandl175a7dc2005-08-25 22:02:43 +00001287 writer.write(">"+newl)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001288
1289class Entity(Identified, Node):
1290 attributes = None
1291 nodeType = Node.ENTITY_NODE
1292 nodeValue = None
1293
1294 actualEncoding = None
1295 encoding = None
1296 version = None
1297
1298 def __init__(self, name, publicId, systemId, notation):
1299 self.nodeName = name
1300 self.notationName = notation
1301 self.childNodes = NodeList()
1302 self._identified_mixin_init(publicId, systemId)
1303
1304 def _get_actualEncoding(self):
1305 return self.actualEncoding
1306
1307 def _get_encoding(self):
1308 return self.encoding
1309
1310 def _get_version(self):
1311 return self.version
1312
1313 def appendChild(self, newChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001314 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001315 "cannot append children to an entity node")
1316
1317 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001318 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001319 "cannot insert children below an entity node")
1320
1321 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001322 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001323 "cannot remove children from an entity node")
1324
1325 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001326 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001327 "cannot replace children of an entity node")
1328
1329class Notation(Identified, Childless, Node):
1330 nodeType = Node.NOTATION_NODE
1331 nodeValue = None
1332
1333 def __init__(self, name, publicId, systemId):
1334 self.nodeName = name
1335 self._identified_mixin_init(publicId, systemId)
Fred Drakef7cf40d2000-12-14 18:16:11 +00001336
1337
Martin v. Löwis787354c2003-01-25 15:28:29 +00001338class DOMImplementation(DOMImplementationLS):
1339 _features = [("core", "1.0"),
1340 ("core", "2.0"),
1341 ("core", "3.0"),
1342 ("core", None),
1343 ("xml", "1.0"),
1344 ("xml", "2.0"),
1345 ("xml", "3.0"),
1346 ("xml", None),
1347 ("ls-load", "3.0"),
1348 ("ls-load", None),
1349 ]
1350
Fred Drakef7cf40d2000-12-14 18:16:11 +00001351 def hasFeature(self, feature, version):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001352 if version == "":
1353 version = None
1354 return (feature.lower(), version) in self._features
Fred Drakef7cf40d2000-12-14 18:16:11 +00001355
1356 def createDocument(self, namespaceURI, qualifiedName, doctype):
1357 if doctype and doctype.parentNode is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001358 raise xml.dom.WrongDocumentErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001359 "doctype object owned by another DOM tree")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001360 doc = self._create_document()
1361
1362 add_root_element = not (namespaceURI is None
1363 and qualifiedName is None
1364 and doctype is None)
1365
1366 if not qualifiedName and add_root_element:
Martin v. Löwisb417be22001-02-06 01:16:06 +00001367 # The spec is unclear what to raise here; SyntaxErr
1368 # would be the other obvious candidate. Since Xerces raises
1369 # InvalidCharacterErr, and since SyntaxErr is not listed
1370 # for createDocument, that seems to be the better choice.
1371 # XXX: need to check for illegal characters here and in
1372 # createElement.
Martin v. Löwis787354c2003-01-25 15:28:29 +00001373
1374 # DOM Level III clears this up when talking about the return value
1375 # of this function. If namespaceURI, qName and DocType are
1376 # Null the document is returned without a document element
1377 # Otherwise if doctype or namespaceURI are not None
1378 # Then we go back to the above problem
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001379 raise xml.dom.InvalidCharacterErr("Element with no name")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001380
1381 if add_root_element:
1382 prefix, localname = _nssplit(qualifiedName)
1383 if prefix == "xml" \
1384 and namespaceURI != "http://www.w3.org/XML/1998/namespace":
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001385 raise xml.dom.NamespaceErr("illegal use of 'xml' prefix")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001386 if prefix and not namespaceURI:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001387 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001388 "illegal use of prefix without namespaces")
1389 element = doc.createElementNS(namespaceURI, qualifiedName)
1390 if doctype:
1391 doc.appendChild(doctype)
1392 doc.appendChild(element)
1393
1394 if doctype:
1395 doctype.parentNode = doctype.ownerDocument = doc
1396
Fred Drakef7cf40d2000-12-14 18:16:11 +00001397 doc.doctype = doctype
1398 doc.implementation = self
1399 return doc
1400
1401 def createDocumentType(self, qualifiedName, publicId, systemId):
1402 doctype = DocumentType(qualifiedName)
1403 doctype.publicId = publicId
1404 doctype.systemId = systemId
1405 return doctype
1406
Martin v. Löwis787354c2003-01-25 15:28:29 +00001407 # DOM Level 3 (WD 9 April 2002)
1408
1409 def getInterface(self, feature):
1410 if self.hasFeature(feature, None):
1411 return self
1412 else:
1413 return None
1414
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001415 # internal
Martin v. Löwis787354c2003-01-25 15:28:29 +00001416 def _create_document(self):
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001417 return Document()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001418
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001419class ElementInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001420 """Object that represents content-model information for an element.
1421
1422 This implementation is not expected to be used in practice; DOM
1423 builders should provide implementations which do the right thing
1424 using information available to it.
1425
1426 """
1427
1428 __slots__ = 'tagName',
1429
1430 def __init__(self, name):
1431 self.tagName = name
1432
1433 def getAttributeType(self, aname):
1434 return _no_type
1435
1436 def getAttributeTypeNS(self, namespaceURI, localName):
1437 return _no_type
1438
1439 def isElementContent(self):
1440 return False
1441
1442 def isEmpty(self):
1443 """Returns true iff this element is declared to have an EMPTY
1444 content model."""
1445 return False
1446
1447 def isId(self, aname):
1448 """Returns true iff the named attribte is a DTD-style ID."""
1449 return False
1450
1451 def isIdNS(self, namespaceURI, localName):
1452 """Returns true iff the identified attribute is a DTD-style ID."""
1453 return False
1454
1455 def __getstate__(self):
1456 return self.tagName
1457
1458 def __setstate__(self, state):
1459 self.tagName = state
1460
1461def _clear_id_cache(node):
1462 if node.nodeType == Node.DOCUMENT_NODE:
1463 node._id_cache.clear()
1464 node._id_search_stack = None
1465 elif _in_document(node):
1466 node.ownerDocument._id_cache.clear()
1467 node.ownerDocument._id_search_stack= None
1468
1469class Document(Node, DocumentLS):
1470 _child_node_types = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
1471 Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)
1472
Fred Drake1f549022000-09-24 05:21:58 +00001473 nodeType = Node.DOCUMENT_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +00001474 nodeName = "#document"
1475 nodeValue = None
1476 attributes = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001477 doctype = None
1478 parentNode = None
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001479 previousSibling = nextSibling = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001480
1481 implementation = DOMImplementation()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001482
1483 # Document attributes from Level 3 (WD 9 April 2002)
1484
1485 actualEncoding = None
1486 encoding = None
1487 standalone = None
1488 version = None
1489 strictErrorChecking = False
1490 errorHandler = None
1491 documentURI = None
1492
1493 _magic_id_count = 0
1494
1495 def __init__(self):
1496 self.childNodes = NodeList()
1497 # mapping of (namespaceURI, localName) -> ElementInfo
1498 # and tagName -> ElementInfo
1499 self._elem_info = {}
1500 self._id_cache = {}
1501 self._id_search_stack = None
1502
1503 def _get_elem_info(self, element):
1504 if element.namespaceURI:
1505 key = element.namespaceURI, element.localName
1506 else:
1507 key = element.tagName
1508 return self._elem_info.get(key)
1509
1510 def _get_actualEncoding(self):
1511 return self.actualEncoding
1512
1513 def _get_doctype(self):
1514 return self.doctype
1515
1516 def _get_documentURI(self):
1517 return self.documentURI
1518
1519 def _get_encoding(self):
1520 return self.encoding
1521
1522 def _get_errorHandler(self):
1523 return self.errorHandler
1524
1525 def _get_standalone(self):
1526 return self.standalone
1527
1528 def _get_strictErrorChecking(self):
1529 return self.strictErrorChecking
1530
1531 def _get_version(self):
1532 return self.version
Fred Drake55c38192000-06-29 19:39:57 +00001533
Fred Drake1f549022000-09-24 05:21:58 +00001534 def appendChild(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001535 if node.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001536 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001537 "%s cannot be child of %s" % (repr(node), repr(self)))
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001538 if node.parentNode is not None:
Martin v. Löwis787354c2003-01-25 15:28:29 +00001539 # This needs to be done before the next test since this
1540 # may *be* the document element, in which case it should
1541 # end up re-ordered to the end.
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001542 node.parentNode.removeChild(node)
1543
Fred Drakef7cf40d2000-12-14 18:16:11 +00001544 if node.nodeType == Node.ELEMENT_NODE \
1545 and self._get_documentElement():
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001546 raise xml.dom.HierarchyRequestErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001547 "two document elements disallowed")
Fred Drake4ccf4a12000-11-21 22:02:22 +00001548 return Node.appendChild(self, node)
Paul Prescod73678da2000-07-01 04:58:47 +00001549
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001550 def removeChild(self, oldChild):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001551 try:
1552 self.childNodes.remove(oldChild)
1553 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001554 raise xml.dom.NotFoundErr()
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001555 oldChild.nextSibling = oldChild.previousSibling = None
1556 oldChild.parentNode = None
1557 if self.documentElement is oldChild:
1558 self.documentElement = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +00001559
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001560 return oldChild
1561
Fred Drakef7cf40d2000-12-14 18:16:11 +00001562 def _get_documentElement(self):
1563 for node in self.childNodes:
1564 if node.nodeType == Node.ELEMENT_NODE:
1565 return node
1566
1567 def unlink(self):
1568 if self.doctype is not None:
1569 self.doctype.unlink()
1570 self.doctype = None
1571 Node.unlink(self)
1572
Martin v. Löwis787354c2003-01-25 15:28:29 +00001573 def cloneNode(self, deep):
1574 if not deep:
1575 return None
1576 clone = self.implementation.createDocument(None, None, None)
1577 clone.encoding = self.encoding
1578 clone.standalone = self.standalone
1579 clone.version = self.version
1580 for n in self.childNodes:
1581 childclone = _clone_node(n, deep, clone)
1582 assert childclone.ownerDocument.isSameNode(clone)
1583 clone.childNodes.append(childclone)
1584 if childclone.nodeType == Node.DOCUMENT_NODE:
1585 assert clone.documentElement is None
1586 elif childclone.nodeType == Node.DOCUMENT_TYPE_NODE:
1587 assert clone.doctype is None
1588 clone.doctype = childclone
1589 childclone.parentNode = clone
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001590 self._call_user_data_handler(xml.dom.UserDataHandler.NODE_CLONED,
Martin v. Löwis787354c2003-01-25 15:28:29 +00001591 self, clone)
1592 return clone
1593
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001594 def createDocumentFragment(self):
1595 d = DocumentFragment()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001596 d.ownerDocument = self
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001597 return d
Fred Drake55c38192000-06-29 19:39:57 +00001598
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001599 def createElement(self, tagName):
1600 e = Element(tagName)
1601 e.ownerDocument = self
1602 return e
Fred Drake55c38192000-06-29 19:39:57 +00001603
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001604 def createTextNode(self, data):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001605 if not isinstance(data, StringTypes):
1606 raise TypeError, "node contents must be a string"
1607 t = Text()
1608 t.data = data
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001609 t.ownerDocument = self
1610 return t
Fred Drake55c38192000-06-29 19:39:57 +00001611
Fred Drake87432f42001-04-04 14:09:46 +00001612 def createCDATASection(self, data):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001613 if not isinstance(data, StringTypes):
1614 raise TypeError, "node contents must be a string"
1615 c = CDATASection()
1616 c.data = data
Fred Drake87432f42001-04-04 14:09:46 +00001617 c.ownerDocument = self
1618 return c
1619
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001620 def createComment(self, data):
1621 c = Comment(data)
1622 c.ownerDocument = self
1623 return c
Fred Drake55c38192000-06-29 19:39:57 +00001624
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001625 def createProcessingInstruction(self, target, data):
1626 p = ProcessingInstruction(target, data)
1627 p.ownerDocument = self
1628 return p
1629
1630 def createAttribute(self, qName):
1631 a = Attr(qName)
1632 a.ownerDocument = self
Martin v. Löwiscb67ea12001-03-31 16:30:40 +00001633 a.value = ""
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001634 return a
Fred Drake55c38192000-06-29 19:39:57 +00001635
1636 def createElementNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001637 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001638 e = Element(qualifiedName, namespaceURI, prefix)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001639 e.ownerDocument = self
1640 return e
Fred Drake55c38192000-06-29 19:39:57 +00001641
1642 def createAttributeNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001643 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001644 a = Attr(qualifiedName, namespaceURI, localName, prefix)
1645 a.ownerDocument = self
Martin v. Löwiscb67ea12001-03-31 16:30:40 +00001646 a.value = ""
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001647 return a
Fred Drake55c38192000-06-29 19:39:57 +00001648
Martin v. Löwis787354c2003-01-25 15:28:29 +00001649 # A couple of implementation-specific helpers to create node types
1650 # not supported by the W3C DOM specs:
1651
1652 def _create_entity(self, name, publicId, systemId, notationName):
1653 e = Entity(name, publicId, systemId, notationName)
1654 e.ownerDocument = self
1655 return e
1656
1657 def _create_notation(self, name, publicId, systemId):
1658 n = Notation(name, publicId, systemId)
1659 n.ownerDocument = self
1660 return n
1661
1662 def getElementById(self, id):
1663 if self._id_cache.has_key(id):
1664 return self._id_cache[id]
1665 if not (self._elem_info or self._magic_id_count):
1666 return None
1667
1668 stack = self._id_search_stack
1669 if stack is None:
1670 # we never searched before, or the cache has been cleared
1671 stack = [self.documentElement]
1672 self._id_search_stack = stack
1673 elif not stack:
1674 # Previous search was completed and cache is still valid;
1675 # no matching node.
1676 return None
1677
1678 result = None
1679 while stack:
1680 node = stack.pop()
1681 # add child elements to stack for continued searching
1682 stack.extend([child for child in node.childNodes
1683 if child.nodeType in _nodeTypes_with_children])
1684 # check this node
1685 info = self._get_elem_info(node)
1686 if info:
1687 # We have to process all ID attributes before
1688 # returning in order to get all the attributes set to
1689 # be IDs using Element.setIdAttribute*().
1690 for attr in node.attributes.values():
1691 if attr.namespaceURI:
1692 if info.isIdNS(attr.namespaceURI, attr.localName):
1693 self._id_cache[attr.value] = node
1694 if attr.value == id:
1695 result = node
1696 elif not node._magic_id_nodes:
1697 break
1698 elif info.isId(attr.name):
1699 self._id_cache[attr.value] = node
1700 if attr.value == id:
1701 result = node
1702 elif not node._magic_id_nodes:
1703 break
1704 elif attr._is_id:
1705 self._id_cache[attr.value] = node
1706 if attr.value == id:
1707 result = node
1708 elif node._magic_id_nodes == 1:
1709 break
1710 elif node._magic_id_nodes:
1711 for attr in node.attributes.values():
1712 if attr._is_id:
1713 self._id_cache[attr.value] = node
1714 if attr.value == id:
1715 result = node
1716 if result is not None:
1717 break
1718 return result
1719
Fred Drake1f549022000-09-24 05:21:58 +00001720 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001721 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drakefbe7b4f2001-07-04 06:25:53 +00001722
1723 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001724 return _get_elements_by_tagName_ns_helper(
1725 self, namespaceURI, localName, NodeList())
1726
1727 def isSupported(self, feature, version):
1728 return self.implementation.hasFeature(feature, version)
1729
1730 def importNode(self, node, deep):
1731 if node.nodeType == Node.DOCUMENT_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001732 raise xml.dom.NotSupportedErr("cannot import document nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001733 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001734 raise xml.dom.NotSupportedErr("cannot import document type nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001735 return _clone_node(node, deep, self)
Fred Drake55c38192000-06-29 19:39:57 +00001736
Martin v. Löwis7d650ca2002-06-30 15:05:00 +00001737 def writexml(self, writer, indent="", addindent="", newl="",
1738 encoding = None):
1739 if encoding is None:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001740 writer.write('<?xml version="1.0" ?>'+newl)
Martin v. Löwis7d650ca2002-06-30 15:05:00 +00001741 else:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001742 writer.write('<?xml version="1.0" encoding="%s"?>%s' % (encoding, newl))
Fred Drake55c38192000-06-29 19:39:57 +00001743 for node in self.childNodes:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001744 node.writexml(writer, indent, addindent, newl)
Fred Drake55c38192000-06-29 19:39:57 +00001745
Martin v. Löwis787354c2003-01-25 15:28:29 +00001746 # DOM Level 3 (WD 9 April 2002)
1747
1748 def renameNode(self, n, namespaceURI, name):
1749 if n.ownerDocument is not self:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001750 raise xml.dom.WrongDocumentErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001751 "cannot rename nodes from other documents;\n"
1752 "expected %s,\nfound %s" % (self, n.ownerDocument))
1753 if n.nodeType not in (Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001754 raise xml.dom.NotSupportedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001755 "renameNode() only applies to element and attribute nodes")
1756 if namespaceURI != EMPTY_NAMESPACE:
1757 if ':' in name:
1758 prefix, localName = name.split(':', 1)
1759 if ( prefix == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001760 and namespaceURI != xml.dom.XMLNS_NAMESPACE):
1761 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001762 "illegal use of 'xmlns' prefix")
1763 else:
1764 if ( name == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001765 and namespaceURI != xml.dom.XMLNS_NAMESPACE
Martin v. Löwis787354c2003-01-25 15:28:29 +00001766 and n.nodeType == Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001767 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001768 "illegal use of the 'xmlns' attribute")
1769 prefix = None
1770 localName = name
1771 else:
1772 prefix = None
1773 localName = None
1774 if n.nodeType == Node.ATTRIBUTE_NODE:
1775 element = n.ownerElement
1776 if element is not None:
1777 is_id = n._is_id
1778 element.removeAttributeNode(n)
1779 else:
1780 element = None
1781 # avoid __setattr__
1782 d = n.__dict__
1783 d['prefix'] = prefix
1784 d['localName'] = localName
1785 d['namespaceURI'] = namespaceURI
1786 d['nodeName'] = name
1787 if n.nodeType == Node.ELEMENT_NODE:
1788 d['tagName'] = name
1789 else:
1790 # attribute node
1791 d['name'] = name
1792 if element is not None:
1793 element.setAttributeNode(n)
1794 if is_id:
1795 element.setIdAttributeNode(n)
1796 # It's not clear from a semantic perspective whether we should
1797 # call the user data handlers for the NODE_RENAMED event since
1798 # we're re-using the existing node. The draft spec has been
1799 # interpreted as meaning "no, don't call the handler unless a
1800 # new node is created."
1801 return n
1802
1803defproperty(Document, "documentElement",
1804 doc="Top-level element of this document.")
1805
1806
1807def _clone_node(node, deep, newOwnerDocument):
1808 """
1809 Clone a node and give it the new owner document.
1810 Called by Node.cloneNode and Document.importNode
1811 """
1812 if node.ownerDocument.isSameNode(newOwnerDocument):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001813 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001814 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001815 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001816 if node.nodeType == Node.ELEMENT_NODE:
1817 clone = newOwnerDocument.createElementNS(node.namespaceURI,
1818 node.nodeName)
1819 for attr in node.attributes.values():
1820 clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value)
1821 a = clone.getAttributeNodeNS(attr.namespaceURI, attr.localName)
1822 a.specified = attr.specified
1823
1824 if deep:
1825 for child in node.childNodes:
1826 c = _clone_node(child, deep, newOwnerDocument)
1827 clone.appendChild(c)
1828
1829 elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
1830 clone = newOwnerDocument.createDocumentFragment()
1831 if deep:
1832 for child in node.childNodes:
1833 c = _clone_node(child, deep, newOwnerDocument)
1834 clone.appendChild(c)
1835
1836 elif node.nodeType == Node.TEXT_NODE:
1837 clone = newOwnerDocument.createTextNode(node.data)
1838 elif node.nodeType == Node.CDATA_SECTION_NODE:
1839 clone = newOwnerDocument.createCDATASection(node.data)
1840 elif node.nodeType == Node.PROCESSING_INSTRUCTION_NODE:
1841 clone = newOwnerDocument.createProcessingInstruction(node.target,
1842 node.data)
1843 elif node.nodeType == Node.COMMENT_NODE:
1844 clone = newOwnerDocument.createComment(node.data)
1845 elif node.nodeType == Node.ATTRIBUTE_NODE:
1846 clone = newOwnerDocument.createAttributeNS(node.namespaceURI,
1847 node.nodeName)
1848 clone.specified = True
1849 clone.value = node.value
1850 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
1851 assert node.ownerDocument is not newOwnerDocument
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001852 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001853 clone = newOwnerDocument.implementation.createDocumentType(
1854 node.name, node.publicId, node.systemId)
1855 clone.ownerDocument = newOwnerDocument
1856 if deep:
1857 clone.entities._seq = []
1858 clone.notations._seq = []
1859 for n in node.notations._seq:
1860 notation = Notation(n.nodeName, n.publicId, n.systemId)
1861 notation.ownerDocument = newOwnerDocument
1862 clone.notations._seq.append(notation)
1863 if hasattr(n, '_call_user_data_handler'):
1864 n._call_user_data_handler(operation, n, notation)
1865 for e in node.entities._seq:
1866 entity = Entity(e.nodeName, e.publicId, e.systemId,
1867 e.notationName)
1868 entity.actualEncoding = e.actualEncoding
1869 entity.encoding = e.encoding
1870 entity.version = e.version
1871 entity.ownerDocument = newOwnerDocument
1872 clone.entities._seq.append(entity)
1873 if hasattr(e, '_call_user_data_handler'):
1874 e._call_user_data_handler(operation, n, entity)
1875 else:
1876 # Note the cloning of Document and DocumentType nodes is
1877 # implemenetation specific. minidom handles those cases
1878 # directly in the cloneNode() methods.
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001879 raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001880
1881 # Check for _call_user_data_handler() since this could conceivably
1882 # used with other DOM implementations (one of the FourThought
1883 # DOMs, perhaps?).
1884 if hasattr(node, '_call_user_data_handler'):
1885 node._call_user_data_handler(operation, node, clone)
1886 return clone
1887
1888
1889def _nssplit(qualifiedName):
1890 fields = qualifiedName.split(':', 1)
1891 if len(fields) == 2:
1892 return fields
1893 else:
1894 return (None, fields[0])
1895
1896
Fred Drake4ccf4a12000-11-21 22:02:22 +00001897def _get_StringIO():
Fred Drakef7cf40d2000-12-14 18:16:11 +00001898 # we can't use cStringIO since it doesn't support Unicode strings
1899 from StringIO import StringIO
Fred Drake4ccf4a12000-11-21 22:02:22 +00001900 return StringIO()
1901
Martin v. Löwis787354c2003-01-25 15:28:29 +00001902def _do_pulldom_parse(func, args, kwargs):
Raymond Hettingerff41c482003-04-06 09:01:11 +00001903 events = func(*args, **kwargs)
Fred Drake1f549022000-09-24 05:21:58 +00001904 toktype, rootNode = events.getEvent()
1905 events.expandNode(rootNode)
Martin v. Löwisb417be22001-02-06 01:16:06 +00001906 events.clear()
Fred Drake55c38192000-06-29 19:39:57 +00001907 return rootNode
1908
Martin v. Löwis787354c2003-01-25 15:28:29 +00001909def parse(file, parser=None, bufsize=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001910 """Parse a file into a DOM by filename or file object."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001911 if parser is None and not bufsize:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001912 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001913 return expatbuilder.parse(file)
1914 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001915 from xml.dom import pulldom
Raymond Hettingerff41c482003-04-06 09:01:11 +00001916 return _do_pulldom_parse(pulldom.parse, (file,),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001917 {'parser': parser, 'bufsize': bufsize})
Fred Drake55c38192000-06-29 19:39:57 +00001918
Martin v. Löwis787354c2003-01-25 15:28:29 +00001919def parseString(string, parser=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001920 """Parse a file into a DOM from a string."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001921 if parser is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001922 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001923 return expatbuilder.parseString(string)
1924 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001925 from xml.dom import pulldom
Martin v. Löwis787354c2003-01-25 15:28:29 +00001926 return _do_pulldom_parse(pulldom.parseString, (string,),
1927 {'parser': parser})
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001928
Martin v. Löwis787354c2003-01-25 15:28:29 +00001929def getDOMImplementation(features=None):
1930 if features:
1931 if isinstance(features, StringTypes):
1932 features = domreg._parse_feature_string(features)
1933 for f, v in features:
1934 if not Document.implementation.hasFeature(f, v):
1935 return None
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001936 return Document.implementation