[Python-checkins] CVS: python/dist/src/Lib/xml/dom minidom.py,1.14,1.15

Fred L. Drake python-dev@python.org
Thu, 14 Dec 2000 10:16:13 -0800


Update of /cvsroot/python/python/dist/src/Lib/xml/dom
In directory slayer.i.sourceforge.net:/tmp/cvs-serv23928

Modified Files:
	minidom.py 
Log Message:

Lots of small bug fixes and DOM API conformance improvements:

Make Node inherit from xml.dom.Node to pick up the NodeType values
defined by the W3C recommendation.

When raising AttributeError, be sure to provide the name of the attribute
that does not exist.

Node.normalize():  Make sure we do not allow an empty text node to survive
                   as the first child; update the sibling links properly.

_getElementsByTagNameNSHelper():  Make recursive calls using the right
                                  number of parameters.

Attr.__setattr__():  Be sure to update name and nodeName at the same time
                     since they are synonyms for this node type.

AttributeList:  Renamed to NamedNodeMap (AttributeList maintained as an
                alias).  Compute the length attribute dynamically to allow
                the underlying structures to mutate.

AttributeList.item():  Call .keys() on the dictionary rather than using
                       self.keys() for performance.

AttributeList.setNamedItem(), .setNamedItemNS():
        Added methods.

Text.splitText():
        Added method.

DocumentType:
        Added implementation class.

DOMImplementation:
        Added implementation class.

Document.appendChild():  Do not allow a second document element to be added.

Document.documentElement:  Find this dynamically, so that one can be
        removed and another added.

Document.unlink():  Clear the doctype attribute.

_get_StringIO():  Only use the StringIO module; cStringIO does not support
                  Unicode.


Index: minidom.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/xml/dom/minidom.py,v
retrieving revision 1.14
retrieving revision 1.15
diff -C2 -r1.14 -r1.15
*** minidom.py	2000/11/21 22:02:22	1.14
--- minidom.py	2000/12/14 18:16:11	1.15
***************
*** 1,4 ****
  """\
! minidom.py -- a lightweight DOM implementation based on SAX.
  
  parse( "foo.xml" )
--- 1,4 ----
  """\
! minidom.py -- a lightweight DOM implementation.
  
  parse( "foo.xml" )
***************
*** 28,46 ****
  del types
  
  
- class Node:
-     ELEMENT_NODE                = 1
-     ATTRIBUTE_NODE              = 2
-     TEXT_NODE                   = 3
-     CDATA_SECTION_NODE          = 4
-     ENTITY_REFERENCE_NODE       = 5
-     ENTITY_NODE                 = 6
-     PROCESSING_INSTRUCTION_NODE = 7
-     COMMENT_NODE                = 8
-     DOCUMENT_NODE               = 9
-     DOCUMENT_TYPE_NODE          = 10
-     DOCUMENT_FRAGMENT_NODE      = 11
-     NOTATION_NODE               = 12
  
      allnodes = {}
      _debug = 0
--- 28,37 ----
  del types
  
+ import xml.dom
+ _Node = xml.dom.Node
+ del xml
  
  
+ class Node(_Node):
      allnodes = {}
      _debug = 0
***************
*** 60,64 ****
      def __getattr__(self, key):
          if key[0:2] == "__":
!             raise AttributeError
          # getattr should never call getattr!
          if self.__dict__.has_key("inGetAttr"):
--- 51,55 ----
      def __getattr__(self, key):
          if key[0:2] == "__":
!             raise AttributeError, key
          # getattr should never call getattr!
          if self.__dict__.has_key("inGetAttr"):
***************
*** 159,167 ****
  
      def normalize(self):
!         if len(self.childNodes) > 1:
!             L = [self.childNodes[0]]
!             for child in self.childNodes[1:]:
!                 if (  child.nodeType == Node.TEXT_NODE
!                       and L[-1].nodeType == child.nodeType):
                      # collapse text node
                      node = L[-1]
--- 150,158 ----
  
      def normalize(self):
!         L = []
!         for child in self.childNodes:
!             if child.nodeType == Node.TEXT_NODE:
!                 data = child.data
!                 if data and L and L[-1].nodeType == child.nodeType:
                      # collapse text node
                      node = L[-1]
***************
*** 169,181 ****
                      node.nextSibling = child.nextSibling
                      child.unlink()
                  else:
                      L[-1].nextSibling = child
                      child.previousSibling = L[-1]
!                     L.append(child)
                      child.normalize()
!             self.childNodes = L
!         elif self.childNodes:
!             # exactly one child -- just recurse
!             self.childNodes[0].normalize()
  
      def cloneNode(self, deep):
--- 160,183 ----
                      node.nextSibling = child.nextSibling
                      child.unlink()
+                 elif data:
+                     if L:
+                         L[-1].nextSibling = child
+                         child.previousSibling = L[-1]
+                     else:
+                         child.previousSibling = None
+                     L.append(child)
                  else:
+                     # empty text node; discard
+                     child.unlink()
+             else:
+                 if L:
                      L[-1].nextSibling = child
                      child.previousSibling = L[-1]
!                 else:
!                     child.previousSibling = None
!                 L.append(child)
!                 if child.nodeType == Node.ELEMENT_NODE:
                      child.normalize()
!         self.childNodes[:] = L
  
      def cloneNode(self, deep):
***************
*** 225,229 ****
                  (nsURI == "*" or node.namespaceURI == nsURI)):
                  rc.append(node)
!             _getElementsByTagNameNSHelper(node, name, rc)
  
  class Attr(Node):
--- 227,232 ----
                  (nsURI == "*" or node.namespaceURI == nsURI)):
                  rc.append(node)
!             _getElementsByTagNameNSHelper(node, nsURI, localName, rc)
!     return rc
  
  class Attr(Node):
***************
*** 243,250 ****
  
      def __setattr__(self, name, value):
          if name in ("value", "nodeValue"):
!             self.__dict__["value"] = self.__dict__["nodeValue"] = value
          else:
!             self.__dict__[name] = value
  
      def cloneNode(self, deep):
--- 246,256 ----
  
      def __setattr__(self, name, value):
+         d = self.__dict__
          if name in ("value", "nodeValue"):
!             d["value"] = d["nodeValue"] = value
!         elif name in ("name", "nodeName"):
!             d["name"] = d["nodeName"] = value
          else:
!             d[name] = value
  
      def cloneNode(self, deep):
***************
*** 253,270 ****
              del clone.ownerElement
          return clone
  
! class AttributeList:
      """The attribute list is a transient interface to the underlying
      dictionaries.  Mutations here will change the underlying element's
!     dictionary"""
  
      def __init__(self, attrs, attrsNS):
          self._attrs = attrs
          self._attrsNS = attrsNS
!         self.length = len(self._attrs)
  
      def item(self, index):
          try:
!             return self[self.keys()[index]]
          except IndexError:
              return None
--- 259,285 ----
              del clone.ownerElement
          return clone
+ 
  
! class NamedNodeMap:
      """The attribute list is a transient interface to the underlying
      dictionaries.  Mutations here will change the underlying element's
!     dictionary.
  
+     Ordering is imposed artificially and does not reflect the order of
+     attributes as found in an input document.
+     """
+ 
      def __init__(self, attrs, attrsNS):
          self._attrs = attrs
          self._attrsNS = attrsNS
! 
!     def __getattr__(self, name):
!         if name == "length":
!             return len(self._attrs)
!         raise AttributeError, name
  
      def item(self, index):
          try:
!             return self[self._attrs.keys()[index]]
          except IndexError:
              return None
***************
*** 316,324 ****
                  raise TypeError, "value must be a string or Attr object"
              node = value
!         old = self._attrs.get(attname, None)
          if old:
              old.unlink()
          self._attrs[node.name] = node
          self._attrsNS[(node.namespaceURI, node.localName)] = node
  
      def __delitem__(self, attname_or_tuple):
--- 331,346 ----
                  raise TypeError, "value must be a string or Attr object"
              node = value
!         self.setNamedItem(node)
! 
!     def setNamedItem(self, node):
!         old = self._attrs.get(node.name)
          if old:
              old.unlink()
          self._attrs[node.name] = node
          self._attrsNS[(node.namespaceURI, node.localName)] = node
+         return old
+ 
+     def setNamedItemNS(self, node):
+         return self.setNamedItem(node)
  
      def __delitem__(self, attname_or_tuple):
***************
*** 327,331 ****
--- 349,357 ----
          del self._attrs[node.name]
          del self._attrsNS[(node.namespaceURI, node.localName)]
+         self.length = len(self._attrs)
  
+ AttributeList = NamedNodeMap
+ 
+ 
  class Element(Node):
      nodeType = Node.ELEMENT_NODE
***************
*** 496,499 ****
--- 522,538 ----
          return "<DOM Text node \"%s%s\">" % (self.data[0:10], dotdotdot)
  
+     def splitText(self, offset):
+         if offset < 0 or offset > len(self.data):
+             raise ValueError, "illegal offset value for splitText()"
+         newText = Text(self.data[offset:])
+         next = self.nextSibling
+         if self.parentNode and self in self.parentNode.childNodes:
+             if next is None:
+                 self.parentNode.appendChild(newText)
+             else:
+                 self.parentNode.insertBefore(newText, next)
+         self.data = self.data[:offset]
+         return newText
+ 
      def writexml(self, writer):
          _write_data(writer, self.data)
***************
*** 506,509 ****
--- 545,599 ----
          return ('', fields[0])
  
+ 
+ class DocumentType(Node):
+     nodeType = Node.DOCUMENT_TYPE_NODE
+     nodeValue = None
+     attributes = None
+     name = None
+     publicId = None
+     systemId = None
+     internalSubset = ""
+     entities = None
+     notations = None
+ 
+     def __init__(self, qualifiedName):
+         Node.__init__(self)
+         if qualifiedName:
+             prefix, localname = _nssplit(qualifiedName)
+             self.name = localname
+ 
+ 
+ class DOMImplementation:
+     def hasFeature(self, feature, version):
+         if version not in ("1.0", "2.0"):
+             return 0
+         feature = _string.lower(feature)
+         return feature == "core"
+ 
+     def createDocument(self, namespaceURI, qualifiedName, doctype):
+         if doctype and doctype.parentNode is not None:
+             raise ValueError, "doctype object owned by another DOM tree"
+         doc = Document()
+         if doctype is None:
+             doctype = self.createDocumentType(qualifiedName, None, None)
+         if qualifiedName:
+             prefix, localname = _nssplit(qualifiedName)
+             if prefix == "xml" \
+                and namespaceURI != "http://www.w3.org/XML/1998/namespace":
+                 raise ValueError, "illegal use of 'xml' prefix"
+             if prefix and not namespaceURI:
+                 raise ValueError, "illegal use of prefix without namespaces"
+         doctype.parentNode = doc
+         doc.doctype = doctype
+         doc.implementation = self
+         return doc
+ 
+     def createDocumentType(self, qualifiedName, publicId, systemId):
+         doctype = DocumentType(qualifiedName)
+         doctype.publicId = publicId
+         doctype.systemId = systemId
+         return doctype
+ 
+ 
  class Document(Node):
      nodeType = Node.DOCUMENT_NODE
***************
*** 511,524 ****
      nodeValue = None
      attributes = None
!     documentElement = None
  
      def appendChild(self, node):
!         if node.nodeType == Node.ELEMENT_NODE:
!             if self.documentElement:
!                 raise TypeError, "Two document elements disallowed"
!             else:
!                 self.documentElement = node
          return Node.appendChild(self, node)
  
      createElement = Element
  
--- 601,626 ----
      nodeValue = None
      attributes = None
!     doctype = None
!     parentNode = None
! 
!     implementation = DOMImplementation()
  
      def appendChild(self, node):
!         if node.nodeType == Node.ELEMENT_NODE \
!            and self._get_documentElement():
!             raise TypeError, "two document elements disallowed"
          return Node.appendChild(self, node)
  
+     def _get_documentElement(self):
+         for node in self.childNodes:
+             if node.nodeType == Node.ELEMENT_NODE:
+                 return node
+ 
+     def unlink(self):
+         if self.doctype is not None:
+             self.doctype.unlink()
+             self.doctype = None
+         Node.unlink(self)
+ 
      createElement = Element
  
***************
*** 544,551 ****
          _getElementsByTagNameNSHelper(self, namespaceURI, localName)
  
-     def unlink(self):
-         self.documentElement = None
-         Node.unlink(self)
- 
      def getElementsByTagName(self, name):
          rc = []
--- 646,649 ----
***************
*** 558,565 ****
  
  def _get_StringIO():
!     try:
!         from cStringIO import StringIO
!     except ImportError:
!         from StringIO import StringIO
      return StringIO()
  
--- 656,661 ----
  
  def _get_StringIO():
!     # we can't use cStringIO since it doesn't support Unicode strings
!     from StringIO import StringIO
      return StringIO()
  
***************
*** 571,580 ****
  
  def parse(*args, **kwargs):
!     "Parse a file into a DOM by filename or file object"
      from xml.dom import pulldom
      return _doparse(pulldom.parse, args, kwargs)
  
  def parseString(*args, **kwargs):
!     "Parse a file into a DOM from a string"
      from xml.dom import pulldom
      return _doparse(pulldom.parseString, args, kwargs)
--- 667,676 ----
  
  def parse(*args, **kwargs):
!     """Parse a file into a DOM by filename or file object."""
      from xml.dom import pulldom
      return _doparse(pulldom.parse, args, kwargs)
  
  def parseString(*args, **kwargs):
!     """Parse a file into a DOM from a string."""
      from xml.dom import pulldom
      return _doparse(pulldom.parseString, args, kwargs)