[xml] python wrapper for document API (AND transformCtxt API)



This is my two recent areas of work combined.

My motivation for building this API was to allow me to identify what
transformation a particular load was occuring for and this patch
enables me to do that. That's why I've combined them... they actually
make sense (to me anyway) together.


It does the following:

- adds a function to create an xslt transformContext from python

- adds a function to apply a stylesheet with a user supplied
  transformContext

- adds a python doc loader which calls a registered python function
  with a URI, xpathParserContext and transformContext and accepts a
  document in return

- adds a function to set the doc loader to a python function

- adds comparison API for transformContext objects


The patch is not complete... but it is usable and I will complete it
by adding these functions:

- a free for transformContext objects

- a getter for the python doc loader function


There are some problems that I could use some help with:

- why is the doc loader context sometimes a stylesheet instead of a
  transformContext?

  can libxslt/libxslt/documents.c::xsltLoadStyleDocument be changed so
  that it creates a transformContext or something?

- when the doc comes back from the python doc loader function do I
  have to DECREF it in some way?

- if I uncomment the xmlFreeParserCtxt(pctxt) at the end of the
  pythonDocLoaderFuncWrapper I get complaints from libc about double
  free-ing:

    *** glibc detected *** double free or corruption (fasttop): 0x0819a7f8 ***
    Aborted

  I can't see why this is really... I've copied the bones of the
  function from the libxml2 entity loader solution and it doesn't seem
  to have a problem with double free-ing.

- why could I not get a static cmp function to work as with
  libxml_compareNodesEqual? 

  There seems to be some difference between the libxml generator and
  the libxslt one?


-- 
Nic Ferrier
http://www.tapsellferrier.co.uk   for all your tapsell ferrier needs

Only in ../pristine/libxslt-1.1.17/libexslt: exsltconfig.h
Only in ../pristine/libxslt-1.1.17/libxslt: xsltconfig.h
Only in ../pristine/libxslt-1.1.17/libxslt: xsltwin32config.h
Only in ../pristine/libxslt-1.1.17: libxslt.spec
diff -r -u ../pristine/libxslt-1.1.17/python/generator.py ./python/generator.py
--- ../pristine/libxslt-1.1.17/python/generator.py      2004-01-22 17:40:16.000000000 +0000
+++ ./python/generator.py       2006-09-07 00:24:31.000000000 +0100
@@ -564,6 +564,7 @@
 classes_ancestor = {
     "xpathContext" : "libxml2.xpathContext",
     "xpathParserContext" : "libxml2.xpathParserContext",
+    "transformCtxt": "transformCtxtBase",
 }
 classes_destructors = {
     "xpathContext" : "pass"
Only in ./python: generator.py~
diff -r -u ../pristine/libxslt-1.1.17/python/libxsl.py ./python/libxsl.py
--- ../pristine/libxslt-1.1.17/python/libxsl.py 2004-07-11 12:12:33.000000000 +0100
+++ ./python/libxsl.py  2006-09-07 00:46:18.000000000 +0100
@@ -56,6 +56,20 @@
         import libxsltmod
         import libxml2
 
+
+class transformCtxtBase:
+    def __init__(self, _obj=None):
+        if _obj != None: 
+            self._o = _obj;
+            return
+        self._o = None
+    def __eq__(self, other):
+        if self == None or other == None:
+            return 0
+        v = libxsltmod.xsltCompareTransformContextsEqual(self._o, other._o)
+        return v
+        
+
 class extensionModule:
     def _styleInit(self, style, URI):
         return self.styleInit(stylesheet(_obj=style), URI)
Only in ./python: libxsl.py~
Only in ../pristine/libxslt-1.1.17/python: libxslt-py.c
diff -r -u ../pristine/libxslt-1.1.17/python/libxslt-python-api.xml ./python/libxslt-python-api.xml
--- ../pristine/libxslt-1.1.17/python/libxslt-python-api.xml    2006-09-01 03:14:20.000000000 +0100
+++ ./python/libxslt-python-api.xml     2006-09-07 00:33:35.000000000 +0100
@@ -11,6 +11,31 @@
       <arg name='style' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/>
       <arg name='result' type='xmlDocPtr' info='The result document'/>
     </function>
+    <function name='xsltSetLoaderFunc' file='python'>
+      <info>Set the function for controlling document loading</info>
+      <return type='long' info='0 or 1'/>
+      <arg name='loader' type='pythonObject' info='the loader function'/>
+    </function>
+    <function name='xsltNewTransformContext' file='python'>
+      <info>Create a new XSLT TransformContext</info>
+      <return type='xsltTransformContextPtr' info='an xslt TransformContext'/>
+      <arg name='style' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/>
+      <arg name='doc' type='xmlDocPtr' info='the input document'/>
+    </function>
+    <function name='xsltCompareTransformContextsEqual' file='python'>
+      <info>Compare one transformCtxt with another</info>
+      <return type='int' info='1 in case of success, 0 or -1 in error' />
+      <arg name='transformCtxt' type='xsltTransformContextPtr' info='a parsed XSLT transformContext'/>
+      <arg name='other' type='xsltTransformContextPtr' info='a parsed XSLT transformContext'/>
+    </function>
+    <function name='xsltApplyStylesheetUser' file='python'>
+      <info>Apply the stylesheet to the document</info>
+      <return type='xmlDocPtr' info="the result document or NULL in case of error"/>
+      <arg name='style' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/>
+      <arg name='doc' type='xmlDocPtr' info='a parsed XML document'/>
+      <arg name='params' type='pythonObject' info='the parameters dictionnary'/>
+      <arg name='transformCtxt' type='xsltTransformContextPtr' info='transformation context'/>
+    </function>
     <function name='xsltApplyStylesheet' file='python'>
       <info>Apply the stylesheet to the document</info>
       <return type='xmlDocPtr' info="the result document or NULL in case of error"/>
Only in ./python: libxslt-python-api.xml~
diff -r -u ../pristine/libxslt-1.1.17/python/libxslt.c ./python/libxslt.c
--- ../pristine/libxslt-1.1.17/python/libxslt.c 2004-07-02 14:49:07.000000000 +0100
+++ ./python/libxslt.c  2006-09-07 00:34:38.000000000 +0100
@@ -20,6 +20,8 @@
 #include "libxslt_wrap.h"
 #include "libxslt-py.h"
 
+#include <stdio.h>
+
 #if (defined(_MSC_VER) || defined(__MINGW32__)) && !defined(vsnprintf)
 #define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a)
 #elif defined(XSLT_NEED_TRIO)
@@ -55,6 +57,9 @@
     }
     ret = PyCObject_FromVoidPtrAndDesc((void *) style,
                                       (char *)"xsltStylesheetPtr", NULL);
+
+    // Py_AddAttr(ret, cmp_function_impl);
+
     return(ret);
 }
 
@@ -90,6 +95,26 @@
     return(ret);
 }
 
+PyObject *
+libxslt_xsltCompareTransformContextsEqual(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+    
+    PyObject *py_tctxt1, *py_tctxt2;
+    xsltTransformContextPtr tctxt1, tctxt2;
+
+    if (!PyArg_ParseTuple(args, (char *)"OO:compareTransformContextsEqual", 
+                          &py_tctxt1, &py_tctxt2))
+        return NULL;
+
+    tctxt1 = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt1);
+    tctxt2 = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt2);
+
+    if ( tctxt1 == tctxt2 )
+        return Py_BuildValue((char *)"i", 1);
+    else
+        return Py_BuildValue((char *)"i", 0);
+}
+
+
 /************************************************************************
  *                                                                     *
  *                     Extending the API                               *
@@ -423,6 +448,105 @@
     return(py_retval);
 }
 
+
+/************************************************************************
+ *                                                                     *
+ *                     Document loading front-ends                     *
+ *                                                                     *
+ ************************************************************************/
+
+static PyObject *pythonDocLoaderObject = NULL;
+
+static xmlDocPtr
+pythonDocLoaderFuncWrapper(const xmlChar * URI, xmlDictPtr dict, int options,
+                           void *ctxt ATTRIBUTE_UNUSED,
+                           xsltLoadType type ATTRIBUTE_UNUSED)
+{
+    xmlParserCtxtPtr pctxt;
+    xmlDocPtr doc;
+
+    pctxt = xmlNewParserCtxt();
+    if (pctxt == NULL)
+        return(NULL);
+    if ((dict != NULL) && (pctxt->dict != NULL)) {
+        xmlDictFree(pctxt->dict);
+       pctxt->dict = NULL;
+    }
+    if (dict != NULL) {
+       pctxt->dict = dict;
+       xmlDictReference(pctxt->dict);
+#ifdef WITH_XSLT_DEBUG
+       xsltGenericDebug(xsltGenericDebugContext,
+                     "Reusing dictionary for document\n");
+#endif
+    }
+    xmlCtxtUseOptions(pctxt, options);
+
+    // now pass to python: pctxt, uri, options, ctxt
+    // the ctxt should be the stylesheet allowing us to differentiate between transformations
+    if (pythonDocLoaderObject != NULL) {
+        xsltStylesheetPtr style;
+        PyObject *ctxtobj;
+        PyObject *pctxtobj;
+        PyObject *result;
+
+        style = (xsltStylesheetPtr) ctxt;
+        ctxtobj = libxslt_xsltStylesheetPtrWrap(ctxt);
+        pctxtobj = libxml_xmlParserCtxtPtrWrap(pctxt);
+
+        // For now just send parserContext and URL
+        result = PyObject_CallFunction(pythonDocLoaderObject, 
+                                       (char *) "(sOO)", URI, pctxtobj, ctxtobj);
+       Py_XDECREF(pctxtobj);
+
+        if (result != NULL) {
+            // The return value should be the document
+            // Should we test it somehow before getting the C object from it?
+            PyObject *py_doc = PyObject_GetAttrString(result, "_o");
+            doc = PyxmlNode_Get(py_doc);
+
+            // do we have to DECCREF the result??
+        }
+    }
+
+    if (pctxt->wellFormed) {
+        // xmlDocDump(stderr, doc);
+        ;
+    }
+    else {
+        if (doc != NULL) {
+            xmlFreeDoc(doc);
+        }
+        if (pctxt->myDoc != NULL) {
+            doc = NULL;
+            xmlFreeDoc(pctxt->myDoc);
+            pctxt->myDoc = NULL;
+        }
+    }
+    // xmlFreeParserCtxt(pctxt);   // libc complains about double free-ing with this line
+
+    return(doc);
+}
+
+
+PyObject *
+libxslt_xsltSetLoaderFunc(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+    PyObject *py_retval;
+    PyObject *loader;
+
+    if (!PyArg_ParseTuple(args, (char *)"O:libxslt_xsltSetLoaderFunc",
+               &loader))
+       return(NULL);
+
+    pythonDocLoaderObject = loader;
+    xsltSetLoaderFunc(pythonDocLoaderFuncWrapper);
+
+    py_retval = PyInt_FromLong(0);
+    return(py_retval);    
+}
+
+
+
 /************************************************************************
  *                                                                     *
  *                     Some customized front-ends                      *
@@ -430,6 +554,103 @@
  ************************************************************************/
 
 PyObject *
+libxslt_xsltNewTransformContext(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+    PyObject *py_retval;
+    PyObject *pyobj_style;
+    PyObject *pyobj_doc;
+    xsltStylesheetPtr style;
+    xmlDocPtr doc;
+    xsltTransformContextPtr c_retval;
+
+    if (!PyArg_ParseTuple(args, (char *) "OO:xsltNewTransformContext",
+                         &pyobj_style, &pyobj_doc))
+        return(NULL);
+
+    style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style);
+    doc = (xmlDocPtr) PyxmlNode_Get(pyobj_doc);
+    
+    c_retval = xsltNewTransformContext(style, doc);
+    py_retval = libxslt_xsltTransformContextPtrWrap((xsltTransformContextPtr) c_retval);
+    return (py_retval);
+}
+
+PyObject *
+libxslt_xsltApplyStylesheetUser(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+    PyObject *py_retval;
+    xmlDocPtr c_retval;
+    xsltStylesheetPtr style;
+    PyObject *pyobj_style;
+    xmlDocPtr doc;
+    xsltTransformContextPtr transformCtxt;
+    PyObject *pyobj_doc;
+    PyObject *pyobj_params;
+    PyObject *pyobj_transformCtxt;
+    const char **params = NULL;
+    int len = 0, i = 0, j;
+    PyObject *name;
+    PyObject *value;
+
+    if (!PyArg_ParseTuple(args, (char *) "OOOO:xsltApplyStylesheetUser",
+                         &pyobj_style, &pyobj_doc, &pyobj_params, &pyobj_transformCtxt))
+        return(NULL);
+
+    if (pyobj_params != Py_None) {
+       if (PyDict_Check(pyobj_params)) {
+           len = PyDict_Size(pyobj_params);
+           if (len > 0) {
+               params = (const char **) xmlMalloc((len + 1) * 2 *
+                                                  sizeof(char *));
+               if (params == NULL) {
+                   printf("libxslt_xsltApplyStylesheet: out of memory\n");
+                   Py_INCREF(Py_None);
+                   return(Py_None);
+               }
+               j = 0;
+               while (PyDict_Next(pyobj_params, &i, &name, &value)) {
+                   const char *tmp;
+                   int size;
+
+                   tmp = PyString_AS_STRING(name);
+                   size = PyString_GET_SIZE(name);
+                   params[j * 2] = (char *) xmlCharStrndup(tmp, size);
+                   if (PyString_Check(value)) {
+                       tmp = PyString_AS_STRING(value);
+                       size = PyString_GET_SIZE(value);
+                       params[(j * 2) + 1] = (char *)
+                           xmlCharStrndup(tmp, size);
+                   } else {
+                       params[(j * 2) + 1] = NULL;
+                   }
+                   j = j + 1;
+               }
+               params[j * 2] = NULL;
+               params[(j * 2) + 1] = NULL;
+           }
+       } else {
+           printf("libxslt_xsltApplyStylesheet: parameters not a dict\n");
+           Py_INCREF(Py_None);
+           return(Py_None);
+       }
+    }
+    style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style);
+    doc = (xmlDocPtr) PyxmlNode_Get(pyobj_doc);
+    transformCtxt = (xsltTransformContextPtr) PytransformCtxt_Get(pyobj_transformCtxt);
+
+    c_retval = xsltApplyStylesheetUser(style, doc, params, NULL, NULL, transformCtxt);
+    py_retval = libxml_xmlDocPtrWrap((xmlDocPtr) c_retval);
+    if (params != NULL) {
+       if (len > 0) {
+           for (i = 0;i < 2 * len;i++) {
+               if (params[i] != NULL)
+                   xmlFree((char *)params[i]);
+           }
+           xmlFree(params);
+       }
+    }
+    return(py_retval);
+}
+
+PyObject *
 libxslt_xsltApplyStylesheet(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
     PyObject *py_retval;
     xmlDocPtr c_retval;
Only in ./python: libxslt.c~
Only in ./python/tests: loader.py
Only in ./python/tests: loader.py~


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