home *** CD-ROM | disk | FTP | other *** search
/ Komputer for Alle 2004 #2 / K-CD-2-2004.ISO / OpenOffice Sv / f_0397 / python-core-2.2.2 / lib / xml / dom / minidom.py < prev    next >
Encoding:
Python Source  |  2003-07-18  |  31.5 KB  |  971 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, NodeList())
  588.  
  589.     def getElementsByTagNameNS(self, namespaceURI, localName):
  590.         return _getElementsByTagNameNSHelper(self, namespaceURI, localName,
  591.                                              NodeList())
  592.  
  593.     def __repr__(self):
  594.         return "<DOM Element: %s at %s>" % (self.tagName, id(self))
  595.  
  596.     def writexml(self, writer, indent="", addindent="", newl=""):
  597.         # indent = current indentation
  598.         # addindent = indentation to add to higher levels
  599.         # newl = newline string
  600.         writer.write(indent+"<" + self.tagName)
  601.  
  602.         attrs = self._get_attributes()
  603.         a_names = attrs.keys()
  604.         a_names.sort()
  605.  
  606.         for a_name in a_names:
  607.             writer.write(" %s=\"" % a_name)
  608.             _write_data(writer, attrs[a_name].value)
  609.             writer.write("\"")
  610.         if self.childNodes:
  611.             writer.write(">%s"%(newl))
  612.             for node in self.childNodes:
  613.                 node.writexml(writer,indent+addindent,addindent,newl)
  614.             writer.write("%s</%s>%s" % (indent,self.tagName,newl))
  615.         else:
  616.             writer.write("/>%s"%(newl))
  617.  
  618.     def _get_attributes(self):
  619.         return NamedNodeMap(self._attrs, self._attrsNS, self)
  620.  
  621.     try:
  622.         property
  623.     except NameError:
  624.         pass
  625.     else:
  626.         attributes = property(_get_attributes,
  627.                               doc="NamedNodeMap of attributes on the element.")
  628.  
  629.     def hasAttributes(self):
  630.         if self._attrs or self._attrsNS:
  631.             return 1
  632.         else:
  633.             return 0
  634.  
  635. class Comment(Node):
  636.     nodeType = Node.COMMENT_NODE
  637.     nodeName = "#comment"
  638.     attributes = None
  639.     childNodeTypes = ()
  640.  
  641.     def __init__(self, data):
  642.         Node.__init__(self)
  643.         self.data = self.nodeValue = data
  644.  
  645.     def writexml(self, writer, indent="", addindent="", newl=""):
  646.         writer.write("%s<!--%s-->%s" % (indent,self.data,newl))
  647.  
  648. class ProcessingInstruction(Node):
  649.     nodeType = Node.PROCESSING_INSTRUCTION_NODE
  650.     attributes = None
  651.     childNodeTypes = ()
  652.  
  653.     def __init__(self, target, data):
  654.         Node.__init__(self)
  655.         self.target = self.nodeName = target
  656.         self.data = self.nodeValue = data
  657.  
  658.     def writexml(self, writer, indent="", addindent="", newl=""):
  659.         writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))
  660.  
  661. class CharacterData(Node):
  662.     def __init__(self, data):
  663.         if type(data) not in _StringTypes:
  664.             raise TypeError, "node contents must be a string"
  665.         Node.__init__(self)
  666.         self.data = self.nodeValue = data
  667.         self.length = len(data)
  668.  
  669.     def __repr__(self):
  670.         if len(self.data) > 10:
  671.             dotdotdot = "..."
  672.         else:
  673.             dotdotdot = ""
  674.         return "<DOM %s node \"%s%s\">" % (
  675.             self.__class__.__name__, self.data[0:10], dotdotdot)
  676.  
  677.     def substringData(self, offset, count):
  678.         if offset < 0:
  679.             raise xml.dom.IndexSizeErr("offset cannot be negative")
  680.         if offset >= len(self.data):
  681.             raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
  682.         if count < 0:
  683.             raise xml.dom.IndexSizeErr("count cannot be negative")
  684.         return self.data[offset:offset+count]
  685.  
  686.     def appendData(self, arg):
  687.         self.data = self.data + arg
  688.         self.nodeValue = self.data
  689.         self.length = len(self.data)
  690.  
  691.     def insertData(self, offset, arg):
  692.         if offset < 0:
  693.             raise xml.dom.IndexSizeErr("offset cannot be negative")
  694.         if offset >= len(self.data):
  695.             raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
  696.         if arg:
  697.             self.data = "%s%s%s" % (
  698.                 self.data[:offset], arg, self.data[offset:])
  699.             self.nodeValue = self.data
  700.             self.length = len(self.data)
  701.  
  702.     def deleteData(self, offset, count):
  703.         if offset < 0:
  704.             raise xml.dom.IndexSizeErr("offset cannot be negative")
  705.         if offset >= len(self.data):
  706.             raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
  707.         if count < 0:
  708.             raise xml.dom.IndexSizeErr("count cannot be negative")
  709.         if count:
  710.             self.data = self.data[:offset] + self.data[offset+count:]
  711.             self.nodeValue = self.data
  712.             self.length = len(self.data)
  713.  
  714.     def replaceData(self, offset, count, arg):
  715.         if offset < 0:
  716.             raise xml.dom.IndexSizeErr("offset cannot be negative")
  717.         if offset >= len(self.data):
  718.             raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
  719.         if count < 0:
  720.             raise xml.dom.IndexSizeErr("count cannot be negative")
  721.         if count:
  722.             self.data = "%s%s%s" % (
  723.                 self.data[:offset], arg, self.data[offset+count:])
  724.             self.nodeValue = self.data
  725.             self.length = len(self.data)
  726.  
  727. class Text(CharacterData):
  728.     nodeType = Node.TEXT_NODE
  729.     nodeName = "#text"
  730.     attributes = None
  731.     childNodeTypes = ()
  732.  
  733.     def splitText(self, offset):
  734.         if offset < 0 or offset > len(self.data):
  735.             raise xml.dom.IndexSizeErr("illegal offset value")
  736.         newText = Text(self.data[offset:])
  737.         next = self.nextSibling
  738.         if self.parentNode and self in self.parentNode.childNodes:
  739.             if next is None:
  740.                 self.parentNode.appendChild(newText)
  741.             else:
  742.                 self.parentNode.insertBefore(newText, next)
  743.         self.data = self.data[:offset]
  744.         self.nodeValue = self.data
  745.         self.length = len(self.data)
  746.         return newText
  747.  
  748.     def writexml(self, writer, indent="", addindent="", newl=""):
  749.         _write_data(writer, "%s%s%s"%(indent, self.data, newl))
  750.  
  751.  
  752. class CDATASection(Text):
  753.     nodeType = Node.CDATA_SECTION_NODE
  754.     nodeName = "#cdata-section"
  755.  
  756.     def writexml(self, writer, indent="", addindent="", newl=""):
  757.         writer.write("<![CDATA[%s]]>" % self.data)
  758.  
  759.  
  760. def _nssplit(qualifiedName):
  761.     fields = _string.split(qualifiedName, ':', 1)
  762.     if len(fields) == 2:
  763.         return fields
  764.     elif len(fields) == 1:
  765.         return (None, fields[0])
  766.  
  767.  
  768. class DocumentType(Node):
  769.     nodeType = Node.DOCUMENT_TYPE_NODE
  770.     nodeValue = None
  771.     attributes = None
  772.     name = None
  773.     publicId = None
  774.     systemId = None
  775.     internalSubset = None
  776.     entities = None
  777.     notations = None
  778.  
  779.     def __init__(self, qualifiedName):
  780.         Node.__init__(self)
  781.         if qualifiedName:
  782.             prefix, localname = _nssplit(qualifiedName)
  783.             self.name = localname
  784.  
  785.  
  786. class DOMImplementation:
  787.     def hasFeature(self, feature, version):
  788.         if version not in ("1.0", "2.0"):
  789.             return 0
  790.         feature = _string.lower(feature)
  791.         return feature == "core"
  792.  
  793.     def createDocument(self, namespaceURI, qualifiedName, doctype):
  794.         if doctype and doctype.parentNode is not None:
  795.             raise xml.dom.WrongDocumentErr(
  796.                 "doctype object owned by another DOM tree")
  797.         doc = self._createDocument()
  798.         if doctype is None:
  799.             doctype = self.createDocumentType(qualifiedName, None, None)
  800.         if not qualifiedName:
  801.             # The spec is unclear what to raise here; SyntaxErr
  802.             # would be the other obvious candidate. Since Xerces raises
  803.             # InvalidCharacterErr, and since SyntaxErr is not listed
  804.             # for createDocument, that seems to be the better choice.
  805.             # XXX: need to check for illegal characters here and in
  806.             # createElement.
  807.             raise xml.dom.InvalidCharacterErr("Element with no name")
  808.         prefix, localname = _nssplit(qualifiedName)
  809.         if prefix == "xml" \
  810.            and namespaceURI != "http://www.w3.org/XML/1998/namespace":
  811.             raise xml.dom.NamespaceErr("illegal use of 'xml' prefix")
  812.         if prefix and not namespaceURI:
  813.             raise xml.dom.NamespaceErr(
  814.                 "illegal use of prefix without namespaces")
  815.         element = doc.createElementNS(namespaceURI, qualifiedName)
  816.         doc.appendChild(element)
  817.         doctype.parentNode = doctype.ownerDocument = doc
  818.         doc.doctype = doctype
  819.         doc.implementation = self
  820.         return doc
  821.  
  822.     def createDocumentType(self, qualifiedName, publicId, systemId):
  823.         doctype = DocumentType(qualifiedName)
  824.         doctype.publicId = publicId
  825.         doctype.systemId = systemId
  826.         return doctype
  827.  
  828.     # internal
  829.     def _createDocument(self):
  830.         return Document()
  831.  
  832. class Document(Node):
  833.     nodeType = Node.DOCUMENT_NODE
  834.     nodeName = "#document"
  835.     nodeValue = None
  836.     attributes = None
  837.     doctype = None
  838.     parentNode = None
  839.     previousSibling = nextSibling = None
  840.  
  841.     implementation = DOMImplementation()
  842.     childNodeTypes = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
  843.                       Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)
  844.  
  845.     def appendChild(self, node):
  846.         if node.nodeType not in self.childNodeTypes:
  847.             raise HierarchyRequestErr, \
  848.                   "%s cannot be child of %s" % (repr(node), repr(self))
  849.         if node.parentNode is not None:
  850.             node.parentNode.removeChild(node)
  851.  
  852.         if node.nodeType == Node.ELEMENT_NODE \
  853.            and self._get_documentElement():
  854.             raise xml.dom.HierarchyRequestErr(
  855.                 "two document elements disallowed")
  856.         return Node.appendChild(self, node)
  857.  
  858.     def removeChild(self, oldChild):
  859.         self.childNodes.remove(oldChild)
  860.         oldChild.nextSibling = oldChild.previousSibling = None
  861.         oldChild.parentNode = None
  862.         if self.documentElement is oldChild:
  863.             self.documentElement = None
  864.  
  865.         return oldChild
  866.  
  867.     def _get_documentElement(self):
  868.         for node in self.childNodes:
  869.             if node.nodeType == Node.ELEMENT_NODE:
  870.                 return node
  871.  
  872.     try:
  873.         property
  874.     except NameError:
  875.         pass
  876.     else:
  877.         documentElement = property(_get_documentElement,
  878.                                    doc="Top-level element of this document.")
  879.  
  880.     def unlink(self):
  881.         if self.doctype is not None:
  882.             self.doctype.unlink()
  883.             self.doctype = None
  884.         Node.unlink(self)
  885.  
  886.     def createDocumentFragment(self):
  887.         d = DocumentFragment()
  888.         d.ownerDoc = self
  889.         return d
  890.  
  891.     def createElement(self, tagName):
  892.         e = Element(tagName)
  893.         e.ownerDocument = self
  894.         return e
  895.  
  896.     def createTextNode(self, data):
  897.         t = Text(data)
  898.         t.ownerDocument = self
  899.         return t
  900.  
  901.     def createCDATASection(self, data):
  902.         c = CDATASection(data)
  903.         c.ownerDocument = self
  904.         return c
  905.  
  906.     def createComment(self, data):
  907.         c = Comment(data)
  908.         c.ownerDocument = self
  909.         return c
  910.  
  911.     def createProcessingInstruction(self, target, data):
  912.         p = ProcessingInstruction(target, data)
  913.         p.ownerDocument = self
  914.         return p
  915.  
  916.     def createAttribute(self, qName):
  917.         a = Attr(qName)
  918.         a.ownerDocument = self
  919.         a.value = ""
  920.         return a
  921.  
  922.     def createElementNS(self, namespaceURI, qualifiedName):
  923.         prefix, localName = _nssplit(qualifiedName)
  924.         e = Element(qualifiedName, namespaceURI, prefix, localName)
  925.         e.ownerDocument = self
  926.         return e
  927.  
  928.     def createAttributeNS(self, namespaceURI, qualifiedName):
  929.         prefix, localName = _nssplit(qualifiedName)
  930.         a = Attr(qualifiedName, namespaceURI, localName, prefix)
  931.         a.ownerDocument = self
  932.         a.value = ""
  933.         return a
  934.  
  935.     def getElementsByTagName(self, name):
  936.         return _getElementsByTagNameHelper(self, name, NodeList())
  937.  
  938.     def getElementsByTagNameNS(self, namespaceURI, localName):
  939.         return _getElementsByTagNameNSHelper(self, namespaceURI, localName,
  940.                                              NodeList())
  941.  
  942.     def writexml(self, writer, indent="", addindent="", newl=""):
  943.         writer.write('<?xml version="1.0" ?>\n')
  944.         for node in self.childNodes:
  945.             node.writexml(writer, indent, addindent, newl)
  946.  
  947. def _get_StringIO():
  948.     # we can't use cStringIO since it doesn't support Unicode strings
  949.     from StringIO import StringIO
  950.     return StringIO()
  951.  
  952. def _doparse(func, args, kwargs):
  953.     events = apply(func, args, kwargs)
  954.     toktype, rootNode = events.getEvent()
  955.     events.expandNode(rootNode)
  956.     events.clear()
  957.     return rootNode
  958.  
  959. def parse(*args, **kwargs):
  960.     """Parse a file into a DOM by filename or file object."""
  961.     from xml.dom import pulldom
  962.     return _doparse(pulldom.parse, args, kwargs)
  963.  
  964. def parseString(*args, **kwargs):
  965.     """Parse a file into a DOM from a string."""
  966.     from xml.dom import pulldom
  967.     return _doparse(pulldom.parseString, args, kwargs)
  968.  
  969. def getDOMImplementation():
  970.     return Document.implementation
  971.