home *** CD-ROM | disk | FTP | other *** search
/ PC Extra 07 & 08 / pca1507.iso / Software / psp8 / Data1.cab / minidom.py < prev    next >
Encoding:
Python Source  |  2003-04-22  |  32.3 KB  |  969 lines

  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 string
  18. _string = string
  19. del string
  20.  
  21. from xml.dom import HierarchyRequestErr, EMPTY_NAMESPACE
  22.  
  23. # localize the types, and allow support for Unicode values if available:
  24. import types
  25. _TupleType = types.TupleType
  26. try:
  27.     _StringTypes = (types.StringType, types.UnicodeType)
  28. except AttributeError:
  29.     _StringTypes = (types.StringType,)
  30. del types
  31.  
  32. import xml.dom
  33.  
  34.  
  35. if list is type([]):
  36.     class NodeList(list):
  37.         def item(self, index):
  38.             if 0 <= index < len(self):
  39.                 return self[index]
  40.  
  41.         length = property(lambda self: len(self),
  42.                           doc="The number of nodes in the NodeList.")
  43.  
  44. else:
  45.     def NodeList():
  46.         return []
  47.     
  48.  
  49. class Node(xml.dom.Node):
  50.     allnodes = {}
  51.     _debug = 0
  52.     _makeParentNodes = 1
  53.     debug = None
  54.     childNodeTypes = ()
  55.     namespaceURI = None # this is non-null only for elements and attributes
  56.     parentNode = None
  57.     ownerDocument = None
  58.  
  59.     def __init__(self):
  60.         self.childNodes = NodeList()
  61.         if Node._debug:
  62.             index = repr(id(self)) + repr(self.__class__)
  63.             Node.allnodes[index] = repr(self.__dict__)
  64.             if Node.debug is None:
  65.                 Node.debug = _get_StringIO()
  66.                 #open("debug4.out", "w")
  67.             Node.debug.write("create %s\n" % index)
  68.  
  69.     def __nonzero__(self):
  70.         return 1
  71.  
  72.     def toxml(self):
  73.         writer = _get_StringIO()
  74.         self.writexml(writer)
  75.         return writer.getvalue()
  76.  
  77.     def toprettyxml(self, indent="\t", newl="\n"):
  78.         # indent = the indentation string to prepend, per level
  79.         # newl = the newline string to append
  80.         writer = _get_StringIO()
  81.         self.writexml(writer, "", indent, newl)
  82.         return writer.getvalue()
  83.  
  84.     def hasChildNodes(self):
  85.         if self.childNodes:
  86.             return 1
  87.         else:
  88.             return 0
  89.  
  90.     def _get_firstChild(self):
  91.         if self.childNodes:
  92.             return self.childNodes[0]
  93.  
  94.     def _get_lastChild(self):
  95.         if self.childNodes:
  96.             return self.childNodes[-1]
  97.  
  98.     try:
  99.         property
  100.     except NameError:
  101.         def __getattr__(self, key):
  102.             if key[0:2] == "__":
  103.                 raise AttributeError, key
  104.             # getattr should never call getattr!
  105.             if self.__dict__.has_key("inGetAttr"):
  106.                 del self.inGetAttr
  107.                 raise AttributeError, key
  108.  
  109.             prefix, attrname = key[:5], key[5:]
  110.             if prefix == "_get_":
  111.                 self.inGetAttr = 1
  112.                 if hasattr(self, attrname):
  113.                     del self.inGetAttr
  114.                     return (lambda self=self, attrname=attrname:
  115.                                     getattr(self, attrname))
  116.                 else:
  117.                     del self.inGetAttr
  118.                     raise AttributeError, key
  119.             else:
  120.                 self.inGetAttr = 1
  121.                 try:
  122.                     func = getattr(self, "_get_" + key)
  123.                 except AttributeError:
  124.                     raise AttributeError, key
  125.                 del self.inGetAttr
  126.                 return func()
  127.     else:
  128.         firstChild = property(_get_firstChild,
  129.                               doc="First child node, or None.")
  130.         lastChild = property(_get_lastChild,
  131.                              doc="Last child node, or None.")
  132.  
  133.     def insertBefore(self, newChild, refChild):
  134.         if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
  135.             for c in tuple(newChild.childNodes):
  136.                 self.insertBefore(c, refChild)
  137.             ### The DOM does not clearly specify what to return in this case
  138.             return newChild
  139.         if newChild.nodeType not in self.childNodeTypes:
  140.             raise HierarchyRequestErr, \
  141.                   "%s cannot be child of %s" % (repr(newChild), repr(self))
  142.         if newChild.parentNode is not None:
  143.             newChild.parentNode.removeChild(newChild)
  144.         if refChild is None:
  145.             self.appendChild(newChild)
  146.         else:
  147.             index = self.childNodes.index(refChild)
  148.             self.childNodes.insert(index, newChild)
  149.             newChild.nextSibling = refChild
  150.             refChild.previousSibling = newChild
  151.             if index:
  152.                 node = self.childNodes[index-1]
  153.                 node.nextSibling = newChild
  154.                 newChild.previousSibling = node
  155.             else:
  156.                 newChild.previousSibling = None
  157.             if self._makeParentNodes:
  158.                 newChild.parentNode = self
  159.         return newChild
  160.  
  161.     def appendChild(self, node):
  162.         if node.nodeType == self.DOCUMENT_FRAGMENT_NODE:
  163.             for c in tuple(node.childNodes):
  164.                 self.appendChild(c)
  165.             ### The DOM does not clearly specify what to return in this case
  166.             return node
  167.         if node.nodeType not in self.childNodeTypes:
  168.             raise HierarchyRequestErr, \
  169.                   "%s cannot be child of %s" % (repr(node), repr(self))
  170.         if node.parentNode is not None:
  171.             node.parentNode.removeChild(node)
  172.         if self.childNodes:
  173.             last = self.lastChild
  174.             node.previousSibling = last
  175.             last.nextSibling = node
  176.         else:
  177.             node.previousSibling = None
  178.         node.nextSibling = None
  179.         self.childNodes.append(node)
  180.         if self._makeParentNodes:
  181.             node.parentNode = self
  182.         return node
  183.  
  184.     def replaceChild(self, newChild, oldChild):
  185.         if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
  186.             refChild = oldChild.nextSibling
  187.             self.removeChild(oldChild)
  188.             return self.insertBefore(newChild, refChild)
  189.         if newChild.nodeType not in self.childNodeTypes:
  190.             raise HierarchyRequestErr, \
  191.                   "%s cannot be child of %s" % (repr(newChild), repr(self))
  192.         if newChild.parentNode is not None:
  193.             newChild.parentNode.removeChild(newChild)
  194.         if newChild is oldChild:
  195.             return
  196.         index = self.childNodes.index(oldChild)
  197.         self.childNodes[index] = newChild
  198.         if self._makeParentNodes:
  199.             newChild.parentNode = self
  200.             oldChild.parentNode = None
  201.         newChild.nextSibling = oldChild.nextSibling
  202.         newChild.previousSibling = oldChild.previousSibling
  203.         oldChild.nextSibling = None
  204.         oldChild.previousSibling = None
  205.         if newChild.previousSibling:
  206.             newChild.previousSibling.nextSibling = newChild
  207.         if newChild.nextSibling:
  208.             newChild.nextSibling.previousSibling = newChild
  209.         return oldChild
  210.  
  211.     def removeChild(self, oldChild):
  212.         self.childNodes.remove(oldChild)
  213.         if oldChild.nextSibling is not None:
  214.             oldChild.nextSibling.previousSibling = oldChild.previousSibling
  215.         if oldChild.previousSibling is not None:
  216.             oldChild.previousSibling.nextSibling = oldChild.nextSibling
  217.         oldChild.nextSibling = oldChild.previousSibling = None
  218.  
  219.         if self._makeParentNodes:
  220.             oldChild.parentNode = None
  221.         return oldChild
  222.  
  223.     def normalize(self):
  224.         L = []
  225.         for child in self.childNodes:
  226.             if child.nodeType == Node.TEXT_NODE:
  227.                 data = child.data
  228.                 if data and L and L[-1].nodeType == child.nodeType:
  229.                     # collapse text node
  230.                     node = L[-1]
  231.                     node.data = node.nodeValue = node.data + child.data
  232.                     node.nextSibling = child.nextSibling
  233.                     child.unlink()
  234.                 elif data:
  235.                     if L:
  236.                         L[-1].nextSibling = child
  237.                         child.previousSibling = L[-1]
  238.                     else:
  239.                         child.previousSibling = None
  240.                     L.append(child)
  241.                 else:
  242.                     # empty text node; discard
  243.                     child.unlink()
  244.             else:
  245.                 if L:
  246.                     L[-1].nextSibling = child
  247.                     child.previousSibling = L[-1]
  248.                 else:
  249.                     child.previousSibling = None
  250.                 L.append(child)
  251.                 if child.nodeType == Node.ELEMENT_NODE:
  252.                     child.normalize()
  253.         self.childNodes[:] = L
  254.  
  255.     def cloneNode(self, deep):
  256.         import new
  257.         clone = new.instance(self.__class__, self.__dict__.copy())
  258.         if self._makeParentNodes:
  259.             clone.parentNode = None
  260.         clone.childNodes = NodeList()
  261.         if deep:
  262.             for child in self.childNodes:
  263.                 clone.appendChild(child.cloneNode(1))
  264.         return clone
  265.  
  266.     # DOM Level 3 (Working Draft 2001-Jan-26)
  267.  
  268.     def isSameNode(self, other):
  269.         return self is other
  270.  
  271.     # minidom-specific API:
  272.  
  273.     def unlink(self):
  274.         self.parentNode = self.ownerDocument = None
  275.         for child in self.childNodes:
  276.             child.unlink()
  277.         self.childNodes = None
  278.         self.previousSibling = None
  279.         self.nextSibling = None
  280.         if Node._debug:
  281.             index = repr(id(self)) + repr(self.__class__)
  282.             self.debug.write("Deleting: %s\n" % index)
  283.             del Node.allnodes[index]
  284.  
  285. def _write_data(writer, data):
  286.     "Writes datachars to writer."
  287.     replace = _string.replace
  288.     data = replace(data, "&", "&")
  289.     data = replace(data, "<", "<")
  290.     data = replace(data, "\"", """)
  291.     data = replace(data, ">", ">")
  292.     writer.write(data)
  293.  
  294. def _getElementsByTagNameHelper(parent, name, rc):
  295.     for node in parent.childNodes:
  296.         if node.nodeType == Node.ELEMENT_NODE and \
  297.             (name == "*" or node.tagName == name):
  298.             rc.append(node)
  299.         _getElementsByTagNameHelper(node, name, rc)
  300.     return rc
  301.  
  302. def _getElementsByTagNameNSHelper(parent, nsURI, localName, rc):
  303.     for node in parent.childNodes:
  304.         if node.nodeType == Node.ELEMENT_NODE:
  305.             if ((localName == "*" or node.localName == localName) and
  306.                 (nsURI == "*" or node.namespaceURI == nsURI)):
  307.                 rc.append(node)
  308.             _getElementsByTagNameNSHelper(node, nsURI, localName, rc)
  309.     return rc
  310.  
  311. class DocumentFragment(Node):
  312.     nodeType = Node.DOCUMENT_FRAGMENT_NODE
  313.     nodeName = "#document-fragment"
  314.     nodeValue = None
  315.     attributes = None
  316.     parentNode = None
  317.     childNodeTypes = (Node.ELEMENT_NODE,
  318.                       Node.TEXT_NODE,
  319.                       Node.CDATA_SECTION_NODE,
  320.                       Node.ENTITY_REFERENCE_NODE,
  321.                       Node.PROCESSING_INSTRUCTION_NODE,
  322.                       Node.COMMENT_NODE,
  323.                       Node.NOTATION_NODE)
  324.  
  325.  
  326. class Attr(Node):
  327.     nodeType = Node.ATTRIBUTE_NODE
  328.     attributes = None
  329.     ownerElement = None
  330.     childNodeTypes = (Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE)
  331.  
  332.     def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None, prefix=None):
  333.         # skip setattr for performance
  334.         d = self.__dict__
  335.         d["localName"] = localName or qName
  336.         d["nodeName"] = d["name"] = qName
  337.         d["namespaceURI"] = namespaceURI
  338.         d["prefix"] = prefix
  339.         Node.__init__(self)
  340.         # nodeValue and value are set elsewhere
  341.  
  342.     def __setattr__(self, name, value):
  343.         d = self.__dict__
  344.         if name in ("value", "nodeValue"):
  345.             d["value"] = d["nodeValue"] = value
  346.         elif name in ("name", "nodeName"):
  347.             d["name"] = d["nodeName"] = value
  348.         else:
  349.             d[name] = value
  350.  
  351.     def cloneNode(self, deep):
  352.         clone = Node.cloneNode(self, deep)
  353.         if clone.__dict__.has_key("ownerElement"):
  354.             del clone.ownerElement
  355.         return clone
  356.  
  357.  
  358. class NamedNodeMap:
  359.     """The attribute list is a transient interface to the underlying
  360.     dictionaries.  Mutations here will change the underlying element's
  361.     dictionary.
  362.  
  363.     Ordering is imposed artificially and does not reflect the order of
  364.     attributes as found in an input document.
  365.     """
  366.  
  367.     def __init__(self, attrs, attrsNS, ownerElement):
  368.         self._attrs = attrs
  369.         self._attrsNS = attrsNS
  370.         self._ownerElement = ownerElement
  371.  
  372.     try:
  373.         property
  374.     except NameError:
  375.         def __getattr__(self, name):
  376.             if name == "length":
  377.                 return len(self._attrs)
  378.             raise AttributeError, name
  379.     else:
  380.         length = property(lambda self: len(self._attrs),
  381.                           doc="Number of nodes in the NamedNodeMap.")
  382.  
  383.     def item(self, index):
  384.         try:
  385.             return self[self._attrs.keys()[index]]
  386.         except IndexError:
  387.             return None
  388.  
  389.     def items(self):
  390.         L = []
  391.         for node in self._attrs.values():
  392.             L.append((node.nodeName, node.value))
  393.         return L
  394.  
  395.     def itemsNS(self):
  396.         L = []
  397.         for node in self._attrs.values():
  398.             L.append(((node.namespaceURI, node.localName), node.value))
  399.         return L
  400.  
  401.     def keys(self):
  402.         return self._attrs.keys()
  403.  
  404.     def keysNS(self):
  405.         return self._attrsNS.keys()
  406.  
  407.     def values(self):
  408.         return self._attrs.values()
  409.  
  410.     def get(self, name, value = None):
  411.         return self._attrs.get(name, value)
  412.  
  413.     def __len__(self):
  414.         return self.length
  415.  
  416.     def __cmp__(self, other):
  417.         if self._attrs is getattr(other, "_attrs", None):
  418.             return 0
  419.         else:
  420.             return cmp(id(self), id(other))
  421.  
  422.     #FIXME: is it appropriate to return .value?
  423.     def __getitem__(self, attname_or_tuple):
  424.         if type(attname_or_tuple) is _TupleType:
  425.             return self._attrsNS[attname_or_tuple]
  426.         else:
  427.             return self._attrs[attname_or_tuple]
  428.  
  429.     # same as set
  430.     def __setitem__(self, attname, value):
  431.         if type(value) in _StringTypes:
  432.             node = Attr(attname)
  433.             node.value = value
  434.             node.ownerDocument = self._ownerElement.ownerDocument
  435.         else:
  436.             if not isinstance(value, Attr):
  437.                 raise TypeError, "value must be a string or Attr object"
  438.             node = value
  439.         self.setNamedItem(node)
  440.  
  441.     def setNamedItem(self, node):
  442.         if not isinstance(node, Attr):
  443.             raise HierarchyRequestErr, \
  444.                   "%s cannot be child of %s" % (repr(node), repr(self))
  445.         old = self._attrs.get(node.name)
  446.         if old:
  447.             old.unlink()
  448.         self._attrs[node.name] = node
  449.         self._attrsNS[(node.namespaceURI, node.localName)] = node
  450.         node.ownerElement = self._ownerElement
  451.         return old
  452.  
  453.     def setNamedItemNS(self, node):
  454.         return self.setNamedItem(node)
  455.  
  456.     def __delitem__(self, attname_or_tuple):
  457.         node = self[attname_or_tuple]
  458.         node.unlink()
  459.         del self._attrs[node.name]
  460.         del self._attrsNS[(node.namespaceURI, node.localName)]
  461.         self.length = len(self._attrs)
  462.  
  463. AttributeList = NamedNodeMap
  464.  
  465.  
  466. class Element(Node):
  467.     nodeType = Node.ELEMENT_NODE
  468.     nextSibling = None
  469.     previousSibling = None
  470.     childNodeTypes = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
  471.                       Node.COMMENT_NODE, Node.TEXT_NODE,
  472.                       Node.CDATA_SECTION_NODE, Node.ENTITY_REFERENCE_NODE)
  473.  
  474.     def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None,
  475.                  localName=None):
  476.         Node.__init__(self)
  477.         self.tagName = self.nodeName = tagName
  478.         self.localName = localName or tagName
  479.         self.prefix = prefix
  480.         self.namespaceURI = namespaceURI
  481.         self.nodeValue = None
  482.  
  483.         self._attrs = {}   # attributes are double-indexed:
  484.         self._attrsNS = {} #    tagName -> Attribute
  485.                            #    URI,localName -> Attribute
  486.                            # in the future: consider lazy generation
  487.                            # of attribute objects this is too tricky
  488.                            # for now because of headaches with
  489.                            # namespaces.
  490.  
  491.     def cloneNode(self, deep):
  492.         clone = Node.cloneNode(self, deep)
  493.         clone._attrs = {}
  494.         clone._attrsNS = {}
  495.         for attr in self._attrs.values():
  496.             node = attr.cloneNode(1)
  497.             clone._attrs[node.name] = node
  498.             clone._attrsNS[(node.namespaceURI, node.localName)] = node
  499.             node.ownerElement = clone
  500.         return clone
  501.  
  502.     def unlink(self):
  503.         for attr in self._attrs.values():
  504.             attr.unlink()
  505.         self._attrs = None
  506.         self._attrsNS = None
  507.         Node.unlink(self)
  508.  
  509.     def getAttribute(self, attname):
  510.         try:
  511.             return self._attrs[attname].value
  512.         except KeyError:
  513.             return ""
  514.  
  515.     def getAttributeNS(self, namespaceURI, localName):
  516.         try:
  517.             return self._attrsNS[(namespaceURI, localName)].value
  518.         except KeyError:
  519.             return ""
  520.  
  521.     def setAttribute(self, attname, value):
  522.         attr = Attr(attname)
  523.         # for performance
  524.         d = attr.__dict__
  525.         d["value"] = d["nodeValue"] = value
  526.         d["ownerDocument"] = self.ownerDocument
  527.         self.setAttributeNode(attr)
  528.  
  529.     def setAttributeNS(self, namespaceURI, qualifiedName, value):
  530.         prefix, localname = _nssplit(qualifiedName)
  531.         # for performance
  532.         attr = Attr(qualifiedName, namespaceURI, localname, prefix)
  533.         d = attr.__dict__
  534.         d["value"] = d["nodeValue"] = value
  535.         d["ownerDocument"] = self.ownerDocument
  536.         self.setAttributeNode(attr)
  537.  
  538.     def getAttributeNode(self, attrname):
  539.         return self._attrs.get(attrname)
  540.  
  541.     def getAttributeNodeNS(self, namespaceURI, localName):
  542.         return self._attrsNS.get((namespaceURI, localName))
  543.  
  544.     def setAttributeNode(self, attr):
  545.         if attr.ownerElement not in (None, self):
  546.             raise xml.dom.InuseAttributeErr("attribute node already owned")
  547.         old = self._attrs.get(attr.name, None)
  548.         if old:
  549.             old.unlink()
  550.         self._attrs[attr.name] = attr
  551.         self._attrsNS[(attr.namespaceURI, attr.localName)] = attr
  552.  
  553.         # This creates a circular reference, but Element.unlink()
  554.         # breaks the cycle since the references to the attribute
  555.         # dictionaries are tossed.
  556.         attr.ownerElement = self
  557.  
  558.         if old is not attr:
  559.             # It might have already been part of this node, in which case
  560.             # it doesn't represent a change, and should not be returned.
  561.             return old
  562.  
  563.     setAttributeNodeNS = setAttributeNode
  564.  
  565.     def removeAttribute(self, name):
  566.         attr = self._attrs[name]
  567.         self.removeAttributeNode(attr)
  568.  
  569.     def removeAttributeNS(self, namespaceURI, localName):
  570.         attr = self._attrsNS[(namespaceURI, localName)]
  571.         self.removeAttributeNode(attr)
  572.  
  573.     def removeAttributeNode(self, node):
  574.         node.unlink()
  575.         del self._attrs[node.name]
  576.         del self._attrsNS[(node.namespaceURI, node.localName)]
  577.  
  578.     removeAttributeNodeNS = removeAttributeNode
  579.  
  580.     def hasAttribute(self, name):
  581.         return self._attrs.has_key(name)
  582.  
  583.     def hasAttributeNS(self, namespaceURI, localName):
  584.         return self._attrsNS.has_key((namespaceURI, localName))
  585.  
  586.     def getElementsByTagName(self, name):
  587.         return _getElementsByTagNameHelper(self, name, [])
  588.  
  589.     def getElementsByTagNameNS(self, namespaceURI, localName):
  590.         return _getElementsByTagNameNSHelper(self, namespaceURI, localName, [])
  591.  
  592.     def __repr__(self):
  593.         return "<DOM Element: %s at %s>" % (self.tagName, id(self))
  594.  
  595.     def writexml(self, writer, indent="", addindent="", newl=""):
  596.         # indent = current indentation
  597.         # addindent = indentation to add to higher levels
  598.         # newl = newline string
  599.         writer.write(indent+"<" + self.tagName)
  600.  
  601.         attrs = self._get_attributes()
  602.         a_names = attrs.keys()
  603.         a_names.sort()
  604.  
  605.         for a_name in a_names:
  606.             writer.write(" %s=\"" % a_name)
  607.             _write_data(writer, attrs[a_name].value)
  608.             writer.write("\"")
  609.         if self.childNodes:
  610.             writer.write(">%s"%(newl))
  611.             for node in self.childNodes:
  612.                 node.writexml(writer,indent+addindent,addindent,newl)
  613.             writer.write("%s</%s>%s" % (indent,self.tagName,newl))
  614.         else:
  615.             writer.write("/>%s"%(newl))
  616.  
  617.     def _get_attributes(self):
  618.         return NamedNodeMap(self._attrs, self._attrsNS, self)
  619.  
  620.     try:
  621.         property
  622.     except NameError:
  623.         pass
  624.     else:
  625.         attributes = property(_get_attributes,
  626.                               doc="NamedNodeMap of attributes on the element.")
  627.  
  628.     def hasAttributes(self):
  629.         if self._attrs or self._attrsNS:
  630.             return 1
  631.         else:
  632.             return 0
  633.  
  634. class Comment(Node):
  635.     nodeType = Node.COMMENT_NODE
  636.     nodeName = "#comment"
  637.     attributes = None
  638.     childNodeTypes = ()
  639.  
  640.     def __init__(self, data):
  641.         Node.__init__(self)
  642.         self.data = self.nodeValue = data
  643.  
  644.     def writexml(self, writer, indent="", addindent="", newl=""):
  645.         writer.write("%s<!--%s-->%s" % (indent,self.data,newl))
  646.  
  647. class ProcessingInstruction(Node):
  648.     nodeType = Node.PROCESSING_INSTRUCTION_NODE
  649.     attributes = None
  650.     childNodeTypes = ()
  651.  
  652.     def __init__(self, target, data):
  653.         Node.__init__(self)
  654.         self.target = self.nodeName = target
  655.         self.data = self.nodeValue = data
  656.  
  657.     def writexml(self, writer, indent="", addindent="", newl=""):
  658.         writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))
  659.  
  660. class CharacterData(Node):
  661.     def __init__(self, data):
  662.         if type(data) not in _StringTypes:
  663.             raise TypeError, "node contents must be a string"
  664.         Node.__init__(self)
  665.         self.data = self.nodeValue = data
  666.         self.length = len(data)
  667.  
  668.     def __repr__(self):
  669.         if len(self.data) > 10:
  670.             dotdotdot = "..."
  671.         else:
  672.             dotdotdot = ""
  673.         return "<DOM %s node \"%s%s\">" % (
  674.             self.__class__.__name__, self.data[0:10], dotdotdot)
  675.  
  676.     def substringData(self, offset, count):
  677.         if offset < 0:
  678.             raise xml.dom.IndexSizeErr("offset cannot be negative")
  679.         if offset >= len(self.data):
  680.             raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
  681.         if count < 0:
  682.             raise xml.dom.IndexSizeErr("count cannot be negative")
  683.         return self.data[offset:offset+count]
  684.  
  685.     def appendData(self, arg):
  686.         self.data = self.data + arg
  687.         self.nodeValue = self.data
  688.         self.length = len(self.data)
  689.  
  690.     def insertData(self, offset, arg):
  691.         if offset < 0:
  692.             raise xml.dom.IndexSizeErr("offset cannot be negative")
  693.         if offset >= len(self.data):
  694.             raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
  695.         if arg:
  696.             self.data = "%s%s%s" % (
  697.                 self.data[:offset], arg, self.data[offset:])
  698.             self.nodeValue = self.data
  699.             self.length = len(self.data)
  700.  
  701.     def deleteData(self, offset, count):
  702.         if offset < 0:
  703.             raise xml.dom.IndexSizeErr("offset cannot be negative")
  704.         if offset >= len(self.data):
  705.             raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
  706.         if count < 0:
  707.             raise xml.dom.IndexSizeErr("count cannot be negative")
  708.         if count:
  709.             self.data = self.data[:offset] + self.data[offset+count:]
  710.             self.nodeValue = self.data
  711.             self.length = len(self.data)
  712.  
  713.     def replaceData(self, offset, count, arg):
  714.         if offset < 0:
  715.             raise xml.dom.IndexSizeErr("offset cannot be negative")
  716.         if offset >= len(self.data):
  717.             raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
  718.         if count < 0:
  719.             raise xml.dom.IndexSizeErr("count cannot be negative")
  720.         if count:
  721.             self.data = "%s%s%s" % (
  722.                 self.data[:offset], arg, self.data[offset+count:])
  723.             self.nodeValue = self.data
  724.             self.length = len(self.data)
  725.  
  726. class Text(CharacterData):
  727.     nodeType = Node.TEXT_NODE
  728.     nodeName = "#text"
  729.     attributes = None
  730.     childNodeTypes = ()
  731.  
  732.     def splitText(self, offset):
  733.         if offset < 0 or offset > len(self.data):
  734.             raise xml.dom.IndexSizeErr("illegal offset value")
  735.         newText = Text(self.data[offset:])
  736.         next = self.nextSibling
  737.         if self.parentNode and self in self.parentNode.childNodes:
  738.             if next is None:
  739.                 self.parentNode.appendChild(newText)
  740.             else:
  741.                 self.parentNode.insertBefore(newText, next)
  742.         self.data = self.data[:offset]
  743.         self.nodeValue = self.data
  744.         self.length = len(self.data)
  745.         return newText
  746.  
  747.     def writexml(self, writer, indent="", addindent="", newl=""):
  748.         _write_data(writer, "%s%s%s"%(indent, self.data, newl))
  749.  
  750.  
  751. class CDATASection(Text):
  752.     nodeType = Node.CDATA_SECTION_NODE
  753.     nodeName = "#cdata-section"
  754.  
  755.     def writexml(self, writer, indent="", addindent="", newl=""):
  756.         writer.write("<![CDATA[%s]]>" % self.data)
  757.  
  758.  
  759. def _nssplit(qualifiedName):
  760.     fields = _string.split(qualifiedName, ':', 1)
  761.     if len(fields) == 2:
  762.         return fields
  763.     elif len(fields) == 1:
  764.         return (None, fields[0])
  765.  
  766.  
  767. class DocumentType(Node):
  768.     nodeType = Node.DOCUMENT_TYPE_NODE
  769.     nodeValue = None
  770.     attributes = None
  771.     name = None
  772.     publicId = None
  773.     systemId = None
  774.     internalSubset = None
  775.     entities = None
  776.     notations = None
  777.  
  778.     def __init__(self, qualifiedName):
  779.         Node.__init__(self)
  780.         if qualifiedName:
  781.             prefix, localname = _nssplit(qualifiedName)
  782.             self.name = localname
  783.  
  784.  
  785. class DOMImplementation:
  786.     def hasFeature(self, feature, version):
  787.         if version not in ("1.0", "2.0"):
  788.             return 0
  789.         feature = _string.lower(feature)
  790.         return feature == "core"
  791.  
  792.     def createDocument(self, namespaceURI, qualifiedName, doctype):
  793.         if doctype and doctype.parentNode is not None:
  794.             raise xml.dom.WrongDocumentErr(
  795.                 "doctype object owned by another DOM tree")
  796.         doc = self._createDocument()
  797.         if doctype is None:
  798.             doctype = self.createDocumentType(qualifiedName, None, None)
  799.         if not qualifiedName:
  800.             # The spec is unclear what to raise here; SyntaxErr
  801.             # would be the other obvious candidate. Since Xerces raises
  802.             # InvalidCharacterErr, and since SyntaxErr is not listed
  803.             # for createDocument, that seems to be the better choice.
  804.             # XXX: need to check for illegal characters here and in
  805.             # createElement.
  806.             raise xml.dom.InvalidCharacterErr("Element with no name")
  807.         prefix, localname = _nssplit(qualifiedName)
  808.         if prefix == "xml" \
  809.            and namespaceURI != "http://www.w3.org/XML/1998/namespace":
  810.             raise xml.dom.NamespaceErr("illegal use of 'xml' prefix")
  811.         if prefix and not namespaceURI:
  812.             raise xml.dom.NamespaceErr(
  813.                 "illegal use of prefix without namespaces")
  814.         element = doc.createElementNS(namespaceURI, qualifiedName)
  815.         doc.appendChild(element)
  816.         doctype.parentNode = doctype.ownerDocument = doc
  817.         doc.doctype = doctype
  818.         doc.implementation = self
  819.         return doc
  820.  
  821.     def createDocumentType(self, qualifiedName, publicId, systemId):
  822.         doctype = DocumentType(qualifiedName)
  823.         doctype.publicId = publicId
  824.         doctype.systemId = systemId
  825.         return doctype
  826.  
  827.     # internal
  828.     def _createDocument(self):
  829.         return Document()
  830.  
  831. class Document(Node):
  832.     nodeType = Node.DOCUMENT_NODE
  833.     nodeName = "#document"
  834.     nodeValue = None
  835.     attributes = None
  836.     doctype = None
  837.     parentNode = None
  838.     previousSibling = nextSibling = None
  839.  
  840.     implementation = DOMImplementation()
  841.     childNodeTypes = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
  842.                       Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)
  843.  
  844.     def appendChild(self, node):
  845.         if node.nodeType not in self.childNodeTypes:
  846.             raise HierarchyRequestErr, \
  847.                   "%s cannot be child of %s" % (repr(node), repr(self))
  848.         if node.parentNode is not None:
  849.             node.parentNode.removeChild(node)
  850.  
  851.         if node.nodeType == Node.ELEMENT_NODE \
  852.            and self._get_documentElement():
  853.             raise xml.dom.HierarchyRequestErr(
  854.                 "two document elements disallowed")
  855.         return Node.appendChild(self, node)
  856.  
  857.     def removeChild(self, oldChild):
  858.         self.childNodes.remove(oldChild)
  859.         oldChild.nextSibling = oldChild.previousSibling = None
  860.         oldChild.parentNode = None
  861.         if self.documentElement is oldChild:
  862.             self.documentElement = None
  863.  
  864.         return oldChild
  865.  
  866.     def _get_documentElement(self):
  867.         for node in self.childNodes:
  868.             if node.nodeType == Node.ELEMENT_NODE:
  869.                 return node
  870.  
  871.     try:
  872.         property
  873.     except NameError:
  874.         pass
  875.     else:
  876.         documentElement = property(_get_documentElement,
  877.                                    doc="Top-level element of this document.")
  878.  
  879.     def unlink(self):
  880.         if self.doctype is not None:
  881.             self.doctype.unlink()
  882.             self.doctype = None
  883.         Node.unlink(self)
  884.  
  885.     def createDocumentFragment(self):
  886.         d = DocumentFragment()
  887.         d.ownerDoc = self
  888.         return d
  889.  
  890.     def createElement(self, tagName):
  891.         e = Element(tagName)
  892.         e.ownerDocument = self
  893.         return e
  894.  
  895.     def createTextNode(self, data):
  896.         t = Text(data)
  897.         t.ownerDocument = self
  898.         return t
  899.  
  900.     def createCDATASection(self, data):
  901.         c = CDATASection(data)
  902.         c.ownerDocument = self
  903.         return c
  904.  
  905.     def createComment(self, data):
  906.         c = Comment(data)
  907.         c.ownerDocument = self
  908.         return c
  909.  
  910.     def createProcessingInstruction(self, target, data):
  911.         p = ProcessingInstruction(target, data)
  912.         p.ownerDocument = self
  913.         return p
  914.  
  915.     def createAttribute(self, qName):
  916.         a = Attr(qName)
  917.         a.ownerDocument = self
  918.         a.value = ""
  919.         return a
  920.  
  921.     def createElementNS(self, namespaceURI, qualifiedName):
  922.         prefix, localName = _nssplit(qualifiedName)
  923.         e = Element(qualifiedName, namespaceURI, prefix, localName)
  924.         e.ownerDocument = self
  925.         return e
  926.  
  927.     def createAttributeNS(self, namespaceURI, qualifiedName):
  928.         prefix, localName = _nssplit(qualifiedName)
  929.         a = Attr(qualifiedName, namespaceURI, localName, prefix)
  930.         a.ownerDocument = self
  931.         a.value = ""
  932.         return a
  933.  
  934.     def getElementsByTagName(self, name):
  935.         return _getElementsByTagNameHelper(self, name, [])
  936.  
  937.     def getElementsByTagNameNS(self, namespaceURI, localName):
  938.         return _getElementsByTagNameNSHelper(self, namespaceURI, localName, [])
  939.  
  940.     def writexml(self, writer, indent="", addindent="", newl=""):
  941.         writer.write('<?xml version="1.0" ?>\n')
  942.         for node in self.childNodes:
  943.             node.writexml(writer, indent, addindent, newl)
  944.  
  945. def _get_StringIO():
  946.     # we can't use cStringIO since it doesn't support Unicode strings
  947.     from StringIO import StringIO
  948.     return StringIO()
  949.  
  950. def _doparse(func, args, kwargs):
  951.     events = apply(func, args, kwargs)
  952.     toktype, rootNode = events.getEvent()
  953.     events.expandNode(rootNode)
  954.     events.clear()
  955.     return rootNode
  956.  
  957. def parse(*args, **kwargs):
  958.     """Parse a file into a DOM by filename or file object."""
  959.     from xml.dom import pulldom
  960.     return _doparse(pulldom.parse, args, kwargs)
  961.  
  962. def parseString(*args, **kwargs):
  963.     """Parse a file into a DOM from a string."""
  964.     from xml.dom import pulldom
  965.     return _doparse(pulldom.parseString, args, kwargs)
  966.  
  967. def getDOMImplementation():
  968.     return Document.implementation
  969.