blob: ca4d718c7fb61d66224d56258b0611263f11bb3b [file] [log] [blame]
"""
SAX driver for the Java SAX parsers. Can only be used in Jython.
$Id: drv_javasax.py,v 1.5 2003/01/26 09:08:51 loewis Exp $
"""
# --- Initialization
version = "0.10"
revision = "$Revision: 1.5 $"
import string
from xml.sax import xmlreader, saxutils
from xml.sax.handler import feature_namespaces, feature_namespace_prefixes
from xml.sax import _exceptions
# we only work in jython
import sys
if sys.platform[:4] != "java":
raise _exceptions.SAXReaderNotAvailable("drv_javasax not available in CPython", None)
del sys
# get the necessary Java SAX classes
try:
from org.python.core import FilelikeInputStream
from org.xml.sax.helpers import XMLReaderFactory
from org.xml import sax as javasax
from org.xml.sax.ext import LexicalHandler
except ImportError:
raise _exceptions.SAXReaderNotAvailable("SAX is not on the classpath", None)
# get some JAXP stuff
try:
from javax.xml.parsers import SAXParserFactory, ParserConfigurationException
factory = SAXParserFactory.newInstance()
jaxp = 1
except ImportError:
jaxp = 0
from java.lang import String
def _wrap_sax_exception(e):
return _exceptions.SAXParseException(e.message,
e.exception,
SimpleLocator(e.columnNumber,
e.lineNumber,
e.publicId,
e.systemId))
class JyErrorHandlerWrapper(javasax.ErrorHandler):
def __init__(self, err_handler):
self._err_handler = err_handler
def error(self, exc):
self._err_handler.error(_wrap_sax_exception(exc))
def fatalError(self, exc):
self._err_handler.fatalError(_wrap_sax_exception(exc))
def warning(self, exc):
self._err_handler.warning(_wrap_sax_exception(exc))
class JyInputSourceWrapper(javasax.InputSource):
def __init__(self, source):
if isinstance(source, basestring):
javasax.InputSource.__init__(self, source)
elif hasattr(source, "read"):#file like object
f = source
javasax.InputSource.__init__(self, FilelikeInputStream(f))
if hasattr(f, "name"):
self.setSystemId(f.name)
else:#xml.sax.xmlreader.InputSource object
#Use byte stream constructor if possible so that Xerces won't attempt to open
#the url at systemId unless it's really there
if source.getByteStream():
javasax.InputSource.__init__(self,
FilelikeInputStream(source.getByteStream()))
else:
javasax.InputSource.__init__(self)
if source.getSystemId():
self.setSystemId(source.getSystemId())
self.setPublicId(source.getPublicId())
self.setEncoding(source.getEncoding())
class JyEntityResolverWrapper(javasax.EntityResolver):
def __init__(self, entityResolver):
self._resolver = entityResolver
def resolveEntity(self, pubId, sysId):
return JyInputSourceWrapper(self._resolver.resolveEntity(pubId, sysId))
class JyDTDHandlerWrapper(javasax.DTDHandler):
def __init__(self, dtdHandler):
self._handler = dtdHandler
def notationDecl(self, name, publicId, systemId):
self._handler.notationDecl(name, publicId, systemId)
def unparsedEntityDecl(self, name, publicId, systemId, notationName):
self._handler.unparsedEntityDecl(name, publicId, systemId, notationName)
class SimpleLocator(xmlreader.Locator):
def __init__(self, colNum, lineNum, pubId, sysId):
self.colNum = colNum
self.lineNum = lineNum
self.pubId = pubId
self.sysId = sysId
def getColumnNumber(self):
return self.colNum
def getLineNumber(self):
return self.lineNum
def getPublicId(self):
return self.pubId
def getSystemId(self):
return self.sysId
# --- JavaSAXParser
class JavaSAXParser(xmlreader.XMLReader, javasax.ContentHandler, LexicalHandler):
"SAX driver for the Java SAX parsers."
def __init__(self, jdriver = None):
xmlreader.XMLReader.__init__(self)
self._parser = create_java_parser(jdriver)
self._parser.setFeature(feature_namespaces, 0)
self._parser.setFeature(feature_namespace_prefixes, 0)
self._parser.setContentHandler(self)
self._nsattrs = AttributesNSImpl()
self._attrs = AttributesImpl()
self.setEntityResolver(self.getEntityResolver())
self.setErrorHandler(self.getErrorHandler())
self.setDTDHandler(self.getDTDHandler())
try:
self._parser.setProperty("http://xml.org/sax/properties/lexical-handler", self)
except Exception, x:
pass
# XMLReader methods
def parse(self, source):
"Parse an XML document from a URL or an InputSource."
self._parser.parse(JyInputSourceWrapper(source))
def getFeature(self, name):
return self._parser.getFeature(name)
def setFeature(self, name, state):
self._parser.setFeature(name, state)
def getProperty(self, name):
return self._parser.getProperty(name)
def setProperty(self, name, value):
self._parser.setProperty(name, value)
def setEntityResolver(self, resolver):
self._parser.entityResolver = JyEntityResolverWrapper(resolver)
xmlreader.XMLReader.setEntityResolver(self, resolver)
def setErrorHandler(self, err_handler):
self._parser.errorHandler = JyErrorHandlerWrapper(err_handler)
xmlreader.XMLReader.setErrorHandler(self, err_handler)
def setDTDHandler(self, dtd_handler):
self._parser.setDTDHandler(JyDTDHandlerWrapper(dtd_handler))
xmlreader.XMLReader.setDTDHandler(self, dtd_handler)
# ContentHandler methods
def setDocumentLocator(self, locator):
self._cont_handler.setDocumentLocator(locator)
def startDocument(self):
self._cont_handler.startDocument()
self._namespaces = self._parser.getFeature(feature_namespaces)
def startElement(self, uri, lname, qname, attrs):
if self._namespaces:
self._nsattrs._attrs = attrs
self._cont_handler.startElementNS((uri or None, lname), qname,
self._nsattrs)
else:
self._attrs._attrs = attrs
self._cont_handler.startElement(qname, self._attrs)
def startPrefixMapping(self, prefix, uri):
self._cont_handler.startPrefixMapping(prefix, uri)
def characters(self, char, start, len):
self._cont_handler.characters(unicode(String(char, start, len)))
def ignorableWhitespace(self, char, start, len):
self._cont_handler.ignorableWhitespace(unicode(String(char, start,
len)))
def endElement(self, uri, lname, qname):
if self._namespaces:
self._cont_handler.endElementNS((uri or None, lname), qname)
else:
self._cont_handler.endElement(qname)
def endPrefixMapping(self, prefix):
self._cont_handler.endPrefixMapping(prefix)
def endDocument(self):
self._cont_handler.endDocument()
def processingInstruction(self, target, data):
self._cont_handler.processingInstruction(target, data)
# Lexical handler methods
def comment(self, char, start, len):
try:
# Need to wrap this in a try..except in case the parser does not support lexical events
self._cont_handler.comment(unicode(String(char, start, len)))
except:
pass
def startCDATA(self):
pass # TODO
def endCDATA(self):
pass # TODO
def startDTD(self, name, publicId, systemId):
pass # TODO
def endDTD(self):
pass # TODO
def startEntity(self, name):
pass # TODO
def endEntity(self, name):
pass # TODO
def _fixTuple(nsTuple, frm, to):
if len(nsTuple) == 2:
nsUri, localName = nsTuple
if nsUri == frm:
nsUri = to
return (nsUri, localName)
return nsTuple
def _makeJavaNsTuple(nsTuple):
return _fixTuple(nsTuple, None, '')
def _makePythonNsTuple(nsTuple):
return _fixTuple(nsTuple, '', None)
class AttributesImpl:
def __init__(self, attrs = None):
self._attrs = attrs
def getLength(self):
return self._attrs.getLength()
def getType(self, name):
return self._attrs.getType(_makeJavaNsTuple(name))
def getValue(self, name):
value = self._attrs.getValue(_makeJavaNsTuple(name))
if value == None:
raise KeyError(name)
return value
def getNames(self):
return [_makePythonNsTuple(self._attrs.getQName(index)) for index in range(len(self))]
def getQNames(self):
return [self._attrs.getQName(index) for index in range(len(self))]
def getValueByQName(self, qname):
idx = self._attrs.getIndex(qname)
if idx == -1:
raise KeyError, qname
return self._attrs.getValue(idx)
def getNameByQName(self, qname):
idx = self._attrs.getIndex(qname)
if idx == -1:
raise KeyError, qname
return qname
def getQNameByName(self, name):
idx = self._attrs.getIndex(_makeJavaNsTuple(name))
if idx == -1:
raise KeyError, name
return name
def __len__(self):
return self._attrs.getLength()
def __getitem__(self, name):
return self.getValue(name)
def keys(self):
return self.getNames()
def copy(self):
return self.__class__(self._attrs)
def items(self):
return [(name, self[name]) for name in self.getNames()]
def values(self):
return map(self.getValue, self.getNames())
def get(self, name, alt=None):
try:
return self.getValue(name)
except KeyError:
return alt
def has_key(self, name):
try:
self.getValue(name)
return True
except KeyError:
return False
# --- AttributesNSImpl
class AttributesNSImpl(AttributesImpl):
def __init__(self, attrs=None):
AttributesImpl.__init__(self, attrs)
def getType(self, name):
name = _makeJavaNsTuple(name)
return self._attrs.getType(name[0], name[1])
def getValue(self, name):
jname = _makeJavaNsTuple(name)
value = self._attrs.getValue(jname[0], jname[1])
if value == None:
raise KeyError(name)
return value
def getNames(self):
names = []
for idx in range(len(self)):
names.append(_makePythonNsTuple( (self._attrs.getURI(idx), self._attrs.getLocalName(idx)) ))
return names
def getNameByQName(self, qname):
idx = self._attrs.getIndex(qname)
if idx == -1:
raise KeyError, qname
return _makePythonNsTuple( (self._attrs.getURI(idx), self._attrs.getLocalName(idx)) )
def getQNameByName(self, name):
name = _makeJavaNsTuple(name)
idx = self._attrs.getIndex(name[0], name[1])
if idx == -1:
raise KeyError, name
return self._attrs.getQName(idx)
def getQNames(self):
return [self._attrs.getQName(idx) for idx in range(len(self))]
# ---
def create_java_parser(jdriver = None):
try:
if jdriver:
return XMLReaderFactory.createXMLReader(jdriver)
elif jaxp:
return factory.newSAXParser().getXMLReader()
else:
return XMLReaderFactory.createXMLReader()
except ParserConfigurationException, e:
raise _exceptions.SAXReaderNotAvailable(e.getMessage())
except javasax.SAXException, e:
raise _exceptions.SAXReaderNotAvailable(e.getMessage())
def create_parser(jdriver = None):
return JavaSAXParser(jdriver)