blob: 1083b481387100719cd6601e9b0fdd3f65253891 [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
Henry Harutyunyandc04a052020-02-29 12:22:19 +040046 def toxml(self, encoding=None, standalone=None):
47 return self.toprettyxml("", "", encoding, standalone)
Fred Drake55c38192000-06-29 19:39:57 +000048
Henry Harutyunyandc04a052020-02-29 12:22:19 +040049 def toprettyxml(self, indent="\t", newl="\n", encoding=None,
50 standalone=None):
Eli Bendersky8a805022012-07-13 09:52:39 +030051 if encoding is None:
52 writer = io.StringIO()
53 else:
54 writer = io.TextIOWrapper(io.BytesIO(),
55 encoding=encoding,
56 errors="xmlcharrefreplace",
57 newline='\n')
Martin v. Löwis7d650ca2002-06-30 15:05:00 +000058 if self.nodeType == Node.DOCUMENT_NODE:
59 # Can pass encoding only to document, to put it into XML header
Henry Harutyunyandc04a052020-02-29 12:22:19 +040060 self.writexml(writer, "", indent, newl, encoding, standalone)
Martin v. Löwis7d650ca2002-06-30 15:05:00 +000061 else:
62 self.writexml(writer, "", indent, newl)
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000063 if encoding is None:
Eli Bendersky8a805022012-07-13 09:52:39 +030064 return writer.getvalue()
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000065 else:
Eli Bendersky8a805022012-07-13 09:52:39 +030066 return writer.detach().getvalue()
Martin v. Löwis46fa39a2001-02-06 00:14:08 +000067
Fred Drake1f549022000-09-24 05:21:58 +000068 def hasChildNodes(self):
Florent Xicluna8cf4b512012-03-05 12:37:02 +010069 return bool(self.childNodes)
Martin v. Löwis787354c2003-01-25 15:28:29 +000070
71 def _get_childNodes(self):
72 return self.childNodes
Fred Drake55c38192000-06-29 19:39:57 +000073
Fred Drake1f549022000-09-24 05:21:58 +000074 def _get_firstChild(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +000075 if self.childNodes:
76 return self.childNodes[0]
Paul Prescod73678da2000-07-01 04:58:47 +000077
Fred Drake1f549022000-09-24 05:21:58 +000078 def _get_lastChild(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +000079 if self.childNodes:
80 return self.childNodes[-1]
Paul Prescod73678da2000-07-01 04:58:47 +000081
Fred Drake1f549022000-09-24 05:21:58 +000082 def insertBefore(self, newChild, refChild):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000083 if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
Fred Drakee50959a2001-12-06 04:32:18 +000084 for c in tuple(newChild.childNodes):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000085 self.insertBefore(c, refChild)
86 ### The DOM does not clearly specify what to return in this case
87 return newChild
Martin v. Löwis787354c2003-01-25 15:28:29 +000088 if newChild.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000089 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +000090 "%s cannot be child of %s" % (repr(newChild), repr(self)))
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +000091 if newChild.parentNode is not None:
92 newChild.parentNode.removeChild(newChild)
Fred Drake4ccf4a12000-11-21 22:02:22 +000093 if refChild is None:
94 self.appendChild(newChild)
95 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +000096 try:
97 index = self.childNodes.index(refChild)
98 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +000099 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000100 if newChild.nodeType in _nodeTypes_with_children:
101 _clear_id_cache(self)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000102 self.childNodes.insert(index, newChild)
103 newChild.nextSibling = refChild
104 refChild.previousSibling = newChild
105 if index:
106 node = self.childNodes[index-1]
107 node.nextSibling = newChild
108 newChild.previousSibling = node
109 else:
110 newChild.previousSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000111 newChild.parentNode = self
Fred Drake4ccf4a12000-11-21 22:02:22 +0000112 return newChild
Fred Drake55c38192000-06-29 19:39:57 +0000113
Fred Drake1f549022000-09-24 05:21:58 +0000114 def appendChild(self, node):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000115 if node.nodeType == self.DOCUMENT_FRAGMENT_NODE:
Fred Drakee50959a2001-12-06 04:32:18 +0000116 for c in tuple(node.childNodes):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000117 self.appendChild(c)
118 ### The DOM does not clearly specify what to return in this case
119 return node
Martin v. Löwis787354c2003-01-25 15:28:29 +0000120 if node.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000121 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000122 "%s cannot be child of %s" % (repr(node), repr(self)))
123 elif node.nodeType in _nodeTypes_with_children:
124 _clear_id_cache(self)
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000125 if node.parentNode is not None:
126 node.parentNode.removeChild(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000127 _append_child(self, node)
Fred Drake13a30692000-10-09 20:04:16 +0000128 node.nextSibling = None
Paul Prescod73678da2000-07-01 04:58:47 +0000129 return node
130
Fred Drake1f549022000-09-24 05:21:58 +0000131 def replaceChild(self, newChild, oldChild):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000132 if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
133 refChild = oldChild.nextSibling
134 self.removeChild(oldChild)
135 return self.insertBefore(newChild, refChild)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000136 if newChild.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000137 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000138 "%s cannot be child of %s" % (repr(newChild), repr(self)))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000139 if newChild is oldChild:
140 return
Andrew M. Kuchling841d25e2005-11-22 19:03:16 +0000141 if newChild.parentNode is not None:
142 newChild.parentNode.removeChild(newChild)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000143 try:
144 index = self.childNodes.index(oldChild)
145 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000146 raise xml.dom.NotFoundErr()
Fred Drake4ccf4a12000-11-21 22:02:22 +0000147 self.childNodes[index] = newChild
Martin v. Löwis787354c2003-01-25 15:28:29 +0000148 newChild.parentNode = self
149 oldChild.parentNode = None
150 if (newChild.nodeType in _nodeTypes_with_children
151 or oldChild.nodeType in _nodeTypes_with_children):
152 _clear_id_cache(self)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000153 newChild.nextSibling = oldChild.nextSibling
154 newChild.previousSibling = oldChild.previousSibling
Martin v. Löwis156c3372000-12-28 18:40:56 +0000155 oldChild.nextSibling = None
Fred Drake4ccf4a12000-11-21 22:02:22 +0000156 oldChild.previousSibling = None
Martin v. Löwis156c3372000-12-28 18:40:56 +0000157 if newChild.previousSibling:
158 newChild.previousSibling.nextSibling = newChild
159 if newChild.nextSibling:
160 newChild.nextSibling.previousSibling = newChild
Fred Drake4ccf4a12000-11-21 22:02:22 +0000161 return oldChild
Paul Prescod73678da2000-07-01 04:58:47 +0000162
Fred Drake1f549022000-09-24 05:21:58 +0000163 def removeChild(self, oldChild):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000164 try:
165 self.childNodes.remove(oldChild)
166 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000167 raise xml.dom.NotFoundErr()
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000168 if oldChild.nextSibling is not None:
169 oldChild.nextSibling.previousSibling = oldChild.previousSibling
170 if oldChild.previousSibling is not None:
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000171 oldChild.previousSibling.nextSibling = oldChild.nextSibling
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +0000172 oldChild.nextSibling = oldChild.previousSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000173 if oldChild.nodeType in _nodeTypes_with_children:
174 _clear_id_cache(self)
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000175
Martin v. Löwis787354c2003-01-25 15:28:29 +0000176 oldChild.parentNode = None
Fred Drake4ccf4a12000-11-21 22:02:22 +0000177 return oldChild
178
179 def normalize(self):
Fred Drakef7cf40d2000-12-14 18:16:11 +0000180 L = []
181 for child in self.childNodes:
182 if child.nodeType == Node.TEXT_NODE:
R. David Murraydc6da8a2009-04-09 22:16:43 +0000183 if not child.data:
184 # empty text node; discard
185 if L:
186 L[-1].nextSibling = child.nextSibling
187 if child.nextSibling:
188 child.nextSibling.previousSibling = child.previousSibling
189 child.unlink()
190 elif L and L[-1].nodeType == child.nodeType:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000191 # collapse text node
192 node = L[-1]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000193 node.data = node.data + child.data
Fred Drake4ccf4a12000-11-21 22:02:22 +0000194 node.nextSibling = child.nextSibling
R. David Murraydc6da8a2009-04-09 22:16:43 +0000195 if child.nextSibling:
196 child.nextSibling.previousSibling = node
Fred Drake4ccf4a12000-11-21 22:02:22 +0000197 child.unlink()
R. David Murraydc6da8a2009-04-09 22:16:43 +0000198 else:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000199 L.append(child)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000200 else:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000201 L.append(child)
202 if child.nodeType == Node.ELEMENT_NODE:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000203 child.normalize()
Fred Drakef7cf40d2000-12-14 18:16:11 +0000204 self.childNodes[:] = L
Paul Prescod73678da2000-07-01 04:58:47 +0000205
Fred Drake1f549022000-09-24 05:21:58 +0000206 def cloneNode(self, deep):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000207 return _clone_node(self, deep, self.ownerDocument or self)
Fred Drake55c38192000-06-29 19:39:57 +0000208
Martin v. Löwis787354c2003-01-25 15:28:29 +0000209 def isSupported(self, feature, version):
210 return self.ownerDocument.implementation.hasFeature(feature, version)
211
212 def _get_localName(self):
213 # Overridden in Element and Attr where localName can be Non-Null
214 return None
215
216 # Node interfaces from Level 3 (WD 9 April 2002)
Fred Drake25239772001-02-02 19:40:19 +0000217
218 def isSameNode(self, other):
219 return self is other
220
Martin v. Löwis787354c2003-01-25 15:28:29 +0000221 def getInterface(self, feature):
222 if self.isSupported(feature, None):
223 return self
224 else:
225 return None
226
227 # The "user data" functions use a dictionary that is only present
228 # if some user data has been set, so be careful not to assume it
229 # exists.
230
231 def getUserData(self, key):
232 try:
233 return self._user_data[key][0]
234 except (AttributeError, KeyError):
235 return None
236
237 def setUserData(self, key, data, handler):
238 old = None
239 try:
240 d = self._user_data
241 except AttributeError:
242 d = {}
243 self._user_data = d
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000244 if key in d:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000245 old = d[key][0]
246 if data is None:
247 # ignore handlers passed for None
248 handler = None
249 if old is not None:
250 del d[key]
251 else:
252 d[key] = (data, handler)
253 return old
254
255 def _call_user_data_handler(self, operation, src, dst):
256 if hasattr(self, "_user_data"):
Brett Cannon861fd6f2007-02-21 22:05:37 +0000257 for key, (data, handler) in list(self._user_data.items()):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000258 if handler is not None:
259 handler.handle(operation, key, data, src, dst)
260
Fred Drake25239772001-02-02 19:40:19 +0000261 # minidom-specific API:
262
Fred Drake1f549022000-09-24 05:21:58 +0000263 def unlink(self):
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000264 self.parentNode = self.ownerDocument = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000265 if self.childNodes:
266 for child in self.childNodes:
267 child.unlink()
268 self.childNodes = NodeList()
Paul Prescod4221ff02000-10-13 20:11:42 +0000269 self.previousSibling = None
270 self.nextSibling = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000271
Kristján Valur Jónsson17173cf2010-06-09 08:13:42 +0000272 # A Node is its own context manager, to ensure that an unlink() call occurs.
273 # This is similar to how a file object works.
274 def __enter__(self):
275 return self
276
277 def __exit__(self, et, ev, tb):
278 self.unlink()
279
Martin v. Löwis787354c2003-01-25 15:28:29 +0000280defproperty(Node, "firstChild", doc="First child node, or None.")
281defproperty(Node, "lastChild", doc="Last child node, or None.")
282defproperty(Node, "localName", doc="Namespace-local name of this node.")
283
284
285def _append_child(self, node):
286 # fast path with less checks; usable by DOM builders if careful
287 childNodes = self.childNodes
288 if childNodes:
289 last = childNodes[-1]
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100290 node.previousSibling = last
291 last.nextSibling = node
Martin v. Löwis787354c2003-01-25 15:28:29 +0000292 childNodes.append(node)
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100293 node.parentNode = self
Martin v. Löwis787354c2003-01-25 15:28:29 +0000294
295def _in_document(node):
296 # return True iff node is part of a document tree
297 while node is not None:
298 if node.nodeType == Node.DOCUMENT_NODE:
299 return True
300 node = node.parentNode
301 return False
Fred Drake55c38192000-06-29 19:39:57 +0000302
Fred Drake1f549022000-09-24 05:21:58 +0000303def _write_data(writer, data):
Fred Drake55c38192000-06-29 19:39:57 +0000304 "Writes datachars to writer."
Georg Brandlb9cd72a2010-10-15 17:58:45 +0000305 if data:
306 data = data.replace("&", "&amp;").replace("<", "&lt;"). \
307 replace("\"", "&quot;").replace(">", "&gt;")
308 writer.write(data)
Fred Drake55c38192000-06-29 19:39:57 +0000309
Martin v. Löwis787354c2003-01-25 15:28:29 +0000310def _get_elements_by_tagName_helper(parent, name, rc):
Fred Drake55c38192000-06-29 19:39:57 +0000311 for node in parent.childNodes:
Fred Drake1f549022000-09-24 05:21:58 +0000312 if node.nodeType == Node.ELEMENT_NODE and \
313 (name == "*" or node.tagName == name):
314 rc.append(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000315 _get_elements_by_tagName_helper(node, name, rc)
Fred Drake55c38192000-06-29 19:39:57 +0000316 return rc
317
Martin v. Löwis787354c2003-01-25 15:28:29 +0000318def _get_elements_by_tagName_ns_helper(parent, nsURI, localName, rc):
Fred Drake55c38192000-06-29 19:39:57 +0000319 for node in parent.childNodes:
Fred Drake1f549022000-09-24 05:21:58 +0000320 if node.nodeType == Node.ELEMENT_NODE:
Martin v. Löwised525fb2001-06-03 14:06:42 +0000321 if ((localName == "*" or node.localName == localName) and
Fred Drake1f549022000-09-24 05:21:58 +0000322 (nsURI == "*" or node.namespaceURI == nsURI)):
323 rc.append(node)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000324 _get_elements_by_tagName_ns_helper(node, nsURI, localName, rc)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000325 return rc
Fred Drake55c38192000-06-29 19:39:57 +0000326
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000327class DocumentFragment(Node):
328 nodeType = Node.DOCUMENT_FRAGMENT_NODE
329 nodeName = "#document-fragment"
330 nodeValue = None
331 attributes = None
332 parentNode = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000333 _child_node_types = (Node.ELEMENT_NODE,
334 Node.TEXT_NODE,
335 Node.CDATA_SECTION_NODE,
336 Node.ENTITY_REFERENCE_NODE,
337 Node.PROCESSING_INSTRUCTION_NODE,
338 Node.COMMENT_NODE,
339 Node.NOTATION_NODE)
340
341 def __init__(self):
342 self.childNodes = NodeList()
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000343
344
Fred Drake55c38192000-06-29 19:39:57 +0000345class Attr(Node):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100346 __slots__=('_name', '_value', 'namespaceURI',
347 '_prefix', 'childNodes', '_localName', 'ownerDocument', 'ownerElement')
Fred Drake1f549022000-09-24 05:21:58 +0000348 nodeType = Node.ATTRIBUTE_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +0000349 attributes = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000350 specified = False
351 _is_id = False
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000352
Martin v. Löwis787354c2003-01-25 15:28:29 +0000353 _child_node_types = (Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE)
354
355 def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None,
356 prefix=None):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100357 self.ownerElement = None
358 self._name = qName
359 self.namespaceURI = namespaceURI
360 self._prefix = prefix
361 self.childNodes = NodeList()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000362
363 # Add the single child node that represents the value of the attr
364 self.childNodes.append(Text())
365
Paul Prescod73678da2000-07-01 04:58:47 +0000366 # nodeValue and value are set elsewhere
Fred Drake55c38192000-06-29 19:39:57 +0000367
Martin v. Löwis787354c2003-01-25 15:28:29 +0000368 def _get_localName(self):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100369 try:
370 return self._localName
371 except AttributeError:
372 return self.nodeName.split(":", 1)[-1]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000373
Martin v. Löwis787354c2003-01-25 15:28:29 +0000374 def _get_specified(self):
375 return self.specified
376
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100377 def _get_name(self):
378 return self._name
379
380 def _set_name(self, value):
381 self._name = value
382 if self.ownerElement is not None:
383 _clear_id_cache(self.ownerElement)
384
385 nodeName = name = property(_get_name, _set_name)
386
387 def _get_value(self):
388 return self._value
389
390 def _set_value(self, value):
391 self._value = value
392 self.childNodes[0].data = value
393 if self.ownerElement is not None:
394 _clear_id_cache(self.ownerElement)
395 self.childNodes[0].data = value
396
397 nodeValue = value = property(_get_value, _set_value)
398
399 def _get_prefix(self):
400 return self._prefix
Fred Drake55c38192000-06-29 19:39:57 +0000401
Martin v. Löwis995359c2003-01-26 08:59:32 +0000402 def _set_prefix(self, prefix):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000403 nsuri = self.namespaceURI
Martin v. Löwis995359c2003-01-26 08:59:32 +0000404 if prefix == "xmlns":
405 if nsuri and nsuri != XMLNS_NAMESPACE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000406 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000407 "illegal use of 'xmlns' prefix for the wrong namespace")
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100408 self._prefix = prefix
Martin v. Löwis787354c2003-01-25 15:28:29 +0000409 if prefix is None:
410 newName = self.localName
411 else:
Martin v. Löwis995359c2003-01-26 08:59:32 +0000412 newName = "%s:%s" % (prefix, self.localName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000413 if self.ownerElement:
414 _clear_id_cache(self.ownerElement)
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100415 self.name = newName
Martin v. Löwis787354c2003-01-25 15:28:29 +0000416
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100417 prefix = property(_get_prefix, _set_prefix)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000418
419 def unlink(self):
420 # This implementation does not call the base implementation
421 # since most of that is not needed, and the expense of the
422 # method call is not warranted. We duplicate the removal of
423 # children, but that's all we needed from the base class.
424 elem = self.ownerElement
425 if elem is not None:
426 del elem._attrs[self.nodeName]
427 del elem._attrsNS[(self.namespaceURI, self.localName)]
428 if self._is_id:
429 self._is_id = False
430 elem._magic_id_nodes -= 1
431 self.ownerDocument._magic_id_count -= 1
432 for child in self.childNodes:
433 child.unlink()
434 del self.childNodes[:]
435
436 def _get_isId(self):
437 if self._is_id:
438 return True
439 doc = self.ownerDocument
440 elem = self.ownerElement
441 if doc is None or elem is None:
442 return False
443
444 info = doc._get_elem_info(elem)
445 if info is None:
446 return False
447 if self.namespaceURI:
448 return info.isIdNS(self.namespaceURI, self.localName)
449 else:
450 return info.isId(self.nodeName)
451
452 def _get_schemaType(self):
453 doc = self.ownerDocument
454 elem = self.ownerElement
455 if doc is None or elem is None:
456 return _no_type
457
458 info = doc._get_elem_info(elem)
459 if info is None:
460 return _no_type
461 if self.namespaceURI:
462 return info.getAttributeTypeNS(self.namespaceURI, self.localName)
463 else:
464 return info.getAttributeType(self.nodeName)
465
466defproperty(Attr, "isId", doc="True if this attribute is an ID.")
467defproperty(Attr, "localName", doc="Namespace-local name of this attribute.")
468defproperty(Attr, "schemaType", doc="Schema type for this attribute.")
Fred Drake4ccf4a12000-11-21 22:02:22 +0000469
Fred Drakef7cf40d2000-12-14 18:16:11 +0000470
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000471class NamedNodeMap(object):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000472 """The attribute list is a transient interface to the underlying
473 dictionaries. Mutations here will change the underlying element's
Fred Drakef7cf40d2000-12-14 18:16:11 +0000474 dictionary.
475
476 Ordering is imposed artificially and does not reflect the order of
477 attributes as found in an input document.
478 """
Fred Drake4ccf4a12000-11-21 22:02:22 +0000479
Martin v. Löwis787354c2003-01-25 15:28:29 +0000480 __slots__ = ('_attrs', '_attrsNS', '_ownerElement')
481
Fred Drake2998a552001-12-06 18:27:48 +0000482 def __init__(self, attrs, attrsNS, ownerElement):
Fred Drake1f549022000-09-24 05:21:58 +0000483 self._attrs = attrs
484 self._attrsNS = attrsNS
Fred Drake2998a552001-12-06 18:27:48 +0000485 self._ownerElement = ownerElement
Fred Drakef7cf40d2000-12-14 18:16:11 +0000486
Martin v. Löwis787354c2003-01-25 15:28:29 +0000487 def _get_length(self):
488 return len(self._attrs)
Fred Drake55c38192000-06-29 19:39:57 +0000489
Fred Drake1f549022000-09-24 05:21:58 +0000490 def item(self, index):
Fred Drake55c38192000-06-29 19:39:57 +0000491 try:
Brett Cannon861fd6f2007-02-21 22:05:37 +0000492 return self[list(self._attrs.keys())[index]]
Fred Drake55c38192000-06-29 19:39:57 +0000493 except IndexError:
494 return None
Fred Drake55c38192000-06-29 19:39:57 +0000495
Fred Drake1f549022000-09-24 05:21:58 +0000496 def items(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000497 L = []
498 for node in self._attrs.values():
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000499 L.append((node.nodeName, node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000500 return L
Fred Drake1f549022000-09-24 05:21:58 +0000501
502 def itemsNS(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000503 L = []
504 for node in self._attrs.values():
Fred Drake49a5d032001-11-30 22:21:58 +0000505 L.append(((node.namespaceURI, node.localName), node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000506 return L
Fred Drake16f63292000-10-23 18:09:50 +0000507
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000508 def __contains__(self, key):
Christian Heimesc9543e42007-11-28 08:28:28 +0000509 if isinstance(key, str):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000510 return key in self._attrs
Martin v. Löwis787354c2003-01-25 15:28:29 +0000511 else:
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000512 return key in self._attrsNS
Martin v. Löwis787354c2003-01-25 15:28:29 +0000513
Fred Drake1f549022000-09-24 05:21:58 +0000514 def keys(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000515 return self._attrs.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000516
Fred Drake1f549022000-09-24 05:21:58 +0000517 def keysNS(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000518 return self._attrsNS.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000519
Fred Drake1f549022000-09-24 05:21:58 +0000520 def values(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000521 return self._attrs.values()
Fred Drake55c38192000-06-29 19:39:57 +0000522
Martin v. Löwis787354c2003-01-25 15:28:29 +0000523 def get(self, name, value=None):
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000524 return self._attrs.get(name, value)
525
Martin v. Löwis787354c2003-01-25 15:28:29 +0000526 __len__ = _get_length
Fred Drake55c38192000-06-29 19:39:57 +0000527
Mark Dickinsona56c4672009-01-27 18:17:45 +0000528 def _cmp(self, other):
Fred Drake1f549022000-09-24 05:21:58 +0000529 if self._attrs is getattr(other, "_attrs", None):
Fred Drake55c38192000-06-29 19:39:57 +0000530 return 0
Fred Drake16f63292000-10-23 18:09:50 +0000531 else:
Mark Dickinsona56c4672009-01-27 18:17:45 +0000532 return (id(self) > id(other)) - (id(self) < id(other))
533
534 def __eq__(self, other):
535 return self._cmp(other) == 0
536
537 def __ge__(self, other):
538 return self._cmp(other) >= 0
539
540 def __gt__(self, other):
541 return self._cmp(other) > 0
542
543 def __le__(self, other):
544 return self._cmp(other) <= 0
545
546 def __lt__(self, other):
547 return self._cmp(other) < 0
548
Fred Drake1f549022000-09-24 05:21:58 +0000549 def __getitem__(self, attname_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000550 if isinstance(attname_or_tuple, tuple):
Paul Prescod73678da2000-07-01 04:58:47 +0000551 return self._attrsNS[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000552 else:
Paul Prescod73678da2000-07-01 04:58:47 +0000553 return self._attrs[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000554
Paul Prescod1e688272000-07-01 19:21:47 +0000555 # same as set
Fred Drake1f549022000-09-24 05:21:58 +0000556 def __setitem__(self, attname, value):
Christian Heimesc9543e42007-11-28 08:28:28 +0000557 if isinstance(value, str):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000558 try:
559 node = self._attrs[attname]
560 except KeyError:
561 node = Attr(attname)
562 node.ownerDocument = self._ownerElement.ownerDocument
Martin v. Löwis995359c2003-01-26 08:59:32 +0000563 self.setNamedItem(node)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000564 node.value = value
Paul Prescod1e688272000-07-01 19:21:47 +0000565 else:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000566 if not isinstance(value, Attr):
Collin Winter70e79802007-08-24 18:57:22 +0000567 raise TypeError("value must be a string or Attr object")
Fred Drake1f549022000-09-24 05:21:58 +0000568 node = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000569 self.setNamedItem(node)
570
571 def getNamedItem(self, name):
572 try:
573 return self._attrs[name]
574 except KeyError:
575 return None
576
577 def getNamedItemNS(self, namespaceURI, localName):
578 try:
579 return self._attrsNS[(namespaceURI, localName)]
580 except KeyError:
581 return None
582
583 def removeNamedItem(self, name):
584 n = self.getNamedItem(name)
585 if n is not None:
586 _clear_id_cache(self._ownerElement)
587 del self._attrs[n.nodeName]
588 del self._attrsNS[(n.namespaceURI, n.localName)]
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100589 if hasattr(n, 'ownerElement'):
590 n.ownerElement = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000591 return n
592 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000593 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000594
595 def removeNamedItemNS(self, namespaceURI, localName):
596 n = self.getNamedItemNS(namespaceURI, localName)
597 if n is not None:
598 _clear_id_cache(self._ownerElement)
599 del self._attrsNS[(n.namespaceURI, n.localName)]
600 del self._attrs[n.nodeName]
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100601 if hasattr(n, 'ownerElement'):
602 n.ownerElement = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000603 return n
604 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000605 raise xml.dom.NotFoundErr()
Fred Drakef7cf40d2000-12-14 18:16:11 +0000606
607 def setNamedItem(self, node):
Andrew M. Kuchlingbc8f72c2001-02-21 01:30:26 +0000608 if not isinstance(node, Attr):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000609 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000610 "%s cannot be child of %s" % (repr(node), repr(self)))
Fred Drakef7cf40d2000-12-14 18:16:11 +0000611 old = self._attrs.get(node.name)
Paul Prescod1e688272000-07-01 19:21:47 +0000612 if old:
613 old.unlink()
Fred Drake1f549022000-09-24 05:21:58 +0000614 self._attrs[node.name] = node
615 self._attrsNS[(node.namespaceURI, node.localName)] = node
Fred Drake2998a552001-12-06 18:27:48 +0000616 node.ownerElement = self._ownerElement
Martin v. Löwis787354c2003-01-25 15:28:29 +0000617 _clear_id_cache(node.ownerElement)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000618 return old
619
620 def setNamedItemNS(self, node):
621 return self.setNamedItem(node)
Paul Prescod73678da2000-07-01 04:58:47 +0000622
Fred Drake1f549022000-09-24 05:21:58 +0000623 def __delitem__(self, attname_or_tuple):
624 node = self[attname_or_tuple]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000625 _clear_id_cache(node.ownerElement)
Paul Prescod73678da2000-07-01 04:58:47 +0000626 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000627
628 def __getstate__(self):
629 return self._attrs, self._attrsNS, self._ownerElement
630
631 def __setstate__(self, state):
632 self._attrs, self._attrsNS, self._ownerElement = state
633
634defproperty(NamedNodeMap, "length",
635 doc="Number of nodes in the NamedNodeMap.")
Fred Drakef7cf40d2000-12-14 18:16:11 +0000636
637AttributeList = NamedNodeMap
638
Fred Drake1f549022000-09-24 05:21:58 +0000639
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000640class TypeInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000641 __slots__ = 'namespace', 'name'
642
643 def __init__(self, namespace, name):
644 self.namespace = namespace
645 self.name = name
646
647 def __repr__(self):
648 if self.namespace:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300649 return "<%s %r (from %r)>" % (self.__class__.__name__, self.name,
650 self.namespace)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000651 else:
Serhiy Storchaka465e60e2014-07-25 23:36:00 +0300652 return "<%s %r>" % (self.__class__.__name__, self.name)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000653
654 def _get_name(self):
655 return self.name
656
657 def _get_namespace(self):
658 return self.namespace
659
660_no_type = TypeInfo(None, None)
661
Martin v. Löwisa2fda0d2000-10-07 12:10:28 +0000662class Element(Node):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100663 __slots__=('ownerDocument', 'parentNode', 'tagName', 'nodeName', 'prefix',
664 'namespaceURI', '_localName', 'childNodes', '_attrs', '_attrsNS',
665 'nextSibling', 'previousSibling')
Fred Drake1f549022000-09-24 05:21:58 +0000666 nodeType = Node.ELEMENT_NODE
Martin v. Löwis787354c2003-01-25 15:28:29 +0000667 nodeValue = None
668 schemaType = _no_type
669
670 _magic_id_nodes = 0
671
672 _child_node_types = (Node.ELEMENT_NODE,
673 Node.PROCESSING_INSTRUCTION_NODE,
674 Node.COMMENT_NODE,
675 Node.TEXT_NODE,
676 Node.CDATA_SECTION_NODE,
677 Node.ENTITY_REFERENCE_NODE)
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000678
Fred Drake49a5d032001-11-30 22:21:58 +0000679 def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None,
Fred Drake1f549022000-09-24 05:21:58 +0000680 localName=None):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100681 self.parentNode = None
Fred Drake55c38192000-06-29 19:39:57 +0000682 self.tagName = self.nodeName = tagName
Fred Drake1f549022000-09-24 05:21:58 +0000683 self.prefix = prefix
684 self.namespaceURI = namespaceURI
Martin v. Löwis787354c2003-01-25 15:28:29 +0000685 self.childNodes = NodeList()
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100686 self.nextSibling = self.previousSibling = None
Fred Drake55c38192000-06-29 19:39:57 +0000687
Martin v. Löwis7b771882012-02-19 20:55:05 +0100688 # Attribute dictionaries are lazily created
689 # attributes are double-indexed:
690 # tagName -> Attribute
691 # URI,localName -> Attribute
692 # in the future: consider lazy generation
693 # of attribute objects this is too tricky
694 # for now because of headaches with
695 # namespaces.
696 self._attrs = None
697 self._attrsNS = None
698
699 def _ensure_attributes(self):
700 if self._attrs is None:
701 self._attrs = {}
702 self._attrsNS = {}
Fred Drake4ccf4a12000-11-21 22:02:22 +0000703
Martin v. Löwis787354c2003-01-25 15:28:29 +0000704 def _get_localName(self):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100705 try:
706 return self._localName
707 except AttributeError:
708 return self.tagName.split(":", 1)[-1]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000709
710 def _get_tagName(self):
711 return self.tagName
Fred Drake4ccf4a12000-11-21 22:02:22 +0000712
713 def unlink(self):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100714 if self._attrs is not None:
715 for attr in list(self._attrs.values()):
716 attr.unlink()
Fred Drake4ccf4a12000-11-21 22:02:22 +0000717 self._attrs = None
718 self._attrsNS = None
719 Node.unlink(self)
Fred Drake55c38192000-06-29 19:39:57 +0000720
Fred Drake1f549022000-09-24 05:21:58 +0000721 def getAttribute(self, attname):
Martin v. Löwis67245a62012-03-05 07:01:49 +0100722 if self._attrs is None:
723 return ""
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000724 try:
725 return self._attrs[attname].value
726 except KeyError:
727 return ""
Fred Drake55c38192000-06-29 19:39:57 +0000728
Fred Drake1f549022000-09-24 05:21:58 +0000729 def getAttributeNS(self, namespaceURI, localName):
Martin v. Löwis67245a62012-03-05 07:01:49 +0100730 if self._attrsNS is None:
731 return ""
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000732 try:
733 return self._attrsNS[(namespaceURI, localName)].value
734 except KeyError:
735 return ""
Fred Drake1f549022000-09-24 05:21:58 +0000736
737 def setAttribute(self, attname, value):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000738 attr = self.getAttributeNode(attname)
739 if attr is None:
740 attr = Attr(attname)
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100741 attr.value = value # also sets nodeValue
742 attr.ownerDocument = self.ownerDocument
Martin v. Löwis787354c2003-01-25 15:28:29 +0000743 self.setAttributeNode(attr)
744 elif value != attr.value:
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100745 attr.value = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000746 if attr.isId:
747 _clear_id_cache(self)
Fred Drake55c38192000-06-29 19:39:57 +0000748
Fred Drake1f549022000-09-24 05:21:58 +0000749 def setAttributeNS(self, namespaceURI, qualifiedName, value):
750 prefix, localname = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000751 attr = self.getAttributeNodeNS(namespaceURI, localname)
752 if attr is None:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000753 attr = Attr(qualifiedName, namespaceURI, localname, prefix)
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100754 attr.value = value
755 attr.ownerDocument = self.ownerDocument
Martin v. Löwis787354c2003-01-25 15:28:29 +0000756 self.setAttributeNode(attr)
757 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000758 if value != attr.value:
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100759 attr.value = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000760 if attr.isId:
761 _clear_id_cache(self)
762 if attr.prefix != prefix:
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100763 attr.prefix = prefix
764 attr.nodeName = qualifiedName
Fred Drake55c38192000-06-29 19:39:57 +0000765
Fred Drake1f549022000-09-24 05:21:58 +0000766 def getAttributeNode(self, attrname):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100767 if self._attrs is None:
768 return None
Fred Drake1f549022000-09-24 05:21:58 +0000769 return self._attrs.get(attrname)
Paul Prescod73678da2000-07-01 04:58:47 +0000770
Fred Drake1f549022000-09-24 05:21:58 +0000771 def getAttributeNodeNS(self, namespaceURI, localName):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100772 if self._attrsNS is None:
773 return None
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000774 return self._attrsNS.get((namespaceURI, localName))
Paul Prescod73678da2000-07-01 04:58:47 +0000775
Fred Drake1f549022000-09-24 05:21:58 +0000776 def setAttributeNode(self, attr):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000777 if attr.ownerElement not in (None, self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000778 raise xml.dom.InuseAttributeErr("attribute node already owned")
Martin v. Löwis7b771882012-02-19 20:55:05 +0100779 self._ensure_attributes()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000780 old1 = self._attrs.get(attr.name, None)
781 if old1 is not None:
782 self.removeAttributeNode(old1)
783 old2 = self._attrsNS.get((attr.namespaceURI, attr.localName), None)
784 if old2 is not None and old2 is not old1:
785 self.removeAttributeNode(old2)
786 _set_attribute_node(self, attr)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000787
Martin v. Löwis787354c2003-01-25 15:28:29 +0000788 if old1 is not attr:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000789 # It might have already been part of this node, in which case
790 # it doesn't represent a change, and should not be returned.
Martin v. Löwis787354c2003-01-25 15:28:29 +0000791 return old1
792 if old2 is not attr:
793 return old2
Fred Drake55c38192000-06-29 19:39:57 +0000794
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000795 setAttributeNodeNS = setAttributeNode
796
Fred Drake1f549022000-09-24 05:21:58 +0000797 def removeAttribute(self, name):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100798 if self._attrsNS is None:
799 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000800 try:
801 attr = self._attrs[name]
802 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000803 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000804 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000805
Fred Drake1f549022000-09-24 05:21:58 +0000806 def removeAttributeNS(self, namespaceURI, localName):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100807 if self._attrsNS is None:
808 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000809 try:
810 attr = self._attrsNS[(namespaceURI, localName)]
811 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000812 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000813 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000814
Fred Drake1f549022000-09-24 05:21:58 +0000815 def removeAttributeNode(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000816 if node is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000817 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000818 try:
819 self._attrs[node.name]
820 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000821 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000822 _clear_id_cache(self)
Paul Prescod73678da2000-07-01 04:58:47 +0000823 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000824 # Restore this since the node is still useful and otherwise
825 # unlinked
826 node.ownerDocument = self.ownerDocument
arikrupnik5bfa0582018-06-06 23:42:38 -0500827 return node
Fred Drake16f63292000-10-23 18:09:50 +0000828
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000829 removeAttributeNodeNS = removeAttributeNode
830
Martin v. Löwis156c3372000-12-28 18:40:56 +0000831 def hasAttribute(self, name):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100832 if self._attrs is None:
833 return False
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000834 return name in self._attrs
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000835
Martin v. Löwis156c3372000-12-28 18:40:56 +0000836 def hasAttributeNS(self, namespaceURI, localName):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100837 if self._attrsNS is None:
838 return False
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000839 return (namespaceURI, localName) in self._attrsNS
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000840
Fred Drake1f549022000-09-24 05:21:58 +0000841 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000842 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000843
Fred Drake1f549022000-09-24 05:21:58 +0000844 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000845 return _get_elements_by_tagName_ns_helper(
846 self, namespaceURI, localName, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000847
Fred Drake1f549022000-09-24 05:21:58 +0000848 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000849 return "<DOM Element: %s at %#x>" % (self.tagName, id(self))
Fred Drake55c38192000-06-29 19:39:57 +0000850
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000851 def writexml(self, writer, indent="", addindent="", newl=""):
852 # indent = current indentation
853 # addindent = indentation to add to higher levels
854 # newl = newline string
855 writer.write(indent+"<" + self.tagName)
Fred Drake16f63292000-10-23 18:09:50 +0000856
Fred Drake4ccf4a12000-11-21 22:02:22 +0000857 attrs = self._get_attributes()
Fred Drake55c38192000-06-29 19:39:57 +0000858
Diego Rojas5598cc92018-11-07 09:09:04 -0500859 for a_name in attrs.keys():
Fred Drake1f549022000-09-24 05:21:58 +0000860 writer.write(" %s=\"" % a_name)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000861 _write_data(writer, attrs[a_name].value)
Fred Drake55c38192000-06-29 19:39:57 +0000862 writer.write("\"")
863 if self.childNodes:
R David Murray791744b2011-10-01 16:19:51 -0400864 writer.write(">")
Ezio Melotti8008f2a2011-11-18 17:34:26 +0200865 if (len(self.childNodes) == 1 and
Vladimir Surjaninov384b81d2019-03-27 08:58:49 +0300866 self.childNodes[0].nodeType in (
867 Node.TEXT_NODE, Node.CDATA_SECTION_NODE)):
Ezio Melotti8008f2a2011-11-18 17:34:26 +0200868 self.childNodes[0].writexml(writer, '', '', '')
869 else:
R David Murray791744b2011-10-01 16:19:51 -0400870 writer.write(newl)
Ezio Melotti8008f2a2011-11-18 17:34:26 +0200871 for node in self.childNodes:
872 node.writexml(writer, indent+addindent, addindent, newl)
873 writer.write(indent)
874 writer.write("</%s>%s" % (self.tagName, newl))
Fred Drake55c38192000-06-29 19:39:57 +0000875 else:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000876 writer.write("/>%s"%(newl))
Fred Drake55c38192000-06-29 19:39:57 +0000877
Fred Drake1f549022000-09-24 05:21:58 +0000878 def _get_attributes(self):
Martin v. Löwis7b771882012-02-19 20:55:05 +0100879 self._ensure_attributes()
Fred Drake2998a552001-12-06 18:27:48 +0000880 return NamedNodeMap(self._attrs, self._attrsNS, self)
Fred Drake55c38192000-06-29 19:39:57 +0000881
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000882 def hasAttributes(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000883 if self._attrs:
884 return True
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000885 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000886 return False
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000887
Martin v. Löwis787354c2003-01-25 15:28:29 +0000888 # DOM Level 3 attributes, based on the 22 Oct 2002 draft
889
890 def setIdAttribute(self, name):
891 idAttr = self.getAttributeNode(name)
892 self.setIdAttributeNode(idAttr)
893
894 def setIdAttributeNS(self, namespaceURI, localName):
895 idAttr = self.getAttributeNodeNS(namespaceURI, localName)
896 self.setIdAttributeNode(idAttr)
897
898 def setIdAttributeNode(self, idAttr):
899 if idAttr is None or not self.isSameNode(idAttr.ownerElement):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000900 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000901 if _get_containing_entref(self) is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000902 raise xml.dom.NoModificationAllowedErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000903 if not idAttr._is_id:
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100904 idAttr._is_id = True
Martin v. Löwis787354c2003-01-25 15:28:29 +0000905 self._magic_id_nodes += 1
906 self.ownerDocument._magic_id_count += 1
907 _clear_id_cache(self)
908
909defproperty(Element, "attributes",
910 doc="NamedNodeMap of attributes on the element.")
911defproperty(Element, "localName",
912 doc="Namespace-local name of this element.")
913
914
915def _set_attribute_node(element, attr):
916 _clear_id_cache(element)
Martin v. Löwis7b771882012-02-19 20:55:05 +0100917 element._ensure_attributes()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000918 element._attrs[attr.name] = attr
919 element._attrsNS[(attr.namespaceURI, attr.localName)] = attr
920
921 # This creates a circular reference, but Element.unlink()
922 # breaks the cycle since the references to the attribute
923 # dictionaries are tossed.
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100924 attr.ownerElement = element
Martin v. Löwis787354c2003-01-25 15:28:29 +0000925
926class Childless:
927 """Mixin that makes childless-ness easy to implement and avoids
928 the complexity of the Node methods that deal with children.
929 """
Florent Xicluna8cf4b512012-03-05 12:37:02 +0100930 __slots__ = ()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000931
Fred Drake4ccf4a12000-11-21 22:02:22 +0000932 attributes = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000933 childNodes = EmptyNodeList()
934 firstChild = None
935 lastChild = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000936
Martin v. Löwis787354c2003-01-25 15:28:29 +0000937 def _get_firstChild(self):
938 return None
Fred Drake55c38192000-06-29 19:39:57 +0000939
Martin v. Löwis787354c2003-01-25 15:28:29 +0000940 def _get_lastChild(self):
941 return None
Fred Drake1f549022000-09-24 05:21:58 +0000942
Martin v. Löwis787354c2003-01-25 15:28:29 +0000943 def appendChild(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000944 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000945 self.nodeName + " nodes cannot have children")
946
947 def hasChildNodes(self):
948 return False
949
950 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000951 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000952 self.nodeName + " nodes do not have children")
953
954 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000955 raise xml.dom.NotFoundErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000956 self.nodeName + " nodes do not have children")
957
Andrew M. Kuchling688b9e32010-07-25 23:38:47 +0000958 def normalize(self):
959 # For childless nodes, normalize() has nothing to do.
960 pass
961
Martin v. Löwis787354c2003-01-25 15:28:29 +0000962 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000963 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000964 self.nodeName + " nodes do not have children")
965
966
967class ProcessingInstruction(Childless, Node):
Fred Drake1f549022000-09-24 05:21:58 +0000968 nodeType = Node.PROCESSING_INSTRUCTION_NODE
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100969 __slots__ = ('target', 'data')
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000970
Fred Drake1f549022000-09-24 05:21:58 +0000971 def __init__(self, target, data):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100972 self.target = target
973 self.data = data
Fred Drake55c38192000-06-29 19:39:57 +0000974
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100975 # nodeValue is an alias for data
976 def _get_nodeValue(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000977 return self.data
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100978 def _set_nodeValue(self, value):
Raymond Hettinger92a40552014-06-15 14:48:19 -0700979 self.data = value
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100980 nodeValue = property(_get_nodeValue, _set_nodeValue)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000981
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100982 # nodeName is an alias for target
983 def _get_nodeName(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000984 return self.target
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100985 def _set_nodeName(self, value):
986 self.target = value
987 nodeName = property(_get_nodeName, _set_nodeName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000988
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000989 def writexml(self, writer, indent="", addindent="", newl=""):
990 writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))
Fred Drake55c38192000-06-29 19:39:57 +0000991
Martin v. Löwis787354c2003-01-25 15:28:29 +0000992
993class CharacterData(Childless, Node):
Martin v. Löwis14aa2802012-02-19 20:25:12 +0100994 __slots__=('_data', 'ownerDocument','parentNode', 'previousSibling', 'nextSibling')
995
996 def __init__(self):
997 self.ownerDocument = self.parentNode = None
998 self.previousSibling = self.nextSibling = None
999 self._data = ''
1000 Node.__init__(self)
1001
Martin v. Löwis787354c2003-01-25 15:28:29 +00001002 def _get_length(self):
1003 return len(self.data)
1004 __len__ = _get_length
1005
1006 def _get_data(self):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001007 return self._data
Martin v. Löwis787354c2003-01-25 15:28:29 +00001008 def _set_data(self, data):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001009 self._data = data
Martin v. Löwis787354c2003-01-25 15:28:29 +00001010
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001011 data = nodeValue = property(_get_data, _set_data)
Fred Drake87432f42001-04-04 14:09:46 +00001012
Fred Drake55c38192000-06-29 19:39:57 +00001013 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001014 data = self.data
1015 if len(data) > 10:
Fred Drake1f549022000-09-24 05:21:58 +00001016 dotdotdot = "..."
Fred Drake55c38192000-06-29 19:39:57 +00001017 else:
Fred Drake1f549022000-09-24 05:21:58 +00001018 dotdotdot = ""
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001019 return '<DOM %s node "%r%s">' % (
Martin v. Löwis787354c2003-01-25 15:28:29 +00001020 self.__class__.__name__, data[0:10], dotdotdot)
Fred Drake87432f42001-04-04 14:09:46 +00001021
1022 def substringData(self, offset, count):
1023 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001024 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001025 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001026 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001027 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001028 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001029 return self.data[offset:offset+count]
1030
1031 def appendData(self, arg):
1032 self.data = self.data + arg
Fred Drake87432f42001-04-04 14:09:46 +00001033
1034 def insertData(self, offset, arg):
1035 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001036 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001037 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001038 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001039 if arg:
1040 self.data = "%s%s%s" % (
1041 self.data[:offset], arg, self.data[offset:])
Fred Drake87432f42001-04-04 14:09:46 +00001042
1043 def deleteData(self, offset, count):
1044 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001045 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001046 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001047 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001048 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001049 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001050 if count:
1051 self.data = self.data[:offset] + self.data[offset+count:]
Fred Drake87432f42001-04-04 14:09:46 +00001052
1053 def replaceData(self, offset, count, arg):
1054 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001055 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001056 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001057 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001058 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001059 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001060 if count:
1061 self.data = "%s%s%s" % (
1062 self.data[:offset], arg, self.data[offset+count:])
Martin v. Löwis787354c2003-01-25 15:28:29 +00001063
1064defproperty(CharacterData, "length", doc="Length of the string data.")
1065
Fred Drake87432f42001-04-04 14:09:46 +00001066
1067class Text(CharacterData):
Florent Xicluna8cf4b512012-03-05 12:37:02 +01001068 __slots__ = ()
1069
Fred Drake87432f42001-04-04 14:09:46 +00001070 nodeType = Node.TEXT_NODE
1071 nodeName = "#text"
1072 attributes = None
Fred Drake55c38192000-06-29 19:39:57 +00001073
Fred Drakef7cf40d2000-12-14 18:16:11 +00001074 def splitText(self, offset):
1075 if offset < 0 or offset > len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001076 raise xml.dom.IndexSizeErr("illegal offset value")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001077 newText = self.__class__()
1078 newText.data = self.data[offset:]
1079 newText.ownerDocument = self.ownerDocument
Fred Drakef7cf40d2000-12-14 18:16:11 +00001080 next = self.nextSibling
1081 if self.parentNode and self in self.parentNode.childNodes:
1082 if next is None:
1083 self.parentNode.appendChild(newText)
1084 else:
1085 self.parentNode.insertBefore(newText, next)
1086 self.data = self.data[:offset]
1087 return newText
1088
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001089 def writexml(self, writer, indent="", addindent="", newl=""):
Ezio Melotti8008f2a2011-11-18 17:34:26 +02001090 _write_data(writer, "%s%s%s" % (indent, self.data, newl))
Fred Drake55c38192000-06-29 19:39:57 +00001091
Martin v. Löwis787354c2003-01-25 15:28:29 +00001092 # DOM Level 3 (WD 9 April 2002)
1093
1094 def _get_wholeText(self):
1095 L = [self.data]
1096 n = self.previousSibling
1097 while n is not None:
1098 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1099 L.insert(0, n.data)
1100 n = n.previousSibling
1101 else:
1102 break
1103 n = self.nextSibling
1104 while n is not None:
1105 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1106 L.append(n.data)
1107 n = n.nextSibling
1108 else:
1109 break
1110 return ''.join(L)
1111
1112 def replaceWholeText(self, content):
1113 # XXX This needs to be seriously changed if minidom ever
1114 # supports EntityReference nodes.
1115 parent = self.parentNode
1116 n = self.previousSibling
1117 while n is not None:
1118 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1119 next = n.previousSibling
1120 parent.removeChild(n)
1121 n = next
1122 else:
1123 break
1124 n = self.nextSibling
1125 if not content:
1126 parent.removeChild(self)
1127 while n is not None:
1128 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1129 next = n.nextSibling
1130 parent.removeChild(n)
1131 n = next
1132 else:
1133 break
1134 if content:
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001135 self.data = content
Martin v. Löwis787354c2003-01-25 15:28:29 +00001136 return self
1137 else:
1138 return None
1139
1140 def _get_isWhitespaceInElementContent(self):
1141 if self.data.strip():
1142 return False
1143 elem = _get_containing_element(self)
1144 if elem is None:
1145 return False
1146 info = self.ownerDocument._get_elem_info(elem)
1147 if info is None:
1148 return False
1149 else:
1150 return info.isElementContent()
1151
1152defproperty(Text, "isWhitespaceInElementContent",
1153 doc="True iff this text node contains only whitespace"
1154 " and is in element content.")
1155defproperty(Text, "wholeText",
1156 doc="The text of all logically-adjacent text nodes.")
1157
1158
1159def _get_containing_element(node):
1160 c = node.parentNode
1161 while c is not None:
1162 if c.nodeType == Node.ELEMENT_NODE:
1163 return c
1164 c = c.parentNode
1165 return None
1166
1167def _get_containing_entref(node):
1168 c = node.parentNode
1169 while c is not None:
1170 if c.nodeType == Node.ENTITY_REFERENCE_NODE:
1171 return c
1172 c = c.parentNode
1173 return None
1174
1175
Alex Martelli0ee43512006-08-21 19:53:20 +00001176class Comment(CharacterData):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001177 nodeType = Node.COMMENT_NODE
1178 nodeName = "#comment"
1179
1180 def __init__(self, data):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001181 CharacterData.__init__(self)
1182 self._data = data
Martin v. Löwis787354c2003-01-25 15:28:29 +00001183
1184 def writexml(self, writer, indent="", addindent="", newl=""):
Benjamin Peterson2b7411d2008-05-26 17:36:47 +00001185 if "--" in self.data:
1186 raise ValueError("'--' is not allowed in a comment node")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001187 writer.write("%s<!--%s-->%s" % (indent, self.data, newl))
1188
Fred Drake87432f42001-04-04 14:09:46 +00001189
1190class CDATASection(Text):
Florent Xicluna8cf4b512012-03-05 12:37:02 +01001191 __slots__ = ()
1192
Fred Drake87432f42001-04-04 14:09:46 +00001193 nodeType = Node.CDATA_SECTION_NODE
1194 nodeName = "#cdata-section"
1195
1196 def writexml(self, writer, indent="", addindent="", newl=""):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001197 if self.data.find("]]>") >= 0:
1198 raise ValueError("']]>' not allowed in a CDATA section")
Guido van Rossum5b5e0b92001-09-19 13:28:25 +00001199 writer.write("<![CDATA[%s]]>" % self.data)
Fred Drake87432f42001-04-04 14:09:46 +00001200
1201
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001202class ReadOnlySequentialNamedNodeMap(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001203 __slots__ = '_seq',
1204
1205 def __init__(self, seq=()):
1206 # seq should be a list or tuple
1207 self._seq = seq
1208
1209 def __len__(self):
1210 return len(self._seq)
1211
1212 def _get_length(self):
1213 return len(self._seq)
1214
1215 def getNamedItem(self, name):
1216 for n in self._seq:
1217 if n.nodeName == name:
1218 return n
1219
1220 def getNamedItemNS(self, namespaceURI, localName):
1221 for n in self._seq:
1222 if n.namespaceURI == namespaceURI and n.localName == localName:
1223 return n
1224
1225 def __getitem__(self, name_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001226 if isinstance(name_or_tuple, tuple):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001227 node = self.getNamedItemNS(*name_or_tuple)
1228 else:
1229 node = self.getNamedItem(name_or_tuple)
1230 if node is None:
Collin Winter70e79802007-08-24 18:57:22 +00001231 raise KeyError(name_or_tuple)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001232 return node
1233
1234 def item(self, index):
1235 if index < 0:
1236 return None
1237 try:
1238 return self._seq[index]
1239 except IndexError:
1240 return None
1241
1242 def removeNamedItem(self, name):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001243 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001244 "NamedNodeMap instance is read-only")
1245
1246 def removeNamedItemNS(self, namespaceURI, localName):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001247 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001248 "NamedNodeMap instance is read-only")
1249
1250 def setNamedItem(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001251 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001252 "NamedNodeMap instance is read-only")
1253
1254 def setNamedItemNS(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001255 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001256 "NamedNodeMap instance is read-only")
1257
1258 def __getstate__(self):
1259 return [self._seq]
1260
1261 def __setstate__(self, state):
1262 self._seq = state[0]
1263
1264defproperty(ReadOnlySequentialNamedNodeMap, "length",
1265 doc="Number of entries in the NamedNodeMap.")
Paul Prescod73678da2000-07-01 04:58:47 +00001266
Fred Drakef7cf40d2000-12-14 18:16:11 +00001267
Martin v. Löwis787354c2003-01-25 15:28:29 +00001268class Identified:
1269 """Mix-in class that supports the publicId and systemId attributes."""
1270
Florent Xicluna8cf4b512012-03-05 12:37:02 +01001271 __slots__ = 'publicId', 'systemId'
Martin v. Löwis787354c2003-01-25 15:28:29 +00001272
1273 def _identified_mixin_init(self, publicId, systemId):
1274 self.publicId = publicId
1275 self.systemId = systemId
1276
1277 def _get_publicId(self):
1278 return self.publicId
1279
1280 def _get_systemId(self):
1281 return self.systemId
1282
1283class DocumentType(Identified, Childless, Node):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001284 nodeType = Node.DOCUMENT_TYPE_NODE
1285 nodeValue = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001286 name = None
1287 publicId = None
1288 systemId = None
Fred Drakedc806702001-04-05 14:41:30 +00001289 internalSubset = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001290
1291 def __init__(self, qualifiedName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001292 self.entities = ReadOnlySequentialNamedNodeMap()
1293 self.notations = ReadOnlySequentialNamedNodeMap()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001294 if qualifiedName:
1295 prefix, localname = _nssplit(qualifiedName)
1296 self.name = localname
Martin v. Löwis787354c2003-01-25 15:28:29 +00001297 self.nodeName = self.name
1298
1299 def _get_internalSubset(self):
1300 return self.internalSubset
1301
1302 def cloneNode(self, deep):
1303 if self.ownerDocument is None:
1304 # it's ok
1305 clone = DocumentType(None)
1306 clone.name = self.name
1307 clone.nodeName = self.name
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001308 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001309 if deep:
1310 clone.entities._seq = []
1311 clone.notations._seq = []
1312 for n in self.notations._seq:
1313 notation = Notation(n.nodeName, n.publicId, n.systemId)
1314 clone.notations._seq.append(notation)
1315 n._call_user_data_handler(operation, n, notation)
1316 for e in self.entities._seq:
1317 entity = Entity(e.nodeName, e.publicId, e.systemId,
1318 e.notationName)
1319 entity.actualEncoding = e.actualEncoding
1320 entity.encoding = e.encoding
1321 entity.version = e.version
1322 clone.entities._seq.append(entity)
Victor Stinner8e041862018-12-10 11:12:53 +01001323 e._call_user_data_handler(operation, e, entity)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001324 self._call_user_data_handler(operation, self, clone)
1325 return clone
1326 else:
1327 return None
1328
1329 def writexml(self, writer, indent="", addindent="", newl=""):
1330 writer.write("<!DOCTYPE ")
1331 writer.write(self.name)
1332 if self.publicId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001333 writer.write("%s PUBLIC '%s'%s '%s'"
1334 % (newl, self.publicId, newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001335 elif self.systemId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001336 writer.write("%s SYSTEM '%s'" % (newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001337 if self.internalSubset is not None:
1338 writer.write(" [")
1339 writer.write(self.internalSubset)
1340 writer.write("]")
Georg Brandl175a7dc2005-08-25 22:02:43 +00001341 writer.write(">"+newl)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001342
1343class Entity(Identified, Node):
1344 attributes = None
1345 nodeType = Node.ENTITY_NODE
1346 nodeValue = None
1347
1348 actualEncoding = None
1349 encoding = None
1350 version = None
1351
1352 def __init__(self, name, publicId, systemId, notation):
1353 self.nodeName = name
1354 self.notationName = notation
1355 self.childNodes = NodeList()
1356 self._identified_mixin_init(publicId, systemId)
1357
1358 def _get_actualEncoding(self):
1359 return self.actualEncoding
1360
1361 def _get_encoding(self):
1362 return self.encoding
1363
1364 def _get_version(self):
1365 return self.version
1366
1367 def appendChild(self, newChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001368 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001369 "cannot append children to an entity node")
1370
1371 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001372 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001373 "cannot insert children below an entity node")
1374
1375 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001376 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001377 "cannot remove children from an entity node")
1378
1379 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001380 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001381 "cannot replace children of an entity node")
1382
1383class Notation(Identified, Childless, Node):
1384 nodeType = Node.NOTATION_NODE
1385 nodeValue = None
1386
1387 def __init__(self, name, publicId, systemId):
1388 self.nodeName = name
1389 self._identified_mixin_init(publicId, systemId)
Fred Drakef7cf40d2000-12-14 18:16:11 +00001390
1391
Martin v. Löwis787354c2003-01-25 15:28:29 +00001392class DOMImplementation(DOMImplementationLS):
1393 _features = [("core", "1.0"),
1394 ("core", "2.0"),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001395 ("core", None),
1396 ("xml", "1.0"),
1397 ("xml", "2.0"),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001398 ("xml", None),
1399 ("ls-load", "3.0"),
1400 ("ls-load", None),
1401 ]
1402
Fred Drakef7cf40d2000-12-14 18:16:11 +00001403 def hasFeature(self, feature, version):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001404 if version == "":
1405 version = None
1406 return (feature.lower(), version) in self._features
Fred Drakef7cf40d2000-12-14 18:16:11 +00001407
1408 def createDocument(self, namespaceURI, qualifiedName, doctype):
1409 if doctype and doctype.parentNode is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001410 raise xml.dom.WrongDocumentErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001411 "doctype object owned by another DOM tree")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001412 doc = self._create_document()
1413
1414 add_root_element = not (namespaceURI is None
1415 and qualifiedName is None
1416 and doctype is None)
1417
1418 if not qualifiedName and add_root_element:
Martin v. Löwisb417be22001-02-06 01:16:06 +00001419 # The spec is unclear what to raise here; SyntaxErr
1420 # would be the other obvious candidate. Since Xerces raises
1421 # InvalidCharacterErr, and since SyntaxErr is not listed
1422 # for createDocument, that seems to be the better choice.
1423 # XXX: need to check for illegal characters here and in
1424 # createElement.
Martin v. Löwis787354c2003-01-25 15:28:29 +00001425
1426 # DOM Level III clears this up when talking about the return value
1427 # of this function. If namespaceURI, qName and DocType are
1428 # Null the document is returned without a document element
1429 # Otherwise if doctype or namespaceURI are not None
1430 # Then we go back to the above problem
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001431 raise xml.dom.InvalidCharacterErr("Element with no name")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001432
1433 if add_root_element:
1434 prefix, localname = _nssplit(qualifiedName)
1435 if prefix == "xml" \
1436 and namespaceURI != "http://www.w3.org/XML/1998/namespace":
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001437 raise xml.dom.NamespaceErr("illegal use of 'xml' prefix")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001438 if prefix and not namespaceURI:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001439 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001440 "illegal use of prefix without namespaces")
1441 element = doc.createElementNS(namespaceURI, qualifiedName)
1442 if doctype:
1443 doc.appendChild(doctype)
1444 doc.appendChild(element)
1445
1446 if doctype:
1447 doctype.parentNode = doctype.ownerDocument = doc
1448
Fred Drakef7cf40d2000-12-14 18:16:11 +00001449 doc.doctype = doctype
1450 doc.implementation = self
1451 return doc
1452
1453 def createDocumentType(self, qualifiedName, publicId, systemId):
1454 doctype = DocumentType(qualifiedName)
1455 doctype.publicId = publicId
1456 doctype.systemId = systemId
1457 return doctype
1458
Martin v. Löwis787354c2003-01-25 15:28:29 +00001459 # DOM Level 3 (WD 9 April 2002)
1460
1461 def getInterface(self, feature):
1462 if self.hasFeature(feature, None):
1463 return self
1464 else:
1465 return None
1466
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001467 # internal
Martin v. Löwis787354c2003-01-25 15:28:29 +00001468 def _create_document(self):
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001469 return Document()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001470
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001471class ElementInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001472 """Object that represents content-model information for an element.
1473
1474 This implementation is not expected to be used in practice; DOM
1475 builders should provide implementations which do the right thing
1476 using information available to it.
1477
1478 """
1479
1480 __slots__ = 'tagName',
1481
1482 def __init__(self, name):
1483 self.tagName = name
1484
1485 def getAttributeType(self, aname):
1486 return _no_type
1487
1488 def getAttributeTypeNS(self, namespaceURI, localName):
1489 return _no_type
1490
1491 def isElementContent(self):
1492 return False
1493
1494 def isEmpty(self):
1495 """Returns true iff this element is declared to have an EMPTY
1496 content model."""
1497 return False
1498
1499 def isId(self, aname):
Ezio Melotti42da6632011-03-15 05:18:48 +02001500 """Returns true iff the named attribute is a DTD-style ID."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001501 return False
1502
1503 def isIdNS(self, namespaceURI, localName):
1504 """Returns true iff the identified attribute is a DTD-style ID."""
1505 return False
1506
1507 def __getstate__(self):
1508 return self.tagName
1509
1510 def __setstate__(self, state):
1511 self.tagName = state
1512
1513def _clear_id_cache(node):
1514 if node.nodeType == Node.DOCUMENT_NODE:
1515 node._id_cache.clear()
1516 node._id_search_stack = None
1517 elif _in_document(node):
1518 node.ownerDocument._id_cache.clear()
1519 node.ownerDocument._id_search_stack= None
1520
1521class Document(Node, DocumentLS):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001522 __slots__ = ('_elem_info', 'doctype',
1523 '_id_search_stack', 'childNodes', '_id_cache')
Martin v. Löwis787354c2003-01-25 15:28:29 +00001524 _child_node_types = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
1525 Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)
1526
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001527 implementation = DOMImplementation()
Fred Drake1f549022000-09-24 05:21:58 +00001528 nodeType = Node.DOCUMENT_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +00001529 nodeName = "#document"
1530 nodeValue = None
1531 attributes = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001532 parentNode = None
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001533 previousSibling = nextSibling = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001534
Martin v. Löwis787354c2003-01-25 15:28:29 +00001535
1536 # Document attributes from Level 3 (WD 9 April 2002)
1537
1538 actualEncoding = None
1539 encoding = None
1540 standalone = None
1541 version = None
1542 strictErrorChecking = False
1543 errorHandler = None
1544 documentURI = None
1545
1546 _magic_id_count = 0
1547
1548 def __init__(self):
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001549 self.doctype = None
Martin v. Löwis787354c2003-01-25 15:28:29 +00001550 self.childNodes = NodeList()
1551 # mapping of (namespaceURI, localName) -> ElementInfo
1552 # and tagName -> ElementInfo
1553 self._elem_info = {}
1554 self._id_cache = {}
1555 self._id_search_stack = None
1556
1557 def _get_elem_info(self, element):
1558 if element.namespaceURI:
1559 key = element.namespaceURI, element.localName
1560 else:
1561 key = element.tagName
1562 return self._elem_info.get(key)
1563
1564 def _get_actualEncoding(self):
1565 return self.actualEncoding
1566
1567 def _get_doctype(self):
1568 return self.doctype
1569
1570 def _get_documentURI(self):
1571 return self.documentURI
1572
1573 def _get_encoding(self):
1574 return self.encoding
1575
1576 def _get_errorHandler(self):
1577 return self.errorHandler
1578
1579 def _get_standalone(self):
1580 return self.standalone
1581
1582 def _get_strictErrorChecking(self):
1583 return self.strictErrorChecking
1584
1585 def _get_version(self):
1586 return self.version
Fred Drake55c38192000-06-29 19:39:57 +00001587
Fred Drake1f549022000-09-24 05:21:58 +00001588 def appendChild(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001589 if node.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001590 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001591 "%s cannot be child of %s" % (repr(node), repr(self)))
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001592 if node.parentNode is not None:
Martin v. Löwis787354c2003-01-25 15:28:29 +00001593 # This needs to be done before the next test since this
1594 # may *be* the document element, in which case it should
1595 # end up re-ordered to the end.
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001596 node.parentNode.removeChild(node)
1597
Fred Drakef7cf40d2000-12-14 18:16:11 +00001598 if node.nodeType == Node.ELEMENT_NODE \
1599 and self._get_documentElement():
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001600 raise xml.dom.HierarchyRequestErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001601 "two document elements disallowed")
Fred Drake4ccf4a12000-11-21 22:02:22 +00001602 return Node.appendChild(self, node)
Paul Prescod73678da2000-07-01 04:58:47 +00001603
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001604 def removeChild(self, oldChild):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001605 try:
1606 self.childNodes.remove(oldChild)
1607 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001608 raise xml.dom.NotFoundErr()
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001609 oldChild.nextSibling = oldChild.previousSibling = None
1610 oldChild.parentNode = None
1611 if self.documentElement is oldChild:
1612 self.documentElement = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +00001613
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001614 return oldChild
1615
Fred Drakef7cf40d2000-12-14 18:16:11 +00001616 def _get_documentElement(self):
1617 for node in self.childNodes:
1618 if node.nodeType == Node.ELEMENT_NODE:
1619 return node
1620
1621 def unlink(self):
1622 if self.doctype is not None:
1623 self.doctype.unlink()
1624 self.doctype = None
1625 Node.unlink(self)
1626
Martin v. Löwis787354c2003-01-25 15:28:29 +00001627 def cloneNode(self, deep):
1628 if not deep:
1629 return None
1630 clone = self.implementation.createDocument(None, None, None)
1631 clone.encoding = self.encoding
1632 clone.standalone = self.standalone
1633 clone.version = self.version
1634 for n in self.childNodes:
1635 childclone = _clone_node(n, deep, clone)
1636 assert childclone.ownerDocument.isSameNode(clone)
1637 clone.childNodes.append(childclone)
1638 if childclone.nodeType == Node.DOCUMENT_NODE:
1639 assert clone.documentElement is None
1640 elif childclone.nodeType == Node.DOCUMENT_TYPE_NODE:
1641 assert clone.doctype is None
1642 clone.doctype = childclone
1643 childclone.parentNode = clone
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001644 self._call_user_data_handler(xml.dom.UserDataHandler.NODE_CLONED,
Martin v. Löwis787354c2003-01-25 15:28:29 +00001645 self, clone)
1646 return clone
1647
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001648 def createDocumentFragment(self):
1649 d = DocumentFragment()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001650 d.ownerDocument = self
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001651 return d
Fred Drake55c38192000-06-29 19:39:57 +00001652
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001653 def createElement(self, tagName):
1654 e = Element(tagName)
1655 e.ownerDocument = self
1656 return e
Fred Drake55c38192000-06-29 19:39:57 +00001657
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001658 def createTextNode(self, data):
Christian Heimesc9543e42007-11-28 08:28:28 +00001659 if not isinstance(data, str):
Collin Winter70e79802007-08-24 18:57:22 +00001660 raise TypeError("node contents must be a string")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001661 t = Text()
1662 t.data = data
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001663 t.ownerDocument = self
1664 return t
Fred Drake55c38192000-06-29 19:39:57 +00001665
Fred Drake87432f42001-04-04 14:09:46 +00001666 def createCDATASection(self, data):
Christian Heimesc9543e42007-11-28 08:28:28 +00001667 if not isinstance(data, str):
Collin Winter70e79802007-08-24 18:57:22 +00001668 raise TypeError("node contents must be a string")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001669 c = CDATASection()
1670 c.data = data
Fred Drake87432f42001-04-04 14:09:46 +00001671 c.ownerDocument = self
1672 return c
1673
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001674 def createComment(self, data):
1675 c = Comment(data)
1676 c.ownerDocument = self
1677 return c
Fred Drake55c38192000-06-29 19:39:57 +00001678
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001679 def createProcessingInstruction(self, target, data):
1680 p = ProcessingInstruction(target, data)
1681 p.ownerDocument = self
1682 return p
1683
1684 def createAttribute(self, qName):
1685 a = Attr(qName)
1686 a.ownerDocument = self
Martin v. Löwiscb67ea12001-03-31 16:30:40 +00001687 a.value = ""
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001688 return a
Fred Drake55c38192000-06-29 19:39:57 +00001689
1690 def createElementNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001691 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001692 e = Element(qualifiedName, namespaceURI, prefix)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001693 e.ownerDocument = self
1694 return e
Fred Drake55c38192000-06-29 19:39:57 +00001695
1696 def createAttributeNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001697 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001698 a = Attr(qualifiedName, namespaceURI, localName, prefix)
1699 a.ownerDocument = self
Martin v. Löwiscb67ea12001-03-31 16:30:40 +00001700 a.value = ""
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001701 return a
Fred Drake55c38192000-06-29 19:39:57 +00001702
Martin v. Löwis787354c2003-01-25 15:28:29 +00001703 # A couple of implementation-specific helpers to create node types
1704 # not supported by the W3C DOM specs:
1705
1706 def _create_entity(self, name, publicId, systemId, notationName):
1707 e = Entity(name, publicId, systemId, notationName)
1708 e.ownerDocument = self
1709 return e
1710
1711 def _create_notation(self, name, publicId, systemId):
1712 n = Notation(name, publicId, systemId)
1713 n.ownerDocument = self
1714 return n
1715
1716 def getElementById(self, id):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +00001717 if id in self._id_cache:
Martin v. Löwis787354c2003-01-25 15:28:29 +00001718 return self._id_cache[id]
1719 if not (self._elem_info or self._magic_id_count):
1720 return None
1721
1722 stack = self._id_search_stack
1723 if stack is None:
1724 # we never searched before, or the cache has been cleared
1725 stack = [self.documentElement]
1726 self._id_search_stack = stack
1727 elif not stack:
1728 # Previous search was completed and cache is still valid;
1729 # no matching node.
1730 return None
1731
1732 result = None
1733 while stack:
1734 node = stack.pop()
1735 # add child elements to stack for continued searching
1736 stack.extend([child for child in node.childNodes
1737 if child.nodeType in _nodeTypes_with_children])
1738 # check this node
1739 info = self._get_elem_info(node)
1740 if info:
1741 # We have to process all ID attributes before
1742 # returning in order to get all the attributes set to
1743 # be IDs using Element.setIdAttribute*().
1744 for attr in node.attributes.values():
1745 if attr.namespaceURI:
1746 if info.isIdNS(attr.namespaceURI, attr.localName):
1747 self._id_cache[attr.value] = node
1748 if attr.value == id:
1749 result = node
1750 elif not node._magic_id_nodes:
1751 break
1752 elif info.isId(attr.name):
1753 self._id_cache[attr.value] = node
1754 if attr.value == id:
1755 result = node
1756 elif not node._magic_id_nodes:
1757 break
1758 elif attr._is_id:
1759 self._id_cache[attr.value] = node
1760 if attr.value == id:
1761 result = node
1762 elif node._magic_id_nodes == 1:
1763 break
1764 elif node._magic_id_nodes:
1765 for attr in node.attributes.values():
1766 if attr._is_id:
1767 self._id_cache[attr.value] = node
1768 if attr.value == id:
1769 result = node
1770 if result is not None:
1771 break
1772 return result
1773
Fred Drake1f549022000-09-24 05:21:58 +00001774 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001775 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drakefbe7b4f2001-07-04 06:25:53 +00001776
1777 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001778 return _get_elements_by_tagName_ns_helper(
1779 self, namespaceURI, localName, NodeList())
1780
1781 def isSupported(self, feature, version):
1782 return self.implementation.hasFeature(feature, version)
1783
1784 def importNode(self, node, deep):
1785 if node.nodeType == Node.DOCUMENT_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001786 raise xml.dom.NotSupportedErr("cannot import document nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001787 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001788 raise xml.dom.NotSupportedErr("cannot import document type nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001789 return _clone_node(node, deep, self)
Fred Drake55c38192000-06-29 19:39:57 +00001790
Henry Harutyunyandc04a052020-02-29 12:22:19 +04001791 def writexml(self, writer, indent="", addindent="", newl="", encoding=None,
1792 standalone=None):
1793 declarations = []
1794
1795 if encoding:
1796 declarations.append(f'encoding="{encoding}"')
1797 if standalone is not None:
1798 declarations.append(f'standalone="{"yes" if standalone else "no"}"')
1799
1800 writer.write(f'<?xml version="1.0" {" ".join(declarations)}?>{newl}')
1801
Fred Drake55c38192000-06-29 19:39:57 +00001802 for node in self.childNodes:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001803 node.writexml(writer, indent, addindent, newl)
Fred Drake55c38192000-06-29 19:39:57 +00001804
Martin v. Löwis787354c2003-01-25 15:28:29 +00001805 # DOM Level 3 (WD 9 April 2002)
1806
1807 def renameNode(self, n, namespaceURI, name):
1808 if n.ownerDocument is not self:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001809 raise xml.dom.WrongDocumentErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001810 "cannot rename nodes from other documents;\n"
1811 "expected %s,\nfound %s" % (self, n.ownerDocument))
1812 if n.nodeType not in (Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001813 raise xml.dom.NotSupportedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001814 "renameNode() only applies to element and attribute nodes")
1815 if namespaceURI != EMPTY_NAMESPACE:
1816 if ':' in name:
1817 prefix, localName = name.split(':', 1)
1818 if ( prefix == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001819 and namespaceURI != xml.dom.XMLNS_NAMESPACE):
1820 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001821 "illegal use of 'xmlns' prefix")
1822 else:
1823 if ( name == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001824 and namespaceURI != xml.dom.XMLNS_NAMESPACE
Martin v. Löwis787354c2003-01-25 15:28:29 +00001825 and n.nodeType == Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001826 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001827 "illegal use of the 'xmlns' attribute")
1828 prefix = None
1829 localName = name
1830 else:
1831 prefix = None
1832 localName = None
1833 if n.nodeType == Node.ATTRIBUTE_NODE:
1834 element = n.ownerElement
1835 if element is not None:
1836 is_id = n._is_id
1837 element.removeAttributeNode(n)
1838 else:
1839 element = None
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001840 n.prefix = prefix
1841 n._localName = localName
1842 n.namespaceURI = namespaceURI
1843 n.nodeName = name
Martin v. Löwis787354c2003-01-25 15:28:29 +00001844 if n.nodeType == Node.ELEMENT_NODE:
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001845 n.tagName = name
Martin v. Löwis787354c2003-01-25 15:28:29 +00001846 else:
1847 # attribute node
Martin v. Löwis14aa2802012-02-19 20:25:12 +01001848 n.name = name
Martin v. Löwis787354c2003-01-25 15:28:29 +00001849 if element is not None:
1850 element.setAttributeNode(n)
1851 if is_id:
1852 element.setIdAttributeNode(n)
1853 # It's not clear from a semantic perspective whether we should
1854 # call the user data handlers for the NODE_RENAMED event since
1855 # we're re-using the existing node. The draft spec has been
1856 # interpreted as meaning "no, don't call the handler unless a
1857 # new node is created."
1858 return n
1859
1860defproperty(Document, "documentElement",
1861 doc="Top-level element of this document.")
1862
1863
1864def _clone_node(node, deep, newOwnerDocument):
1865 """
1866 Clone a node and give it the new owner document.
1867 Called by Node.cloneNode and Document.importNode
1868 """
1869 if node.ownerDocument.isSameNode(newOwnerDocument):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001870 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001871 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001872 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001873 if node.nodeType == Node.ELEMENT_NODE:
1874 clone = newOwnerDocument.createElementNS(node.namespaceURI,
1875 node.nodeName)
1876 for attr in node.attributes.values():
1877 clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value)
1878 a = clone.getAttributeNodeNS(attr.namespaceURI, attr.localName)
1879 a.specified = attr.specified
1880
1881 if deep:
1882 for child in node.childNodes:
1883 c = _clone_node(child, deep, newOwnerDocument)
1884 clone.appendChild(c)
1885
1886 elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
1887 clone = newOwnerDocument.createDocumentFragment()
1888 if deep:
1889 for child in node.childNodes:
1890 c = _clone_node(child, deep, newOwnerDocument)
1891 clone.appendChild(c)
1892
1893 elif node.nodeType == Node.TEXT_NODE:
1894 clone = newOwnerDocument.createTextNode(node.data)
1895 elif node.nodeType == Node.CDATA_SECTION_NODE:
1896 clone = newOwnerDocument.createCDATASection(node.data)
1897 elif node.nodeType == Node.PROCESSING_INSTRUCTION_NODE:
1898 clone = newOwnerDocument.createProcessingInstruction(node.target,
1899 node.data)
1900 elif node.nodeType == Node.COMMENT_NODE:
1901 clone = newOwnerDocument.createComment(node.data)
1902 elif node.nodeType == Node.ATTRIBUTE_NODE:
1903 clone = newOwnerDocument.createAttributeNS(node.namespaceURI,
1904 node.nodeName)
1905 clone.specified = True
1906 clone.value = node.value
1907 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
1908 assert node.ownerDocument is not newOwnerDocument
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001909 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001910 clone = newOwnerDocument.implementation.createDocumentType(
1911 node.name, node.publicId, node.systemId)
1912 clone.ownerDocument = newOwnerDocument
1913 if deep:
1914 clone.entities._seq = []
1915 clone.notations._seq = []
1916 for n in node.notations._seq:
1917 notation = Notation(n.nodeName, n.publicId, n.systemId)
1918 notation.ownerDocument = newOwnerDocument
1919 clone.notations._seq.append(notation)
1920 if hasattr(n, '_call_user_data_handler'):
1921 n._call_user_data_handler(operation, n, notation)
1922 for e in node.entities._seq:
1923 entity = Entity(e.nodeName, e.publicId, e.systemId,
1924 e.notationName)
1925 entity.actualEncoding = e.actualEncoding
1926 entity.encoding = e.encoding
1927 entity.version = e.version
1928 entity.ownerDocument = newOwnerDocument
1929 clone.entities._seq.append(entity)
1930 if hasattr(e, '_call_user_data_handler'):
Victor Stinner8e041862018-12-10 11:12:53 +01001931 e._call_user_data_handler(operation, e, entity)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001932 else:
1933 # Note the cloning of Document and DocumentType nodes is
Ezio Melotti13925002011-03-16 11:05:33 +02001934 # implementation specific. minidom handles those cases
Martin v. Löwis787354c2003-01-25 15:28:29 +00001935 # directly in the cloneNode() methods.
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001936 raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001937
1938 # Check for _call_user_data_handler() since this could conceivably
1939 # used with other DOM implementations (one of the FourThought
1940 # DOMs, perhaps?).
1941 if hasattr(node, '_call_user_data_handler'):
1942 node._call_user_data_handler(operation, node, clone)
1943 return clone
1944
1945
1946def _nssplit(qualifiedName):
1947 fields = qualifiedName.split(':', 1)
1948 if len(fields) == 2:
1949 return fields
1950 else:
1951 return (None, fields[0])
1952
1953
Martin v. Löwis787354c2003-01-25 15:28:29 +00001954def _do_pulldom_parse(func, args, kwargs):
Raymond Hettingerff41c482003-04-06 09:01:11 +00001955 events = func(*args, **kwargs)
Fred Drake1f549022000-09-24 05:21:58 +00001956 toktype, rootNode = events.getEvent()
1957 events.expandNode(rootNode)
Martin v. Löwisb417be22001-02-06 01:16:06 +00001958 events.clear()
Fred Drake55c38192000-06-29 19:39:57 +00001959 return rootNode
1960
Martin v. Löwis787354c2003-01-25 15:28:29 +00001961def parse(file, parser=None, bufsize=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001962 """Parse a file into a DOM by filename or file object."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001963 if parser is None and not bufsize:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001964 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001965 return expatbuilder.parse(file)
1966 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001967 from xml.dom import pulldom
Raymond Hettingerff41c482003-04-06 09:01:11 +00001968 return _do_pulldom_parse(pulldom.parse, (file,),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001969 {'parser': parser, 'bufsize': bufsize})
Fred Drake55c38192000-06-29 19:39:57 +00001970
Martin v. Löwis787354c2003-01-25 15:28:29 +00001971def parseString(string, parser=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001972 """Parse a file into a DOM from a string."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001973 if parser is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001974 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001975 return expatbuilder.parseString(string)
1976 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001977 from xml.dom import pulldom
Martin v. Löwis787354c2003-01-25 15:28:29 +00001978 return _do_pulldom_parse(pulldom.parseString, (string,),
1979 {'parser': parser})
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001980
Martin v. Löwis787354c2003-01-25 15:28:29 +00001981def getDOMImplementation(features=None):
1982 if features:
Christian Heimesc9543e42007-11-28 08:28:28 +00001983 if isinstance(features, str):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001984 features = domreg._parse_feature_string(features)
1985 for f, v in features:
1986 if not Document.implementation.hasFeature(f, v):
1987 return None
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001988 return Document.implementation