patch from Stéphane Bidoul for better per context error message APIs
* xmlreader.c python/drv_libxml2.py python/generator.py
python/libxml.c python/libxml.py python/libxml_wrap.h
python/types.c: patch from Stéphane Bidoul for better per
context error message APIs
* python/tests/ctxterror.py python/tests/readererr.py:
update of the tests
Daniel
diff --git a/ChangeLog b/ChangeLog
index a43de44..2c5064c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Mon Jan 20 23:25:00 CET 2003 Daniel Veillard <daniel@veillard.com>
+
+ * xmlreader.c python/drv_libxml2.py python/generator.py
+ python/libxml.c python/libxml.py python/libxml_wrap.h
+ python/types.c: patch from Stéphane Bidoul for better per
+ context error message APIs
+ * python/tests/ctxterror.py python/tests/readererr.py:
+ update of the tests
+
Sun Jan 19 17:09:28 MST 2003 John Fleck <jfleck@inkstain.net>
* doc/guidelines.html
diff --git a/include/libxml/xmlreader.h b/include/libxml/xmlreader.h
index 53314b1..e9475a7 100644
--- a/include/libxml/xmlreader.h
+++ b/include/libxml/xmlreader.h
@@ -24,11 +24,11 @@
} xmlParserProperties;
typedef enum {
- XMLREADER_SEVERITY_VALIDITY_WARNING = 1,
- XMLREADER_SEVERITY_VALIDITY_ERROR = 2,
- XMLREADER_SEVERITY_WARNING = 3,
- XMLREADER_SEVERITY_ERROR = 4
-} xmlReaderSeverities;
+ XML_PARSER_SEVERITY_VALIDITY_WARNING = 1,
+ XML_PARSER_SEVERITY_VALIDITY_ERROR = 2,
+ XML_PARSER_SEVERITY_WARNING = 3,
+ XML_PARSER_SEVERITY_ERROR = 4
+} xmlParserSeverities;
typedef struct _xmlTextReader xmlTextReader;
typedef xmlTextReader *xmlTextReaderPtr;
@@ -110,12 +110,14 @@
/*
* Error handling extensions
*/
-typedef void (*xmlTextReaderErrorFunc) (void *arg,
+typedef void * xmlTextReaderLocatorPtr;
+typedef void (*xmlTextReaderErrorFunc) (void *arg,
const char *msg,
- int line,
- int col,
- const char *URI,
- xmlReaderSeverities severity);
+ xmlParserSeverities severity,
+ xmlTextReaderLocatorPtr locator);
+int xmlTextReaderLocatorLineNumber (xmlTextReaderLocatorPtr locator);
+/*int xmlTextReaderLocatorLinePosition(xmlTextReaderLocatorPtr locator);*/
+xmlChar * xmlTextReaderLocatorBaseURI (xmlTextReaderLocatorPtr locator);
void xmlTextReaderSetErrorHandler (xmlTextReaderPtr reader,
xmlTextReaderErrorFunc f,
void *arg);
diff --git a/python/drv_libxml2.py b/python/drv_libxml2.py
index c9951e6..977c868 100644
--- a/python/drv_libxml2.py
+++ b/python/drv_libxml2.py
@@ -9,10 +9,10 @@
CAVEATS
- Lexical handlers are supported, except for start/endEntity
(waiting for XmlReader.ResolveEntity) and start/endDTD
- - as understand it, libxml2 error handlers are globals (per thread);
- each call to parse() registers a new error handler,
- overwriting any previously registered handler
- --> you can't have 2 LibXml2Reader active at the same time
+ - Error callbacks are not exactly synchronous, they tend
+ to be invoked before the corresponding content callback,
+ because the underlying reader interface parses
+ data by chunks of 512 bytes
TODO
- search for TODO
@@ -34,7 +34,7 @@
"""
__author__ = u"Stéphane Bidoul <sbi@skynet.be>"
-__version__ = "0.2"
+__version__ = "0.3"
import codecs
import sys
@@ -69,15 +69,27 @@
raise SAXReaderNotAvailable("libxml2 not available: " \
"import error was: %s" % e)
-def _registerErrorHandler(handler):
- if not sys.modules.has_key('libxslt'):
- # normal behaviour when libxslt is not imported
- libxml2.registerErrorHandler(handler,"drv_libxml2")
- else:
- # when libxslt is imported, one must
- # use libxst's error handler instead (see libxml2 bug 102181)
- import libxslt
- libxslt.registerErrorHandler(handler,"drv_libxml2")
+class Locator(xmlreader.Locator):
+ """SAX Locator adapter for libxml2.xmlTextReaderLocator"""
+
+ def __init__(self,locator):
+ self.__locator = locator
+
+ def getColumnNumber(self):
+ "Return the column number where the current event ends."
+ return -1
+
+ def getLineNumber(self):
+ "Return the line number where the current event ends."
+ return self.__locator.LineNumber()
+
+ def getPublicId(self):
+ "Return the public identifier for the current event."
+ return None
+
+ def getSystemId(self):
+ "Return the system identifier for the current event."
+ return self.__locator.BaseURI()
class LibXml2Reader(xmlreader.XMLReader):
@@ -95,21 +107,30 @@
# error messages accumulator
self.__errors = None
- def _errorHandler(self,ctx,str):
+ def _errorHandler(self,arg,msg,severity,locator):
if self.__errors is None:
self.__errors = []
- self.__errors.append(str)
+ self.__errors.append((severity,
+ SAXParseException(msg,None,
+ Locator(locator))))
- def _reportError(self,callback):
- # TODO: use SAXParseException, but we need a Locator for that
- # TODO: distinguish warnings from errors
- msg = "".join(self.__errors)
+ def _reportErrors(self,fatal):
+ for severity,exception in self.__errors:
+ if severity in (libxml2.PARSER_SEVERITY_VALIDITY_WARNING,
+ libxml2.PARSER_SEVERITY_WARNING):
+ self._err_handler.warning(exception)
+ else:
+ # when fatal is set, the parse will stop;
+ # we consider that the last error reported
+ # is the fatal one.
+ if fatal and exception is self.__errors[-1][1]:
+ self._err_handler.fatalError(exception)
+ else:
+ self._err_handler.error(exception)
self.__errors = None
- callback(SAXException(msg))
def parse(self, source):
self.__parsing = 1
- _registerErrorHandler(self._errorHandler)
try:
# prepare source and create reader
if type(source) in StringTypes:
@@ -118,6 +139,7 @@
source = saxutils.prepare_input_source(source)
input = libxml2.inputBuffer(source.getByteStream())
reader = input.newTextReader(source.getSystemId())
+ reader.SetErrorHandler(self._errorHandler,None)
# configure reader
reader.SetParserProp(libxml2.PARSER_LOADDTD,1)
reader.SetParserProp(libxml2.PARSER_DEFAULTATTRS,1)
@@ -137,21 +159,18 @@
# check for errors
if r == 1:
if not self.__errors is None:
- # non-fatal error
- self._reportError(self._err_handler.error)
+ self._reportErrors(0)
elif r == 0:
if not self.__errors is None:
- # non-fatal error
- self._reportError(self._err_handler.error)
- break
+ self._reportErrors(0)
+ break # end of parse
else:
- # fatal error
if not self.__errors is None:
- self._reportError(self._err_handler.fatalError)
+ self._reportErrors(1)
else:
self._err_handler.fatalError(\
SAXException("Read failed (no details available)"))
- break
+ break # fatal parse error
# get node type
nodeType = reader.NodeType()
# Element
@@ -180,6 +199,7 @@
_d(reader.LocalName()))
qnames[attName] = qname
attrs[attName] = value
+ reader.MoveToElement()
self._cont_handler.startElementNS( \
eltName,eltQName,attributesNSImpl)
if reader.IsEmptyElement():
@@ -194,6 +214,7 @@
while reader.MoveToNextAttribute():
attName = _d(reader.Name())
attrs[attName] = _d(reader.Value())
+ reader.MoveToElement()
self._cont_handler.startElement( \
eltName,attributesImpl)
if reader.IsEmptyElement():
@@ -275,7 +296,6 @@
reader.Close()
finally:
self.__parsing = 0
- # TODO: unregister error handler?
def setDTDHandler(self, handler):
# TODO (when supported, the inherited method works just fine)
diff --git a/python/generator.py b/python/generator.py
index cc1b41b..20e89b7 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -271,6 +271,7 @@
'xmlOutputBufferPtr': ('O', "outputBuffer", "xmlOutputBufferPtr", "xmlOutputBufferPtr"),
'xmlParserInputBufferPtr': ('O', "inputBuffer", "xmlParserInputBufferPtr", "xmlParserInputBufferPtr"),
'xmlRegexpPtr': ('O', "xmlReg", "xmlRegexpPtr", "xmlRegexpPtr"),
+ 'xmlTextReaderLocatorPtr': ('O', "xmlTextReaderLocator", "xmlTextReaderLocatorPtr", "xmlTextReaderLocatorPtr"),
'xmlTextReaderPtr': ('O', "xmlTextReader", "xmlTextReaderPtr", "xmlTextReaderPtr"),
}
@@ -602,6 +603,7 @@
"xmlOutputBufferPtr": ("._o", "outputBuffer(_obj=%s)", "outputBuffer"),
"xmlParserInputBufferPtr": ("._o", "inputBuffer(_obj=%s)", "inputBuffer"),
"xmlRegexpPtr": ("._o", "xmlReg(_obj=%s)", "xmlReg"),
+ "xmlTextReaderLocatorPtr": ("._o", "xmlTextReaderLocator(_obj=%s)", "xmlTextReaderLocator"),
"xmlTextReaderPtr": ("._o", "xmlTextReader(_obj=%s)", "xmlTextReader"),
}
@@ -690,6 +692,8 @@
func = "regexp" + name[9:]
elif name[0:6] == "xmlReg" and file == "xmlregexp":
func = "regexp" + name[6:]
+ elif name[0:20] == "xmlTextReaderLocator" and file == "xmlreader":
+ func = name[20:]
elif name[0:13] == "xmlTextReader" and file == "xmlreader":
func = name[13:]
elif name[0:11] == "xmlACatalog":
diff --git a/python/libxml.c b/python/libxml.c
index a762ac7..0603950 100644
--- a/python/libxml.c
+++ b/python/libxml.c
@@ -1177,32 +1177,6 @@
return (Py_None);
}
-PyObject *
-libxml_xmlFreeParserCtxt(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) {
- xmlParserCtxtPtr ctxt;
- PyObject *pyobj_ctxt;
- xmlParserCtxtPyCtxtPtr pyCtxt;
-
- if (!PyArg_ParseTuple(args, (char *)"O:xmlFreeParserCtxt", &pyobj_ctxt))
- return(NULL);
- ctxt = (xmlParserCtxtPtr) PyparserCtxt_Get(pyobj_ctxt);
-
- if (ctxt != NULL) {
- pyCtxt = (xmlParserCtxtPyCtxtPtr)((xmlParserCtxtPtr)ctxt)->_private;
- if (pyCtxt) {
- Py_XDECREF(pyCtxt->errorFunc);
- Py_XDECREF(pyCtxt->errorFuncArg);
- Py_XDECREF(pyCtxt->warningFunc);
- Py_XDECREF(pyCtxt->warningFuncArg);
- xmlFree(pyCtxt);
- }
- xmlFreeParserCtxt(ctxt);
- }
-
- Py_INCREF(Py_None);
- return(Py_None);
-}
-
/************************************************************************
* *
* Error message callback *
@@ -1332,44 +1306,87 @@
* *
************************************************************************/
-static void
-libxml_xmlParserCtxtErrorFuncHandler(void *ctxt, const char *msg, ...)
+typedef struct
{
- char *str;
- va_list ap;
+ PyObject *f;
+ PyObject *arg;
+} xmlParserCtxtPyCtxt;
+typedef xmlParserCtxtPyCtxt *xmlParserCtxtPyCtxtPtr;
+
+static void
+libxml_xmlParserCtxtGenericErrorFuncHandler(void *ctx, int severity, char *str)
+{
PyObject *list;
- PyObject *message;
PyObject *result;
+ xmlParserCtxtPtr ctxt;
xmlParserCtxtPyCtxtPtr pyCtxt;
#ifdef DEBUG_ERROR
- printf("libxml_xmlParserCtxtErrorFuncHandler(%p, %s, ...) called\n", ctx, msg);
+ printf("libxml_xmlParserCtxtGenericErrorFuncHandler(%p, %s, ...) called\n", ctx, msg);
#endif
- pyCtxt = (xmlParserCtxtPyCtxtPtr)((xmlParserCtxtPtr)ctxt)->_private;
+ ctxt = (xmlParserCtxtPtr)ctx;
+ pyCtxt = (xmlParserCtxtPyCtxtPtr)ctxt->_private;
- if (pyCtxt->errorFunc == NULL) {
- va_start(ap, msg);
- vfprintf(stdout, msg, ap);
- va_end(ap);
- } else {
- va_start(ap, msg);
- str = libxml_buildMessage(msg,ap);
- va_end(ap);
-
- list = PyTuple_New(2);
- PyTuple_SetItem(list, 0, pyCtxt->errorFuncArg);
- Py_XINCREF(pyCtxt->errorFuncArg);
- message = libxml_charPtrWrap(str);
- PyTuple_SetItem(list, 1, message);
- result = PyEval_CallObject(pyCtxt->errorFunc, list);
- Py_XDECREF(list);
- Py_XDECREF(result);
+ list = PyTuple_New(4);
+ PyTuple_SetItem(list, 0, pyCtxt->arg);
+ Py_XINCREF(pyCtxt->arg);
+ PyTuple_SetItem(list, 1, libxml_charPtrWrap(str));
+ PyTuple_SetItem(list, 2, libxml_intWrap(severity));
+ PyTuple_SetItem(list, 3, Py_None);
+ Py_INCREF(Py_None);
+ result = PyEval_CallObject(pyCtxt->f, list);
+ if (result == NULL)
+ {
+ /* TODO: manage for the exception to be propagated... */
+ PyErr_Print();
}
+ Py_XDECREF(list);
+ Py_XDECREF(result);
+}
+
+static void
+libxml_xmlParserCtxtErrorFuncHandler(void *ctx, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ libxml_xmlParserCtxtGenericErrorFuncHandler(ctx,XML_PARSER_SEVERITY_ERROR,libxml_buildMessage(msg,ap));
+ va_end(ap);
+}
+
+static void
+libxml_xmlParserCtxtWarningFuncHandler(void *ctx, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ libxml_xmlParserCtxtGenericErrorFuncHandler(ctx,XML_PARSER_SEVERITY_WARNING,libxml_buildMessage(msg,ap));
+ va_end(ap);
+}
+
+static void
+libxml_xmlParserCtxtValidityErrorFuncHandler(void *ctx, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ libxml_xmlParserCtxtGenericErrorFuncHandler(ctx,XML_PARSER_SEVERITY_VALIDITY_ERROR,libxml_buildMessage(msg,ap));
+ va_end(ap);
+}
+
+static void
+libxml_xmlParserCtxtValidityWarningFuncHandler(void *ctx, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ libxml_xmlParserCtxtGenericErrorFuncHandler(ctx,XML_PARSER_SEVERITY_VALIDITY_WARNING,libxml_buildMessage(msg,ap));
+ va_end(ap);
}
PyObject *
-libxml_xmlSetParserCtxtErrorHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args)
+libxml_xmlParserCtxtSetErrorHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args)
{
PyObject *py_retval;
xmlParserCtxtPtr ctxt;
@@ -1378,7 +1395,7 @@
PyObject *pyobj_f;
PyObject *pyobj_arg;
- if (!PyArg_ParseTuple(args, (char *)"OOO:xmlSetParserCtxtErrorHandler",
+ if (!PyArg_ParseTuple(args, (char *)"OOO:xmlParserCtxtSetErrorHandler",
&pyobj_ctxt, &pyobj_f, &pyobj_arg))
return(NULL);
ctxt = (xmlParserCtxtPtr) PyparserCtxt_Get(pyobj_ctxt);
@@ -1392,99 +1409,88 @@
ctxt->_private = pyCtxt;
}
else {
- pyCtxt = ctxt->_private;
+ pyCtxt = (xmlParserCtxtPyCtxtPtr)ctxt->_private;
}
/* TODO: check f is a function ! */
- Py_XDECREF(pyCtxt->errorFunc);
+ Py_XDECREF(pyCtxt->f);
Py_XINCREF(pyobj_f);
- pyCtxt->errorFunc = pyobj_f;
- Py_XDECREF(pyCtxt->errorFuncArg);
+ pyCtxt->f = pyobj_f;
+ Py_XDECREF(pyCtxt->arg);
Py_XINCREF(pyobj_arg);
- pyCtxt->errorFuncArg = pyobj_arg;
+ pyCtxt->arg = pyobj_arg;
- ctxt->sax->error = libxml_xmlParserCtxtErrorFuncHandler;
- ctxt->vctxt.error = libxml_xmlParserCtxtErrorFuncHandler;
+ if (pyobj_f != Py_None) {
+ ctxt->sax->error = libxml_xmlParserCtxtErrorFuncHandler;
+ ctxt->sax->warning = libxml_xmlParserCtxtWarningFuncHandler;
+ ctxt->vctxt.error = libxml_xmlParserCtxtValidityErrorFuncHandler;
+ ctxt->vctxt.warning = libxml_xmlParserCtxtValidityWarningFuncHandler;
+ }
+ else {
+ ctxt->sax->error = xmlParserError;
+ ctxt->vctxt.error = xmlParserValidityError;
+ ctxt->sax->warning = xmlParserWarning;
+ ctxt->vctxt.warning = xmlParserValidityWarning;
+ }
py_retval = libxml_intWrap(1);
return(py_retval);
}
-static void
-libxml_xmlParserCtxtWarningFuncHandler(void *ctxt, const char *msg, ...)
-{
- char *str;
- va_list ap;
- PyObject *list;
- PyObject *message;
- PyObject *result;
- xmlParserCtxtPyCtxtPtr pyCtxt;
-
-#ifdef DEBUG_ERROR
- printf("libxml_xmlParserCtxtWarningFuncHandler(%p, %s, ...) called\n", ctx, msg);
-#endif
-
- pyCtxt = (xmlParserCtxtPyCtxtPtr)((xmlParserCtxtPtr)ctxt)->_private;
-
- if (pyCtxt->warningFunc == NULL) {
- va_start(ap, msg);
- vfprintf(stdout, msg, ap);
- va_end(ap);
- } else {
- va_start(ap, msg);
- str = libxml_buildMessage(msg,ap);
- va_end(ap);
-
- list = PyTuple_New(2);
- PyTuple_SetItem(list, 0, pyCtxt->warningFuncArg);
- Py_XINCREF(pyCtxt->warningFuncArg);
- message = libxml_charPtrWrap(str);
- PyTuple_SetItem(list, 1, message);
- result = PyEval_CallObject(pyCtxt->warningFunc, list);
- Py_XDECREF(list);
- Py_XDECREF(result);
- }
-}
-
PyObject *
-libxml_xmlSetParserCtxtWarningHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args)
+libxml_xmlParserCtxtGetErrorHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args)
{
PyObject *py_retval;
xmlParserCtxtPtr ctxt;
xmlParserCtxtPyCtxtPtr pyCtxt;
PyObject *pyobj_ctxt;
- PyObject *pyobj_f;
- PyObject *pyobj_arg;
- if (!PyArg_ParseTuple(args, (char *)"OOO:xmlSetParserCtxtWarningHandler", &pyobj_ctxt, &pyobj_f, &pyobj_arg))
+ if (!PyArg_ParseTuple(args, (char *)"O:xmlParserCtxtGetErrorHandler",
+ &pyobj_ctxt))
return(NULL);
ctxt = (xmlParserCtxtPtr) PyparserCtxt_Get(pyobj_ctxt);
- if (ctxt->_private == NULL) {
- pyCtxt = xmlMalloc(sizeof(xmlParserCtxtPyCtxt));
- if (pyCtxt == NULL) {
- py_retval = libxml_intWrap(-1);
- return(py_retval);
- }
- memset(pyCtxt,0,sizeof(xmlParserCtxtPyCtxt));
- ctxt->_private = pyCtxt;
+ py_retval = PyTuple_New(2);
+ if (ctxt->_private != NULL) {
+ pyCtxt = (xmlParserCtxtPyCtxtPtr)ctxt->_private;
+
+ PyTuple_SetItem(py_retval, 0, pyCtxt->f);
+ Py_XINCREF(pyCtxt->f);
+ PyTuple_SetItem(py_retval, 1, pyCtxt->arg);
+ Py_XINCREF(pyCtxt->arg);
}
else {
- pyCtxt = ctxt->_private;
+ /* no python error handler registered */
+ PyTuple_SetItem(py_retval, 0, Py_None);
+ Py_XINCREF(Py_None);
+ PyTuple_SetItem(py_retval, 1, Py_None);
+ Py_XINCREF(Py_None);
}
- /* TODO: check f is a function ! */
- Py_XDECREF(pyCtxt->warningFunc);
- Py_XINCREF(pyobj_f);
- pyCtxt->warningFunc = pyobj_f;
- Py_XDECREF(pyCtxt->warningFuncArg);
- Py_XINCREF(pyobj_arg);
- pyCtxt->warningFuncArg = pyobj_arg;
-
- ctxt->sax->warning = libxml_xmlParserCtxtWarningFuncHandler;
- ctxt->vctxt.warning = libxml_xmlParserCtxtWarningFuncHandler;
-
- py_retval = libxml_intWrap(1);
return(py_retval);
}
+PyObject *
+libxml_xmlFreeParserCtxt(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) {
+ xmlParserCtxtPtr ctxt;
+ PyObject *pyobj_ctxt;
+ xmlParserCtxtPyCtxtPtr pyCtxt;
+
+ if (!PyArg_ParseTuple(args, (char *)"O:xmlFreeParserCtxt", &pyobj_ctxt))
+ return(NULL);
+ ctxt = (xmlParserCtxtPtr) PyparserCtxt_Get(pyobj_ctxt);
+
+ if (ctxt != NULL) {
+ pyCtxt = (xmlParserCtxtPyCtxtPtr)((xmlParserCtxtPtr)ctxt)->_private;
+ if (pyCtxt) {
+ Py_XDECREF(pyCtxt->f);
+ Py_XDECREF(pyCtxt->arg);
+ xmlFree(pyCtxt);
+ }
+ xmlFreeParserCtxt(ctxt);
+ }
+
+ Py_INCREF(Py_None);
+ return(Py_None);
+}
+
/************************************************************************
* *
* Per xmlTextReader error handler *
@@ -1501,27 +1507,23 @@
static void
libxml_xmlTextReaderErrorCallback(void *arg,
const char *msg,
- int line,
- int col,
- const char *URI,
- int severity)
+ int severity,
+ xmlTextReaderLocatorPtr locator)
{
xmlTextReaderPyCtxt *pyCtxt = (xmlTextReaderPyCtxt *)arg;
PyObject *list;
PyObject *result;
- list = PyTuple_New(6);
+ list = PyTuple_New(4);
PyTuple_SetItem(list, 0, pyCtxt->arg);
Py_XINCREF(pyCtxt->arg);
PyTuple_SetItem(list, 1, libxml_charPtrConstWrap(msg));
- PyTuple_SetItem(list, 2, libxml_intWrap(line));
- PyTuple_SetItem(list, 3, libxml_intWrap(col));
- PyTuple_SetItem(list, 4, libxml_charPtrConstWrap(URI));
- PyTuple_SetItem(list, 5, libxml_intWrap(severity));
+ PyTuple_SetItem(list, 2, libxml_intWrap(severity));
+ PyTuple_SetItem(list, 3, libxml_xmlTextReaderLocatorPtrWrap(locator));
result = PyEval_CallObject(pyCtxt->f, list);
if (result == NULL)
{
- /* TODO: manage for the exception to be go up... */
+ /* TODO: manage for the exception to be propagated... */
PyErr_Print();
}
Py_XDECREF(list);
@@ -2558,8 +2560,8 @@
{(char *) "inputBufferCreate", libxml_xmlCreateInputBuffer, METH_VARARGS, NULL},
{(char *) "setEntityLoader", libxml_xmlSetEntityLoader, METH_VARARGS, NULL},
{(char *)"xmlRegisterErrorHandler", libxml_xmlRegisterErrorHandler, METH_VARARGS, NULL },
- {(char *)"xmlSetParserCtxtErrorHandler", libxml_xmlSetParserCtxtErrorHandler, METH_VARARGS, NULL },
- {(char *)"xmlSetParserCtxtWarningHandler", libxml_xmlSetParserCtxtWarningHandler, METH_VARARGS, NULL },
+ {(char *)"xmlParserCtxtSetErrorHandler", libxml_xmlParserCtxtSetErrorHandler, METH_VARARGS, NULL },
+ {(char *)"xmlParserCtxtGetErrorHandler", libxml_xmlParserCtxtGetErrorHandler, METH_VARARGS, NULL },
{(char *)"xmlFreeParserCtxt", libxml_xmlFreeParserCtxt, METH_VARARGS, NULL },
{(char *)"xmlTextReaderSetErrorHandler", libxml_xmlTextReaderSetErrorHandler, METH_VARARGS, NULL },
{(char *)"xmlTextReaderGetErrorHandler", libxml_xmlTextReaderGetErrorHandler, METH_VARARGS, NULL },
diff --git a/python/libxml.py b/python/libxml.py
index 8f9185c..8ffa383 100644
--- a/python/libxml.py
+++ b/python/libxml.py
@@ -462,12 +462,12 @@
PARSER_SUBST_ENTITIES=4
#
-# For the xmlTextReader error severities
+# For the error callback severities
#
-XMLREADER_SEVERITY_VALIDITY_WARNING=1
-XMLREADER_SEVERITY_VALIDITY_ERROR=2
-XMLREADER_SEVERITY_WARNING=3
-XMLREADER_SEVERITY_ERROR=4
+PARSER_SEVERITY_VALIDITY_WARNING=1
+PARSER_SEVERITY_VALIDITY_ERROR=2
+PARSER_SEVERITY_WARNING=3
+PARSER_SEVERITY_ERROR=4
#
# register the libxml2 error handler
@@ -499,11 +499,21 @@
libxml2mod.xmlFreeParserCtxt(self._o)
self._o = None
- def registerErrorHandler(self,f,arg):
- libxml2mod.xmlSetParserCtxtErrorHandler(self._o,f,arg)
+ def setErrorHandler(self,f,arg):
+ """Register an error handler that will be called back as
+ f(arg,msg,severity,reserved).
+
+ @reserved is currently always None."""
+ libxml2mod.xmlParserCtxtSetErrorHandler(self._o,f,arg)
- def registerWarningHandler(self,f,arg):
- libxml2mod.xmlSetParserCtxtWarningHandler(self._o,f,arg)
+ def getErrorHandler(self):
+ """Return (f,arg) as previously registered with setErrorHandler
+ or (None,None)."""
+ return libxml2mod.xmlParserCtxtGetErrorHandler(self._o)
+
+def _xmlTextReaderErrorFunc((f,arg),msg,severity,locator):
+ """Intermediate callback to wrap the locator"""
+ return f(arg,msg,severity,xmlTextReaderLocator(locator))
class xmlTextReaderCore:
@@ -517,15 +527,25 @@
libxml2mod.xmlFreeTextReader(self._o)
self._o = None
- def setErrorHandler(self,f,arg):
+ def SetErrorHandler(self,f,arg):
"""Register an error handler that will be called back as
- f(arg,msg,line,col,URI,severity)."""
- libxml2mod.xmlTextReaderSetErrorHandler(self._o,f,arg)
+ f(arg,msg,severity,locator)."""
+ if f is None:
+ libxml2mod.xmlTextReaderSetErrorHandler(\
+ self._o,None,None)
+ else:
+ libxml2mod.xmlTextReaderSetErrorHandler(\
+ self._o,_xmlTextReaderErrorFunc,(f,arg))
- def getErrorHandler(self):
+ def GetErrorHandler(self):
"""Return (f,arg) as previously registered with setErrorHandler
or (None,None)."""
- return libxml2mod.xmlTextReaderGetErrorHandler(self._o)
+ f,arg = libxml2mod.xmlTextReaderGetErrorHandler(self._o)
+ if f is None:
+ return None,None
+ else:
+ # assert f is _xmlTextReaderErrorFunc
+ return arg
# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
#
diff --git a/python/libxml_wrap.h b/python/libxml_wrap.h
index c8730ca..c59b706 100644
--- a/python/libxml_wrap.h
+++ b/python/libxml_wrap.h
@@ -93,6 +93,14 @@
xmlTextReaderPtr obj;
} PyxmlTextReader_Object;
+#define PyxmlTextReaderLocator_Get(v) (((v) == Py_None) ? NULL : \
+ (((PyxmlTextReaderLocator_Object *)(v))->obj))
+
+typedef struct {
+ PyObject_HEAD
+ xmlTextReaderLocatorPtr obj;
+} PyxmlTextReaderLocator_Object;
+
#define PyURI_Get(v) (((v) == Py_None) ? NULL : \
(((PyURI_Object *)(v))->obj))
@@ -147,19 +155,6 @@
PyObject * libxml_xmlParserInputBufferPtrWrap(xmlParserInputBufferPtr buffer);
PyObject * libxml_xmlRegexpPtrWrap(xmlRegexpPtr regexp);
PyObject * libxml_xmlTextReaderPtrWrap(xmlTextReaderPtr reader);
+PyObject * libxml_xmlTextReaderLocatorPtrWrap(xmlTextReaderLocatorPtr locator);
xmlXPathObjectPtr libxml_xmlXPathObjectPtrConvert(PyObject * obj);
-
-/*
- * Data structure that makes the link from the parser context
- * to the python wrapper.
- */
-typedef struct
-{
- PyObject *errorFunc;
- PyObject *errorFuncArg;
- PyObject *warningFunc;
- PyObject *warningFuncArg;
-} xmlParserCtxtPyCtxt;
-typedef xmlParserCtxtPyCtxt *xmlParserCtxtPyCtxtPtr;
-
diff --git a/python/tests/ctxterror.py b/python/tests/ctxterror.py
index 44589cd..265bb1e 100755
--- a/python/tests/ctxterror.py
+++ b/python/tests/ctxterror.py
@@ -9,20 +9,22 @@
# Memory debug specific
libxml2.debugMemory(1)
-expect="""--> Opening and ending tag mismatch: x and y
+expect="""--> (3) xmlns: URI foo is not absolute
+--> (4) Opening and ending tag mismatch: x and y
"""
err=""
-def callback(ctx, str):
- global err
+def callback(arg,msg,severity,reserved):
+ global err
+ err = err + "%s (%d) %s" % (arg,severity,msg)
- err = err + "%s %s" % (ctx, str)
-
-s = """<x></y>"""
+s = """<x xmlns="foo"></y>"""
parserCtxt = libxml2.createPushParser(None,"",0,"test.xml")
-parserCtxt.registerErrorHandler(callback, "-->")
-parserCtxt.registerWarningHandler(callback, "-->")
+parserCtxt.setErrorHandler(callback, "-->")
+if parserCtxt.getErrorHandler() != (callback,"-->"):
+ print "getErrorHandler failed"
+ sys.exit(1)
parserCtxt.parseChunk(s,len(s),1)
doc = parserCtxt.doc()
doc.freeDoc()
@@ -37,8 +39,7 @@
i = 10000
while i > 0:
parserCtxt = libxml2.createPushParser(None,"",0,"test.xml")
- parserCtxt.registerErrorHandler(callback, "-->")
- parserCtxt.registerWarningHandler(callback, "-->")
+ parserCtxt.setErrorHandler(callback, "-->")
parserCtxt.parseChunk(s,len(s),1)
doc = parserCtxt.doc()
doc.freeDoc()
diff --git a/python/tests/readererr.py b/python/tests/readererr.py
index abbbba5..dbdeb47 100644
--- a/python/tests/readererr.py
+++ b/python/tests/readererr.py
@@ -13,14 +13,14 @@
--> (4) test1:1:Opening and ending tag mismatch: c and a
"""
err=""
-def myErrorHandler(arg,msg,line,col,URI,severity):
+def myErrorHandler(arg,msg,severity,locator):
global err
- err = err + "%s (%d) %s:%d:%s" % (arg,severity,URI,line,msg)
+ err = err + "%s (%d) %s:%d:%s" % (arg,severity,locator.BaseURI(),locator.LineNumber(),msg)
f = StringIO.StringIO("""<a xmlns="foo"><b b1="b1"/><c>content of c</a>""")
input = libxml2.inputBuffer(f)
reader = input.newTextReader("test1")
-reader.setErrorHandler(myErrorHandler,"-->")
+reader.SetErrorHandler(myErrorHandler,"-->")
while reader.Read() == 1:
pass
@@ -30,9 +30,9 @@
print "expected %s" %(expect)
sys.exit(1)
-reader.setErrorHandler(None,None)
-if reader.getErrorHandler() != (None,None):
- print "getErrorHandler failed"
+reader.SetErrorHandler(None,None)
+if reader.GetErrorHandler() != (None,None):
+ print "GetErrorHandler failed"
sys.exit(1)
#
diff --git a/python/types.c b/python/types.c
index 6562620..a05c48a 100644
--- a/python/types.c
+++ b/python/types.c
@@ -566,3 +566,22 @@
(char *) "xmlTextReaderPtr", NULL);
return (ret);
}
+
+PyObject *
+libxml_xmlTextReaderLocatorPtrWrap(xmlTextReaderLocatorPtr locator)
+{
+ PyObject *ret;
+
+#ifdef DEBUG
+ printf("libxml_xmlTextReaderLocatorPtrWrap: locator = %p\n", locator);
+#endif
+ if (locator == NULL) {
+ Py_INCREF(Py_None);
+ return (Py_None);
+ }
+ ret =
+ PyCObject_FromVoidPtrAndDesc((void *) locator,
+ (char *) "xmlTextReaderLocatorPtr", NULL);
+ return (ret);
+}
+
diff --git a/win32/libxml2.def.src b/win32/libxml2.def.src
index 8d2a957..5023927 100644
--- a/win32/libxml2.def.src
+++ b/win32/libxml2.def.src
@@ -1219,6 +1219,9 @@
/* Error handling extensions */
xmlTextReaderSetErrorHandler
xmlTextReaderGetErrorHandler
+ xmlTextReaderLocatorLineNumber
+ /*xmlTextReaderLocatorLinePosition*/
+ xmlTextReaderLocatorBaseURI
diff --git a/xmlreader.c b/xmlreader.c
index 9ae4b6e..3632376 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -2281,6 +2281,74 @@
return str;
}
+/**
+ * xmlTextReaderLocatorLineNumber
+ * @locator: the xmlTextReaderLocatorPtr used
+ *
+ * Obtain the line number for the given locator.
+ *
+ * Returns the line number or -1 in case of error.
+ */
+int
+xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
+ /* we know that locator is a xmlParserCtxtPtr */
+ xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
+ int ret = -1;
+
+ if (ctx->node != NULL) {
+ ret = xmlGetLineNo(ctx->node);
+ }
+ else {
+ /* inspired from error.c */
+ xmlParserInputPtr input;
+ input = ctx->input;
+ if ((input->filename == NULL) && (ctx->inputNr > 1))
+ input = ctx->inputTab[ctx->inputNr - 2];
+ if (input != NULL) {
+ ret = input->line;
+ }
+ else {
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * xmlTextReaderLocatorBaseURI
+ * @locator: the xmlTextReaderLocatorPtr used
+ *
+ * Obtain the base URI for the given locator.
+ *
+ * Returns the base URI or NULL in case of error.
+ */
+xmlChar *
+xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
+ /* we know that locator is a xmlParserCtxtPtr */
+ xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
+ xmlChar *ret = NULL;
+
+ if (ctx->node != NULL) {
+ ret = xmlNodeGetBase(NULL,ctx->node);
+ }
+ else {
+ /* inspired from error.c */
+ xmlParserInputPtr input;
+ input = ctx->input;
+ if ((input->filename == NULL) && (ctx->inputNr > 1))
+ input = ctx->inputTab[ctx->inputNr - 2];
+ if (input != NULL) {
+ ret = xmlStrdup(input->filename);
+ }
+ else {
+ ret = NULL;
+ }
+ }
+
+ return ret;
+}
+
static void
xmlTextReaderGenericError(void *ctxt, int severity, char *str) {
xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)ctxt;
@@ -2289,10 +2357,8 @@
if (str != NULL) {
reader->errorFunc(reader->errorFuncArg,
str,
- ctx->input->line,
- ctx->input->col,
- ctx->input->filename,
- severity);
+ severity,
+ (xmlTextReaderLocatorPtr)ctx);
xmlFree(str);
}
}
@@ -2303,7 +2369,7 @@
va_start(ap,msg);
xmlTextReaderGenericError(ctxt,
- XMLREADER_SEVERITY_ERROR,
+ XML_PARSER_SEVERITY_ERROR,
xmlTextReaderBuildMessage(msg,ap));
va_end(ap);
@@ -2315,7 +2381,7 @@
va_start(ap,msg);
xmlTextReaderGenericError(ctxt,
- XMLREADER_SEVERITY_WARNING,
+ XML_PARSER_SEVERITY_WARNING,
xmlTextReaderBuildMessage(msg,ap));
va_end(ap);
}
@@ -2323,24 +2389,37 @@
static void
xmlTextReaderValidityError(void *ctxt, const char *msg, ...) {
va_list ap;
+ int len = xmlStrlen((const xmlChar *) msg);
- va_start(ap,msg);
- xmlTextReaderGenericError(ctxt,
- XMLREADER_SEVERITY_VALIDITY_ERROR,
- xmlTextReaderBuildMessage(msg,ap));
- va_end(ap);
-
+ if ((len > 1) && (msg[len - 2] != ':')) {
+ /*
+ * some callbacks only report locator information:
+ * skip them (mimicking behaviour in error.c)
+ */
+ va_start(ap,msg);
+ xmlTextReaderGenericError(ctxt,
+ XML_PARSER_SEVERITY_VALIDITY_ERROR,
+ xmlTextReaderBuildMessage(msg,ap));
+ va_end(ap);
+ }
}
static void
xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) {
va_list ap;
+ int len = xmlStrlen((const xmlChar *) msg);
- va_start(ap,msg);
- xmlTextReaderGenericError(ctxt,
- XMLREADER_SEVERITY_VALIDITY_WARNING,
- xmlTextReaderBuildMessage(msg,ap));
- va_end(ap);
+ if ((len != 0) && (msg[len - 1] != ':')) {
+ /*
+ * some callbacks only report locator information:
+ * skip them (mimicking behaviour in error.c)
+ */
+ va_start(ap,msg);
+ xmlTextReaderGenericError(ctxt,
+ XML_PARSER_SEVERITY_VALIDITY_WARNING,
+ xmlTextReaderBuildMessage(msg,ap));
+ va_end(ap);
+ }
}
/**
@@ -2349,13 +2428,14 @@
* @f: the callback function to call on error and warnings
* @arg: a user argument to pass to the callback function
*
+ * Register a callback function that will be called on error and warnings.
+ *
* If @f is NULL, the default error and warning handlers are restored.
*/
void
xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
xmlTextReaderErrorFunc f,
- void *arg)
-{
+ void *arg) {
if (f != NULL) {
reader->ctxt->sax->error = xmlTextReaderError;
reader->ctxt->vctxt.error = xmlTextReaderValidityError;
@@ -2375,11 +2455,18 @@
}
}
+/**
+ * xmlTextReaderGetErrorHandler:
+ * @reader: the xmlTextReaderPtr used
+ * @f: the callback function or NULL is no callback has been registered
+ * @arg: a user argument
+ *
+ * Retrieve the error callback function and user argument.
+ */
void
xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
xmlTextReaderErrorFunc *f,
- void **arg)
-{
+ void **arg) {
*f = reader->errorFunc;
*arg = reader->errorFuncArg;
}