diff options
| author | Stefan Behnel <stefan_ml@behnel.de> | 2012-04-05 20:45:11 +0200 |
|---|---|---|
| committer | Stefan Behnel <stefan_ml@behnel.de> | 2012-04-05 20:45:11 +0200 |
| commit | 1eb7c789f683f5d18b7ea2a2d0bb35f179c51452 (patch) | |
| tree | 650dee33cf53d85e512da2d3bba3f97f8de79ec4 /src | |
| parent | 6abdda77f824d487b93c945f2d534b8ca19d8f3f (diff) | |
| download | python-lxml-1eb7c789f683f5d18b7ea2a2d0bb35f179c51452.tar.gz | |
instead of a global setup, use execution local error callbacks for XMLSchema and parsing
Diffstat (limited to 'src')
| -rw-r--r-- | src/lxml/include/htmlparser.pxd | 2 | ||||
| -rw-r--r-- | src/lxml/include/xmlparser.pxd | 4 | ||||
| -rw-r--r-- | src/lxml/include/xmlschema.pxd | 8 | ||||
| -rw-r--r-- | src/lxml/parser.pxi | 49 | ||||
| -rw-r--r-- | src/lxml/xmlerror.pxi | 7 | ||||
| -rw-r--r-- | src/lxml/xmlschema.pxi | 28 |
6 files changed, 69 insertions, 29 deletions
diff --git a/src/lxml/include/htmlparser.pxd b/src/lxml/include/htmlparser.pxd index 488f7c66..ff0e54c1 100644 --- a/src/lxml/include/htmlparser.pxd +++ b/src/lxml/include/htmlparser.pxd @@ -14,6 +14,8 @@ cdef extern from "libxml/HTMLparser.h": HTML_PARSE_RECOVER # Relaxed parsing HTML_PARSE_COMPACT # compact small text nodes + xmlSAXHandler htmlDefaultSAXHandler + cdef xmlParserCtxt* htmlCreateMemoryParserCtxt( char* buffer, int size) nogil cdef xmlParserCtxt* htmlCreateFileParserCtxt( diff --git a/src/lxml/include/xmlparser.pxd b/src/lxml/include/xmlparser.pxd index 7b1eb5da..a405e663 100644 --- a/src/lxml/include/xmlparser.pxd +++ b/src/lxml/include/xmlparser.pxd @@ -1,6 +1,6 @@ from tree cimport xmlDoc, xmlNode, xmlDict, xmlDtd from tree cimport xmlInputReadCallback, xmlInputCloseCallback -from xmlerror cimport xmlError +from xmlerror cimport xmlError, xmlStructuredErrorFunc cdef extern from "libxml/parser.h": @@ -73,6 +73,8 @@ cdef extern from "libxml/tree.h": startDocumentSAXFunc startDocument endDocumentSAXFunc endDocument int initialized + xmlStructuredErrorFunc serror + void* _private cdef extern from "libxml/xmlIO.h": cdef xmlParserInputBuffer* xmlAllocParserInputBuffer(int enc) nogil diff --git a/src/lxml/include/xmlschema.pxd b/src/lxml/include/xmlschema.pxd index 626e601b..1526a369 100644 --- a/src/lxml/include/xmlschema.pxd +++ b/src/lxml/include/xmlschema.pxd @@ -1,5 +1,6 @@ -from xmlparser cimport xmlSAXHandler from tree cimport xmlDoc +from xmlparser cimport xmlSAXHandler +from xmlerror cimport xmlStructuredErrorFunc cdef extern from "libxml/xmlschemas.h": ctypedef struct xmlSchema @@ -12,6 +13,11 @@ cdef extern from "libxml/xmlschemas.h": XML_SCHEMA_VAL_VC_I_CREATE = 1 cdef xmlSchemaValidCtxt* xmlSchemaNewValidCtxt(xmlSchema* schema) nogil + cdef void xmlSchemaSetParserStructuredErrors(xmlSchemaParserCtxt* ctxt, + xmlStructuredErrorFunc serror, void *ctx) + cdef void xmlSchemaSetValidStructuredErrors(xmlSchemaValidCtxt* ctxt, + xmlStructuredErrorFunc serror, void *ctx) + cdef int xmlSchemaValidateDoc(xmlSchemaValidCtxt* ctxt, xmlDoc* doc) nogil cdef xmlSchema* xmlSchemaParse(xmlSchemaParserCtxt* ctxt) nogil cdef xmlSchemaParserCtxt* xmlSchemaNewParserCtxt(char* URL) nogil diff --git a/src/lxml/parser.pxi b/src/lxml/parser.pxi index b1b8e657..3bb6eb84 100644 --- a/src/lxml/parser.pxi +++ b/src/lxml/parser.pxi @@ -543,9 +543,10 @@ cdef class _ParserContext(_ResolverContext): self._lock, python.WAIT_LOCK) if result == 0: raise ParserError, u"parser locking failed" - self._error_log.connect() + self._error_log.clear() + self._c_ctxt.sax.serror = _receiveParserError if self._validator is not None: - self._validator.connect(self._c_ctxt) + self._validator.connect(self._c_ctxt, self._error_log) return 0 cdef int cleanup(self) except -1: @@ -553,7 +554,7 @@ cdef class _ParserContext(_ResolverContext): self._validator.disconnect() self._resetParserContext() self.clear() - self._error_log.disconnect() + self._c_ctxt.sax.serror = NULL if config.ENABLE_THREADING and self._lock is not NULL: python.PyThread_release_lock(self._lock) return 0 @@ -581,6 +582,16 @@ cdef _initParserContext(_ParserContext context, if c_ctxt is not NULL: context._initParserContext(c_ctxt) +cdef void _forwardParserError(xmlparser.xmlParserCtxt* _parser_context, xmlerror.xmlError* error) with gil: + (<_ParserContext>_parser_context._private)._error_log._receive(error) + +cdef void _receiveParserError(void* c_context, xmlerror.xmlError* error) nogil: + if __DEBUG: + if c_context is NULL or (<xmlparser.xmlParserCtxt*>c_context)._private is NULL: + _forwardError(NULL, error) + else: + _forwardParserError(<xmlparser.xmlParserCtxt*>c_context, error) + cdef int _raiseParseError(xmlparser.xmlParserCtxt* ctxt, filename, _ErrorLog error_log) except 0: if filename is not None and \ @@ -800,23 +811,41 @@ cdef class _BaseParser: context._setTarget(target) return context + cdef int _registerHtmlErrorHandler(self, xmlparser.xmlParserCtxt* c_ctxt) except -1: + cdef xmlparser.xmlSAXHandler* sax = c_ctxt.sax + if sax is not NULL and sax.initialized and sax.initialized != xmlparser.XML_SAX2_MAGIC: + # need to extend SAX1 context to SAX2 to get proper error reports + if sax is &htmlparser.htmlDefaultSAXHandler: + sax = <xmlparser.xmlSAXHandler*> stdlib.malloc(sizeof(xmlparser.xmlSAXHandler)) + if sax is NULL: + raise MemoryError() + cstring_h.memcpy(sax, &htmlparser.htmlDefaultSAXHandler, + sizeof(htmlparser.htmlDefaultSAXHandler)) + c_ctxt.sax = sax + sax.initialized = xmlparser.XML_SAX2_MAGIC + sax.serror = _receiveParserError + sax.startElementNs = NULL + sax.endElementNs = NULL + sax._private = NULL + return 0 + cdef xmlparser.xmlParserCtxt* _newParserCtxt(self): + cdef xmlparser.xmlParserCtxt* c_ctxt if self._for_html: - return htmlparser.htmlCreateMemoryParserCtxt('dummy', 5) + c_ctxt = htmlparser.htmlCreateMemoryParserCtxt('dummy', 5) + self._registerHtmlErrorHandler(c_ctxt) else: - return xmlparser.xmlNewParserCtxt() + c_ctxt = xmlparser.xmlNewParserCtxt() + return c_ctxt cdef xmlparser.xmlParserCtxt* _newPushParserCtxt(self): cdef xmlparser.xmlParserCtxt* c_ctxt - cdef char* c_filename - if self._filename is not None: - c_filename = _cstr(self._filename) - else: - c_filename = NULL + cdef char* c_filename = _cstr(self._filename) if self._filename is not None else NULL if self._for_html: c_ctxt = htmlparser.htmlCreatePushParserCtxt( NULL, NULL, NULL, 0, c_filename, tree.XML_CHAR_ENCODING_NONE) if c_ctxt is not NULL: + self._registerHtmlErrorHandler(c_ctxt) htmlparser.htmlCtxtUseOptions(c_ctxt, self._parse_options) else: c_ctxt = xmlparser.xmlCreatePushParserCtxt( diff --git a/src/lxml/xmlerror.pxi b/src/lxml/xmlerror.pxi index 9ca31424..0dea3b61 100644 --- a/src/lxml/xmlerror.pxi +++ b/src/lxml/xmlerror.pxi @@ -331,15 +331,16 @@ cdef class _ErrorLog(_ListErrorLog): def __init__(self): _ListErrorLog.__init__(self, [], None, None) - cdef void connect(self): + cdef int connect(self) except -1: self._first_error = None del self._entries[:] connectErrorLog(<void*>self) + return 0 cdef void disconnect(self): connectErrorLog(NULL) - def clear(self): + cpdef clear(self): self._first_error = None del self._entries[:] @@ -511,13 +512,11 @@ cdef void _forwardError(void* c_log_handler, xmlerror.xmlError* error) with gil: cdef void _receiveError(void* c_log_handler, xmlerror.xmlError* error) nogil: # no Python objects here, may be called without thread context ! - # when we declare a Python object, Pyrex will INCREF(None) ! if __DEBUG: _forwardError(c_log_handler, error) cdef void _receiveXSLTError(void* c_log_handler, char* msg, ...) nogil: # no Python objects here, may be called without thread context ! - # when we declare a Python object, Pyrex will INCREF(None) ! cdef xmlerror.xmlError c_error cdef cvarargs.va_list args cdef char* c_text diff --git a/src/lxml/xmlschema.pxi b/src/lxml/xmlschema.pxi index e7af9e6d..8044f331 100644 --- a/src/lxml/xmlschema.pxi +++ b/src/lxml/xmlschema.pxi @@ -65,22 +65,21 @@ cdef class XMLSchema(_Validator): raise XMLSchemaParseError, u"Document is not XML Schema" fake_c_doc = _fakeRootDoc(doc._c_doc, root_node._c_node) - self._error_log.connect() parser_ctxt = xmlschema.xmlSchemaNewDocParserCtxt(fake_c_doc) elif file is not None: if _isString(file): doc = None filename = _encodeFilename(file) - self._error_log.connect() parser_ctxt = xmlschema.xmlSchemaNewParserCtxt(_cstr(filename)) else: doc = _parseDocument(file, None, None) - self._error_log.connect() parser_ctxt = xmlschema.xmlSchemaNewDocParserCtxt(doc._c_doc) else: raise XMLSchemaParseError, u"No tree or file given" if parser_ctxt is not NULL: + xmlschema.xmlSchemaSetParserStructuredErrors( + parser_ctxt, _receiveError, <void*>self._error_log) if doc is None: with nogil: self._c_schema = xmlschema.xmlSchemaParse(parser_ctxt) @@ -96,8 +95,6 @@ cdef class XMLSchema(_Validator): if _LIBXML_VERSION_INT >= 20624: xmlschema.xmlSchemaFreeParserCtxt(parser_ctxt) - self._error_log.disconnect() - if fake_c_doc is not NULL: _destroyFakeDoc(doc._c_doc, fake_c_doc) @@ -132,16 +129,17 @@ cdef class XMLSchema(_Validator): doc = _documentOrRaise(etree) root_node = _rootNodeOrRaise(etree) - self._error_log.connect() valid_ctxt = xmlschema.xmlSchemaNewValidCtxt(self._c_schema) if valid_ctxt is NULL: - self._error_log.disconnect() - return python.PyErr_NoMemory() + raise MemoryError() if self._add_attribute_defaults: xmlschema.xmlSchemaSetValidOptions( valid_ctxt, xmlschema.XML_SCHEMA_VAL_VC_I_CREATE) + xmlschema.xmlSchemaSetValidStructuredErrors( + valid_ctxt, _receiveError, <void*>self._error_log) + c_doc = _fakeRootDoc(doc._c_doc, root_node._c_node) with nogil: ret = xmlschema.xmlSchemaValidateDoc(valid_ctxt, c_doc) @@ -149,7 +147,6 @@ cdef class XMLSchema(_Validator): xmlschema.xmlSchemaFreeValidCtxt(valid_ctxt) - self._error_log.disconnect() if ret == -1: raise XMLSchemaValidateError( u"Internal error in XML Schema validation.", @@ -198,16 +195,18 @@ cdef class _ParserSchemaValidationContext: with nogil: xmlschema.xmlSchemaValidateDoc(self._valid_ctxt, c_doc) - cdef int connect(self, xmlparser.xmlParserCtxt* c_ctxt) except -1: + cdef int connect(self, xmlparser.xmlParserCtxt* c_ctxt, _BaseErrorLog error_log) except -1: if self._valid_ctxt is NULL: self._valid_ctxt = xmlschema.xmlSchemaNewValidCtxt( self._schema._c_schema) if self._valid_ctxt is NULL: - return python.PyErr_NoMemory() + raise MemoryError() if self._add_default_attributes: xmlschema.xmlSchemaSetValidOptions( - self._valid_ctxt, - xmlschema.XML_SCHEMA_VAL_VC_I_CREATE) + self._valid_ctxt, xmlschema.XML_SCHEMA_VAL_VC_I_CREATE) + if error_log is not None: + xmlschema.xmlSchemaSetValidStructuredErrors( + self._valid_ctxt, _receiveError, <void*>error_log) self._sax_plug = xmlschema.xmlSchemaSAXPlug( self._valid_ctxt, &c_ctxt.sax, &c_ctxt.userData) @@ -215,6 +214,9 @@ cdef class _ParserSchemaValidationContext: if self._sax_plug is not NULL: xmlschema.xmlSchemaSAXUnplug(self._sax_plug) self._sax_plug = NULL + if self._valid_ctxt is not NULL: + xmlschema.xmlSchemaSetValidStructuredErrors( + self._valid_ctxt, NULL, NULL) cdef bint isvalid(self): if self._valid_ctxt is NULL: |
