blob: f4f4400d896bea113031638ce38e83adee77b194 [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
Alexandre Vassalotti794652d2008-06-11 22:58:36 +000017import codecs
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000018import io
Thomas Wouters0e3f5912006-08-11 14:57:12 +000019import xml.dom
Fred Drake55c38192000-06-29 19:39:57 +000020
Thomas Wouters0e3f5912006-08-11 14:57:12 +000021from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE, domreg
22from xml.dom.minicompat import *
23from xml.dom.xmlbuilder import DOMImplementationLS, DocumentLS
Fred Drake3ac6a092001-09-28 04:33:06 +000024
Martin v. Löwis787354c2003-01-25 15:28:29 +000025# This is used by the ID-cache invalidation checks; the list isn't
26# actually complete, since the nodes being checked will never be the
27# DOCUMENT_NODE or DOCUMENT_FRAGMENT_NODE. (The node being checked is
28# the node being added or removed, not the node being modified.)
29#
Thomas Wouters0e3f5912006-08-11 14:57:12 +000030_nodeTypes_with_children = (xml.dom.Node.ELEMENT_NODE,
31 xml.dom.Node.ENTITY_REFERENCE_NODE)
Martin v. Löwis95700f72002-03-15 13:51:59 +000032
Fred Drake3ac6a092001-09-28 04:33:06 +000033
Thomas Wouters0e3f5912006-08-11 14:57:12 +000034class Node(xml.dom.Node):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000035 namespaceURI = None # this is non-null only for elements and attributes
Fred Drake575712e2001-09-28 20:25:45 +000036 parentNode = None
37 ownerDocument = None
Martin v. Löwis787354c2003-01-25 15:28:29 +000038 nextSibling = None
39 previousSibling = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +000040
Martin v. Löwis787354c2003-01-25 15:28:29 +000041 prefix = EMPTY_PREFIX # non-null only for NS elements and attributes
Fred Drake55c38192000-06-29 19:39:57 +000042
Jack Diederich4dafcc42006-11-28 19:15:13 +000043 def __bool__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +000044 return True
Fred Drake55c38192000-06-29 19:39:57 +000045
Georg Brandlfe991052009-09-16 15:54:04 +000046 def toxml(self, encoding=None):
Martin v. Löwis7d650ca2002-06-30 15:05:00 +000047 return self.toprettyxml("", "", encoding)
Fred Drake55c38192000-06-29 19:39:57 +000048
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000049 def toprettyxml(self, indent="\t", newl="\n", encoding=None):
Martin v. Löwiscb67ea12001-03-31 16:30:40 +000050 # indent = the indentation string to prepend, per level
51 # newl = the newline string to append
Guido van Rossum55b15c92007-08-07 23:03:33 +000052 use_encoding = "utf-8" if encoding is None else encoding
Alexandre Vassalotti794652d2008-06-11 22:58:36 +000053 writer = codecs.getwriter(use_encoding)(io.BytesIO())
Martin v. Löwis7d650ca2002-06-30 15:05:00 +000054 if self.nodeType == Node.DOCUMENT_NODE:
55 # Can pass encoding only to document, to put it into XML header
56 self.writexml(writer, "", indent, newl, encoding)
57 else:
58 self.writexml(writer, "", indent, newl)
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000059 if encoding is None:
Alexandre Vassalotti794652d2008-06-11 22:58:36 +000060 return writer.stream.getvalue().decode(use_encoding)
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000061 else:
Alexandre Vassalotti794652d2008-06-11 22:58:36 +000062 return writer.stream.getvalue()
Martin v. Löwis46fa39a2001-02-06 00:14:08 +000063
Fred Drake1f549022000-09-24 05:21:58 +000064 def hasChildNodes(self):
65 if self.childNodes:
Martin v. Löwis787354c2003-01-25 15:28:29 +000066 return True
Fred Drake1f549022000-09-24 05:21:58 +000067 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +000068 return False
69
70 def _get_childNodes(self):
71 return self.childNodes
Fred Drake55c38192000-06-29 19:39:57 +000072
Fred Drake1f549022000-09-24 05:21:58 +000073 def _get_firstChild(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +000074 if self.childNodes:
75 return self.childNodes[0]
Paul Prescod73678da2000-07-01 04:58:47 +000076
Fred Drake1f549022000-09-24 05:21:58 +000077 def _get_lastChild(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +000078 if self.childNodes:
79 return self.childNodes[-1]
Paul Prescod73678da2000-07-01 04:58:47 +000080
Fred Drake1f549022000-09-24 05:21:58 +000081 def insertBefore(self, newChild, refChild):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000082 if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
Fred Drakee50959a2001-12-06 04:32:18 +000083 for c in tuple(newChild.childNodes):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000084 self.insertBefore(c, refChild)
85 ### The DOM does not clearly specify what to return in this case
86 return newChild
Martin v. Löwis787354c2003-01-25 15:28:29 +000087 if newChild.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000088 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +000089 "%s cannot be child of %s" % (repr(newChild), repr(self)))
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +000090 if newChild.parentNode is not None:
91 newChild.parentNode.removeChild(newChild)
Fred Drake4ccf4a12000-11-21 22:02:22 +000092 if refChild is None:
93 self.appendChild(newChild)
94 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +000095 try:
96 index = self.childNodes.index(refChild)
97 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000098 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +000099 if newChild.nodeType in _nodeTypes_with_children:
100 _clear_id_cache(self)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000101 self.childNodes.insert(index, newChild)
102 newChild.nextSibling = refChild
103 refChild.previousSibling = newChild
104 if index:
105 node = self.childNodes[index-1]
106 node.nextSibling = newChild
107 newChild.previousSibling = node
108 else:
109 newChild.previousSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000110 newChild.parentNode = self
Fred Drake4ccf4a12000-11-21 22:02:22 +0000111 return newChild
Fred Drake55c38192000-06-29 19:39:57 +0000112
Fred Drake1f549022000-09-24 05:21:58 +0000113 def appendChild(self, node):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000114 if node.nodeType == self.DOCUMENT_FRAGMENT_NODE:
Fred Drakee50959a2001-12-06 04:32:18 +0000115 for c in tuple(node.childNodes):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000116 self.appendChild(c)
117 ### The DOM does not clearly specify what to return in this case
118 return node
Martin v. Löwis787354c2003-01-25 15:28:29 +0000119 if node.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000120 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000121 "%s cannot be child of %s" % (repr(node), repr(self)))
122 elif node.nodeType in _nodeTypes_with_children:
123 _clear_id_cache(self)
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000124 if node.parentNode is not None:
125 node.parentNode.removeChild(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000126 _append_child(self, node)
Fred Drake13a30692000-10-09 20:04:16 +0000127 node.nextSibling = None
Paul Prescod73678da2000-07-01 04:58:47 +0000128 return node
129
Fred Drake1f549022000-09-24 05:21:58 +0000130 def replaceChild(self, newChild, oldChild):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000131 if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
132 refChild = oldChild.nextSibling
133 self.removeChild(oldChild)
134 return self.insertBefore(newChild, refChild)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000135 if newChild.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000136 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000137 "%s cannot be child of %s" % (repr(newChild), repr(self)))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000138 if newChild is oldChild:
139 return
Andrew M. Kuchling841d25e2005-11-22 19:03:16 +0000140 if newChild.parentNode is not None:
141 newChild.parentNode.removeChild(newChild)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000142 try:
143 index = self.childNodes.index(oldChild)
144 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000145 raise xml.dom.NotFoundErr()
Fred Drake4ccf4a12000-11-21 22:02:22 +0000146 self.childNodes[index] = newChild
Martin v. Löwis787354c2003-01-25 15:28:29 +0000147 newChild.parentNode = self
148 oldChild.parentNode = None
149 if (newChild.nodeType in _nodeTypes_with_children
150 or oldChild.nodeType in _nodeTypes_with_children):
151 _clear_id_cache(self)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000152 newChild.nextSibling = oldChild.nextSibling
153 newChild.previousSibling = oldChild.previousSibling
Martin v. Löwis156c3372000-12-28 18:40:56 +0000154 oldChild.nextSibling = None
Fred Drake4ccf4a12000-11-21 22:02:22 +0000155 oldChild.previousSibling = None
Martin v. Löwis156c3372000-12-28 18:40:56 +0000156 if newChild.previousSibling:
157 newChild.previousSibling.nextSibling = newChild
158 if newChild.nextSibling:
159 newChild.nextSibling.previousSibling = newChild
Fred Drake4ccf4a12000-11-21 22:02:22 +0000160 return oldChild
Paul Prescod73678da2000-07-01 04:58:47 +0000161
Fred Drake1f549022000-09-24 05:21:58 +0000162 def removeChild(self, oldChild):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000163 try:
164 self.childNodes.remove(oldChild)
165 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000166 raise xml.dom.NotFoundErr()
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000167 if oldChild.nextSibling is not None:
168 oldChild.nextSibling.previousSibling = oldChild.previousSibling
169 if oldChild.previousSibling is not None:
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000170 oldChild.previousSibling.nextSibling = oldChild.nextSibling
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000171 oldChild.nextSibling = oldChild.previousSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000172 if oldChild.nodeType in _nodeTypes_with_children:
173 _clear_id_cache(self)
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000174
Martin v. Löwis787354c2003-01-25 15:28:29 +0000175 oldChild.parentNode = None
Fred Drake4ccf4a12000-11-21 22:02:22 +0000176 return oldChild
177
178 def normalize(self):
Fred Drakef7cf40d2000-12-14 18:16:11 +0000179 L = []
180 for child in self.childNodes:
181 if child.nodeType == Node.TEXT_NODE:
R. David Murraydc6da8a2009-04-09 22:16:43 +0000182 if not child.data:
183 # empty text node; discard
184 if L:
185 L[-1].nextSibling = child.nextSibling
186 if child.nextSibling:
187 child.nextSibling.previousSibling = child.previousSibling
188 child.unlink()
189 elif L and L[-1].nodeType == child.nodeType:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000190 # collapse text node
191 node = L[-1]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000192 node.data = node.data + child.data
Fred Drake4ccf4a12000-11-21 22:02:22 +0000193 node.nextSibling = child.nextSibling
R. David Murraydc6da8a2009-04-09 22:16:43 +0000194 if child.nextSibling:
195 child.nextSibling.previousSibling = node
Fred Drake4ccf4a12000-11-21 22:02:22 +0000196 child.unlink()
R. David Murraydc6da8a2009-04-09 22:16:43 +0000197 else:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000198 L.append(child)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000199 else:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000200 L.append(child)
201 if child.nodeType == Node.ELEMENT_NODE:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000202 child.normalize()
Fred Drakef7cf40d2000-12-14 18:16:11 +0000203 self.childNodes[:] = L
Paul Prescod73678da2000-07-01 04:58:47 +0000204
Fred Drake1f549022000-09-24 05:21:58 +0000205 def cloneNode(self, deep):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000206 return _clone_node(self, deep, self.ownerDocument or self)
Fred Drake55c38192000-06-29 19:39:57 +0000207
Martin v. Löwis787354c2003-01-25 15:28:29 +0000208 def isSupported(self, feature, version):
209 return self.ownerDocument.implementation.hasFeature(feature, version)
210
211 def _get_localName(self):
212 # Overridden in Element and Attr where localName can be Non-Null
213 return None
214
215 # Node interfaces from Level 3 (WD 9 April 2002)
Fred Drake25239772001-02-02 19:40:19 +0000216
217 def isSameNode(self, other):
218 return self is other
219
Martin v. Löwis787354c2003-01-25 15:28:29 +0000220 def getInterface(self, feature):
221 if self.isSupported(feature, None):
222 return self
223 else:
224 return None
225
226 # The "user data" functions use a dictionary that is only present
227 # if some user data has been set, so be careful not to assume it
228 # exists.
229
230 def getUserData(self, key):
231 try:
232 return self._user_data[key][0]
233 except (AttributeError, KeyError):
234 return None
235
236 def setUserData(self, key, data, handler):
237 old = None
238 try:
239 d = self._user_data
240 except AttributeError:
241 d = {}
242 self._user_data = d
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000243 if key in d:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000244 old = d[key][0]
245 if data is None:
246 # ignore handlers passed for None
247 handler = None
248 if old is not None:
249 del d[key]
250 else:
251 d[key] = (data, handler)
252 return old
253
254 def _call_user_data_handler(self, operation, src, dst):
255 if hasattr(self, "_user_data"):
Brett Cannon861fd6f2007-02-21 22:05:37 +0000256 for key, (data, handler) in list(self._user_data.items()):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000257 if handler is not None:
258 handler.handle(operation, key, data, src, dst)
259
Fred Drake25239772001-02-02 19:40:19 +0000260 # minidom-specific API:
261
Fred Drake1f549022000-09-24 05:21:58 +0000262 def unlink(self):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000263 self.parentNode = self.ownerDocument = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000264 if self.childNodes:
265 for child in self.childNodes:
266 child.unlink()
267 self.childNodes = NodeList()
Paul Prescod4221ff02000-10-13 20:11:42 +0000268 self.previousSibling = None
269 self.nextSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000270
271defproperty(Node, "firstChild", doc="First child node, or None.")
272defproperty(Node, "lastChild", doc="Last child node, or None.")
273defproperty(Node, "localName", doc="Namespace-local name of this node.")
274
275
276def _append_child(self, node):
277 # fast path with less checks; usable by DOM builders if careful
278 childNodes = self.childNodes
279 if childNodes:
280 last = childNodes[-1]
281 node.__dict__["previousSibling"] = last
282 last.__dict__["nextSibling"] = node
283 childNodes.append(node)
284 node.__dict__["parentNode"] = self
285
286def _in_document(node):
287 # return True iff node is part of a document tree
288 while node is not None:
289 if node.nodeType == Node.DOCUMENT_NODE:
290 return True
291 node = node.parentNode
292 return False
Fred Drake55c38192000-06-29 19:39:57 +0000293
Fred Drake1f549022000-09-24 05:21:58 +0000294def _write_data(writer, data):
Fred Drake55c38192000-06-29 19:39:57 +0000295 "Writes datachars to writer."
Martin v. Löwis787354c2003-01-25 15:28:29 +0000296 data = data.replace("&", "&amp;").replace("<", "&lt;")
297 data = data.replace("\"", "&quot;").replace(">", "&gt;")
Fred Drake55c38192000-06-29 19:39:57 +0000298 writer.write(data)
299
Martin v. Löwis787354c2003-01-25 15:28:29 +0000300def _get_elements_by_tagName_helper(parent, name, rc):
Fred Drake55c38192000-06-29 19:39:57 +0000301 for node in parent.childNodes:
Fred Drake1f549022000-09-24 05:21:58 +0000302 if node.nodeType == Node.ELEMENT_NODE and \
303 (name == "*" or node.tagName == name):
304 rc.append(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000305 _get_elements_by_tagName_helper(node, name, rc)
Fred Drake55c38192000-06-29 19:39:57 +0000306 return rc
307
Martin v. Löwis787354c2003-01-25 15:28:29 +0000308def _get_elements_by_tagName_ns_helper(parent, nsURI, localName, rc):
Fred Drake55c38192000-06-29 19:39:57 +0000309 for node in parent.childNodes:
Fred Drake1f549022000-09-24 05:21:58 +0000310 if node.nodeType == Node.ELEMENT_NODE:
Martin v. Löwised525fb2001-06-03 14:06:42 +0000311 if ((localName == "*" or node.localName == localName) and
Fred Drake1f549022000-09-24 05:21:58 +0000312 (nsURI == "*" or node.namespaceURI == nsURI)):
313 rc.append(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000314 _get_elements_by_tagName_ns_helper(node, nsURI, localName, rc)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000315 return rc
Fred Drake55c38192000-06-29 19:39:57 +0000316
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000317class DocumentFragment(Node):
318 nodeType = Node.DOCUMENT_FRAGMENT_NODE
319 nodeName = "#document-fragment"
320 nodeValue = None
321 attributes = None
322 parentNode = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000323 _child_node_types = (Node.ELEMENT_NODE,
324 Node.TEXT_NODE,
325 Node.CDATA_SECTION_NODE,
326 Node.ENTITY_REFERENCE_NODE,
327 Node.PROCESSING_INSTRUCTION_NODE,
328 Node.COMMENT_NODE,
329 Node.NOTATION_NODE)
330
331 def __init__(self):
332 self.childNodes = NodeList()
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000333
334
Fred Drake55c38192000-06-29 19:39:57 +0000335class Attr(Node):
Fred Drake1f549022000-09-24 05:21:58 +0000336 nodeType = Node.ATTRIBUTE_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +0000337 attributes = None
338 ownerElement = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000339 specified = False
340 _is_id = False
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000341
Martin v. Löwis787354c2003-01-25 15:28:29 +0000342 _child_node_types = (Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE)
343
344 def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None,
345 prefix=None):
Fred Drake55c38192000-06-29 19:39:57 +0000346 # skip setattr for performance
Fred Drake4ccf4a12000-11-21 22:02:22 +0000347 d = self.__dict__
Fred Drake4ccf4a12000-11-21 22:02:22 +0000348 d["nodeName"] = d["name"] = qName
349 d["namespaceURI"] = namespaceURI
350 d["prefix"] = prefix
Martin v. Löwis787354c2003-01-25 15:28:29 +0000351 d['childNodes'] = NodeList()
352
353 # Add the single child node that represents the value of the attr
354 self.childNodes.append(Text())
355
Paul Prescod73678da2000-07-01 04:58:47 +0000356 # nodeValue and value are set elsewhere
Fred Drake55c38192000-06-29 19:39:57 +0000357
Martin v. Löwis787354c2003-01-25 15:28:29 +0000358 def _get_localName(self):
Alex Martelli0ee43512006-08-21 19:53:20 +0000359 if 'localName' in self.__dict__:
Guido van Rossum3e1f85e2007-07-27 18:03:11 +0000360 return self.__dict__['localName']
Martin v. Löwis787354c2003-01-25 15:28:29 +0000361 return self.nodeName.split(":", 1)[-1]
362
363 def _get_name(self):
364 return self.name
365
366 def _get_specified(self):
367 return self.specified
368
Fred Drake1f549022000-09-24 05:21:58 +0000369 def __setattr__(self, name, value):
Fred Drakef7cf40d2000-12-14 18:16:11 +0000370 d = self.__dict__
Fred Drake1f549022000-09-24 05:21:58 +0000371 if name in ("value", "nodeValue"):
Fred Drakef7cf40d2000-12-14 18:16:11 +0000372 d["value"] = d["nodeValue"] = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000373 d2 = self.childNodes[0].__dict__
374 d2["data"] = d2["nodeValue"] = value
375 if self.ownerElement is not None:
376 _clear_id_cache(self.ownerElement)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000377 elif name in ("name", "nodeName"):
378 d["name"] = d["nodeName"] = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000379 if self.ownerElement is not None:
380 _clear_id_cache(self.ownerElement)
Fred Drake55c38192000-06-29 19:39:57 +0000381 else:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000382 d[name] = value
Fred Drake55c38192000-06-29 19:39:57 +0000383
Martin v. Löwis995359c2003-01-26 08:59:32 +0000384 def _set_prefix(self, prefix):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000385 nsuri = self.namespaceURI
Martin v. Löwis995359c2003-01-26 08:59:32 +0000386 if prefix == "xmlns":
387 if nsuri and nsuri != XMLNS_NAMESPACE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000388 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000389 "illegal use of 'xmlns' prefix for the wrong namespace")
390 d = self.__dict__
391 d['prefix'] = prefix
392 if prefix is None:
393 newName = self.localName
394 else:
Martin v. Löwis995359c2003-01-26 08:59:32 +0000395 newName = "%s:%s" % (prefix, self.localName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000396 if self.ownerElement:
397 _clear_id_cache(self.ownerElement)
398 d['nodeName'] = d['name'] = newName
399
400 def _set_value(self, value):
401 d = self.__dict__
402 d['value'] = d['nodeValue'] = value
403 if self.ownerElement:
404 _clear_id_cache(self.ownerElement)
405 self.childNodes[0].data = value
406
407 def unlink(self):
408 # This implementation does not call the base implementation
409 # since most of that is not needed, and the expense of the
410 # method call is not warranted. We duplicate the removal of
411 # children, but that's all we needed from the base class.
412 elem = self.ownerElement
413 if elem is not None:
414 del elem._attrs[self.nodeName]
415 del elem._attrsNS[(self.namespaceURI, self.localName)]
416 if self._is_id:
417 self._is_id = False
418 elem._magic_id_nodes -= 1
419 self.ownerDocument._magic_id_count -= 1
420 for child in self.childNodes:
421 child.unlink()
422 del self.childNodes[:]
423
424 def _get_isId(self):
425 if self._is_id:
426 return True
427 doc = self.ownerDocument
428 elem = self.ownerElement
429 if doc is None or elem is None:
430 return False
431
432 info = doc._get_elem_info(elem)
433 if info is None:
434 return False
435 if self.namespaceURI:
436 return info.isIdNS(self.namespaceURI, self.localName)
437 else:
438 return info.isId(self.nodeName)
439
440 def _get_schemaType(self):
441 doc = self.ownerDocument
442 elem = self.ownerElement
443 if doc is None or elem is None:
444 return _no_type
445
446 info = doc._get_elem_info(elem)
447 if info is None:
448 return _no_type
449 if self.namespaceURI:
450 return info.getAttributeTypeNS(self.namespaceURI, self.localName)
451 else:
452 return info.getAttributeType(self.nodeName)
453
454defproperty(Attr, "isId", doc="True if this attribute is an ID.")
455defproperty(Attr, "localName", doc="Namespace-local name of this attribute.")
456defproperty(Attr, "schemaType", doc="Schema type for this attribute.")
Fred Drake4ccf4a12000-11-21 22:02:22 +0000457
Fred Drakef7cf40d2000-12-14 18:16:11 +0000458
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000459class NamedNodeMap(object):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000460 """The attribute list is a transient interface to the underlying
461 dictionaries. Mutations here will change the underlying element's
Fred Drakef7cf40d2000-12-14 18:16:11 +0000462 dictionary.
463
464 Ordering is imposed artificially and does not reflect the order of
465 attributes as found in an input document.
466 """
Fred Drake4ccf4a12000-11-21 22:02:22 +0000467
Martin v. Löwis787354c2003-01-25 15:28:29 +0000468 __slots__ = ('_attrs', '_attrsNS', '_ownerElement')
469
Fred Drake2998a552001-12-06 18:27:48 +0000470 def __init__(self, attrs, attrsNS, ownerElement):
Fred Drake1f549022000-09-24 05:21:58 +0000471 self._attrs = attrs
472 self._attrsNS = attrsNS
Fred Drake2998a552001-12-06 18:27:48 +0000473 self._ownerElement = ownerElement
Fred Drakef7cf40d2000-12-14 18:16:11 +0000474
Martin v. Löwis787354c2003-01-25 15:28:29 +0000475 def _get_length(self):
476 return len(self._attrs)
Fred Drake55c38192000-06-29 19:39:57 +0000477
Fred Drake1f549022000-09-24 05:21:58 +0000478 def item(self, index):
Fred Drake55c38192000-06-29 19:39:57 +0000479 try:
Brett Cannon861fd6f2007-02-21 22:05:37 +0000480 return self[list(self._attrs.keys())[index]]
Fred Drake55c38192000-06-29 19:39:57 +0000481 except IndexError:
482 return None
Fred Drake55c38192000-06-29 19:39:57 +0000483
Fred Drake1f549022000-09-24 05:21:58 +0000484 def items(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000485 L = []
486 for node in self._attrs.values():
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000487 L.append((node.nodeName, node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000488 return L
Fred Drake1f549022000-09-24 05:21:58 +0000489
490 def itemsNS(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000491 L = []
492 for node in self._attrs.values():
Fred Drake49a5d032001-11-30 22:21:58 +0000493 L.append(((node.namespaceURI, node.localName), node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000494 return L
Fred Drake16f63292000-10-23 18:09:50 +0000495
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000496 def __contains__(self, key):
Christian Heimesc9543e42007-11-28 08:28:28 +0000497 if isinstance(key, str):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000498 return key in self._attrs
Martin v. Löwis787354c2003-01-25 15:28:29 +0000499 else:
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000500 return key in self._attrsNS
Martin v. Löwis787354c2003-01-25 15:28:29 +0000501
Fred Drake1f549022000-09-24 05:21:58 +0000502 def keys(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000503 return self._attrs.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000504
Fred Drake1f549022000-09-24 05:21:58 +0000505 def keysNS(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000506 return self._attrsNS.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000507
Fred Drake1f549022000-09-24 05:21:58 +0000508 def values(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000509 return self._attrs.values()
Fred Drake55c38192000-06-29 19:39:57 +0000510
Martin v. Löwis787354c2003-01-25 15:28:29 +0000511 def get(self, name, value=None):
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000512 return self._attrs.get(name, value)
513
Martin v. Löwis787354c2003-01-25 15:28:29 +0000514 __len__ = _get_length
Fred Drake55c38192000-06-29 19:39:57 +0000515
Mark Dickinsona56c4672009-01-27 18:17:45 +0000516 def _cmp(self, other):
Fred Drake1f549022000-09-24 05:21:58 +0000517 if self._attrs is getattr(other, "_attrs", None):
Fred Drake55c38192000-06-29 19:39:57 +0000518 return 0
Fred Drake16f63292000-10-23 18:09:50 +0000519 else:
Mark Dickinsona56c4672009-01-27 18:17:45 +0000520 return (id(self) > id(other)) - (id(self) < id(other))
521
522 def __eq__(self, other):
523 return self._cmp(other) == 0
524
525 def __ge__(self, other):
526 return self._cmp(other) >= 0
527
528 def __gt__(self, other):
529 return self._cmp(other) > 0
530
531 def __le__(self, other):
532 return self._cmp(other) <= 0
533
534 def __lt__(self, other):
535 return self._cmp(other) < 0
536
537 def __ne__(self, other):
538 return self._cmp(other) != 0
Fred Drake55c38192000-06-29 19:39:57 +0000539
Fred Drake1f549022000-09-24 05:21:58 +0000540 def __getitem__(self, attname_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000541 if isinstance(attname_or_tuple, tuple):
Paul Prescod73678da2000-07-01 04:58:47 +0000542 return self._attrsNS[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000543 else:
Paul Prescod73678da2000-07-01 04:58:47 +0000544 return self._attrs[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000545
Paul Prescod1e688272000-07-01 19:21:47 +0000546 # same as set
Fred Drake1f549022000-09-24 05:21:58 +0000547 def __setitem__(self, attname, value):
Christian Heimesc9543e42007-11-28 08:28:28 +0000548 if isinstance(value, str):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000549 try:
550 node = self._attrs[attname]
551 except KeyError:
552 node = Attr(attname)
553 node.ownerDocument = self._ownerElement.ownerDocument
Martin v. Löwis995359c2003-01-26 08:59:32 +0000554 self.setNamedItem(node)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000555 node.value = value
Paul Prescod1e688272000-07-01 19:21:47 +0000556 else:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000557 if not isinstance(value, Attr):
Collin Winter70e79802007-08-24 18:57:22 +0000558 raise TypeError("value must be a string or Attr object")
Fred Drake1f549022000-09-24 05:21:58 +0000559 node = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000560 self.setNamedItem(node)
561
562 def getNamedItem(self, name):
563 try:
564 return self._attrs[name]
565 except KeyError:
566 return None
567
568 def getNamedItemNS(self, namespaceURI, localName):
569 try:
570 return self._attrsNS[(namespaceURI, localName)]
571 except KeyError:
572 return None
573
574 def removeNamedItem(self, name):
575 n = self.getNamedItem(name)
576 if n is not None:
577 _clear_id_cache(self._ownerElement)
578 del self._attrs[n.nodeName]
579 del self._attrsNS[(n.namespaceURI, n.localName)]
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000580 if 'ownerElement' in n.__dict__:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000581 n.__dict__['ownerElement'] = None
582 return n
583 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000584 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000585
586 def removeNamedItemNS(self, namespaceURI, localName):
587 n = self.getNamedItemNS(namespaceURI, localName)
588 if n is not None:
589 _clear_id_cache(self._ownerElement)
590 del self._attrsNS[(n.namespaceURI, n.localName)]
591 del self._attrs[n.nodeName]
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000592 if 'ownerElement' in n.__dict__:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000593 n.__dict__['ownerElement'] = None
594 return n
595 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000596 raise xml.dom.NotFoundErr()
Fred Drakef7cf40d2000-12-14 18:16:11 +0000597
598 def setNamedItem(self, node):
Andrew M. Kuchlingbc8f72c2001-02-21 01:30:26 +0000599 if not isinstance(node, Attr):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000600 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000601 "%s cannot be child of %s" % (repr(node), repr(self)))
Fred Drakef7cf40d2000-12-14 18:16:11 +0000602 old = self._attrs.get(node.name)
Paul Prescod1e688272000-07-01 19:21:47 +0000603 if old:
604 old.unlink()
Fred Drake1f549022000-09-24 05:21:58 +0000605 self._attrs[node.name] = node
606 self._attrsNS[(node.namespaceURI, node.localName)] = node
Fred Drake2998a552001-12-06 18:27:48 +0000607 node.ownerElement = self._ownerElement
Martin v. Löwis787354c2003-01-25 15:28:29 +0000608 _clear_id_cache(node.ownerElement)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000609 return old
610
611 def setNamedItemNS(self, node):
612 return self.setNamedItem(node)
Paul Prescod73678da2000-07-01 04:58:47 +0000613
Fred Drake1f549022000-09-24 05:21:58 +0000614 def __delitem__(self, attname_or_tuple):
615 node = self[attname_or_tuple]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000616 _clear_id_cache(node.ownerElement)
Paul Prescod73678da2000-07-01 04:58:47 +0000617 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000618
619 def __getstate__(self):
620 return self._attrs, self._attrsNS, self._ownerElement
621
622 def __setstate__(self, state):
623 self._attrs, self._attrsNS, self._ownerElement = state
624
625defproperty(NamedNodeMap, "length",
626 doc="Number of nodes in the NamedNodeMap.")
Fred Drakef7cf40d2000-12-14 18:16:11 +0000627
628AttributeList = NamedNodeMap
629
Fred Drake1f549022000-09-24 05:21:58 +0000630
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000631class TypeInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000632 __slots__ = 'namespace', 'name'
633
634 def __init__(self, namespace, name):
635 self.namespace = namespace
636 self.name = name
637
638 def __repr__(self):
639 if self.namespace:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000640 return "<TypeInfo %r (from %r)>" % (self.name, self.namespace)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000641 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000642 return "<TypeInfo %r>" % self.name
Martin v. Löwis787354c2003-01-25 15:28:29 +0000643
644 def _get_name(self):
645 return self.name
646
647 def _get_namespace(self):
648 return self.namespace
649
650_no_type = TypeInfo(None, None)
651
Martin v. Löwisa2fda0d2000-10-07 12:10:28 +0000652class Element(Node):
Fred Drake1f549022000-09-24 05:21:58 +0000653 nodeType = Node.ELEMENT_NODE
Martin v. Löwis787354c2003-01-25 15:28:29 +0000654 nodeValue = None
655 schemaType = _no_type
656
657 _magic_id_nodes = 0
658
659 _child_node_types = (Node.ELEMENT_NODE,
660 Node.PROCESSING_INSTRUCTION_NODE,
661 Node.COMMENT_NODE,
662 Node.TEXT_NODE,
663 Node.CDATA_SECTION_NODE,
664 Node.ENTITY_REFERENCE_NODE)
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000665
Fred Drake49a5d032001-11-30 22:21:58 +0000666 def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None,
Fred Drake1f549022000-09-24 05:21:58 +0000667 localName=None):
Fred Drake55c38192000-06-29 19:39:57 +0000668 self.tagName = self.nodeName = tagName
Fred Drake1f549022000-09-24 05:21:58 +0000669 self.prefix = prefix
670 self.namespaceURI = namespaceURI
Martin v. Löwis787354c2003-01-25 15:28:29 +0000671 self.childNodes = NodeList()
Fred Drake55c38192000-06-29 19:39:57 +0000672
Fred Drake4ccf4a12000-11-21 22:02:22 +0000673 self._attrs = {} # attributes are double-indexed:
674 self._attrsNS = {} # tagName -> Attribute
675 # URI,localName -> Attribute
676 # in the future: consider lazy generation
677 # of attribute objects this is too tricky
678 # for now because of headaches with
679 # namespaces.
680
Martin v. Löwis787354c2003-01-25 15:28:29 +0000681 def _get_localName(self):
Alex Martelli0ee43512006-08-21 19:53:20 +0000682 if 'localName' in self.__dict__:
Guido van Rossum3e1f85e2007-07-27 18:03:11 +0000683 return self.__dict__['localName']
Martin v. Löwis787354c2003-01-25 15:28:29 +0000684 return self.tagName.split(":", 1)[-1]
685
686 def _get_tagName(self):
687 return self.tagName
Fred Drake4ccf4a12000-11-21 22:02:22 +0000688
689 def unlink(self):
Brett Cannon861fd6f2007-02-21 22:05:37 +0000690 for attr in list(self._attrs.values()):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000691 attr.unlink()
692 self._attrs = None
693 self._attrsNS = None
694 Node.unlink(self)
Fred Drake55c38192000-06-29 19:39:57 +0000695
Fred Drake1f549022000-09-24 05:21:58 +0000696 def getAttribute(self, attname):
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000697 try:
698 return self._attrs[attname].value
699 except KeyError:
700 return ""
Fred Drake55c38192000-06-29 19:39:57 +0000701
Fred Drake1f549022000-09-24 05:21:58 +0000702 def getAttributeNS(self, namespaceURI, localName):
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000703 try:
704 return self._attrsNS[(namespaceURI, localName)].value
705 except KeyError:
706 return ""
Fred Drake1f549022000-09-24 05:21:58 +0000707
708 def setAttribute(self, attname, value):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000709 attr = self.getAttributeNode(attname)
710 if attr is None:
711 attr = Attr(attname)
712 # for performance
713 d = attr.__dict__
714 d["value"] = d["nodeValue"] = value
715 d["ownerDocument"] = self.ownerDocument
716 self.setAttributeNode(attr)
717 elif value != attr.value:
718 d = attr.__dict__
719 d["value"] = d["nodeValue"] = value
720 if attr.isId:
721 _clear_id_cache(self)
Fred Drake55c38192000-06-29 19:39:57 +0000722
Fred Drake1f549022000-09-24 05:21:58 +0000723 def setAttributeNS(self, namespaceURI, qualifiedName, value):
724 prefix, localname = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000725 attr = self.getAttributeNodeNS(namespaceURI, localname)
726 if attr is None:
727 # for performance
728 attr = Attr(qualifiedName, namespaceURI, localname, prefix)
729 d = attr.__dict__
730 d["prefix"] = prefix
731 d["nodeName"] = qualifiedName
732 d["value"] = d["nodeValue"] = value
733 d["ownerDocument"] = self.ownerDocument
734 self.setAttributeNode(attr)
735 else:
736 d = attr.__dict__
737 if value != attr.value:
738 d["value"] = d["nodeValue"] = value
739 if attr.isId:
740 _clear_id_cache(self)
741 if attr.prefix != prefix:
742 d["prefix"] = prefix
743 d["nodeName"] = qualifiedName
Fred Drake55c38192000-06-29 19:39:57 +0000744
Fred Drake1f549022000-09-24 05:21:58 +0000745 def getAttributeNode(self, attrname):
746 return self._attrs.get(attrname)
Paul Prescod73678da2000-07-01 04:58:47 +0000747
Fred Drake1f549022000-09-24 05:21:58 +0000748 def getAttributeNodeNS(self, namespaceURI, localName):
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000749 return self._attrsNS.get((namespaceURI, localName))
Paul Prescod73678da2000-07-01 04:58:47 +0000750
Fred Drake1f549022000-09-24 05:21:58 +0000751 def setAttributeNode(self, attr):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000752 if attr.ownerElement not in (None, self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000753 raise xml.dom.InuseAttributeErr("attribute node already owned")
Martin v. Löwis787354c2003-01-25 15:28:29 +0000754 old1 = self._attrs.get(attr.name, None)
755 if old1 is not None:
756 self.removeAttributeNode(old1)
757 old2 = self._attrsNS.get((attr.namespaceURI, attr.localName), None)
758 if old2 is not None and old2 is not old1:
759 self.removeAttributeNode(old2)
760 _set_attribute_node(self, attr)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000761
Martin v. Löwis787354c2003-01-25 15:28:29 +0000762 if old1 is not attr:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000763 # It might have already been part of this node, in which case
764 # it doesn't represent a change, and should not be returned.
Martin v. Löwis787354c2003-01-25 15:28:29 +0000765 return old1
766 if old2 is not attr:
767 return old2
Fred Drake55c38192000-06-29 19:39:57 +0000768
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000769 setAttributeNodeNS = setAttributeNode
770
Fred Drake1f549022000-09-24 05:21:58 +0000771 def removeAttribute(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000772 try:
773 attr = self._attrs[name]
774 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000775 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000776 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000777
Fred Drake1f549022000-09-24 05:21:58 +0000778 def removeAttributeNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000779 try:
780 attr = self._attrsNS[(namespaceURI, localName)]
781 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000782 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000783 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000784
Fred Drake1f549022000-09-24 05:21:58 +0000785 def removeAttributeNode(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000786 if node is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000787 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000788 try:
789 self._attrs[node.name]
790 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000791 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000792 _clear_id_cache(self)
Paul Prescod73678da2000-07-01 04:58:47 +0000793 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000794 # Restore this since the node is still useful and otherwise
795 # unlinked
796 node.ownerDocument = self.ownerDocument
Fred Drake16f63292000-10-23 18:09:50 +0000797
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000798 removeAttributeNodeNS = removeAttributeNode
799
Martin v. Löwis156c3372000-12-28 18:40:56 +0000800 def hasAttribute(self, name):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000801 return name in self._attrs
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000802
Martin v. Löwis156c3372000-12-28 18:40:56 +0000803 def hasAttributeNS(self, namespaceURI, localName):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000804 return (namespaceURI, localName) in self._attrsNS
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000805
Fred Drake1f549022000-09-24 05:21:58 +0000806 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000807 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000808
Fred Drake1f549022000-09-24 05:21:58 +0000809 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000810 return _get_elements_by_tagName_ns_helper(
811 self, namespaceURI, localName, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000812
Fred Drake1f549022000-09-24 05:21:58 +0000813 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000814 return "<DOM Element: %s at %#x>" % (self.tagName, id(self))
Fred Drake55c38192000-06-29 19:39:57 +0000815
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000816 def writexml(self, writer, indent="", addindent="", newl=""):
817 # indent = current indentation
818 # addindent = indentation to add to higher levels
819 # newl = newline string
820 writer.write(indent+"<" + self.tagName)
Fred Drake16f63292000-10-23 18:09:50 +0000821
Fred Drake4ccf4a12000-11-21 22:02:22 +0000822 attrs = self._get_attributes()
Brett Cannon861fd6f2007-02-21 22:05:37 +0000823 a_names = sorted(attrs.keys())
Fred Drake55c38192000-06-29 19:39:57 +0000824
825 for a_name in a_names:
Fred Drake1f549022000-09-24 05:21:58 +0000826 writer.write(" %s=\"" % a_name)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000827 _write_data(writer, attrs[a_name].value)
Fred Drake55c38192000-06-29 19:39:57 +0000828 writer.write("\"")
829 if self.childNodes:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000830 writer.write(">%s"%(newl))
Fred Drake55c38192000-06-29 19:39:57 +0000831 for node in self.childNodes:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000832 node.writexml(writer,indent+addindent,addindent,newl)
833 writer.write("%s</%s>%s" % (indent,self.tagName,newl))
Fred Drake55c38192000-06-29 19:39:57 +0000834 else:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000835 writer.write("/>%s"%(newl))
Fred Drake55c38192000-06-29 19:39:57 +0000836
Fred Drake1f549022000-09-24 05:21:58 +0000837 def _get_attributes(self):
Fred Drake2998a552001-12-06 18:27:48 +0000838 return NamedNodeMap(self._attrs, self._attrsNS, self)
Fred Drake55c38192000-06-29 19:39:57 +0000839
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000840 def hasAttributes(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000841 if self._attrs:
842 return True
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000843 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000844 return False
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000845
Martin v. Löwis787354c2003-01-25 15:28:29 +0000846 # DOM Level 3 attributes, based on the 22 Oct 2002 draft
847
848 def setIdAttribute(self, name):
849 idAttr = self.getAttributeNode(name)
850 self.setIdAttributeNode(idAttr)
851
852 def setIdAttributeNS(self, namespaceURI, localName):
853 idAttr = self.getAttributeNodeNS(namespaceURI, localName)
854 self.setIdAttributeNode(idAttr)
855
856 def setIdAttributeNode(self, idAttr):
857 if idAttr is None or not self.isSameNode(idAttr.ownerElement):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000858 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000859 if _get_containing_entref(self) is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000860 raise xml.dom.NoModificationAllowedErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000861 if not idAttr._is_id:
862 idAttr.__dict__['_is_id'] = True
863 self._magic_id_nodes += 1
864 self.ownerDocument._magic_id_count += 1
865 _clear_id_cache(self)
866
867defproperty(Element, "attributes",
868 doc="NamedNodeMap of attributes on the element.")
869defproperty(Element, "localName",
870 doc="Namespace-local name of this element.")
871
872
873def _set_attribute_node(element, attr):
874 _clear_id_cache(element)
875 element._attrs[attr.name] = attr
876 element._attrsNS[(attr.namespaceURI, attr.localName)] = attr
877
878 # This creates a circular reference, but Element.unlink()
879 # breaks the cycle since the references to the attribute
880 # dictionaries are tossed.
881 attr.__dict__['ownerElement'] = element
882
883
884class Childless:
885 """Mixin that makes childless-ness easy to implement and avoids
886 the complexity of the Node methods that deal with children.
887 """
888
Fred Drake4ccf4a12000-11-21 22:02:22 +0000889 attributes = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000890 childNodes = EmptyNodeList()
891 firstChild = None
892 lastChild = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000893
Martin v. Löwis787354c2003-01-25 15:28:29 +0000894 def _get_firstChild(self):
895 return None
Fred Drake55c38192000-06-29 19:39:57 +0000896
Martin v. Löwis787354c2003-01-25 15:28:29 +0000897 def _get_lastChild(self):
898 return None
Fred Drake1f549022000-09-24 05:21:58 +0000899
Martin v. Löwis787354c2003-01-25 15:28:29 +0000900 def appendChild(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000901 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000902 self.nodeName + " nodes cannot have children")
903
904 def hasChildNodes(self):
905 return False
906
907 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000908 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000909 self.nodeName + " nodes do not have children")
910
911 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000912 raise xml.dom.NotFoundErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000913 self.nodeName + " nodes do not have children")
914
915 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000916 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000917 self.nodeName + " nodes do not have children")
918
919
920class ProcessingInstruction(Childless, Node):
Fred Drake1f549022000-09-24 05:21:58 +0000921 nodeType = Node.PROCESSING_INSTRUCTION_NODE
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000922
Fred Drake1f549022000-09-24 05:21:58 +0000923 def __init__(self, target, data):
Fred Drake55c38192000-06-29 19:39:57 +0000924 self.target = self.nodeName = target
925 self.data = self.nodeValue = data
Fred Drake55c38192000-06-29 19:39:57 +0000926
Martin v. Löwis787354c2003-01-25 15:28:29 +0000927 def _get_data(self):
928 return self.data
929 def _set_data(self, value):
930 d = self.__dict__
931 d['data'] = d['nodeValue'] = value
932
933 def _get_target(self):
934 return self.target
935 def _set_target(self, value):
936 d = self.__dict__
937 d['target'] = d['nodeName'] = value
938
939 def __setattr__(self, name, value):
940 if name == "data" or name == "nodeValue":
941 self.__dict__['data'] = self.__dict__['nodeValue'] = value
942 elif name == "target" or name == "nodeName":
943 self.__dict__['target'] = self.__dict__['nodeName'] = value
944 else:
945 self.__dict__[name] = value
946
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000947 def writexml(self, writer, indent="", addindent="", newl=""):
948 writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))
Fred Drake55c38192000-06-29 19:39:57 +0000949
Martin v. Löwis787354c2003-01-25 15:28:29 +0000950
951class CharacterData(Childless, Node):
952 def _get_length(self):
953 return len(self.data)
954 __len__ = _get_length
955
956 def _get_data(self):
957 return self.__dict__['data']
958 def _set_data(self, data):
959 d = self.__dict__
960 d['data'] = d['nodeValue'] = data
961
962 _get_nodeValue = _get_data
963 _set_nodeValue = _set_data
964
965 def __setattr__(self, name, value):
966 if name == "data" or name == "nodeValue":
967 self.__dict__['data'] = self.__dict__['nodeValue'] = value
968 else:
969 self.__dict__[name] = value
Fred Drake87432f42001-04-04 14:09:46 +0000970
Fred Drake55c38192000-06-29 19:39:57 +0000971 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000972 data = self.data
973 if len(data) > 10:
Fred Drake1f549022000-09-24 05:21:58 +0000974 dotdotdot = "..."
Fred Drake55c38192000-06-29 19:39:57 +0000975 else:
Fred Drake1f549022000-09-24 05:21:58 +0000976 dotdotdot = ""
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000977 return '<DOM %s node "%r%s">' % (
Martin v. Löwis787354c2003-01-25 15:28:29 +0000978 self.__class__.__name__, data[0:10], dotdotdot)
Fred Drake87432f42001-04-04 14:09:46 +0000979
980 def substringData(self, offset, count):
981 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000982 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +0000983 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000984 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +0000985 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000986 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +0000987 return self.data[offset:offset+count]
988
989 def appendData(self, arg):
990 self.data = self.data + arg
Fred Drake87432f42001-04-04 14:09:46 +0000991
992 def insertData(self, offset, arg):
993 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000994 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +0000995 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000996 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +0000997 if arg:
998 self.data = "%s%s%s" % (
999 self.data[:offset], arg, self.data[offset:])
Fred Drake87432f42001-04-04 14:09:46 +00001000
1001 def deleteData(self, offset, count):
1002 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001003 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001004 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001005 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001006 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001007 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001008 if count:
1009 self.data = self.data[:offset] + self.data[offset+count:]
Fred Drake87432f42001-04-04 14:09:46 +00001010
1011 def replaceData(self, offset, count, arg):
1012 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001013 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001014 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001015 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001016 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001017 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001018 if count:
1019 self.data = "%s%s%s" % (
1020 self.data[:offset], arg, self.data[offset+count:])
Martin v. Löwis787354c2003-01-25 15:28:29 +00001021
1022defproperty(CharacterData, "length", doc="Length of the string data.")
1023
Fred Drake87432f42001-04-04 14:09:46 +00001024
1025class Text(CharacterData):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001026 # Make sure we don't add an instance __dict__ if we don't already
1027 # have one, at least when that's possible:
Martin v. Löwis995359c2003-01-26 08:59:32 +00001028 # XXX this does not work, CharacterData is an old-style class
1029 # __slots__ = ()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001030
Fred Drake87432f42001-04-04 14:09:46 +00001031 nodeType = Node.TEXT_NODE
1032 nodeName = "#text"
1033 attributes = None
Fred Drake55c38192000-06-29 19:39:57 +00001034
Fred Drakef7cf40d2000-12-14 18:16:11 +00001035 def splitText(self, offset):
1036 if offset < 0 or offset > len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001037 raise xml.dom.IndexSizeErr("illegal offset value")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001038 newText = self.__class__()
1039 newText.data = self.data[offset:]
1040 newText.ownerDocument = self.ownerDocument
Fred Drakef7cf40d2000-12-14 18:16:11 +00001041 next = self.nextSibling
1042 if self.parentNode and self in self.parentNode.childNodes:
1043 if next is None:
1044 self.parentNode.appendChild(newText)
1045 else:
1046 self.parentNode.insertBefore(newText, next)
1047 self.data = self.data[:offset]
1048 return newText
1049
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001050 def writexml(self, writer, indent="", addindent="", newl=""):
1051 _write_data(writer, "%s%s%s"%(indent, self.data, newl))
Fred Drake55c38192000-06-29 19:39:57 +00001052
Martin v. Löwis787354c2003-01-25 15:28:29 +00001053 # DOM Level 3 (WD 9 April 2002)
1054
1055 def _get_wholeText(self):
1056 L = [self.data]
1057 n = self.previousSibling
1058 while n is not None:
1059 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1060 L.insert(0, n.data)
1061 n = n.previousSibling
1062 else:
1063 break
1064 n = self.nextSibling
1065 while n is not None:
1066 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1067 L.append(n.data)
1068 n = n.nextSibling
1069 else:
1070 break
1071 return ''.join(L)
1072
1073 def replaceWholeText(self, content):
1074 # XXX This needs to be seriously changed if minidom ever
1075 # supports EntityReference nodes.
1076 parent = self.parentNode
1077 n = self.previousSibling
1078 while n is not None:
1079 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1080 next = n.previousSibling
1081 parent.removeChild(n)
1082 n = next
1083 else:
1084 break
1085 n = self.nextSibling
1086 if not content:
1087 parent.removeChild(self)
1088 while n is not None:
1089 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1090 next = n.nextSibling
1091 parent.removeChild(n)
1092 n = next
1093 else:
1094 break
1095 if content:
1096 d = self.__dict__
1097 d['data'] = content
1098 d['nodeValue'] = content
1099 return self
1100 else:
1101 return None
1102
1103 def _get_isWhitespaceInElementContent(self):
1104 if self.data.strip():
1105 return False
1106 elem = _get_containing_element(self)
1107 if elem is None:
1108 return False
1109 info = self.ownerDocument._get_elem_info(elem)
1110 if info is None:
1111 return False
1112 else:
1113 return info.isElementContent()
1114
1115defproperty(Text, "isWhitespaceInElementContent",
1116 doc="True iff this text node contains only whitespace"
1117 " and is in element content.")
1118defproperty(Text, "wholeText",
1119 doc="The text of all logically-adjacent text nodes.")
1120
1121
1122def _get_containing_element(node):
1123 c = node.parentNode
1124 while c is not None:
1125 if c.nodeType == Node.ELEMENT_NODE:
1126 return c
1127 c = c.parentNode
1128 return None
1129
1130def _get_containing_entref(node):
1131 c = node.parentNode
1132 while c is not None:
1133 if c.nodeType == Node.ENTITY_REFERENCE_NODE:
1134 return c
1135 c = c.parentNode
1136 return None
1137
1138
Alex Martelli0ee43512006-08-21 19:53:20 +00001139class Comment(CharacterData):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001140 nodeType = Node.COMMENT_NODE
1141 nodeName = "#comment"
1142
1143 def __init__(self, data):
1144 self.data = self.nodeValue = data
1145
1146 def writexml(self, writer, indent="", addindent="", newl=""):
Benjamin Peterson2b7411d2008-05-26 17:36:47 +00001147 if "--" in self.data:
1148 raise ValueError("'--' is not allowed in a comment node")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001149 writer.write("%s<!--%s-->%s" % (indent, self.data, newl))
1150
Fred Drake87432f42001-04-04 14:09:46 +00001151
1152class CDATASection(Text):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001153 # Make sure we don't add an instance __dict__ if we don't already
1154 # have one, at least when that's possible:
Martin v. Löwis995359c2003-01-26 08:59:32 +00001155 # XXX this does not work, Text is an old-style class
1156 # __slots__ = ()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001157
Fred Drake87432f42001-04-04 14:09:46 +00001158 nodeType = Node.CDATA_SECTION_NODE
1159 nodeName = "#cdata-section"
1160
1161 def writexml(self, writer, indent="", addindent="", newl=""):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001162 if self.data.find("]]>") >= 0:
1163 raise ValueError("']]>' not allowed in a CDATA section")
Guido van Rossum5b5e0b92001-09-19 13:28:25 +00001164 writer.write("<![CDATA[%s]]>" % self.data)
Fred Drake87432f42001-04-04 14:09:46 +00001165
1166
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001167class ReadOnlySequentialNamedNodeMap(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001168 __slots__ = '_seq',
1169
1170 def __init__(self, seq=()):
1171 # seq should be a list or tuple
1172 self._seq = seq
1173
1174 def __len__(self):
1175 return len(self._seq)
1176
1177 def _get_length(self):
1178 return len(self._seq)
1179
1180 def getNamedItem(self, name):
1181 for n in self._seq:
1182 if n.nodeName == name:
1183 return n
1184
1185 def getNamedItemNS(self, namespaceURI, localName):
1186 for n in self._seq:
1187 if n.namespaceURI == namespaceURI and n.localName == localName:
1188 return n
1189
1190 def __getitem__(self, name_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001191 if isinstance(name_or_tuple, tuple):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001192 node = self.getNamedItemNS(*name_or_tuple)
1193 else:
1194 node = self.getNamedItem(name_or_tuple)
1195 if node is None:
Collin Winter70e79802007-08-24 18:57:22 +00001196 raise KeyError(name_or_tuple)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001197 return node
1198
1199 def item(self, index):
1200 if index < 0:
1201 return None
1202 try:
1203 return self._seq[index]
1204 except IndexError:
1205 return None
1206
1207 def removeNamedItem(self, name):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001208 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001209 "NamedNodeMap instance is read-only")
1210
1211 def removeNamedItemNS(self, namespaceURI, localName):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001212 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001213 "NamedNodeMap instance is read-only")
1214
1215 def setNamedItem(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001216 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001217 "NamedNodeMap instance is read-only")
1218
1219 def setNamedItemNS(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001220 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001221 "NamedNodeMap instance is read-only")
1222
1223 def __getstate__(self):
1224 return [self._seq]
1225
1226 def __setstate__(self, state):
1227 self._seq = state[0]
1228
1229defproperty(ReadOnlySequentialNamedNodeMap, "length",
1230 doc="Number of entries in the NamedNodeMap.")
Paul Prescod73678da2000-07-01 04:58:47 +00001231
Fred Drakef7cf40d2000-12-14 18:16:11 +00001232
Martin v. Löwis787354c2003-01-25 15:28:29 +00001233class Identified:
1234 """Mix-in class that supports the publicId and systemId attributes."""
1235
Martin v. Löwis995359c2003-01-26 08:59:32 +00001236 # XXX this does not work, this is an old-style class
1237 # __slots__ = 'publicId', 'systemId'
Martin v. Löwis787354c2003-01-25 15:28:29 +00001238
1239 def _identified_mixin_init(self, publicId, systemId):
1240 self.publicId = publicId
1241 self.systemId = systemId
1242
1243 def _get_publicId(self):
1244 return self.publicId
1245
1246 def _get_systemId(self):
1247 return self.systemId
1248
1249class DocumentType(Identified, Childless, Node):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001250 nodeType = Node.DOCUMENT_TYPE_NODE
1251 nodeValue = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001252 name = None
1253 publicId = None
1254 systemId = None
Fred Drakedc806702001-04-05 14:41:30 +00001255 internalSubset = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001256
1257 def __init__(self, qualifiedName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001258 self.entities = ReadOnlySequentialNamedNodeMap()
1259 self.notations = ReadOnlySequentialNamedNodeMap()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001260 if qualifiedName:
1261 prefix, localname = _nssplit(qualifiedName)
1262 self.name = localname
Martin v. Löwis787354c2003-01-25 15:28:29 +00001263 self.nodeName = self.name
1264
1265 def _get_internalSubset(self):
1266 return self.internalSubset
1267
1268 def cloneNode(self, deep):
1269 if self.ownerDocument is None:
1270 # it's ok
1271 clone = DocumentType(None)
1272 clone.name = self.name
1273 clone.nodeName = self.name
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001274 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001275 if deep:
1276 clone.entities._seq = []
1277 clone.notations._seq = []
1278 for n in self.notations._seq:
1279 notation = Notation(n.nodeName, n.publicId, n.systemId)
1280 clone.notations._seq.append(notation)
1281 n._call_user_data_handler(operation, n, notation)
1282 for e in self.entities._seq:
1283 entity = Entity(e.nodeName, e.publicId, e.systemId,
1284 e.notationName)
1285 entity.actualEncoding = e.actualEncoding
1286 entity.encoding = e.encoding
1287 entity.version = e.version
1288 clone.entities._seq.append(entity)
1289 e._call_user_data_handler(operation, n, entity)
1290 self._call_user_data_handler(operation, self, clone)
1291 return clone
1292 else:
1293 return None
1294
1295 def writexml(self, writer, indent="", addindent="", newl=""):
1296 writer.write("<!DOCTYPE ")
1297 writer.write(self.name)
1298 if self.publicId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001299 writer.write("%s PUBLIC '%s'%s '%s'"
1300 % (newl, self.publicId, newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001301 elif self.systemId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001302 writer.write("%s SYSTEM '%s'" % (newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001303 if self.internalSubset is not None:
1304 writer.write(" [")
1305 writer.write(self.internalSubset)
1306 writer.write("]")
Georg Brandl175a7dc2005-08-25 22:02:43 +00001307 writer.write(">"+newl)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001308
1309class Entity(Identified, Node):
1310 attributes = None
1311 nodeType = Node.ENTITY_NODE
1312 nodeValue = None
1313
1314 actualEncoding = None
1315 encoding = None
1316 version = None
1317
1318 def __init__(self, name, publicId, systemId, notation):
1319 self.nodeName = name
1320 self.notationName = notation
1321 self.childNodes = NodeList()
1322 self._identified_mixin_init(publicId, systemId)
1323
1324 def _get_actualEncoding(self):
1325 return self.actualEncoding
1326
1327 def _get_encoding(self):
1328 return self.encoding
1329
1330 def _get_version(self):
1331 return self.version
1332
1333 def appendChild(self, newChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001334 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001335 "cannot append children to an entity node")
1336
1337 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001338 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001339 "cannot insert children below an entity node")
1340
1341 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001342 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001343 "cannot remove children from an entity node")
1344
1345 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001346 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001347 "cannot replace children of an entity node")
1348
1349class Notation(Identified, Childless, Node):
1350 nodeType = Node.NOTATION_NODE
1351 nodeValue = None
1352
1353 def __init__(self, name, publicId, systemId):
1354 self.nodeName = name
1355 self._identified_mixin_init(publicId, systemId)
Fred Drakef7cf40d2000-12-14 18:16:11 +00001356
1357
Martin v. Löwis787354c2003-01-25 15:28:29 +00001358class DOMImplementation(DOMImplementationLS):
1359 _features = [("core", "1.0"),
1360 ("core", "2.0"),
1361 ("core", "3.0"),
1362 ("core", None),
1363 ("xml", "1.0"),
1364 ("xml", "2.0"),
1365 ("xml", "3.0"),
1366 ("xml", None),
1367 ("ls-load", "3.0"),
1368 ("ls-load", None),
1369 ]
1370
Fred Drakef7cf40d2000-12-14 18:16:11 +00001371 def hasFeature(self, feature, version):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001372 if version == "":
1373 version = None
1374 return (feature.lower(), version) in self._features
Fred Drakef7cf40d2000-12-14 18:16:11 +00001375
1376 def createDocument(self, namespaceURI, qualifiedName, doctype):
1377 if doctype and doctype.parentNode is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001378 raise xml.dom.WrongDocumentErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001379 "doctype object owned by another DOM tree")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001380 doc = self._create_document()
1381
1382 add_root_element = not (namespaceURI is None
1383 and qualifiedName is None
1384 and doctype is None)
1385
1386 if not qualifiedName and add_root_element:
Martin v. Löwisb417be22001-02-06 01:16:06 +00001387 # The spec is unclear what to raise here; SyntaxErr
1388 # would be the other obvious candidate. Since Xerces raises
1389 # InvalidCharacterErr, and since SyntaxErr is not listed
1390 # for createDocument, that seems to be the better choice.
1391 # XXX: need to check for illegal characters here and in
1392 # createElement.
Martin v. Löwis787354c2003-01-25 15:28:29 +00001393
1394 # DOM Level III clears this up when talking about the return value
1395 # of this function. If namespaceURI, qName and DocType are
1396 # Null the document is returned without a document element
1397 # Otherwise if doctype or namespaceURI are not None
1398 # Then we go back to the above problem
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001399 raise xml.dom.InvalidCharacterErr("Element with no name")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001400
1401 if add_root_element:
1402 prefix, localname = _nssplit(qualifiedName)
1403 if prefix == "xml" \
1404 and namespaceURI != "http://www.w3.org/XML/1998/namespace":
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001405 raise xml.dom.NamespaceErr("illegal use of 'xml' prefix")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001406 if prefix and not namespaceURI:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001407 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001408 "illegal use of prefix without namespaces")
1409 element = doc.createElementNS(namespaceURI, qualifiedName)
1410 if doctype:
1411 doc.appendChild(doctype)
1412 doc.appendChild(element)
1413
1414 if doctype:
1415 doctype.parentNode = doctype.ownerDocument = doc
1416
Fred Drakef7cf40d2000-12-14 18:16:11 +00001417 doc.doctype = doctype
1418 doc.implementation = self
1419 return doc
1420
1421 def createDocumentType(self, qualifiedName, publicId, systemId):
1422 doctype = DocumentType(qualifiedName)
1423 doctype.publicId = publicId
1424 doctype.systemId = systemId
1425 return doctype
1426
Martin v. Löwis787354c2003-01-25 15:28:29 +00001427 # DOM Level 3 (WD 9 April 2002)
1428
1429 def getInterface(self, feature):
1430 if self.hasFeature(feature, None):
1431 return self
1432 else:
1433 return None
1434
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001435 # internal
Martin v. Löwis787354c2003-01-25 15:28:29 +00001436 def _create_document(self):
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001437 return Document()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001438
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001439class ElementInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001440 """Object that represents content-model information for an element.
1441
1442 This implementation is not expected to be used in practice; DOM
1443 builders should provide implementations which do the right thing
1444 using information available to it.
1445
1446 """
1447
1448 __slots__ = 'tagName',
1449
1450 def __init__(self, name):
1451 self.tagName = name
1452
1453 def getAttributeType(self, aname):
1454 return _no_type
1455
1456 def getAttributeTypeNS(self, namespaceURI, localName):
1457 return _no_type
1458
1459 def isElementContent(self):
1460 return False
1461
1462 def isEmpty(self):
1463 """Returns true iff this element is declared to have an EMPTY
1464 content model."""
1465 return False
1466
1467 def isId(self, aname):
1468 """Returns true iff the named attribte is a DTD-style ID."""
1469 return False
1470
1471 def isIdNS(self, namespaceURI, localName):
1472 """Returns true iff the identified attribute is a DTD-style ID."""
1473 return False
1474
1475 def __getstate__(self):
1476 return self.tagName
1477
1478 def __setstate__(self, state):
1479 self.tagName = state
1480
1481def _clear_id_cache(node):
1482 if node.nodeType == Node.DOCUMENT_NODE:
1483 node._id_cache.clear()
1484 node._id_search_stack = None
1485 elif _in_document(node):
1486 node.ownerDocument._id_cache.clear()
1487 node.ownerDocument._id_search_stack= None
1488
1489class Document(Node, DocumentLS):
1490 _child_node_types = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
1491 Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)
1492
Fred Drake1f549022000-09-24 05:21:58 +00001493 nodeType = Node.DOCUMENT_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +00001494 nodeName = "#document"
1495 nodeValue = None
1496 attributes = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001497 doctype = None
1498 parentNode = None
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001499 previousSibling = nextSibling = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001500
1501 implementation = DOMImplementation()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001502
1503 # Document attributes from Level 3 (WD 9 April 2002)
1504
1505 actualEncoding = None
1506 encoding = None
1507 standalone = None
1508 version = None
1509 strictErrorChecking = False
1510 errorHandler = None
1511 documentURI = None
1512
1513 _magic_id_count = 0
1514
1515 def __init__(self):
1516 self.childNodes = NodeList()
1517 # mapping of (namespaceURI, localName) -> ElementInfo
1518 # and tagName -> ElementInfo
1519 self._elem_info = {}
1520 self._id_cache = {}
1521 self._id_search_stack = None
1522
1523 def _get_elem_info(self, element):
1524 if element.namespaceURI:
1525 key = element.namespaceURI, element.localName
1526 else:
1527 key = element.tagName
1528 return self._elem_info.get(key)
1529
1530 def _get_actualEncoding(self):
1531 return self.actualEncoding
1532
1533 def _get_doctype(self):
1534 return self.doctype
1535
1536 def _get_documentURI(self):
1537 return self.documentURI
1538
1539 def _get_encoding(self):
1540 return self.encoding
1541
1542 def _get_errorHandler(self):
1543 return self.errorHandler
1544
1545 def _get_standalone(self):
1546 return self.standalone
1547
1548 def _get_strictErrorChecking(self):
1549 return self.strictErrorChecking
1550
1551 def _get_version(self):
1552 return self.version
Fred Drake55c38192000-06-29 19:39:57 +00001553
Fred Drake1f549022000-09-24 05:21:58 +00001554 def appendChild(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001555 if node.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001556 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001557 "%s cannot be child of %s" % (repr(node), repr(self)))
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001558 if node.parentNode is not None:
Martin v. Löwis787354c2003-01-25 15:28:29 +00001559 # This needs to be done before the next test since this
1560 # may *be* the document element, in which case it should
1561 # end up re-ordered to the end.
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001562 node.parentNode.removeChild(node)
1563
Fred Drakef7cf40d2000-12-14 18:16:11 +00001564 if node.nodeType == Node.ELEMENT_NODE \
1565 and self._get_documentElement():
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001566 raise xml.dom.HierarchyRequestErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001567 "two document elements disallowed")
Fred Drake4ccf4a12000-11-21 22:02:22 +00001568 return Node.appendChild(self, node)
Paul Prescod73678da2000-07-01 04:58:47 +00001569
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001570 def removeChild(self, oldChild):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001571 try:
1572 self.childNodes.remove(oldChild)
1573 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001574 raise xml.dom.NotFoundErr()
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001575 oldChild.nextSibling = oldChild.previousSibling = None
1576 oldChild.parentNode = None
1577 if self.documentElement is oldChild:
1578 self.documentElement = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +00001579
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001580 return oldChild
1581
Fred Drakef7cf40d2000-12-14 18:16:11 +00001582 def _get_documentElement(self):
1583 for node in self.childNodes:
1584 if node.nodeType == Node.ELEMENT_NODE:
1585 return node
1586
1587 def unlink(self):
1588 if self.doctype is not None:
1589 self.doctype.unlink()
1590 self.doctype = None
1591 Node.unlink(self)
1592
Martin v. Löwis787354c2003-01-25 15:28:29 +00001593 def cloneNode(self, deep):
1594 if not deep:
1595 return None
1596 clone = self.implementation.createDocument(None, None, None)
1597 clone.encoding = self.encoding
1598 clone.standalone = self.standalone
1599 clone.version = self.version
1600 for n in self.childNodes:
1601 childclone = _clone_node(n, deep, clone)
1602 assert childclone.ownerDocument.isSameNode(clone)
1603 clone.childNodes.append(childclone)
1604 if childclone.nodeType == Node.DOCUMENT_NODE:
1605 assert clone.documentElement is None
1606 elif childclone.nodeType == Node.DOCUMENT_TYPE_NODE:
1607 assert clone.doctype is None
1608 clone.doctype = childclone
1609 childclone.parentNode = clone
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001610 self._call_user_data_handler(xml.dom.UserDataHandler.NODE_CLONED,
Martin v. Löwis787354c2003-01-25 15:28:29 +00001611 self, clone)
1612 return clone
1613
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001614 def createDocumentFragment(self):
1615 d = DocumentFragment()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001616 d.ownerDocument = self
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001617 return d
Fred Drake55c38192000-06-29 19:39:57 +00001618
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001619 def createElement(self, tagName):
1620 e = Element(tagName)
1621 e.ownerDocument = self
1622 return e
Fred Drake55c38192000-06-29 19:39:57 +00001623
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001624 def createTextNode(self, data):
Christian Heimesc9543e42007-11-28 08:28:28 +00001625 if not isinstance(data, str):
Collin Winter70e79802007-08-24 18:57:22 +00001626 raise TypeError("node contents must be a string")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001627 t = Text()
1628 t.data = data
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001629 t.ownerDocument = self
1630 return t
Fred Drake55c38192000-06-29 19:39:57 +00001631
Fred Drake87432f42001-04-04 14:09:46 +00001632 def createCDATASection(self, data):
Christian Heimesc9543e42007-11-28 08:28:28 +00001633 if not isinstance(data, str):
Collin Winter70e79802007-08-24 18:57:22 +00001634 raise TypeError("node contents must be a string")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001635 c = CDATASection()
1636 c.data = data
Fred Drake87432f42001-04-04 14:09:46 +00001637 c.ownerDocument = self
1638 return c
1639
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001640 def createComment(self, data):
1641 c = Comment(data)
1642 c.ownerDocument = self
1643 return c
Fred Drake55c38192000-06-29 19:39:57 +00001644
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001645 def createProcessingInstruction(self, target, data):
1646 p = ProcessingInstruction(target, data)
1647 p.ownerDocument = self
1648 return p
1649
1650 def createAttribute(self, qName):
1651 a = Attr(qName)
1652 a.ownerDocument = self
Martin v. Löwiscb67ea12001-03-31 16:30:40 +00001653 a.value = ""
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001654 return a
Fred Drake55c38192000-06-29 19:39:57 +00001655
1656 def createElementNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001657 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001658 e = Element(qualifiedName, namespaceURI, prefix)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001659 e.ownerDocument = self
1660 return e
Fred Drake55c38192000-06-29 19:39:57 +00001661
1662 def createAttributeNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001663 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001664 a = Attr(qualifiedName, namespaceURI, localName, prefix)
1665 a.ownerDocument = self
Martin v. Löwiscb67ea12001-03-31 16:30:40 +00001666 a.value = ""
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001667 return a
Fred Drake55c38192000-06-29 19:39:57 +00001668
Martin v. Löwis787354c2003-01-25 15:28:29 +00001669 # A couple of implementation-specific helpers to create node types
1670 # not supported by the W3C DOM specs:
1671
1672 def _create_entity(self, name, publicId, systemId, notationName):
1673 e = Entity(name, publicId, systemId, notationName)
1674 e.ownerDocument = self
1675 return e
1676
1677 def _create_notation(self, name, publicId, systemId):
1678 n = Notation(name, publicId, systemId)
1679 n.ownerDocument = self
1680 return n
1681
1682 def getElementById(self, id):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +00001683 if id in self._id_cache:
Martin v. Löwis787354c2003-01-25 15:28:29 +00001684 return self._id_cache[id]
1685 if not (self._elem_info or self._magic_id_count):
1686 return None
1687
1688 stack = self._id_search_stack
1689 if stack is None:
1690 # we never searched before, or the cache has been cleared
1691 stack = [self.documentElement]
1692 self._id_search_stack = stack
1693 elif not stack:
1694 # Previous search was completed and cache is still valid;
1695 # no matching node.
1696 return None
1697
1698 result = None
1699 while stack:
1700 node = stack.pop()
1701 # add child elements to stack for continued searching
1702 stack.extend([child for child in node.childNodes
1703 if child.nodeType in _nodeTypes_with_children])
1704 # check this node
1705 info = self._get_elem_info(node)
1706 if info:
1707 # We have to process all ID attributes before
1708 # returning in order to get all the attributes set to
1709 # be IDs using Element.setIdAttribute*().
1710 for attr in node.attributes.values():
1711 if attr.namespaceURI:
1712 if info.isIdNS(attr.namespaceURI, attr.localName):
1713 self._id_cache[attr.value] = node
1714 if attr.value == id:
1715 result = node
1716 elif not node._magic_id_nodes:
1717 break
1718 elif info.isId(attr.name):
1719 self._id_cache[attr.value] = node
1720 if attr.value == id:
1721 result = node
1722 elif not node._magic_id_nodes:
1723 break
1724 elif attr._is_id:
1725 self._id_cache[attr.value] = node
1726 if attr.value == id:
1727 result = node
1728 elif node._magic_id_nodes == 1:
1729 break
1730 elif node._magic_id_nodes:
1731 for attr in node.attributes.values():
1732 if attr._is_id:
1733 self._id_cache[attr.value] = node
1734 if attr.value == id:
1735 result = node
1736 if result is not None:
1737 break
1738 return result
1739
Fred Drake1f549022000-09-24 05:21:58 +00001740 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001741 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drakefbe7b4f2001-07-04 06:25:53 +00001742
1743 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001744 return _get_elements_by_tagName_ns_helper(
1745 self, namespaceURI, localName, NodeList())
1746
1747 def isSupported(self, feature, version):
1748 return self.implementation.hasFeature(feature, version)
1749
1750 def importNode(self, node, deep):
1751 if node.nodeType == Node.DOCUMENT_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001752 raise xml.dom.NotSupportedErr("cannot import document nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001753 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001754 raise xml.dom.NotSupportedErr("cannot import document type nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001755 return _clone_node(node, deep, self)
Fred Drake55c38192000-06-29 19:39:57 +00001756
Martin v. Löwis7d650ca2002-06-30 15:05:00 +00001757 def writexml(self, writer, indent="", addindent="", newl="",
1758 encoding = None):
1759 if encoding is None:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001760 writer.write('<?xml version="1.0" ?>'+newl)
Martin v. Löwis7d650ca2002-06-30 15:05:00 +00001761 else:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001762 writer.write('<?xml version="1.0" encoding="%s"?>%s' % (encoding, newl))
Fred Drake55c38192000-06-29 19:39:57 +00001763 for node in self.childNodes:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001764 node.writexml(writer, indent, addindent, newl)
Fred Drake55c38192000-06-29 19:39:57 +00001765
Martin v. Löwis787354c2003-01-25 15:28:29 +00001766 # DOM Level 3 (WD 9 April 2002)
1767
1768 def renameNode(self, n, namespaceURI, name):
1769 if n.ownerDocument is not self:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001770 raise xml.dom.WrongDocumentErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001771 "cannot rename nodes from other documents;\n"
1772 "expected %s,\nfound %s" % (self, n.ownerDocument))
1773 if n.nodeType not in (Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001774 raise xml.dom.NotSupportedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001775 "renameNode() only applies to element and attribute nodes")
1776 if namespaceURI != EMPTY_NAMESPACE:
1777 if ':' in name:
1778 prefix, localName = name.split(':', 1)
1779 if ( prefix == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001780 and namespaceURI != xml.dom.XMLNS_NAMESPACE):
1781 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001782 "illegal use of 'xmlns' prefix")
1783 else:
1784 if ( name == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001785 and namespaceURI != xml.dom.XMLNS_NAMESPACE
Martin v. Löwis787354c2003-01-25 15:28:29 +00001786 and n.nodeType == Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001787 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001788 "illegal use of the 'xmlns' attribute")
1789 prefix = None
1790 localName = name
1791 else:
1792 prefix = None
1793 localName = None
1794 if n.nodeType == Node.ATTRIBUTE_NODE:
1795 element = n.ownerElement
1796 if element is not None:
1797 is_id = n._is_id
1798 element.removeAttributeNode(n)
1799 else:
1800 element = None
1801 # avoid __setattr__
1802 d = n.__dict__
1803 d['prefix'] = prefix
1804 d['localName'] = localName
1805 d['namespaceURI'] = namespaceURI
1806 d['nodeName'] = name
1807 if n.nodeType == Node.ELEMENT_NODE:
1808 d['tagName'] = name
1809 else:
1810 # attribute node
1811 d['name'] = name
1812 if element is not None:
1813 element.setAttributeNode(n)
1814 if is_id:
1815 element.setIdAttributeNode(n)
1816 # It's not clear from a semantic perspective whether we should
1817 # call the user data handlers for the NODE_RENAMED event since
1818 # we're re-using the existing node. The draft spec has been
1819 # interpreted as meaning "no, don't call the handler unless a
1820 # new node is created."
1821 return n
1822
1823defproperty(Document, "documentElement",
1824 doc="Top-level element of this document.")
1825
1826
1827def _clone_node(node, deep, newOwnerDocument):
1828 """
1829 Clone a node and give it the new owner document.
1830 Called by Node.cloneNode and Document.importNode
1831 """
1832 if node.ownerDocument.isSameNode(newOwnerDocument):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001833 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001834 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001835 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001836 if node.nodeType == Node.ELEMENT_NODE:
1837 clone = newOwnerDocument.createElementNS(node.namespaceURI,
1838 node.nodeName)
1839 for attr in node.attributes.values():
1840 clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value)
1841 a = clone.getAttributeNodeNS(attr.namespaceURI, attr.localName)
1842 a.specified = attr.specified
1843
1844 if deep:
1845 for child in node.childNodes:
1846 c = _clone_node(child, deep, newOwnerDocument)
1847 clone.appendChild(c)
1848
1849 elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
1850 clone = newOwnerDocument.createDocumentFragment()
1851 if deep:
1852 for child in node.childNodes:
1853 c = _clone_node(child, deep, newOwnerDocument)
1854 clone.appendChild(c)
1855
1856 elif node.nodeType == Node.TEXT_NODE:
1857 clone = newOwnerDocument.createTextNode(node.data)
1858 elif node.nodeType == Node.CDATA_SECTION_NODE:
1859 clone = newOwnerDocument.createCDATASection(node.data)
1860 elif node.nodeType == Node.PROCESSING_INSTRUCTION_NODE:
1861 clone = newOwnerDocument.createProcessingInstruction(node.target,
1862 node.data)
1863 elif node.nodeType == Node.COMMENT_NODE:
1864 clone = newOwnerDocument.createComment(node.data)
1865 elif node.nodeType == Node.ATTRIBUTE_NODE:
1866 clone = newOwnerDocument.createAttributeNS(node.namespaceURI,
1867 node.nodeName)
1868 clone.specified = True
1869 clone.value = node.value
1870 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
1871 assert node.ownerDocument is not newOwnerDocument
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001872 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001873 clone = newOwnerDocument.implementation.createDocumentType(
1874 node.name, node.publicId, node.systemId)
1875 clone.ownerDocument = newOwnerDocument
1876 if deep:
1877 clone.entities._seq = []
1878 clone.notations._seq = []
1879 for n in node.notations._seq:
1880 notation = Notation(n.nodeName, n.publicId, n.systemId)
1881 notation.ownerDocument = newOwnerDocument
1882 clone.notations._seq.append(notation)
1883 if hasattr(n, '_call_user_data_handler'):
1884 n._call_user_data_handler(operation, n, notation)
1885 for e in node.entities._seq:
1886 entity = Entity(e.nodeName, e.publicId, e.systemId,
1887 e.notationName)
1888 entity.actualEncoding = e.actualEncoding
1889 entity.encoding = e.encoding
1890 entity.version = e.version
1891 entity.ownerDocument = newOwnerDocument
1892 clone.entities._seq.append(entity)
1893 if hasattr(e, '_call_user_data_handler'):
1894 e._call_user_data_handler(operation, n, entity)
1895 else:
1896 # Note the cloning of Document and DocumentType nodes is
1897 # implemenetation specific. minidom handles those cases
1898 # directly in the cloneNode() methods.
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001899 raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001900
1901 # Check for _call_user_data_handler() since this could conceivably
1902 # used with other DOM implementations (one of the FourThought
1903 # DOMs, perhaps?).
1904 if hasattr(node, '_call_user_data_handler'):
1905 node._call_user_data_handler(operation, node, clone)
1906 return clone
1907
1908
1909def _nssplit(qualifiedName):
1910 fields = qualifiedName.split(':', 1)
1911 if len(fields) == 2:
1912 return fields
1913 else:
1914 return (None, fields[0])
1915
1916
Martin v. Löwis787354c2003-01-25 15:28:29 +00001917def _do_pulldom_parse(func, args, kwargs):
Raymond Hettingerff41c482003-04-06 09:01:11 +00001918 events = func(*args, **kwargs)
Fred Drake1f549022000-09-24 05:21:58 +00001919 toktype, rootNode = events.getEvent()
1920 events.expandNode(rootNode)
Martin v. Löwisb417be22001-02-06 01:16:06 +00001921 events.clear()
Fred Drake55c38192000-06-29 19:39:57 +00001922 return rootNode
1923
Martin v. Löwis787354c2003-01-25 15:28:29 +00001924def parse(file, parser=None, bufsize=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001925 """Parse a file into a DOM by filename or file object."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001926 if parser is None and not bufsize:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001927 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001928 return expatbuilder.parse(file)
1929 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001930 from xml.dom import pulldom
Raymond Hettingerff41c482003-04-06 09:01:11 +00001931 return _do_pulldom_parse(pulldom.parse, (file,),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001932 {'parser': parser, 'bufsize': bufsize})
Fred Drake55c38192000-06-29 19:39:57 +00001933
Martin v. Löwis787354c2003-01-25 15:28:29 +00001934def parseString(string, parser=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001935 """Parse a file into a DOM from a string."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001936 if parser is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001937 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001938 return expatbuilder.parseString(string)
1939 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001940 from xml.dom import pulldom
Martin v. Löwis787354c2003-01-25 15:28:29 +00001941 return _do_pulldom_parse(pulldom.parseString, (string,),
1942 {'parser': parser})
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001943
Martin v. Löwis787354c2003-01-25 15:28:29 +00001944def getDOMImplementation(features=None):
1945 if features:
Christian Heimesc9543e42007-11-28 08:28:28 +00001946 if isinstance(features, str):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001947 features = domreg._parse_feature_string(features)
1948 for f, v in features:
1949 if not Document.implementation.hasFeature(f, v):
1950 return None
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001951 return Document.implementation