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