[xml] python wrapper for the document loading API: patch



Here is my patch for the python wrapper for the document loading API.

It now works and is complete in all but one respect. I don't seem to
be able to get the xsltGetLoaderFunc function to appear in the python
API. I think this is because the return value of the function _must_
be a pythonObject and I think there might be something wrong with the
generator in that case.

Anyway... getLoaderFunc() isn't all that necessary and I can fix it
down the line so I think this patch could be considered for inclusion.


Here's a changelog for this patch:

2006-09-08  Nic James Ferrier  <nferrier tapsellferrier co uk>

        * python/tests/loader.py: new test of loader API wrapper
        * python/tests/2stage.py: new test of stylesheet creation, then parsing
        * python/libxslt.c: new functions libxslt_xsltNewTransformContext,
        libxslt_xsltFreeTransformContext, libxslt_xsltApplyStylesheetUser
        * python/libxslt.c: new functions pythonDocLoaderFuncWrapper,
        libxslt_xsltSetLoaderFunc, libxslt_xsltGetLoaderFunc
        * python/libxslt.c: new static variable pythonDocLoaderObject
        * python/libxslt.c: new functions
        libxslt_xsltCompareStylesheetsEqual, libxslt_xsltCompareTransformContextsEqual
        * python/libxslt-python-api.xml: add declarations for
        xsltSetLoaderFunc, xsltGetLoaderFunc, xsltNewTranformContext,
        xsltCompareTransformContextsEqual, xsltCompareStylesheetsEqual,
        xsltApplyStylesheetUser
        * python/libxsl.py: new classes transformCtxtBase, stylesheetBase
        * python/generator.py: add base classes for transformCtxt,
        stylesheet


Daniel, would you consider including this please?

-- 
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 -x '*~' --unidirectional-new-file -r ../pristine/libxslt-1.1.17/python/generator.py ./python/generator.py
566a567,568
    "transformCtxt": "transformCtxtBase",
    "stylesheet": "stylesheetBase",
diff -x '*~' --unidirectional-new-file -r ../pristine/libxslt-1.1.17/python/libxsl.py ./python/libxsl.py
58a59,83

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 stylesheetBase:
    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.xsltCompareStylesheetsEqual(self._o, other._o)
        return v

Only in ../pristine/libxslt-1.1.17/python: libxslt-py.c
diff -x '*~' --unidirectional-new-file -r ../pristine/libxslt-1.1.17/python/libxslt-python-api.xml 
./python/libxslt-python-api.xml
13a14,53
    <function name='xsltSetLoaderFunc' file='python'>
      <info>Set the function for controlling document loading</info>
      <return type='long' info='0 for failure or 1 for success'/>
      <arg name='loader' type='pythonObject' info='the loader function; should take: string URI, 
xsltParserContext, context, type; when type == 1 the context is a stylesheet, when type == 0 the context is 
a transformCtxt'/>
    </function>
    <function name='xsltGetLoaderFunc' file='python'>
      <info>Get the function for controlling document loading</info>
      <return type='pythonObject *' info='the 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='xsltFreeTransformContext' file='python'>
      <info>Free up an existing XSLT TransformContext</info>
      <return type='void' info='None'/>
      <arg name='transformCtxt' type='xsltTransformContextPtr' info='an existing tranformCtxt'/>
    </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='xsltCompareStylesheetsEqual' file='python'>
      <info>Compare one stylesheet with another</info>
      <return type='int' info='1 in case of success, 0 or -1 in error' />
      <arg name='stylesheet' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/>
      <arg name='other' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/>
    </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>
diff -x '*~' --unidirectional-new-file -r ../pristine/libxslt-1.1.17/python/libxslt.c ./python/libxslt.c
22a23,24
#include <stdio.h>

57a60,62

    // Py_AddAttr(ret, cmp_function_impl);

92a98,135
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);
}

PyObject *
libxslt_xsltCompareStylesheetsEqual(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
    
    PyObject *py_style1, *py_style2;
    xsltStylesheetPtr style1, style2;

    if (!PyArg_ParseTuple(args, (char *)"OO:compareStylesheetsEqual", 
                          &py_style1, &py_style2))
        return NULL;

    style1 = (xsltStylesheetPtr) Pystylesheet_Get(py_style1);
    style2 = (xsltStylesheetPtr) Pystylesheet_Get(py_style2);

    if ( style1 == style2 )
        return Py_BuildValue((char *)"i", 1);
    else
        return Py_BuildValue((char *)"i", 0);
}

425a469,571

/************************************************************************
 *                                                                    *
 *                    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 the URI, the xsltParserContext and the context 
    // (either a transformContext or a stylesheet) and get back an xmlDocPtr
    if (pythonDocLoaderObject != NULL) {
        PyObject *ctxtobj, *pctxtobj, *result;
        pctxtobj = libxml_xmlParserCtxtPtrWrap(pctxt);

        if (type == XSLT_LOAD_DOCUMENT) {
          ctxtobj = libxslt_xsltTransformContextPtrWrap(ctxt);
          result = PyObject_CallFunction(pythonDocLoaderObject, 
                                         (char *) "(sOOi)", URI, pctxtobj, ctxtobj, 0); 
        }
        else {
          ctxtobj = libxslt_xsltStylesheetPtrWrap(ctxt);
          result = PyObject_CallFunction(pythonDocLoaderObject, 
                                         (char *) "(sOOi)", URI, pctxtobj, ctxtobj, 1); 
        }

      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) {
        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);    
}

PyObject *
libxslt_xsltGetLoaderFunc(void) {
    PyObject *py_retval;

    py_retval = pythonDocLoaderObject;
    return(py_retval);    
}


432a579,691
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_xsltFreeTransformContext(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
    PyObject *py_tctxt;
    xsltTransformContextPtr tctxt;

    if (!PyArg_ParseTuple(args, (char *) "O:xsltFreeTransformContext", &py_tctxt))
        return(NULL);
                     
    tctxt = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt);
    xsltFreeTransformContext(tctxt);

    // Return None
    Py_INCREF(Py_None);
    return(Py_None);    
}

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 *
diff -x '*~' --unidirectional-new-file -r ../pristine/libxslt-1.1.17/python/tests/2stage.py 
./python/tests/2stage.py
0a1,22
#!/usr/bin/python

import libxslt
import libxml2
import sys

styledoc = libxml2.parseDoc("""
<xsl:stylesheet version='1.0'
  xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
  <xsl:template match='/'>
    <x><xsl:value-of select='*'/></x>
  </xsl:template>
</xsl:stylesheet>
""")
style = libxslt.newStylesheet()
style.parseStylesheetProcess(styledoc)

testdoc = libxml2.parseDoc("<a>hello!</a>")
result = style.applyStylesheet(testdoc, {})
result.dump(sys.stdout)

# End
diff -x '*~' --unidirectional-new-file -r ../pristine/libxslt-1.1.17/python/tests/loader.py 
./python/tests/loader.py
0a1,94
import libxslt
import libxml2
import sys
import pdb


savedTC1 = None
savedTC2 = None
savedStyle1 = None
savedStyle2 = None

def fn(url, pctx, ctx, type):
    global savedTC1
    global savedTC2
    global savedStyle1
    global savedStyle2

    try:
        if type == 0:
            tc = libxslt.transformCtxt(_obj=ctx)

            if savedTC1 == tc:
                print "matched TC1!"

            if savedTC2 == tc:
                print "matched TC2!"

            pctxt = libxml2.parserCtxt(_obj=pctx)
            doc = pctxt.ctxtReadDoc("""<?xml version='1.0'?><b>Goodbye</b>""", url, "UTF-8", 2)
            return doc

        else:
            style = libxslt.stylesheet(_obj=ctx)

            if savedStyle1 == style:
                print "matched savedStyle1!"

            if savedStyle2 == style:
                print "matched savedStyle2!"

            pctxt = libxml2.parserCtxt(_obj=pctx)
            doc = pctxt.ctxtReadDoc("""
<xsl:stylesheet version='1.0'
  xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
</xsl:stylesheet>""", url, "UTF-8", 2)
            return doc

    except Exception, e:
        print >>sys.stderr, "something went wrong: ", e
        return None

def run():
    libxslt.setLoaderFunc(fn)
    styledoc = libxml2.parseDoc("""
<xsl:stylesheet version='1.0'
  xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
  <xsl:import href='import1.xslt'/>
  <xsl:template match='/'>
    <x><xsl:value-of select='document("b.xml")'/></x>
  </xsl:template>
</xsl:stylesheet>
""")
    style = libxslt.newStylesheet()
    if style:
        global savedStyle1
        global savedTC1
        global savedTC2
        savedStyle1 = style

        style.parseStylesheetProcess(styledoc)

        src_doc1 = libxml2.parseDoc("<a/>")
        transform_ctxt1 = style.newTransformContext(src_doc1)
        savedTC1 = transform_ctxt1

        src_doc2 = libxml2.parseDoc("<c/>")
        transform_ctxt2 = style.newTransformContext(src_doc2)
        savedTC2 = transform_ctxt2

        result = style.applyStylesheetUser(src_doc1, {}, transform_ctxt1)
        result.dump(sys.stdout)

        style.freeStylesheet()
        src_doc1.freeDoc()
        src_doc2.freeDoc()

        transform_ctxt1.freeTransformContext()
        transform_ctxt2.freeTransformContext()

    #print libxslt.getLoaderFunc()

run()

# End


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