[XML-SIG] SAX2.py

Lars Marius Garshol larsga@garshol.priv.no
04 Oct 1999 13:49:47 +0200


* uche ogbuji
| 
| The module is attached.  

Uche, this is great! It duplicates what I have already done (and
already posted), but that doesn't matter. If we can thrash out the
issues on the list and arrive at one set of interfaces then that would
be great.

I've sent your proposal to the printer and will look at it tonight.
For comparison, here is mine:

--- Features

The list below is copied directly from David Megginsons latest
proposal. Note that all features are optional.


http://xml.org/sax/features/validation
  Validate (true) or don't validate (false).

http://xml.org/sax/features/external-general-entities
  Expand external general entities (true) or don't expand (false).

http://xml.org/sax/features/external-parameter-entities
  Expand external parameter entities including the external DTD subset
  (true) or don't expand (false).

http://xml.org/sax/features/namespaces
  Preprocess namespaces (true) or don't preprocess (false).  See also
  the http://xml.org/sax/properties/namespace-sep property.

http://xml.org/sax/features/normalize-text
  Ensure that all consecutive text is returned in a single callback to
  DocumentHandler.characters or DocumentHandler.ignorableWhitespace
  (true) or explicitly do not require it (false).

http://xml.org/sax/features/use-locator
  Provide a Locator using the DocumentHandler.setDocumentLocator
  callback (true), or explicitly do not provide one (false).


--- LexicalHandler

This handler is supposed to be used by applications that need
information about lexical details in the document such as comments and
entity boundaries. Most applications won't need this, but the DOM will
find it useful. Support for this handler will be optional.

This handler has the handerID http://xml.org/sax/handlers/lexical.

class LexicalHandler:

  def xmlDecl(self, version, encoding, standalone):
    """All three parameters are strings. encoding and standalone are not
    specified on the XML declaration, their values will be None."""

  def startDTD(self, root, publicID, systemID):
    """This event is reported when the DOCTYPE declaration is
    encountered. root is the name of the root element type, while the two last
    parameters are the public and system identifiers of the external
    DTD subset."""

  def endDTD(self):
    "This event is reported after the DTD has been parsed."

  def startEntity(self, name):
    """Reports the beginning of a new entity. If the entity is the
    external DTD subset the name will be '[dtd]'."""

  def endEntity(self, name):
    pass

  def startCDATA(self):
    pass

  def endCDATA(self):
    pass


--- Extended parser

class Parser2(Parser):

  def setFeature(featureID, state)
    This turns on or off (depending on whether state is true or false)
    support for a particular feature (like namespaces, validation etc).
    The parser can raise SAXNotSupportedException if it doesn't
    support the feature or its subclass SAXUnrecognizedException.

  def setHandler(handlerID, handler):
    This registers an event handler with the parser (LexicalHandler,
    NamespaceHandler or maybe some special parser-defined handler).
    The parser can raise SAXNotSupportedException if it doesn't
    support the handler or its subclass SAXUnrecognizedException.

  def set(propertyID, value):
    This sets the value of a parser property (such as the namespace
    separator string or something parser-defined.) The parser can
    raise SAXNotSupportedException if it doesn't support the handler
    or its subclass SAXUnrecognizedException.

  def get(propertyID):   
    This returns the value of a property. The parser can raise
    SAXNotSupportedException if it doesn't support the handler or its
    subclass SAXUnrecognizedException.


--- Properties

The first three properties come from the JavaSAX proposal, while the
last one was invented by yours truly.


http://xml.org/sax/properties/namespace-sep <String> (write-only)
  Set the separator to be used between the URI part of a name and the
  local part of a name when namespace processing is being performed
  (see the http://xml.org/sax/features/namespaces feature).  By
  default, the separator is a single space.  This property may not be
  set while a parse is in progress (throws a SAXNotSupportedException).

http://xml.org/sax/properties/dom-node <Node> (read-only)
  Get the DOM node currently being visited, if the SAX parser is
  iterating over a DOM tree.  If the parser recognises and supports
  this property but is not currently visiting a DOM node, it should
  return null (this is a good way to check for availability before the
  parse begins).

  This property doesn't make much sense for Python, but I see no point
  in leaving it out, either.

http://xml.org/sax/properties/xml-string <String> (read-only)
  Get the literal string of characters associated with the current
  event.  If the parser recognises and supports this property but is
  not currently parsing text, it should return null (this is a good
  way to check for availability before the parse begins).  I stole
  this idea from Expat.


In addition, I think PySAX needs the following property:

http://python.org/sax/properties/data-encoding <String> (read/write)
  This property can be used to control which character encoding is
  used for data events that come from the parser. Throws
  SAXEncodingNotSupportedException if the encoding is not supported
  by the parser.


--- AttributeList2

This posting specifies both an extended AttributeList interface for
information needed by the DOM (and possibly also others) and also for
full XML 1.0 conformance. I'm not really sure whether we should
actually use all of this, so opinions are welcome.

class AttributeList2:

  def isSpecified(self,attr):
    """Returns true if the attribute was explicitly specified in the
    document and false otherwise. attr can be the attribute name or
    its index in the AttributeList."""

  def getEntityRefList(self,attr):
    """This returns the EntityRefList (see below) for an attribute,
    which can be specified by name or index."""


The class below is inteded to be used for discovering entity reference
boundaries inside attribute values. This is needed because the XML 1.0
recommendation requires parsers to report unexpanded entity references, 
also inside attribute values. Whether this is really
something we want is another matter.

class EntityRefList:

  def getLength(self):
    "Returns the number of entity references inside this attribute value."

  def getEntityName(self, ix):
    "Returns the name of entity reference number ix (zero-based index)."

  def getEntityRefStart(self, ix):
    """Returns the index of the first character inside the attribute
    value that stems from entity reference number ix."""

  def getEntityRefEnd(self, ix):
    "Returns the index of the last character in entity reference ix."


One redeeming feature of this interface is that it lives entirely
outside the attribute value, and so can be ignored entirely by those
who are not interested.


--Lars M.