blob: 386494d288ee900ca4e020f39d20a95e7779575f [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
Kristján Valur Jónsson17173cf2010-06-09 08:13:42 +0000271 # A Node is its own context manager, to ensure that an unlink() call occurs.
272 # This is similar to how a file object works.
273 def __enter__(self):
274 return self
275
276 def __exit__(self, et, ev, tb):
277 self.unlink()
278
Martin v. Löwis787354c2003-01-25 15:28:29 +0000279defproperty(Node, "firstChild", doc="First child node, or None.")
280defproperty(Node, "lastChild", doc="Last child node, or None.")
281defproperty(Node, "localName", doc="Namespace-local name of this node.")
282
283
284def _append_child(self, node):
285 # fast path with less checks; usable by DOM builders if careful
286 childNodes = self.childNodes
287 if childNodes:
288 last = childNodes[-1]
289 node.__dict__["previousSibling"] = last
290 last.__dict__["nextSibling"] = node
291 childNodes.append(node)
292 node.__dict__["parentNode"] = self
293
294def _in_document(node):
295 # return True iff node is part of a document tree
296 while node is not None:
297 if node.nodeType == Node.DOCUMENT_NODE:
298 return True
299 node = node.parentNode
300 return False
Fred Drake55c38192000-06-29 19:39:57 +0000301
Fred Drake1f549022000-09-24 05:21:58 +0000302def _write_data(writer, data):
Fred Drake55c38192000-06-29 19:39:57 +0000303 "Writes datachars to writer."
Georg Brandlb9cd72a2010-10-15 17:58:45 +0000304 if data:
305 data = data.replace("&", "&amp;").replace("<", "&lt;"). \
306 replace("\"", "&quot;").replace(">", "&gt;")
307 writer.write(data)
Fred Drake55c38192000-06-29 19:39:57 +0000308
Martin v. Löwis787354c2003-01-25 15:28:29 +0000309def _get_elements_by_tagName_helper(parent, name, rc):
Fred Drake55c38192000-06-29 19:39:57 +0000310 for node in parent.childNodes:
Fred Drake1f549022000-09-24 05:21:58 +0000311 if node.nodeType == Node.ELEMENT_NODE and \
312 (name == "*" or node.tagName == name):
313 rc.append(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000314 _get_elements_by_tagName_helper(node, name, rc)
Fred Drake55c38192000-06-29 19:39:57 +0000315 return rc
316
Martin v. Löwis787354c2003-01-25 15:28:29 +0000317def _get_elements_by_tagName_ns_helper(parent, nsURI, localName, rc):
Fred Drake55c38192000-06-29 19:39:57 +0000318 for node in parent.childNodes:
Fred Drake1f549022000-09-24 05:21:58 +0000319 if node.nodeType == Node.ELEMENT_NODE:
Martin v. Löwised525fb2001-06-03 14:06:42 +0000320 if ((localName == "*" or node.localName == localName) and
Fred Drake1f549022000-09-24 05:21:58 +0000321 (nsURI == "*" or node.namespaceURI == nsURI)):
322 rc.append(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000323 _get_elements_by_tagName_ns_helper(node, nsURI, localName, rc)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000324 return rc
Fred Drake55c38192000-06-29 19:39:57 +0000325
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000326class DocumentFragment(Node):
327 nodeType = Node.DOCUMENT_FRAGMENT_NODE
328 nodeName = "#document-fragment"
329 nodeValue = None
330 attributes = None
331 parentNode = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000332 _child_node_types = (Node.ELEMENT_NODE,
333 Node.TEXT_NODE,
334 Node.CDATA_SECTION_NODE,
335 Node.ENTITY_REFERENCE_NODE,
336 Node.PROCESSING_INSTRUCTION_NODE,
337 Node.COMMENT_NODE,
338 Node.NOTATION_NODE)
339
340 def __init__(self):
341 self.childNodes = NodeList()
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000342
343
Fred Drake55c38192000-06-29 19:39:57 +0000344class Attr(Node):
Fred Drake1f549022000-09-24 05:21:58 +0000345 nodeType = Node.ATTRIBUTE_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +0000346 attributes = None
347 ownerElement = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000348 specified = False
349 _is_id = False
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000350
Martin v. Löwis787354c2003-01-25 15:28:29 +0000351 _child_node_types = (Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE)
352
353 def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None,
354 prefix=None):
Fred Drake55c38192000-06-29 19:39:57 +0000355 # skip setattr for performance
Fred Drake4ccf4a12000-11-21 22:02:22 +0000356 d = self.__dict__
Fred Drake4ccf4a12000-11-21 22:02:22 +0000357 d["nodeName"] = d["name"] = qName
358 d["namespaceURI"] = namespaceURI
359 d["prefix"] = prefix
Martin v. Löwis787354c2003-01-25 15:28:29 +0000360 d['childNodes'] = NodeList()
361
362 # Add the single child node that represents the value of the attr
363 self.childNodes.append(Text())
364
Paul Prescod73678da2000-07-01 04:58:47 +0000365 # nodeValue and value are set elsewhere
Fred Drake55c38192000-06-29 19:39:57 +0000366
Martin v. Löwis787354c2003-01-25 15:28:29 +0000367 def _get_localName(self):
Alex Martelli0ee43512006-08-21 19:53:20 +0000368 if 'localName' in self.__dict__:
Guido van Rossum3e1f85e2007-07-27 18:03:11 +0000369 return self.__dict__['localName']
Martin v. Löwis787354c2003-01-25 15:28:29 +0000370 return self.nodeName.split(":", 1)[-1]
371
372 def _get_name(self):
373 return self.name
374
375 def _get_specified(self):
376 return self.specified
377
Fred Drake1f549022000-09-24 05:21:58 +0000378 def __setattr__(self, name, value):
Fred Drakef7cf40d2000-12-14 18:16:11 +0000379 d = self.__dict__
Fred Drake1f549022000-09-24 05:21:58 +0000380 if name in ("value", "nodeValue"):
Fred Drakef7cf40d2000-12-14 18:16:11 +0000381 d["value"] = d["nodeValue"] = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000382 d2 = self.childNodes[0].__dict__
383 d2["data"] = d2["nodeValue"] = value
384 if self.ownerElement is not None:
385 _clear_id_cache(self.ownerElement)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000386 elif name in ("name", "nodeName"):
387 d["name"] = d["nodeName"] = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000388 if self.ownerElement is not None:
389 _clear_id_cache(self.ownerElement)
Fred Drake55c38192000-06-29 19:39:57 +0000390 else:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000391 d[name] = value
Fred Drake55c38192000-06-29 19:39:57 +0000392
Martin v. Löwis995359c2003-01-26 08:59:32 +0000393 def _set_prefix(self, prefix):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000394 nsuri = self.namespaceURI
Martin v. Löwis995359c2003-01-26 08:59:32 +0000395 if prefix == "xmlns":
396 if nsuri and nsuri != XMLNS_NAMESPACE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000397 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000398 "illegal use of 'xmlns' prefix for the wrong namespace")
399 d = self.__dict__
400 d['prefix'] = prefix
401 if prefix is None:
402 newName = self.localName
403 else:
Martin v. Löwis995359c2003-01-26 08:59:32 +0000404 newName = "%s:%s" % (prefix, self.localName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000405 if self.ownerElement:
406 _clear_id_cache(self.ownerElement)
407 d['nodeName'] = d['name'] = newName
408
409 def _set_value(self, value):
410 d = self.__dict__
411 d['value'] = d['nodeValue'] = value
412 if self.ownerElement:
413 _clear_id_cache(self.ownerElement)
414 self.childNodes[0].data = value
415
416 def unlink(self):
417 # This implementation does not call the base implementation
418 # since most of that is not needed, and the expense of the
419 # method call is not warranted. We duplicate the removal of
420 # children, but that's all we needed from the base class.
421 elem = self.ownerElement
422 if elem is not None:
423 del elem._attrs[self.nodeName]
424 del elem._attrsNS[(self.namespaceURI, self.localName)]
425 if self._is_id:
426 self._is_id = False
427 elem._magic_id_nodes -= 1
428 self.ownerDocument._magic_id_count -= 1
429 for child in self.childNodes:
430 child.unlink()
431 del self.childNodes[:]
432
433 def _get_isId(self):
434 if self._is_id:
435 return True
436 doc = self.ownerDocument
437 elem = self.ownerElement
438 if doc is None or elem is None:
439 return False
440
441 info = doc._get_elem_info(elem)
442 if info is None:
443 return False
444 if self.namespaceURI:
445 return info.isIdNS(self.namespaceURI, self.localName)
446 else:
447 return info.isId(self.nodeName)
448
449 def _get_schemaType(self):
450 doc = self.ownerDocument
451 elem = self.ownerElement
452 if doc is None or elem is None:
453 return _no_type
454
455 info = doc._get_elem_info(elem)
456 if info is None:
457 return _no_type
458 if self.namespaceURI:
459 return info.getAttributeTypeNS(self.namespaceURI, self.localName)
460 else:
461 return info.getAttributeType(self.nodeName)
462
463defproperty(Attr, "isId", doc="True if this attribute is an ID.")
464defproperty(Attr, "localName", doc="Namespace-local name of this attribute.")
465defproperty(Attr, "schemaType", doc="Schema type for this attribute.")
Fred Drake4ccf4a12000-11-21 22:02:22 +0000466
Fred Drakef7cf40d2000-12-14 18:16:11 +0000467
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000468class NamedNodeMap(object):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000469 """The attribute list is a transient interface to the underlying
470 dictionaries. Mutations here will change the underlying element's
Fred Drakef7cf40d2000-12-14 18:16:11 +0000471 dictionary.
472
473 Ordering is imposed artificially and does not reflect the order of
474 attributes as found in an input document.
475 """
Fred Drake4ccf4a12000-11-21 22:02:22 +0000476
Martin v. Löwis787354c2003-01-25 15:28:29 +0000477 __slots__ = ('_attrs', '_attrsNS', '_ownerElement')
478
Fred Drake2998a552001-12-06 18:27:48 +0000479 def __init__(self, attrs, attrsNS, ownerElement):
Fred Drake1f549022000-09-24 05:21:58 +0000480 self._attrs = attrs
481 self._attrsNS = attrsNS
Fred Drake2998a552001-12-06 18:27:48 +0000482 self._ownerElement = ownerElement
Fred Drakef7cf40d2000-12-14 18:16:11 +0000483
Martin v. Löwis787354c2003-01-25 15:28:29 +0000484 def _get_length(self):
485 return len(self._attrs)
Fred Drake55c38192000-06-29 19:39:57 +0000486
Fred Drake1f549022000-09-24 05:21:58 +0000487 def item(self, index):
Fred Drake55c38192000-06-29 19:39:57 +0000488 try:
Brett Cannon861fd6f2007-02-21 22:05:37 +0000489 return self[list(self._attrs.keys())[index]]
Fred Drake55c38192000-06-29 19:39:57 +0000490 except IndexError:
491 return None
Fred Drake55c38192000-06-29 19:39:57 +0000492
Fred Drake1f549022000-09-24 05:21:58 +0000493 def items(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000494 L = []
495 for node in self._attrs.values():
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000496 L.append((node.nodeName, node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000497 return L
Fred Drake1f549022000-09-24 05:21:58 +0000498
499 def itemsNS(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000500 L = []
501 for node in self._attrs.values():
Fred Drake49a5d032001-11-30 22:21:58 +0000502 L.append(((node.namespaceURI, node.localName), node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000503 return L
Fred Drake16f63292000-10-23 18:09:50 +0000504
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000505 def __contains__(self, key):
Christian Heimesc9543e42007-11-28 08:28:28 +0000506 if isinstance(key, str):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000507 return key in self._attrs
Martin v. Löwis787354c2003-01-25 15:28:29 +0000508 else:
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000509 return key in self._attrsNS
Martin v. Löwis787354c2003-01-25 15:28:29 +0000510
Fred Drake1f549022000-09-24 05:21:58 +0000511 def keys(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000512 return self._attrs.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000513
Fred Drake1f549022000-09-24 05:21:58 +0000514 def keysNS(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000515 return self._attrsNS.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000516
Fred Drake1f549022000-09-24 05:21:58 +0000517 def values(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000518 return self._attrs.values()
Fred Drake55c38192000-06-29 19:39:57 +0000519
Martin v. Löwis787354c2003-01-25 15:28:29 +0000520 def get(self, name, value=None):
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000521 return self._attrs.get(name, value)
522
Martin v. Löwis787354c2003-01-25 15:28:29 +0000523 __len__ = _get_length
Fred Drake55c38192000-06-29 19:39:57 +0000524
Mark Dickinsona56c4672009-01-27 18:17:45 +0000525 def _cmp(self, other):
Fred Drake1f549022000-09-24 05:21:58 +0000526 if self._attrs is getattr(other, "_attrs", None):
Fred Drake55c38192000-06-29 19:39:57 +0000527 return 0
Fred Drake16f63292000-10-23 18:09:50 +0000528 else:
Mark Dickinsona56c4672009-01-27 18:17:45 +0000529 return (id(self) > id(other)) - (id(self) < id(other))
530
531 def __eq__(self, other):
532 return self._cmp(other) == 0
533
534 def __ge__(self, other):
535 return self._cmp(other) >= 0
536
537 def __gt__(self, other):
538 return self._cmp(other) > 0
539
540 def __le__(self, other):
541 return self._cmp(other) <= 0
542
543 def __lt__(self, other):
544 return self._cmp(other) < 0
545
546 def __ne__(self, other):
547 return self._cmp(other) != 0
Fred Drake55c38192000-06-29 19:39:57 +0000548
Fred Drake1f549022000-09-24 05:21:58 +0000549 def __getitem__(self, attname_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000550 if isinstance(attname_or_tuple, tuple):
Paul Prescod73678da2000-07-01 04:58:47 +0000551 return self._attrsNS[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000552 else:
Paul Prescod73678da2000-07-01 04:58:47 +0000553 return self._attrs[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000554
Paul Prescod1e688272000-07-01 19:21:47 +0000555 # same as set
Fred Drake1f549022000-09-24 05:21:58 +0000556 def __setitem__(self, attname, value):
Christian Heimesc9543e42007-11-28 08:28:28 +0000557 if isinstance(value, str):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000558 try:
559 node = self._attrs[attname]
560 except KeyError:
561 node = Attr(attname)
562 node.ownerDocument = self._ownerElement.ownerDocument
Martin v. Löwis995359c2003-01-26 08:59:32 +0000563 self.setNamedItem(node)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000564 node.value = value
Paul Prescod1e688272000-07-01 19:21:47 +0000565 else:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000566 if not isinstance(value, Attr):
Collin Winter70e79802007-08-24 18:57:22 +0000567 raise TypeError("value must be a string or Attr object")
Fred Drake1f549022000-09-24 05:21:58 +0000568 node = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000569 self.setNamedItem(node)
570
571 def getNamedItem(self, name):
572 try:
573 return self._attrs[name]
574 except KeyError:
575 return None
576
577 def getNamedItemNS(self, namespaceURI, localName):
578 try:
579 return self._attrsNS[(namespaceURI, localName)]
580 except KeyError:
581 return None
582
583 def removeNamedItem(self, name):
584 n = self.getNamedItem(name)
585 if n is not None:
586 _clear_id_cache(self._ownerElement)
587 del self._attrs[n.nodeName]
588 del self._attrsNS[(n.namespaceURI, n.localName)]
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000589 if 'ownerElement' in n.__dict__:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000590 n.__dict__['ownerElement'] = None
591 return n
592 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000593 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000594
595 def removeNamedItemNS(self, namespaceURI, localName):
596 n = self.getNamedItemNS(namespaceURI, localName)
597 if n is not None:
598 _clear_id_cache(self._ownerElement)
599 del self._attrsNS[(n.namespaceURI, n.localName)]
600 del self._attrs[n.nodeName]
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000601 if 'ownerElement' in n.__dict__:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000602 n.__dict__['ownerElement'] = None
603 return n
604 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000605 raise xml.dom.NotFoundErr()
Fred Drakef7cf40d2000-12-14 18:16:11 +0000606
607 def setNamedItem(self, node):
Andrew M. Kuchlingbc8f72c2001-02-21 01:30:26 +0000608 if not isinstance(node, Attr):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000609 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000610 "%s cannot be child of %s" % (repr(node), repr(self)))
Fred Drakef7cf40d2000-12-14 18:16:11 +0000611 old = self._attrs.get(node.name)
Paul Prescod1e688272000-07-01 19:21:47 +0000612 if old:
613 old.unlink()
Fred Drake1f549022000-09-24 05:21:58 +0000614 self._attrs[node.name] = node
615 self._attrsNS[(node.namespaceURI, node.localName)] = node
Fred Drake2998a552001-12-06 18:27:48 +0000616 node.ownerElement = self._ownerElement
Martin v. Löwis787354c2003-01-25 15:28:29 +0000617 _clear_id_cache(node.ownerElement)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000618 return old
619
620 def setNamedItemNS(self, node):
621 return self.setNamedItem(node)
Paul Prescod73678da2000-07-01 04:58:47 +0000622
Fred Drake1f549022000-09-24 05:21:58 +0000623 def __delitem__(self, attname_or_tuple):
624 node = self[attname_or_tuple]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000625 _clear_id_cache(node.ownerElement)
Paul Prescod73678da2000-07-01 04:58:47 +0000626 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000627
628 def __getstate__(self):
629 return self._attrs, self._attrsNS, self._ownerElement
630
631 def __setstate__(self, state):
632 self._attrs, self._attrsNS, self._ownerElement = state
633
634defproperty(NamedNodeMap, "length",
635 doc="Number of nodes in the NamedNodeMap.")
Fred Drakef7cf40d2000-12-14 18:16:11 +0000636
637AttributeList = NamedNodeMap
638
Fred Drake1f549022000-09-24 05:21:58 +0000639
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000640class TypeInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000641 __slots__ = 'namespace', 'name'
642
643 def __init__(self, namespace, name):
644 self.namespace = namespace
645 self.name = name
646
647 def __repr__(self):
648 if self.namespace:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000649 return "<TypeInfo %r (from %r)>" % (self.name, self.namespace)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000650 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000651 return "<TypeInfo %r>" % self.name
Martin v. Löwis787354c2003-01-25 15:28:29 +0000652
653 def _get_name(self):
654 return self.name
655
656 def _get_namespace(self):
657 return self.namespace
658
659_no_type = TypeInfo(None, None)
660
Martin v. Löwisa2fda0d2000-10-07 12:10:28 +0000661class Element(Node):
Fred Drake1f549022000-09-24 05:21:58 +0000662 nodeType = Node.ELEMENT_NODE
Martin v. Löwis787354c2003-01-25 15:28:29 +0000663 nodeValue = None
664 schemaType = _no_type
665
666 _magic_id_nodes = 0
667
668 _child_node_types = (Node.ELEMENT_NODE,
669 Node.PROCESSING_INSTRUCTION_NODE,
670 Node.COMMENT_NODE,
671 Node.TEXT_NODE,
672 Node.CDATA_SECTION_NODE,
673 Node.ENTITY_REFERENCE_NODE)
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000674
Fred Drake49a5d032001-11-30 22:21:58 +0000675 def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None,
Fred Drake1f549022000-09-24 05:21:58 +0000676 localName=None):
Fred Drake55c38192000-06-29 19:39:57 +0000677 self.tagName = self.nodeName = tagName
Fred Drake1f549022000-09-24 05:21:58 +0000678 self.prefix = prefix
679 self.namespaceURI = namespaceURI
Martin v. Löwis787354c2003-01-25 15:28:29 +0000680 self.childNodes = NodeList()
Fred Drake55c38192000-06-29 19:39:57 +0000681
Fred Drake4ccf4a12000-11-21 22:02:22 +0000682 self._attrs = {} # attributes are double-indexed:
683 self._attrsNS = {} # tagName -> Attribute
684 # URI,localName -> Attribute
685 # in the future: consider lazy generation
686 # of attribute objects this is too tricky
687 # for now because of headaches with
688 # namespaces.
689
Martin v. Löwis787354c2003-01-25 15:28:29 +0000690 def _get_localName(self):
Alex Martelli0ee43512006-08-21 19:53:20 +0000691 if 'localName' in self.__dict__:
Guido van Rossum3e1f85e2007-07-27 18:03:11 +0000692 return self.__dict__['localName']
Martin v. Löwis787354c2003-01-25 15:28:29 +0000693 return self.tagName.split(":", 1)[-1]
694
695 def _get_tagName(self):
696 return self.tagName
Fred Drake4ccf4a12000-11-21 22:02:22 +0000697
698 def unlink(self):
Brett Cannon861fd6f2007-02-21 22:05:37 +0000699 for attr in list(self._attrs.values()):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000700 attr.unlink()
701 self._attrs = None
702 self._attrsNS = None
703 Node.unlink(self)
Fred Drake55c38192000-06-29 19:39:57 +0000704
Fred Drake1f549022000-09-24 05:21:58 +0000705 def getAttribute(self, attname):
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000706 try:
707 return self._attrs[attname].value
708 except KeyError:
709 return ""
Fred Drake55c38192000-06-29 19:39:57 +0000710
Fred Drake1f549022000-09-24 05:21:58 +0000711 def getAttributeNS(self, namespaceURI, localName):
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000712 try:
713 return self._attrsNS[(namespaceURI, localName)].value
714 except KeyError:
715 return ""
Fred Drake1f549022000-09-24 05:21:58 +0000716
717 def setAttribute(self, attname, value):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000718 attr = self.getAttributeNode(attname)
719 if attr is None:
720 attr = Attr(attname)
721 # for performance
722 d = attr.__dict__
723 d["value"] = d["nodeValue"] = value
724 d["ownerDocument"] = self.ownerDocument
725 self.setAttributeNode(attr)
726 elif value != attr.value:
727 d = attr.__dict__
728 d["value"] = d["nodeValue"] = value
729 if attr.isId:
730 _clear_id_cache(self)
Fred Drake55c38192000-06-29 19:39:57 +0000731
Fred Drake1f549022000-09-24 05:21:58 +0000732 def setAttributeNS(self, namespaceURI, qualifiedName, value):
733 prefix, localname = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000734 attr = self.getAttributeNodeNS(namespaceURI, localname)
735 if attr is None:
736 # for performance
737 attr = Attr(qualifiedName, namespaceURI, localname, prefix)
738 d = attr.__dict__
739 d["prefix"] = prefix
740 d["nodeName"] = qualifiedName
741 d["value"] = d["nodeValue"] = value
742 d["ownerDocument"] = self.ownerDocument
743 self.setAttributeNode(attr)
744 else:
745 d = attr.__dict__
746 if value != attr.value:
747 d["value"] = d["nodeValue"] = value
748 if attr.isId:
749 _clear_id_cache(self)
750 if attr.prefix != prefix:
751 d["prefix"] = prefix
752 d["nodeName"] = qualifiedName
Fred Drake55c38192000-06-29 19:39:57 +0000753
Fred Drake1f549022000-09-24 05:21:58 +0000754 def getAttributeNode(self, attrname):
755 return self._attrs.get(attrname)
Paul Prescod73678da2000-07-01 04:58:47 +0000756
Fred Drake1f549022000-09-24 05:21:58 +0000757 def getAttributeNodeNS(self, namespaceURI, localName):
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000758 return self._attrsNS.get((namespaceURI, localName))
Paul Prescod73678da2000-07-01 04:58:47 +0000759
Fred Drake1f549022000-09-24 05:21:58 +0000760 def setAttributeNode(self, attr):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000761 if attr.ownerElement not in (None, self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000762 raise xml.dom.InuseAttributeErr("attribute node already owned")
Martin v. Löwis787354c2003-01-25 15:28:29 +0000763 old1 = self._attrs.get(attr.name, None)
764 if old1 is not None:
765 self.removeAttributeNode(old1)
766 old2 = self._attrsNS.get((attr.namespaceURI, attr.localName), None)
767 if old2 is not None and old2 is not old1:
768 self.removeAttributeNode(old2)
769 _set_attribute_node(self, attr)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000770
Martin v. Löwis787354c2003-01-25 15:28:29 +0000771 if old1 is not attr:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000772 # It might have already been part of this node, in which case
773 # it doesn't represent a change, and should not be returned.
Martin v. Löwis787354c2003-01-25 15:28:29 +0000774 return old1
775 if old2 is not attr:
776 return old2
Fred Drake55c38192000-06-29 19:39:57 +0000777
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000778 setAttributeNodeNS = setAttributeNode
779
Fred Drake1f549022000-09-24 05:21:58 +0000780 def removeAttribute(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000781 try:
782 attr = self._attrs[name]
783 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000784 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000785 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000786
Fred Drake1f549022000-09-24 05:21:58 +0000787 def removeAttributeNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000788 try:
789 attr = self._attrsNS[(namespaceURI, localName)]
790 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000791 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000792 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000793
Fred Drake1f549022000-09-24 05:21:58 +0000794 def removeAttributeNode(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000795 if node is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000796 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000797 try:
798 self._attrs[node.name]
799 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000800 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000801 _clear_id_cache(self)
Paul Prescod73678da2000-07-01 04:58:47 +0000802 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000803 # Restore this since the node is still useful and otherwise
804 # unlinked
805 node.ownerDocument = self.ownerDocument
Fred Drake16f63292000-10-23 18:09:50 +0000806
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000807 removeAttributeNodeNS = removeAttributeNode
808
Martin v. Löwis156c3372000-12-28 18:40:56 +0000809 def hasAttribute(self, name):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000810 return name in self._attrs
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000811
Martin v. Löwis156c3372000-12-28 18:40:56 +0000812 def hasAttributeNS(self, namespaceURI, localName):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000813 return (namespaceURI, localName) in self._attrsNS
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000814
Fred Drake1f549022000-09-24 05:21:58 +0000815 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000816 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000817
Fred Drake1f549022000-09-24 05:21:58 +0000818 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000819 return _get_elements_by_tagName_ns_helper(
820 self, namespaceURI, localName, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000821
Fred Drake1f549022000-09-24 05:21:58 +0000822 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000823 return "<DOM Element: %s at %#x>" % (self.tagName, id(self))
Fred Drake55c38192000-06-29 19:39:57 +0000824
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000825 def writexml(self, writer, indent="", addindent="", newl=""):
826 # indent = current indentation
827 # addindent = indentation to add to higher levels
828 # newl = newline string
829 writer.write(indent+"<" + self.tagName)
Fred Drake16f63292000-10-23 18:09:50 +0000830
Fred Drake4ccf4a12000-11-21 22:02:22 +0000831 attrs = self._get_attributes()
Brett Cannon861fd6f2007-02-21 22:05:37 +0000832 a_names = sorted(attrs.keys())
Fred Drake55c38192000-06-29 19:39:57 +0000833
834 for a_name in a_names:
Fred Drake1f549022000-09-24 05:21:58 +0000835 writer.write(" %s=\"" % a_name)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000836 _write_data(writer, attrs[a_name].value)
Fred Drake55c38192000-06-29 19:39:57 +0000837 writer.write("\"")
838 if self.childNodes:
R David Murray791744b2011-10-01 16:19:51 -0400839 writer.write(">")
840 if self.childNodes[0].nodeType != Node.TEXT_NODE:
841 writer.write(newl)
Fred Drake55c38192000-06-29 19:39:57 +0000842 for node in self.childNodes:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000843 node.writexml(writer,indent+addindent,addindent,newl)
844 writer.write("%s</%s>%s" % (indent,self.tagName,newl))
Fred Drake55c38192000-06-29 19:39:57 +0000845 else:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000846 writer.write("/>%s"%(newl))
Fred Drake55c38192000-06-29 19:39:57 +0000847
Fred Drake1f549022000-09-24 05:21:58 +0000848 def _get_attributes(self):
Fred Drake2998a552001-12-06 18:27:48 +0000849 return NamedNodeMap(self._attrs, self._attrsNS, self)
Fred Drake55c38192000-06-29 19:39:57 +0000850
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000851 def hasAttributes(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000852 if self._attrs:
853 return True
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000854 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000855 return False
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000856
Martin v. Löwis787354c2003-01-25 15:28:29 +0000857 # DOM Level 3 attributes, based on the 22 Oct 2002 draft
858
859 def setIdAttribute(self, name):
860 idAttr = self.getAttributeNode(name)
861 self.setIdAttributeNode(idAttr)
862
863 def setIdAttributeNS(self, namespaceURI, localName):
864 idAttr = self.getAttributeNodeNS(namespaceURI, localName)
865 self.setIdAttributeNode(idAttr)
866
867 def setIdAttributeNode(self, idAttr):
868 if idAttr is None or not self.isSameNode(idAttr.ownerElement):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000869 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000870 if _get_containing_entref(self) is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000871 raise xml.dom.NoModificationAllowedErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000872 if not idAttr._is_id:
873 idAttr.__dict__['_is_id'] = True
874 self._magic_id_nodes += 1
875 self.ownerDocument._magic_id_count += 1
876 _clear_id_cache(self)
877
878defproperty(Element, "attributes",
879 doc="NamedNodeMap of attributes on the element.")
880defproperty(Element, "localName",
881 doc="Namespace-local name of this element.")
882
883
884def _set_attribute_node(element, attr):
885 _clear_id_cache(element)
886 element._attrs[attr.name] = attr
887 element._attrsNS[(attr.namespaceURI, attr.localName)] = attr
888
889 # This creates a circular reference, but Element.unlink()
890 # breaks the cycle since the references to the attribute
891 # dictionaries are tossed.
892 attr.__dict__['ownerElement'] = element
893
894
895class Childless:
896 """Mixin that makes childless-ness easy to implement and avoids
897 the complexity of the Node methods that deal with children.
898 """
899
Fred Drake4ccf4a12000-11-21 22:02:22 +0000900 attributes = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000901 childNodes = EmptyNodeList()
902 firstChild = None
903 lastChild = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000904
Martin v. Löwis787354c2003-01-25 15:28:29 +0000905 def _get_firstChild(self):
906 return None
Fred Drake55c38192000-06-29 19:39:57 +0000907
Martin v. Löwis787354c2003-01-25 15:28:29 +0000908 def _get_lastChild(self):
909 return None
Fred Drake1f549022000-09-24 05:21:58 +0000910
Martin v. Löwis787354c2003-01-25 15:28:29 +0000911 def appendChild(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000912 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000913 self.nodeName + " nodes cannot have children")
914
915 def hasChildNodes(self):
916 return False
917
918 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000919 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000920 self.nodeName + " nodes do not have children")
921
922 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000923 raise xml.dom.NotFoundErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000924 self.nodeName + " nodes do not have children")
925
Andrew M. Kuchling688b9e32010-07-25 23:38:47 +0000926 def normalize(self):
927 # For childless nodes, normalize() has nothing to do.
928 pass
929
Martin v. Löwis787354c2003-01-25 15:28:29 +0000930 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000931 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000932 self.nodeName + " nodes do not have children")
933
934
935class ProcessingInstruction(Childless, Node):
Fred Drake1f549022000-09-24 05:21:58 +0000936 nodeType = Node.PROCESSING_INSTRUCTION_NODE
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000937
Fred Drake1f549022000-09-24 05:21:58 +0000938 def __init__(self, target, data):
Fred Drake55c38192000-06-29 19:39:57 +0000939 self.target = self.nodeName = target
940 self.data = self.nodeValue = data
Fred Drake55c38192000-06-29 19:39:57 +0000941
Martin v. Löwis787354c2003-01-25 15:28:29 +0000942 def _get_data(self):
943 return self.data
944 def _set_data(self, value):
945 d = self.__dict__
946 d['data'] = d['nodeValue'] = value
947
948 def _get_target(self):
949 return self.target
950 def _set_target(self, value):
951 d = self.__dict__
952 d['target'] = d['nodeName'] = value
953
954 def __setattr__(self, name, value):
955 if name == "data" or name == "nodeValue":
956 self.__dict__['data'] = self.__dict__['nodeValue'] = value
957 elif name == "target" or name == "nodeName":
958 self.__dict__['target'] = self.__dict__['nodeName'] = value
959 else:
960 self.__dict__[name] = value
961
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000962 def writexml(self, writer, indent="", addindent="", newl=""):
963 writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))
Fred Drake55c38192000-06-29 19:39:57 +0000964
Martin v. Löwis787354c2003-01-25 15:28:29 +0000965
966class CharacterData(Childless, Node):
967 def _get_length(self):
968 return len(self.data)
969 __len__ = _get_length
970
971 def _get_data(self):
972 return self.__dict__['data']
973 def _set_data(self, data):
974 d = self.__dict__
975 d['data'] = d['nodeValue'] = data
976
977 _get_nodeValue = _get_data
978 _set_nodeValue = _set_data
979
980 def __setattr__(self, name, value):
981 if name == "data" or name == "nodeValue":
982 self.__dict__['data'] = self.__dict__['nodeValue'] = value
983 else:
984 self.__dict__[name] = value
Fred Drake87432f42001-04-04 14:09:46 +0000985
Fred Drake55c38192000-06-29 19:39:57 +0000986 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000987 data = self.data
988 if len(data) > 10:
Fred Drake1f549022000-09-24 05:21:58 +0000989 dotdotdot = "..."
Fred Drake55c38192000-06-29 19:39:57 +0000990 else:
Fred Drake1f549022000-09-24 05:21:58 +0000991 dotdotdot = ""
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000992 return '<DOM %s node "%r%s">' % (
Martin v. Löwis787354c2003-01-25 15:28:29 +0000993 self.__class__.__name__, data[0:10], dotdotdot)
Fred Drake87432f42001-04-04 14:09:46 +0000994
995 def substringData(self, offset, count):
996 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000997 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +0000998 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000999 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001000 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001001 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001002 return self.data[offset:offset+count]
1003
1004 def appendData(self, arg):
1005 self.data = self.data + arg
Fred Drake87432f42001-04-04 14:09:46 +00001006
1007 def insertData(self, offset, arg):
1008 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001009 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001010 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001011 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001012 if arg:
1013 self.data = "%s%s%s" % (
1014 self.data[:offset], arg, self.data[offset:])
Fred Drake87432f42001-04-04 14:09:46 +00001015
1016 def deleteData(self, offset, count):
1017 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001018 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001019 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001020 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001021 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001022 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001023 if count:
1024 self.data = self.data[:offset] + self.data[offset+count:]
Fred Drake87432f42001-04-04 14:09:46 +00001025
1026 def replaceData(self, offset, count, arg):
1027 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001028 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001029 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001030 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001031 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001032 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001033 if count:
1034 self.data = "%s%s%s" % (
1035 self.data[:offset], arg, self.data[offset+count:])
Martin v. Löwis787354c2003-01-25 15:28:29 +00001036
1037defproperty(CharacterData, "length", doc="Length of the string data.")
1038
Fred Drake87432f42001-04-04 14:09:46 +00001039
1040class Text(CharacterData):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001041 # Make sure we don't add an instance __dict__ if we don't already
1042 # have one, at least when that's possible:
Martin v. Löwis995359c2003-01-26 08:59:32 +00001043 # XXX this does not work, CharacterData is an old-style class
1044 # __slots__ = ()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001045
Fred Drake87432f42001-04-04 14:09:46 +00001046 nodeType = Node.TEXT_NODE
1047 nodeName = "#text"
1048 attributes = None
Fred Drake55c38192000-06-29 19:39:57 +00001049
Fred Drakef7cf40d2000-12-14 18:16:11 +00001050 def splitText(self, offset):
1051 if offset < 0 or offset > len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001052 raise xml.dom.IndexSizeErr("illegal offset value")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001053 newText = self.__class__()
1054 newText.data = self.data[offset:]
1055 newText.ownerDocument = self.ownerDocument
Fred Drakef7cf40d2000-12-14 18:16:11 +00001056 next = self.nextSibling
1057 if self.parentNode and self in self.parentNode.childNodes:
1058 if next is None:
1059 self.parentNode.appendChild(newText)
1060 else:
1061 self.parentNode.insertBefore(newText, next)
1062 self.data = self.data[:offset]
1063 return newText
1064
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001065 def writexml(self, writer, indent="", addindent="", newl=""):
R David Murray791744b2011-10-01 16:19:51 -04001066 _write_data(writer, self.data)
Fred Drake55c38192000-06-29 19:39:57 +00001067
Martin v. Löwis787354c2003-01-25 15:28:29 +00001068 # DOM Level 3 (WD 9 April 2002)
1069
1070 def _get_wholeText(self):
1071 L = [self.data]
1072 n = self.previousSibling
1073 while n is not None:
1074 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1075 L.insert(0, n.data)
1076 n = n.previousSibling
1077 else:
1078 break
1079 n = self.nextSibling
1080 while n is not None:
1081 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1082 L.append(n.data)
1083 n = n.nextSibling
1084 else:
1085 break
1086 return ''.join(L)
1087
1088 def replaceWholeText(self, content):
1089 # XXX This needs to be seriously changed if minidom ever
1090 # supports EntityReference nodes.
1091 parent = self.parentNode
1092 n = self.previousSibling
1093 while n is not None:
1094 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1095 next = n.previousSibling
1096 parent.removeChild(n)
1097 n = next
1098 else:
1099 break
1100 n = self.nextSibling
1101 if not content:
1102 parent.removeChild(self)
1103 while n is not None:
1104 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1105 next = n.nextSibling
1106 parent.removeChild(n)
1107 n = next
1108 else:
1109 break
1110 if content:
1111 d = self.__dict__
1112 d['data'] = content
1113 d['nodeValue'] = content
1114 return self
1115 else:
1116 return None
1117
1118 def _get_isWhitespaceInElementContent(self):
1119 if self.data.strip():
1120 return False
1121 elem = _get_containing_element(self)
1122 if elem is None:
1123 return False
1124 info = self.ownerDocument._get_elem_info(elem)
1125 if info is None:
1126 return False
1127 else:
1128 return info.isElementContent()
1129
1130defproperty(Text, "isWhitespaceInElementContent",
1131 doc="True iff this text node contains only whitespace"
1132 " and is in element content.")
1133defproperty(Text, "wholeText",
1134 doc="The text of all logically-adjacent text nodes.")
1135
1136
1137def _get_containing_element(node):
1138 c = node.parentNode
1139 while c is not None:
1140 if c.nodeType == Node.ELEMENT_NODE:
1141 return c
1142 c = c.parentNode
1143 return None
1144
1145def _get_containing_entref(node):
1146 c = node.parentNode
1147 while c is not None:
1148 if c.nodeType == Node.ENTITY_REFERENCE_NODE:
1149 return c
1150 c = c.parentNode
1151 return None
1152
1153
Alex Martelli0ee43512006-08-21 19:53:20 +00001154class Comment(CharacterData):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001155 nodeType = Node.COMMENT_NODE
1156 nodeName = "#comment"
1157
1158 def __init__(self, data):
1159 self.data = self.nodeValue = data
1160
1161 def writexml(self, writer, indent="", addindent="", newl=""):
Benjamin Peterson2b7411d2008-05-26 17:36:47 +00001162 if "--" in self.data:
1163 raise ValueError("'--' is not allowed in a comment node")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001164 writer.write("%s<!--%s-->%s" % (indent, self.data, newl))
1165
Fred Drake87432f42001-04-04 14:09:46 +00001166
1167class CDATASection(Text):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001168 # Make sure we don't add an instance __dict__ if we don't already
1169 # have one, at least when that's possible:
Martin v. Löwis995359c2003-01-26 08:59:32 +00001170 # XXX this does not work, Text is an old-style class
1171 # __slots__ = ()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001172
Fred Drake87432f42001-04-04 14:09:46 +00001173 nodeType = Node.CDATA_SECTION_NODE
1174 nodeName = "#cdata-section"
1175
1176 def writexml(self, writer, indent="", addindent="", newl=""):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001177 if self.data.find("]]>") >= 0:
1178 raise ValueError("']]>' not allowed in a CDATA section")
Guido van Rossum5b5e0b92001-09-19 13:28:25 +00001179 writer.write("<![CDATA[%s]]>" % self.data)
Fred Drake87432f42001-04-04 14:09:46 +00001180
1181
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001182class ReadOnlySequentialNamedNodeMap(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001183 __slots__ = '_seq',
1184
1185 def __init__(self, seq=()):
1186 # seq should be a list or tuple
1187 self._seq = seq
1188
1189 def __len__(self):
1190 return len(self._seq)
1191
1192 def _get_length(self):
1193 return len(self._seq)
1194
1195 def getNamedItem(self, name):
1196 for n in self._seq:
1197 if n.nodeName == name:
1198 return n
1199
1200 def getNamedItemNS(self, namespaceURI, localName):
1201 for n in self._seq:
1202 if n.namespaceURI == namespaceURI and n.localName == localName:
1203 return n
1204
1205 def __getitem__(self, name_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001206 if isinstance(name_or_tuple, tuple):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001207 node = self.getNamedItemNS(*name_or_tuple)
1208 else:
1209 node = self.getNamedItem(name_or_tuple)
1210 if node is None:
Collin Winter70e79802007-08-24 18:57:22 +00001211 raise KeyError(name_or_tuple)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001212 return node
1213
1214 def item(self, index):
1215 if index < 0:
1216 return None
1217 try:
1218 return self._seq[index]
1219 except IndexError:
1220 return None
1221
1222 def removeNamedItem(self, name):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001223 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001224 "NamedNodeMap instance is read-only")
1225
1226 def removeNamedItemNS(self, namespaceURI, localName):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001227 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001228 "NamedNodeMap instance is read-only")
1229
1230 def setNamedItem(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001231 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001232 "NamedNodeMap instance is read-only")
1233
1234 def setNamedItemNS(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001235 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001236 "NamedNodeMap instance is read-only")
1237
1238 def __getstate__(self):
1239 return [self._seq]
1240
1241 def __setstate__(self, state):
1242 self._seq = state[0]
1243
1244defproperty(ReadOnlySequentialNamedNodeMap, "length",
1245 doc="Number of entries in the NamedNodeMap.")
Paul Prescod73678da2000-07-01 04:58:47 +00001246
Fred Drakef7cf40d2000-12-14 18:16:11 +00001247
Martin v. Löwis787354c2003-01-25 15:28:29 +00001248class Identified:
1249 """Mix-in class that supports the publicId and systemId attributes."""
1250
Martin v. Löwis995359c2003-01-26 08:59:32 +00001251 # XXX this does not work, this is an old-style class
1252 # __slots__ = 'publicId', 'systemId'
Martin v. Löwis787354c2003-01-25 15:28:29 +00001253
1254 def _identified_mixin_init(self, publicId, systemId):
1255 self.publicId = publicId
1256 self.systemId = systemId
1257
1258 def _get_publicId(self):
1259 return self.publicId
1260
1261 def _get_systemId(self):
1262 return self.systemId
1263
1264class DocumentType(Identified, Childless, Node):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001265 nodeType = Node.DOCUMENT_TYPE_NODE
1266 nodeValue = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001267 name = None
1268 publicId = None
1269 systemId = None
Fred Drakedc806702001-04-05 14:41:30 +00001270 internalSubset = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001271
1272 def __init__(self, qualifiedName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001273 self.entities = ReadOnlySequentialNamedNodeMap()
1274 self.notations = ReadOnlySequentialNamedNodeMap()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001275 if qualifiedName:
1276 prefix, localname = _nssplit(qualifiedName)
1277 self.name = localname
Martin v. Löwis787354c2003-01-25 15:28:29 +00001278 self.nodeName = self.name
1279
1280 def _get_internalSubset(self):
1281 return self.internalSubset
1282
1283 def cloneNode(self, deep):
1284 if self.ownerDocument is None:
1285 # it's ok
1286 clone = DocumentType(None)
1287 clone.name = self.name
1288 clone.nodeName = self.name
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001289 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001290 if deep:
1291 clone.entities._seq = []
1292 clone.notations._seq = []
1293 for n in self.notations._seq:
1294 notation = Notation(n.nodeName, n.publicId, n.systemId)
1295 clone.notations._seq.append(notation)
1296 n._call_user_data_handler(operation, n, notation)
1297 for e in self.entities._seq:
1298 entity = Entity(e.nodeName, e.publicId, e.systemId,
1299 e.notationName)
1300 entity.actualEncoding = e.actualEncoding
1301 entity.encoding = e.encoding
1302 entity.version = e.version
1303 clone.entities._seq.append(entity)
1304 e._call_user_data_handler(operation, n, entity)
1305 self._call_user_data_handler(operation, self, clone)
1306 return clone
1307 else:
1308 return None
1309
1310 def writexml(self, writer, indent="", addindent="", newl=""):
1311 writer.write("<!DOCTYPE ")
1312 writer.write(self.name)
1313 if self.publicId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001314 writer.write("%s PUBLIC '%s'%s '%s'"
1315 % (newl, self.publicId, newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001316 elif self.systemId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001317 writer.write("%s SYSTEM '%s'" % (newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001318 if self.internalSubset is not None:
1319 writer.write(" [")
1320 writer.write(self.internalSubset)
1321 writer.write("]")
Georg Brandl175a7dc2005-08-25 22:02:43 +00001322 writer.write(">"+newl)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001323
1324class Entity(Identified, Node):
1325 attributes = None
1326 nodeType = Node.ENTITY_NODE
1327 nodeValue = None
1328
1329 actualEncoding = None
1330 encoding = None
1331 version = None
1332
1333 def __init__(self, name, publicId, systemId, notation):
1334 self.nodeName = name
1335 self.notationName = notation
1336 self.childNodes = NodeList()
1337 self._identified_mixin_init(publicId, systemId)
1338
1339 def _get_actualEncoding(self):
1340 return self.actualEncoding
1341
1342 def _get_encoding(self):
1343 return self.encoding
1344
1345 def _get_version(self):
1346 return self.version
1347
1348 def appendChild(self, newChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001349 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001350 "cannot append children to an entity node")
1351
1352 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001353 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001354 "cannot insert children below an entity node")
1355
1356 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001357 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001358 "cannot remove children from an entity node")
1359
1360 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001361 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001362 "cannot replace children of an entity node")
1363
1364class Notation(Identified, Childless, Node):
1365 nodeType = Node.NOTATION_NODE
1366 nodeValue = None
1367
1368 def __init__(self, name, publicId, systemId):
1369 self.nodeName = name
1370 self._identified_mixin_init(publicId, systemId)
Fred Drakef7cf40d2000-12-14 18:16:11 +00001371
1372
Martin v. Löwis787354c2003-01-25 15:28:29 +00001373class DOMImplementation(DOMImplementationLS):
1374 _features = [("core", "1.0"),
1375 ("core", "2.0"),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001376 ("core", None),
1377 ("xml", "1.0"),
1378 ("xml", "2.0"),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001379 ("xml", None),
1380 ("ls-load", "3.0"),
1381 ("ls-load", None),
1382 ]
1383
Fred Drakef7cf40d2000-12-14 18:16:11 +00001384 def hasFeature(self, feature, version):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001385 if version == "":
1386 version = None
1387 return (feature.lower(), version) in self._features
Fred Drakef7cf40d2000-12-14 18:16:11 +00001388
1389 def createDocument(self, namespaceURI, qualifiedName, doctype):
1390 if doctype and doctype.parentNode is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001391 raise xml.dom.WrongDocumentErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001392 "doctype object owned by another DOM tree")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001393 doc = self._create_document()
1394
1395 add_root_element = not (namespaceURI is None
1396 and qualifiedName is None
1397 and doctype is None)
1398
1399 if not qualifiedName and add_root_element:
Martin v. Löwisb417be22001-02-06 01:16:06 +00001400 # The spec is unclear what to raise here; SyntaxErr
1401 # would be the other obvious candidate. Since Xerces raises
1402 # InvalidCharacterErr, and since SyntaxErr is not listed
1403 # for createDocument, that seems to be the better choice.
1404 # XXX: need to check for illegal characters here and in
1405 # createElement.
Martin v. Löwis787354c2003-01-25 15:28:29 +00001406
1407 # DOM Level III clears this up when talking about the return value
1408 # of this function. If namespaceURI, qName and DocType are
1409 # Null the document is returned without a document element
1410 # Otherwise if doctype or namespaceURI are not None
1411 # Then we go back to the above problem
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001412 raise xml.dom.InvalidCharacterErr("Element with no name")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001413
1414 if add_root_element:
1415 prefix, localname = _nssplit(qualifiedName)
1416 if prefix == "xml" \
1417 and namespaceURI != "http://www.w3.org/XML/1998/namespace":
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001418 raise xml.dom.NamespaceErr("illegal use of 'xml' prefix")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001419 if prefix and not namespaceURI:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001420 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001421 "illegal use of prefix without namespaces")
1422 element = doc.createElementNS(namespaceURI, qualifiedName)
1423 if doctype:
1424 doc.appendChild(doctype)
1425 doc.appendChild(element)
1426
1427 if doctype:
1428 doctype.parentNode = doctype.ownerDocument = doc
1429
Fred Drakef7cf40d2000-12-14 18:16:11 +00001430 doc.doctype = doctype
1431 doc.implementation = self
1432 return doc
1433
1434 def createDocumentType(self, qualifiedName, publicId, systemId):
1435 doctype = DocumentType(qualifiedName)
1436 doctype.publicId = publicId
1437 doctype.systemId = systemId
1438 return doctype
1439
Martin v. Löwis787354c2003-01-25 15:28:29 +00001440 # DOM Level 3 (WD 9 April 2002)
1441
1442 def getInterface(self, feature):
1443 if self.hasFeature(feature, None):
1444 return self
1445 else:
1446 return None
1447
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001448 # internal
Martin v. Löwis787354c2003-01-25 15:28:29 +00001449 def _create_document(self):
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001450 return Document()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001451
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001452class ElementInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001453 """Object that represents content-model information for an element.
1454
1455 This implementation is not expected to be used in practice; DOM
1456 builders should provide implementations which do the right thing
1457 using information available to it.
1458
1459 """
1460
1461 __slots__ = 'tagName',
1462
1463 def __init__(self, name):
1464 self.tagName = name
1465
1466 def getAttributeType(self, aname):
1467 return _no_type
1468
1469 def getAttributeTypeNS(self, namespaceURI, localName):
1470 return _no_type
1471
1472 def isElementContent(self):
1473 return False
1474
1475 def isEmpty(self):
1476 """Returns true iff this element is declared to have an EMPTY
1477 content model."""
1478 return False
1479
1480 def isId(self, aname):
Ezio Melotti42da6632011-03-15 05:18:48 +02001481 """Returns true iff the named attribute is a DTD-style ID."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001482 return False
1483
1484 def isIdNS(self, namespaceURI, localName):
1485 """Returns true iff the identified attribute is a DTD-style ID."""
1486 return False
1487
1488 def __getstate__(self):
1489 return self.tagName
1490
1491 def __setstate__(self, state):
1492 self.tagName = state
1493
1494def _clear_id_cache(node):
1495 if node.nodeType == Node.DOCUMENT_NODE:
1496 node._id_cache.clear()
1497 node._id_search_stack = None
1498 elif _in_document(node):
1499 node.ownerDocument._id_cache.clear()
1500 node.ownerDocument._id_search_stack= None
1501
1502class Document(Node, DocumentLS):
1503 _child_node_types = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
1504 Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)
1505
Fred Drake1f549022000-09-24 05:21:58 +00001506 nodeType = Node.DOCUMENT_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +00001507 nodeName = "#document"
1508 nodeValue = None
1509 attributes = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001510 doctype = None
1511 parentNode = None
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001512 previousSibling = nextSibling = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001513
1514 implementation = DOMImplementation()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001515
1516 # Document attributes from Level 3 (WD 9 April 2002)
1517
1518 actualEncoding = None
1519 encoding = None
1520 standalone = None
1521 version = None
1522 strictErrorChecking = False
1523 errorHandler = None
1524 documentURI = None
1525
1526 _magic_id_count = 0
1527
1528 def __init__(self):
1529 self.childNodes = NodeList()
1530 # mapping of (namespaceURI, localName) -> ElementInfo
1531 # and tagName -> ElementInfo
1532 self._elem_info = {}
1533 self._id_cache = {}
1534 self._id_search_stack = None
1535
1536 def _get_elem_info(self, element):
1537 if element.namespaceURI:
1538 key = element.namespaceURI, element.localName
1539 else:
1540 key = element.tagName
1541 return self._elem_info.get(key)
1542
1543 def _get_actualEncoding(self):
1544 return self.actualEncoding
1545
1546 def _get_doctype(self):
1547 return self.doctype
1548
1549 def _get_documentURI(self):
1550 return self.documentURI
1551
1552 def _get_encoding(self):
1553 return self.encoding
1554
1555 def _get_errorHandler(self):
1556 return self.errorHandler
1557
1558 def _get_standalone(self):
1559 return self.standalone
1560
1561 def _get_strictErrorChecking(self):
1562 return self.strictErrorChecking
1563
1564 def _get_version(self):
1565 return self.version
Fred Drake55c38192000-06-29 19:39:57 +00001566
Fred Drake1f549022000-09-24 05:21:58 +00001567 def appendChild(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001568 if node.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001569 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001570 "%s cannot be child of %s" % (repr(node), repr(self)))
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001571 if node.parentNode is not None:
Martin v. Löwis787354c2003-01-25 15:28:29 +00001572 # This needs to be done before the next test since this
1573 # may *be* the document element, in which case it should
1574 # end up re-ordered to the end.
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001575 node.parentNode.removeChild(node)
1576
Fred Drakef7cf40d2000-12-14 18:16:11 +00001577 if node.nodeType == Node.ELEMENT_NODE \
1578 and self._get_documentElement():
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001579 raise xml.dom.HierarchyRequestErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001580 "two document elements disallowed")
Fred Drake4ccf4a12000-11-21 22:02:22 +00001581 return Node.appendChild(self, node)
Paul Prescod73678da2000-07-01 04:58:47 +00001582
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001583 def removeChild(self, oldChild):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001584 try:
1585 self.childNodes.remove(oldChild)
1586 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001587 raise xml.dom.NotFoundErr()
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001588 oldChild.nextSibling = oldChild.previousSibling = None
1589 oldChild.parentNode = None
1590 if self.documentElement is oldChild:
1591 self.documentElement = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +00001592
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001593 return oldChild
1594
Fred Drakef7cf40d2000-12-14 18:16:11 +00001595 def _get_documentElement(self):
1596 for node in self.childNodes:
1597 if node.nodeType == Node.ELEMENT_NODE:
1598 return node
1599
1600 def unlink(self):
1601 if self.doctype is not None:
1602 self.doctype.unlink()
1603 self.doctype = None
1604 Node.unlink(self)
1605
Martin v. Löwis787354c2003-01-25 15:28:29 +00001606 def cloneNode(self, deep):
1607 if not deep:
1608 return None
1609 clone = self.implementation.createDocument(None, None, None)
1610 clone.encoding = self.encoding
1611 clone.standalone = self.standalone
1612 clone.version = self.version
1613 for n in self.childNodes:
1614 childclone = _clone_node(n, deep, clone)
1615 assert childclone.ownerDocument.isSameNode(clone)
1616 clone.childNodes.append(childclone)
1617 if childclone.nodeType == Node.DOCUMENT_NODE:
1618 assert clone.documentElement is None
1619 elif childclone.nodeType == Node.DOCUMENT_TYPE_NODE:
1620 assert clone.doctype is None
1621 clone.doctype = childclone
1622 childclone.parentNode = clone
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001623 self._call_user_data_handler(xml.dom.UserDataHandler.NODE_CLONED,
Martin v. Löwis787354c2003-01-25 15:28:29 +00001624 self, clone)
1625 return clone
1626
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001627 def createDocumentFragment(self):
1628 d = DocumentFragment()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001629 d.ownerDocument = self
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001630 return d
Fred Drake55c38192000-06-29 19:39:57 +00001631
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001632 def createElement(self, tagName):
1633 e = Element(tagName)
1634 e.ownerDocument = self
1635 return e
Fred Drake55c38192000-06-29 19:39:57 +00001636
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001637 def createTextNode(self, data):
Christian Heimesc9543e42007-11-28 08:28:28 +00001638 if not isinstance(data, str):
Collin Winter70e79802007-08-24 18:57:22 +00001639 raise TypeError("node contents must be a string")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001640 t = Text()
1641 t.data = data
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001642 t.ownerDocument = self
1643 return t
Fred Drake55c38192000-06-29 19:39:57 +00001644
Fred Drake87432f42001-04-04 14:09:46 +00001645 def createCDATASection(self, data):
Christian Heimesc9543e42007-11-28 08:28:28 +00001646 if not isinstance(data, str):
Collin Winter70e79802007-08-24 18:57:22 +00001647 raise TypeError("node contents must be a string")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001648 c = CDATASection()
1649 c.data = data
Fred Drake87432f42001-04-04 14:09:46 +00001650 c.ownerDocument = self
1651 return c
1652
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001653 def createComment(self, data):
1654 c = Comment(data)
1655 c.ownerDocument = self
1656 return c
Fred Drake55c38192000-06-29 19:39:57 +00001657
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001658 def createProcessingInstruction(self, target, data):
1659 p = ProcessingInstruction(target, data)
1660 p.ownerDocument = self
1661 return p
1662
1663 def createAttribute(self, qName):
1664 a = Attr(qName)
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
1669 def createElementNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001670 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001671 e = Element(qualifiedName, namespaceURI, prefix)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001672 e.ownerDocument = self
1673 return e
Fred Drake55c38192000-06-29 19:39:57 +00001674
1675 def createAttributeNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001676 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001677 a = Attr(qualifiedName, namespaceURI, localName, prefix)
1678 a.ownerDocument = self
Martin v. Löwiscb67ea12001-03-31 16:30:40 +00001679 a.value = ""
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001680 return a
Fred Drake55c38192000-06-29 19:39:57 +00001681
Martin v. Löwis787354c2003-01-25 15:28:29 +00001682 # A couple of implementation-specific helpers to create node types
1683 # not supported by the W3C DOM specs:
1684
1685 def _create_entity(self, name, publicId, systemId, notationName):
1686 e = Entity(name, publicId, systemId, notationName)
1687 e.ownerDocument = self
1688 return e
1689
1690 def _create_notation(self, name, publicId, systemId):
1691 n = Notation(name, publicId, systemId)
1692 n.ownerDocument = self
1693 return n
1694
1695 def getElementById(self, id):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +00001696 if id in self._id_cache:
Martin v. Löwis787354c2003-01-25 15:28:29 +00001697 return self._id_cache[id]
1698 if not (self._elem_info or self._magic_id_count):
1699 return None
1700
1701 stack = self._id_search_stack
1702 if stack is None:
1703 # we never searched before, or the cache has been cleared
1704 stack = [self.documentElement]
1705 self._id_search_stack = stack
1706 elif not stack:
1707 # Previous search was completed and cache is still valid;
1708 # no matching node.
1709 return None
1710
1711 result = None
1712 while stack:
1713 node = stack.pop()
1714 # add child elements to stack for continued searching
1715 stack.extend([child for child in node.childNodes
1716 if child.nodeType in _nodeTypes_with_children])
1717 # check this node
1718 info = self._get_elem_info(node)
1719 if info:
1720 # We have to process all ID attributes before
1721 # returning in order to get all the attributes set to
1722 # be IDs using Element.setIdAttribute*().
1723 for attr in node.attributes.values():
1724 if attr.namespaceURI:
1725 if info.isIdNS(attr.namespaceURI, attr.localName):
1726 self._id_cache[attr.value] = node
1727 if attr.value == id:
1728 result = node
1729 elif not node._magic_id_nodes:
1730 break
1731 elif info.isId(attr.name):
1732 self._id_cache[attr.value] = node
1733 if attr.value == id:
1734 result = node
1735 elif not node._magic_id_nodes:
1736 break
1737 elif attr._is_id:
1738 self._id_cache[attr.value] = node
1739 if attr.value == id:
1740 result = node
1741 elif node._magic_id_nodes == 1:
1742 break
1743 elif node._magic_id_nodes:
1744 for attr in node.attributes.values():
1745 if attr._is_id:
1746 self._id_cache[attr.value] = node
1747 if attr.value == id:
1748 result = node
1749 if result is not None:
1750 break
1751 return result
1752
Fred Drake1f549022000-09-24 05:21:58 +00001753 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001754 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drakefbe7b4f2001-07-04 06:25:53 +00001755
1756 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001757 return _get_elements_by_tagName_ns_helper(
1758 self, namespaceURI, localName, NodeList())
1759
1760 def isSupported(self, feature, version):
1761 return self.implementation.hasFeature(feature, version)
1762
1763 def importNode(self, node, deep):
1764 if node.nodeType == Node.DOCUMENT_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001765 raise xml.dom.NotSupportedErr("cannot import document nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001766 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001767 raise xml.dom.NotSupportedErr("cannot import document type nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001768 return _clone_node(node, deep, self)
Fred Drake55c38192000-06-29 19:39:57 +00001769
Martin v. Löwis7d650ca2002-06-30 15:05:00 +00001770 def writexml(self, writer, indent="", addindent="", newl="",
1771 encoding = None):
1772 if encoding is None:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001773 writer.write('<?xml version="1.0" ?>'+newl)
Martin v. Löwis7d650ca2002-06-30 15:05:00 +00001774 else:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001775 writer.write('<?xml version="1.0" encoding="%s"?>%s' % (encoding, newl))
Fred Drake55c38192000-06-29 19:39:57 +00001776 for node in self.childNodes:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001777 node.writexml(writer, indent, addindent, newl)
Fred Drake55c38192000-06-29 19:39:57 +00001778
Martin v. Löwis787354c2003-01-25 15:28:29 +00001779 # DOM Level 3 (WD 9 April 2002)
1780
1781 def renameNode(self, n, namespaceURI, name):
1782 if n.ownerDocument is not self:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001783 raise xml.dom.WrongDocumentErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001784 "cannot rename nodes from other documents;\n"
1785 "expected %s,\nfound %s" % (self, n.ownerDocument))
1786 if n.nodeType not in (Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001787 raise xml.dom.NotSupportedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001788 "renameNode() only applies to element and attribute nodes")
1789 if namespaceURI != EMPTY_NAMESPACE:
1790 if ':' in name:
1791 prefix, localName = name.split(':', 1)
1792 if ( prefix == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001793 and namespaceURI != xml.dom.XMLNS_NAMESPACE):
1794 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001795 "illegal use of 'xmlns' prefix")
1796 else:
1797 if ( name == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001798 and namespaceURI != xml.dom.XMLNS_NAMESPACE
Martin v. Löwis787354c2003-01-25 15:28:29 +00001799 and n.nodeType == Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001800 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001801 "illegal use of the 'xmlns' attribute")
1802 prefix = None
1803 localName = name
1804 else:
1805 prefix = None
1806 localName = None
1807 if n.nodeType == Node.ATTRIBUTE_NODE:
1808 element = n.ownerElement
1809 if element is not None:
1810 is_id = n._is_id
1811 element.removeAttributeNode(n)
1812 else:
1813 element = None
1814 # avoid __setattr__
1815 d = n.__dict__
1816 d['prefix'] = prefix
1817 d['localName'] = localName
1818 d['namespaceURI'] = namespaceURI
1819 d['nodeName'] = name
1820 if n.nodeType == Node.ELEMENT_NODE:
1821 d['tagName'] = name
1822 else:
1823 # attribute node
1824 d['name'] = name
1825 if element is not None:
1826 element.setAttributeNode(n)
1827 if is_id:
1828 element.setIdAttributeNode(n)
1829 # It's not clear from a semantic perspective whether we should
1830 # call the user data handlers for the NODE_RENAMED event since
1831 # we're re-using the existing node. The draft spec has been
1832 # interpreted as meaning "no, don't call the handler unless a
1833 # new node is created."
1834 return n
1835
1836defproperty(Document, "documentElement",
1837 doc="Top-level element of this document.")
1838
1839
1840def _clone_node(node, deep, newOwnerDocument):
1841 """
1842 Clone a node and give it the new owner document.
1843 Called by Node.cloneNode and Document.importNode
1844 """
1845 if node.ownerDocument.isSameNode(newOwnerDocument):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001846 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001847 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001848 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001849 if node.nodeType == Node.ELEMENT_NODE:
1850 clone = newOwnerDocument.createElementNS(node.namespaceURI,
1851 node.nodeName)
1852 for attr in node.attributes.values():
1853 clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value)
1854 a = clone.getAttributeNodeNS(attr.namespaceURI, attr.localName)
1855 a.specified = attr.specified
1856
1857 if deep:
1858 for child in node.childNodes:
1859 c = _clone_node(child, deep, newOwnerDocument)
1860 clone.appendChild(c)
1861
1862 elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
1863 clone = newOwnerDocument.createDocumentFragment()
1864 if deep:
1865 for child in node.childNodes:
1866 c = _clone_node(child, deep, newOwnerDocument)
1867 clone.appendChild(c)
1868
1869 elif node.nodeType == Node.TEXT_NODE:
1870 clone = newOwnerDocument.createTextNode(node.data)
1871 elif node.nodeType == Node.CDATA_SECTION_NODE:
1872 clone = newOwnerDocument.createCDATASection(node.data)
1873 elif node.nodeType == Node.PROCESSING_INSTRUCTION_NODE:
1874 clone = newOwnerDocument.createProcessingInstruction(node.target,
1875 node.data)
1876 elif node.nodeType == Node.COMMENT_NODE:
1877 clone = newOwnerDocument.createComment(node.data)
1878 elif node.nodeType == Node.ATTRIBUTE_NODE:
1879 clone = newOwnerDocument.createAttributeNS(node.namespaceURI,
1880 node.nodeName)
1881 clone.specified = True
1882 clone.value = node.value
1883 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
1884 assert node.ownerDocument is not newOwnerDocument
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001885 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001886 clone = newOwnerDocument.implementation.createDocumentType(
1887 node.name, node.publicId, node.systemId)
1888 clone.ownerDocument = newOwnerDocument
1889 if deep:
1890 clone.entities._seq = []
1891 clone.notations._seq = []
1892 for n in node.notations._seq:
1893 notation = Notation(n.nodeName, n.publicId, n.systemId)
1894 notation.ownerDocument = newOwnerDocument
1895 clone.notations._seq.append(notation)
1896 if hasattr(n, '_call_user_data_handler'):
1897 n._call_user_data_handler(operation, n, notation)
1898 for e in node.entities._seq:
1899 entity = Entity(e.nodeName, e.publicId, e.systemId,
1900 e.notationName)
1901 entity.actualEncoding = e.actualEncoding
1902 entity.encoding = e.encoding
1903 entity.version = e.version
1904 entity.ownerDocument = newOwnerDocument
1905 clone.entities._seq.append(entity)
1906 if hasattr(e, '_call_user_data_handler'):
1907 e._call_user_data_handler(operation, n, entity)
1908 else:
1909 # Note the cloning of Document and DocumentType nodes is
Ezio Melotti13925002011-03-16 11:05:33 +02001910 # implementation specific. minidom handles those cases
Martin v. Löwis787354c2003-01-25 15:28:29 +00001911 # directly in the cloneNode() methods.
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001912 raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001913
1914 # Check for _call_user_data_handler() since this could conceivably
1915 # used with other DOM implementations (one of the FourThought
1916 # DOMs, perhaps?).
1917 if hasattr(node, '_call_user_data_handler'):
1918 node._call_user_data_handler(operation, node, clone)
1919 return clone
1920
1921
1922def _nssplit(qualifiedName):
1923 fields = qualifiedName.split(':', 1)
1924 if len(fields) == 2:
1925 return fields
1926 else:
1927 return (None, fields[0])
1928
1929
Martin v. Löwis787354c2003-01-25 15:28:29 +00001930def _do_pulldom_parse(func, args, kwargs):
Raymond Hettingerff41c482003-04-06 09:01:11 +00001931 events = func(*args, **kwargs)
Fred Drake1f549022000-09-24 05:21:58 +00001932 toktype, rootNode = events.getEvent()
1933 events.expandNode(rootNode)
Martin v. Löwisb417be22001-02-06 01:16:06 +00001934 events.clear()
Fred Drake55c38192000-06-29 19:39:57 +00001935 return rootNode
1936
Martin v. Löwis787354c2003-01-25 15:28:29 +00001937def parse(file, parser=None, bufsize=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001938 """Parse a file into a DOM by filename or file object."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001939 if parser is None and not bufsize:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001940 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001941 return expatbuilder.parse(file)
1942 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001943 from xml.dom import pulldom
Raymond Hettingerff41c482003-04-06 09:01:11 +00001944 return _do_pulldom_parse(pulldom.parse, (file,),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001945 {'parser': parser, 'bufsize': bufsize})
Fred Drake55c38192000-06-29 19:39:57 +00001946
Martin v. Löwis787354c2003-01-25 15:28:29 +00001947def parseString(string, parser=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001948 """Parse a file into a DOM from a string."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001949 if parser is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001950 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001951 return expatbuilder.parseString(string)
1952 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001953 from xml.dom import pulldom
Martin v. Löwis787354c2003-01-25 15:28:29 +00001954 return _do_pulldom_parse(pulldom.parseString, (string,),
1955 {'parser': parser})
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001956
Martin v. Löwis787354c2003-01-25 15:28:29 +00001957def getDOMImplementation(features=None):
1958 if features:
Christian Heimesc9543e42007-11-28 08:28:28 +00001959 if isinstance(features, str):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001960 features = domreg._parse_feature_string(features)
1961 for f, v in features:
1962 if not Document.implementation.hasFeature(f, v):
1963 return None
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001964 return Document.implementation