Re: [xml] Patch to enable xmlSchemaSetValidErrors in python



Daniel Veillard wrote:
On Thu, Oct 28, 2004 at 11:55:37AM -0500, Brent Hendricks wrote:

Speaking of which: I'd like to get python bindings for xmlValidateDtd working. I can go ahead and put code in libxml.c but I thought I would first try to understand why it's being excluded from autogeneration. I see that it's listed in doc/libxml2-api.xml, but does not appear in the generated libxml2-py.c.


  autogeneration of bindings only happens if all types in the function
signature are handled by generate.py, in that case I think there is
no wrapper type or class for xmlValidCtxtPtr.

Thanks! Using this as a starting point, I've put together a patch that adds a wrapper for xmlValidCtxtPtr. It seems to work, and did indeed allow a binding for xmlValidateDtd to be autogenerated along with the following other functions:

xmlValidateOneElement
xmlValidCtxtNormalizeAttributeValue
xmlValidatePopElement
xmlValidateRoot
xmlValidateElement
xmlValidateDtdFinal
xmlValidateNotationUse
xmlNewValidCtxt
xmlValidatePushElement
xmlValidatePushCData
xmlFreeValidCtxt
xmlValidateOneAttribute
xmlValidateDocument
xmlValidateDocumentFinal
xmlValidateOneNamespace

In order to get it to work, I had to exclude xmlValidBuildContentModel, xmlValidateElementDecl, xmlValidateAttributeDecl in generator.py because they depended on PyxmlElement_Get and PyxmlAttribute_Get which didn't seem to exist.

I also added a libxml_xmlSetValidErrors() function in libxml.c to allow for setting validation error handlers. I based this off libxml_xmlRelaxNGSetValidErrors() so the code roughly parallels that.

I've attached the patch as well as a simple test of the validateDtd function. It would be great if this could get committed and get some more exposure. I will continue to test things here as well.

Thanks,
Brent
--

-------------------------------------------------------------------------

"The programmer, like the poet, works only slightly removed from pure
 thought-stuff.  He builds his castles in the air, from air, creating
 by exertion of the imagination.  Few media of creation are so
 flexible, so easy to polish and rework, so readily capable of
 realizing grand conceptual structures."
                        -- Frederick Brooks, Jr., The Mythical Man Month
Index: generator.py
===================================================================
RCS file: /cvs/gnome/libxml2/python/generator.py,v
retrieving revision 1.56
diff -u -r1.56 generator.py
--- generator.py        4 Oct 2004 10:26:54 -0000       1.56
+++ generator.py        10 Nov 2004 03:19:57 -0000
@@ -270,6 +270,7 @@
     'xmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
     'htmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
     'htmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
+    'xmlValidCtxtPtr': ('O', "ValidCtxt", "xmlValidCtxtPtr", "xmlValidCtxtPtr"),
     'xmlCatalogPtr': ('O', "catalog", "xmlCatalogPtr", "xmlCatalogPtr"),
     'FILE *': ('O', "File", "FILEPtr", "FILE *"),
     'xmlURIPtr': ('O', "URI", "xmlURIPtr", "xmlURIPtr"),
@@ -345,6 +346,14 @@
         return 1
     if name == "xmlErrMemory":
         return 1
+
+    if name == "xmlValidBuildContentModel":
+        return 1
+    if name == "xmlValidateElementDecl":
+        return 1
+    if name == "xmlValidateAttributeDecl":
+        return 1
+
     return 0
 
 def print_function_wrapper(name, output, export, include):
@@ -668,6 +677,7 @@
     "xmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
     "htmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
     "htmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
+    "xmlValidCtxtPtr": ("._o", "ValidCtxt(_obj=%s)", "ValidCtxt"),
     "xmlCatalogPtr": ("._o", "catalog(_obj=%s)", "catalog"),
     "xmlURIPtr": ("._o", "URI(_obj=%s)", "URI"),
     "xmlErrorPtr": ("._o", "Error(_obj=%s)", "Error"),
@@ -718,6 +728,7 @@
        "Schema": "xmlSchemaFree",
        "SchemaParserCtxt": "xmlSchemaFreeParserCtxt",
        "SchemaValidCtxt": "xmlSchemaFreeValidCtxt",
+        "ValidCtxt": "xmlFreeValidCtxt",
 }
 
 functions_noexcept = {
Index: libxml.c
===================================================================
RCS file: /cvs/gnome/libxml2/python/libxml.c,v
retrieving revision 1.66
diff -u -r1.66 libxml.c
--- libxml.c    29 Oct 2004 12:10:55 -0000      1.66
+++ libxml.c    10 Nov 2004 03:19:58 -0000
@@ -1554,7 +1554,7 @@
     xmlParserCtxtPyCtxtPtr pyCtxt;
     
 #ifdef DEBUG_ERROR
-    printf("libxml_xmlParserCtxtGenericErrorFuncHandler(%p, %s, ...) called\n", ctx, msg);
+    printf("libxml_xmlParserCtxtGenericErrorFuncHandler(%p, %s, ...) called\n", ctx, str);
 #endif
 
     ctxt = (xmlParserCtxtPtr)ctx;
@@ -1723,6 +1723,141 @@
     return(Py_None);
 }
 
+/***
+ * xmlValidCtxt stuff
+ */
+
+typedef struct 
+{
+    PyObject *warn;
+    PyObject *error;
+    PyObject *arg;
+} xmlValidCtxtPyCtxt;
+typedef xmlValidCtxtPyCtxt *xmlValidCtxtPyCtxtPtr;
+
+static void
+libxml_xmlValidCtxtGenericErrorFuncHandler(void *ctx, int severity, char *str) 
+{
+    PyObject *list;
+    PyObject *result;
+    xmlValidCtxtPyCtxtPtr pyCtxt;
+    
+#ifdef DEBUG_ERROR
+    printf("libxml_xmlValidCtxtGenericErrorFuncHandler(%p, %d, %s, ...) called\n", ctx, severity, str);
+#endif
+
+    pyCtxt = (xmlValidCtxtPyCtxtPtr)ctx;
+    
+    list = PyTuple_New(2);
+    PyTuple_SetItem(list, 0, libxml_charPtrWrap(str));
+    PyTuple_SetItem(list, 1, pyCtxt->arg);
+    Py_XINCREF(pyCtxt->arg);
+    result = PyEval_CallObject(pyCtxt->error, list);
+    if (result == NULL) 
+    {
+       /* TODO: manage for the exception to be propagated... */
+       PyErr_Print();
+    }
+    Py_XDECREF(list);
+    Py_XDECREF(result);
+}
+
+static void
+libxml_xmlValidCtxtGenericWarningFuncHandler(void *ctx, int severity, char *str) 
+{
+    PyObject *list;
+    PyObject *result;
+    xmlValidCtxtPyCtxtPtr pyCtxt;
+    
+#ifdef DEBUG_ERROR
+    printf("libxml_xmlValidCtxtGenericWarningFuncHandler(%p, %d, %s, ...) called\n", ctx, severity, str);
+#endif
+
+    pyCtxt = (xmlValidCtxtPyCtxtPtr)ctx;
+
+    list = PyTuple_New(2);
+    PyTuple_SetItem(list, 0, libxml_charPtrWrap(str));
+    PyTuple_SetItem(list, 1, pyCtxt->arg);
+    Py_XINCREF(pyCtxt->arg);
+    result = PyEval_CallObject(pyCtxt->warn, list);
+    if (result == NULL) 
+    {
+       /* TODO: manage for the exception to be propagated... */
+       PyErr_Print();
+    }
+    Py_XDECREF(list);
+    Py_XDECREF(result);
+}
+
+static void 
+libxml_xmlValidCtxtErrorFuncHandler(void *ctx, const char *msg, ...) 
+{
+    va_list ap;
+
+    va_start(ap, msg);
+    
libxml_xmlValidCtxtGenericErrorFuncHandler(ctx,XML_PARSER_SEVERITY_VALIDITY_ERROR,libxml_buildMessage(msg,ap));
+    va_end(ap);
+}
+
+static void 
+libxml_xmlValidCtxtWarningFuncHandler(void *ctx, const char *msg, ...) 
+{
+    va_list ap;
+
+    va_start(ap, msg);
+    
libxml_xmlValidCtxtGenericWarningFuncHandler(ctx,XML_PARSER_SEVERITY_VALIDITY_WARNING,libxml_buildMessage(msg,ap));
+    va_end(ap);
+}
+
+static PyObject *
+libxml_xmlSetValidErrors(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
+{
+    PyObject *py_retval;
+    PyObject *pyobj_error;
+    PyObject *pyobj_warn;
+    PyObject *pyobj_ctx;
+    PyObject *pyobj_arg = Py_None;
+    xmlValidCtxtPtr ctxt;
+    xmlValidCtxtPyCtxtPtr pyCtxt;
+
+    if (!PyArg_ParseTuple
+        (args, (char *) "OOO|O:xmlSetValidErrors", &pyobj_ctx, &pyobj_error, &pyobj_warn, &pyobj_arg))
+        return (NULL);
+
+#ifdef DEBUG_ERROR
+    printf("libxml_xmlSetValidErrors(%p, %p, %p) called\n", pyobj_ctx, pyobj_error, pyobj_warn);
+#endif
+
+    ctxt = PyValidCtxt_Get(pyobj_ctx);
+    pyCtxt = xmlMalloc(sizeof(xmlValidCtxtPyCtxt));
+    if (pyCtxt == NULL) {
+            py_retval = libxml_intWrap(-1);
+            return(py_retval);
+    }
+    memset(pyCtxt, 0, sizeof(xmlValidCtxtPyCtxt));
+
+    
+    /* TODO: check warn and error is a function ! */
+    Py_XDECREF(pyCtxt->error);
+    Py_XINCREF(pyobj_error);
+    pyCtxt->error = pyobj_error;
+    
+    Py_XDECREF(pyCtxt->warn);
+    Py_XINCREF(pyobj_warn);
+    pyCtxt->warn = pyobj_warn;
+    
+    Py_XDECREF(pyCtxt->arg);
+    Py_XINCREF(pyobj_arg);
+    pyCtxt->arg = pyobj_arg;
+
+    ctxt->error = libxml_xmlValidCtxtErrorFuncHandler;
+    ctxt->warning = libxml_xmlValidCtxtWarningFuncHandler;
+    ctxt->userData = pyCtxt;
+
+    py_retval = libxml_intWrap(1);
+    return (py_retval);
+}
+
 /************************************************************************
  *                                                                     *
  *                      Per xmlTextReader error handler                 *
@@ -3482,6 +3617,7 @@
     {(char *) "type", libxml_type, METH_VARARGS, NULL},
     {(char *) "doc", libxml_doc, METH_VARARGS, NULL},
     {(char *) "xmlNewNode", libxml_xmlNewNode, METH_VARARGS, NULL},
+    {(char *)"xmlSetValidErrors", libxml_xmlSetValidErrors, METH_VARARGS, NULL},
 #ifdef LIBXML_OUTPUT_ENABLED
     {(char *) "serializeNode", libxml_serializeNode, METH_VARARGS, NULL},
     {(char *) "saveNodeTo", libxml_saveNodeTo, METH_VARARGS, NULL},
Index: libxml_wrap.h
===================================================================
RCS file: /cvs/gnome/libxml2/python/libxml_wrap.h,v
retrieving revision 1.23
diff -u -r1.23 libxml_wrap.h
--- libxml_wrap.h       22 Aug 2004 13:11:39 -0000      1.23
+++ libxml_wrap.h       10 Nov 2004 03:19:58 -0000
@@ -73,6 +73,14 @@
     xmlParserCtxtPtr obj;
 } PyparserCtxt_Object;
 
+#define PyValidCtxt_Get(v) (((v) == Py_None) ? NULL : \
+       (((PyValidCtxt_Object *)(v))->obj))
+
+typedef struct {
+       PyObject_HEAD
+       xmlValidCtxtPtr obj;
+} PyValidCtxt_Object;
+
 #define Pycatalog_Get(v) (((v) == Py_None) ? NULL : \
         (((Pycatalog_Object *)(v))->obj))
 
@@ -213,6 +221,7 @@
 PyObject * libxml_xmlParserCtxtPtrWrap(xmlParserCtxtPtr ctxt);
 PyObject * libxml_xmlXPathParserContextPtrWrap(xmlXPathParserContextPtr ctxt);
 PyObject * libxml_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj);
+PyObject * libxml_xmlValidCtxtPtrWrap(xmlValidCtxtPtr valid);
 PyObject * libxml_xmlCatalogPtrWrap(xmlCatalogPtr obj);
 PyObject * libxml_xmlURIPtrWrap(xmlURIPtr uri);
 PyObject * libxml_xmlOutputBufferPtrWrap(xmlOutputBufferPtr buffer);
Index: types.c
===================================================================
RCS file: /cvs/gnome/libxml2/python/types.c,v
retrieving revision 1.18
diff -u -r1.18 types.c
--- types.c     18 Aug 2004 09:13:18 -0000      1.18
+++ types.c     10 Nov 2004 03:19:58 -0000
@@ -478,6 +478,26 @@
 }
 
 PyObject *
+libxml_xmlValidCtxtPtrWrap(xmlValidCtxtPtr valid)
+{
+       PyObject *ret;
+       
+#ifdef DEBUG
+       printf("libxml_xmlValidCtxtPtrWrap: valid = %p\n", valid);
+#endif
+       if (valid == NULL) {
+               Py_INCREF(Py_None);
+               return (Py_None);
+       }
+
+       ret = 
+               PyCObject_FromVoidPtrAndDesc((void *) valid,
+                                                                        (char *) "xmlValidCtxtPtr", NULL);
+
+       return (ret);
+}
+
+PyObject *
 libxml_xmlCatalogPtrWrap(xmlCatalogPtr catal)
 {
     PyObject *ret;
#!/usr/bin/python -u
import libxml2
import sys

# Memory debug specific
libxml2.debugMemory(1)

dtd="""<!ELEMENT foo EMPTY>"""
instance="""<?xml version="1.0"?>
<foo></foo>"""

dtd = libxml2.parseDTD(None, 'test.dtd')
ctxt = libxml2.newValidCtxt()
doc = libxml2.parseDoc(instance)
ret = doc.validateDtd(ctxt, dtd)
if ret != 1:
    print "error doing DTD validation"
    sys.exit(1)

doc.freeDoc()
dtd.freeDtd()
del dtd
del ctxt

# Memory debug specific
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
    print "OK"
else:
    print "Memory leak %d bytes" % (libxml2.debugMemory(1))
    libxml2.dumpMemory()

<!ELEMENT foo EMPTY>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]