[XML-SIG] "simple" config file parser problems

J B Bell cipher@redback.com
Tue, 29 May 2001 10:31:29 -0700


I'm having the very devil of a time trying to do something that I
assume would be simple (if I knew what I was doing) with xml.sax under
Python 2.0 & 2.1.

I'd go into the structure I'm looking to get from the XML, but at this
point, the event-handling methods I have don't come into play before
something deep inside xml.expat explodes.  Likely the object I'm using
lacks a needed trait (it appears to be something to do with name,
though that seems to be there), but I'm not sure what.

Without further ado, too much code, followed by a stack trace.  Any
help at all is greatly appreciated.  If this isn't the appropriate
list, please accept my copious apologies, and if you are kindly
disposed, a pointer to the right place to get assistance would be a
bonus.

--JB

# Note, I have tried with both saxlib.HandlerBase and the presumably
# more generic ContentHandler.  Both give the exact same error.

from xml.sax import make_parser
from xml.sax import saxlib
from xml.sax.handler import feature_namespaces
from xml.sax import ContentHandler

class Config:
    """A base class for all types of configuration information, whether to be
       found in plain files, xml, or databases.  Subclass as appropriate."""

    def parseConfig(self, args):
        """Override this in your subclassed Config"""
        pass

    def __init__(self, *args):
        newConfig = self.parseConfig(args)
        return newConfig

#class RsyncConfigHandler(ContentHandler):
class RsyncConfigHandler(saxlib.HandlerBase):
    """Read in & return a config file for rsync jobs"""

    # Errors should be signaled, so we'll output a message and raise
    # the exception to stop processing
    def fatalError(self, exception):
        sys.stderr.write('ERROR: '+ str(exception)+'\n')
        sys.exit(1)
    error = fatalError
    warning = fatalError

    def startDocument(self):
        self.jobList = []

    def startElement(self, name, attrs):
        methodName = "start" + str(name).capitalize()
        try:
            method = getattr(self, methodName)
        except:
            raise "Unknown element name '<%s>'" % name
        self.attrs = attrs
        if DEBUG: print "Invoking %s with attrs %s" % (methodName, str(attrs))
        apply(method, attrs)

    def endElement(self, name):
        methodName = "start" + str(name).capitalize()
        try:
            method = getattr(self, methodName)
        except:
            raise "Unknown element name '</%s>'" % name
        if DEBUG: print "Invoking %s with attrs %s" % (methodName, str(attrs))
        apply(method, attrs)

    def startConfig(self, attrs):
        """<config> just starts the whole shebang, no need to do anything."""
        pass

    def endConfig(self):
        pass

    def startQueue(self, attrs):
        pass

    def endQueue(self):
        pass

    def startJob(self, attrs):
        pass

    def endJob(self):
        pass
 
class RsyncConfig(Config):
    """Return an rsync configuration object"""

    def parseConfig(self, args):
        parser = make_parser()
        parser.setFeature(feature_namespaces, 0)
        dh = RsyncConfigHandler()    # Might want arguments here one day
        parser.setContentHandler(dh)
        configFile = "/home/cipher/cvs/itdoc/servers/rsync_config.xml"
        parser.parse(configFile)

[And now the stack trace:]

Python 2.0 (#1, Nov  3 2000, 12:11:00) 
[GCC egcs-2.91.66 19990314 (egcs-1.1.2 release)] on netbsd1
Type "copyright", "credits" or "license" for more information.
>>> from rsynct import RsyncConfig
>>> foo = RsyncConfig()
Invoking startConfig with attrs <xml.sax.xmlreader.AttributesImpl
instance at 0x8309bcc>
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "rsynct.py", line 65, in __init__
    newConfig = self.parseConfig(args)
  File "rsynct.py", line 129, in parseConfig
    parser.parse(configFile)
  File
"/usr/pkg/lib/python2.0/site-packages/_xmlplus/sax/expatreader.py",
line 43, in parse
    xmlreader.IncrementalParser.parse(self, source)
  File
"/usr/pkg/lib/python2.0/site-packages/_xmlplus/sax/xmlreader.py", line
121, in parse
    self.feed(buffer)
  File
"/usr/pkg/lib/python2.0/site-packages/_xmlplus/sax/expatreader.py",
line 87, in feed
    self._parser.Parse(data, isFinal)
  File
"/usr/pkg/lib/python2.0/site-packages/_xmlplus/sax/expatreader.py",
line 155, in start_element
    self._cont_handler.startElement(name, AttributesImpl(attrs))
  File "rsynct.py", line 90, in startElement
    apply(method, attrs)
  File
"/usr/pkg/lib/python2.0/site-packages/_xmlplus/sax/xmlreader.py", line
314, in __getitem__
    return self._attrs[name]
KeyError: 0