summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2012-04-05 20:45:11 +0200
committerStefan Behnel <stefan_ml@behnel.de>2012-04-05 20:45:11 +0200
commit1eb7c789f683f5d18b7ea2a2d0bb35f179c51452 (patch)
tree650dee33cf53d85e512da2d3bba3f97f8de79ec4 /src
parent6abdda77f824d487b93c945f2d534b8ca19d8f3f (diff)
downloadpython-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.pxd2
-rw-r--r--src/lxml/include/xmlparser.pxd4
-rw-r--r--src/lxml/include/xmlschema.pxd8
-rw-r--r--src/lxml/parser.pxi49
-rw-r--r--src/lxml/xmlerror.pxi7
-rw-r--r--src/lxml/xmlschema.pxi28
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: