|
1 """\ |
|
2 minidom.py -- a lightweight DOM implementation. |
|
3 |
|
4 parse("foo.xml") |
|
5 |
|
6 parseString("<foo><bar/></foo>") |
|
7 |
|
8 Todo: |
|
9 ===== |
|
10 * convenience methods for getting elements and text. |
|
11 * more testing |
|
12 * bring some of the writer and linearizer code into conformance with this |
|
13 interface |
|
14 * SAX 2 namespaces |
|
15 """ |
|
16 |
|
17 import xml.dom |
|
18 |
|
19 from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE, domreg |
|
20 from xml.dom.minicompat import * |
|
21 from xml.dom.xmlbuilder import DOMImplementationLS, DocumentLS |
|
22 |
|
23 # This is used by the ID-cache invalidation checks; the list isn't |
|
24 # actually complete, since the nodes being checked will never be the |
|
25 # DOCUMENT_NODE or DOCUMENT_FRAGMENT_NODE. (The node being checked is |
|
26 # the node being added or removed, not the node being modified.) |
|
27 # |
|
28 _nodeTypes_with_children = (xml.dom.Node.ELEMENT_NODE, |
|
29 xml.dom.Node.ENTITY_REFERENCE_NODE) |
|
30 |
|
31 |
|
32 class Node(xml.dom.Node): |
|
33 namespaceURI = None # this is non-null only for elements and attributes |
|
34 parentNode = None |
|
35 ownerDocument = None |
|
36 nextSibling = None |
|
37 previousSibling = None |
|
38 |
|
39 prefix = EMPTY_PREFIX # non-null only for NS elements and attributes |
|
40 |
|
41 def __nonzero__(self): |
|
42 return True |
|
43 |
|
44 def toxml(self, encoding = None): |
|
45 return self.toprettyxml("", "", encoding) |
|
46 |
|
47 def toprettyxml(self, indent="\t", newl="\n", encoding = None): |
|
48 # indent = the indentation string to prepend, per level |
|
49 # newl = the newline string to append |
|
50 writer = _get_StringIO() |
|
51 if encoding is not None: |
|
52 import codecs |
|
53 # Can't use codecs.getwriter to preserve 2.0 compatibility |
|
54 writer = codecs.lookup(encoding)[3](writer) |
|
55 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) |
|
60 return writer.getvalue() |
|
61 |
|
62 def hasChildNodes(self): |
|
63 if self.childNodes: |
|
64 return True |
|
65 else: |
|
66 return False |
|
67 |
|
68 def _get_childNodes(self): |
|
69 return self.childNodes |
|
70 |
|
71 def _get_firstChild(self): |
|
72 if self.childNodes: |
|
73 return self.childNodes[0] |
|
74 |
|
75 def _get_lastChild(self): |
|
76 if self.childNodes: |
|
77 return self.childNodes[-1] |
|
78 |
|
79 def insertBefore(self, newChild, refChild): |
|
80 if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE: |
|
81 for c in tuple(newChild.childNodes): |
|
82 self.insertBefore(c, refChild) |
|
83 ### The DOM does not clearly specify what to return in this case |
|
84 return newChild |
|
85 if newChild.nodeType not in self._child_node_types: |
|
86 raise xml.dom.HierarchyRequestErr( |
|
87 "%s cannot be child of %s" % (repr(newChild), repr(self))) |
|
88 if newChild.parentNode is not None: |
|
89 newChild.parentNode.removeChild(newChild) |
|
90 if refChild is None: |
|
91 self.appendChild(newChild) |
|
92 else: |
|
93 try: |
|
94 index = self.childNodes.index(refChild) |
|
95 except ValueError: |
|
96 raise xml.dom.NotFoundErr() |
|
97 if newChild.nodeType in _nodeTypes_with_children: |
|
98 _clear_id_cache(self) |
|
99 self.childNodes.insert(index, newChild) |
|
100 newChild.nextSibling = refChild |
|
101 refChild.previousSibling = newChild |
|
102 if index: |
|
103 node = self.childNodes[index-1] |
|
104 node.nextSibling = newChild |
|
105 newChild.previousSibling = node |
|
106 else: |
|
107 newChild.previousSibling = None |
|
108 newChild.parentNode = self |
|
109 return newChild |
|
110 |
|
111 def appendChild(self, node): |
|
112 if node.nodeType == self.DOCUMENT_FRAGMENT_NODE: |
|
113 for c in tuple(node.childNodes): |
|
114 self.appendChild(c) |
|
115 ### The DOM does not clearly specify what to return in this case |
|
116 return node |
|
117 if node.nodeType not in self._child_node_types: |
|
118 raise xml.dom.HierarchyRequestErr( |
|
119 "%s cannot be child of %s" % (repr(node), repr(self))) |
|
120 elif node.nodeType in _nodeTypes_with_children: |
|
121 _clear_id_cache(self) |
|
122 if node.parentNode is not None: |
|
123 node.parentNode.removeChild(node) |
|
124 _append_child(self, node) |
|
125 node.nextSibling = None |
|
126 return node |
|
127 |
|
128 def replaceChild(self, newChild, oldChild): |
|
129 if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE: |
|
130 refChild = oldChild.nextSibling |
|
131 self.removeChild(oldChild) |
|
132 return self.insertBefore(newChild, refChild) |
|
133 if newChild.nodeType not in self._child_node_types: |
|
134 raise xml.dom.HierarchyRequestErr( |
|
135 "%s cannot be child of %s" % (repr(newChild), repr(self))) |
|
136 if newChild is oldChild: |
|
137 return |
|
138 if newChild.parentNode is not None: |
|
139 newChild.parentNode.removeChild(newChild) |
|
140 try: |
|
141 index = self.childNodes.index(oldChild) |
|
142 except ValueError: |
|
143 raise xml.dom.NotFoundErr() |
|
144 self.childNodes[index] = newChild |
|
145 newChild.parentNode = self |
|
146 oldChild.parentNode = None |
|
147 if (newChild.nodeType in _nodeTypes_with_children |
|
148 or oldChild.nodeType in _nodeTypes_with_children): |
|
149 _clear_id_cache(self) |
|
150 newChild.nextSibling = oldChild.nextSibling |
|
151 newChild.previousSibling = oldChild.previousSibling |
|
152 oldChild.nextSibling = None |
|
153 oldChild.previousSibling = None |
|
154 if newChild.previousSibling: |
|
155 newChild.previousSibling.nextSibling = newChild |
|
156 if newChild.nextSibling: |
|
157 newChild.nextSibling.previousSibling = newChild |
|
158 return oldChild |
|
159 |
|
160 def removeChild(self, oldChild): |
|
161 try: |
|
162 self.childNodes.remove(oldChild) |
|
163 except ValueError: |
|
164 raise xml.dom.NotFoundErr() |
|
165 if oldChild.nextSibling is not None: |
|
166 oldChild.nextSibling.previousSibling = oldChild.previousSibling |
|
167 if oldChild.previousSibling is not None: |
|
168 oldChild.previousSibling.nextSibling = oldChild.nextSibling |
|
169 oldChild.nextSibling = oldChild.previousSibling = None |
|
170 if oldChild.nodeType in _nodeTypes_with_children: |
|
171 _clear_id_cache(self) |
|
172 |
|
173 oldChild.parentNode = None |
|
174 return oldChild |
|
175 |
|
176 def normalize(self): |
|
177 L = [] |
|
178 for child in self.childNodes: |
|
179 if child.nodeType == Node.TEXT_NODE: |
|
180 data = child.data |
|
181 if data and L and L[-1].nodeType == child.nodeType: |
|
182 # collapse text node |
|
183 node = L[-1] |
|
184 node.data = node.data + child.data |
|
185 node.nextSibling = child.nextSibling |
|
186 child.unlink() |
|
187 elif data: |
|
188 if L: |
|
189 L[-1].nextSibling = child |
|
190 child.previousSibling = L[-1] |
|
191 else: |
|
192 child.previousSibling = None |
|
193 L.append(child) |
|
194 else: |
|
195 # empty text node; discard |
|
196 child.unlink() |
|
197 else: |
|
198 if L: |
|
199 L[-1].nextSibling = child |
|
200 child.previousSibling = L[-1] |
|
201 else: |
|
202 child.previousSibling = None |
|
203 L.append(child) |
|
204 if child.nodeType == Node.ELEMENT_NODE: |
|
205 child.normalize() |
|
206 self.childNodes[:] = L |
|
207 |
|
208 def cloneNode(self, deep): |
|
209 return _clone_node(self, deep, self.ownerDocument or self) |
|
210 |
|
211 def isSupported(self, feature, version): |
|
212 return self.ownerDocument.implementation.hasFeature(feature, version) |
|
213 |
|
214 def _get_localName(self): |
|
215 # Overridden in Element and Attr where localName can be Non-Null |
|
216 return None |
|
217 |
|
218 # Node interfaces from Level 3 (WD 9 April 2002) |
|
219 |
|
220 def isSameNode(self, other): |
|
221 return self is other |
|
222 |
|
223 def getInterface(self, feature): |
|
224 if self.isSupported(feature, None): |
|
225 return self |
|
226 else: |
|
227 return None |
|
228 |
|
229 # The "user data" functions use a dictionary that is only present |
|
230 # if some user data has been set, so be careful not to assume it |
|
231 # exists. |
|
232 |
|
233 def getUserData(self, key): |
|
234 try: |
|
235 return self._user_data[key][0] |
|
236 except (AttributeError, KeyError): |
|
237 return None |
|
238 |
|
239 def setUserData(self, key, data, handler): |
|
240 old = None |
|
241 try: |
|
242 d = self._user_data |
|
243 except AttributeError: |
|
244 d = {} |
|
245 self._user_data = d |
|
246 if d.has_key(key): |
|
247 old = d[key][0] |
|
248 if data is None: |
|
249 # ignore handlers passed for None |
|
250 handler = None |
|
251 if old is not None: |
|
252 del d[key] |
|
253 else: |
|
254 d[key] = (data, handler) |
|
255 return old |
|
256 |
|
257 def _call_user_data_handler(self, operation, src, dst): |
|
258 if hasattr(self, "_user_data"): |
|
259 for key, (data, handler) in self._user_data.items(): |
|
260 if handler is not None: |
|
261 handler.handle(operation, key, data, src, dst) |
|
262 |
|
263 # minidom-specific API: |
|
264 |
|
265 def unlink(self): |
|
266 self.parentNode = self.ownerDocument = None |
|
267 if self.childNodes: |
|
268 for child in self.childNodes: |
|
269 child.unlink() |
|
270 self.childNodes = NodeList() |
|
271 self.previousSibling = None |
|
272 self.nextSibling = None |
|
273 |
|
274 defproperty(Node, "firstChild", doc="First child node, or None.") |
|
275 defproperty(Node, "lastChild", doc="Last child node, or None.") |
|
276 defproperty(Node, "localName", doc="Namespace-local name of this node.") |
|
277 |
|
278 |
|
279 def _append_child(self, node): |
|
280 # fast path with less checks; usable by DOM builders if careful |
|
281 childNodes = self.childNodes |
|
282 if childNodes: |
|
283 last = childNodes[-1] |
|
284 node.__dict__["previousSibling"] = last |
|
285 last.__dict__["nextSibling"] = node |
|
286 childNodes.append(node) |
|
287 node.__dict__["parentNode"] = self |
|
288 |
|
289 def _in_document(node): |
|
290 # return True iff node is part of a document tree |
|
291 while node is not None: |
|
292 if node.nodeType == Node.DOCUMENT_NODE: |
|
293 return True |
|
294 node = node.parentNode |
|
295 return False |
|
296 |
|
297 def _write_data(writer, data): |
|
298 "Writes datachars to writer." |
|
299 data = data.replace("&", "&").replace("<", "<") |
|
300 data = data.replace("\"", """).replace(">", ">") |
|
301 writer.write(data) |
|
302 |
|
303 def _get_elements_by_tagName_helper(parent, name, rc): |
|
304 for node in parent.childNodes: |
|
305 if node.nodeType == Node.ELEMENT_NODE and \ |
|
306 (name == "*" or node.tagName == name): |
|
307 rc.append(node) |
|
308 _get_elements_by_tagName_helper(node, name, rc) |
|
309 return rc |
|
310 |
|
311 def _get_elements_by_tagName_ns_helper(parent, nsURI, localName, rc): |
|
312 for node in parent.childNodes: |
|
313 if node.nodeType == Node.ELEMENT_NODE: |
|
314 if ((localName == "*" or node.localName == localName) and |
|
315 (nsURI == "*" or node.namespaceURI == nsURI)): |
|
316 rc.append(node) |
|
317 _get_elements_by_tagName_ns_helper(node, nsURI, localName, rc) |
|
318 return rc |
|
319 |
|
320 class DocumentFragment(Node): |
|
321 nodeType = Node.DOCUMENT_FRAGMENT_NODE |
|
322 nodeName = "#document-fragment" |
|
323 nodeValue = None |
|
324 attributes = None |
|
325 parentNode = None |
|
326 _child_node_types = (Node.ELEMENT_NODE, |
|
327 Node.TEXT_NODE, |
|
328 Node.CDATA_SECTION_NODE, |
|
329 Node.ENTITY_REFERENCE_NODE, |
|
330 Node.PROCESSING_INSTRUCTION_NODE, |
|
331 Node.COMMENT_NODE, |
|
332 Node.NOTATION_NODE) |
|
333 |
|
334 def __init__(self): |
|
335 self.childNodes = NodeList() |
|
336 |
|
337 |
|
338 class Attr(Node): |
|
339 nodeType = Node.ATTRIBUTE_NODE |
|
340 attributes = None |
|
341 ownerElement = None |
|
342 specified = False |
|
343 _is_id = False |
|
344 |
|
345 _child_node_types = (Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE) |
|
346 |
|
347 def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None, |
|
348 prefix=None): |
|
349 # skip setattr for performance |
|
350 d = self.__dict__ |
|
351 d["nodeName"] = d["name"] = qName |
|
352 d["namespaceURI"] = namespaceURI |
|
353 d["prefix"] = prefix |
|
354 d['childNodes'] = NodeList() |
|
355 |
|
356 # Add the single child node that represents the value of the attr |
|
357 self.childNodes.append(Text()) |
|
358 |
|
359 # nodeValue and value are set elsewhere |
|
360 |
|
361 def _get_localName(self): |
|
362 return self.nodeName.split(":", 1)[-1] |
|
363 |
|
364 def _get_name(self): |
|
365 return self.name |
|
366 |
|
367 def _get_specified(self): |
|
368 return self.specified |
|
369 |
|
370 def __setattr__(self, name, value): |
|
371 d = self.__dict__ |
|
372 if name in ("value", "nodeValue"): |
|
373 d["value"] = d["nodeValue"] = value |
|
374 d2 = self.childNodes[0].__dict__ |
|
375 d2["data"] = d2["nodeValue"] = value |
|
376 if self.ownerElement is not None: |
|
377 _clear_id_cache(self.ownerElement) |
|
378 elif name in ("name", "nodeName"): |
|
379 d["name"] = d["nodeName"] = value |
|
380 if self.ownerElement is not None: |
|
381 _clear_id_cache(self.ownerElement) |
|
382 else: |
|
383 d[name] = value |
|
384 |
|
385 def _set_prefix(self, prefix): |
|
386 nsuri = self.namespaceURI |
|
387 if prefix == "xmlns": |
|
388 if nsuri and nsuri != XMLNS_NAMESPACE: |
|
389 raise xml.dom.NamespaceErr( |
|
390 "illegal use of 'xmlns' prefix for the wrong namespace") |
|
391 d = self.__dict__ |
|
392 d['prefix'] = prefix |
|
393 if prefix is None: |
|
394 newName = self.localName |
|
395 else: |
|
396 newName = "%s:%s" % (prefix, self.localName) |
|
397 if self.ownerElement: |
|
398 _clear_id_cache(self.ownerElement) |
|
399 d['nodeName'] = d['name'] = newName |
|
400 |
|
401 def _set_value(self, value): |
|
402 d = self.__dict__ |
|
403 d['value'] = d['nodeValue'] = value |
|
404 if self.ownerElement: |
|
405 _clear_id_cache(self.ownerElement) |
|
406 self.childNodes[0].data = value |
|
407 |
|
408 def unlink(self): |
|
409 # This implementation does not call the base implementation |
|
410 # since most of that is not needed, and the expense of the |
|
411 # method call is not warranted. We duplicate the removal of |
|
412 # children, but that's all we needed from the base class. |
|
413 elem = self.ownerElement |
|
414 if elem is not None: |
|
415 del elem._attrs[self.nodeName] |
|
416 del elem._attrsNS[(self.namespaceURI, self.localName)] |
|
417 if self._is_id: |
|
418 self._is_id = False |
|
419 elem._magic_id_nodes -= 1 |
|
420 self.ownerDocument._magic_id_count -= 1 |
|
421 for child in self.childNodes: |
|
422 child.unlink() |
|
423 del self.childNodes[:] |
|
424 |
|
425 def _get_isId(self): |
|
426 if self._is_id: |
|
427 return True |
|
428 doc = self.ownerDocument |
|
429 elem = self.ownerElement |
|
430 if doc is None or elem is None: |
|
431 return False |
|
432 |
|
433 info = doc._get_elem_info(elem) |
|
434 if info is None: |
|
435 return False |
|
436 if self.namespaceURI: |
|
437 return info.isIdNS(self.namespaceURI, self.localName) |
|
438 else: |
|
439 return info.isId(self.nodeName) |
|
440 |
|
441 def _get_schemaType(self): |
|
442 doc = self.ownerDocument |
|
443 elem = self.ownerElement |
|
444 if doc is None or elem is None: |
|
445 return _no_type |
|
446 |
|
447 info = doc._get_elem_info(elem) |
|
448 if info is None: |
|
449 return _no_type |
|
450 if self.namespaceURI: |
|
451 return info.getAttributeTypeNS(self.namespaceURI, self.localName) |
|
452 else: |
|
453 return info.getAttributeType(self.nodeName) |
|
454 |
|
455 defproperty(Attr, "isId", doc="True if this attribute is an ID.") |
|
456 defproperty(Attr, "localName", doc="Namespace-local name of this attribute.") |
|
457 defproperty(Attr, "schemaType", doc="Schema type for this attribute.") |
|
458 |
|
459 |
|
460 class NamedNodeMap(object): |
|
461 """The attribute list is a transient interface to the underlying |
|
462 dictionaries. Mutations here will change the underlying element's |
|
463 dictionary. |
|
464 |
|
465 Ordering is imposed artificially and does not reflect the order of |
|
466 attributes as found in an input document. |
|
467 """ |
|
468 |
|
469 __slots__ = ('_attrs', '_attrsNS', '_ownerElement') |
|
470 |
|
471 def __init__(self, attrs, attrsNS, ownerElement): |
|
472 self._attrs = attrs |
|
473 self._attrsNS = attrsNS |
|
474 self._ownerElement = ownerElement |
|
475 |
|
476 def _get_length(self): |
|
477 return len(self._attrs) |
|
478 |
|
479 def item(self, index): |
|
480 try: |
|
481 return self[self._attrs.keys()[index]] |
|
482 except IndexError: |
|
483 return None |
|
484 |
|
485 def items(self): |
|
486 L = [] |
|
487 for node in self._attrs.values(): |
|
488 L.append((node.nodeName, node.value)) |
|
489 return L |
|
490 |
|
491 def itemsNS(self): |
|
492 L = [] |
|
493 for node in self._attrs.values(): |
|
494 L.append(((node.namespaceURI, node.localName), node.value)) |
|
495 return L |
|
496 |
|
497 def has_key(self, key): |
|
498 if isinstance(key, StringTypes): |
|
499 return self._attrs.has_key(key) |
|
500 else: |
|
501 return self._attrsNS.has_key(key) |
|
502 |
|
503 def keys(self): |
|
504 return self._attrs.keys() |
|
505 |
|
506 def keysNS(self): |
|
507 return self._attrsNS.keys() |
|
508 |
|
509 def values(self): |
|
510 return self._attrs.values() |
|
511 |
|
512 def get(self, name, value=None): |
|
513 return self._attrs.get(name, value) |
|
514 |
|
515 __len__ = _get_length |
|
516 |
|
517 def __cmp__(self, other): |
|
518 if self._attrs is getattr(other, "_attrs", None): |
|
519 return 0 |
|
520 else: |
|
521 return cmp(id(self), id(other)) |
|
522 |
|
523 def __getitem__(self, attname_or_tuple): |
|
524 if isinstance(attname_or_tuple, tuple): |
|
525 return self._attrsNS[attname_or_tuple] |
|
526 else: |
|
527 return self._attrs[attname_or_tuple] |
|
528 |
|
529 # same as set |
|
530 def __setitem__(self, attname, value): |
|
531 if isinstance(value, StringTypes): |
|
532 try: |
|
533 node = self._attrs[attname] |
|
534 except KeyError: |
|
535 node = Attr(attname) |
|
536 node.ownerDocument = self._ownerElement.ownerDocument |
|
537 self.setNamedItem(node) |
|
538 node.value = value |
|
539 else: |
|
540 if not isinstance(value, Attr): |
|
541 raise TypeError, "value must be a string or Attr object" |
|
542 node = value |
|
543 self.setNamedItem(node) |
|
544 |
|
545 def getNamedItem(self, name): |
|
546 try: |
|
547 return self._attrs[name] |
|
548 except KeyError: |
|
549 return None |
|
550 |
|
551 def getNamedItemNS(self, namespaceURI, localName): |
|
552 try: |
|
553 return self._attrsNS[(namespaceURI, localName)] |
|
554 except KeyError: |
|
555 return None |
|
556 |
|
557 def removeNamedItem(self, name): |
|
558 n = self.getNamedItem(name) |
|
559 if n is not None: |
|
560 _clear_id_cache(self._ownerElement) |
|
561 del self._attrs[n.nodeName] |
|
562 del self._attrsNS[(n.namespaceURI, n.localName)] |
|
563 if n.__dict__.has_key('ownerElement'): |
|
564 n.__dict__['ownerElement'] = None |
|
565 return n |
|
566 else: |
|
567 raise xml.dom.NotFoundErr() |
|
568 |
|
569 def removeNamedItemNS(self, namespaceURI, localName): |
|
570 n = self.getNamedItemNS(namespaceURI, localName) |
|
571 if n is not None: |
|
572 _clear_id_cache(self._ownerElement) |
|
573 del self._attrsNS[(n.namespaceURI, n.localName)] |
|
574 del self._attrs[n.nodeName] |
|
575 if n.__dict__.has_key('ownerElement'): |
|
576 n.__dict__['ownerElement'] = None |
|
577 return n |
|
578 else: |
|
579 raise xml.dom.NotFoundErr() |
|
580 |
|
581 def setNamedItem(self, node): |
|
582 if not isinstance(node, Attr): |
|
583 raise xml.dom.HierarchyRequestErr( |
|
584 "%s cannot be child of %s" % (repr(node), repr(self))) |
|
585 old = self._attrs.get(node.name) |
|
586 if old: |
|
587 old.unlink() |
|
588 self._attrs[node.name] = node |
|
589 self._attrsNS[(node.namespaceURI, node.localName)] = node |
|
590 node.ownerElement = self._ownerElement |
|
591 _clear_id_cache(node.ownerElement) |
|
592 return old |
|
593 |
|
594 def setNamedItemNS(self, node): |
|
595 return self.setNamedItem(node) |
|
596 |
|
597 def __delitem__(self, attname_or_tuple): |
|
598 node = self[attname_or_tuple] |
|
599 _clear_id_cache(node.ownerElement) |
|
600 node.unlink() |
|
601 |
|
602 def __getstate__(self): |
|
603 return self._attrs, self._attrsNS, self._ownerElement |
|
604 |
|
605 def __setstate__(self, state): |
|
606 self._attrs, self._attrsNS, self._ownerElement = state |
|
607 |
|
608 defproperty(NamedNodeMap, "length", |
|
609 doc="Number of nodes in the NamedNodeMap.") |
|
610 |
|
611 AttributeList = NamedNodeMap |
|
612 |
|
613 |
|
614 class TypeInfo(object): |
|
615 __slots__ = 'namespace', 'name' |
|
616 |
|
617 def __init__(self, namespace, name): |
|
618 self.namespace = namespace |
|
619 self.name = name |
|
620 |
|
621 def __repr__(self): |
|
622 if self.namespace: |
|
623 return "<TypeInfo %r (from %r)>" % (self.name, self.namespace) |
|
624 else: |
|
625 return "<TypeInfo %r>" % self.name |
|
626 |
|
627 def _get_name(self): |
|
628 return self.name |
|
629 |
|
630 def _get_namespace(self): |
|
631 return self.namespace |
|
632 |
|
633 _no_type = TypeInfo(None, None) |
|
634 |
|
635 class Element(Node): |
|
636 nodeType = Node.ELEMENT_NODE |
|
637 nodeValue = None |
|
638 schemaType = _no_type |
|
639 |
|
640 _magic_id_nodes = 0 |
|
641 |
|
642 _child_node_types = (Node.ELEMENT_NODE, |
|
643 Node.PROCESSING_INSTRUCTION_NODE, |
|
644 Node.COMMENT_NODE, |
|
645 Node.TEXT_NODE, |
|
646 Node.CDATA_SECTION_NODE, |
|
647 Node.ENTITY_REFERENCE_NODE) |
|
648 |
|
649 def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None, |
|
650 localName=None): |
|
651 self.tagName = self.nodeName = tagName |
|
652 self.prefix = prefix |
|
653 self.namespaceURI = namespaceURI |
|
654 self.childNodes = NodeList() |
|
655 |
|
656 self._attrs = {} # attributes are double-indexed: |
|
657 self._attrsNS = {} # tagName -> Attribute |
|
658 # URI,localName -> Attribute |
|
659 # in the future: consider lazy generation |
|
660 # of attribute objects this is too tricky |
|
661 # for now because of headaches with |
|
662 # namespaces. |
|
663 |
|
664 def _get_localName(self): |
|
665 return self.tagName.split(":", 1)[-1] |
|
666 |
|
667 def _get_tagName(self): |
|
668 return self.tagName |
|
669 |
|
670 def unlink(self): |
|
671 for attr in self._attrs.values(): |
|
672 attr.unlink() |
|
673 self._attrs = None |
|
674 self._attrsNS = None |
|
675 Node.unlink(self) |
|
676 |
|
677 def getAttribute(self, attname): |
|
678 try: |
|
679 return self._attrs[attname].value |
|
680 except KeyError: |
|
681 return "" |
|
682 |
|
683 def getAttributeNS(self, namespaceURI, localName): |
|
684 try: |
|
685 return self._attrsNS[(namespaceURI, localName)].value |
|
686 except KeyError: |
|
687 return "" |
|
688 |
|
689 def setAttribute(self, attname, value): |
|
690 attr = self.getAttributeNode(attname) |
|
691 if attr is None: |
|
692 attr = Attr(attname) |
|
693 # for performance |
|
694 d = attr.__dict__ |
|
695 d["value"] = d["nodeValue"] = value |
|
696 d["ownerDocument"] = self.ownerDocument |
|
697 self.setAttributeNode(attr) |
|
698 elif value != attr.value: |
|
699 d = attr.__dict__ |
|
700 d["value"] = d["nodeValue"] = value |
|
701 if attr.isId: |
|
702 _clear_id_cache(self) |
|
703 |
|
704 def setAttributeNS(self, namespaceURI, qualifiedName, value): |
|
705 prefix, localname = _nssplit(qualifiedName) |
|
706 attr = self.getAttributeNodeNS(namespaceURI, localname) |
|
707 if attr is None: |
|
708 # for performance |
|
709 attr = Attr(qualifiedName, namespaceURI, localname, prefix) |
|
710 d = attr.__dict__ |
|
711 d["prefix"] = prefix |
|
712 d["nodeName"] = qualifiedName |
|
713 d["value"] = d["nodeValue"] = value |
|
714 d["ownerDocument"] = self.ownerDocument |
|
715 self.setAttributeNode(attr) |
|
716 else: |
|
717 d = attr.__dict__ |
|
718 if value != attr.value: |
|
719 d["value"] = d["nodeValue"] = value |
|
720 if attr.isId: |
|
721 _clear_id_cache(self) |
|
722 if attr.prefix != prefix: |
|
723 d["prefix"] = prefix |
|
724 d["nodeName"] = qualifiedName |
|
725 |
|
726 def getAttributeNode(self, attrname): |
|
727 return self._attrs.get(attrname) |
|
728 |
|
729 def getAttributeNodeNS(self, namespaceURI, localName): |
|
730 return self._attrsNS.get((namespaceURI, localName)) |
|
731 |
|
732 def setAttributeNode(self, attr): |
|
733 if attr.ownerElement not in (None, self): |
|
734 raise xml.dom.InuseAttributeErr("attribute node already owned") |
|
735 old1 = self._attrs.get(attr.name, None) |
|
736 if old1 is not None: |
|
737 self.removeAttributeNode(old1) |
|
738 old2 = self._attrsNS.get((attr.namespaceURI, attr.localName), None) |
|
739 if old2 is not None and old2 is not old1: |
|
740 self.removeAttributeNode(old2) |
|
741 _set_attribute_node(self, attr) |
|
742 |
|
743 if old1 is not attr: |
|
744 # It might have already been part of this node, in which case |
|
745 # it doesn't represent a change, and should not be returned. |
|
746 return old1 |
|
747 if old2 is not attr: |
|
748 return old2 |
|
749 |
|
750 setAttributeNodeNS = setAttributeNode |
|
751 |
|
752 def removeAttribute(self, name): |
|
753 try: |
|
754 attr = self._attrs[name] |
|
755 except KeyError: |
|
756 raise xml.dom.NotFoundErr() |
|
757 self.removeAttributeNode(attr) |
|
758 |
|
759 def removeAttributeNS(self, namespaceURI, localName): |
|
760 try: |
|
761 attr = self._attrsNS[(namespaceURI, localName)] |
|
762 except KeyError: |
|
763 raise xml.dom.NotFoundErr() |
|
764 self.removeAttributeNode(attr) |
|
765 |
|
766 def removeAttributeNode(self, node): |
|
767 if node is None: |
|
768 raise xml.dom.NotFoundErr() |
|
769 try: |
|
770 self._attrs[node.name] |
|
771 except KeyError: |
|
772 raise xml.dom.NotFoundErr() |
|
773 _clear_id_cache(self) |
|
774 node.unlink() |
|
775 # Restore this since the node is still useful and otherwise |
|
776 # unlinked |
|
777 node.ownerDocument = self.ownerDocument |
|
778 |
|
779 removeAttributeNodeNS = removeAttributeNode |
|
780 |
|
781 def hasAttribute(self, name): |
|
782 return self._attrs.has_key(name) |
|
783 |
|
784 def hasAttributeNS(self, namespaceURI, localName): |
|
785 return self._attrsNS.has_key((namespaceURI, localName)) |
|
786 |
|
787 def getElementsByTagName(self, name): |
|
788 return _get_elements_by_tagName_helper(self, name, NodeList()) |
|
789 |
|
790 def getElementsByTagNameNS(self, namespaceURI, localName): |
|
791 return _get_elements_by_tagName_ns_helper( |
|
792 self, namespaceURI, localName, NodeList()) |
|
793 |
|
794 def __repr__(self): |
|
795 return "<DOM Element: %s at %#x>" % (self.tagName, id(self)) |
|
796 |
|
797 def writexml(self, writer, indent="", addindent="", newl=""): |
|
798 # indent = current indentation |
|
799 # addindent = indentation to add to higher levels |
|
800 # newl = newline string |
|
801 writer.write(indent+"<" + self.tagName) |
|
802 |
|
803 attrs = self._get_attributes() |
|
804 a_names = attrs.keys() |
|
805 a_names.sort() |
|
806 |
|
807 for a_name in a_names: |
|
808 writer.write(" %s=\"" % a_name) |
|
809 _write_data(writer, attrs[a_name].value) |
|
810 writer.write("\"") |
|
811 if self.childNodes: |
|
812 writer.write(">%s"%(newl)) |
|
813 for node in self.childNodes: |
|
814 node.writexml(writer,indent+addindent,addindent,newl) |
|
815 writer.write("%s</%s>%s" % (indent,self.tagName,newl)) |
|
816 else: |
|
817 writer.write("/>%s"%(newl)) |
|
818 |
|
819 def _get_attributes(self): |
|
820 return NamedNodeMap(self._attrs, self._attrsNS, self) |
|
821 |
|
822 def hasAttributes(self): |
|
823 if self._attrs: |
|
824 return True |
|
825 else: |
|
826 return False |
|
827 |
|
828 # DOM Level 3 attributes, based on the 22 Oct 2002 draft |
|
829 |
|
830 def setIdAttribute(self, name): |
|
831 idAttr = self.getAttributeNode(name) |
|
832 self.setIdAttributeNode(idAttr) |
|
833 |
|
834 def setIdAttributeNS(self, namespaceURI, localName): |
|
835 idAttr = self.getAttributeNodeNS(namespaceURI, localName) |
|
836 self.setIdAttributeNode(idAttr) |
|
837 |
|
838 def setIdAttributeNode(self, idAttr): |
|
839 if idAttr is None or not self.isSameNode(idAttr.ownerElement): |
|
840 raise xml.dom.NotFoundErr() |
|
841 if _get_containing_entref(self) is not None: |
|
842 raise xml.dom.NoModificationAllowedErr() |
|
843 if not idAttr._is_id: |
|
844 idAttr.__dict__['_is_id'] = True |
|
845 self._magic_id_nodes += 1 |
|
846 self.ownerDocument._magic_id_count += 1 |
|
847 _clear_id_cache(self) |
|
848 |
|
849 defproperty(Element, "attributes", |
|
850 doc="NamedNodeMap of attributes on the element.") |
|
851 defproperty(Element, "localName", |
|
852 doc="Namespace-local name of this element.") |
|
853 |
|
854 |
|
855 def _set_attribute_node(element, attr): |
|
856 _clear_id_cache(element) |
|
857 element._attrs[attr.name] = attr |
|
858 element._attrsNS[(attr.namespaceURI, attr.localName)] = attr |
|
859 |
|
860 # This creates a circular reference, but Element.unlink() |
|
861 # breaks the cycle since the references to the attribute |
|
862 # dictionaries are tossed. |
|
863 attr.__dict__['ownerElement'] = element |
|
864 |
|
865 |
|
866 class Childless: |
|
867 """Mixin that makes childless-ness easy to implement and avoids |
|
868 the complexity of the Node methods that deal with children. |
|
869 """ |
|
870 |
|
871 attributes = None |
|
872 childNodes = EmptyNodeList() |
|
873 firstChild = None |
|
874 lastChild = None |
|
875 |
|
876 def _get_firstChild(self): |
|
877 return None |
|
878 |
|
879 def _get_lastChild(self): |
|
880 return None |
|
881 |
|
882 def appendChild(self, node): |
|
883 raise xml.dom.HierarchyRequestErr( |
|
884 self.nodeName + " nodes cannot have children") |
|
885 |
|
886 def hasChildNodes(self): |
|
887 return False |
|
888 |
|
889 def insertBefore(self, newChild, refChild): |
|
890 raise xml.dom.HierarchyRequestErr( |
|
891 self.nodeName + " nodes do not have children") |
|
892 |
|
893 def removeChild(self, oldChild): |
|
894 raise xml.dom.NotFoundErr( |
|
895 self.nodeName + " nodes do not have children") |
|
896 |
|
897 def replaceChild(self, newChild, oldChild): |
|
898 raise xml.dom.HierarchyRequestErr( |
|
899 self.nodeName + " nodes do not have children") |
|
900 |
|
901 |
|
902 class ProcessingInstruction(Childless, Node): |
|
903 nodeType = Node.PROCESSING_INSTRUCTION_NODE |
|
904 |
|
905 def __init__(self, target, data): |
|
906 self.target = self.nodeName = target |
|
907 self.data = self.nodeValue = data |
|
908 |
|
909 def _get_data(self): |
|
910 return self.data |
|
911 def _set_data(self, value): |
|
912 d = self.__dict__ |
|
913 d['data'] = d['nodeValue'] = value |
|
914 |
|
915 def _get_target(self): |
|
916 return self.target |
|
917 def _set_target(self, value): |
|
918 d = self.__dict__ |
|
919 d['target'] = d['nodeName'] = value |
|
920 |
|
921 def __setattr__(self, name, value): |
|
922 if name == "data" or name == "nodeValue": |
|
923 self.__dict__['data'] = self.__dict__['nodeValue'] = value |
|
924 elif name == "target" or name == "nodeName": |
|
925 self.__dict__['target'] = self.__dict__['nodeName'] = value |
|
926 else: |
|
927 self.__dict__[name] = value |
|
928 |
|
929 def writexml(self, writer, indent="", addindent="", newl=""): |
|
930 writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl)) |
|
931 |
|
932 |
|
933 class CharacterData(Childless, Node): |
|
934 def _get_length(self): |
|
935 return len(self.data) |
|
936 __len__ = _get_length |
|
937 |
|
938 def _get_data(self): |
|
939 return self.__dict__['data'] |
|
940 def _set_data(self, data): |
|
941 d = self.__dict__ |
|
942 d['data'] = d['nodeValue'] = data |
|
943 |
|
944 _get_nodeValue = _get_data |
|
945 _set_nodeValue = _set_data |
|
946 |
|
947 def __setattr__(self, name, value): |
|
948 if name == "data" or name == "nodeValue": |
|
949 self.__dict__['data'] = self.__dict__['nodeValue'] = value |
|
950 else: |
|
951 self.__dict__[name] = value |
|
952 |
|
953 def __repr__(self): |
|
954 data = self.data |
|
955 if len(data) > 10: |
|
956 dotdotdot = "..." |
|
957 else: |
|
958 dotdotdot = "" |
|
959 return "<DOM %s node \"%s%s\">" % ( |
|
960 self.__class__.__name__, data[0:10], dotdotdot) |
|
961 |
|
962 def substringData(self, offset, count): |
|
963 if offset < 0: |
|
964 raise xml.dom.IndexSizeErr("offset cannot be negative") |
|
965 if offset >= len(self.data): |
|
966 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data") |
|
967 if count < 0: |
|
968 raise xml.dom.IndexSizeErr("count cannot be negative") |
|
969 return self.data[offset:offset+count] |
|
970 |
|
971 def appendData(self, arg): |
|
972 self.data = self.data + arg |
|
973 |
|
974 def insertData(self, offset, arg): |
|
975 if offset < 0: |
|
976 raise xml.dom.IndexSizeErr("offset cannot be negative") |
|
977 if offset >= len(self.data): |
|
978 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data") |
|
979 if arg: |
|
980 self.data = "%s%s%s" % ( |
|
981 self.data[:offset], arg, self.data[offset:]) |
|
982 |
|
983 def deleteData(self, offset, count): |
|
984 if offset < 0: |
|
985 raise xml.dom.IndexSizeErr("offset cannot be negative") |
|
986 if offset >= len(self.data): |
|
987 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data") |
|
988 if count < 0: |
|
989 raise xml.dom.IndexSizeErr("count cannot be negative") |
|
990 if count: |
|
991 self.data = self.data[:offset] + self.data[offset+count:] |
|
992 |
|
993 def replaceData(self, offset, count, arg): |
|
994 if offset < 0: |
|
995 raise xml.dom.IndexSizeErr("offset cannot be negative") |
|
996 if offset >= len(self.data): |
|
997 raise xml.dom.IndexSizeErr("offset cannot be beyond end of data") |
|
998 if count < 0: |
|
999 raise xml.dom.IndexSizeErr("count cannot be negative") |
|
1000 if count: |
|
1001 self.data = "%s%s%s" % ( |
|
1002 self.data[:offset], arg, self.data[offset+count:]) |
|
1003 |
|
1004 defproperty(CharacterData, "length", doc="Length of the string data.") |
|
1005 |
|
1006 |
|
1007 class Text(CharacterData): |
|
1008 # Make sure we don't add an instance __dict__ if we don't already |
|
1009 # have one, at least when that's possible: |
|
1010 # XXX this does not work, CharacterData is an old-style class |
|
1011 # __slots__ = () |
|
1012 |
|
1013 nodeType = Node.TEXT_NODE |
|
1014 nodeName = "#text" |
|
1015 attributes = None |
|
1016 |
|
1017 def splitText(self, offset): |
|
1018 if offset < 0 or offset > len(self.data): |
|
1019 raise xml.dom.IndexSizeErr("illegal offset value") |
|
1020 newText = self.__class__() |
|
1021 newText.data = self.data[offset:] |
|
1022 newText.ownerDocument = self.ownerDocument |
|
1023 next = self.nextSibling |
|
1024 if self.parentNode and self in self.parentNode.childNodes: |
|
1025 if next is None: |
|
1026 self.parentNode.appendChild(newText) |
|
1027 else: |
|
1028 self.parentNode.insertBefore(newText, next) |
|
1029 self.data = self.data[:offset] |
|
1030 return newText |
|
1031 |
|
1032 def writexml(self, writer, indent="", addindent="", newl=""): |
|
1033 _write_data(writer, "%s%s%s"%(indent, self.data, newl)) |
|
1034 |
|
1035 # DOM Level 3 (WD 9 April 2002) |
|
1036 |
|
1037 def _get_wholeText(self): |
|
1038 L = [self.data] |
|
1039 n = self.previousSibling |
|
1040 while n is not None: |
|
1041 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): |
|
1042 L.insert(0, n.data) |
|
1043 n = n.previousSibling |
|
1044 else: |
|
1045 break |
|
1046 n = self.nextSibling |
|
1047 while n is not None: |
|
1048 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): |
|
1049 L.append(n.data) |
|
1050 n = n.nextSibling |
|
1051 else: |
|
1052 break |
|
1053 return ''.join(L) |
|
1054 |
|
1055 def replaceWholeText(self, content): |
|
1056 # XXX This needs to be seriously changed if minidom ever |
|
1057 # supports EntityReference nodes. |
|
1058 parent = self.parentNode |
|
1059 n = self.previousSibling |
|
1060 while n is not None: |
|
1061 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): |
|
1062 next = n.previousSibling |
|
1063 parent.removeChild(n) |
|
1064 n = next |
|
1065 else: |
|
1066 break |
|
1067 n = self.nextSibling |
|
1068 if not content: |
|
1069 parent.removeChild(self) |
|
1070 while n is not None: |
|
1071 if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): |
|
1072 next = n.nextSibling |
|
1073 parent.removeChild(n) |
|
1074 n = next |
|
1075 else: |
|
1076 break |
|
1077 if content: |
|
1078 d = self.__dict__ |
|
1079 d['data'] = content |
|
1080 d['nodeValue'] = content |
|
1081 return self |
|
1082 else: |
|
1083 return None |
|
1084 |
|
1085 def _get_isWhitespaceInElementContent(self): |
|
1086 if self.data.strip(): |
|
1087 return False |
|
1088 elem = _get_containing_element(self) |
|
1089 if elem is None: |
|
1090 return False |
|
1091 info = self.ownerDocument._get_elem_info(elem) |
|
1092 if info is None: |
|
1093 return False |
|
1094 else: |
|
1095 return info.isElementContent() |
|
1096 |
|
1097 defproperty(Text, "isWhitespaceInElementContent", |
|
1098 doc="True iff this text node contains only whitespace" |
|
1099 " and is in element content.") |
|
1100 defproperty(Text, "wholeText", |
|
1101 doc="The text of all logically-adjacent text nodes.") |
|
1102 |
|
1103 |
|
1104 def _get_containing_element(node): |
|
1105 c = node.parentNode |
|
1106 while c is not None: |
|
1107 if c.nodeType == Node.ELEMENT_NODE: |
|
1108 return c |
|
1109 c = c.parentNode |
|
1110 return None |
|
1111 |
|
1112 def _get_containing_entref(node): |
|
1113 c = node.parentNode |
|
1114 while c is not None: |
|
1115 if c.nodeType == Node.ENTITY_REFERENCE_NODE: |
|
1116 return c |
|
1117 c = c.parentNode |
|
1118 return None |
|
1119 |
|
1120 |
|
1121 class Comment(Childless, CharacterData): |
|
1122 nodeType = Node.COMMENT_NODE |
|
1123 nodeName = "#comment" |
|
1124 |
|
1125 def __init__(self, data): |
|
1126 self.data = self.nodeValue = data |
|
1127 |
|
1128 def writexml(self, writer, indent="", addindent="", newl=""): |
|
1129 writer.write("%s<!--%s-->%s" % (indent, self.data, newl)) |
|
1130 |
|
1131 |
|
1132 class CDATASection(Text): |
|
1133 # Make sure we don't add an instance __dict__ if we don't already |
|
1134 # have one, at least when that's possible: |
|
1135 # XXX this does not work, Text is an old-style class |
|
1136 # __slots__ = () |
|
1137 |
|
1138 nodeType = Node.CDATA_SECTION_NODE |
|
1139 nodeName = "#cdata-section" |
|
1140 |
|
1141 def writexml(self, writer, indent="", addindent="", newl=""): |
|
1142 if self.data.find("]]>") >= 0: |
|
1143 raise ValueError("']]>' not allowed in a CDATA section") |
|
1144 writer.write("<![CDATA[%s]]>" % self.data) |
|
1145 |
|
1146 |
|
1147 class ReadOnlySequentialNamedNodeMap(object): |
|
1148 __slots__ = '_seq', |
|
1149 |
|
1150 def __init__(self, seq=()): |
|
1151 # seq should be a list or tuple |
|
1152 self._seq = seq |
|
1153 |
|
1154 def __len__(self): |
|
1155 return len(self._seq) |
|
1156 |
|
1157 def _get_length(self): |
|
1158 return len(self._seq) |
|
1159 |
|
1160 def getNamedItem(self, name): |
|
1161 for n in self._seq: |
|
1162 if n.nodeName == name: |
|
1163 return n |
|
1164 |
|
1165 def getNamedItemNS(self, namespaceURI, localName): |
|
1166 for n in self._seq: |
|
1167 if n.namespaceURI == namespaceURI and n.localName == localName: |
|
1168 return n |
|
1169 |
|
1170 def __getitem__(self, name_or_tuple): |
|
1171 if isinstance(name_or_tuple, tuple): |
|
1172 node = self.getNamedItemNS(*name_or_tuple) |
|
1173 else: |
|
1174 node = self.getNamedItem(name_or_tuple) |
|
1175 if node is None: |
|
1176 raise KeyError, name_or_tuple |
|
1177 return node |
|
1178 |
|
1179 def item(self, index): |
|
1180 if index < 0: |
|
1181 return None |
|
1182 try: |
|
1183 return self._seq[index] |
|
1184 except IndexError: |
|
1185 return None |
|
1186 |
|
1187 def removeNamedItem(self, name): |
|
1188 raise xml.dom.NoModificationAllowedErr( |
|
1189 "NamedNodeMap instance is read-only") |
|
1190 |
|
1191 def removeNamedItemNS(self, namespaceURI, localName): |
|
1192 raise xml.dom.NoModificationAllowedErr( |
|
1193 "NamedNodeMap instance is read-only") |
|
1194 |
|
1195 def setNamedItem(self, node): |
|
1196 raise xml.dom.NoModificationAllowedErr( |
|
1197 "NamedNodeMap instance is read-only") |
|
1198 |
|
1199 def setNamedItemNS(self, node): |
|
1200 raise xml.dom.NoModificationAllowedErr( |
|
1201 "NamedNodeMap instance is read-only") |
|
1202 |
|
1203 def __getstate__(self): |
|
1204 return [self._seq] |
|
1205 |
|
1206 def __setstate__(self, state): |
|
1207 self._seq = state[0] |
|
1208 |
|
1209 defproperty(ReadOnlySequentialNamedNodeMap, "length", |
|
1210 doc="Number of entries in the NamedNodeMap.") |
|
1211 |
|
1212 |
|
1213 class Identified: |
|
1214 """Mix-in class that supports the publicId and systemId attributes.""" |
|
1215 |
|
1216 # XXX this does not work, this is an old-style class |
|
1217 # __slots__ = 'publicId', 'systemId' |
|
1218 |
|
1219 def _identified_mixin_init(self, publicId, systemId): |
|
1220 self.publicId = publicId |
|
1221 self.systemId = systemId |
|
1222 |
|
1223 def _get_publicId(self): |
|
1224 return self.publicId |
|
1225 |
|
1226 def _get_systemId(self): |
|
1227 return self.systemId |
|
1228 |
|
1229 class DocumentType(Identified, Childless, Node): |
|
1230 nodeType = Node.DOCUMENT_TYPE_NODE |
|
1231 nodeValue = None |
|
1232 name = None |
|
1233 publicId = None |
|
1234 systemId = None |
|
1235 internalSubset = None |
|
1236 |
|
1237 def __init__(self, qualifiedName): |
|
1238 self.entities = ReadOnlySequentialNamedNodeMap() |
|
1239 self.notations = ReadOnlySequentialNamedNodeMap() |
|
1240 if qualifiedName: |
|
1241 prefix, localname = _nssplit(qualifiedName) |
|
1242 self.name = localname |
|
1243 self.nodeName = self.name |
|
1244 |
|
1245 def _get_internalSubset(self): |
|
1246 return self.internalSubset |
|
1247 |
|
1248 def cloneNode(self, deep): |
|
1249 if self.ownerDocument is None: |
|
1250 # it's ok |
|
1251 clone = DocumentType(None) |
|
1252 clone.name = self.name |
|
1253 clone.nodeName = self.name |
|
1254 operation = xml.dom.UserDataHandler.NODE_CLONED |
|
1255 if deep: |
|
1256 clone.entities._seq = [] |
|
1257 clone.notations._seq = [] |
|
1258 for n in self.notations._seq: |
|
1259 notation = Notation(n.nodeName, n.publicId, n.systemId) |
|
1260 clone.notations._seq.append(notation) |
|
1261 n._call_user_data_handler(operation, n, notation) |
|
1262 for e in self.entities._seq: |
|
1263 entity = Entity(e.nodeName, e.publicId, e.systemId, |
|
1264 e.notationName) |
|
1265 entity.actualEncoding = e.actualEncoding |
|
1266 entity.encoding = e.encoding |
|
1267 entity.version = e.version |
|
1268 clone.entities._seq.append(entity) |
|
1269 e._call_user_data_handler(operation, n, entity) |
|
1270 self._call_user_data_handler(operation, self, clone) |
|
1271 return clone |
|
1272 else: |
|
1273 return None |
|
1274 |
|
1275 def writexml(self, writer, indent="", addindent="", newl=""): |
|
1276 writer.write("<!DOCTYPE ") |
|
1277 writer.write(self.name) |
|
1278 if self.publicId: |
|
1279 writer.write("%s PUBLIC '%s'%s '%s'" |
|
1280 % (newl, self.publicId, newl, self.systemId)) |
|
1281 elif self.systemId: |
|
1282 writer.write("%s SYSTEM '%s'" % (newl, self.systemId)) |
|
1283 if self.internalSubset is not None: |
|
1284 writer.write(" [") |
|
1285 writer.write(self.internalSubset) |
|
1286 writer.write("]") |
|
1287 writer.write(">"+newl) |
|
1288 |
|
1289 class Entity(Identified, Node): |
|
1290 attributes = None |
|
1291 nodeType = Node.ENTITY_NODE |
|
1292 nodeValue = None |
|
1293 |
|
1294 actualEncoding = None |
|
1295 encoding = None |
|
1296 version = None |
|
1297 |
|
1298 def __init__(self, name, publicId, systemId, notation): |
|
1299 self.nodeName = name |
|
1300 self.notationName = notation |
|
1301 self.childNodes = NodeList() |
|
1302 self._identified_mixin_init(publicId, systemId) |
|
1303 |
|
1304 def _get_actualEncoding(self): |
|
1305 return self.actualEncoding |
|
1306 |
|
1307 def _get_encoding(self): |
|
1308 return self.encoding |
|
1309 |
|
1310 def _get_version(self): |
|
1311 return self.version |
|
1312 |
|
1313 def appendChild(self, newChild): |
|
1314 raise xml.dom.HierarchyRequestErr( |
|
1315 "cannot append children to an entity node") |
|
1316 |
|
1317 def insertBefore(self, newChild, refChild): |
|
1318 raise xml.dom.HierarchyRequestErr( |
|
1319 "cannot insert children below an entity node") |
|
1320 |
|
1321 def removeChild(self, oldChild): |
|
1322 raise xml.dom.HierarchyRequestErr( |
|
1323 "cannot remove children from an entity node") |
|
1324 |
|
1325 def replaceChild(self, newChild, oldChild): |
|
1326 raise xml.dom.HierarchyRequestErr( |
|
1327 "cannot replace children of an entity node") |
|
1328 |
|
1329 class Notation(Identified, Childless, Node): |
|
1330 nodeType = Node.NOTATION_NODE |
|
1331 nodeValue = None |
|
1332 |
|
1333 def __init__(self, name, publicId, systemId): |
|
1334 self.nodeName = name |
|
1335 self._identified_mixin_init(publicId, systemId) |
|
1336 |
|
1337 |
|
1338 class DOMImplementation(DOMImplementationLS): |
|
1339 _features = [("core", "1.0"), |
|
1340 ("core", "2.0"), |
|
1341 ("core", "3.0"), |
|
1342 ("core", None), |
|
1343 ("xml", "1.0"), |
|
1344 ("xml", "2.0"), |
|
1345 ("xml", "3.0"), |
|
1346 ("xml", None), |
|
1347 ("ls-load", "3.0"), |
|
1348 ("ls-load", None), |
|
1349 ] |
|
1350 |
|
1351 def hasFeature(self, feature, version): |
|
1352 if version == "": |
|
1353 version = None |
|
1354 return (feature.lower(), version) in self._features |
|
1355 |
|
1356 def createDocument(self, namespaceURI, qualifiedName, doctype): |
|
1357 if doctype and doctype.parentNode is not None: |
|
1358 raise xml.dom.WrongDocumentErr( |
|
1359 "doctype object owned by another DOM tree") |
|
1360 doc = self._create_document() |
|
1361 |
|
1362 add_root_element = not (namespaceURI is None |
|
1363 and qualifiedName is None |
|
1364 and doctype is None) |
|
1365 |
|
1366 if not qualifiedName and add_root_element: |
|
1367 # The spec is unclear what to raise here; SyntaxErr |
|
1368 # would be the other obvious candidate. Since Xerces raises |
|
1369 # InvalidCharacterErr, and since SyntaxErr is not listed |
|
1370 # for createDocument, that seems to be the better choice. |
|
1371 # XXX: need to check for illegal characters here and in |
|
1372 # createElement. |
|
1373 |
|
1374 # DOM Level III clears this up when talking about the return value |
|
1375 # of this function. If namespaceURI, qName and DocType are |
|
1376 # Null the document is returned without a document element |
|
1377 # Otherwise if doctype or namespaceURI are not None |
|
1378 # Then we go back to the above problem |
|
1379 raise xml.dom.InvalidCharacterErr("Element with no name") |
|
1380 |
|
1381 if add_root_element: |
|
1382 prefix, localname = _nssplit(qualifiedName) |
|
1383 if prefix == "xml" \ |
|
1384 and namespaceURI != "http://www.w3.org/XML/1998/namespace": |
|
1385 raise xml.dom.NamespaceErr("illegal use of 'xml' prefix") |
|
1386 if prefix and not namespaceURI: |
|
1387 raise xml.dom.NamespaceErr( |
|
1388 "illegal use of prefix without namespaces") |
|
1389 element = doc.createElementNS(namespaceURI, qualifiedName) |
|
1390 if doctype: |
|
1391 doc.appendChild(doctype) |
|
1392 doc.appendChild(element) |
|
1393 |
|
1394 if doctype: |
|
1395 doctype.parentNode = doctype.ownerDocument = doc |
|
1396 |
|
1397 doc.doctype = doctype |
|
1398 doc.implementation = self |
|
1399 return doc |
|
1400 |
|
1401 def createDocumentType(self, qualifiedName, publicId, systemId): |
|
1402 doctype = DocumentType(qualifiedName) |
|
1403 doctype.publicId = publicId |
|
1404 doctype.systemId = systemId |
|
1405 return doctype |
|
1406 |
|
1407 # DOM Level 3 (WD 9 April 2002) |
|
1408 |
|
1409 def getInterface(self, feature): |
|
1410 if self.hasFeature(feature, None): |
|
1411 return self |
|
1412 else: |
|
1413 return None |
|
1414 |
|
1415 # internal |
|
1416 def _create_document(self): |
|
1417 return Document() |
|
1418 |
|
1419 class ElementInfo(object): |
|
1420 """Object that represents content-model information for an element. |
|
1421 |
|
1422 This implementation is not expected to be used in practice; DOM |
|
1423 builders should provide implementations which do the right thing |
|
1424 using information available to it. |
|
1425 |
|
1426 """ |
|
1427 |
|
1428 __slots__ = 'tagName', |
|
1429 |
|
1430 def __init__(self, name): |
|
1431 self.tagName = name |
|
1432 |
|
1433 def getAttributeType(self, aname): |
|
1434 return _no_type |
|
1435 |
|
1436 def getAttributeTypeNS(self, namespaceURI, localName): |
|
1437 return _no_type |
|
1438 |
|
1439 def isElementContent(self): |
|
1440 return False |
|
1441 |
|
1442 def isEmpty(self): |
|
1443 """Returns true iff this element is declared to have an EMPTY |
|
1444 content model.""" |
|
1445 return False |
|
1446 |
|
1447 def isId(self, aname): |
|
1448 """Returns true iff the named attribte is a DTD-style ID.""" |
|
1449 return False |
|
1450 |
|
1451 def isIdNS(self, namespaceURI, localName): |
|
1452 """Returns true iff the identified attribute is a DTD-style ID.""" |
|
1453 return False |
|
1454 |
|
1455 def __getstate__(self): |
|
1456 return self.tagName |
|
1457 |
|
1458 def __setstate__(self, state): |
|
1459 self.tagName = state |
|
1460 |
|
1461 def _clear_id_cache(node): |
|
1462 if node.nodeType == Node.DOCUMENT_NODE: |
|
1463 node._id_cache.clear() |
|
1464 node._id_search_stack = None |
|
1465 elif _in_document(node): |
|
1466 node.ownerDocument._id_cache.clear() |
|
1467 node.ownerDocument._id_search_stack= None |
|
1468 |
|
1469 class Document(Node, DocumentLS): |
|
1470 _child_node_types = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE, |
|
1471 Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE) |
|
1472 |
|
1473 nodeType = Node.DOCUMENT_NODE |
|
1474 nodeName = "#document" |
|
1475 nodeValue = None |
|
1476 attributes = None |
|
1477 doctype = None |
|
1478 parentNode = None |
|
1479 previousSibling = nextSibling = None |
|
1480 |
|
1481 implementation = DOMImplementation() |
|
1482 |
|
1483 # Document attributes from Level 3 (WD 9 April 2002) |
|
1484 |
|
1485 actualEncoding = None |
|
1486 encoding = None |
|
1487 standalone = None |
|
1488 version = None |
|
1489 strictErrorChecking = False |
|
1490 errorHandler = None |
|
1491 documentURI = None |
|
1492 |
|
1493 _magic_id_count = 0 |
|
1494 |
|
1495 def __init__(self): |
|
1496 self.childNodes = NodeList() |
|
1497 # mapping of (namespaceURI, localName) -> ElementInfo |
|
1498 # and tagName -> ElementInfo |
|
1499 self._elem_info = {} |
|
1500 self._id_cache = {} |
|
1501 self._id_search_stack = None |
|
1502 |
|
1503 def _get_elem_info(self, element): |
|
1504 if element.namespaceURI: |
|
1505 key = element.namespaceURI, element.localName |
|
1506 else: |
|
1507 key = element.tagName |
|
1508 return self._elem_info.get(key) |
|
1509 |
|
1510 def _get_actualEncoding(self): |
|
1511 return self.actualEncoding |
|
1512 |
|
1513 def _get_doctype(self): |
|
1514 return self.doctype |
|
1515 |
|
1516 def _get_documentURI(self): |
|
1517 return self.documentURI |
|
1518 |
|
1519 def _get_encoding(self): |
|
1520 return self.encoding |
|
1521 |
|
1522 def _get_errorHandler(self): |
|
1523 return self.errorHandler |
|
1524 |
|
1525 def _get_standalone(self): |
|
1526 return self.standalone |
|
1527 |
|
1528 def _get_strictErrorChecking(self): |
|
1529 return self.strictErrorChecking |
|
1530 |
|
1531 def _get_version(self): |
|
1532 return self.version |
|
1533 |
|
1534 def appendChild(self, node): |
|
1535 if node.nodeType not in self._child_node_types: |
|
1536 raise xml.dom.HierarchyRequestErr( |
|
1537 "%s cannot be child of %s" % (repr(node), repr(self))) |
|
1538 if node.parentNode is not None: |
|
1539 # This needs to be done before the next test since this |
|
1540 # may *be* the document element, in which case it should |
|
1541 # end up re-ordered to the end. |
|
1542 node.parentNode.removeChild(node) |
|
1543 |
|
1544 if node.nodeType == Node.ELEMENT_NODE \ |
|
1545 and self._get_documentElement(): |
|
1546 raise xml.dom.HierarchyRequestErr( |
|
1547 "two document elements disallowed") |
|
1548 return Node.appendChild(self, node) |
|
1549 |
|
1550 def removeChild(self, oldChild): |
|
1551 try: |
|
1552 self.childNodes.remove(oldChild) |
|
1553 except ValueError: |
|
1554 raise xml.dom.NotFoundErr() |
|
1555 oldChild.nextSibling = oldChild.previousSibling = None |
|
1556 oldChild.parentNode = None |
|
1557 if self.documentElement is oldChild: |
|
1558 self.documentElement = None |
|
1559 |
|
1560 return oldChild |
|
1561 |
|
1562 def _get_documentElement(self): |
|
1563 for node in self.childNodes: |
|
1564 if node.nodeType == Node.ELEMENT_NODE: |
|
1565 return node |
|
1566 |
|
1567 def unlink(self): |
|
1568 if self.doctype is not None: |
|
1569 self.doctype.unlink() |
|
1570 self.doctype = None |
|
1571 Node.unlink(self) |
|
1572 |
|
1573 def cloneNode(self, deep): |
|
1574 if not deep: |
|
1575 return None |
|
1576 clone = self.implementation.createDocument(None, None, None) |
|
1577 clone.encoding = self.encoding |
|
1578 clone.standalone = self.standalone |
|
1579 clone.version = self.version |
|
1580 for n in self.childNodes: |
|
1581 childclone = _clone_node(n, deep, clone) |
|
1582 assert childclone.ownerDocument.isSameNode(clone) |
|
1583 clone.childNodes.append(childclone) |
|
1584 if childclone.nodeType == Node.DOCUMENT_NODE: |
|
1585 assert clone.documentElement is None |
|
1586 elif childclone.nodeType == Node.DOCUMENT_TYPE_NODE: |
|
1587 assert clone.doctype is None |
|
1588 clone.doctype = childclone |
|
1589 childclone.parentNode = clone |
|
1590 self._call_user_data_handler(xml.dom.UserDataHandler.NODE_CLONED, |
|
1591 self, clone) |
|
1592 return clone |
|
1593 |
|
1594 def createDocumentFragment(self): |
|
1595 d = DocumentFragment() |
|
1596 d.ownerDocument = self |
|
1597 return d |
|
1598 |
|
1599 def createElement(self, tagName): |
|
1600 e = Element(tagName) |
|
1601 e.ownerDocument = self |
|
1602 return e |
|
1603 |
|
1604 def createTextNode(self, data): |
|
1605 if not isinstance(data, StringTypes): |
|
1606 raise TypeError, "node contents must be a string" |
|
1607 t = Text() |
|
1608 t.data = data |
|
1609 t.ownerDocument = self |
|
1610 return t |
|
1611 |
|
1612 def createCDATASection(self, data): |
|
1613 if not isinstance(data, StringTypes): |
|
1614 raise TypeError, "node contents must be a string" |
|
1615 c = CDATASection() |
|
1616 c.data = data |
|
1617 c.ownerDocument = self |
|
1618 return c |
|
1619 |
|
1620 def createComment(self, data): |
|
1621 c = Comment(data) |
|
1622 c.ownerDocument = self |
|
1623 return c |
|
1624 |
|
1625 def createProcessingInstruction(self, target, data): |
|
1626 p = ProcessingInstruction(target, data) |
|
1627 p.ownerDocument = self |
|
1628 return p |
|
1629 |
|
1630 def createAttribute(self, qName): |
|
1631 a = Attr(qName) |
|
1632 a.ownerDocument = self |
|
1633 a.value = "" |
|
1634 return a |
|
1635 |
|
1636 def createElementNS(self, namespaceURI, qualifiedName): |
|
1637 prefix, localName = _nssplit(qualifiedName) |
|
1638 e = Element(qualifiedName, namespaceURI, prefix) |
|
1639 e.ownerDocument = self |
|
1640 return e |
|
1641 |
|
1642 def createAttributeNS(self, namespaceURI, qualifiedName): |
|
1643 prefix, localName = _nssplit(qualifiedName) |
|
1644 a = Attr(qualifiedName, namespaceURI, localName, prefix) |
|
1645 a.ownerDocument = self |
|
1646 a.value = "" |
|
1647 return a |
|
1648 |
|
1649 # A couple of implementation-specific helpers to create node types |
|
1650 # not supported by the W3C DOM specs: |
|
1651 |
|
1652 def _create_entity(self, name, publicId, systemId, notationName): |
|
1653 e = Entity(name, publicId, systemId, notationName) |
|
1654 e.ownerDocument = self |
|
1655 return e |
|
1656 |
|
1657 def _create_notation(self, name, publicId, systemId): |
|
1658 n = Notation(name, publicId, systemId) |
|
1659 n.ownerDocument = self |
|
1660 return n |
|
1661 |
|
1662 def getElementById(self, id): |
|
1663 if self._id_cache.has_key(id): |
|
1664 return self._id_cache[id] |
|
1665 if not (self._elem_info or self._magic_id_count): |
|
1666 return None |
|
1667 |
|
1668 stack = self._id_search_stack |
|
1669 if stack is None: |
|
1670 # we never searched before, or the cache has been cleared |
|
1671 stack = [self.documentElement] |
|
1672 self._id_search_stack = stack |
|
1673 elif not stack: |
|
1674 # Previous search was completed and cache is still valid; |
|
1675 # no matching node. |
|
1676 return None |
|
1677 |
|
1678 result = None |
|
1679 while stack: |
|
1680 node = stack.pop() |
|
1681 # add child elements to stack for continued searching |
|
1682 stack.extend([child for child in node.childNodes |
|
1683 if child.nodeType in _nodeTypes_with_children]) |
|
1684 # check this node |
|
1685 info = self._get_elem_info(node) |
|
1686 if info: |
|
1687 # We have to process all ID attributes before |
|
1688 # returning in order to get all the attributes set to |
|
1689 # be IDs using Element.setIdAttribute*(). |
|
1690 for attr in node.attributes.values(): |
|
1691 if attr.namespaceURI: |
|
1692 if info.isIdNS(attr.namespaceURI, attr.localName): |
|
1693 self._id_cache[attr.value] = node |
|
1694 if attr.value == id: |
|
1695 result = node |
|
1696 elif not node._magic_id_nodes: |
|
1697 break |
|
1698 elif info.isId(attr.name): |
|
1699 self._id_cache[attr.value] = node |
|
1700 if attr.value == id: |
|
1701 result = node |
|
1702 elif not node._magic_id_nodes: |
|
1703 break |
|
1704 elif attr._is_id: |
|
1705 self._id_cache[attr.value] = node |
|
1706 if attr.value == id: |
|
1707 result = node |
|
1708 elif node._magic_id_nodes == 1: |
|
1709 break |
|
1710 elif node._magic_id_nodes: |
|
1711 for attr in node.attributes.values(): |
|
1712 if attr._is_id: |
|
1713 self._id_cache[attr.value] = node |
|
1714 if attr.value == id: |
|
1715 result = node |
|
1716 if result is not None: |
|
1717 break |
|
1718 return result |
|
1719 |
|
1720 def getElementsByTagName(self, name): |
|
1721 return _get_elements_by_tagName_helper(self, name, NodeList()) |
|
1722 |
|
1723 def getElementsByTagNameNS(self, namespaceURI, localName): |
|
1724 return _get_elements_by_tagName_ns_helper( |
|
1725 self, namespaceURI, localName, NodeList()) |
|
1726 |
|
1727 def isSupported(self, feature, version): |
|
1728 return self.implementation.hasFeature(feature, version) |
|
1729 |
|
1730 def importNode(self, node, deep): |
|
1731 if node.nodeType == Node.DOCUMENT_NODE: |
|
1732 raise xml.dom.NotSupportedErr("cannot import document nodes") |
|
1733 elif node.nodeType == Node.DOCUMENT_TYPE_NODE: |
|
1734 raise xml.dom.NotSupportedErr("cannot import document type nodes") |
|
1735 return _clone_node(node, deep, self) |
|
1736 |
|
1737 def writexml(self, writer, indent="", addindent="", newl="", |
|
1738 encoding = None): |
|
1739 if encoding is None: |
|
1740 writer.write('<?xml version="1.0" ?>'+newl) |
|
1741 else: |
|
1742 writer.write('<?xml version="1.0" encoding="%s"?>%s' % (encoding, newl)) |
|
1743 for node in self.childNodes: |
|
1744 node.writexml(writer, indent, addindent, newl) |
|
1745 |
|
1746 # DOM Level 3 (WD 9 April 2002) |
|
1747 |
|
1748 def renameNode(self, n, namespaceURI, name): |
|
1749 if n.ownerDocument is not self: |
|
1750 raise xml.dom.WrongDocumentErr( |
|
1751 "cannot rename nodes from other documents;\n" |
|
1752 "expected %s,\nfound %s" % (self, n.ownerDocument)) |
|
1753 if n.nodeType not in (Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE): |
|
1754 raise xml.dom.NotSupportedErr( |
|
1755 "renameNode() only applies to element and attribute nodes") |
|
1756 if namespaceURI != EMPTY_NAMESPACE: |
|
1757 if ':' in name: |
|
1758 prefix, localName = name.split(':', 1) |
|
1759 if ( prefix == "xmlns" |
|
1760 and namespaceURI != xml.dom.XMLNS_NAMESPACE): |
|
1761 raise xml.dom.NamespaceErr( |
|
1762 "illegal use of 'xmlns' prefix") |
|
1763 else: |
|
1764 if ( name == "xmlns" |
|
1765 and namespaceURI != xml.dom.XMLNS_NAMESPACE |
|
1766 and n.nodeType == Node.ATTRIBUTE_NODE): |
|
1767 raise xml.dom.NamespaceErr( |
|
1768 "illegal use of the 'xmlns' attribute") |
|
1769 prefix = None |
|
1770 localName = name |
|
1771 else: |
|
1772 prefix = None |
|
1773 localName = None |
|
1774 if n.nodeType == Node.ATTRIBUTE_NODE: |
|
1775 element = n.ownerElement |
|
1776 if element is not None: |
|
1777 is_id = n._is_id |
|
1778 element.removeAttributeNode(n) |
|
1779 else: |
|
1780 element = None |
|
1781 # avoid __setattr__ |
|
1782 d = n.__dict__ |
|
1783 d['prefix'] = prefix |
|
1784 d['localName'] = localName |
|
1785 d['namespaceURI'] = namespaceURI |
|
1786 d['nodeName'] = name |
|
1787 if n.nodeType == Node.ELEMENT_NODE: |
|
1788 d['tagName'] = name |
|
1789 else: |
|
1790 # attribute node |
|
1791 d['name'] = name |
|
1792 if element is not None: |
|
1793 element.setAttributeNode(n) |
|
1794 if is_id: |
|
1795 element.setIdAttributeNode(n) |
|
1796 # It's not clear from a semantic perspective whether we should |
|
1797 # call the user data handlers for the NODE_RENAMED event since |
|
1798 # we're re-using the existing node. The draft spec has been |
|
1799 # interpreted as meaning "no, don't call the handler unless a |
|
1800 # new node is created." |
|
1801 return n |
|
1802 |
|
1803 defproperty(Document, "documentElement", |
|
1804 doc="Top-level element of this document.") |
|
1805 |
|
1806 |
|
1807 def _clone_node(node, deep, newOwnerDocument): |
|
1808 """ |
|
1809 Clone a node and give it the new owner document. |
|
1810 Called by Node.cloneNode and Document.importNode |
|
1811 """ |
|
1812 if node.ownerDocument.isSameNode(newOwnerDocument): |
|
1813 operation = xml.dom.UserDataHandler.NODE_CLONED |
|
1814 else: |
|
1815 operation = xml.dom.UserDataHandler.NODE_IMPORTED |
|
1816 if node.nodeType == Node.ELEMENT_NODE: |
|
1817 clone = newOwnerDocument.createElementNS(node.namespaceURI, |
|
1818 node.nodeName) |
|
1819 for attr in node.attributes.values(): |
|
1820 clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value) |
|
1821 a = clone.getAttributeNodeNS(attr.namespaceURI, attr.localName) |
|
1822 a.specified = attr.specified |
|
1823 |
|
1824 if deep: |
|
1825 for child in node.childNodes: |
|
1826 c = _clone_node(child, deep, newOwnerDocument) |
|
1827 clone.appendChild(c) |
|
1828 |
|
1829 elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE: |
|
1830 clone = newOwnerDocument.createDocumentFragment() |
|
1831 if deep: |
|
1832 for child in node.childNodes: |
|
1833 c = _clone_node(child, deep, newOwnerDocument) |
|
1834 clone.appendChild(c) |
|
1835 |
|
1836 elif node.nodeType == Node.TEXT_NODE: |
|
1837 clone = newOwnerDocument.createTextNode(node.data) |
|
1838 elif node.nodeType == Node.CDATA_SECTION_NODE: |
|
1839 clone = newOwnerDocument.createCDATASection(node.data) |
|
1840 elif node.nodeType == Node.PROCESSING_INSTRUCTION_NODE: |
|
1841 clone = newOwnerDocument.createProcessingInstruction(node.target, |
|
1842 node.data) |
|
1843 elif node.nodeType == Node.COMMENT_NODE: |
|
1844 clone = newOwnerDocument.createComment(node.data) |
|
1845 elif node.nodeType == Node.ATTRIBUTE_NODE: |
|
1846 clone = newOwnerDocument.createAttributeNS(node.namespaceURI, |
|
1847 node.nodeName) |
|
1848 clone.specified = True |
|
1849 clone.value = node.value |
|
1850 elif node.nodeType == Node.DOCUMENT_TYPE_NODE: |
|
1851 assert node.ownerDocument is not newOwnerDocument |
|
1852 operation = xml.dom.UserDataHandler.NODE_IMPORTED |
|
1853 clone = newOwnerDocument.implementation.createDocumentType( |
|
1854 node.name, node.publicId, node.systemId) |
|
1855 clone.ownerDocument = newOwnerDocument |
|
1856 if deep: |
|
1857 clone.entities._seq = [] |
|
1858 clone.notations._seq = [] |
|
1859 for n in node.notations._seq: |
|
1860 notation = Notation(n.nodeName, n.publicId, n.systemId) |
|
1861 notation.ownerDocument = newOwnerDocument |
|
1862 clone.notations._seq.append(notation) |
|
1863 if hasattr(n, '_call_user_data_handler'): |
|
1864 n._call_user_data_handler(operation, n, notation) |
|
1865 for e in node.entities._seq: |
|
1866 entity = Entity(e.nodeName, e.publicId, e.systemId, |
|
1867 e.notationName) |
|
1868 entity.actualEncoding = e.actualEncoding |
|
1869 entity.encoding = e.encoding |
|
1870 entity.version = e.version |
|
1871 entity.ownerDocument = newOwnerDocument |
|
1872 clone.entities._seq.append(entity) |
|
1873 if hasattr(e, '_call_user_data_handler'): |
|
1874 e._call_user_data_handler(operation, n, entity) |
|
1875 else: |
|
1876 # Note the cloning of Document and DocumentType nodes is |
|
1877 # implemenetation specific. minidom handles those cases |
|
1878 # directly in the cloneNode() methods. |
|
1879 raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node)) |
|
1880 |
|
1881 # Check for _call_user_data_handler() since this could conceivably |
|
1882 # used with other DOM implementations (one of the FourThought |
|
1883 # DOMs, perhaps?). |
|
1884 if hasattr(node, '_call_user_data_handler'): |
|
1885 node._call_user_data_handler(operation, node, clone) |
|
1886 return clone |
|
1887 |
|
1888 |
|
1889 def _nssplit(qualifiedName): |
|
1890 fields = qualifiedName.split(':', 1) |
|
1891 if len(fields) == 2: |
|
1892 return fields |
|
1893 else: |
|
1894 return (None, fields[0]) |
|
1895 |
|
1896 |
|
1897 def _get_StringIO(): |
|
1898 # we can't use cStringIO since it doesn't support Unicode strings |
|
1899 from StringIO import StringIO |
|
1900 return StringIO() |
|
1901 |
|
1902 def _do_pulldom_parse(func, args, kwargs): |
|
1903 events = func(*args, **kwargs) |
|
1904 toktype, rootNode = events.getEvent() |
|
1905 events.expandNode(rootNode) |
|
1906 events.clear() |
|
1907 return rootNode |
|
1908 |
|
1909 def parse(file, parser=None, bufsize=None): |
|
1910 """Parse a file into a DOM by filename or file object.""" |
|
1911 if parser is None and not bufsize: |
|
1912 from xml.dom import expatbuilder |
|
1913 return expatbuilder.parse(file) |
|
1914 else: |
|
1915 from xml.dom import pulldom |
|
1916 return _do_pulldom_parse(pulldom.parse, (file,), |
|
1917 {'parser': parser, 'bufsize': bufsize}) |
|
1918 |
|
1919 def parseString(string, parser=None): |
|
1920 """Parse a file into a DOM from a string.""" |
|
1921 if parser is None: |
|
1922 from xml.dom import expatbuilder |
|
1923 return expatbuilder.parseString(string) |
|
1924 else: |
|
1925 from xml.dom import pulldom |
|
1926 return _do_pulldom_parse(pulldom.parseString, (string,), |
|
1927 {'parser': parser}) |
|
1928 |
|
1929 def getDOMImplementation(features=None): |
|
1930 if features: |
|
1931 if isinstance(features, StringTypes): |
|
1932 features = domreg._parse_feature_string(features) |
|
1933 for f, v in features: |
|
1934 if not Document.implementation.hasFeature(f, v): |
|
1935 return None |
|
1936 return Document.implementation |