blob: 1870ebd8a2dbf6f2b3b30be738accad3267684a5 [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
Alexandre Vassalotti794652d2008-06-11 22:58:36 +000018import codecs
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000019import io
Thomas Wouters0e3f5912006-08-11 14:57:12 +000020import xml.dom
Fred Drake55c38192000-06-29 19:39:57 +000021
Thomas Wouters0e3f5912006-08-11 14:57:12 +000022from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE, domreg
23from xml.dom.minicompat import *
24from xml.dom.xmlbuilder import DOMImplementationLS, DocumentLS
Fred Drake3ac6a092001-09-28 04:33:06 +000025
Martin v. Löwis787354c2003-01-25 15:28:29 +000026# This is used by the ID-cache invalidation checks; the list isn't
27# actually complete, since the nodes being checked will never be the
28# DOCUMENT_NODE or DOCUMENT_FRAGMENT_NODE. (The node being checked is
29# the node being added or removed, not the node being modified.)
30#
Thomas Wouters0e3f5912006-08-11 14:57:12 +000031_nodeTypes_with_children = (xml.dom.Node.ELEMENT_NODE,
32 xml.dom.Node.ENTITY_REFERENCE_NODE)
Martin v. Löwis95700f72002-03-15 13:51:59 +000033
Fred Drake3ac6a092001-09-28 04:33:06 +000034
Thomas Wouters0e3f5912006-08-11 14:57:12 +000035class Node(xml.dom.Node):
Martin v. Löwis126f2f62001-03-13 10:50:13 +000036 namespaceURI = None # this is non-null only for elements and attributes
Fred Drake575712e2001-09-28 20:25:45 +000037 parentNode = None
38 ownerDocument = None
Martin v. Löwis787354c2003-01-25 15:28:29 +000039 nextSibling = None
40 previousSibling = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +000041
Martin v. Löwis787354c2003-01-25 15:28:29 +000042 prefix = EMPTY_PREFIX # non-null only for NS elements and attributes
Fred Drake55c38192000-06-29 19:39:57 +000043
Jack Diederich4dafcc42006-11-28 19:15:13 +000044 def __bool__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +000045 return True
Fred Drake55c38192000-06-29 19:39:57 +000046
Georg Brandlfe991052009-09-16 15:54:04 +000047 def toxml(self, encoding=None):
Martin v. Löwis7d650ca2002-06-30 15:05:00 +000048 return self.toprettyxml("", "", encoding)
Fred Drake55c38192000-06-29 19:39:57 +000049
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000050 def toprettyxml(self, indent="\t", newl="\n", encoding=None):
Martin v. Löwiscb67ea12001-03-31 16:30:40 +000051 # indent = the indentation string to prepend, per level
52 # newl = the newline string to append
Guido van Rossum55b15c92007-08-07 23:03:33 +000053 use_encoding = "utf-8" if encoding is None else encoding
Alexandre Vassalotti794652d2008-06-11 22:58:36 +000054 writer = codecs.getwriter(use_encoding)(io.BytesIO())
Martin v. Löwis7d650ca2002-06-30 15:05:00 +000055 if self.nodeType == Node.DOCUMENT_NODE:
56 # Can pass encoding only to document, to put it into XML header
57 self.writexml(writer, "", indent, newl, encoding)
58 else:
59 self.writexml(writer, "", indent, newl)
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000060 if encoding is None:
Alexandre Vassalotti794652d2008-06-11 22:58:36 +000061 return writer.stream.getvalue().decode(use_encoding)
Guido van Rossum3e1f85e2007-07-27 18:03:11 +000062 else:
Alexandre Vassalotti794652d2008-06-11 22:58:36 +000063 return writer.stream.getvalue()
Martin v. Löwis46fa39a2001-02-06 00:14:08 +000064
Fred Drake1f549022000-09-24 05:21:58 +000065 def hasChildNodes(self):
66 if self.childNodes:
Martin v. Löwis787354c2003-01-25 15:28:29 +000067 return True
Fred Drake1f549022000-09-24 05:21:58 +000068 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +000069 return False
70
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]
290 node.__dict__["previousSibling"] = last
291 last.__dict__["nextSibling"] = node
292 childNodes.append(node)
293 node.__dict__["parentNode"] = self
294
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):
Fred Drake1f549022000-09-24 05:21:58 +0000346 nodeType = Node.ATTRIBUTE_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +0000347 attributes = None
348 ownerElement = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000349 specified = False
350 _is_id = False
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000351
Martin v. Löwis787354c2003-01-25 15:28:29 +0000352 _child_node_types = (Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE)
353
354 def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None,
355 prefix=None):
Fred Drake55c38192000-06-29 19:39:57 +0000356 # skip setattr for performance
Fred Drake4ccf4a12000-11-21 22:02:22 +0000357 d = self.__dict__
Fred Drake4ccf4a12000-11-21 22:02:22 +0000358 d["nodeName"] = d["name"] = qName
359 d["namespaceURI"] = namespaceURI
360 d["prefix"] = prefix
Martin v. Löwis787354c2003-01-25 15:28:29 +0000361 d['childNodes'] = NodeList()
362
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):
Alex Martelli0ee43512006-08-21 19:53:20 +0000369 if 'localName' in self.__dict__:
Guido van Rossum3e1f85e2007-07-27 18:03:11 +0000370 return self.__dict__['localName']
Martin v. Löwis787354c2003-01-25 15:28:29 +0000371 return self.nodeName.split(":", 1)[-1]
372
373 def _get_name(self):
374 return self.name
375
376 def _get_specified(self):
377 return self.specified
378
Fred Drake1f549022000-09-24 05:21:58 +0000379 def __setattr__(self, name, value):
Fred Drakef7cf40d2000-12-14 18:16:11 +0000380 d = self.__dict__
Fred Drake1f549022000-09-24 05:21:58 +0000381 if name in ("value", "nodeValue"):
Fred Drakef7cf40d2000-12-14 18:16:11 +0000382 d["value"] = d["nodeValue"] = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000383 d2 = self.childNodes[0].__dict__
384 d2["data"] = d2["nodeValue"] = value
385 if self.ownerElement is not None:
386 _clear_id_cache(self.ownerElement)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000387 elif name in ("name", "nodeName"):
388 d["name"] = d["nodeName"] = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000389 if self.ownerElement is not None:
390 _clear_id_cache(self.ownerElement)
Fred Drake55c38192000-06-29 19:39:57 +0000391 else:
Fred Drakef7cf40d2000-12-14 18:16:11 +0000392 d[name] = value
Fred Drake55c38192000-06-29 19:39:57 +0000393
Martin v. Löwis995359c2003-01-26 08:59:32 +0000394 def _set_prefix(self, prefix):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000395 nsuri = self.namespaceURI
Martin v. Löwis995359c2003-01-26 08:59:32 +0000396 if prefix == "xmlns":
397 if nsuri and nsuri != XMLNS_NAMESPACE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000398 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000399 "illegal use of 'xmlns' prefix for the wrong namespace")
400 d = self.__dict__
401 d['prefix'] = prefix
402 if prefix is None:
403 newName = self.localName
404 else:
Martin v. Löwis995359c2003-01-26 08:59:32 +0000405 newName = "%s:%s" % (prefix, self.localName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000406 if self.ownerElement:
407 _clear_id_cache(self.ownerElement)
408 d['nodeName'] = d['name'] = newName
409
410 def _set_value(self, value):
411 d = self.__dict__
412 d['value'] = d['nodeValue'] = value
413 if self.ownerElement:
414 _clear_id_cache(self.ownerElement)
415 self.childNodes[0].data = value
416
417 def unlink(self):
418 # This implementation does not call the base implementation
419 # since most of that is not needed, and the expense of the
420 # method call is not warranted. We duplicate the removal of
421 # children, but that's all we needed from the base class.
422 elem = self.ownerElement
423 if elem is not None:
424 del elem._attrs[self.nodeName]
425 del elem._attrsNS[(self.namespaceURI, self.localName)]
426 if self._is_id:
427 self._is_id = False
428 elem._magic_id_nodes -= 1
429 self.ownerDocument._magic_id_count -= 1
430 for child in self.childNodes:
431 child.unlink()
432 del self.childNodes[:]
433
434 def _get_isId(self):
435 if self._is_id:
436 return True
437 doc = self.ownerDocument
438 elem = self.ownerElement
439 if doc is None or elem is None:
440 return False
441
442 info = doc._get_elem_info(elem)
443 if info is None:
444 return False
445 if self.namespaceURI:
446 return info.isIdNS(self.namespaceURI, self.localName)
447 else:
448 return info.isId(self.nodeName)
449
450 def _get_schemaType(self):
451 doc = self.ownerDocument
452 elem = self.ownerElement
453 if doc is None or elem is None:
454 return _no_type
455
456 info = doc._get_elem_info(elem)
457 if info is None:
458 return _no_type
459 if self.namespaceURI:
460 return info.getAttributeTypeNS(self.namespaceURI, self.localName)
461 else:
462 return info.getAttributeType(self.nodeName)
463
464defproperty(Attr, "isId", doc="True if this attribute is an ID.")
465defproperty(Attr, "localName", doc="Namespace-local name of this attribute.")
466defproperty(Attr, "schemaType", doc="Schema type for this attribute.")
Fred Drake4ccf4a12000-11-21 22:02:22 +0000467
Fred Drakef7cf40d2000-12-14 18:16:11 +0000468
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000469class NamedNodeMap(object):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000470 """The attribute list is a transient interface to the underlying
471 dictionaries. Mutations here will change the underlying element's
Fred Drakef7cf40d2000-12-14 18:16:11 +0000472 dictionary.
473
474 Ordering is imposed artificially and does not reflect the order of
475 attributes as found in an input document.
476 """
Fred Drake4ccf4a12000-11-21 22:02:22 +0000477
Martin v. Löwis787354c2003-01-25 15:28:29 +0000478 __slots__ = ('_attrs', '_attrsNS', '_ownerElement')
479
Fred Drake2998a552001-12-06 18:27:48 +0000480 def __init__(self, attrs, attrsNS, ownerElement):
Fred Drake1f549022000-09-24 05:21:58 +0000481 self._attrs = attrs
482 self._attrsNS = attrsNS
Fred Drake2998a552001-12-06 18:27:48 +0000483 self._ownerElement = ownerElement
Fred Drakef7cf40d2000-12-14 18:16:11 +0000484
Martin v. Löwis787354c2003-01-25 15:28:29 +0000485 def _get_length(self):
486 return len(self._attrs)
Fred Drake55c38192000-06-29 19:39:57 +0000487
Fred Drake1f549022000-09-24 05:21:58 +0000488 def item(self, index):
Fred Drake55c38192000-06-29 19:39:57 +0000489 try:
Brett Cannon861fd6f2007-02-21 22:05:37 +0000490 return self[list(self._attrs.keys())[index]]
Fred Drake55c38192000-06-29 19:39:57 +0000491 except IndexError:
492 return None
Fred Drake55c38192000-06-29 19:39:57 +0000493
Fred Drake1f549022000-09-24 05:21:58 +0000494 def items(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000495 L = []
496 for node in self._attrs.values():
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000497 L.append((node.nodeName, node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000498 return L
Fred Drake1f549022000-09-24 05:21:58 +0000499
500 def itemsNS(self):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000501 L = []
502 for node in self._attrs.values():
Fred Drake49a5d032001-11-30 22:21:58 +0000503 L.append(((node.namespaceURI, node.localName), node.value))
Fred Drake4ccf4a12000-11-21 22:02:22 +0000504 return L
Fred Drake16f63292000-10-23 18:09:50 +0000505
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000506 def __contains__(self, key):
Christian Heimesc9543e42007-11-28 08:28:28 +0000507 if isinstance(key, str):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000508 return key in self._attrs
Martin v. Löwis787354c2003-01-25 15:28:29 +0000509 else:
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000510 return key in self._attrsNS
Martin v. Löwis787354c2003-01-25 15:28:29 +0000511
Fred Drake1f549022000-09-24 05:21:58 +0000512 def keys(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000513 return self._attrs.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000514
Fred Drake1f549022000-09-24 05:21:58 +0000515 def keysNS(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000516 return self._attrsNS.keys()
Fred Drake55c38192000-06-29 19:39:57 +0000517
Fred Drake1f549022000-09-24 05:21:58 +0000518 def values(self):
Paul Prescod73678da2000-07-01 04:58:47 +0000519 return self._attrs.values()
Fred Drake55c38192000-06-29 19:39:57 +0000520
Martin v. Löwis787354c2003-01-25 15:28:29 +0000521 def get(self, name, value=None):
Martin v. Löwisd5fb58f2001-01-27 08:38:34 +0000522 return self._attrs.get(name, value)
523
Martin v. Löwis787354c2003-01-25 15:28:29 +0000524 __len__ = _get_length
Fred Drake55c38192000-06-29 19:39:57 +0000525
Mark Dickinsona56c4672009-01-27 18:17:45 +0000526 def _cmp(self, other):
Fred Drake1f549022000-09-24 05:21:58 +0000527 if self._attrs is getattr(other, "_attrs", None):
Fred Drake55c38192000-06-29 19:39:57 +0000528 return 0
Fred Drake16f63292000-10-23 18:09:50 +0000529 else:
Mark Dickinsona56c4672009-01-27 18:17:45 +0000530 return (id(self) > id(other)) - (id(self) < id(other))
531
532 def __eq__(self, other):
533 return self._cmp(other) == 0
534
535 def __ge__(self, other):
536 return self._cmp(other) >= 0
537
538 def __gt__(self, other):
539 return self._cmp(other) > 0
540
541 def __le__(self, other):
542 return self._cmp(other) <= 0
543
544 def __lt__(self, other):
545 return self._cmp(other) < 0
546
547 def __ne__(self, other):
548 return self._cmp(other) != 0
Fred Drake55c38192000-06-29 19:39:57 +0000549
Fred Drake1f549022000-09-24 05:21:58 +0000550 def __getitem__(self, attname_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000551 if isinstance(attname_or_tuple, tuple):
Paul Prescod73678da2000-07-01 04:58:47 +0000552 return self._attrsNS[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000553 else:
Paul Prescod73678da2000-07-01 04:58:47 +0000554 return self._attrs[attname_or_tuple]
Fred Drake55c38192000-06-29 19:39:57 +0000555
Paul Prescod1e688272000-07-01 19:21:47 +0000556 # same as set
Fred Drake1f549022000-09-24 05:21:58 +0000557 def __setitem__(self, attname, value):
Christian Heimesc9543e42007-11-28 08:28:28 +0000558 if isinstance(value, str):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000559 try:
560 node = self._attrs[attname]
561 except KeyError:
562 node = Attr(attname)
563 node.ownerDocument = self._ownerElement.ownerDocument
Martin v. Löwis995359c2003-01-26 08:59:32 +0000564 self.setNamedItem(node)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000565 node.value = value
Paul Prescod1e688272000-07-01 19:21:47 +0000566 else:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000567 if not isinstance(value, Attr):
Collin Winter70e79802007-08-24 18:57:22 +0000568 raise TypeError("value must be a string or Attr object")
Fred Drake1f549022000-09-24 05:21:58 +0000569 node = value
Martin v. Löwis787354c2003-01-25 15:28:29 +0000570 self.setNamedItem(node)
571
572 def getNamedItem(self, name):
573 try:
574 return self._attrs[name]
575 except KeyError:
576 return None
577
578 def getNamedItemNS(self, namespaceURI, localName):
579 try:
580 return self._attrsNS[(namespaceURI, localName)]
581 except KeyError:
582 return None
583
584 def removeNamedItem(self, name):
585 n = self.getNamedItem(name)
586 if n is not None:
587 _clear_id_cache(self._ownerElement)
588 del self._attrs[n.nodeName]
589 del self._attrsNS[(n.namespaceURI, n.localName)]
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000590 if 'ownerElement' in n.__dict__:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000591 n.__dict__['ownerElement'] = None
592 return n
593 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000594 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000595
596 def removeNamedItemNS(self, namespaceURI, localName):
597 n = self.getNamedItemNS(namespaceURI, localName)
598 if n is not None:
599 _clear_id_cache(self._ownerElement)
600 del self._attrsNS[(n.namespaceURI, n.localName)]
601 del self._attrs[n.nodeName]
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000602 if 'ownerElement' in n.__dict__:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000603 n.__dict__['ownerElement'] = None
604 return n
605 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000606 raise xml.dom.NotFoundErr()
Fred Drakef7cf40d2000-12-14 18:16:11 +0000607
608 def setNamedItem(self, node):
Andrew M. Kuchlingbc8f72c2001-02-21 01:30:26 +0000609 if not isinstance(node, Attr):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000610 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000611 "%s cannot be child of %s" % (repr(node), repr(self)))
Fred Drakef7cf40d2000-12-14 18:16:11 +0000612 old = self._attrs.get(node.name)
Paul Prescod1e688272000-07-01 19:21:47 +0000613 if old:
614 old.unlink()
Fred Drake1f549022000-09-24 05:21:58 +0000615 self._attrs[node.name] = node
616 self._attrsNS[(node.namespaceURI, node.localName)] = node
Fred Drake2998a552001-12-06 18:27:48 +0000617 node.ownerElement = self._ownerElement
Martin v. Löwis787354c2003-01-25 15:28:29 +0000618 _clear_id_cache(node.ownerElement)
Fred Drakef7cf40d2000-12-14 18:16:11 +0000619 return old
620
621 def setNamedItemNS(self, node):
622 return self.setNamedItem(node)
Paul Prescod73678da2000-07-01 04:58:47 +0000623
Fred Drake1f549022000-09-24 05:21:58 +0000624 def __delitem__(self, attname_or_tuple):
625 node = self[attname_or_tuple]
Martin v. Löwis787354c2003-01-25 15:28:29 +0000626 _clear_id_cache(node.ownerElement)
Paul Prescod73678da2000-07-01 04:58:47 +0000627 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000628
629 def __getstate__(self):
630 return self._attrs, self._attrsNS, self._ownerElement
631
632 def __setstate__(self, state):
633 self._attrs, self._attrsNS, self._ownerElement = state
634
635defproperty(NamedNodeMap, "length",
636 doc="Number of nodes in the NamedNodeMap.")
Fred Drakef7cf40d2000-12-14 18:16:11 +0000637
638AttributeList = NamedNodeMap
639
Fred Drake1f549022000-09-24 05:21:58 +0000640
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000641class TypeInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000642 __slots__ = 'namespace', 'name'
643
644 def __init__(self, namespace, name):
645 self.namespace = namespace
646 self.name = name
647
648 def __repr__(self):
649 if self.namespace:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000650 return "<TypeInfo %r (from %r)>" % (self.name, self.namespace)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000651 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000652 return "<TypeInfo %r>" % 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):
Fred Drake1f549022000-09-24 05:21:58 +0000663 nodeType = Node.ELEMENT_NODE
Martin v. Löwis787354c2003-01-25 15:28:29 +0000664 nodeValue = None
665 schemaType = _no_type
666
667 _magic_id_nodes = 0
668
669 _child_node_types = (Node.ELEMENT_NODE,
670 Node.PROCESSING_INSTRUCTION_NODE,
671 Node.COMMENT_NODE,
672 Node.TEXT_NODE,
673 Node.CDATA_SECTION_NODE,
674 Node.ENTITY_REFERENCE_NODE)
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000675
Fred Drake49a5d032001-11-30 22:21:58 +0000676 def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None,
Fred Drake1f549022000-09-24 05:21:58 +0000677 localName=None):
Fred Drake55c38192000-06-29 19:39:57 +0000678 self.tagName = self.nodeName = tagName
Fred Drake1f549022000-09-24 05:21:58 +0000679 self.prefix = prefix
680 self.namespaceURI = namespaceURI
Martin v. Löwis787354c2003-01-25 15:28:29 +0000681 self.childNodes = NodeList()
Fred Drake55c38192000-06-29 19:39:57 +0000682
Fred Drake4ccf4a12000-11-21 22:02:22 +0000683 self._attrs = {} # attributes are double-indexed:
684 self._attrsNS = {} # tagName -> Attribute
685 # URI,localName -> Attribute
686 # in the future: consider lazy generation
687 # of attribute objects this is too tricky
688 # for now because of headaches with
689 # namespaces.
690
Martin v. Löwis787354c2003-01-25 15:28:29 +0000691 def _get_localName(self):
Alex Martelli0ee43512006-08-21 19:53:20 +0000692 if 'localName' in self.__dict__:
Guido van Rossum3e1f85e2007-07-27 18:03:11 +0000693 return self.__dict__['localName']
Martin v. Löwis787354c2003-01-25 15:28:29 +0000694 return self.tagName.split(":", 1)[-1]
695
696 def _get_tagName(self):
697 return self.tagName
Fred Drake4ccf4a12000-11-21 22:02:22 +0000698
699 def unlink(self):
Brett Cannon861fd6f2007-02-21 22:05:37 +0000700 for attr in list(self._attrs.values()):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000701 attr.unlink()
702 self._attrs = None
703 self._attrsNS = None
704 Node.unlink(self)
Fred Drake55c38192000-06-29 19:39:57 +0000705
Fred Drake1f549022000-09-24 05:21:58 +0000706 def getAttribute(self, attname):
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000707 try:
708 return self._attrs[attname].value
709 except KeyError:
710 return ""
Fred Drake55c38192000-06-29 19:39:57 +0000711
Fred Drake1f549022000-09-24 05:21:58 +0000712 def getAttributeNS(self, namespaceURI, localName):
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000713 try:
714 return self._attrsNS[(namespaceURI, localName)].value
715 except KeyError:
716 return ""
Fred Drake1f549022000-09-24 05:21:58 +0000717
718 def setAttribute(self, attname, value):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000719 attr = self.getAttributeNode(attname)
720 if attr is None:
721 attr = Attr(attname)
722 # for performance
723 d = attr.__dict__
724 d["value"] = d["nodeValue"] = value
725 d["ownerDocument"] = self.ownerDocument
726 self.setAttributeNode(attr)
727 elif value != attr.value:
728 d = attr.__dict__
729 d["value"] = d["nodeValue"] = value
730 if attr.isId:
731 _clear_id_cache(self)
Fred Drake55c38192000-06-29 19:39:57 +0000732
Fred Drake1f549022000-09-24 05:21:58 +0000733 def setAttributeNS(self, namespaceURI, qualifiedName, value):
734 prefix, localname = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +0000735 attr = self.getAttributeNodeNS(namespaceURI, localname)
736 if attr is None:
737 # for performance
738 attr = Attr(qualifiedName, namespaceURI, localname, prefix)
739 d = attr.__dict__
740 d["prefix"] = prefix
741 d["nodeName"] = qualifiedName
742 d["value"] = d["nodeValue"] = value
743 d["ownerDocument"] = self.ownerDocument
744 self.setAttributeNode(attr)
745 else:
746 d = attr.__dict__
747 if value != attr.value:
748 d["value"] = d["nodeValue"] = value
749 if attr.isId:
750 _clear_id_cache(self)
751 if attr.prefix != prefix:
752 d["prefix"] = prefix
753 d["nodeName"] = qualifiedName
Fred Drake55c38192000-06-29 19:39:57 +0000754
Fred Drake1f549022000-09-24 05:21:58 +0000755 def getAttributeNode(self, attrname):
756 return self._attrs.get(attrname)
Paul Prescod73678da2000-07-01 04:58:47 +0000757
Fred Drake1f549022000-09-24 05:21:58 +0000758 def getAttributeNodeNS(self, namespaceURI, localName):
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000759 return self._attrsNS.get((namespaceURI, localName))
Paul Prescod73678da2000-07-01 04:58:47 +0000760
Fred Drake1f549022000-09-24 05:21:58 +0000761 def setAttributeNode(self, attr):
Fred Drake4ccf4a12000-11-21 22:02:22 +0000762 if attr.ownerElement not in (None, self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000763 raise xml.dom.InuseAttributeErr("attribute node already owned")
Martin v. Löwis787354c2003-01-25 15:28:29 +0000764 old1 = self._attrs.get(attr.name, None)
765 if old1 is not None:
766 self.removeAttributeNode(old1)
767 old2 = self._attrsNS.get((attr.namespaceURI, attr.localName), None)
768 if old2 is not None and old2 is not old1:
769 self.removeAttributeNode(old2)
770 _set_attribute_node(self, attr)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000771
Martin v. Löwis787354c2003-01-25 15:28:29 +0000772 if old1 is not attr:
Fred Drake4ccf4a12000-11-21 22:02:22 +0000773 # It might have already been part of this node, in which case
774 # it doesn't represent a change, and should not be returned.
Martin v. Löwis787354c2003-01-25 15:28:29 +0000775 return old1
776 if old2 is not attr:
777 return old2
Fred Drake55c38192000-06-29 19:39:57 +0000778
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000779 setAttributeNodeNS = setAttributeNode
780
Fred Drake1f549022000-09-24 05:21:58 +0000781 def removeAttribute(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000782 try:
783 attr = self._attrs[name]
784 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000785 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000786 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000787
Fred Drake1f549022000-09-24 05:21:58 +0000788 def removeAttributeNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000789 try:
790 attr = self._attrsNS[(namespaceURI, localName)]
791 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000792 raise xml.dom.NotFoundErr()
Fred Drake1f549022000-09-24 05:21:58 +0000793 self.removeAttributeNode(attr)
Fred Drake55c38192000-06-29 19:39:57 +0000794
Fred Drake1f549022000-09-24 05:21:58 +0000795 def removeAttributeNode(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000796 if node is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000797 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000798 try:
799 self._attrs[node.name]
800 except KeyError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000801 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000802 _clear_id_cache(self)
Paul Prescod73678da2000-07-01 04:58:47 +0000803 node.unlink()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000804 # Restore this since the node is still useful and otherwise
805 # unlinked
806 node.ownerDocument = self.ownerDocument
Fred Drake16f63292000-10-23 18:09:50 +0000807
Martin v. Löwis126f2f62001-03-13 10:50:13 +0000808 removeAttributeNodeNS = removeAttributeNode
809
Martin v. Löwis156c3372000-12-28 18:40:56 +0000810 def hasAttribute(self, name):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000811 return name in self._attrs
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000812
Martin v. Löwis156c3372000-12-28 18:40:56 +0000813 def hasAttributeNS(self, namespaceURI, localName):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +0000814 return (namespaceURI, localName) in self._attrsNS
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000815
Fred Drake1f549022000-09-24 05:21:58 +0000816 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000817 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000818
Fred Drake1f549022000-09-24 05:21:58 +0000819 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000820 return _get_elements_by_tagName_ns_helper(
821 self, namespaceURI, localName, NodeList())
Fred Drake55c38192000-06-29 19:39:57 +0000822
Fred Drake1f549022000-09-24 05:21:58 +0000823 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000824 return "<DOM Element: %s at %#x>" % (self.tagName, id(self))
Fred Drake55c38192000-06-29 19:39:57 +0000825
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000826 def writexml(self, writer, indent="", addindent="", newl=""):
827 # indent = current indentation
828 # addindent = indentation to add to higher levels
829 # newl = newline string
830 writer.write(indent+"<" + self.tagName)
Fred Drake16f63292000-10-23 18:09:50 +0000831
Fred Drake4ccf4a12000-11-21 22:02:22 +0000832 attrs = self._get_attributes()
Brett Cannon861fd6f2007-02-21 22:05:37 +0000833 a_names = sorted(attrs.keys())
Fred Drake55c38192000-06-29 19:39:57 +0000834
835 for a_name in a_names:
Fred Drake1f549022000-09-24 05:21:58 +0000836 writer.write(" %s=\"" % a_name)
Fred Drake4ccf4a12000-11-21 22:02:22 +0000837 _write_data(writer, attrs[a_name].value)
Fred Drake55c38192000-06-29 19:39:57 +0000838 writer.write("\"")
839 if self.childNodes:
R David Murray791744b2011-10-01 16:19:51 -0400840 writer.write(">")
Ezio Melotti8008f2a2011-11-18 17:34:26 +0200841 if (len(self.childNodes) == 1 and
842 self.childNodes[0].nodeType == Node.TEXT_NODE):
843 self.childNodes[0].writexml(writer, '', '', '')
844 else:
R David Murray791744b2011-10-01 16:19:51 -0400845 writer.write(newl)
Ezio Melotti8008f2a2011-11-18 17:34:26 +0200846 for node in self.childNodes:
847 node.writexml(writer, indent+addindent, addindent, newl)
848 writer.write(indent)
849 writer.write("</%s>%s" % (self.tagName, newl))
Fred Drake55c38192000-06-29 19:39:57 +0000850 else:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000851 writer.write("/>%s"%(newl))
Fred Drake55c38192000-06-29 19:39:57 +0000852
Fred Drake1f549022000-09-24 05:21:58 +0000853 def _get_attributes(self):
Fred Drake2998a552001-12-06 18:27:48 +0000854 return NamedNodeMap(self._attrs, self._attrsNS, self)
Fred Drake55c38192000-06-29 19:39:57 +0000855
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000856 def hasAttributes(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000857 if self._attrs:
858 return True
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000859 else:
Martin v. Löwis787354c2003-01-25 15:28:29 +0000860 return False
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +0000861
Martin v. Löwis787354c2003-01-25 15:28:29 +0000862 # DOM Level 3 attributes, based on the 22 Oct 2002 draft
863
864 def setIdAttribute(self, name):
865 idAttr = self.getAttributeNode(name)
866 self.setIdAttributeNode(idAttr)
867
868 def setIdAttributeNS(self, namespaceURI, localName):
869 idAttr = self.getAttributeNodeNS(namespaceURI, localName)
870 self.setIdAttributeNode(idAttr)
871
872 def setIdAttributeNode(self, idAttr):
873 if idAttr is None or not self.isSameNode(idAttr.ownerElement):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000874 raise xml.dom.NotFoundErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000875 if _get_containing_entref(self) is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000876 raise xml.dom.NoModificationAllowedErr()
Martin v. Löwis787354c2003-01-25 15:28:29 +0000877 if not idAttr._is_id:
878 idAttr.__dict__['_is_id'] = True
879 self._magic_id_nodes += 1
880 self.ownerDocument._magic_id_count += 1
881 _clear_id_cache(self)
882
883defproperty(Element, "attributes",
884 doc="NamedNodeMap of attributes on the element.")
885defproperty(Element, "localName",
886 doc="Namespace-local name of this element.")
887
888
889def _set_attribute_node(element, attr):
890 _clear_id_cache(element)
891 element._attrs[attr.name] = attr
892 element._attrsNS[(attr.namespaceURI, attr.localName)] = attr
893
894 # This creates a circular reference, but Element.unlink()
895 # breaks the cycle since the references to the attribute
896 # dictionaries are tossed.
897 attr.__dict__['ownerElement'] = element
898
899
900class Childless:
901 """Mixin that makes childless-ness easy to implement and avoids
902 the complexity of the Node methods that deal with children.
903 """
904
Fred Drake4ccf4a12000-11-21 22:02:22 +0000905 attributes = None
Martin v. Löwis787354c2003-01-25 15:28:29 +0000906 childNodes = EmptyNodeList()
907 firstChild = None
908 lastChild = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000909
Martin v. Löwis787354c2003-01-25 15:28:29 +0000910 def _get_firstChild(self):
911 return None
Fred Drake55c38192000-06-29 19:39:57 +0000912
Martin v. Löwis787354c2003-01-25 15:28:29 +0000913 def _get_lastChild(self):
914 return None
Fred Drake1f549022000-09-24 05:21:58 +0000915
Martin v. Löwis787354c2003-01-25 15:28:29 +0000916 def appendChild(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000917 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000918 self.nodeName + " nodes cannot have children")
919
920 def hasChildNodes(self):
921 return False
922
923 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000924 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000925 self.nodeName + " nodes do not have children")
926
927 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000928 raise xml.dom.NotFoundErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000929 self.nodeName + " nodes do not have children")
930
Andrew M. Kuchling688b9e32010-07-25 23:38:47 +0000931 def normalize(self):
932 # For childless nodes, normalize() has nothing to do.
933 pass
934
Martin v. Löwis787354c2003-01-25 15:28:29 +0000935 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000936 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +0000937 self.nodeName + " nodes do not have children")
938
939
940class ProcessingInstruction(Childless, Node):
Fred Drake1f549022000-09-24 05:21:58 +0000941 nodeType = Node.PROCESSING_INSTRUCTION_NODE
Martin v. Löwis52ce0d02001-01-27 08:47:37 +0000942
Fred Drake1f549022000-09-24 05:21:58 +0000943 def __init__(self, target, data):
Fred Drake55c38192000-06-29 19:39:57 +0000944 self.target = self.nodeName = target
945 self.data = self.nodeValue = data
Fred Drake55c38192000-06-29 19:39:57 +0000946
Martin v. Löwis787354c2003-01-25 15:28:29 +0000947 def _get_data(self):
948 return self.data
949 def _set_data(self, value):
950 d = self.__dict__
951 d['data'] = d['nodeValue'] = value
952
953 def _get_target(self):
954 return self.target
955 def _set_target(self, value):
956 d = self.__dict__
957 d['target'] = d['nodeName'] = value
958
959 def __setattr__(self, name, value):
960 if name == "data" or name == "nodeValue":
961 self.__dict__['data'] = self.__dict__['nodeValue'] = value
962 elif name == "target" or name == "nodeName":
963 self.__dict__['target'] = self.__dict__['nodeName'] = value
964 else:
965 self.__dict__[name] = value
966
Martin v. Löwis46fa39a2001-02-06 00:14:08 +0000967 def writexml(self, writer, indent="", addindent="", newl=""):
968 writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))
Fred Drake55c38192000-06-29 19:39:57 +0000969
Martin v. Löwis787354c2003-01-25 15:28:29 +0000970
971class CharacterData(Childless, Node):
972 def _get_length(self):
973 return len(self.data)
974 __len__ = _get_length
975
976 def _get_data(self):
977 return self.__dict__['data']
978 def _set_data(self, data):
979 d = self.__dict__
980 d['data'] = d['nodeValue'] = data
981
982 _get_nodeValue = _get_data
983 _set_nodeValue = _set_data
984
985 def __setattr__(self, name, value):
986 if name == "data" or name == "nodeValue":
987 self.__dict__['data'] = self.__dict__['nodeValue'] = value
988 else:
989 self.__dict__[name] = value
Fred Drake87432f42001-04-04 14:09:46 +0000990
Fred Drake55c38192000-06-29 19:39:57 +0000991 def __repr__(self):
Martin v. Löwis787354c2003-01-25 15:28:29 +0000992 data = self.data
993 if len(data) > 10:
Fred Drake1f549022000-09-24 05:21:58 +0000994 dotdotdot = "..."
Fred Drake55c38192000-06-29 19:39:57 +0000995 else:
Fred Drake1f549022000-09-24 05:21:58 +0000996 dotdotdot = ""
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000997 return '<DOM %s node "%r%s">' % (
Martin v. Löwis787354c2003-01-25 15:28:29 +0000998 self.__class__.__name__, data[0:10], dotdotdot)
Fred Drake87432f42001-04-04 14:09:46 +0000999
1000 def substringData(self, offset, count):
1001 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001002 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001003 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001004 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001005 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001006 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001007 return self.data[offset:offset+count]
1008
1009 def appendData(self, arg):
1010 self.data = self.data + arg
Fred Drake87432f42001-04-04 14:09:46 +00001011
1012 def insertData(self, offset, arg):
1013 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001014 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001015 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001016 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001017 if arg:
1018 self.data = "%s%s%s" % (
1019 self.data[:offset], arg, self.data[offset:])
Fred Drake87432f42001-04-04 14:09:46 +00001020
1021 def deleteData(self, offset, count):
1022 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001023 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001024 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001025 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001026 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001027 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001028 if count:
1029 self.data = self.data[:offset] + self.data[offset+count:]
Fred Drake87432f42001-04-04 14:09:46 +00001030
1031 def replaceData(self, offset, count, arg):
1032 if offset < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001033 raise xml.dom.IndexSizeErr("offset cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001034 if offset >= len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001035 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
Fred Drake87432f42001-04-04 14:09:46 +00001036 if count < 0:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001037 raise xml.dom.IndexSizeErr("count cannot be negative")
Fred Drake87432f42001-04-04 14:09:46 +00001038 if count:
1039 self.data = "%s%s%s" % (
1040 self.data[:offset], arg, self.data[offset+count:])
Martin v. Löwis787354c2003-01-25 15:28:29 +00001041
1042defproperty(CharacterData, "length", doc="Length of the string data.")
1043
Fred Drake87432f42001-04-04 14:09:46 +00001044
1045class Text(CharacterData):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001046 # Make sure we don't add an instance __dict__ if we don't already
1047 # have one, at least when that's possible:
Martin v. Löwis995359c2003-01-26 08:59:32 +00001048 # XXX this does not work, CharacterData is an old-style class
1049 # __slots__ = ()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001050
Fred Drake87432f42001-04-04 14:09:46 +00001051 nodeType = Node.TEXT_NODE
1052 nodeName = "#text"
1053 attributes = None
Fred Drake55c38192000-06-29 19:39:57 +00001054
Fred Drakef7cf40d2000-12-14 18:16:11 +00001055 def splitText(self, offset):
1056 if offset < 0 or offset > len(self.data):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001057 raise xml.dom.IndexSizeErr("illegal offset value")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001058 newText = self.__class__()
1059 newText.data = self.data[offset:]
1060 newText.ownerDocument = self.ownerDocument
Fred Drakef7cf40d2000-12-14 18:16:11 +00001061 next = self.nextSibling
1062 if self.parentNode and self in self.parentNode.childNodes:
1063 if next is None:
1064 self.parentNode.appendChild(newText)
1065 else:
1066 self.parentNode.insertBefore(newText, next)
1067 self.data = self.data[:offset]
1068 return newText
1069
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001070 def writexml(self, writer, indent="", addindent="", newl=""):
Ezio Melotti8008f2a2011-11-18 17:34:26 +02001071 _write_data(writer, "%s%s%s" % (indent, self.data, newl))
Fred Drake55c38192000-06-29 19:39:57 +00001072
Martin v. Löwis787354c2003-01-25 15:28:29 +00001073 # DOM Level 3 (WD 9 April 2002)
1074
1075 def _get_wholeText(self):
1076 L = [self.data]
1077 n = self.previousSibling
1078 while n is not None:
1079 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1080 L.insert(0, n.data)
1081 n = n.previousSibling
1082 else:
1083 break
1084 n = self.nextSibling
1085 while n is not None:
1086 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1087 L.append(n.data)
1088 n = n.nextSibling
1089 else:
1090 break
1091 return ''.join(L)
1092
1093 def replaceWholeText(self, content):
1094 # XXX This needs to be seriously changed if minidom ever
1095 # supports EntityReference nodes.
1096 parent = self.parentNode
1097 n = self.previousSibling
1098 while n is not None:
1099 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1100 next = n.previousSibling
1101 parent.removeChild(n)
1102 n = next
1103 else:
1104 break
1105 n = self.nextSibling
1106 if not content:
1107 parent.removeChild(self)
1108 while n is not None:
1109 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
1110 next = n.nextSibling
1111 parent.removeChild(n)
1112 n = next
1113 else:
1114 break
1115 if content:
1116 d = self.__dict__
1117 d['data'] = content
1118 d['nodeValue'] = content
1119 return self
1120 else:
1121 return None
1122
1123 def _get_isWhitespaceInElementContent(self):
1124 if self.data.strip():
1125 return False
1126 elem = _get_containing_element(self)
1127 if elem is None:
1128 return False
1129 info = self.ownerDocument._get_elem_info(elem)
1130 if info is None:
1131 return False
1132 else:
1133 return info.isElementContent()
1134
1135defproperty(Text, "isWhitespaceInElementContent",
1136 doc="True iff this text node contains only whitespace"
1137 " and is in element content.")
1138defproperty(Text, "wholeText",
1139 doc="The text of all logically-adjacent text nodes.")
1140
1141
1142def _get_containing_element(node):
1143 c = node.parentNode
1144 while c is not None:
1145 if c.nodeType == Node.ELEMENT_NODE:
1146 return c
1147 c = c.parentNode
1148 return None
1149
1150def _get_containing_entref(node):
1151 c = node.parentNode
1152 while c is not None:
1153 if c.nodeType == Node.ENTITY_REFERENCE_NODE:
1154 return c
1155 c = c.parentNode
1156 return None
1157
1158
Alex Martelli0ee43512006-08-21 19:53:20 +00001159class Comment(CharacterData):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001160 nodeType = Node.COMMENT_NODE
1161 nodeName = "#comment"
1162
1163 def __init__(self, data):
1164 self.data = self.nodeValue = data
1165
1166 def writexml(self, writer, indent="", addindent="", newl=""):
Benjamin Peterson2b7411d2008-05-26 17:36:47 +00001167 if "--" in self.data:
1168 raise ValueError("'--' is not allowed in a comment node")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001169 writer.write("%s<!--%s-->%s" % (indent, self.data, newl))
1170
Fred Drake87432f42001-04-04 14:09:46 +00001171
1172class CDATASection(Text):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001173 # Make sure we don't add an instance __dict__ if we don't already
1174 # have one, at least when that's possible:
Martin v. Löwis995359c2003-01-26 08:59:32 +00001175 # XXX this does not work, Text is an old-style class
1176 # __slots__ = ()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001177
Fred Drake87432f42001-04-04 14:09:46 +00001178 nodeType = Node.CDATA_SECTION_NODE
1179 nodeName = "#cdata-section"
1180
1181 def writexml(self, writer, indent="", addindent="", newl=""):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001182 if self.data.find("]]>") >= 0:
1183 raise ValueError("']]>' not allowed in a CDATA section")
Guido van Rossum5b5e0b92001-09-19 13:28:25 +00001184 writer.write("<![CDATA[%s]]>" % self.data)
Fred Drake87432f42001-04-04 14:09:46 +00001185
1186
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001187class ReadOnlySequentialNamedNodeMap(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001188 __slots__ = '_seq',
1189
1190 def __init__(self, seq=()):
1191 # seq should be a list or tuple
1192 self._seq = seq
1193
1194 def __len__(self):
1195 return len(self._seq)
1196
1197 def _get_length(self):
1198 return len(self._seq)
1199
1200 def getNamedItem(self, name):
1201 for n in self._seq:
1202 if n.nodeName == name:
1203 return n
1204
1205 def getNamedItemNS(self, namespaceURI, localName):
1206 for n in self._seq:
1207 if n.namespaceURI == namespaceURI and n.localName == localName:
1208 return n
1209
1210 def __getitem__(self, name_or_tuple):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001211 if isinstance(name_or_tuple, tuple):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001212 node = self.getNamedItemNS(*name_or_tuple)
1213 else:
1214 node = self.getNamedItem(name_or_tuple)
1215 if node is None:
Collin Winter70e79802007-08-24 18:57:22 +00001216 raise KeyError(name_or_tuple)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001217 return node
1218
1219 def item(self, index):
1220 if index < 0:
1221 return None
1222 try:
1223 return self._seq[index]
1224 except IndexError:
1225 return None
1226
1227 def removeNamedItem(self, name):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001228 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001229 "NamedNodeMap instance is read-only")
1230
1231 def removeNamedItemNS(self, namespaceURI, localName):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001232 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001233 "NamedNodeMap instance is read-only")
1234
1235 def setNamedItem(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001236 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001237 "NamedNodeMap instance is read-only")
1238
1239 def setNamedItemNS(self, node):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001240 raise xml.dom.NoModificationAllowedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001241 "NamedNodeMap instance is read-only")
1242
1243 def __getstate__(self):
1244 return [self._seq]
1245
1246 def __setstate__(self, state):
1247 self._seq = state[0]
1248
1249defproperty(ReadOnlySequentialNamedNodeMap, "length",
1250 doc="Number of entries in the NamedNodeMap.")
Paul Prescod73678da2000-07-01 04:58:47 +00001251
Fred Drakef7cf40d2000-12-14 18:16:11 +00001252
Martin v. Löwis787354c2003-01-25 15:28:29 +00001253class Identified:
1254 """Mix-in class that supports the publicId and systemId attributes."""
1255
Martin v. Löwis995359c2003-01-26 08:59:32 +00001256 # XXX this does not work, this is an old-style class
1257 # __slots__ = 'publicId', 'systemId'
Martin v. Löwis787354c2003-01-25 15:28:29 +00001258
1259 def _identified_mixin_init(self, publicId, systemId):
1260 self.publicId = publicId
1261 self.systemId = systemId
1262
1263 def _get_publicId(self):
1264 return self.publicId
1265
1266 def _get_systemId(self):
1267 return self.systemId
1268
1269class DocumentType(Identified, Childless, Node):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001270 nodeType = Node.DOCUMENT_TYPE_NODE
1271 nodeValue = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001272 name = None
1273 publicId = None
1274 systemId = None
Fred Drakedc806702001-04-05 14:41:30 +00001275 internalSubset = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001276
1277 def __init__(self, qualifiedName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001278 self.entities = ReadOnlySequentialNamedNodeMap()
1279 self.notations = ReadOnlySequentialNamedNodeMap()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001280 if qualifiedName:
1281 prefix, localname = _nssplit(qualifiedName)
1282 self.name = localname
Martin v. Löwis787354c2003-01-25 15:28:29 +00001283 self.nodeName = self.name
1284
1285 def _get_internalSubset(self):
1286 return self.internalSubset
1287
1288 def cloneNode(self, deep):
1289 if self.ownerDocument is None:
1290 # it's ok
1291 clone = DocumentType(None)
1292 clone.name = self.name
1293 clone.nodeName = self.name
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001294 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001295 if deep:
1296 clone.entities._seq = []
1297 clone.notations._seq = []
1298 for n in self.notations._seq:
1299 notation = Notation(n.nodeName, n.publicId, n.systemId)
1300 clone.notations._seq.append(notation)
1301 n._call_user_data_handler(operation, n, notation)
1302 for e in self.entities._seq:
1303 entity = Entity(e.nodeName, e.publicId, e.systemId,
1304 e.notationName)
1305 entity.actualEncoding = e.actualEncoding
1306 entity.encoding = e.encoding
1307 entity.version = e.version
1308 clone.entities._seq.append(entity)
1309 e._call_user_data_handler(operation, n, entity)
1310 self._call_user_data_handler(operation, self, clone)
1311 return clone
1312 else:
1313 return None
1314
1315 def writexml(self, writer, indent="", addindent="", newl=""):
1316 writer.write("<!DOCTYPE ")
1317 writer.write(self.name)
1318 if self.publicId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001319 writer.write("%s PUBLIC '%s'%s '%s'"
1320 % (newl, self.publicId, newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001321 elif self.systemId:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001322 writer.write("%s SYSTEM '%s'" % (newl, self.systemId))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001323 if self.internalSubset is not None:
1324 writer.write(" [")
1325 writer.write(self.internalSubset)
1326 writer.write("]")
Georg Brandl175a7dc2005-08-25 22:02:43 +00001327 writer.write(">"+newl)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001328
1329class Entity(Identified, Node):
1330 attributes = None
1331 nodeType = Node.ENTITY_NODE
1332 nodeValue = None
1333
1334 actualEncoding = None
1335 encoding = None
1336 version = None
1337
1338 def __init__(self, name, publicId, systemId, notation):
1339 self.nodeName = name
1340 self.notationName = notation
1341 self.childNodes = NodeList()
1342 self._identified_mixin_init(publicId, systemId)
1343
1344 def _get_actualEncoding(self):
1345 return self.actualEncoding
1346
1347 def _get_encoding(self):
1348 return self.encoding
1349
1350 def _get_version(self):
1351 return self.version
1352
1353 def appendChild(self, newChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001354 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001355 "cannot append children to an entity node")
1356
1357 def insertBefore(self, newChild, refChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001358 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001359 "cannot insert children below an entity node")
1360
1361 def removeChild(self, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001362 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001363 "cannot remove children from an entity node")
1364
1365 def replaceChild(self, newChild, oldChild):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001366 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001367 "cannot replace children of an entity node")
1368
1369class Notation(Identified, Childless, Node):
1370 nodeType = Node.NOTATION_NODE
1371 nodeValue = None
1372
1373 def __init__(self, name, publicId, systemId):
1374 self.nodeName = name
1375 self._identified_mixin_init(publicId, systemId)
Fred Drakef7cf40d2000-12-14 18:16:11 +00001376
1377
Martin v. Löwis787354c2003-01-25 15:28:29 +00001378class DOMImplementation(DOMImplementationLS):
1379 _features = [("core", "1.0"),
1380 ("core", "2.0"),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001381 ("core", None),
1382 ("xml", "1.0"),
1383 ("xml", "2.0"),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001384 ("xml", None),
1385 ("ls-load", "3.0"),
1386 ("ls-load", None),
1387 ]
1388
Fred Drakef7cf40d2000-12-14 18:16:11 +00001389 def hasFeature(self, feature, version):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001390 if version == "":
1391 version = None
1392 return (feature.lower(), version) in self._features
Fred Drakef7cf40d2000-12-14 18:16:11 +00001393
1394 def createDocument(self, namespaceURI, qualifiedName, doctype):
1395 if doctype and doctype.parentNode is not None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001396 raise xml.dom.WrongDocumentErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001397 "doctype object owned by another DOM tree")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001398 doc = self._create_document()
1399
1400 add_root_element = not (namespaceURI is None
1401 and qualifiedName is None
1402 and doctype is None)
1403
1404 if not qualifiedName and add_root_element:
Martin v. Löwisb417be22001-02-06 01:16:06 +00001405 # The spec is unclear what to raise here; SyntaxErr
1406 # would be the other obvious candidate. Since Xerces raises
1407 # InvalidCharacterErr, and since SyntaxErr is not listed
1408 # for createDocument, that seems to be the better choice.
1409 # XXX: need to check for illegal characters here and in
1410 # createElement.
Martin v. Löwis787354c2003-01-25 15:28:29 +00001411
1412 # DOM Level III clears this up when talking about the return value
1413 # of this function. If namespaceURI, qName and DocType are
1414 # Null the document is returned without a document element
1415 # Otherwise if doctype or namespaceURI are not None
1416 # Then we go back to the above problem
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001417 raise xml.dom.InvalidCharacterErr("Element with no name")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001418
1419 if add_root_element:
1420 prefix, localname = _nssplit(qualifiedName)
1421 if prefix == "xml" \
1422 and namespaceURI != "http://www.w3.org/XML/1998/namespace":
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001423 raise xml.dom.NamespaceErr("illegal use of 'xml' prefix")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001424 if prefix and not namespaceURI:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001425 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001426 "illegal use of prefix without namespaces")
1427 element = doc.createElementNS(namespaceURI, qualifiedName)
1428 if doctype:
1429 doc.appendChild(doctype)
1430 doc.appendChild(element)
1431
1432 if doctype:
1433 doctype.parentNode = doctype.ownerDocument = doc
1434
Fred Drakef7cf40d2000-12-14 18:16:11 +00001435 doc.doctype = doctype
1436 doc.implementation = self
1437 return doc
1438
1439 def createDocumentType(self, qualifiedName, publicId, systemId):
1440 doctype = DocumentType(qualifiedName)
1441 doctype.publicId = publicId
1442 doctype.systemId = systemId
1443 return doctype
1444
Martin v. Löwis787354c2003-01-25 15:28:29 +00001445 # DOM Level 3 (WD 9 April 2002)
1446
1447 def getInterface(self, feature):
1448 if self.hasFeature(feature, None):
1449 return self
1450 else:
1451 return None
1452
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001453 # internal
Martin v. Löwis787354c2003-01-25 15:28:29 +00001454 def _create_document(self):
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001455 return Document()
Fred Drakef7cf40d2000-12-14 18:16:11 +00001456
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001457class ElementInfo(object):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001458 """Object that represents content-model information for an element.
1459
1460 This implementation is not expected to be used in practice; DOM
1461 builders should provide implementations which do the right thing
1462 using information available to it.
1463
1464 """
1465
1466 __slots__ = 'tagName',
1467
1468 def __init__(self, name):
1469 self.tagName = name
1470
1471 def getAttributeType(self, aname):
1472 return _no_type
1473
1474 def getAttributeTypeNS(self, namespaceURI, localName):
1475 return _no_type
1476
1477 def isElementContent(self):
1478 return False
1479
1480 def isEmpty(self):
1481 """Returns true iff this element is declared to have an EMPTY
1482 content model."""
1483 return False
1484
1485 def isId(self, aname):
Ezio Melotti42da6632011-03-15 05:18:48 +02001486 """Returns true iff the named attribute is a DTD-style ID."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001487 return False
1488
1489 def isIdNS(self, namespaceURI, localName):
1490 """Returns true iff the identified attribute is a DTD-style ID."""
1491 return False
1492
1493 def __getstate__(self):
1494 return self.tagName
1495
1496 def __setstate__(self, state):
1497 self.tagName = state
1498
1499def _clear_id_cache(node):
1500 if node.nodeType == Node.DOCUMENT_NODE:
1501 node._id_cache.clear()
1502 node._id_search_stack = None
1503 elif _in_document(node):
1504 node.ownerDocument._id_cache.clear()
1505 node.ownerDocument._id_search_stack= None
1506
1507class Document(Node, DocumentLS):
1508 _child_node_types = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
1509 Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)
1510
Fred Drake1f549022000-09-24 05:21:58 +00001511 nodeType = Node.DOCUMENT_NODE
Fred Drake4ccf4a12000-11-21 22:02:22 +00001512 nodeName = "#document"
1513 nodeValue = None
1514 attributes = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001515 doctype = None
1516 parentNode = None
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001517 previousSibling = nextSibling = None
Fred Drakef7cf40d2000-12-14 18:16:11 +00001518
1519 implementation = DOMImplementation()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001520
1521 # Document attributes from Level 3 (WD 9 April 2002)
1522
1523 actualEncoding = None
1524 encoding = None
1525 standalone = None
1526 version = None
1527 strictErrorChecking = False
1528 errorHandler = None
1529 documentURI = None
1530
1531 _magic_id_count = 0
1532
1533 def __init__(self):
1534 self.childNodes = NodeList()
1535 # mapping of (namespaceURI, localName) -> ElementInfo
1536 # and tagName -> ElementInfo
1537 self._elem_info = {}
1538 self._id_cache = {}
1539 self._id_search_stack = None
1540
1541 def _get_elem_info(self, element):
1542 if element.namespaceURI:
1543 key = element.namespaceURI, element.localName
1544 else:
1545 key = element.tagName
1546 return self._elem_info.get(key)
1547
1548 def _get_actualEncoding(self):
1549 return self.actualEncoding
1550
1551 def _get_doctype(self):
1552 return self.doctype
1553
1554 def _get_documentURI(self):
1555 return self.documentURI
1556
1557 def _get_encoding(self):
1558 return self.encoding
1559
1560 def _get_errorHandler(self):
1561 return self.errorHandler
1562
1563 def _get_standalone(self):
1564 return self.standalone
1565
1566 def _get_strictErrorChecking(self):
1567 return self.strictErrorChecking
1568
1569 def _get_version(self):
1570 return self.version
Fred Drake55c38192000-06-29 19:39:57 +00001571
Fred Drake1f549022000-09-24 05:21:58 +00001572 def appendChild(self, node):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001573 if node.nodeType not in self._child_node_types:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001574 raise xml.dom.HierarchyRequestErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001575 "%s cannot be child of %s" % (repr(node), repr(self)))
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001576 if node.parentNode is not None:
Martin v. Löwis787354c2003-01-25 15:28:29 +00001577 # This needs to be done before the next test since this
1578 # may *be* the document element, in which case it should
1579 # end up re-ordered to the end.
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001580 node.parentNode.removeChild(node)
1581
Fred Drakef7cf40d2000-12-14 18:16:11 +00001582 if node.nodeType == Node.ELEMENT_NODE \
1583 and self._get_documentElement():
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001584 raise xml.dom.HierarchyRequestErr(
Guido van Rossum9e1fe1e2001-02-05 19:17:50 +00001585 "two document elements disallowed")
Fred Drake4ccf4a12000-11-21 22:02:22 +00001586 return Node.appendChild(self, node)
Paul Prescod73678da2000-07-01 04:58:47 +00001587
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001588 def removeChild(self, oldChild):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001589 try:
1590 self.childNodes.remove(oldChild)
1591 except ValueError:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001592 raise xml.dom.NotFoundErr()
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001593 oldChild.nextSibling = oldChild.previousSibling = None
1594 oldChild.parentNode = None
1595 if self.documentElement is oldChild:
1596 self.documentElement = None
Martin v. Löwis52ce0d02001-01-27 08:47:37 +00001597
Andrew M. Kuchling04a45e92000-12-20 14:47:24 +00001598 return oldChild
1599
Fred Drakef7cf40d2000-12-14 18:16:11 +00001600 def _get_documentElement(self):
1601 for node in self.childNodes:
1602 if node.nodeType == Node.ELEMENT_NODE:
1603 return node
1604
1605 def unlink(self):
1606 if self.doctype is not None:
1607 self.doctype.unlink()
1608 self.doctype = None
1609 Node.unlink(self)
1610
Martin v. Löwis787354c2003-01-25 15:28:29 +00001611 def cloneNode(self, deep):
1612 if not deep:
1613 return None
1614 clone = self.implementation.createDocument(None, None, None)
1615 clone.encoding = self.encoding
1616 clone.standalone = self.standalone
1617 clone.version = self.version
1618 for n in self.childNodes:
1619 childclone = _clone_node(n, deep, clone)
1620 assert childclone.ownerDocument.isSameNode(clone)
1621 clone.childNodes.append(childclone)
1622 if childclone.nodeType == Node.DOCUMENT_NODE:
1623 assert clone.documentElement is None
1624 elif childclone.nodeType == Node.DOCUMENT_TYPE_NODE:
1625 assert clone.doctype is None
1626 clone.doctype = childclone
1627 childclone.parentNode = clone
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001628 self._call_user_data_handler(xml.dom.UserDataHandler.NODE_CLONED,
Martin v. Löwis787354c2003-01-25 15:28:29 +00001629 self, clone)
1630 return clone
1631
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001632 def createDocumentFragment(self):
1633 d = DocumentFragment()
Martin v. Löwis787354c2003-01-25 15:28:29 +00001634 d.ownerDocument = self
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001635 return d
Fred Drake55c38192000-06-29 19:39:57 +00001636
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001637 def createElement(self, tagName):
1638 e = Element(tagName)
1639 e.ownerDocument = self
1640 return e
Fred Drake55c38192000-06-29 19:39:57 +00001641
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001642 def createTextNode(self, data):
Christian Heimesc9543e42007-11-28 08:28:28 +00001643 if not isinstance(data, str):
Collin Winter70e79802007-08-24 18:57:22 +00001644 raise TypeError("node contents must be a string")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001645 t = Text()
1646 t.data = data
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001647 t.ownerDocument = self
1648 return t
Fred Drake55c38192000-06-29 19:39:57 +00001649
Fred Drake87432f42001-04-04 14:09:46 +00001650 def createCDATASection(self, data):
Christian Heimesc9543e42007-11-28 08:28:28 +00001651 if not isinstance(data, str):
Collin Winter70e79802007-08-24 18:57:22 +00001652 raise TypeError("node contents must be a string")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001653 c = CDATASection()
1654 c.data = data
Fred Drake87432f42001-04-04 14:09:46 +00001655 c.ownerDocument = self
1656 return c
1657
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001658 def createComment(self, data):
1659 c = Comment(data)
1660 c.ownerDocument = self
1661 return c
Fred Drake55c38192000-06-29 19:39:57 +00001662
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001663 def createProcessingInstruction(self, target, data):
1664 p = ProcessingInstruction(target, data)
1665 p.ownerDocument = self
1666 return p
1667
1668 def createAttribute(self, qName):
1669 a = Attr(qName)
1670 a.ownerDocument = self
Martin v. Löwiscb67ea12001-03-31 16:30:40 +00001671 a.value = ""
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001672 return a
Fred Drake55c38192000-06-29 19:39:57 +00001673
1674 def createElementNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001675 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis787354c2003-01-25 15:28:29 +00001676 e = Element(qualifiedName, namespaceURI, prefix)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001677 e.ownerDocument = self
1678 return e
Fred Drake55c38192000-06-29 19:39:57 +00001679
1680 def createAttributeNS(self, namespaceURI, qualifiedName):
Fred Drake4ccf4a12000-11-21 22:02:22 +00001681 prefix, localName = _nssplit(qualifiedName)
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001682 a = Attr(qualifiedName, namespaceURI, localName, prefix)
1683 a.ownerDocument = self
Martin v. Löwiscb67ea12001-03-31 16:30:40 +00001684 a.value = ""
Martin v. Löwis126f2f62001-03-13 10:50:13 +00001685 return a
Fred Drake55c38192000-06-29 19:39:57 +00001686
Martin v. Löwis787354c2003-01-25 15:28:29 +00001687 # A couple of implementation-specific helpers to create node types
1688 # not supported by the W3C DOM specs:
1689
1690 def _create_entity(self, name, publicId, systemId, notationName):
1691 e = Entity(name, publicId, systemId, notationName)
1692 e.ownerDocument = self
1693 return e
1694
1695 def _create_notation(self, name, publicId, systemId):
1696 n = Notation(name, publicId, systemId)
1697 n.ownerDocument = self
1698 return n
1699
1700 def getElementById(self, id):
Guido van Rossum1b01e5c2006-08-19 02:45:06 +00001701 if id in self._id_cache:
Martin v. Löwis787354c2003-01-25 15:28:29 +00001702 return self._id_cache[id]
1703 if not (self._elem_info or self._magic_id_count):
1704 return None
1705
1706 stack = self._id_search_stack
1707 if stack is None:
1708 # we never searched before, or the cache has been cleared
1709 stack = [self.documentElement]
1710 self._id_search_stack = stack
1711 elif not stack:
1712 # Previous search was completed and cache is still valid;
1713 # no matching node.
1714 return None
1715
1716 result = None
1717 while stack:
1718 node = stack.pop()
1719 # add child elements to stack for continued searching
1720 stack.extend([child for child in node.childNodes
1721 if child.nodeType in _nodeTypes_with_children])
1722 # check this node
1723 info = self._get_elem_info(node)
1724 if info:
1725 # We have to process all ID attributes before
1726 # returning in order to get all the attributes set to
1727 # be IDs using Element.setIdAttribute*().
1728 for attr in node.attributes.values():
1729 if attr.namespaceURI:
1730 if info.isIdNS(attr.namespaceURI, attr.localName):
1731 self._id_cache[attr.value] = node
1732 if attr.value == id:
1733 result = node
1734 elif not node._magic_id_nodes:
1735 break
1736 elif info.isId(attr.name):
1737 self._id_cache[attr.value] = node
1738 if attr.value == id:
1739 result = node
1740 elif not node._magic_id_nodes:
1741 break
1742 elif attr._is_id:
1743 self._id_cache[attr.value] = node
1744 if attr.value == id:
1745 result = node
1746 elif node._magic_id_nodes == 1:
1747 break
1748 elif node._magic_id_nodes:
1749 for attr in node.attributes.values():
1750 if attr._is_id:
1751 self._id_cache[attr.value] = node
1752 if attr.value == id:
1753 result = node
1754 if result is not None:
1755 break
1756 return result
1757
Fred Drake1f549022000-09-24 05:21:58 +00001758 def getElementsByTagName(self, name):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001759 return _get_elements_by_tagName_helper(self, name, NodeList())
Fred Drakefbe7b4f2001-07-04 06:25:53 +00001760
1761 def getElementsByTagNameNS(self, namespaceURI, localName):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001762 return _get_elements_by_tagName_ns_helper(
1763 self, namespaceURI, localName, NodeList())
1764
1765 def isSupported(self, feature, version):
1766 return self.implementation.hasFeature(feature, version)
1767
1768 def importNode(self, node, deep):
1769 if node.nodeType == Node.DOCUMENT_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001770 raise xml.dom.NotSupportedErr("cannot import document nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001771 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001772 raise xml.dom.NotSupportedErr("cannot import document type nodes")
Martin v. Löwis787354c2003-01-25 15:28:29 +00001773 return _clone_node(node, deep, self)
Fred Drake55c38192000-06-29 19:39:57 +00001774
Martin v. Löwis7d650ca2002-06-30 15:05:00 +00001775 def writexml(self, writer, indent="", addindent="", newl="",
1776 encoding = None):
1777 if encoding is None:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001778 writer.write('<?xml version="1.0" ?>'+newl)
Martin v. Löwis7d650ca2002-06-30 15:05:00 +00001779 else:
Georg Brandl175a7dc2005-08-25 22:02:43 +00001780 writer.write('<?xml version="1.0" encoding="%s"?>%s' % (encoding, newl))
Fred Drake55c38192000-06-29 19:39:57 +00001781 for node in self.childNodes:
Martin v. Löwis46fa39a2001-02-06 00:14:08 +00001782 node.writexml(writer, indent, addindent, newl)
Fred Drake55c38192000-06-29 19:39:57 +00001783
Martin v. Löwis787354c2003-01-25 15:28:29 +00001784 # DOM Level 3 (WD 9 April 2002)
1785
1786 def renameNode(self, n, namespaceURI, name):
1787 if n.ownerDocument is not self:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001788 raise xml.dom.WrongDocumentErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001789 "cannot rename nodes from other documents;\n"
1790 "expected %s,\nfound %s" % (self, n.ownerDocument))
1791 if n.nodeType not in (Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001792 raise xml.dom.NotSupportedErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001793 "renameNode() only applies to element and attribute nodes")
1794 if namespaceURI != EMPTY_NAMESPACE:
1795 if ':' in name:
1796 prefix, localName = name.split(':', 1)
1797 if ( prefix == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001798 and namespaceURI != xml.dom.XMLNS_NAMESPACE):
1799 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001800 "illegal use of 'xmlns' prefix")
1801 else:
1802 if ( name == "xmlns"
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001803 and namespaceURI != xml.dom.XMLNS_NAMESPACE
Martin v. Löwis787354c2003-01-25 15:28:29 +00001804 and n.nodeType == Node.ATTRIBUTE_NODE):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001805 raise xml.dom.NamespaceErr(
Martin v. Löwis787354c2003-01-25 15:28:29 +00001806 "illegal use of the 'xmlns' attribute")
1807 prefix = None
1808 localName = name
1809 else:
1810 prefix = None
1811 localName = None
1812 if n.nodeType == Node.ATTRIBUTE_NODE:
1813 element = n.ownerElement
1814 if element is not None:
1815 is_id = n._is_id
1816 element.removeAttributeNode(n)
1817 else:
1818 element = None
1819 # avoid __setattr__
1820 d = n.__dict__
1821 d['prefix'] = prefix
1822 d['localName'] = localName
1823 d['namespaceURI'] = namespaceURI
1824 d['nodeName'] = name
1825 if n.nodeType == Node.ELEMENT_NODE:
1826 d['tagName'] = name
1827 else:
1828 # attribute node
1829 d['name'] = name
1830 if element is not None:
1831 element.setAttributeNode(n)
1832 if is_id:
1833 element.setIdAttributeNode(n)
1834 # It's not clear from a semantic perspective whether we should
1835 # call the user data handlers for the NODE_RENAMED event since
1836 # we're re-using the existing node. The draft spec has been
1837 # interpreted as meaning "no, don't call the handler unless a
1838 # new node is created."
1839 return n
1840
1841defproperty(Document, "documentElement",
1842 doc="Top-level element of this document.")
1843
1844
1845def _clone_node(node, deep, newOwnerDocument):
1846 """
1847 Clone a node and give it the new owner document.
1848 Called by Node.cloneNode and Document.importNode
1849 """
1850 if node.ownerDocument.isSameNode(newOwnerDocument):
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001851 operation = xml.dom.UserDataHandler.NODE_CLONED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001852 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001853 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001854 if node.nodeType == Node.ELEMENT_NODE:
1855 clone = newOwnerDocument.createElementNS(node.namespaceURI,
1856 node.nodeName)
1857 for attr in node.attributes.values():
1858 clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value)
1859 a = clone.getAttributeNodeNS(attr.namespaceURI, attr.localName)
1860 a.specified = attr.specified
1861
1862 if deep:
1863 for child in node.childNodes:
1864 c = _clone_node(child, deep, newOwnerDocument)
1865 clone.appendChild(c)
1866
1867 elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
1868 clone = newOwnerDocument.createDocumentFragment()
1869 if deep:
1870 for child in node.childNodes:
1871 c = _clone_node(child, deep, newOwnerDocument)
1872 clone.appendChild(c)
1873
1874 elif node.nodeType == Node.TEXT_NODE:
1875 clone = newOwnerDocument.createTextNode(node.data)
1876 elif node.nodeType == Node.CDATA_SECTION_NODE:
1877 clone = newOwnerDocument.createCDATASection(node.data)
1878 elif node.nodeType == Node.PROCESSING_INSTRUCTION_NODE:
1879 clone = newOwnerDocument.createProcessingInstruction(node.target,
1880 node.data)
1881 elif node.nodeType == Node.COMMENT_NODE:
1882 clone = newOwnerDocument.createComment(node.data)
1883 elif node.nodeType == Node.ATTRIBUTE_NODE:
1884 clone = newOwnerDocument.createAttributeNS(node.namespaceURI,
1885 node.nodeName)
1886 clone.specified = True
1887 clone.value = node.value
1888 elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
1889 assert node.ownerDocument is not newOwnerDocument
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001890 operation = xml.dom.UserDataHandler.NODE_IMPORTED
Martin v. Löwis787354c2003-01-25 15:28:29 +00001891 clone = newOwnerDocument.implementation.createDocumentType(
1892 node.name, node.publicId, node.systemId)
1893 clone.ownerDocument = newOwnerDocument
1894 if deep:
1895 clone.entities._seq = []
1896 clone.notations._seq = []
1897 for n in node.notations._seq:
1898 notation = Notation(n.nodeName, n.publicId, n.systemId)
1899 notation.ownerDocument = newOwnerDocument
1900 clone.notations._seq.append(notation)
1901 if hasattr(n, '_call_user_data_handler'):
1902 n._call_user_data_handler(operation, n, notation)
1903 for e in node.entities._seq:
1904 entity = Entity(e.nodeName, e.publicId, e.systemId,
1905 e.notationName)
1906 entity.actualEncoding = e.actualEncoding
1907 entity.encoding = e.encoding
1908 entity.version = e.version
1909 entity.ownerDocument = newOwnerDocument
1910 clone.entities._seq.append(entity)
1911 if hasattr(e, '_call_user_data_handler'):
1912 e._call_user_data_handler(operation, n, entity)
1913 else:
1914 # Note the cloning of Document and DocumentType nodes is
Ezio Melotti13925002011-03-16 11:05:33 +02001915 # implementation specific. minidom handles those cases
Martin v. Löwis787354c2003-01-25 15:28:29 +00001916 # directly in the cloneNode() methods.
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001917 raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node))
Martin v. Löwis787354c2003-01-25 15:28:29 +00001918
1919 # Check for _call_user_data_handler() since this could conceivably
1920 # used with other DOM implementations (one of the FourThought
1921 # DOMs, perhaps?).
1922 if hasattr(node, '_call_user_data_handler'):
1923 node._call_user_data_handler(operation, node, clone)
1924 return clone
1925
1926
1927def _nssplit(qualifiedName):
1928 fields = qualifiedName.split(':', 1)
1929 if len(fields) == 2:
1930 return fields
1931 else:
1932 return (None, fields[0])
1933
1934
Martin v. Löwis787354c2003-01-25 15:28:29 +00001935def _do_pulldom_parse(func, args, kwargs):
Raymond Hettingerff41c482003-04-06 09:01:11 +00001936 events = func(*args, **kwargs)
Fred Drake1f549022000-09-24 05:21:58 +00001937 toktype, rootNode = events.getEvent()
1938 events.expandNode(rootNode)
Martin v. Löwisb417be22001-02-06 01:16:06 +00001939 events.clear()
Fred Drake55c38192000-06-29 19:39:57 +00001940 return rootNode
1941
Martin v. Löwis787354c2003-01-25 15:28:29 +00001942def parse(file, parser=None, bufsize=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001943 """Parse a file into a DOM by filename or file object."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001944 if parser is None and not bufsize:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001945 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001946 return expatbuilder.parse(file)
1947 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001948 from xml.dom import pulldom
Raymond Hettingerff41c482003-04-06 09:01:11 +00001949 return _do_pulldom_parse(pulldom.parse, (file,),
Martin v. Löwis787354c2003-01-25 15:28:29 +00001950 {'parser': parser, 'bufsize': bufsize})
Fred Drake55c38192000-06-29 19:39:57 +00001951
Martin v. Löwis787354c2003-01-25 15:28:29 +00001952def parseString(string, parser=None):
Fred Drakef7cf40d2000-12-14 18:16:11 +00001953 """Parse a file into a DOM from a string."""
Martin v. Löwis787354c2003-01-25 15:28:29 +00001954 if parser is None:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001955 from xml.dom import expatbuilder
Martin v. Löwis787354c2003-01-25 15:28:29 +00001956 return expatbuilder.parseString(string)
1957 else:
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001958 from xml.dom import pulldom
Martin v. Löwis787354c2003-01-25 15:28:29 +00001959 return _do_pulldom_parse(pulldom.parseString, (string,),
1960 {'parser': parser})
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001961
Martin v. Löwis787354c2003-01-25 15:28:29 +00001962def getDOMImplementation(features=None):
1963 if features:
Christian Heimesc9543e42007-11-28 08:28:28 +00001964 if isinstance(features, str):
Martin v. Löwis787354c2003-01-25 15:28:29 +00001965 features = domreg._parse_feature_string(features)
1966 for f, v in features:
1967 if not Document.implementation.hasFeature(f, v):
1968 return None
Martin v. Löwis7edbd4f2001-02-22 14:05:50 +00001969 return Document.implementation