XML/SAX: Externe Entities in Python code einbetten

Code-Stücke können hier veröffentlicht werden.
Antworten
rapidmax
User
Beiträge: 3
Registriert: Freitag 3. September 2004, 13:11

Oft will man mit möglichst wenig Dateien auskommen. Da bietet es sich an, externe Entities direkt in den Python Code einzubetten. Am Beispiel von eingebetteten DTDs zeigt der folgende Code Schnippsel wie das zu erreichen ist.
Der erste Schritt ist eine eigene Implementation des Entity Resolvers zu schreiben. Dieser gibt die eingebettete Entity zurück, falls vorhanden. Wenn die Entity nicht vorhanden ist, wird der original Resolver bemüht.
Die eingebetteten Entities wurden mit zlib komprimiert und mit Base64 kodiert eingebettet. Bereits beim Laden des Pythonmoduls werden die Entities entpackt.

Code: Alles auswählen

import xml.sax
from zlib import decompress
from base64 import decodestring
from StringIO import StringIO # cStringIO works too...

__myfirst_dtd = decompress(decodestring("""
eNqzUXT1cfV19QtRyK2syM1JyU82VNBQDnB2cQxx1LQDAIl5CKU=""" ))
__mysecond_dtd = decompress(decodestring("""
eNqzUXT1cfV19QtRyK2syM1JyU82UtBQDnB2cQxx1LQDAImFCKY=""" ))
# Translation dictionary for internal DTDs
INTERNAL_DTD = { 'myfirst.dtd' : __myfirst_dtd,
                 'mysecond.dtd': __mysecond_dtd }

class OwnEntityResolver(xml.sax.handler.EntityResolver):
    """ Own external entity resolver returns embedded entities """
    def __init__(self, oldresolver):
        self.oldresolver = oldresolver
    def resolveEntity(self, publicId, systemId):
        if INTERNAL_DTD.has_key(systemId):
            insrc = xml.sax.InputSource()
            insrc.setByteStream(StringIO(INTERNAL_DTD[systemId]))
            return insrc
        else:
            return self.oldresolver.resolveEntity(publicId, systemId)
Die Anwendung des neuen Resolvers sieht nun so aus:

Code: Alles auswählen

handler = SpamXmlHandler()
parser = xml.sax.make_parser()
parser.setContentHandler(handler)
# install own entity-Resolver
res = OwnEntityResolver(parser.getEntityResolver())
parser.setEntityResolver(res)
# finally parse it!
result = parser.parse(file)
Die Entities können mit dem folgenden lambda für das Einbetten vorbereitet werden:

Code: Alles auswählen

embedding = lambda data: base64.encodestring(zlib.compress(data, 9))
Gruss, Andy
Antworten