blob: 28e5030b86afb3a39439539c90d9216f5b39e70d [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
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000017import io
Thomas Wouters0e3f5912006-08-11 14:57:12 +000018import xml.dom
Fred Drake55c38192000-06-29 19:39:57 +000019
Thomas Wouters0e3f5912006-08-11 14:57:12 +000020from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE, domreg
21from xml.dom.minicompat import *
22from xml.dom.xmlbuilder import DOMImplementationLS, DocumentLS
Fred Drake3ac6a092001-09-28 04:33:06 +000023
Martin v. Löwis787354c2003-01-25 15:28:29 +000024# This is used by the ID-cache invalidation checks; the list isn't
25# actually complete, since the nodes being checked will never be the
26# DOCUMENT_NODE or DOCUMENT_FRAGMENT_NODE. (The node being checked is
27# the node being added or removed, not the node being modified.)
28#
Thomas Wouters0e3f5912006-08-11 14:57:12 +000029_nodeTypes_with_children = (xml.dom.Node.ELEMENT_NODE,
30 xml.dom.Node.ENTITY_REFERENCE_NODE)
Martin v. Löwis95700f72002-03-15 13:51:59 +000031
Fred Drake3ac6a092001-09-28 04:33:06 +000032
Thomas Wouters0e3f5912006-08-11 14:57:12 +000033class Node(xml.dom.Node):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000034 namespaceURI = None # this is non-null only for elements and attributes
Fred Drake575712e2001-09-28 20:25:45 +000035 parentNode = None
36 ownerDocument = None
Martin v. Löwis787354c2003-01-25 15:28:29 +000037 nextSibling = None
38 previousSibling = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +000039
Martin v. Löwis787354c2003-01-25 15:28:29 +000040 prefix = EMPTY_PREFIX # non-null only for NS elements and attributes
Fred Drake55c38192000-06-29 19:39:57 +000041
Jack Diederich4dafcc42006-11-28 19:15:13 +000042 def __bool__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +000043 return True
Fred Drake55c38192000-06-29 19:39:57 +000044
Georg Brandlfe991052009-09-16 15:54:04 +000045 def toxml(self, encoding=None):
Martin v. Löwis7d650ca2002-06-30 15:05:00 +000046 return self.toprettyxml("", "", encoding)
Fred Drake55c38192000-06-29 19:39:57 +000047
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000048 def toprettyxml(self, indent="\t", newl="\n", encoding=None):
Eli Bendersky8a805022012-07-13 09:52:39 +030049 if encoding is None:
50 writer = io.StringIO()
51 else:
52 writer = io.TextIOWrapper(io.BytesIO(),
53 encoding=encoding,
54 errors="xmlcharrefreplace",
55 newline='\n')
Martin v. Löwis7d650ca2002-06-30 15:05:00 +000056 if self.nodeType == Node.DOCUMENT_NODE:
57 # Can pass encoding only to document, to put it into XML header
58 self.writexml(writer, "", indent, newl, encoding)
59 else:
60 self.writexml(writer, "", indent, newl)
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000061 if encoding is None:
Eli Bendersky8a805022012-07-13 09:52:39 +030062 return writer.getvalue()
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000063 else:
Eli Bendersky8a805022012-07-13 09:52:39 +030064 return writer.detach().getvalue()
Martin v. Löwis46fa39a2001-02-06 00:14:08 +000065
Fred Drake1f549022000-09-24 05:21:58 +000066 def hasChildNodes(self):
Florent Xicluna8cf4b512012-03-05 12:37:02 +010067 return bool(self.childNodes)
Martin v. Löwis787354c2003-01-25 15:28:29 +000068
69 def _get_childNodes(self):
70 return self.childNodes
Fred Drake55c38192000-06-29 19:39:57 +000071
Fred Drake1f549022000-09-24 05:21:58 +000072 def _get_firstChild(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +000073 if self.childNodes:
74 return self.childNodes[0]
Paul Prescod73678da2000-07-01 04:58:47 +000075
Fred Drake1f549022000-09-24 05:21:58 +000076 def _get_lastChild(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +000077 if self.childNodes:
78 return self.childNodes[-1]
Paul Prescod73678da2000-07-01 04:58:47 +000079
Fred Drake1f549022000-09-24 05:21:58 +000080 def insertBefore(self, newChild, refChild):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000081 if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
Fred Drakee50959a2001-12-06 04:32:18 +000082 for c in tuple(newChild.childNodes):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000083 self.insertBefore(c, refChild)
84 ### The DOM does not clearly specify what to return in this case
85 return newChild
Martin v. Löwis787354c2003-01-25 15:28:29 +000086 if newChild.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000087 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +000088 "%s cannot be child of %s" % (repr(newChild), repr(self)))
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +000089 if newChild.parentNode is not None:
90 newChild.parentNode.removeChild(newChild)
Fred Drake4ccf4a12000-11-21 22:02:22 +000091 if refChild is None:
92 self.appendChild(newChild)
93 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +000094 try:
95 index = self.childNodes.index(refChild)
96 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000097 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +000098 if newChild.nodeType in _nodeTypes_with_children:
99 _clear_id_cache(self)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000100 self.childNodes.insert(index, newChild)
101 newChild.nextSibling = refChild
102 refChild.previousSibling = newChild
103 if index:
104 node = self.childNodes[index-1]
105 node.nextSibling = newChild
106 newChild.previousSibling = node
107 else:
108 newChild.previousSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000109 newChild.parentNode = self
Fred Drake4ccf4a12000-11-21 22:02:22 +0000110 return newChild
Fred Drake55c38192000-06-29 19:39:57 +0000111
Fred Drake1f549022000-09-24 05:21:58 +0000112 def appendChild(self, node):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000113 if node.nodeType == self.DOCUMENT_FRAGMENT_NODE:
Fred Drakee50959a2001-12-06 04:32:18 +0000114 for c in tuple(node.childNodes):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000115 self.appendChild(c)
116 ### The DOM does not clearly specify what to return in this case
117 return node
Martin v. Löwis787354c2003-01-25 15:28:29 +0000118 if node.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000119 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000120 "%s cannot be child of %s" % (repr(node), repr(self)))
121 elif node.nodeType in _nodeTypes_with_children:
122 _clear_id_cache(self)
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000123 if node.parentNode is not None:
124 node.parentNode.removeChild(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000125 _append_child(self, node)
Fred Drake13a30692000-10-09 20:04:16 +0000126 node.nextSibling = None
Paul Prescod73678da2000-07-01 04:58:47 +0000127 return node
128
Fred Drake1f549022000-09-24 05:21:58 +0000129 def replaceChild(self, newChild, oldChild):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000130 if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
131 refChild = oldChild.nextSibling
132 self.removeChild(oldChild)
133 return self.insertBefore(newChild, refChild)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000134 if newChild.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000135 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000136 "%s cannot be child of %s" % (repr(newChild), repr(self)))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000137 if newChild is oldChild:
138 return
Andrew M. Kuchling841d25e2005-11-22 19:03:16 +0000139 if newChild.parentNode is not None:
140 newChild.parentNode.removeChild(newChild)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000141 try:
142 index = self.childNodes.index(oldChild)
143 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000144 raise xml.dom.NotFoundErr()
Fred Drake4ccf4a12000-11-21 22:02:22 +0000145 self.childNodes[index] = newChild
Martin v. Löwis787354c2003-01-25 15:28:29 +0000146 newChild.parentNode = self
147 oldChild.parentNode = None
148 if (newChild.nodeType in _nodeTypes_with_children
149 or oldChild.nodeType in _nodeTypes_with_children):
150 _clear_id_cache(self)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000151 newChild.nextSibling = oldChild.nextSibling
152 newChild.previousSibling = oldChild.previousSibling
Martin v. Löwis156c3372000-12-28 18:40:56 +0000153 oldChild.nextSibling = None
Fred Drake4ccf4a12000-11-21 22:02:22 +0000154 oldChild.previousSibling = None
Martin v. Löwis156c3372000-12-28 18:40:56 +0000155 if newChild.previousSibling:
156 newChild.previousSibling.nextSibling = newChild
157 if newChild.nextSibling:
158 newChild.nextSibling.previousSibling = newChild
Fred Drake4ccf4a12000-11-21 22:02:22 +0000159 return oldChild
Paul Prescod73678da2000-07-01 04:58:47 +0000160
Fred Drake1f549022000-09-24 05:21:58 +0000161 def removeChild(self, oldChild):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000162 try:
163 self.childNodes.remove(oldChild)
164 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000165 raise xml.dom.NotFoundErr()
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000166 if oldChild.nextSibling is not None:
167 oldChild.nextSibling.previousSibling = oldChild.previousSibling
168 if oldChild.previousSibling is not None:
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000169 oldChild.previousSibling.nextSibling = oldChild.nextSibling
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000170 oldChild.nextSibling = oldChild.previousSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000171 if oldChild.nodeType in _nodeTypes_with_children:
172 _clear_id_cache(self)
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000173
Martin v. Löwis787354c2003-01-25 15:28:29 +0000174 oldChild.parentNode = None
Fred Drake4ccf4a12000-11-21 22:02:22 +0000175 return oldChild
176
177 def normalize(self):
Fred Drakef7cf40d2000-12-14 18:16:11 +0000178 L = []
179 for child in self.childNodes:
180 if child.nodeType == Node.TEXT_NODE:
R. David Murraydc6da8a2009-04-09 22:16:43 +0000181 if not child.data:
182 # empty text node; discard
183 if L:
184 L[-1].nextSibling = child.nextSibling
185 if child.nextSibling:
186 child.nextSibling.previousSibling = child.previousSibling
187 child.unlink()
188 elif L and L[-1].nodeType == child.nodeType:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000189 # collapse text node
190 node = L[-1]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000191 node.data = node.data + child.data
Fred Drake4ccf4a12000-11-21 22:02:22 +0000192 node.nextSibling = child.nextSibling
R. David Murraydc6da8a2009-04-09 22:16:43 +0000193 if child.nextSibling:
194 child.nextSibling.previousSibling = node
Fred Drake4ccf4a12000-11-21 22:02:22 +0000195 child.unlink()
R. David Murraydc6da8a2009-04-09 22:16:43 +0000196 else:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000197 L.append(child)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000198 else:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000199 L.append(child)
200 if child.nodeType == Node.ELEMENT_NODE:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000201 child.normalize()
Fred Drakef7cf40d2000-12-14 18:16:11 +0000202 self.childNodes[:] = L
Paul Prescod73678da2000-07-01 04:58:47 +0000203
Fred Drake1f549022000-09-24 05:21:58 +0000204 def cloneNode(self, deep):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000205 return _clone_node(self, deep, self.ownerDocument or self)
Fred Drake55c38192000-06-29 19:39:57 +0000206
Martin v. Löwis787354c2003-01-25 15:28:29 +0000207 def isSupported(self, feature, version):
208 return self.ownerDocument.implementation.hasFeature(feature, version)
209
210 def _get_localName(self):
211 # Overridden in Element and Attr where localName can be Non-Null
212 return None
213
214 # Node interfaces from Level 3 (WD 9 April 2002)
Fred Drake25239772001-02-02 19:40:19 +0000215
216 def isSameNode(self, other):
217 return self is other
218
Martin v. Löwis787354c2003-01-25 15:28:29 +0000219 def getInterface(self, feature):
220 if self.isSupported(feature, None):
221 return self
222 else:
223 return None
224
225 # The "user data" functions use a dictionary that is only present
226 # if some user data has been set, so be careful not to assume it
227 # exists.
228
229 def getUserData(self, key):
230 try:
231 return self._user_data[key][0]
232 except (AttributeError, KeyError):
233 return None
234
235 def setUserData(self, key, data, handler):
236 old = None
237 try:
238 d = self._user_data
239 except AttributeError:
240 d = {}
241 self._user_data = d
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000242 if key in d:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000243 old = d[key][0]
244 if data is None:
245 # ignore handlers passed for None
246 handler = None
247 if old is not None:
248 del d[key]
249 else:
250 d[key] = (data, handler)
251 return old
252
253 def _call_user_data_handler(self, operation, src, dst):
254 if hasattr(self, "_user_data"):
Brett Cannon861fd6f2007-02-21 22:05:37 +0000255 for key, (data, handler) in list(self._user_data.items()):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000256 if handler is not None:
257 handler.handle(operation, key, data, src, dst)
258
Fred Drake25239772001-02-02 19:40:19 +0000259 # minidom-specific API:
260
Fred Drake1f549022000-09-24 05:21:58 +0000261 def unlink(self):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000262 self.parentNode = self.ownerDocument = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000263 if self.childNodes:
264 for child in self.childNodes:
265 child.unlink()
266 self.childNodes = NodeList()
Paul Prescod4221ff02000-10-13 20:11:42 +0000267 self.previousSibling = None
268 self.nextSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000269
Kristján Valur Jónsson17173cf2010-06-09 08:13:42 +0000270 # A Node is its own context manager, to ensure that an unlink() call occurs.
271 # This is similar to how a file object works.
272 def __enter__(self):
273 return self
274
275 def __exit__(self, et, ev, tb):
276 self.unlink()
277
Martin v. Löwis787354c2003-01-25 15:28:29 +0000278defproperty(Node, "firstChild", doc="First child node, or None.")
279defproperty(Node, "lastChild", doc="Last child node, or None.")
280defproperty(Node, "localName", doc="Namespace-local name of this node.")
281
282
283def _append_child(self, node):
284 # fast path with less checks; usable by DOM builders if careful
285 childNodes = self.childNodes
286 if childNodes:
287 last = childNodes[-1]
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100288 node.previousSibling = last
289 last.nextSibling = node
Martin v. Löwis787354c2003-01-25 15:28:29 +0000290 childNodes.append(node)
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100291 node.parentNode = self
Martin v. Löwis787354c2003-01-25 15:28:29 +0000292
293def _in_document(node):
294 # return True iff node is part of a document tree
295 while node is not None:
296 if node.nodeType == Node.DOCUMENT_NODE:
297 return True
298 node = node.parentNode
299 return False
Fred Drake55c38192000-06-29 19:39:57 +0000300
Fred Drake1f549022000-09-24 05:21:58 +0000301def _write_data(writer, data):
Fred Drake55c38192000-06-29 19:39:57 +0000302 "Writes datachars to writer."
Georg Brandlb9cd72a2010-10-15 17:58:45 +0000303 if data:
304 data = data.replace("&", "&amp;").replace("<", "&lt;"). \
305 replace("\"", "&quot;").replace(">", "&gt;")
306 writer.write(data)
Fred Drake55c38192000-06-29 19:39:57 +0000307
Martin v. Löwis787354c2003-01-25 15:28:29 +0000308def _get_elements_by_tagName_helper(parent, name, 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 and \
311 (name == "*" or node.tagName == name):
312 rc.append(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000313 _get_elements_by_tagName_helper(node, name, rc)
Fred Drake55c38192000-06-29 19:39:57 +0000314 return rc
315
Martin v. Löwis787354c2003-01-25 15:28:29 +0000316def _get_elements_by_tagName_ns_helper(parent, nsURI, localName, rc):
Fred Drake55c38192000-06-29 19:39:57 +0000317 for node in parent.childNodes:
Fred Drake1f549022000-09-24 05:21:58 +0000318 if node.nodeType == Node.ELEMENT_NODE:
Martin v. Löwised525fb2001-06-03 14:06:42 +0000319 if ((localName == "*" or node.localName == localName) and
Fred Drake1f549022000-09-24 05:21:58 +0000320 (nsURI == "*" or node.namespaceURI == nsURI)):
321 rc.append(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000322 _get_elements_by_tagName_ns_helper(node, nsURI, localName, rc)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000323 return rc
Fred Drake55c38192000-06-29 19:39:57 +0000324
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000325class DocumentFragment(Node):
326 nodeType = Node.DOCUMENT_FRAGMENT_NODE
327 nodeName = "#document-fragment"
328 nodeValue = None
329 attributes = None
330 parentNode = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000331 _child_node_types = (Node.ELEMENT_NODE,
332 Node.TEXT_NODE,
333 Node.CDATA_SECTION_NODE,
334 Node.ENTITY_REFERENCE_NODE,
335 Node.PROCESSING_INSTRUCTION_NODE,
336 Node.COMMENT_NODE,
337 Node.NOTATION_NODE)
338
339 def __init__(self):
340 self.childNodes = NodeList()
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000341
342
Fred Drake55c38192000-06-29 19:39:57 +0000343class Attr(Node):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100344 __slots__=('_name', '_value', 'namespaceURI',
345 '_prefix', 'childNodes', '_localName', 'ownerDocument', 'ownerElement')
Fred Drake1f549022000-09-24 05:21:58 +0000346 nodeType = Node.ATTRIBUTE_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +0000347 attributes = 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):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100355 self.ownerElement = None
356 self._name = qName
357 self.namespaceURI = namespaceURI
358 self._prefix = prefix
359 self.childNodes = NodeList()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000360
361 # Add the single child node that represents the value of the attr
362 self.childNodes.append(Text())
363
Paul Prescod73678da2000-07-01 04:58:47 +0000364 # nodeValue and value are set elsewhere
Fred Drake55c38192000-06-29 19:39:57 +0000365
Martin v. Löwis787354c2003-01-25 15:28:29 +0000366 def _get_localName(self):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100367 try:
368 return self._localName
369 except AttributeError:
370 return self.nodeName.split(":", 1)[-1]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000371
372 def _get_name(self):
373 return self.name
374
375 def _get_specified(self):
376 return self.specified
377
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100378 def _get_name(self):
379 return self._name
380
381 def _set_name(self, value):
382 self._name = value
383 if self.ownerElement is not None:
384 _clear_id_cache(self.ownerElement)
385
386 nodeName = name = property(_get_name, _set_name)
387
388 def _get_value(self):
389 return self._value
390
391 def _set_value(self, value):
392 self._value = value
393 self.childNodes[0].data = value
394 if self.ownerElement is not None:
395 _clear_id_cache(self.ownerElement)
396 self.childNodes[0].data = value
397
398 nodeValue = value = property(_get_value, _set_value)
399
400 def _get_prefix(self):
401 return self._prefix
Fred Drake55c38192000-06-29 19:39:57 +0000402
Martin v. Löwis995359c2003-01-26 08:59:32 +0000403 def _set_prefix(self, prefix):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000404 nsuri = self.namespaceURI
Martin v. Löwis995359c2003-01-26 08:59:32 +0000405 if prefix == "xmlns":
406 if nsuri and nsuri != XMLNS_NAMESPACE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000407 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000408 "illegal use of 'xmlns' prefix for the wrong namespace")
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100409 self._prefix = prefix
Martin v. Löwis787354c2003-01-25 15:28:29 +0000410 if prefix is None:
411 newName = self.localName
412 else:
Martin v. Löwis995359c2003-01-26 08:59:32 +0000413 newName = "%s:%s" % (prefix, self.localName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000414 if self.ownerElement:
415 _clear_id_cache(self.ownerElement)
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100416 self.name = newName
Martin v. Löwis787354c2003-01-25 15:28:29 +0000417
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100418 prefix = property(_get_prefix, _set_prefix)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000419
420 def unlink(self):
421 # This implementation does not call the base implementation
422 # since most of that is not needed, and the expense of the
423 # method call is not warranted. We duplicate the removal of
424 # children, but that's all we needed from the base class.
425 elem = self.ownerElement
426 if elem is not None:
427 del elem._attrs[self.nodeName]
428 del elem._attrsNS[(self.namespaceURI, self.localName)]
429 if self._is_id:
430 self._is_id = False
431 elem._magic_id_nodes -= 1
432 self.ownerDocument._magic_id_count -= 1
433 for child in self.childNodes:
434 child.unlink()
435 del self.childNodes[:]
436
437 def _get_isId(self):
438 if self._is_id:
439 return True
440 doc = self.ownerDocument
441 elem = self.ownerElement
442 if doc is None or elem is None:
443 return False
444
445 info = doc._get_elem_info(elem)
446 if info is None:
447 return False
448 if self.namespaceURI:
449 return info.isIdNS(self.namespaceURI, self.localName)
450 else:
451 return info.isId(self.nodeName)
452
453 def _get_schemaType(self):
454 doc = self.ownerDocument
455 elem = self.ownerElement
456 if doc is None or elem is None:
457 return _no_type
458
459 info = doc._get_elem_info(elem)
460 if info is None:
461 return _no_type
462 if self.namespaceURI:
463 return info.getAttributeTypeNS(self.namespaceURI, self.localName)
464 else:
465 return info.getAttributeType(self.nodeName)
466
467defproperty(Attr, "isId", doc="True if this attribute is an ID.")
468defproperty(Attr, "localName", doc="Namespace-local name of this attribute.")
469defproperty(Attr, "schemaType", doc="Schema type for this attribute.")
Fred Drake4ccf4a12000-11-21 22:02:22 +0000470
Fred Drakef7cf40d2000-12-14 18:16:11 +0000471
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000472class NamedNodeMap(object):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000473 """The attribute list is a transient interface to the underlying
474 dictionaries. Mutations here will change the underlying element's
Fred Drakef7cf40d2000-12-14 18:16:11 +0000475 dictionary.
476
477 Ordering is imposed artificially and does not reflect the order of
478 attributes as found in an input document.
479 """
Fred Drake4ccf4a12000-11-21 22:02:22 +0000480
Martin v. Löwis787354c2003-01-25 15:28:29 +0000481 __slots__ = ('_attrs', '_attrsNS', '_ownerElement')
482
Fred Drake2998a552001-12-06 18:27:48 +0000483 def __init__(self, attrs, attrsNS, ownerElement):
Fred Drake1f549022000-09-24 05:21:58 +0000484 self._attrs = attrs
485 self._attrsNS = attrsNS
Fred Drake2998a552001-12-06 18:27:48 +0000486 self._ownerElement = ownerElement
Fred Drakef7cf40d2000-12-14 18:16:11 +0000487
Martin v. Löwis787354c2003-01-25 15:28:29 +0000488 def _get_length(self):
489 return len(self._attrs)
Fred Drake55c38192000-06-29 19:39:57 +0000490
Fred Drake1f549022000-09-24 05:21:58 +0000491 def item(self, index):
Fred Drake55c38192000-06-29 19:39:57 +0000492 try:
Brett Cannon861fd6f2007-02-21 22:05:37 +0000493 return self[list(self._attrs.keys())[index]]
Fred Drake55c38192000-06-29 19:39:57 +0000494 except IndexError:
495 return None
Fred Drake55c38192000-06-29 19:39:57 +0000496
Fred Drake1f549022000-09-24 05:21:58 +0000497 def items(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000498 L = []
499 for node in self._attrs.values():
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000500 L.append((node.nodeName, node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000501 return L
Fred Drake1f549022000-09-24 05:21:58 +0000502
503 def itemsNS(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000504 L = []
505 for node in self._attrs.values():
Fred Drake49a5d032001-11-30 22:21:58 +0000506 L.append(((node.namespaceURI, node.localName), node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000507 return L
Fred Drake16f63292000-10-23 18:09:50 +0000508
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000509 def __contains__(self, key):
Christian Heimesc9543e42007-11-28 08:28:28 +0000510 if isinstance(key, str):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000511 return key in self._attrs
Martin v. Löwis787354c2003-01-25 15:28:29 +0000512 else:
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000513 return key in self._attrsNS
Martin v. Löwis787354c2003-01-25 15:28:29 +0000514
Fred Drake1f549022000-09-24 05:21:58 +0000515 def keys(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000516 return self._attrs.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000517
Fred Drake1f549022000-09-24 05:21:58 +0000518 def keysNS(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000519 return self._attrsNS.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000520
Fred Drake1f549022000-09-24 05:21:58 +0000521 def values(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000522 return self._attrs.values()
Fred Drake55c38192000-06-29 19:39:57 +0000523
Martin v. Löwis787354c2003-01-25 15:28:29 +0000524 def get(self, name, value=None):
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000525 return self._attrs.get(name, value)
526
Martin v. Löwis787354c2003-01-25 15:28:29 +0000527 __len__ = _get_length
Fred Drake55c38192000-06-29 19:39:57 +0000528
Mark Dickinsona56c4672009-01-27 18:17:45 +0000529 def _cmp(self, other):
Fred Drake1f549022000-09-24 05:21:58 +0000530 if self._attrs is getattr(other, "_attrs", None):
Fred Drake55c38192000-06-29 19:39:57 +0000531 return 0
Fred Drake16f63292000-10-23 18:09:50 +0000532 else:
Mark Dickinsona56c4672009-01-27 18:17:45 +0000533 return (id(self) > id(other)) - (id(self) < id(other))
534
535 def __eq__(self, other):
536 return self._cmp(other) == 0
537
538 def __ge__(self, other):
539 return self._cmp(other) >= 0
540
541 def __gt__(self, other):
542 return self._cmp(other) > 0
543
544 def __le__(self, other):
545 return self._cmp(other) <= 0
546
547 def __lt__(self, other):
548 return self._cmp(other) < 0
549
550 def __ne__(self, other):
551 return self._cmp(other) != 0
Fred Drake55c38192000-06-29 19:39:57 +0000552
Fred Drake1f549022000-09-24 05:21:58 +0000553 def __getitem__(self, attname_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000554 if isinstance(attname_or_tuple, tuple):
Paul Prescod73678da2000-07-01 04:58:47 +0000555 return self._attrsNS[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000556 else:
Paul Prescod73678da2000-07-01 04:58:47 +0000557 return self._attrs[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000558
Paul Prescod1e688272000-07-01 19:21:47 +0000559 # same as set
Fred Drake1f549022000-09-24 05:21:58 +0000560 def __setitem__(self, attname, value):
Christian Heimesc9543e42007-11-28 08:28:28 +0000561 if isinstance(value, str):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000562 try:
563 node = self._attrs[attname]
564 except KeyError:
565 node = Attr(attname)
566 node.ownerDocument = self._ownerElement.ownerDocument
Martin v. Löwis995359c2003-01-26 08:59:32 +0000567 self.setNamedItem(node)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000568 node.value = value
Paul Prescod1e688272000-07-01 19:21:47 +0000569 else:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000570 if not isinstance(value, Attr):
Collin Winter70e79802007-08-24 18:57:22 +0000571 raise TypeError("value must be a string or Attr object")
Fred Drake1f549022000-09-24 05:21:58 +0000572 node = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000573 self.setNamedItem(node)
574
575 def getNamedItem(self, name):
576 try:
577 return self._attrs[name]
578 except KeyError:
579 return None
580
581 def getNamedItemNS(self, namespaceURI, localName):
582 try:
583 return self._attrsNS[(namespaceURI, localName)]
584 except KeyError:
585 return None
586
587 def removeNamedItem(self, name):
588 n = self.getNamedItem(name)
589 if n is not None:
590 _clear_id_cache(self._ownerElement)
591 del self._attrs[n.nodeName]
592 del self._attrsNS[(n.namespaceURI, n.localName)]
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100593 if hasattr(n, 'ownerElement'):
594 n.ownerElement = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000595 return n
596 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000597 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000598
599 def removeNamedItemNS(self, namespaceURI, localName):
600 n = self.getNamedItemNS(namespaceURI, localName)
601 if n is not None:
602 _clear_id_cache(self._ownerElement)
603 del self._attrsNS[(n.namespaceURI, n.localName)]
604 del self._attrs[n.nodeName]
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100605 if hasattr(n, 'ownerElement'):
606 n.ownerElement = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000607 return n
608 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000609 raise xml.dom.NotFoundErr()
Fred Drakef7cf40d2000-12-14 18:16:11 +0000610
611 def setNamedItem(self, node):
Andrew M. Kuchlingbc8f72c2001-02-21 01:30:26 +0000612 if not isinstance(node, Attr):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000613 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000614 "%s cannot be child of %s" % (repr(node), repr(self)))
Fred Drakef7cf40d2000-12-14 18:16:11 +0000615 old = self._attrs.get(node.name)
Paul Prescod1e688272000-07-01 19:21:47 +0000616 if old:
617 old.unlink()
Fred Drake1f549022000-09-24 05:21:58 +0000618 self._attrs[node.name] = node
619 self._attrsNS[(node.namespaceURI, node.localName)] = node
Fred Drake2998a552001-12-06 18:27:48 +0000620 node.ownerElement = self._ownerElement
Martin v. Löwis787354c2003-01-25 15:28:29 +0000621 _clear_id_cache(node.ownerElement)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000622 return old
623
624 def setNamedItemNS(self, node):
625 return self.setNamedItem(node)
Paul Prescod73678da2000-07-01 04:58:47 +0000626
Fred Drake1f549022000-09-24 05:21:58 +0000627 def __delitem__(self, attname_or_tuple):
628 node = self[attname_or_tuple]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000629 _clear_id_cache(node.ownerElement)
Paul Prescod73678da2000-07-01 04:58:47 +0000630 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000631
632 def __getstate__(self):
633 return self._attrs, self._attrsNS, self._ownerElement
634
635 def __setstate__(self, state):
636 self._attrs, self._attrsNS, self._ownerElement = state
637
638defproperty(NamedNodeMap, "length",
639 doc="Number of nodes in the NamedNodeMap.")
Fred Drakef7cf40d2000-12-14 18:16:11 +0000640
641AttributeList = NamedNodeMap
642
Fred Drake1f549022000-09-24 05:21:58 +0000643
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000644class TypeInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000645 __slots__ = 'namespace', 'name'
646
647 def __init__(self, namespace, name):
648 self.namespace = namespace
649 self.name = name
650
651 def __repr__(self):
652 if self.namespace:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000653 return "<TypeInfo %r (from %r)>" % (self.name, self.namespace)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000654 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000655 return "<TypeInfo %r>" % self.name
Martin v. Löwis787354c2003-01-25 15:28:29 +0000656
657 def _get_name(self):
658 return self.name
659
660 def _get_namespace(self):
661 return self.namespace
662
663_no_type = TypeInfo(None, None)
664
Martin v. Löwisa2fda0d2000-10-07 12:10:28 +0000665class Element(Node):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100666 __slots__=('ownerDocument', 'parentNode', 'tagName', 'nodeName', 'prefix',
667 'namespaceURI', '_localName', 'childNodes', '_attrs', '_attrsNS',
668 'nextSibling', 'previousSibling')
Fred Drake1f549022000-09-24 05:21:58 +0000669 nodeType = Node.ELEMENT_NODE
Martin v. Löwis787354c2003-01-25 15:28:29 +0000670 nodeValue = None
671 schemaType = _no_type
672
673 _magic_id_nodes = 0
674
675 _child_node_types = (Node.ELEMENT_NODE,
676 Node.PROCESSING_INSTRUCTION_NODE,
677 Node.COMMENT_NODE,
678 Node.TEXT_NODE,
679 Node.CDATA_SECTION_NODE,
680 Node.ENTITY_REFERENCE_NODE)
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000681
Fred Drake49a5d032001-11-30 22:21:58 +0000682 def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None,
Fred Drake1f549022000-09-24 05:21:58 +0000683 localName=None):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100684 self.parentNode = None
Fred Drake55c38192000-06-29 19:39:57 +0000685 self.tagName = self.nodeName = tagName
Fred Drake1f549022000-09-24 05:21:58 +0000686 self.prefix = prefix
687 self.namespaceURI = namespaceURI
Martin v. Löwis787354c2003-01-25 15:28:29 +0000688 self.childNodes = NodeList()
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100689 self.nextSibling = self.previousSibling = None
Fred Drake55c38192000-06-29 19:39:57 +0000690
Martin v. Löwis7b771882012-02-19 20:55:05 +0100691 # Attribute dictionaries are lazily created
692 # attributes are double-indexed:
693 # tagName -> Attribute
694 # URI,localName -> Attribute
695 # in the future: consider lazy generation
696 # of attribute objects this is too tricky
697 # for now because of headaches with
698 # namespaces.
699 self._attrs = None
700 self._attrsNS = None
701
702 def _ensure_attributes(self):
703 if self._attrs is None:
704 self._attrs = {}
705 self._attrsNS = {}
Fred Drake4ccf4a12000-11-21 22:02:22 +0000706
Martin v. Löwis787354c2003-01-25 15:28:29 +0000707 def _get_localName(self):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100708 try:
709 return self._localName
710 except AttributeError:
711 return self.tagName.split(":", 1)[-1]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000712
713 def _get_tagName(self):
714 return self.tagName
Fred Drake4ccf4a12000-11-21 22:02:22 +0000715
716 def unlink(self):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100717 if self._attrs is not None:
718 for attr in list(self._attrs.values()):
719 attr.unlink()
Fred Drake4ccf4a12000-11-21 22:02:22 +0000720 self._attrs = None
721 self._attrsNS = None
722 Node.unlink(self)
Fred Drake55c38192000-06-29 19:39:57 +0000723
Fred Drake1f549022000-09-24 05:21:58 +0000724 def getAttribute(self, attname):
Martin v. Löwis67245a62012-03-05 07:01:49 +0100725 if self._attrs is None:
726 return ""
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000727 try:
728 return self._attrs[attname].value
729 except KeyError:
730 return ""
Fred Drake55c38192000-06-29 19:39:57 +0000731
Fred Drake1f549022000-09-24 05:21:58 +0000732 def getAttributeNS(self, namespaceURI, localName):
Martin v. Löwis67245a62012-03-05 07:01:49 +0100733 if self._attrsNS is None:
734 return ""
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000735 try:
736 return self._attrsNS[(namespaceURI, localName)].value
737 except KeyError:
738 return ""
Fred Drake1f549022000-09-24 05:21:58 +0000739
740 def setAttribute(self, attname, value):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000741 attr = self.getAttributeNode(attname)
742 if attr is None:
743 attr = Attr(attname)
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100744 attr.value = value # also sets nodeValue
745 attr.ownerDocument = self.ownerDocument
Martin v. Löwis787354c2003-01-25 15:28:29 +0000746 self.setAttributeNode(attr)
747 elif value != attr.value:
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100748 attr.value = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000749 if attr.isId:
750 _clear_id_cache(self)
Fred Drake55c38192000-06-29 19:39:57 +0000751
Fred Drake1f549022000-09-24 05:21:58 +0000752 def setAttributeNS(self, namespaceURI, qualifiedName, value):
753 prefix, localname = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000754 attr = self.getAttributeNodeNS(namespaceURI, localname)
755 if attr is None:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000756 attr = Attr(qualifiedName, namespaceURI, localname, prefix)
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100757 attr.value = value
758 attr.ownerDocument = self.ownerDocument
Martin v. Löwis787354c2003-01-25 15:28:29 +0000759 self.setAttributeNode(attr)
760 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000761 if value != attr.value:
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100762 attr.value = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000763 if attr.isId:
764 _clear_id_cache(self)
765 if attr.prefix != prefix:
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100766 attr.prefix = prefix
767 attr.nodeName = qualifiedName
Fred Drake55c38192000-06-29 19:39:57 +0000768
Fred Drake1f549022000-09-24 05:21:58 +0000769 def getAttributeNode(self, attrname):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100770 if self._attrs is None:
771 return None
Fred Drake1f549022000-09-24 05:21:58 +0000772 return self._attrs.get(attrname)
Paul Prescod73678da2000-07-01 04:58:47 +0000773
Fred Drake1f549022000-09-24 05:21:58 +0000774 def getAttributeNodeNS(self, namespaceURI, localName):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100775 if self._attrsNS is None:
776 return None
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000777 return self._attrsNS.get((namespaceURI, localName))
Paul Prescod73678da2000-07-01 04:58:47 +0000778
Fred Drake1f549022000-09-24 05:21:58 +0000779 def setAttributeNode(self, attr):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000780 if attr.ownerElement not in (None, self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000781 raise xml.dom.InuseAttributeErr("attribute node already owned")
Martin v. Löwis7b771882012-02-19 20:55:05 +0100782 self._ensure_attributes()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000783 old1 = self._attrs.get(attr.name, None)
784 if old1 is not None:
785 self.removeAttributeNode(old1)
786 old2 = self._attrsNS.get((attr.namespaceURI, attr.localName), None)
787 if old2 is not None and old2 is not old1:
788 self.removeAttributeNode(old2)
789 _set_attribute_node(self, attr)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000790
Martin v. Löwis787354c2003-01-25 15:28:29 +0000791 if old1 is not attr:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000792 # It might have already been part of this node, in which case
793 # it doesn't represent a change, and should not be returned.
Martin v. Löwis787354c2003-01-25 15:28:29 +0000794 return old1
795 if old2 is not attr:
796 return old2
Fred Drake55c38192000-06-29 19:39:57 +0000797
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000798 setAttributeNodeNS = setAttributeNode
799
Fred Drake1f549022000-09-24 05:21:58 +0000800 def removeAttribute(self, name):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100801 if self._attrsNS is None:
802 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000803 try:
804 attr = self._attrs[name]
805 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000806 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000807 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000808
Fred Drake1f549022000-09-24 05:21:58 +0000809 def removeAttributeNS(self, namespaceURI, localName):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100810 if self._attrsNS is None:
811 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000812 try:
813 attr = self._attrsNS[(namespaceURI, localName)]
814 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000815 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000816 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000817
Fred Drake1f549022000-09-24 05:21:58 +0000818 def removeAttributeNode(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000819 if node is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000820 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000821 try:
822 self._attrs[node.name]
823 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000824 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000825 _clear_id_cache(self)
Paul Prescod73678da2000-07-01 04:58:47 +0000826 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000827 # Restore this since the node is still useful and otherwise
828 # unlinked
829 node.ownerDocument = self.ownerDocument
Fred Drake16f63292000-10-23 18:09:50 +0000830
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000831 removeAttributeNodeNS = removeAttributeNode
832
Martin v. Löwis156c3372000-12-28 18:40:56 +0000833 def hasAttribute(self, name):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100834 if self._attrs is None:
835 return False
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000836 return name in self._attrs
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000837
Martin v. Löwis156c3372000-12-28 18:40:56 +0000838 def hasAttributeNS(self, namespaceURI, localName):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100839 if self._attrsNS is None:
840 return False
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000841 return (namespaceURI, localName) in self._attrsNS
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000842
Fred Drake1f549022000-09-24 05:21:58 +0000843 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000844 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000845
Fred Drake1f549022000-09-24 05:21:58 +0000846 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000847 return _get_elements_by_tagName_ns_helper(
848 self, namespaceURI, localName, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000849
Fred Drake1f549022000-09-24 05:21:58 +0000850 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000851 return "<DOM Element: %s at %#x>" % (self.tagName, id(self))
Fred Drake55c38192000-06-29 19:39:57 +0000852
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000853 def writexml(self, writer, indent="", addindent="", newl=""):
854 # indent = current indentation
855 # addindent = indentation to add to higher levels
856 # newl = newline string
857 writer.write(indent+"<" + self.tagName)
Fred Drake16f63292000-10-23 18:09:50 +0000858
Fred Drake4ccf4a12000-11-21 22:02:22 +0000859 attrs = self._get_attributes()
Brett Cannon861fd6f2007-02-21 22:05:37 +0000860 a_names = sorted(attrs.keys())
Fred Drake55c38192000-06-29 19:39:57 +0000861
862 for a_name in a_names:
Fred Drake1f549022000-09-24 05:21:58 +0000863 writer.write(" %s=\"" % a_name)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000864 _write_data(writer, attrs[a_name].value)
Fred Drake55c38192000-06-29 19:39:57 +0000865 writer.write("\"")
866 if self.childNodes:
R David Murray791744b2011-10-01 16:19:51 -0400867 writer.write(">")
Ezio Melotti8008f2a2011-11-18 17:34:26 +0200868 if (len(self.childNodes) == 1 and
869 self.childNodes[0].nodeType == Node.TEXT_NODE):
870 self.childNodes[0].writexml(writer, '', '', '')
871 else:
R David Murray791744b2011-10-01 16:19:51 -0400872 writer.write(newl)
Ezio Melotti8008f2a2011-11-18 17:34:26 +0200873 for node in self.childNodes:
874 node.writexml(writer, indent+addindent, addindent, newl)
875 writer.write(indent)
876 writer.write("</%s>%s" % (self.tagName, newl))
Fred Drake55c38192000-06-29 19:39:57 +0000877 else:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000878 writer.write("/>%s"%(newl))
Fred Drake55c38192000-06-29 19:39:57 +0000879
Fred Drake1f549022000-09-24 05:21:58 +0000880 def _get_attributes(self):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100881 self._ensure_attributes()
Fred Drake2998a552001-12-06 18:27:48 +0000882 return NamedNodeMap(self._attrs, self._attrsNS, self)
Fred Drake55c38192000-06-29 19:39:57 +0000883
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000884 def hasAttributes(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000885 if self._attrs:
886 return True
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000887 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000888 return False
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000889
Martin v. Löwis787354c2003-01-25 15:28:29 +0000890 # DOM Level 3 attributes, based on the 22 Oct 2002 draft
891
892 def setIdAttribute(self, name):
893 idAttr = self.getAttributeNode(name)
894 self.setIdAttributeNode(idAttr)
895
896 def setIdAttributeNS(self, namespaceURI, localName):
897 idAttr = self.getAttributeNodeNS(namespaceURI, localName)
898 self.setIdAttributeNode(idAttr)
899
900 def setIdAttributeNode(self, idAttr):
901 if idAttr is None or not self.isSameNode(idAttr.ownerElement):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000902 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000903 if _get_containing_entref(self) is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000904 raise xml.dom.NoModificationAllowedErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000905 if not idAttr._is_id:
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100906 idAttr._is_id = True
Martin v. Löwis787354c2003-01-25 15:28:29 +0000907 self._magic_id_nodes += 1
908 self.ownerDocument._magic_id_count += 1
909 _clear_id_cache(self)
910
911defproperty(Element, "attributes",
912 doc="NamedNodeMap of attributes on the element.")
913defproperty(Element, "localName",
914 doc="Namespace-local name of this element.")
915
916
917def _set_attribute_node(element, attr):
918 _clear_id_cache(element)
Martin v. Löwis7b771882012-02-19 20:55:05 +0100919 element._ensure_attributes()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000920 element._attrs[attr.name] = attr
921 element._attrsNS[(attr.namespaceURI, attr.localName)] = attr
922
923 # This creates a circular reference, but Element.unlink()
924 # breaks the cycle since the references to the attribute
925 # dictionaries are tossed.
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100926 attr.ownerElement = element
Martin v. Löwis787354c2003-01-25 15:28:29 +0000927
928class Childless:
929 """Mixin that makes childless-ness easy to implement and avoids
930 the complexity of the Node methods that deal with children.
931 """
Florent Xicluna8cf4b512012-03-05 12:37:02 +0100932 __slots__ = ()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000933
Fred Drake4ccf4a12000-11-21 22:02:22 +0000934 attributes = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000935 childNodes = EmptyNodeList()
936 firstChild = None
937 lastChild = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000938
Martin v. Löwis787354c2003-01-25 15:28:29 +0000939 def _get_firstChild(self):
940 return None
Fred Drake55c38192000-06-29 19:39:57 +0000941
Martin v. Löwis787354c2003-01-25 15:28:29 +0000942 def _get_lastChild(self):
943 return None
Fred Drake1f549022000-09-24 05:21:58 +0000944
Martin v. Löwis787354c2003-01-25 15:28:29 +0000945 def appendChild(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000946 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000947 self.nodeName + " nodes cannot have children")
948
949 def hasChildNodes(self):
950 return False
951
952 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000953 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000954 self.nodeName + " nodes do not have children")
955
956 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000957 raise xml.dom.NotFoundErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000958 self.nodeName + " nodes do not have children")
959
Andrew M. Kuchling688b9e32010-07-25 23:38:47 +0000960 def normalize(self):
961 # For childless nodes, normalize() has nothing to do.
962 pass
963
Martin v. Löwis787354c2003-01-25 15:28:29 +0000964 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000965 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000966 self.nodeName + " nodes do not have children")
967
968
969class ProcessingInstruction(Childless, Node):
Fred Drake1f549022000-09-24 05:21:58 +0000970 nodeType = Node.PROCESSING_INSTRUCTION_NODE
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100971 __slots__ = ('target', 'data')
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000972
Fred Drake1f549022000-09-24 05:21:58 +0000973 def __init__(self, target, data):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100974 self.target = target
975 self.data = data
Fred Drake55c38192000-06-29 19:39:57 +0000976
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100977 # nodeValue is an alias for data
978 def _get_nodeValue(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000979 return self.data
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100980 def _set_nodeValue(self, value):
981 self.data = data
982 nodeValue = property(_get_nodeValue, _set_nodeValue)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000983
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100984 # nodeName is an alias for target
985 def _get_nodeName(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000986 return self.target
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100987 def _set_nodeName(self, value):
988 self.target = value
989 nodeName = property(_get_nodeName, _set_nodeName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000990
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000991 def writexml(self, writer, indent="", addindent="", newl=""):
992 writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))
Fred Drake55c38192000-06-29 19:39:57 +0000993
Martin v. Löwis787354c2003-01-25 15:28:29 +0000994
995class CharacterData(Childless, Node):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100996 __slots__=('_data', 'ownerDocument','parentNode', 'previousSibling', 'nextSibling')
997
998 def __init__(self):
999 self.ownerDocument = self.parentNode = None
1000 self.previousSibling = self.nextSibling = None
1001 self._data = ''
1002 Node.__init__(self)
1003
Martin v. Löwis787354c2003-01-25 15:28:29 +00001004 def _get_length(self):
1005 return len(self.data)
1006 __len__ = _get_length
1007
1008 def _get_data(self):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001009 return self._data
Martin v. Löwis787354c2003-01-25 15:28:29 +00001010 def _set_data(self, data):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001011 self._data = data
Martin v. Löwis787354c2003-01-25 15:28:29 +00001012
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001013 data = nodeValue = property(_get_data, _set_data)
Fred Drake87432f42001-04-04 14:09:46 +00001014
Fred Drake55c38192000-06-29 19:39:57 +00001015 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001016 data = self.data
1017 if len(data) > 10:
Fred Drake1f549022000-09-24 05:21:58 +00001018 dotdotdot = "..."
Fred Drake55c38192000-06-29 19:39:57 +00001019 else:
Fred Drake1f549022000-09-24 05:21:58 +00001020 dotdotdot = ""
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001021 return '<DOM %s node "%r%s">' % (
Martin v. Löwis787354c2003-01-25 15:28:29 +00001022 self.__class__.__name__, data[0:10], dotdotdot)
Fred Drake87432f42001-04-04 14:09:46 +00001023
1024 def substringData(self, offset, count):
1025 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001026 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001027 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001028 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001029 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001030 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001031 return self.data[offset:offset+count]
1032
1033 def appendData(self, arg):
1034 self.data = self.data + arg
Fred Drake87432f42001-04-04 14:09:46 +00001035
1036 def insertData(self, offset, arg):
1037 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001038 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001039 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001040 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001041 if arg:
1042 self.data = "%s%s%s" % (
1043 self.data[:offset], arg, self.data[offset:])
Fred Drake87432f42001-04-04 14:09:46 +00001044
1045 def deleteData(self, offset, count):
1046 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001047 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001048 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001049 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001050 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001051 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001052 if count:
1053 self.data = self.data[:offset] + self.data[offset+count:]
Fred Drake87432f42001-04-04 14:09:46 +00001054
1055 def replaceData(self, offset, count, arg):
1056 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001057 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001058 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001059 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001060 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001061 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001062 if count:
1063 self.data = "%s%s%s" % (
1064 self.data[:offset], arg, self.data[offset+count:])
Martin v. Löwis787354c2003-01-25 15:28:29 +00001065
1066defproperty(CharacterData, "length", doc="Length of the string data.")
1067
Fred Drake87432f42001-04-04 14:09:46 +00001068
1069class Text(CharacterData):
Florent Xicluna8cf4b512012-03-05 12:37:02 +01001070 __slots__ = ()
1071
Fred Drake87432f42001-04-04 14:09:46 +00001072 nodeType = Node.TEXT_NODE
1073 nodeName = "#text"
1074 attributes = None
Fred Drake55c38192000-06-29 19:39:57 +00001075
Fred Drakef7cf40d2000-12-14 18:16:11 +00001076 def splitText(self, offset):
1077 if offset < 0 or offset > len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001078 raise xml.dom.IndexSizeErr("illegal offset value")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001079 newText = self.__class__()
1080 newText.data = self.data[offset:]
1081 newText.ownerDocument = self.ownerDocument
Fred Drakef7cf40d2000-12-14 18:16:11 +00001082 next = self.nextSibling
1083 if self.parentNode and self in self.parentNode.childNodes:
1084 if next is None:
1085 self.parentNode.appendChild(newText)
1086 else:
1087 self.parentNode.insertBefore(newText, next)
1088 self.data = self.data[:offset]
1089 return newText
1090
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001091 def writexml(self, writer, indent="", addindent="", newl=""):
Ezio Melotti8008f2a2011-11-18 17:34:26 +02001092 _write_data(writer, "%s%s%s" % (indent, self.data, newl))
Fred Drake55c38192000-06-29 19:39:57 +00001093
Martin v. Löwis787354c2003-01-25 15:28:29 +00001094 # DOM Level 3 (WD 9 April 2002)
1095
1096 def _get_wholeText(self):
1097 L = [self.data]
1098 n = self.previousSibling
1099 while n is not None:
1100 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1101 L.insert(0, n.data)
1102 n = n.previousSibling
1103 else:
1104 break
1105 n = self.nextSibling
1106 while n is not None:
1107 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1108 L.append(n.data)
1109 n = n.nextSibling
1110 else:
1111 break
1112 return ''.join(L)
1113
1114 def replaceWholeText(self, content):
1115 # XXX This needs to be seriously changed if minidom ever
1116 # supports EntityReference nodes.
1117 parent = self.parentNode
1118 n = self.previousSibling
1119 while n is not None:
1120 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1121 next = n.previousSibling
1122 parent.removeChild(n)
1123 n = next
1124 else:
1125 break
1126 n = self.nextSibling
1127 if not content:
1128 parent.removeChild(self)
1129 while n is not None:
1130 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1131 next = n.nextSibling
1132 parent.removeChild(n)
1133 n = next
1134 else:
1135 break
1136 if content:
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001137 self.data = content
Martin v. Löwis787354c2003-01-25 15:28:29 +00001138 return self
1139 else:
1140 return None
1141
1142 def _get_isWhitespaceInElementContent(self):
1143 if self.data.strip():
1144 return False
1145 elem = _get_containing_element(self)
1146 if elem is None:
1147 return False
1148 info = self.ownerDocument._get_elem_info(elem)
1149 if info is None:
1150 return False
1151 else:
1152 return info.isElementContent()
1153
1154defproperty(Text, "isWhitespaceInElementContent",
1155 doc="True iff this text node contains only whitespace"
1156 " and is in element content.")
1157defproperty(Text, "wholeText",
1158 doc="The text of all logically-adjacent text nodes.")
1159
1160
1161def _get_containing_element(node):
1162 c = node.parentNode
1163 while c is not None:
1164 if c.nodeType == Node.ELEMENT_NODE:
1165 return c
1166 c = c.parentNode
1167 return None
1168
1169def _get_containing_entref(node):
1170 c = node.parentNode
1171 while c is not None:
1172 if c.nodeType == Node.ENTITY_REFERENCE_NODE:
1173 return c
1174 c = c.parentNode
1175 return None
1176
1177
Alex Martelli0ee43512006-08-21 19:53:20 +00001178class Comment(CharacterData):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001179 nodeType = Node.COMMENT_NODE
1180 nodeName = "#comment"
1181
1182 def __init__(self, data):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001183 CharacterData.__init__(self)
1184 self._data = data
Martin v. Löwis787354c2003-01-25 15:28:29 +00001185
1186 def writexml(self, writer, indent="", addindent="", newl=""):
Benjamin Peterson2b7411d2008-05-26 17:36:47 +00001187 if "--" in self.data:
1188 raise ValueError("'--' is not allowed in a comment node")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001189 writer.write("%s<!--%s-->%s" % (indent, self.data, newl))
1190
Fred Drake87432f42001-04-04 14:09:46 +00001191
1192class CDATASection(Text):
Florent Xicluna8cf4b512012-03-05 12:37:02 +01001193 __slots__ = ()
1194
Fred Drake87432f42001-04-04 14:09:46 +00001195 nodeType = Node.CDATA_SECTION_NODE
1196 nodeName = "#cdata-section"
1197
1198 def writexml(self, writer, indent="", addindent="", newl=""):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001199 if self.data.find("]]>") >= 0:
1200 raise ValueError("']]>' not allowed in a CDATA section")
Guido van Rossum5b5e0b92001-09-19 13:28:25 +00001201 writer.write("<![CDATA[%s]]>" % self.data)
Fred Drake87432f42001-04-04 14:09:46 +00001202
1203
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001204class ReadOnlySequentialNamedNodeMap(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001205 __slots__ = '_seq',
1206
1207 def __init__(self, seq=()):
1208 # seq should be a list or tuple
1209 self._seq = seq
1210
1211 def __len__(self):
1212 return len(self._seq)
1213
1214 def _get_length(self):
1215 return len(self._seq)
1216
1217 def getNamedItem(self, name):
1218 for n in self._seq:
1219 if n.nodeName == name:
1220 return n
1221
1222 def getNamedItemNS(self, namespaceURI, localName):
1223 for n in self._seq:
1224 if n.namespaceURI == namespaceURI and n.localName == localName:
1225 return n
1226
1227 def __getitem__(self, name_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001228 if isinstance(name_or_tuple, tuple):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001229 node = self.getNamedItemNS(*name_or_tuple)
1230 else:
1231 node = self.getNamedItem(name_or_tuple)
1232 if node is None:
Collin Winter70e79802007-08-24 18:57:22 +00001233 raise KeyError(name_or_tuple)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001234 return node
1235
1236 def item(self, index):
1237 if index < 0:
1238 return None
1239 try:
1240 return self._seq[index]
1241 except IndexError:
1242 return None
1243
1244 def removeNamedItem(self, name):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001245 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001246 "NamedNodeMap instance is read-only")
1247
1248 def removeNamedItemNS(self, namespaceURI, localName):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001249 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001250 "NamedNodeMap instance is read-only")
1251
1252 def setNamedItem(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001253 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001254 "NamedNodeMap instance is read-only")
1255
1256 def setNamedItemNS(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001257 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001258 "NamedNodeMap instance is read-only")
1259
1260 def __getstate__(self):
1261 return [self._seq]
1262
1263 def __setstate__(self, state):
1264 self._seq = state[0]
1265
1266defproperty(ReadOnlySequentialNamedNodeMap, "length",
1267 doc="Number of entries in the NamedNodeMap.")
Paul Prescod73678da2000-07-01 04:58:47 +00001268
Fred Drakef7cf40d2000-12-14 18:16:11 +00001269
Martin v. Löwis787354c2003-01-25 15:28:29 +00001270class Identified:
1271 """Mix-in class that supports the publicId and systemId attributes."""
1272
Florent Xicluna8cf4b512012-03-05 12:37:02 +01001273 __slots__ = 'publicId', 'systemId'
Martin v. Löwis787354c2003-01-25 15:28:29 +00001274
1275 def _identified_mixin_init(self, publicId, systemId):
1276 self.publicId = publicId
1277 self.systemId = systemId
1278
1279 def _get_publicId(self):
1280 return self.publicId
1281
1282 def _get_systemId(self):
1283 return self.systemId
1284
1285class DocumentType(Identified, Childless, Node):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001286 nodeType = Node.DOCUMENT_TYPE_NODE
1287 nodeValue = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001288 name = None
1289 publicId = None
1290 systemId = None
Fred Drakedc806702001-04-05 14:41:30 +00001291 internalSubset = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001292
1293 def __init__(self, qualifiedName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001294 self.entities = ReadOnlySequentialNamedNodeMap()
1295 self.notations = ReadOnlySequentialNamedNodeMap()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001296 if qualifiedName:
1297 prefix, localname = _nssplit(qualifiedName)
1298 self.name = localname
Martin v. Löwis787354c2003-01-25 15:28:29 +00001299 self.nodeName = self.name
1300
1301 def _get_internalSubset(self):
1302 return self.internalSubset
1303
1304 def cloneNode(self, deep):
1305 if self.ownerDocument is None:
1306 # it's ok
1307 clone = DocumentType(None)
1308 clone.name = self.name
1309 clone.nodeName = self.name
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001310 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001311 if deep:
1312 clone.entities._seq = []
1313 clone.notations._seq = []
1314 for n in self.notations._seq:
1315 notation = Notation(n.nodeName, n.publicId, n.systemId)
1316 clone.notations._seq.append(notation)
1317 n._call_user_data_handler(operation, n, notation)
1318 for e in self.entities._seq:
1319 entity = Entity(e.nodeName, e.publicId, e.systemId,
1320 e.notationName)
1321 entity.actualEncoding = e.actualEncoding
1322 entity.encoding = e.encoding
1323 entity.version = e.version
1324 clone.entities._seq.append(entity)
1325 e._call_user_data_handler(operation, n, entity)
1326 self._call_user_data_handler(operation, self, clone)
1327 return clone
1328 else:
1329 return None
1330
1331 def writexml(self, writer, indent="", addindent="", newl=""):
1332 writer.write("<!DOCTYPE ")
1333 writer.write(self.name)
1334 if self.publicId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001335 writer.write("%s PUBLIC '%s'%s '%s'"
1336 % (newl, self.publicId, newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001337 elif self.systemId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001338 writer.write("%s SYSTEM '%s'" % (newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001339 if self.internalSubset is not None:
1340 writer.write(" [")
1341 writer.write(self.internalSubset)
1342 writer.write("]")
Georg Brandl175a7dc2005-08-25 22:02:43 +00001343 writer.write(">"+newl)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001344
1345class Entity(Identified, Node):
1346 attributes = None
1347 nodeType = Node.ENTITY_NODE
1348 nodeValue = None
1349
1350 actualEncoding = None
1351 encoding = None
1352 version = None
1353
1354 def __init__(self, name, publicId, systemId, notation):
1355 self.nodeName = name
1356 self.notationName = notation
1357 self.childNodes = NodeList()
1358 self._identified_mixin_init(publicId, systemId)
1359
1360 def _get_actualEncoding(self):
1361 return self.actualEncoding
1362
1363 def _get_encoding(self):
1364 return self.encoding
1365
1366 def _get_version(self):
1367 return self.version
1368
1369 def appendChild(self, newChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001370 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001371 "cannot append children to an entity node")
1372
1373 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001374 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001375 "cannot insert children below an entity node")
1376
1377 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001378 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001379 "cannot remove children from an entity node")
1380
1381 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001382 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001383 "cannot replace children of an entity node")
1384
1385class Notation(Identified, Childless, Node):
1386 nodeType = Node.NOTATION_NODE
1387 nodeValue = None
1388
1389 def __init__(self, name, publicId, systemId):
1390 self.nodeName = name
1391 self._identified_mixin_init(publicId, systemId)
Fred Drakef7cf40d2000-12-14 18:16:11 +00001392
1393
Martin v. Löwis787354c2003-01-25 15:28:29 +00001394class DOMImplementation(DOMImplementationLS):
1395 _features = [("core", "1.0"),
1396 ("core", "2.0"),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001397 ("core", None),
1398 ("xml", "1.0"),
1399 ("xml", "2.0"),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001400 ("xml", None),
1401 ("ls-load", "3.0"),
1402 ("ls-load", None),
1403 ]
1404
Fred Drakef7cf40d2000-12-14 18:16:11 +00001405 def hasFeature(self, feature, version):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001406 if version == "":
1407 version = None
1408 return (feature.lower(), version) in self._features
Fred Drakef7cf40d2000-12-14 18:16:11 +00001409
1410 def createDocument(self, namespaceURI, qualifiedName, doctype):
1411 if doctype and doctype.parentNode is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001412 raise xml.dom.WrongDocumentErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001413 "doctype object owned by another DOM tree")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001414 doc = self._create_document()
1415
1416 add_root_element = not (namespaceURI is None
1417 and qualifiedName is None
1418 and doctype is None)
1419
1420 if not qualifiedName and add_root_element:
Martin v. Löwisb417be22001-02-06 01:16:06 +00001421 # The spec is unclear what to raise here; SyntaxErr
1422 # would be the other obvious candidate. Since Xerces raises
1423 # InvalidCharacterErr, and since SyntaxErr is not listed
1424 # for createDocument, that seems to be the better choice.
1425 # XXX: need to check for illegal characters here and in
1426 # createElement.
Martin v. Löwis787354c2003-01-25 15:28:29 +00001427
1428 # DOM Level III clears this up when talking about the return value
1429 # of this function. If namespaceURI, qName and DocType are
1430 # Null the document is returned without a document element
1431 # Otherwise if doctype or namespaceURI are not None
1432 # Then we go back to the above problem
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001433 raise xml.dom.InvalidCharacterErr("Element with no name")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001434
1435 if add_root_element:
1436 prefix, localname = _nssplit(qualifiedName)
1437 if prefix == "xml" \
1438 and namespaceURI != "http://www.w3.org/XML/1998/namespace":
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001439 raise xml.dom.NamespaceErr("illegal use of 'xml' prefix")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001440 if prefix and not namespaceURI:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001441 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001442 "illegal use of prefix without namespaces")
1443 element = doc.createElementNS(namespaceURI, qualifiedName)
1444 if doctype:
1445 doc.appendChild(doctype)
1446 doc.appendChild(element)
1447
1448 if doctype:
1449 doctype.parentNode = doctype.ownerDocument = doc
1450
Fred Drakef7cf40d2000-12-14 18:16:11 +00001451 doc.doctype = doctype
1452 doc.implementation = self
1453 return doc
1454
1455 def createDocumentType(self, qualifiedName, publicId, systemId):
1456 doctype = DocumentType(qualifiedName)
1457 doctype.publicId = publicId
1458 doctype.systemId = systemId
1459 return doctype
1460
Martin v. Löwis787354c2003-01-25 15:28:29 +00001461 # DOM Level 3 (WD 9 April 2002)
1462
1463 def getInterface(self, feature):
1464 if self.hasFeature(feature, None):
1465 return self
1466 else:
1467 return None
1468
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001469 # internal
Martin v. Löwis787354c2003-01-25 15:28:29 +00001470 def _create_document(self):
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001471 return Document()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001472
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001473class ElementInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001474 """Object that represents content-model information for an element.
1475
1476 This implementation is not expected to be used in practice; DOM
1477 builders should provide implementations which do the right thing
1478 using information available to it.
1479
1480 """
1481
1482 __slots__ = 'tagName',
1483
1484 def __init__(self, name):
1485 self.tagName = name
1486
1487 def getAttributeType(self, aname):
1488 return _no_type
1489
1490 def getAttributeTypeNS(self, namespaceURI, localName):
1491 return _no_type
1492
1493 def isElementContent(self):
1494 return False
1495
1496 def isEmpty(self):
1497 """Returns true iff this element is declared to have an EMPTY
1498 content model."""
1499 return False
1500
1501 def isId(self, aname):
Ezio Melotti42da6632011-03-15 05:18:48 +02001502 """Returns true iff the named attribute is a DTD-style ID."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001503 return False
1504
1505 def isIdNS(self, namespaceURI, localName):
1506 """Returns true iff the identified attribute is a DTD-style ID."""
1507 return False
1508
1509 def __getstate__(self):
1510 return self.tagName
1511
1512 def __setstate__(self, state):
1513 self.tagName = state
1514
1515def _clear_id_cache(node):
1516 if node.nodeType == Node.DOCUMENT_NODE:
1517 node._id_cache.clear()
1518 node._id_search_stack = None
1519 elif _in_document(node):
1520 node.ownerDocument._id_cache.clear()
1521 node.ownerDocument._id_search_stack= None
1522
1523class Document(Node, DocumentLS):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001524 __slots__ = ('_elem_info', 'doctype',
1525 '_id_search_stack', 'childNodes', '_id_cache')
Martin v. Löwis787354c2003-01-25 15:28:29 +00001526 _child_node_types = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
1527 Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)
1528
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001529 implementation = DOMImplementation()
Fred Drake1f549022000-09-24 05:21:58 +00001530 nodeType = Node.DOCUMENT_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +00001531 nodeName = "#document"
1532 nodeValue = None
1533 attributes = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001534 parentNode = None
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001535 previousSibling = nextSibling = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001536
Martin v. Löwis787354c2003-01-25 15:28:29 +00001537
1538 # Document attributes from Level 3 (WD 9 April 2002)
1539
1540 actualEncoding = None
1541 encoding = None
1542 standalone = None
1543 version = None
1544 strictErrorChecking = False
1545 errorHandler = None
1546 documentURI = None
1547
1548 _magic_id_count = 0
1549
1550 def __init__(self):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001551 self.doctype = None
Martin v. Löwis787354c2003-01-25 15:28:29 +00001552 self.childNodes = NodeList()
1553 # mapping of (namespaceURI, localName) -> ElementInfo
1554 # and tagName -> ElementInfo
1555 self._elem_info = {}
1556 self._id_cache = {}
1557 self._id_search_stack = None
1558
1559 def _get_elem_info(self, element):
1560 if element.namespaceURI:
1561 key = element.namespaceURI, element.localName
1562 else:
1563 key = element.tagName
1564 return self._elem_info.get(key)
1565
1566 def _get_actualEncoding(self):
1567 return self.actualEncoding
1568
1569 def _get_doctype(self):
1570 return self.doctype
1571
1572 def _get_documentURI(self):
1573 return self.documentURI
1574
1575 def _get_encoding(self):
1576 return self.encoding
1577
1578 def _get_errorHandler(self):
1579 return self.errorHandler
1580
1581 def _get_standalone(self):
1582 return self.standalone
1583
1584 def _get_strictErrorChecking(self):
1585 return self.strictErrorChecking
1586
1587 def _get_version(self):
1588 return self.version
Fred Drake55c38192000-06-29 19:39:57 +00001589
Fred Drake1f549022000-09-24 05:21:58 +00001590 def appendChild(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001591 if node.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001592 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001593 "%s cannot be child of %s" % (repr(node), repr(self)))
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001594 if node.parentNode is not None:
Martin v. Löwis787354c2003-01-25 15:28:29 +00001595 # This needs to be done before the next test since this
1596 # may *be* the document element, in which case it should
1597 # end up re-ordered to the end.
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001598 node.parentNode.removeChild(node)
1599
Fred Drakef7cf40d2000-12-14 18:16:11 +00001600 if node.nodeType == Node.ELEMENT_NODE \
1601 and self._get_documentElement():
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001602 raise xml.dom.HierarchyRequestErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001603 "two document elements disallowed")
Fred Drake4ccf4a12000-11-21 22:02:22 +00001604 return Node.appendChild(self, node)
Paul Prescod73678da2000-07-01 04:58:47 +00001605
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001606 def removeChild(self, oldChild):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001607 try:
1608 self.childNodes.remove(oldChild)
1609 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001610 raise xml.dom.NotFoundErr()
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001611 oldChild.nextSibling = oldChild.previousSibling = None
1612 oldChild.parentNode = None
1613 if self.documentElement is oldChild:
1614 self.documentElement = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +00001615
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001616 return oldChild
1617
Fred Drakef7cf40d2000-12-14 18:16:11 +00001618 def _get_documentElement(self):
1619 for node in self.childNodes:
1620 if node.nodeType == Node.ELEMENT_NODE:
1621 return node
1622
1623 def unlink(self):
1624 if self.doctype is not None:
1625 self.doctype.unlink()
1626 self.doctype = None
1627 Node.unlink(self)
1628
Martin v. Löwis787354c2003-01-25 15:28:29 +00001629 def cloneNode(self, deep):
1630 if not deep:
1631 return None
1632 clone = self.implementation.createDocument(None, None, None)
1633 clone.encoding = self.encoding
1634 clone.standalone = self.standalone
1635 clone.version = self.version
1636 for n in self.childNodes:
1637 childclone = _clone_node(n, deep, clone)
1638 assert childclone.ownerDocument.isSameNode(clone)
1639 clone.childNodes.append(childclone)
1640 if childclone.nodeType == Node.DOCUMENT_NODE:
1641 assert clone.documentElement is None
1642 elif childclone.nodeType == Node.DOCUMENT_TYPE_NODE:
1643 assert clone.doctype is None
1644 clone.doctype = childclone
1645 childclone.parentNode = clone
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001646 self._call_user_data_handler(xml.dom.UserDataHandler.NODE_CLONED,
Martin v. Löwis787354c2003-01-25 15:28:29 +00001647 self, clone)
1648 return clone
1649
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001650 def createDocumentFragment(self):
1651 d = DocumentFragment()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001652 d.ownerDocument = self
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001653 return d
Fred Drake55c38192000-06-29 19:39:57 +00001654
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001655 def createElement(self, tagName):
1656 e = Element(tagName)
1657 e.ownerDocument = self
1658 return e
Fred Drake55c38192000-06-29 19:39:57 +00001659
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001660 def createTextNode(self, data):
Christian Heimesc9543e42007-11-28 08:28:28 +00001661 if not isinstance(data, str):
Collin Winter70e79802007-08-24 18:57:22 +00001662 raise TypeError("node contents must be a string")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001663 t = Text()
1664 t.data = data
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001665 t.ownerDocument = self
1666 return t
Fred Drake55c38192000-06-29 19:39:57 +00001667
Fred Drake87432f42001-04-04 14:09:46 +00001668 def createCDATASection(self, data):
Christian Heimesc9543e42007-11-28 08:28:28 +00001669 if not isinstance(data, str):
Collin Winter70e79802007-08-24 18:57:22 +00001670 raise TypeError("node contents must be a string")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001671 c = CDATASection()
1672 c.data = data
Fred Drake87432f42001-04-04 14:09:46 +00001673 c.ownerDocument = self
1674 return c
1675
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001676 def createComment(self, data):
1677 c = Comment(data)
1678 c.ownerDocument = self
1679 return c
Fred Drake55c38192000-06-29 19:39:57 +00001680
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001681 def createProcessingInstruction(self, target, data):
1682 p = ProcessingInstruction(target, data)
1683 p.ownerDocument = self
1684 return p
1685
1686 def createAttribute(self, qName):
1687 a = Attr(qName)
1688 a.ownerDocument = self
Martin v. Löwiscb67ea12001-03-31 16:30:40 +00001689 a.value = ""
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001690 return a
Fred Drake55c38192000-06-29 19:39:57 +00001691
1692 def createElementNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001693 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001694 e = Element(qualifiedName, namespaceURI, prefix)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001695 e.ownerDocument = self
1696 return e
Fred Drake55c38192000-06-29 19:39:57 +00001697
1698 def createAttributeNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001699 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001700 a = Attr(qualifiedName, namespaceURI, localName, prefix)
1701 a.ownerDocument = self
Martin v. Löwiscb67ea12001-03-31 16:30:40 +00001702 a.value = ""
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001703 return a
Fred Drake55c38192000-06-29 19:39:57 +00001704
Martin v. Löwis787354c2003-01-25 15:28:29 +00001705 # A couple of implementation-specific helpers to create node types
1706 # not supported by the W3C DOM specs:
1707
1708 def _create_entity(self, name, publicId, systemId, notationName):
1709 e = Entity(name, publicId, systemId, notationName)
1710 e.ownerDocument = self
1711 return e
1712
1713 def _create_notation(self, name, publicId, systemId):
1714 n = Notation(name, publicId, systemId)
1715 n.ownerDocument = self
1716 return n
1717
1718 def getElementById(self, id):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +00001719 if id in self._id_cache:
Martin v. Löwis787354c2003-01-25 15:28:29 +00001720 return self._id_cache[id]
1721 if not (self._elem_info or self._magic_id_count):
1722 return None
1723
1724 stack = self._id_search_stack
1725 if stack is None:
1726 # we never searched before, or the cache has been cleared
1727 stack = [self.documentElement]
1728 self._id_search_stack = stack
1729 elif not stack:
1730 # Previous search was completed and cache is still valid;
1731 # no matching node.
1732 return None
1733
1734 result = None
1735 while stack:
1736 node = stack.pop()
1737 # add child elements to stack for continued searching
1738 stack.extend([child for child in node.childNodes
1739 if child.nodeType in _nodeTypes_with_children])
1740 # check this node
1741 info = self._get_elem_info(node)
1742 if info:
1743 # We have to process all ID attributes before
1744 # returning in order to get all the attributes set to
1745 # be IDs using Element.setIdAttribute*().
1746 for attr in node.attributes.values():
1747 if attr.namespaceURI:
1748 if info.isIdNS(attr.namespaceURI, attr.localName):
1749 self._id_cache[attr.value] = node
1750 if attr.value == id:
1751 result = node
1752 elif not node._magic_id_nodes:
1753 break
1754 elif info.isId(attr.name):
1755 self._id_cache[attr.value] = node
1756 if attr.value == id:
1757 result = node
1758 elif not node._magic_id_nodes:
1759 break
1760 elif attr._is_id:
1761 self._id_cache[attr.value] = node
1762 if attr.value == id:
1763 result = node
1764 elif node._magic_id_nodes == 1:
1765 break
1766 elif node._magic_id_nodes:
1767 for attr in node.attributes.values():
1768 if attr._is_id:
1769 self._id_cache[attr.value] = node
1770 if attr.value == id:
1771 result = node
1772 if result is not None:
1773 break
1774 return result
1775
Fred Drake1f549022000-09-24 05:21:58 +00001776 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001777 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drakefbe7b4f2001-07-04 06:25:53 +00001778
1779 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001780 return _get_elements_by_tagName_ns_helper(
1781 self, namespaceURI, localName, NodeList())
1782
1783 def isSupported(self, feature, version):
1784 return self.implementation.hasFeature(feature, version)
1785
1786 def importNode(self, node, deep):
1787 if node.nodeType == Node.DOCUMENT_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001788 raise xml.dom.NotSupportedErr("cannot import document nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001789 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001790 raise xml.dom.NotSupportedErr("cannot import document type nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001791 return _clone_node(node, deep, self)
Fred Drake55c38192000-06-29 19:39:57 +00001792
Eli Bendersky8a805022012-07-13 09:52:39 +03001793 def writexml(self, writer, indent="", addindent="", newl="", encoding=None):
Martin v. Löwis7d650ca2002-06-30 15:05:00 +00001794 if encoding is None:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001795 writer.write('<?xml version="1.0" ?>'+newl)
Martin v. Löwis7d650ca2002-06-30 15:05:00 +00001796 else:
Eli Bendersky8a805022012-07-13 09:52:39 +03001797 writer.write('<?xml version="1.0" encoding="%s"?>%s' % (
1798 encoding, newl))
Fred Drake55c38192000-06-29 19:39:57 +00001799 for node in self.childNodes:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001800 node.writexml(writer, indent, addindent, newl)
Fred Drake55c38192000-06-29 19:39:57 +00001801
Martin v. Löwis787354c2003-01-25 15:28:29 +00001802 # DOM Level 3 (WD 9 April 2002)
1803
1804 def renameNode(self, n, namespaceURI, name):
1805 if n.ownerDocument is not self:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001806 raise xml.dom.WrongDocumentErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001807 "cannot rename nodes from other documents;\n"
1808 "expected %s,\nfound %s" % (self, n.ownerDocument))
1809 if n.nodeType not in (Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001810 raise xml.dom.NotSupportedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001811 "renameNode() only applies to element and attribute nodes")
1812 if namespaceURI != EMPTY_NAMESPACE:
1813 if ':' in name:
1814 prefix, localName = name.split(':', 1)
1815 if ( prefix == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001816 and namespaceURI != xml.dom.XMLNS_NAMESPACE):
1817 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001818 "illegal use of 'xmlns' prefix")
1819 else:
1820 if ( name == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001821 and namespaceURI != xml.dom.XMLNS_NAMESPACE
Martin v. Löwis787354c2003-01-25 15:28:29 +00001822 and n.nodeType == Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001823 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001824 "illegal use of the 'xmlns' attribute")
1825 prefix = None
1826 localName = name
1827 else:
1828 prefix = None
1829 localName = None
1830 if n.nodeType == Node.ATTRIBUTE_NODE:
1831 element = n.ownerElement
1832 if element is not None:
1833 is_id = n._is_id
1834 element.removeAttributeNode(n)
1835 else:
1836 element = None
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001837 n.prefix = prefix
1838 n._localName = localName
1839 n.namespaceURI = namespaceURI
1840 n.nodeName = name
Martin v. Löwis787354c2003-01-25 15:28:29 +00001841 if n.nodeType == Node.ELEMENT_NODE:
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001842 n.tagName = name
Martin v. Löwis787354c2003-01-25 15:28:29 +00001843 else:
1844 # attribute node
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001845 n.name = name
Martin v. Löwis787354c2003-01-25 15:28:29 +00001846 if element is not None:
1847 element.setAttributeNode(n)
1848 if is_id:
1849 element.setIdAttributeNode(n)
1850 # It's not clear from a semantic perspective whether we should
1851 # call the user data handlers for the NODE_RENAMED event since
1852 # we're re-using the existing node. The draft spec has been
1853 # interpreted as meaning "no, don't call the handler unless a
1854 # new node is created."
1855 return n
1856
1857defproperty(Document, "documentElement",
1858 doc="Top-level element of this document.")
1859
1860
1861def _clone_node(node, deep, newOwnerDocument):
1862 """
1863 Clone a node and give it the new owner document.
1864 Called by Node.cloneNode and Document.importNode
1865 """
1866 if node.ownerDocument.isSameNode(newOwnerDocument):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001867 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001868 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001869 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001870 if node.nodeType == Node.ELEMENT_NODE:
1871 clone = newOwnerDocument.createElementNS(node.namespaceURI,
1872 node.nodeName)
1873 for attr in node.attributes.values():
1874 clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value)
1875 a = clone.getAttributeNodeNS(attr.namespaceURI, attr.localName)
1876 a.specified = attr.specified
1877
1878 if deep:
1879 for child in node.childNodes:
1880 c = _clone_node(child, deep, newOwnerDocument)
1881 clone.appendChild(c)
1882
1883 elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
1884 clone = newOwnerDocument.createDocumentFragment()
1885 if deep:
1886 for child in node.childNodes:
1887 c = _clone_node(child, deep, newOwnerDocument)
1888 clone.appendChild(c)
1889
1890 elif node.nodeType == Node.TEXT_NODE:
1891 clone = newOwnerDocument.createTextNode(node.data)
1892 elif node.nodeType == Node.CDATA_SECTION_NODE:
1893 clone = newOwnerDocument.createCDATASection(node.data)
1894 elif node.nodeType == Node.PROCESSING_INSTRUCTION_NODE:
1895 clone = newOwnerDocument.createProcessingInstruction(node.target,
1896 node.data)
1897 elif node.nodeType == Node.COMMENT_NODE:
1898 clone = newOwnerDocument.createComment(node.data)
1899 elif node.nodeType == Node.ATTRIBUTE_NODE:
1900 clone = newOwnerDocument.createAttributeNS(node.namespaceURI,
1901 node.nodeName)
1902 clone.specified = True
1903 clone.value = node.value
1904 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
1905 assert node.ownerDocument is not newOwnerDocument
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001906 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001907 clone = newOwnerDocument.implementation.createDocumentType(
1908 node.name, node.publicId, node.systemId)
1909 clone.ownerDocument = newOwnerDocument
1910 if deep:
1911 clone.entities._seq = []
1912 clone.notations._seq = []
1913 for n in node.notations._seq:
1914 notation = Notation(n.nodeName, n.publicId, n.systemId)
1915 notation.ownerDocument = newOwnerDocument
1916 clone.notations._seq.append(notation)
1917 if hasattr(n, '_call_user_data_handler'):
1918 n._call_user_data_handler(operation, n, notation)
1919 for e in node.entities._seq:
1920 entity = Entity(e.nodeName, e.publicId, e.systemId,
1921 e.notationName)
1922 entity.actualEncoding = e.actualEncoding
1923 entity.encoding = e.encoding
1924 entity.version = e.version
1925 entity.ownerDocument = newOwnerDocument
1926 clone.entities._seq.append(entity)
1927 if hasattr(e, '_call_user_data_handler'):
1928 e._call_user_data_handler(operation, n, entity)
1929 else:
1930 # Note the cloning of Document and DocumentType nodes is
Ezio Melotti13925002011-03-16 11:05:33 +02001931 # implementation specific. minidom handles those cases
Martin v. Löwis787354c2003-01-25 15:28:29 +00001932 # directly in the cloneNode() methods.
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001933 raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001934
1935 # Check for _call_user_data_handler() since this could conceivably
1936 # used with other DOM implementations (one of the FourThought
1937 # DOMs, perhaps?).
1938 if hasattr(node, '_call_user_data_handler'):
1939 node._call_user_data_handler(operation, node, clone)
1940 return clone
1941
1942
1943def _nssplit(qualifiedName):
1944 fields = qualifiedName.split(':', 1)
1945 if len(fields) == 2:
1946 return fields
1947 else:
1948 return (None, fields[0])
1949
1950
Martin v. Löwis787354c2003-01-25 15:28:29 +00001951def _do_pulldom_parse(func, args, kwargs):
Raymond Hettingerff41c482003-04-06 09:01:11 +00001952 events = func(*args, **kwargs)
Fred Drake1f549022000-09-24 05:21:58 +00001953 toktype, rootNode = events.getEvent()
1954 events.expandNode(rootNode)
Martin v. Löwisb417be22001-02-06 01:16:06 +00001955 events.clear()
Fred Drake55c38192000-06-29 19:39:57 +00001956 return rootNode
1957
Martin v. Löwis787354c2003-01-25 15:28:29 +00001958def parse(file, parser=None, bufsize=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001959 """Parse a file into a DOM by filename or file object."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001960 if parser is None and not bufsize:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001961 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001962 return expatbuilder.parse(file)
1963 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001964 from xml.dom import pulldom
Raymond Hettingerff41c482003-04-06 09:01:11 +00001965 return _do_pulldom_parse(pulldom.parse, (file,),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001966 {'parser': parser, 'bufsize': bufsize})
Fred Drake55c38192000-06-29 19:39:57 +00001967
Martin v. Löwis787354c2003-01-25 15:28:29 +00001968def parseString(string, parser=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001969 """Parse a file into a DOM from a string."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001970 if parser is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001971 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001972 return expatbuilder.parseString(string)
1973 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001974 from xml.dom import pulldom
Martin v. Löwis787354c2003-01-25 15:28:29 +00001975 return _do_pulldom_parse(pulldom.parseString, (string,),
1976 {'parser': parser})
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001977
Martin v. Löwis787354c2003-01-25 15:28:29 +00001978def getDOMImplementation(features=None):
1979 if features:
Christian Heimesc9543e42007-11-28 08:28:28 +00001980 if isinstance(features, str):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001981 features = domreg._parse_feature_string(features)
1982 for f, v in features:
1983 if not Document.implementation.hasFeature(f, v):
1984 return None
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001985 return Document.implementation