[XML-SIG] SAX, freeze problem

Gregor Mosheh stigmata@blackangel.net
Tue, 2 Apr 2002 20:25:27 -0800 (PST)


I am unable to freeze Python programs that use SAX, apparently due to
failed imports. I saw an article (and in the reeze docs) mentioning that
some extension modules, such as SAX, don't have enough explicit import
statements for the freezer to find and import everything.

I'm trying to freeze the program below (the goal: take an array of objects
and XML-encode their attributes), and I'd much appreciate it if someone
has a list/reference of the changes I can make to allow this program to be
frozen.

The problem seems to be in xml.sax.writer, specifically.

I do have another question, incidentally: is SAX portable to Windows? That
is, has anyone using Win32/MSVC++ ever successfully compiled expat and
used it with SAX/Python?



import xml.sax, xml.sax.writer, xml.sax.handler
import cStringIO
import re
from re import sub
from re import match

privateattribute = re.compile("^_")


# encode() takes a list of objects and encodes their attributes
class XMLEncoder(xml.sax.writer.PrettyPrinter):
    def startDocument(self):
        pass

def encode(objectlist,includeprivate=0):
    # use a StringIO buffer to hold the string, cuz the XML stuff requires streams (bleh)
    buffer = cStringIO.StringIO()
    saxout = XMLEncoder(buffer)

    saxout.startDocument()
    saxout.startElement("objects",{})
    # go thru the list of objects...
    for thisobject in objectlist:
        # populate thisobjecthash with the object's attributes, skipping privates if necessary
        thisobjecthash = {}
        for property in dir(thisobject):
            if not match(privateattribute,property) or includeprivate:
                content = str(getattr(thisobject,property))
                thisobjecthash[property] = content
        # it was empty? must not not have been interesting, so skip it
        if not thisobjecthash:
           continue
        saxout.startElement("object",thisobjecthash)
        saxout.endElement("object")
    saxout.endElement("objects")
    saxout.endDocument()
    return buffer.getvalue()



# decode() takes an XML string and returns a tuple of hashes. the hashes represent the attributes of objects
class XMLDecoder(xml.sax.handler.ContentHandler):
    def __init__(self):
        self.objectlist = []
    def startElement(self, name, attrs):
        if name=='object':
            newDict = {}
            for key, value in attrs.items():
                newDict[str(key)] = value
            self.objectlist.append(newDict)

def decode(xmlstring):
    try:
        xmlhandler = XMLDecoder()
        xml.sax.parseString(xmlstring, xmlhandler)
        return tuple(xmlhandler.objectlist)
    except:
        return



# an example, if this module is executed
def runexample():
    # create an array of instances of this class, then encode it
    class Example:
        def __init__(self,x,y):
            self.X = x
            self.Y = y
            self.ObjectClass = 'Example'

    objectlist = [ Example(1,'this has "quote marks" in it') , Example(2,'abc>&<def') , Example(3,'\312') ]
    encoded_as_xml      = encode(objectlist)
    decoded_into_hashes = decode(encoded_as_xml)

    print "Three Example objects encoded as XML:"
    print encoded_as_xml
    print "\n"
    print "The XML decodes back into this:"
    print decoded_into_hashes
    print "\n"

if __name__ == '__main__':
    runexample()