blob: 464420b76598e07ea38aabc9a22705c0650c7471 [file] [log] [blame]
Ezio Melottida4b5b82013-01-22 22:47:57 +02001"""Simple implementation of the Level 1 DOM.
2
3Namespaces and other minor Level 2 features are also supported.
Fred Drake55c38192000-06-29 19:39:57 +00004
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00005parse("foo.xml")
Paul Prescod623511b2000-07-21 22:05:49 +00006
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00007parseString("<foo><bar/></foo>")
Paul Prescod623511b2000-07-21 22:05:49 +00008
Fred Drake55c38192000-06-29 19:39:57 +00009Todo:
10=====
11 * convenience methods for getting elements and text.
12 * more testing
13 * bring some of the writer and linearizer code into conformance with this
14 interface
15 * SAX 2 namespaces
16"""
17
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000018import io
Thomas Wouters0e3f5912006-08-11 14:57:12 +000019import xml.dom
Fred Drake55c38192000-06-29 19:39:57 +000020
Thomas Wouters0e3f5912006-08-11 14:57:12 +000021from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE, domreg
22from xml.dom.minicompat import *
23from xml.dom.xmlbuilder import DOMImplementationLS, DocumentLS
Fred Drake3ac6a092001-09-28 04:33:06 +000024
Martin v. Löwis787354c2003-01-25 15:28:29 +000025# This is used by the ID-cache invalidation checks; the list isn't
26# actually complete, since the nodes being checked will never be the
27# DOCUMENT_NODE or DOCUMENT_FRAGMENT_NODE. (The node being checked is
28# the node being added or removed, not the node being modified.)
29#
Thomas Wouters0e3f5912006-08-11 14:57:12 +000030_nodeTypes_with_children = (xml.dom.Node.ELEMENT_NODE,
31 xml.dom.Node.ENTITY_REFERENCE_NODE)
Martin v. Löwis95700f72002-03-15 13:51:59 +000032
Fred Drake3ac6a092001-09-28 04:33:06 +000033
Thomas Wouters0e3f5912006-08-11 14:57:12 +000034class Node(xml.dom.Node):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000035 namespaceURI = None # this is non-null only for elements and attributes
Fred Drake575712e2001-09-28 20:25:45 +000036 parentNode = None
37 ownerDocument = None
Martin v. Löwis787354c2003-01-25 15:28:29 +000038 nextSibling = None
39 previousSibling = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +000040
Martin v. Löwis787354c2003-01-25 15:28:29 +000041 prefix = EMPTY_PREFIX # non-null only for NS elements and attributes
Fred Drake55c38192000-06-29 19:39:57 +000042
Jack Diederich4dafcc42006-11-28 19:15:13 +000043 def __bool__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +000044 return True
Fred Drake55c38192000-06-29 19:39:57 +000045
Georg Brandlfe991052009-09-16 15:54:04 +000046 def toxml(self, encoding=None):
Martin v. Löwis7d650ca2002-06-30 15:05:00 +000047 return self.toprettyxml("", "", encoding)
Fred Drake55c38192000-06-29 19:39:57 +000048
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000049 def toprettyxml(self, indent="\t", newl="\n", encoding=None):
Eli Bendersky8a805022012-07-13 09:52:39 +030050 if encoding is None:
51 writer = io.StringIO()
52 else:
53 writer = io.TextIOWrapper(io.BytesIO(),
54 encoding=encoding,
55 errors="xmlcharrefreplace",
56 newline='\n')
Martin v. Löwis7d650ca2002-06-30 15:05:00 +000057 if self.nodeType == Node.DOCUMENT_NODE:
58 # Can pass encoding only to document, to put it into XML header
59 self.writexml(writer, "", indent, newl, encoding)
60 else:
61 self.writexml(writer, "", indent, newl)
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000062 if encoding is None:
Eli Bendersky8a805022012-07-13 09:52:39 +030063 return writer.getvalue()
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000064 else:
Eli Bendersky8a805022012-07-13 09:52:39 +030065 return writer.detach().getvalue()
Martin v. Löwis46fa39a2001-02-06 00:14:08 +000066
Fred Drake1f549022000-09-24 05:21:58 +000067 def hasChildNodes(self):
Florent Xicluna8cf4b512012-03-05 12:37:02 +010068 return bool(self.childNodes)
Martin v. Löwis787354c2003-01-25 15:28:29 +000069
70 def _get_childNodes(self):
71 return self.childNodes
Fred Drake55c38192000-06-29 19:39:57 +000072
Fred Drake1f549022000-09-24 05:21:58 +000073 def _get_firstChild(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +000074 if self.childNodes:
75 return self.childNodes[0]
Paul Prescod73678da2000-07-01 04:58:47 +000076
Fred Drake1f549022000-09-24 05:21:58 +000077 def _get_lastChild(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +000078 if self.childNodes:
79 return self.childNodes[-1]
Paul Prescod73678da2000-07-01 04:58:47 +000080
Fred Drake1f549022000-09-24 05:21:58 +000081 def insertBefore(self, newChild, refChild):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000082 if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
Fred Drakee50959a2001-12-06 04:32:18 +000083 for c in tuple(newChild.childNodes):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000084 self.insertBefore(c, refChild)
85 ### The DOM does not clearly specify what to return in this case
86 return newChild
Martin v. Löwis787354c2003-01-25 15:28:29 +000087 if newChild.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000088 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +000089 "%s cannot be child of %s" % (repr(newChild), repr(self)))
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +000090 if newChild.parentNode is not None:
91 newChild.parentNode.removeChild(newChild)
Fred Drake4ccf4a12000-11-21 22:02:22 +000092 if refChild is None:
93 self.appendChild(newChild)
94 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +000095 try:
96 index = self.childNodes.index(refChild)
97 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000098 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +000099 if newChild.nodeType in _nodeTypes_with_children:
100 _clear_id_cache(self)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000101 self.childNodes.insert(index, newChild)
102 newChild.nextSibling = refChild
103 refChild.previousSibling = newChild
104 if index:
105 node = self.childNodes[index-1]
106 node.nextSibling = newChild
107 newChild.previousSibling = node
108 else:
109 newChild.previousSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000110 newChild.parentNode = self
Fred Drake4ccf4a12000-11-21 22:02:22 +0000111 return newChild
Fred Drake55c38192000-06-29 19:39:57 +0000112
Fred Drake1f549022000-09-24 05:21:58 +0000113 def appendChild(self, node):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000114 if node.nodeType == self.DOCUMENT_FRAGMENT_NODE:
Fred Drakee50959a2001-12-06 04:32:18 +0000115 for c in tuple(node.childNodes):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000116 self.appendChild(c)
117 ### The DOM does not clearly specify what to return in this case
118 return node
Martin v. Löwis787354c2003-01-25 15:28:29 +0000119 if node.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000120 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000121 "%s cannot be child of %s" % (repr(node), repr(self)))
122 elif node.nodeType in _nodeTypes_with_children:
123 _clear_id_cache(self)
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000124 if node.parentNode is not None:
125 node.parentNode.removeChild(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000126 _append_child(self, node)
Fred Drake13a30692000-10-09 20:04:16 +0000127 node.nextSibling = None
Paul Prescod73678da2000-07-01 04:58:47 +0000128 return node
129
Fred Drake1f549022000-09-24 05:21:58 +0000130 def replaceChild(self, newChild, oldChild):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000131 if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
132 refChild = oldChild.nextSibling
133 self.removeChild(oldChild)
134 return self.insertBefore(newChild, refChild)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000135 if newChild.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000136 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000137 "%s cannot be child of %s" % (repr(newChild), repr(self)))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000138 if newChild is oldChild:
139 return
Andrew M. Kuchling841d25e2005-11-22 19:03:16 +0000140 if newChild.parentNode is not None:
141 newChild.parentNode.removeChild(newChild)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000142 try:
143 index = self.childNodes.index(oldChild)
144 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000145 raise xml.dom.NotFoundErr()
Fred Drake4ccf4a12000-11-21 22:02:22 +0000146 self.childNodes[index] = newChild
Martin v. Löwis787354c2003-01-25 15:28:29 +0000147 newChild.parentNode = self
148 oldChild.parentNode = None
149 if (newChild.nodeType in _nodeTypes_with_children
150 or oldChild.nodeType in _nodeTypes_with_children):
151 _clear_id_cache(self)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000152 newChild.nextSibling = oldChild.nextSibling
153 newChild.previousSibling = oldChild.previousSibling
Martin v. Löwis156c3372000-12-28 18:40:56 +0000154 oldChild.nextSibling = None
Fred Drake4ccf4a12000-11-21 22:02:22 +0000155 oldChild.previousSibling = None
Martin v. Löwis156c3372000-12-28 18:40:56 +0000156 if newChild.previousSibling:
157 newChild.previousSibling.nextSibling = newChild
158 if newChild.nextSibling:
159 newChild.nextSibling.previousSibling = newChild
Fred Drake4ccf4a12000-11-21 22:02:22 +0000160 return oldChild
Paul Prescod73678da2000-07-01 04:58:47 +0000161
Fred Drake1f549022000-09-24 05:21:58 +0000162 def removeChild(self, oldChild):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000163 try:
164 self.childNodes.remove(oldChild)
165 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000166 raise xml.dom.NotFoundErr()
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000167 if oldChild.nextSibling is not None:
168 oldChild.nextSibling.previousSibling = oldChild.previousSibling
169 if oldChild.previousSibling is not None:
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000170 oldChild.previousSibling.nextSibling = oldChild.nextSibling
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000171 oldChild.nextSibling = oldChild.previousSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000172 if oldChild.nodeType in _nodeTypes_with_children:
173 _clear_id_cache(self)
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000174
Martin v. Löwis787354c2003-01-25 15:28:29 +0000175 oldChild.parentNode = None
Fred Drake4ccf4a12000-11-21 22:02:22 +0000176 return oldChild
177
178 def normalize(self):
Fred Drakef7cf40d2000-12-14 18:16:11 +0000179 L = []
180 for child in self.childNodes:
181 if child.nodeType == Node.TEXT_NODE:
R. David Murraydc6da8a2009-04-09 22:16:43 +0000182 if not child.data:
183 # empty text node; discard
184 if L:
185 L[-1].nextSibling = child.nextSibling
186 if child.nextSibling:
187 child.nextSibling.previousSibling = child.previousSibling
188 child.unlink()
189 elif L and L[-1].nodeType == child.nodeType:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000190 # collapse text node
191 node = L[-1]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000192 node.data = node.data + child.data
Fred Drake4ccf4a12000-11-21 22:02:22 +0000193 node.nextSibling = child.nextSibling
R. David Murraydc6da8a2009-04-09 22:16:43 +0000194 if child.nextSibling:
195 child.nextSibling.previousSibling = node
Fred Drake4ccf4a12000-11-21 22:02:22 +0000196 child.unlink()
R. David Murraydc6da8a2009-04-09 22:16:43 +0000197 else:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000198 L.append(child)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000199 else:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000200 L.append(child)
201 if child.nodeType == Node.ELEMENT_NODE:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000202 child.normalize()
Fred Drakef7cf40d2000-12-14 18:16:11 +0000203 self.childNodes[:] = L
Paul Prescod73678da2000-07-01 04:58:47 +0000204
Fred Drake1f549022000-09-24 05:21:58 +0000205 def cloneNode(self, deep):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000206 return _clone_node(self, deep, self.ownerDocument or self)
Fred Drake55c38192000-06-29 19:39:57 +0000207
Martin v. Löwis787354c2003-01-25 15:28:29 +0000208 def isSupported(self, feature, version):
209 return self.ownerDocument.implementation.hasFeature(feature, version)
210
211 def _get_localName(self):
212 # Overridden in Element and Attr where localName can be Non-Null
213 return None
214
215 # Node interfaces from Level 3 (WD 9 April 2002)
Fred Drake25239772001-02-02 19:40:19 +0000216
217 def isSameNode(self, other):
218 return self is other
219
Martin v. Löwis787354c2003-01-25 15:28:29 +0000220 def getInterface(self, feature):
221 if self.isSupported(feature, None):
222 return self
223 else:
224 return None
225
226 # The "user data" functions use a dictionary that is only present
227 # if some user data has been set, so be careful not to assume it
228 # exists.
229
230 def getUserData(self, key):
231 try:
232 return self._user_data[key][0]
233 except (AttributeError, KeyError):
234 return None
235
236 def setUserData(self, key, data, handler):
237 old = None
238 try:
239 d = self._user_data
240 except AttributeError:
241 d = {}
242 self._user_data = d
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000243 if key in d:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000244 old = d[key][0]
245 if data is None:
246 # ignore handlers passed for None
247 handler = None
248 if old is not None:
249 del d[key]
250 else:
251 d[key] = (data, handler)
252 return old
253
254 def _call_user_data_handler(self, operation, src, dst):
255 if hasattr(self, "_user_data"):
Brett Cannon861fd6f2007-02-21 22:05:37 +0000256 for key, (data, handler) in list(self._user_data.items()):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000257 if handler is not None:
258 handler.handle(operation, key, data, src, dst)
259
Fred Drake25239772001-02-02 19:40:19 +0000260 # minidom-specific API:
261
Fred Drake1f549022000-09-24 05:21:58 +0000262 def unlink(self):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000263 self.parentNode = self.ownerDocument = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000264 if self.childNodes:
265 for child in self.childNodes:
266 child.unlink()
267 self.childNodes = NodeList()
Paul Prescod4221ff02000-10-13 20:11:42 +0000268 self.previousSibling = None
269 self.nextSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000270
Kristján Valur Jónsson17173cf2010-06-09 08:13:42 +0000271 # A Node is its own context manager, to ensure that an unlink() call occurs.
272 # This is similar to how a file object works.
273 def __enter__(self):
274 return self
275
276 def __exit__(self, et, ev, tb):
277 self.unlink()
278
Martin v. Löwis787354c2003-01-25 15:28:29 +0000279defproperty(Node, "firstChild", doc="First child node, or None.")
280defproperty(Node, "lastChild", doc="Last child node, or None.")
281defproperty(Node, "localName", doc="Namespace-local name of this node.")
282
283
284def _append_child(self, node):
285 # fast path with less checks; usable by DOM builders if careful
286 childNodes = self.childNodes
287 if childNodes:
288 last = childNodes[-1]
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100289 node.previousSibling = last
290 last.nextSibling = node
Martin v. Löwis787354c2003-01-25 15:28:29 +0000291 childNodes.append(node)
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100292 node.parentNode = self
Martin v. Löwis787354c2003-01-25 15:28:29 +0000293
294def _in_document(node):
295 # return True iff node is part of a document tree
296 while node is not None:
297 if node.nodeType == Node.DOCUMENT_NODE:
298 return True
299 node = node.parentNode
300 return False
Fred Drake55c38192000-06-29 19:39:57 +0000301
Fred Drake1f549022000-09-24 05:21:58 +0000302def _write_data(writer, data):
Fred Drake55c38192000-06-29 19:39:57 +0000303 "Writes datachars to writer."
Georg Brandlb9cd72a2010-10-15 17:58:45 +0000304 if data:
305 data = data.replace("&", "&amp;").replace("<", "&lt;"). \
306 replace("\"", "&quot;").replace(">", "&gt;")
307 writer.write(data)
Fred Drake55c38192000-06-29 19:39:57 +0000308
Martin v. Löwis787354c2003-01-25 15:28:29 +0000309def _get_elements_by_tagName_helper(parent, name, rc):
Fred Drake55c38192000-06-29 19:39:57 +0000310 for node in parent.childNodes:
Fred Drake1f549022000-09-24 05:21:58 +0000311 if node.nodeType == Node.ELEMENT_NODE and \
312 (name == "*" or node.tagName == name):
313 rc.append(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000314 _get_elements_by_tagName_helper(node, name, rc)
Fred Drake55c38192000-06-29 19:39:57 +0000315 return rc
316
Martin v. Löwis787354c2003-01-25 15:28:29 +0000317def _get_elements_by_tagName_ns_helper(parent, nsURI, localName, rc):
Fred Drake55c38192000-06-29 19:39:57 +0000318 for node in parent.childNodes:
Fred Drake1f549022000-09-24 05:21:58 +0000319 if node.nodeType == Node.ELEMENT_NODE:
Martin v. Löwised525fb2001-06-03 14:06:42 +0000320 if ((localName == "*" or node.localName == localName) and
Fred Drake1f549022000-09-24 05:21:58 +0000321 (nsURI == "*" or node.namespaceURI == nsURI)):
322 rc.append(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000323 _get_elements_by_tagName_ns_helper(node, nsURI, localName, rc)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000324 return rc
Fred Drake55c38192000-06-29 19:39:57 +0000325
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000326class DocumentFragment(Node):
327 nodeType = Node.DOCUMENT_FRAGMENT_NODE
328 nodeName = "#document-fragment"
329 nodeValue = None
330 attributes = None
331 parentNode = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000332 _child_node_types = (Node.ELEMENT_NODE,
333 Node.TEXT_NODE,
334 Node.CDATA_SECTION_NODE,
335 Node.ENTITY_REFERENCE_NODE,
336 Node.PROCESSING_INSTRUCTION_NODE,
337 Node.COMMENT_NODE,
338 Node.NOTATION_NODE)
339
340 def __init__(self):
341 self.childNodes = NodeList()
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000342
343
Fred Drake55c38192000-06-29 19:39:57 +0000344class Attr(Node):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100345 __slots__=('_name', '_value', 'namespaceURI',
346 '_prefix', 'childNodes', '_localName', 'ownerDocument', 'ownerElement')
Fred Drake1f549022000-09-24 05:21:58 +0000347 nodeType = Node.ATTRIBUTE_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +0000348 attributes = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000349 specified = False
350 _is_id = False
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000351
Martin v. Löwis787354c2003-01-25 15:28:29 +0000352 _child_node_types = (Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE)
353
354 def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None,
355 prefix=None):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100356 self.ownerElement = None
357 self._name = qName
358 self.namespaceURI = namespaceURI
359 self._prefix = prefix
360 self.childNodes = NodeList()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000361
362 # Add the single child node that represents the value of the attr
363 self.childNodes.append(Text())
364
Paul Prescod73678da2000-07-01 04:58:47 +0000365 # nodeValue and value are set elsewhere
Fred Drake55c38192000-06-29 19:39:57 +0000366
Martin v. Löwis787354c2003-01-25 15:28:29 +0000367 def _get_localName(self):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100368 try:
369 return self._localName
370 except AttributeError:
371 return self.nodeName.split(":", 1)[-1]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000372
Martin v. Löwis787354c2003-01-25 15:28:29 +0000373 def _get_specified(self):
374 return self.specified
375
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100376 def _get_name(self):
377 return self._name
378
379 def _set_name(self, value):
380 self._name = value
381 if self.ownerElement is not None:
382 _clear_id_cache(self.ownerElement)
383
384 nodeName = name = property(_get_name, _set_name)
385
386 def _get_value(self):
387 return self._value
388
389 def _set_value(self, value):
390 self._value = value
391 self.childNodes[0].data = value
392 if self.ownerElement is not None:
393 _clear_id_cache(self.ownerElement)
394 self.childNodes[0].data = value
395
396 nodeValue = value = property(_get_value, _set_value)
397
398 def _get_prefix(self):
399 return self._prefix
Fred Drake55c38192000-06-29 19:39:57 +0000400
Martin v. Löwis995359c2003-01-26 08:59:32 +0000401 def _set_prefix(self, prefix):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000402 nsuri = self.namespaceURI
Martin v. Löwis995359c2003-01-26 08:59:32 +0000403 if prefix == "xmlns":
404 if nsuri and nsuri != XMLNS_NAMESPACE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000405 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000406 "illegal use of 'xmlns' prefix for the wrong namespace")
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100407 self._prefix = prefix
Martin v. Löwis787354c2003-01-25 15:28:29 +0000408 if prefix is None:
409 newName = self.localName
410 else:
Martin v. Löwis995359c2003-01-26 08:59:32 +0000411 newName = "%s:%s" % (prefix, self.localName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000412 if self.ownerElement:
413 _clear_id_cache(self.ownerElement)
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100414 self.name = newName
Martin v. Löwis787354c2003-01-25 15:28:29 +0000415
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100416 prefix = property(_get_prefix, _set_prefix)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000417
418 def unlink(self):
419 # This implementation does not call the base implementation
420 # since most of that is not needed, and the expense of the
421 # method call is not warranted. We duplicate the removal of
422 # children, but that's all we needed from the base class.
423 elem = self.ownerElement
424 if elem is not None:
425 del elem._attrs[self.nodeName]
426 del elem._attrsNS[(self.namespaceURI, self.localName)]
427 if self._is_id:
428 self._is_id = False
429 elem._magic_id_nodes -= 1
430 self.ownerDocument._magic_id_count -= 1
431 for child in self.childNodes:
432 child.unlink()
433 del self.childNodes[:]
434
435 def _get_isId(self):
436 if self._is_id:
437 return True
438 doc = self.ownerDocument
439 elem = self.ownerElement
440 if doc is None or elem is None:
441 return False
442
443 info = doc._get_elem_info(elem)
444 if info is None:
445 return False
446 if self.namespaceURI:
447 return info.isIdNS(self.namespaceURI, self.localName)
448 else:
449 return info.isId(self.nodeName)
450
451 def _get_schemaType(self):
452 doc = self.ownerDocument
453 elem = self.ownerElement
454 if doc is None or elem is None:
455 return _no_type
456
457 info = doc._get_elem_info(elem)
458 if info is None:
459 return _no_type
460 if self.namespaceURI:
461 return info.getAttributeTypeNS(self.namespaceURI, self.localName)
462 else:
463 return info.getAttributeType(self.nodeName)
464
465defproperty(Attr, "isId", doc="True if this attribute is an ID.")
466defproperty(Attr, "localName", doc="Namespace-local name of this attribute.")
467defproperty(Attr, "schemaType", doc="Schema type for this attribute.")
Fred Drake4ccf4a12000-11-21 22:02:22 +0000468
Fred Drakef7cf40d2000-12-14 18:16:11 +0000469
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000470class NamedNodeMap(object):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000471 """The attribute list is a transient interface to the underlying
472 dictionaries. Mutations here will change the underlying element's
Fred Drakef7cf40d2000-12-14 18:16:11 +0000473 dictionary.
474
475 Ordering is imposed artificially and does not reflect the order of
476 attributes as found in an input document.
477 """
Fred Drake4ccf4a12000-11-21 22:02:22 +0000478
Martin v. Löwis787354c2003-01-25 15:28:29 +0000479 __slots__ = ('_attrs', '_attrsNS', '_ownerElement')
480
Fred Drake2998a552001-12-06 18:27:48 +0000481 def __init__(self, attrs, attrsNS, ownerElement):
Fred Drake1f549022000-09-24 05:21:58 +0000482 self._attrs = attrs
483 self._attrsNS = attrsNS
Fred Drake2998a552001-12-06 18:27:48 +0000484 self._ownerElement = ownerElement
Fred Drakef7cf40d2000-12-14 18:16:11 +0000485
Martin v. Löwis787354c2003-01-25 15:28:29 +0000486 def _get_length(self):
487 return len(self._attrs)
Fred Drake55c38192000-06-29 19:39:57 +0000488
Fred Drake1f549022000-09-24 05:21:58 +0000489 def item(self, index):
Fred Drake55c38192000-06-29 19:39:57 +0000490 try:
Brett Cannon861fd6f2007-02-21 22:05:37 +0000491 return self[list(self._attrs.keys())[index]]
Fred Drake55c38192000-06-29 19:39:57 +0000492 except IndexError:
493 return None
Fred Drake55c38192000-06-29 19:39:57 +0000494
Fred Drake1f549022000-09-24 05:21:58 +0000495 def items(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000496 L = []
497 for node in self._attrs.values():
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000498 L.append((node.nodeName, node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000499 return L
Fred Drake1f549022000-09-24 05:21:58 +0000500
501 def itemsNS(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000502 L = []
503 for node in self._attrs.values():
Fred Drake49a5d032001-11-30 22:21:58 +0000504 L.append(((node.namespaceURI, node.localName), node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000505 return L
Fred Drake16f63292000-10-23 18:09:50 +0000506
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000507 def __contains__(self, key):
Christian Heimesc9543e42007-11-28 08:28:28 +0000508 if isinstance(key, str):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000509 return key in self._attrs
Martin v. Löwis787354c2003-01-25 15:28:29 +0000510 else:
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000511 return key in self._attrsNS
Martin v. Löwis787354c2003-01-25 15:28:29 +0000512
Fred Drake1f549022000-09-24 05:21:58 +0000513 def keys(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000514 return self._attrs.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000515
Fred Drake1f549022000-09-24 05:21:58 +0000516 def keysNS(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000517 return self._attrsNS.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000518
Fred Drake1f549022000-09-24 05:21:58 +0000519 def values(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000520 return self._attrs.values()
Fred Drake55c38192000-06-29 19:39:57 +0000521
Martin v. Löwis787354c2003-01-25 15:28:29 +0000522 def get(self, name, value=None):
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000523 return self._attrs.get(name, value)
524
Martin v. Löwis787354c2003-01-25 15:28:29 +0000525 __len__ = _get_length
Fred Drake55c38192000-06-29 19:39:57 +0000526
Mark Dickinsona56c4672009-01-27 18:17:45 +0000527 def _cmp(self, other):
Fred Drake1f549022000-09-24 05:21:58 +0000528 if self._attrs is getattr(other, "_attrs", None):
Fred Drake55c38192000-06-29 19:39:57 +0000529 return 0
Fred Drake16f63292000-10-23 18:09:50 +0000530 else:
Mark Dickinsona56c4672009-01-27 18:17:45 +0000531 return (id(self) > id(other)) - (id(self) < id(other))
532
533 def __eq__(self, other):
534 return self._cmp(other) == 0
535
536 def __ge__(self, other):
537 return self._cmp(other) >= 0
538
539 def __gt__(self, other):
540 return self._cmp(other) > 0
541
542 def __le__(self, other):
543 return self._cmp(other) <= 0
544
545 def __lt__(self, other):
546 return self._cmp(other) < 0
547
Fred Drake1f549022000-09-24 05:21:58 +0000548 def __getitem__(self, attname_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000549 if isinstance(attname_or_tuple, tuple):
Paul Prescod73678da2000-07-01 04:58:47 +0000550 return self._attrsNS[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000551 else:
Paul Prescod73678da2000-07-01 04:58:47 +0000552 return self._attrs[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000553
Paul Prescod1e688272000-07-01 19:21:47 +0000554 # same as set
Fred Drake1f549022000-09-24 05:21:58 +0000555 def __setitem__(self, attname, value):
Christian Heimesc9543e42007-11-28 08:28:28 +0000556 if isinstance(value, str):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000557 try:
558 node = self._attrs[attname]
559 except KeyError:
560 node = Attr(attname)
561 node.ownerDocument = self._ownerElement.ownerDocument
Martin v. Löwis995359c2003-01-26 08:59:32 +0000562 self.setNamedItem(node)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000563 node.value = value
Paul Prescod1e688272000-07-01 19:21:47 +0000564 else:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000565 if not isinstance(value, Attr):
Collin Winter70e79802007-08-24 18:57:22 +0000566 raise TypeError("value must be a string or Attr object")
Fred Drake1f549022000-09-24 05:21:58 +0000567 node = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000568 self.setNamedItem(node)
569
570 def getNamedItem(self, name):
571 try:
572 return self._attrs[name]
573 except KeyError:
574 return None
575
576 def getNamedItemNS(self, namespaceURI, localName):
577 try:
578 return self._attrsNS[(namespaceURI, localName)]
579 except KeyError:
580 return None
581
582 def removeNamedItem(self, name):
583 n = self.getNamedItem(name)
584 if n is not None:
585 _clear_id_cache(self._ownerElement)
586 del self._attrs[n.nodeName]
587 del self._attrsNS[(n.namespaceURI, n.localName)]
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100588 if hasattr(n, 'ownerElement'):
589 n.ownerElement = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000590 return n
591 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000592 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000593
594 def removeNamedItemNS(self, namespaceURI, localName):
595 n = self.getNamedItemNS(namespaceURI, localName)
596 if n is not None:
597 _clear_id_cache(self._ownerElement)
598 del self._attrsNS[(n.namespaceURI, n.localName)]
599 del self._attrs[n.nodeName]
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100600 if hasattr(n, 'ownerElement'):
601 n.ownerElement = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000602 return n
603 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000604 raise xml.dom.NotFoundErr()
Fred Drakef7cf40d2000-12-14 18:16:11 +0000605
606 def setNamedItem(self, node):
Andrew M. Kuchlingbc8f72c2001-02-21 01:30:26 +0000607 if not isinstance(node, Attr):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000608 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000609 "%s cannot be child of %s" % (repr(node), repr(self)))
Fred Drakef7cf40d2000-12-14 18:16:11 +0000610 old = self._attrs.get(node.name)
Paul Prescod1e688272000-07-01 19:21:47 +0000611 if old:
612 old.unlink()
Fred Drake1f549022000-09-24 05:21:58 +0000613 self._attrs[node.name] = node
614 self._attrsNS[(node.namespaceURI, node.localName)] = node
Fred Drake2998a552001-12-06 18:27:48 +0000615 node.ownerElement = self._ownerElement
Martin v. Löwis787354c2003-01-25 15:28:29 +0000616 _clear_id_cache(node.ownerElement)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000617 return old
618
619 def setNamedItemNS(self, node):
620 return self.setNamedItem(node)
Paul Prescod73678da2000-07-01 04:58:47 +0000621
Fred Drake1f549022000-09-24 05:21:58 +0000622 def __delitem__(self, attname_or_tuple):
623 node = self[attname_or_tuple]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000624 _clear_id_cache(node.ownerElement)
Paul Prescod73678da2000-07-01 04:58:47 +0000625 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000626
627 def __getstate__(self):
628 return self._attrs, self._attrsNS, self._ownerElement
629
630 def __setstate__(self, state):
631 self._attrs, self._attrsNS, self._ownerElement = state
632
633defproperty(NamedNodeMap, "length",
634 doc="Number of nodes in the NamedNodeMap.")
Fred Drakef7cf40d2000-12-14 18:16:11 +0000635
636AttributeList = NamedNodeMap
637
Fred Drake1f549022000-09-24 05:21:58 +0000638
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000639class TypeInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000640 __slots__ = 'namespace', 'name'
641
642 def __init__(self, namespace, name):
643 self.namespace = namespace
644 self.name = name
645
646 def __repr__(self):
647 if self.namespace:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300648 return "<%s %r (from %r)>" % (self.__class__.__name__, self.name,
649 self.namespace)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000650 else:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300651 return "<%s %r>" % (self.__class__.__name__, self.name)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000652
653 def _get_name(self):
654 return self.name
655
656 def _get_namespace(self):
657 return self.namespace
658
659_no_type = TypeInfo(None, None)
660
Martin v. Löwisa2fda0d2000-10-07 12:10:28 +0000661class Element(Node):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100662 __slots__=('ownerDocument', 'parentNode', 'tagName', 'nodeName', 'prefix',
663 'namespaceURI', '_localName', 'childNodes', '_attrs', '_attrsNS',
664 'nextSibling', 'previousSibling')
Fred Drake1f549022000-09-24 05:21:58 +0000665 nodeType = Node.ELEMENT_NODE
Martin v. Löwis787354c2003-01-25 15:28:29 +0000666 nodeValue = None
667 schemaType = _no_type
668
669 _magic_id_nodes = 0
670
671 _child_node_types = (Node.ELEMENT_NODE,
672 Node.PROCESSING_INSTRUCTION_NODE,
673 Node.COMMENT_NODE,
674 Node.TEXT_NODE,
675 Node.CDATA_SECTION_NODE,
676 Node.ENTITY_REFERENCE_NODE)
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000677
Fred Drake49a5d032001-11-30 22:21:58 +0000678 def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None,
Fred Drake1f549022000-09-24 05:21:58 +0000679 localName=None):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100680 self.parentNode = None
Fred Drake55c38192000-06-29 19:39:57 +0000681 self.tagName = self.nodeName = tagName
Fred Drake1f549022000-09-24 05:21:58 +0000682 self.prefix = prefix
683 self.namespaceURI = namespaceURI
Martin v. Löwis787354c2003-01-25 15:28:29 +0000684 self.childNodes = NodeList()
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100685 self.nextSibling = self.previousSibling = None
Fred Drake55c38192000-06-29 19:39:57 +0000686
Martin v. Löwis7b771882012-02-19 20:55:05 +0100687 # Attribute dictionaries are lazily created
688 # attributes are double-indexed:
689 # tagName -> Attribute
690 # URI,localName -> Attribute
691 # in the future: consider lazy generation
692 # of attribute objects this is too tricky
693 # for now because of headaches with
694 # namespaces.
695 self._attrs = None
696 self._attrsNS = None
697
698 def _ensure_attributes(self):
699 if self._attrs is None:
700 self._attrs = {}
701 self._attrsNS = {}
Fred Drake4ccf4a12000-11-21 22:02:22 +0000702
Martin v. Löwis787354c2003-01-25 15:28:29 +0000703 def _get_localName(self):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100704 try:
705 return self._localName
706 except AttributeError:
707 return self.tagName.split(":", 1)[-1]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000708
709 def _get_tagName(self):
710 return self.tagName
Fred Drake4ccf4a12000-11-21 22:02:22 +0000711
712 def unlink(self):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100713 if self._attrs is not None:
714 for attr in list(self._attrs.values()):
715 attr.unlink()
Fred Drake4ccf4a12000-11-21 22:02:22 +0000716 self._attrs = None
717 self._attrsNS = None
718 Node.unlink(self)
Fred Drake55c38192000-06-29 19:39:57 +0000719
Fred Drake1f549022000-09-24 05:21:58 +0000720 def getAttribute(self, attname):
Martin v. Löwis67245a62012-03-05 07:01:49 +0100721 if self._attrs is None:
722 return ""
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000723 try:
724 return self._attrs[attname].value
725 except KeyError:
726 return ""
Fred Drake55c38192000-06-29 19:39:57 +0000727
Fred Drake1f549022000-09-24 05:21:58 +0000728 def getAttributeNS(self, namespaceURI, localName):
Martin v. Löwis67245a62012-03-05 07:01:49 +0100729 if self._attrsNS is None:
730 return ""
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000731 try:
732 return self._attrsNS[(namespaceURI, localName)].value
733 except KeyError:
734 return ""
Fred Drake1f549022000-09-24 05:21:58 +0000735
736 def setAttribute(self, attname, value):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000737 attr = self.getAttributeNode(attname)
738 if attr is None:
739 attr = Attr(attname)
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100740 attr.value = value # also sets nodeValue
741 attr.ownerDocument = self.ownerDocument
Martin v. Löwis787354c2003-01-25 15:28:29 +0000742 self.setAttributeNode(attr)
743 elif value != attr.value:
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100744 attr.value = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000745 if attr.isId:
746 _clear_id_cache(self)
Fred Drake55c38192000-06-29 19:39:57 +0000747
Fred Drake1f549022000-09-24 05:21:58 +0000748 def setAttributeNS(self, namespaceURI, qualifiedName, value):
749 prefix, localname = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000750 attr = self.getAttributeNodeNS(namespaceURI, localname)
751 if attr is None:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000752 attr = Attr(qualifiedName, namespaceURI, localname, prefix)
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100753 attr.value = value
754 attr.ownerDocument = self.ownerDocument
Martin v. Löwis787354c2003-01-25 15:28:29 +0000755 self.setAttributeNode(attr)
756 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000757 if value != attr.value:
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100758 attr.value = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000759 if attr.isId:
760 _clear_id_cache(self)
761 if attr.prefix != prefix:
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100762 attr.prefix = prefix
763 attr.nodeName = qualifiedName
Fred Drake55c38192000-06-29 19:39:57 +0000764
Fred Drake1f549022000-09-24 05:21:58 +0000765 def getAttributeNode(self, attrname):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100766 if self._attrs is None:
767 return None
Fred Drake1f549022000-09-24 05:21:58 +0000768 return self._attrs.get(attrname)
Paul Prescod73678da2000-07-01 04:58:47 +0000769
Fred Drake1f549022000-09-24 05:21:58 +0000770 def getAttributeNodeNS(self, namespaceURI, localName):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100771 if self._attrsNS is None:
772 return None
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000773 return self._attrsNS.get((namespaceURI, localName))
Paul Prescod73678da2000-07-01 04:58:47 +0000774
Fred Drake1f549022000-09-24 05:21:58 +0000775 def setAttributeNode(self, attr):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000776 if attr.ownerElement not in (None, self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000777 raise xml.dom.InuseAttributeErr("attribute node already owned")
Martin v. Löwis7b771882012-02-19 20:55:05 +0100778 self._ensure_attributes()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000779 old1 = self._attrs.get(attr.name, None)
780 if old1 is not None:
781 self.removeAttributeNode(old1)
782 old2 = self._attrsNS.get((attr.namespaceURI, attr.localName), None)
783 if old2 is not None and old2 is not old1:
784 self.removeAttributeNode(old2)
785 _set_attribute_node(self, attr)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000786
Martin v. Löwis787354c2003-01-25 15:28:29 +0000787 if old1 is not attr:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000788 # It might have already been part of this node, in which case
789 # it doesn't represent a change, and should not be returned.
Martin v. Löwis787354c2003-01-25 15:28:29 +0000790 return old1
791 if old2 is not attr:
792 return old2
Fred Drake55c38192000-06-29 19:39:57 +0000793
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000794 setAttributeNodeNS = setAttributeNode
795
Fred Drake1f549022000-09-24 05:21:58 +0000796 def removeAttribute(self, name):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100797 if self._attrsNS is None:
798 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000799 try:
800 attr = self._attrs[name]
801 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000802 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000803 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000804
Fred Drake1f549022000-09-24 05:21:58 +0000805 def removeAttributeNS(self, namespaceURI, localName):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100806 if self._attrsNS is None:
807 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000808 try:
809 attr = self._attrsNS[(namespaceURI, localName)]
810 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000811 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000812 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000813
Fred Drake1f549022000-09-24 05:21:58 +0000814 def removeAttributeNode(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000815 if node is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000816 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000817 try:
818 self._attrs[node.name]
819 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000820 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000821 _clear_id_cache(self)
Paul Prescod73678da2000-07-01 04:58:47 +0000822 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000823 # Restore this since the node is still useful and otherwise
824 # unlinked
825 node.ownerDocument = self.ownerDocument
arikrupnik5bfa0582018-06-06 23:42:38 -0500826 return node
Fred Drake16f63292000-10-23 18:09:50 +0000827
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000828 removeAttributeNodeNS = removeAttributeNode
829
Martin v. Löwis156c3372000-12-28 18:40:56 +0000830 def hasAttribute(self, name):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100831 if self._attrs is None:
832 return False
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000833 return name in self._attrs
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000834
Martin v. Löwis156c3372000-12-28 18:40:56 +0000835 def hasAttributeNS(self, namespaceURI, localName):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100836 if self._attrsNS is None:
837 return False
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000838 return (namespaceURI, localName) in self._attrsNS
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000839
Fred Drake1f549022000-09-24 05:21:58 +0000840 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000841 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000842
Fred Drake1f549022000-09-24 05:21:58 +0000843 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000844 return _get_elements_by_tagName_ns_helper(
845 self, namespaceURI, localName, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000846
Fred Drake1f549022000-09-24 05:21:58 +0000847 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000848 return "<DOM Element: %s at %#x>" % (self.tagName, id(self))
Fred Drake55c38192000-06-29 19:39:57 +0000849
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000850 def writexml(self, writer, indent="", addindent="", newl=""):
851 # indent = current indentation
852 # addindent = indentation to add to higher levels
853 # newl = newline string
854 writer.write(indent+"<" + self.tagName)
Fred Drake16f63292000-10-23 18:09:50 +0000855
Fred Drake4ccf4a12000-11-21 22:02:22 +0000856 attrs = self._get_attributes()
Fred Drake55c38192000-06-29 19:39:57 +0000857
Diego Rojas5598cc92018-11-07 09:09:04 -0500858 for a_name in attrs.keys():
Fred Drake1f549022000-09-24 05:21:58 +0000859 writer.write(" %s=\"" % a_name)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000860 _write_data(writer, attrs[a_name].value)
Fred Drake55c38192000-06-29 19:39:57 +0000861 writer.write("\"")
862 if self.childNodes:
R David Murray791744b2011-10-01 16:19:51 -0400863 writer.write(">")
Ezio Melotti8008f2a2011-11-18 17:34:26 +0200864 if (len(self.childNodes) == 1 and
Vladimir Surjaninov384b81d2019-03-27 08:58:49 +0300865 self.childNodes[0].nodeType in (
866 Node.TEXT_NODE, Node.CDATA_SECTION_NODE)):
Ezio Melotti8008f2a2011-11-18 17:34:26 +0200867 self.childNodes[0].writexml(writer, '', '', '')
868 else:
R David Murray791744b2011-10-01 16:19:51 -0400869 writer.write(newl)
Ezio Melotti8008f2a2011-11-18 17:34:26 +0200870 for node in self.childNodes:
871 node.writexml(writer, indent+addindent, addindent, newl)
872 writer.write(indent)
873 writer.write("</%s>%s" % (self.tagName, newl))
Fred Drake55c38192000-06-29 19:39:57 +0000874 else:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000875 writer.write("/>%s"%(newl))
Fred Drake55c38192000-06-29 19:39:57 +0000876
Fred Drake1f549022000-09-24 05:21:58 +0000877 def _get_attributes(self):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100878 self._ensure_attributes()
Fred Drake2998a552001-12-06 18:27:48 +0000879 return NamedNodeMap(self._attrs, self._attrsNS, self)
Fred Drake55c38192000-06-29 19:39:57 +0000880
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000881 def hasAttributes(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000882 if self._attrs:
883 return True
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000884 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000885 return False
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000886
Martin v. Löwis787354c2003-01-25 15:28:29 +0000887 # DOM Level 3 attributes, based on the 22 Oct 2002 draft
888
889 def setIdAttribute(self, name):
890 idAttr = self.getAttributeNode(name)
891 self.setIdAttributeNode(idAttr)
892
893 def setIdAttributeNS(self, namespaceURI, localName):
894 idAttr = self.getAttributeNodeNS(namespaceURI, localName)
895 self.setIdAttributeNode(idAttr)
896
897 def setIdAttributeNode(self, idAttr):
898 if idAttr is None or not self.isSameNode(idAttr.ownerElement):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000899 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000900 if _get_containing_entref(self) is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000901 raise xml.dom.NoModificationAllowedErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000902 if not idAttr._is_id:
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100903 idAttr._is_id = True
Martin v. Löwis787354c2003-01-25 15:28:29 +0000904 self._magic_id_nodes += 1
905 self.ownerDocument._magic_id_count += 1
906 _clear_id_cache(self)
907
908defproperty(Element, "attributes",
909 doc="NamedNodeMap of attributes on the element.")
910defproperty(Element, "localName",
911 doc="Namespace-local name of this element.")
912
913
914def _set_attribute_node(element, attr):
915 _clear_id_cache(element)
Martin v. Löwis7b771882012-02-19 20:55:05 +0100916 element._ensure_attributes()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000917 element._attrs[attr.name] = attr
918 element._attrsNS[(attr.namespaceURI, attr.localName)] = attr
919
920 # This creates a circular reference, but Element.unlink()
921 # breaks the cycle since the references to the attribute
922 # dictionaries are tossed.
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100923 attr.ownerElement = element
Martin v. Löwis787354c2003-01-25 15:28:29 +0000924
925class Childless:
926 """Mixin that makes childless-ness easy to implement and avoids
927 the complexity of the Node methods that deal with children.
928 """
Florent Xicluna8cf4b512012-03-05 12:37:02 +0100929 __slots__ = ()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000930
Fred Drake4ccf4a12000-11-21 22:02:22 +0000931 attributes = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000932 childNodes = EmptyNodeList()
933 firstChild = None
934 lastChild = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000935
Martin v. Löwis787354c2003-01-25 15:28:29 +0000936 def _get_firstChild(self):
937 return None
Fred Drake55c38192000-06-29 19:39:57 +0000938
Martin v. Löwis787354c2003-01-25 15:28:29 +0000939 def _get_lastChild(self):
940 return None
Fred Drake1f549022000-09-24 05:21:58 +0000941
Martin v. Löwis787354c2003-01-25 15:28:29 +0000942 def appendChild(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000943 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000944 self.nodeName + " nodes cannot have children")
945
946 def hasChildNodes(self):
947 return False
948
949 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000950 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000951 self.nodeName + " nodes do not have children")
952
953 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000954 raise xml.dom.NotFoundErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000955 self.nodeName + " nodes do not have children")
956
Andrew M. Kuchling688b9e32010-07-25 23:38:47 +0000957 def normalize(self):
958 # For childless nodes, normalize() has nothing to do.
959 pass
960
Martin v. Löwis787354c2003-01-25 15:28:29 +0000961 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000962 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000963 self.nodeName + " nodes do not have children")
964
965
966class ProcessingInstruction(Childless, Node):
Fred Drake1f549022000-09-24 05:21:58 +0000967 nodeType = Node.PROCESSING_INSTRUCTION_NODE
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100968 __slots__ = ('target', 'data')
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000969
Fred Drake1f549022000-09-24 05:21:58 +0000970 def __init__(self, target, data):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100971 self.target = target
972 self.data = data
Fred Drake55c38192000-06-29 19:39:57 +0000973
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100974 # nodeValue is an alias for data
975 def _get_nodeValue(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000976 return self.data
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100977 def _set_nodeValue(self, value):
Raymond Hettinger92a40552014-06-15 14:48:19 -0700978 self.data = value
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100979 nodeValue = property(_get_nodeValue, _set_nodeValue)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000980
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100981 # nodeName is an alias for target
982 def _get_nodeName(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000983 return self.target
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100984 def _set_nodeName(self, value):
985 self.target = value
986 nodeName = property(_get_nodeName, _set_nodeName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000987
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000988 def writexml(self, writer, indent="", addindent="", newl=""):
989 writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))
Fred Drake55c38192000-06-29 19:39:57 +0000990
Martin v. Löwis787354c2003-01-25 15:28:29 +0000991
992class CharacterData(Childless, Node):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100993 __slots__=('_data', 'ownerDocument','parentNode', 'previousSibling', 'nextSibling')
994
995 def __init__(self):
996 self.ownerDocument = self.parentNode = None
997 self.previousSibling = self.nextSibling = None
998 self._data = ''
999 Node.__init__(self)
1000
Martin v. Löwis787354c2003-01-25 15:28:29 +00001001 def _get_length(self):
1002 return len(self.data)
1003 __len__ = _get_length
1004
1005 def _get_data(self):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001006 return self._data
Martin v. Löwis787354c2003-01-25 15:28:29 +00001007 def _set_data(self, data):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001008 self._data = data
Martin v. Löwis787354c2003-01-25 15:28:29 +00001009
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001010 data = nodeValue = property(_get_data, _set_data)
Fred Drake87432f42001-04-04 14:09:46 +00001011
Fred Drake55c38192000-06-29 19:39:57 +00001012 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001013 data = self.data
1014 if len(data) > 10:
Fred Drake1f549022000-09-24 05:21:58 +00001015 dotdotdot = "..."
Fred Drake55c38192000-06-29 19:39:57 +00001016 else:
Fred Drake1f549022000-09-24 05:21:58 +00001017 dotdotdot = ""
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001018 return '<DOM %s node "%r%s">' % (
Martin v. Löwis787354c2003-01-25 15:28:29 +00001019 self.__class__.__name__, data[0:10], dotdotdot)
Fred Drake87432f42001-04-04 14:09:46 +00001020
1021 def substringData(self, offset, count):
1022 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001023 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001024 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001025 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001026 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001027 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001028 return self.data[offset:offset+count]
1029
1030 def appendData(self, arg):
1031 self.data = self.data + arg
Fred Drake87432f42001-04-04 14:09:46 +00001032
1033 def insertData(self, offset, arg):
1034 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001035 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001036 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001037 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001038 if arg:
1039 self.data = "%s%s%s" % (
1040 self.data[:offset], arg, self.data[offset:])
Fred Drake87432f42001-04-04 14:09:46 +00001041
1042 def deleteData(self, offset, count):
1043 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001044 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001045 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001046 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001047 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001048 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001049 if count:
1050 self.data = self.data[:offset] + self.data[offset+count:]
Fred Drake87432f42001-04-04 14:09:46 +00001051
1052 def replaceData(self, offset, count, arg):
1053 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001054 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001055 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001056 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001057 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001058 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001059 if count:
1060 self.data = "%s%s%s" % (
1061 self.data[:offset], arg, self.data[offset+count:])
Martin v. Löwis787354c2003-01-25 15:28:29 +00001062
1063defproperty(CharacterData, "length", doc="Length of the string data.")
1064
Fred Drake87432f42001-04-04 14:09:46 +00001065
1066class Text(CharacterData):
Florent Xicluna8cf4b512012-03-05 12:37:02 +01001067 __slots__ = ()
1068
Fred Drake87432f42001-04-04 14:09:46 +00001069 nodeType = Node.TEXT_NODE
1070 nodeName = "#text"
1071 attributes = None
Fred Drake55c38192000-06-29 19:39:57 +00001072
Fred Drakef7cf40d2000-12-14 18:16:11 +00001073 def splitText(self, offset):
1074 if offset < 0 or offset > len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001075 raise xml.dom.IndexSizeErr("illegal offset value")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001076 newText = self.__class__()
1077 newText.data = self.data[offset:]
1078 newText.ownerDocument = self.ownerDocument
Fred Drakef7cf40d2000-12-14 18:16:11 +00001079 next = self.nextSibling
1080 if self.parentNode and self in self.parentNode.childNodes:
1081 if next is None:
1082 self.parentNode.appendChild(newText)
1083 else:
1084 self.parentNode.insertBefore(newText, next)
1085 self.data = self.data[:offset]
1086 return newText
1087
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001088 def writexml(self, writer, indent="", addindent="", newl=""):
Ezio Melotti8008f2a2011-11-18 17:34:26 +02001089 _write_data(writer, "%s%s%s" % (indent, self.data, newl))
Fred Drake55c38192000-06-29 19:39:57 +00001090
Martin v. Löwis787354c2003-01-25 15:28:29 +00001091 # DOM Level 3 (WD 9 April 2002)
1092
1093 def _get_wholeText(self):
1094 L = [self.data]
1095 n = self.previousSibling
1096 while n is not None:
1097 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1098 L.insert(0, n.data)
1099 n = n.previousSibling
1100 else:
1101 break
1102 n = self.nextSibling
1103 while n is not None:
1104 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1105 L.append(n.data)
1106 n = n.nextSibling
1107 else:
1108 break
1109 return ''.join(L)
1110
1111 def replaceWholeText(self, content):
1112 # XXX This needs to be seriously changed if minidom ever
1113 # supports EntityReference nodes.
1114 parent = self.parentNode
1115 n = self.previousSibling
1116 while n is not None:
1117 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1118 next = n.previousSibling
1119 parent.removeChild(n)
1120 n = next
1121 else:
1122 break
1123 n = self.nextSibling
1124 if not content:
1125 parent.removeChild(self)
1126 while n is not None:
1127 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1128 next = n.nextSibling
1129 parent.removeChild(n)
1130 n = next
1131 else:
1132 break
1133 if content:
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001134 self.data = content
Martin v. Löwis787354c2003-01-25 15:28:29 +00001135 return self
1136 else:
1137 return None
1138
1139 def _get_isWhitespaceInElementContent(self):
1140 if self.data.strip():
1141 return False
1142 elem = _get_containing_element(self)
1143 if elem is None:
1144 return False
1145 info = self.ownerDocument._get_elem_info(elem)
1146 if info is None:
1147 return False
1148 else:
1149 return info.isElementContent()
1150
1151defproperty(Text, "isWhitespaceInElementContent",
1152 doc="True iff this text node contains only whitespace"
1153 " and is in element content.")
1154defproperty(Text, "wholeText",
1155 doc="The text of all logically-adjacent text nodes.")
1156
1157
1158def _get_containing_element(node):
1159 c = node.parentNode
1160 while c is not None:
1161 if c.nodeType == Node.ELEMENT_NODE:
1162 return c
1163 c = c.parentNode
1164 return None
1165
1166def _get_containing_entref(node):
1167 c = node.parentNode
1168 while c is not None:
1169 if c.nodeType == Node.ENTITY_REFERENCE_NODE:
1170 return c
1171 c = c.parentNode
1172 return None
1173
1174
Alex Martelli0ee43512006-08-21 19:53:20 +00001175class Comment(CharacterData):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001176 nodeType = Node.COMMENT_NODE
1177 nodeName = "#comment"
1178
1179 def __init__(self, data):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001180 CharacterData.__init__(self)
1181 self._data = data
Martin v. Löwis787354c2003-01-25 15:28:29 +00001182
1183 def writexml(self, writer, indent="", addindent="", newl=""):
Benjamin Peterson2b7411d2008-05-26 17:36:47 +00001184 if "--" in self.data:
1185 raise ValueError("'--' is not allowed in a comment node")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001186 writer.write("%s<!--%s-->%s" % (indent, self.data, newl))
1187
Fred Drake87432f42001-04-04 14:09:46 +00001188
1189class CDATASection(Text):
Florent Xicluna8cf4b512012-03-05 12:37:02 +01001190 __slots__ = ()
1191
Fred Drake87432f42001-04-04 14:09:46 +00001192 nodeType = Node.CDATA_SECTION_NODE
1193 nodeName = "#cdata-section"
1194
1195 def writexml(self, writer, indent="", addindent="", newl=""):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001196 if self.data.find("]]>") >= 0:
1197 raise ValueError("']]>' not allowed in a CDATA section")
Guido van Rossum5b5e0b92001-09-19 13:28:25 +00001198 writer.write("<![CDATA[%s]]>" % self.data)
Fred Drake87432f42001-04-04 14:09:46 +00001199
1200
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001201class ReadOnlySequentialNamedNodeMap(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001202 __slots__ = '_seq',
1203
1204 def __init__(self, seq=()):
1205 # seq should be a list or tuple
1206 self._seq = seq
1207
1208 def __len__(self):
1209 return len(self._seq)
1210
1211 def _get_length(self):
1212 return len(self._seq)
1213
1214 def getNamedItem(self, name):
1215 for n in self._seq:
1216 if n.nodeName == name:
1217 return n
1218
1219 def getNamedItemNS(self, namespaceURI, localName):
1220 for n in self._seq:
1221 if n.namespaceURI == namespaceURI and n.localName == localName:
1222 return n
1223
1224 def __getitem__(self, name_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001225 if isinstance(name_or_tuple, tuple):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001226 node = self.getNamedItemNS(*name_or_tuple)
1227 else:
1228 node = self.getNamedItem(name_or_tuple)
1229 if node is None:
Collin Winter70e79802007-08-24 18:57:22 +00001230 raise KeyError(name_or_tuple)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001231 return node
1232
1233 def item(self, index):
1234 if index < 0:
1235 return None
1236 try:
1237 return self._seq[index]
1238 except IndexError:
1239 return None
1240
1241 def removeNamedItem(self, name):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001242 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001243 "NamedNodeMap instance is read-only")
1244
1245 def removeNamedItemNS(self, namespaceURI, localName):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001246 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001247 "NamedNodeMap instance is read-only")
1248
1249 def setNamedItem(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001250 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001251 "NamedNodeMap instance is read-only")
1252
1253 def setNamedItemNS(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001254 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001255 "NamedNodeMap instance is read-only")
1256
1257 def __getstate__(self):
1258 return [self._seq]
1259
1260 def __setstate__(self, state):
1261 self._seq = state[0]
1262
1263defproperty(ReadOnlySequentialNamedNodeMap, "length",
1264 doc="Number of entries in the NamedNodeMap.")
Paul Prescod73678da2000-07-01 04:58:47 +00001265
Fred Drakef7cf40d2000-12-14 18:16:11 +00001266
Martin v. Löwis787354c2003-01-25 15:28:29 +00001267class Identified:
1268 """Mix-in class that supports the publicId and systemId attributes."""
1269
Florent Xicluna8cf4b512012-03-05 12:37:02 +01001270 __slots__ = 'publicId', 'systemId'
Martin v. Löwis787354c2003-01-25 15:28:29 +00001271
1272 def _identified_mixin_init(self, publicId, systemId):
1273 self.publicId = publicId
1274 self.systemId = systemId
1275
1276 def _get_publicId(self):
1277 return self.publicId
1278
1279 def _get_systemId(self):
1280 return self.systemId
1281
1282class DocumentType(Identified, Childless, Node):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001283 nodeType = Node.DOCUMENT_TYPE_NODE
1284 nodeValue = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001285 name = None
1286 publicId = None
1287 systemId = None
Fred Drakedc806702001-04-05 14:41:30 +00001288 internalSubset = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001289
1290 def __init__(self, qualifiedName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001291 self.entities = ReadOnlySequentialNamedNodeMap()
1292 self.notations = ReadOnlySequentialNamedNodeMap()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001293 if qualifiedName:
1294 prefix, localname = _nssplit(qualifiedName)
1295 self.name = localname
Martin v. Löwis787354c2003-01-25 15:28:29 +00001296 self.nodeName = self.name
1297
1298 def _get_internalSubset(self):
1299 return self.internalSubset
1300
1301 def cloneNode(self, deep):
1302 if self.ownerDocument is None:
1303 # it's ok
1304 clone = DocumentType(None)
1305 clone.name = self.name
1306 clone.nodeName = self.name
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001307 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001308 if deep:
1309 clone.entities._seq = []
1310 clone.notations._seq = []
1311 for n in self.notations._seq:
1312 notation = Notation(n.nodeName, n.publicId, n.systemId)
1313 clone.notations._seq.append(notation)
1314 n._call_user_data_handler(operation, n, notation)
1315 for e in self.entities._seq:
1316 entity = Entity(e.nodeName, e.publicId, e.systemId,
1317 e.notationName)
1318 entity.actualEncoding = e.actualEncoding
1319 entity.encoding = e.encoding
1320 entity.version = e.version
1321 clone.entities._seq.append(entity)
Victor Stinner8e041862018-12-10 11:12:53 +01001322 e._call_user_data_handler(operation, e, entity)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001323 self._call_user_data_handler(operation, self, clone)
1324 return clone
1325 else:
1326 return None
1327
1328 def writexml(self, writer, indent="", addindent="", newl=""):
1329 writer.write("<!DOCTYPE ")
1330 writer.write(self.name)
1331 if self.publicId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001332 writer.write("%s PUBLIC '%s'%s '%s'"
1333 % (newl, self.publicId, newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001334 elif self.systemId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001335 writer.write("%s SYSTEM '%s'" % (newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001336 if self.internalSubset is not None:
1337 writer.write(" [")
1338 writer.write(self.internalSubset)
1339 writer.write("]")
Georg Brandl175a7dc2005-08-25 22:02:43 +00001340 writer.write(">"+newl)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001341
1342class Entity(Identified, Node):
1343 attributes = None
1344 nodeType = Node.ENTITY_NODE
1345 nodeValue = None
1346
1347 actualEncoding = None
1348 encoding = None
1349 version = None
1350
1351 def __init__(self, name, publicId, systemId, notation):
1352 self.nodeName = name
1353 self.notationName = notation
1354 self.childNodes = NodeList()
1355 self._identified_mixin_init(publicId, systemId)
1356
1357 def _get_actualEncoding(self):
1358 return self.actualEncoding
1359
1360 def _get_encoding(self):
1361 return self.encoding
1362
1363 def _get_version(self):
1364 return self.version
1365
1366 def appendChild(self, newChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001367 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001368 "cannot append children to an entity node")
1369
1370 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001371 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001372 "cannot insert children below an entity node")
1373
1374 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001375 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001376 "cannot remove children from an entity node")
1377
1378 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001379 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001380 "cannot replace children of an entity node")
1381
1382class Notation(Identified, Childless, Node):
1383 nodeType = Node.NOTATION_NODE
1384 nodeValue = None
1385
1386 def __init__(self, name, publicId, systemId):
1387 self.nodeName = name
1388 self._identified_mixin_init(publicId, systemId)
Fred Drakef7cf40d2000-12-14 18:16:11 +00001389
1390
Martin v. Löwis787354c2003-01-25 15:28:29 +00001391class DOMImplementation(DOMImplementationLS):
1392 _features = [("core", "1.0"),
1393 ("core", "2.0"),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001394 ("core", None),
1395 ("xml", "1.0"),
1396 ("xml", "2.0"),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001397 ("xml", None),
1398 ("ls-load", "3.0"),
1399 ("ls-load", None),
1400 ]
1401
Fred Drakef7cf40d2000-12-14 18:16:11 +00001402 def hasFeature(self, feature, version):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001403 if version == "":
1404 version = None
1405 return (feature.lower(), version) in self._features
Fred Drakef7cf40d2000-12-14 18:16:11 +00001406
1407 def createDocument(self, namespaceURI, qualifiedName, doctype):
1408 if doctype and doctype.parentNode is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001409 raise xml.dom.WrongDocumentErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001410 "doctype object owned by another DOM tree")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001411 doc = self._create_document()
1412
1413 add_root_element = not (namespaceURI is None
1414 and qualifiedName is None
1415 and doctype is None)
1416
1417 if not qualifiedName and add_root_element:
Martin v. Löwisb417be22001-02-06 01:16:06 +00001418 # The spec is unclear what to raise here; SyntaxErr
1419 # would be the other obvious candidate. Since Xerces raises
1420 # InvalidCharacterErr, and since SyntaxErr is not listed
1421 # for createDocument, that seems to be the better choice.
1422 # XXX: need to check for illegal characters here and in
1423 # createElement.
Martin v. Löwis787354c2003-01-25 15:28:29 +00001424
1425 # DOM Level III clears this up when talking about the return value
1426 # of this function. If namespaceURI, qName and DocType are
1427 # Null the document is returned without a document element
1428 # Otherwise if doctype or namespaceURI are not None
1429 # Then we go back to the above problem
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001430 raise xml.dom.InvalidCharacterErr("Element with no name")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001431
1432 if add_root_element:
1433 prefix, localname = _nssplit(qualifiedName)
1434 if prefix == "xml" \
1435 and namespaceURI != "http://www.w3.org/XML/1998/namespace":
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001436 raise xml.dom.NamespaceErr("illegal use of 'xml' prefix")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001437 if prefix and not namespaceURI:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001438 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001439 "illegal use of prefix without namespaces")
1440 element = doc.createElementNS(namespaceURI, qualifiedName)
1441 if doctype:
1442 doc.appendChild(doctype)
1443 doc.appendChild(element)
1444
1445 if doctype:
1446 doctype.parentNode = doctype.ownerDocument = doc
1447
Fred Drakef7cf40d2000-12-14 18:16:11 +00001448 doc.doctype = doctype
1449 doc.implementation = self
1450 return doc
1451
1452 def createDocumentType(self, qualifiedName, publicId, systemId):
1453 doctype = DocumentType(qualifiedName)
1454 doctype.publicId = publicId
1455 doctype.systemId = systemId
1456 return doctype
1457
Martin v. Löwis787354c2003-01-25 15:28:29 +00001458 # DOM Level 3 (WD 9 April 2002)
1459
1460 def getInterface(self, feature):
1461 if self.hasFeature(feature, None):
1462 return self
1463 else:
1464 return None
1465
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001466 # internal
Martin v. Löwis787354c2003-01-25 15:28:29 +00001467 def _create_document(self):
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001468 return Document()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001469
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001470class ElementInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001471 """Object that represents content-model information for an element.
1472
1473 This implementation is not expected to be used in practice; DOM
1474 builders should provide implementations which do the right thing
1475 using information available to it.
1476
1477 """
1478
1479 __slots__ = 'tagName',
1480
1481 def __init__(self, name):
1482 self.tagName = name
1483
1484 def getAttributeType(self, aname):
1485 return _no_type
1486
1487 def getAttributeTypeNS(self, namespaceURI, localName):
1488 return _no_type
1489
1490 def isElementContent(self):
1491 return False
1492
1493 def isEmpty(self):
1494 """Returns true iff this element is declared to have an EMPTY
1495 content model."""
1496 return False
1497
1498 def isId(self, aname):
Ezio Melotti42da6632011-03-15 05:18:48 +02001499 """Returns true iff the named attribute is a DTD-style ID."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001500 return False
1501
1502 def isIdNS(self, namespaceURI, localName):
1503 """Returns true iff the identified attribute is a DTD-style ID."""
1504 return False
1505
1506 def __getstate__(self):
1507 return self.tagName
1508
1509 def __setstate__(self, state):
1510 self.tagName = state
1511
1512def _clear_id_cache(node):
1513 if node.nodeType == Node.DOCUMENT_NODE:
1514 node._id_cache.clear()
1515 node._id_search_stack = None
1516 elif _in_document(node):
1517 node.ownerDocument._id_cache.clear()
1518 node.ownerDocument._id_search_stack= None
1519
1520class Document(Node, DocumentLS):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001521 __slots__ = ('_elem_info', 'doctype',
1522 '_id_search_stack', 'childNodes', '_id_cache')
Martin v. Löwis787354c2003-01-25 15:28:29 +00001523 _child_node_types = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
1524 Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)
1525
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001526 implementation = DOMImplementation()
Fred Drake1f549022000-09-24 05:21:58 +00001527 nodeType = Node.DOCUMENT_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +00001528 nodeName = "#document"
1529 nodeValue = None
1530 attributes = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001531 parentNode = None
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001532 previousSibling = nextSibling = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001533
Martin v. Löwis787354c2003-01-25 15:28:29 +00001534
1535 # Document attributes from Level 3 (WD 9 April 2002)
1536
1537 actualEncoding = None
1538 encoding = None
1539 standalone = None
1540 version = None
1541 strictErrorChecking = False
1542 errorHandler = None
1543 documentURI = None
1544
1545 _magic_id_count = 0
1546
1547 def __init__(self):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001548 self.doctype = None
Martin v. Löwis787354c2003-01-25 15:28:29 +00001549 self.childNodes = NodeList()
1550 # mapping of (namespaceURI, localName) -> ElementInfo
1551 # and tagName -> ElementInfo
1552 self._elem_info = {}
1553 self._id_cache = {}
1554 self._id_search_stack = None
1555
1556 def _get_elem_info(self, element):
1557 if element.namespaceURI:
1558 key = element.namespaceURI, element.localName
1559 else:
1560 key = element.tagName
1561 return self._elem_info.get(key)
1562
1563 def _get_actualEncoding(self):
1564 return self.actualEncoding
1565
1566 def _get_doctype(self):
1567 return self.doctype
1568
1569 def _get_documentURI(self):
1570 return self.documentURI
1571
1572 def _get_encoding(self):
1573 return self.encoding
1574
1575 def _get_errorHandler(self):
1576 return self.errorHandler
1577
1578 def _get_standalone(self):
1579 return self.standalone
1580
1581 def _get_strictErrorChecking(self):
1582 return self.strictErrorChecking
1583
1584 def _get_version(self):
1585 return self.version
Fred Drake55c38192000-06-29 19:39:57 +00001586
Fred Drake1f549022000-09-24 05:21:58 +00001587 def appendChild(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001588 if node.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001589 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001590 "%s cannot be child of %s" % (repr(node), repr(self)))
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001591 if node.parentNode is not None:
Martin v. Löwis787354c2003-01-25 15:28:29 +00001592 # This needs to be done before the next test since this
1593 # may *be* the document element, in which case it should
1594 # end up re-ordered to the end.
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001595 node.parentNode.removeChild(node)
1596
Fred Drakef7cf40d2000-12-14 18:16:11 +00001597 if node.nodeType == Node.ELEMENT_NODE \
1598 and self._get_documentElement():
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001599 raise xml.dom.HierarchyRequestErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001600 "two document elements disallowed")
Fred Drake4ccf4a12000-11-21 22:02:22 +00001601 return Node.appendChild(self, node)
Paul Prescod73678da2000-07-01 04:58:47 +00001602
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001603 def removeChild(self, oldChild):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001604 try:
1605 self.childNodes.remove(oldChild)
1606 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001607 raise xml.dom.NotFoundErr()
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001608 oldChild.nextSibling = oldChild.previousSibling = None
1609 oldChild.parentNode = None
1610 if self.documentElement is oldChild:
1611 self.documentElement = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +00001612
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001613 return oldChild
1614
Fred Drakef7cf40d2000-12-14 18:16:11 +00001615 def _get_documentElement(self):
1616 for node in self.childNodes:
1617 if node.nodeType == Node.ELEMENT_NODE:
1618 return node
1619
1620 def unlink(self):
1621 if self.doctype is not None:
1622 self.doctype.unlink()
1623 self.doctype = None
1624 Node.unlink(self)
1625
Martin v. Löwis787354c2003-01-25 15:28:29 +00001626 def cloneNode(self, deep):
1627 if not deep:
1628 return None
1629 clone = self.implementation.createDocument(None, None, None)
1630 clone.encoding = self.encoding
1631 clone.standalone = self.standalone
1632 clone.version = self.version
1633 for n in self.childNodes:
1634 childclone = _clone_node(n, deep, clone)
1635 assert childclone.ownerDocument.isSameNode(clone)
1636 clone.childNodes.append(childclone)
1637 if childclone.nodeType == Node.DOCUMENT_NODE:
1638 assert clone.documentElement is None
1639 elif childclone.nodeType == Node.DOCUMENT_TYPE_NODE:
1640 assert clone.doctype is None
1641 clone.doctype = childclone
1642 childclone.parentNode = clone
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001643 self._call_user_data_handler(xml.dom.UserDataHandler.NODE_CLONED,
Martin v. Löwis787354c2003-01-25 15:28:29 +00001644 self, clone)
1645 return clone
1646
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001647 def createDocumentFragment(self):
1648 d = DocumentFragment()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001649 d.ownerDocument = self
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001650 return d
Fred Drake55c38192000-06-29 19:39:57 +00001651
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001652 def createElement(self, tagName):
1653 e = Element(tagName)
1654 e.ownerDocument = self
1655 return e
Fred Drake55c38192000-06-29 19:39:57 +00001656
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001657 def createTextNode(self, data):
Christian Heimesc9543e42007-11-28 08:28:28 +00001658 if not isinstance(data, str):
Collin Winter70e79802007-08-24 18:57:22 +00001659 raise TypeError("node contents must be a string")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001660 t = Text()
1661 t.data = data
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001662 t.ownerDocument = self
1663 return t
Fred Drake55c38192000-06-29 19:39:57 +00001664
Fred Drake87432f42001-04-04 14:09:46 +00001665 def createCDATASection(self, data):
Christian Heimesc9543e42007-11-28 08:28:28 +00001666 if not isinstance(data, str):
Collin Winter70e79802007-08-24 18:57:22 +00001667 raise TypeError("node contents must be a string")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001668 c = CDATASection()
1669 c.data = data
Fred Drake87432f42001-04-04 14:09:46 +00001670 c.ownerDocument = self
1671 return c
1672
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001673 def createComment(self, data):
1674 c = Comment(data)
1675 c.ownerDocument = self
1676 return c
Fred Drake55c38192000-06-29 19:39:57 +00001677
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001678 def createProcessingInstruction(self, target, data):
1679 p = ProcessingInstruction(target, data)
1680 p.ownerDocument = self
1681 return p
1682
1683 def createAttribute(self, qName):
1684 a = Attr(qName)
1685 a.ownerDocument = self
Martin v. Löwiscb67ea12001-03-31 16:30:40 +00001686 a.value = ""
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001687 return a
Fred Drake55c38192000-06-29 19:39:57 +00001688
1689 def createElementNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001690 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001691 e = Element(qualifiedName, namespaceURI, prefix)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001692 e.ownerDocument = self
1693 return e
Fred Drake55c38192000-06-29 19:39:57 +00001694
1695 def createAttributeNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001696 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001697 a = Attr(qualifiedName, namespaceURI, localName, prefix)
1698 a.ownerDocument = self
Martin v. Löwiscb67ea12001-03-31 16:30:40 +00001699 a.value = ""
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001700 return a
Fred Drake55c38192000-06-29 19:39:57 +00001701
Martin v. Löwis787354c2003-01-25 15:28:29 +00001702 # A couple of implementation-specific helpers to create node types
1703 # not supported by the W3C DOM specs:
1704
1705 def _create_entity(self, name, publicId, systemId, notationName):
1706 e = Entity(name, publicId, systemId, notationName)
1707 e.ownerDocument = self
1708 return e
1709
1710 def _create_notation(self, name, publicId, systemId):
1711 n = Notation(name, publicId, systemId)
1712 n.ownerDocument = self
1713 return n
1714
1715 def getElementById(self, id):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +00001716 if id in self._id_cache:
Martin v. Löwis787354c2003-01-25 15:28:29 +00001717 return self._id_cache[id]
1718 if not (self._elem_info or self._magic_id_count):
1719 return None
1720
1721 stack = self._id_search_stack
1722 if stack is None:
1723 # we never searched before, or the cache has been cleared
1724 stack = [self.documentElement]
1725 self._id_search_stack = stack
1726 elif not stack:
1727 # Previous search was completed and cache is still valid;
1728 # no matching node.
1729 return None
1730
1731 result = None
1732 while stack:
1733 node = stack.pop()
1734 # add child elements to stack for continued searching
1735 stack.extend([child for child in node.childNodes
1736 if child.nodeType in _nodeTypes_with_children])
1737 # check this node
1738 info = self._get_elem_info(node)
1739 if info:
1740 # We have to process all ID attributes before
1741 # returning in order to get all the attributes set to
1742 # be IDs using Element.setIdAttribute*().
1743 for attr in node.attributes.values():
1744 if attr.namespaceURI:
1745 if info.isIdNS(attr.namespaceURI, attr.localName):
1746 self._id_cache[attr.value] = node
1747 if attr.value == id:
1748 result = node
1749 elif not node._magic_id_nodes:
1750 break
1751 elif info.isId(attr.name):
1752 self._id_cache[attr.value] = node
1753 if attr.value == id:
1754 result = node
1755 elif not node._magic_id_nodes:
1756 break
1757 elif attr._is_id:
1758 self._id_cache[attr.value] = node
1759 if attr.value == id:
1760 result = node
1761 elif node._magic_id_nodes == 1:
1762 break
1763 elif node._magic_id_nodes:
1764 for attr in node.attributes.values():
1765 if attr._is_id:
1766 self._id_cache[attr.value] = node
1767 if attr.value == id:
1768 result = node
1769 if result is not None:
1770 break
1771 return result
1772
Fred Drake1f549022000-09-24 05:21:58 +00001773 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001774 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drakefbe7b4f2001-07-04 06:25:53 +00001775
1776 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001777 return _get_elements_by_tagName_ns_helper(
1778 self, namespaceURI, localName, NodeList())
1779
1780 def isSupported(self, feature, version):
1781 return self.implementation.hasFeature(feature, version)
1782
1783 def importNode(self, node, deep):
1784 if node.nodeType == Node.DOCUMENT_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001785 raise xml.dom.NotSupportedErr("cannot import document nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001786 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001787 raise xml.dom.NotSupportedErr("cannot import document type nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001788 return _clone_node(node, deep, self)
Fred Drake55c38192000-06-29 19:39:57 +00001789
Eli Bendersky8a805022012-07-13 09:52:39 +03001790 def writexml(self, writer, indent="", addindent="", newl="", encoding=None):
Martin v. Löwis7d650ca2002-06-30 15:05:00 +00001791 if encoding is None:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001792 writer.write('<?xml version="1.0" ?>'+newl)
Martin v. Löwis7d650ca2002-06-30 15:05:00 +00001793 else:
Eli Bendersky8a805022012-07-13 09:52:39 +03001794 writer.write('<?xml version="1.0" encoding="%s"?>%s' % (
1795 encoding, newl))
Fred Drake55c38192000-06-29 19:39:57 +00001796 for node in self.childNodes:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001797 node.writexml(writer, indent, addindent, newl)
Fred Drake55c38192000-06-29 19:39:57 +00001798
Martin v. Löwis787354c2003-01-25 15:28:29 +00001799 # DOM Level 3 (WD 9 April 2002)
1800
1801 def renameNode(self, n, namespaceURI, name):
1802 if n.ownerDocument is not self:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001803 raise xml.dom.WrongDocumentErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001804 "cannot rename nodes from other documents;\n"
1805 "expected %s,\nfound %s" % (self, n.ownerDocument))
1806 if n.nodeType not in (Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001807 raise xml.dom.NotSupportedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001808 "renameNode() only applies to element and attribute nodes")
1809 if namespaceURI != EMPTY_NAMESPACE:
1810 if ':' in name:
1811 prefix, localName = name.split(':', 1)
1812 if ( prefix == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001813 and namespaceURI != xml.dom.XMLNS_NAMESPACE):
1814 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001815 "illegal use of 'xmlns' prefix")
1816 else:
1817 if ( name == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001818 and namespaceURI != xml.dom.XMLNS_NAMESPACE
Martin v. Löwis787354c2003-01-25 15:28:29 +00001819 and n.nodeType == Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001820 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001821 "illegal use of the 'xmlns' attribute")
1822 prefix = None
1823 localName = name
1824 else:
1825 prefix = None
1826 localName = None
1827 if n.nodeType == Node.ATTRIBUTE_NODE:
1828 element = n.ownerElement
1829 if element is not None:
1830 is_id = n._is_id
1831 element.removeAttributeNode(n)
1832 else:
1833 element = None
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001834 n.prefix = prefix
1835 n._localName = localName
1836 n.namespaceURI = namespaceURI
1837 n.nodeName = name
Martin v. Löwis787354c2003-01-25 15:28:29 +00001838 if n.nodeType == Node.ELEMENT_NODE:
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001839 n.tagName = name
Martin v. Löwis787354c2003-01-25 15:28:29 +00001840 else:
1841 # attribute node
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001842 n.name = name
Martin v. Löwis787354c2003-01-25 15:28:29 +00001843 if element is not None:
1844 element.setAttributeNode(n)
1845 if is_id:
1846 element.setIdAttributeNode(n)
1847 # It's not clear from a semantic perspective whether we should
1848 # call the user data handlers for the NODE_RENAMED event since
1849 # we're re-using the existing node. The draft spec has been
1850 # interpreted as meaning "no, don't call the handler unless a
1851 # new node is created."
1852 return n
1853
1854defproperty(Document, "documentElement",
1855 doc="Top-level element of this document.")
1856
1857
1858def _clone_node(node, deep, newOwnerDocument):
1859 """
1860 Clone a node and give it the new owner document.
1861 Called by Node.cloneNode and Document.importNode
1862 """
1863 if node.ownerDocument.isSameNode(newOwnerDocument):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001864 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001865 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001866 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001867 if node.nodeType == Node.ELEMENT_NODE:
1868 clone = newOwnerDocument.createElementNS(node.namespaceURI,
1869 node.nodeName)
1870 for attr in node.attributes.values():
1871 clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value)
1872 a = clone.getAttributeNodeNS(attr.namespaceURI, attr.localName)
1873 a.specified = attr.specified
1874
1875 if deep:
1876 for child in node.childNodes:
1877 c = _clone_node(child, deep, newOwnerDocument)
1878 clone.appendChild(c)
1879
1880 elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
1881 clone = newOwnerDocument.createDocumentFragment()
1882 if deep:
1883 for child in node.childNodes:
1884 c = _clone_node(child, deep, newOwnerDocument)
1885 clone.appendChild(c)
1886
1887 elif node.nodeType == Node.TEXT_NODE:
1888 clone = newOwnerDocument.createTextNode(node.data)
1889 elif node.nodeType == Node.CDATA_SECTION_NODE:
1890 clone = newOwnerDocument.createCDATASection(node.data)
1891 elif node.nodeType == Node.PROCESSING_INSTRUCTION_NODE:
1892 clone = newOwnerDocument.createProcessingInstruction(node.target,
1893 node.data)
1894 elif node.nodeType == Node.COMMENT_NODE:
1895 clone = newOwnerDocument.createComment(node.data)
1896 elif node.nodeType == Node.ATTRIBUTE_NODE:
1897 clone = newOwnerDocument.createAttributeNS(node.namespaceURI,
1898 node.nodeName)
1899 clone.specified = True
1900 clone.value = node.value
1901 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
1902 assert node.ownerDocument is not newOwnerDocument
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001903 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001904 clone = newOwnerDocument.implementation.createDocumentType(
1905 node.name, node.publicId, node.systemId)
1906 clone.ownerDocument = newOwnerDocument
1907 if deep:
1908 clone.entities._seq = []
1909 clone.notations._seq = []
1910 for n in node.notations._seq:
1911 notation = Notation(n.nodeName, n.publicId, n.systemId)
1912 notation.ownerDocument = newOwnerDocument
1913 clone.notations._seq.append(notation)
1914 if hasattr(n, '_call_user_data_handler'):
1915 n._call_user_data_handler(operation, n, notation)
1916 for e in node.entities._seq:
1917 entity = Entity(e.nodeName, e.publicId, e.systemId,
1918 e.notationName)
1919 entity.actualEncoding = e.actualEncoding
1920 entity.encoding = e.encoding
1921 entity.version = e.version
1922 entity.ownerDocument = newOwnerDocument
1923 clone.entities._seq.append(entity)
1924 if hasattr(e, '_call_user_data_handler'):
Victor Stinner8e041862018-12-10 11:12:53 +01001925 e._call_user_data_handler(operation, e, entity)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001926 else:
1927 # Note the cloning of Document and DocumentType nodes is
Ezio Melotti13925002011-03-16 11:05:33 +02001928 # implementation specific. minidom handles those cases
Martin v. Löwis787354c2003-01-25 15:28:29 +00001929 # directly in the cloneNode() methods.
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001930 raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001931
1932 # Check for _call_user_data_handler() since this could conceivably
1933 # used with other DOM implementations (one of the FourThought
1934 # DOMs, perhaps?).
1935 if hasattr(node, '_call_user_data_handler'):
1936 node._call_user_data_handler(operation, node, clone)
1937 return clone
1938
1939
1940def _nssplit(qualifiedName):
1941 fields = qualifiedName.split(':', 1)
1942 if len(fields) == 2:
1943 return fields
1944 else:
1945 return (None, fields[0])
1946
1947
Martin v. Löwis787354c2003-01-25 15:28:29 +00001948def _do_pulldom_parse(func, args, kwargs):
Raymond Hettingerff41c482003-04-06 09:01:11 +00001949 events = func(*args, **kwargs)
Fred Drake1f549022000-09-24 05:21:58 +00001950 toktype, rootNode = events.getEvent()
1951 events.expandNode(rootNode)
Martin v. Löwisb417be22001-02-06 01:16:06 +00001952 events.clear()
Fred Drake55c38192000-06-29 19:39:57 +00001953 return rootNode
1954
Martin v. Löwis787354c2003-01-25 15:28:29 +00001955def parse(file, parser=None, bufsize=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001956 """Parse a file into a DOM by filename or file object."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001957 if parser is None and not bufsize:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001958 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001959 return expatbuilder.parse(file)
1960 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001961 from xml.dom import pulldom
Raymond Hettingerff41c482003-04-06 09:01:11 +00001962 return _do_pulldom_parse(pulldom.parse, (file,),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001963 {'parser': parser, 'bufsize': bufsize})
Fred Drake55c38192000-06-29 19:39:57 +00001964
Martin v. Löwis787354c2003-01-25 15:28:29 +00001965def parseString(string, parser=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001966 """Parse a file into a DOM from a string."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001967 if parser is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001968 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001969 return expatbuilder.parseString(string)
1970 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001971 from xml.dom import pulldom
Martin v. Löwis787354c2003-01-25 15:28:29 +00001972 return _do_pulldom_parse(pulldom.parseString, (string,),
1973 {'parser': parser})
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001974
Martin v. Löwis787354c2003-01-25 15:28:29 +00001975def getDOMImplementation(features=None):
1976 if features:
Christian Heimesc9543e42007-11-28 08:28:28 +00001977 if isinstance(features, str):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001978 features = domreg._parse_feature_string(features)
1979 for f, v in features:
1980 if not Document.implementation.hasFeature(f, v):
1981 return None
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001982 return Document.implementation