From a7340c830e4bddd86201cfdb97ac81e30b0dee62 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Fri, 1 Feb 2002 17:56:45 +0000 Subject: [PATCH] more work, now able to extend the XPath interpreter with functions written * python/Makefile.am python/generator.py python/libxml.c python/libxml.py: more work, now able to extend the XPath interpreter with functions written in python. Daniel --- ChangeLog | 6 ++ python/Makefile.am | 2 +- python/generator.py | 4 ++ python/libxml.c | 170 +++++++++++++++++++++++++++++++++++++++++++- python/libxml.py | 6 ++ 5 files changed, 186 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index a18bc175..14375777 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Fri Feb 1 18:48:19 CET 2002 Daniel Veillard + + * python/Makefile.am python/generator.py python/libxml.c + python/libxml.py: more work, now able to extend the + XPath interpreter with functions written in python. + Fri Feb 1 10:28:51 CET 2002 Daniel Veillard * python/Makefile.am: Jacob sent a patch to allow building from diff --git a/python/Makefile.am b/python/Makefile.am index 3ac8c78e..158f149e 100644 --- a/python/Makefile.am +++ b/python/Makefile.am @@ -38,4 +38,4 @@ $(GENERATED): $(srcdir)/$(GENERATE) $(API_DESC) cd $(srcdir) && $(PYTHON) $(GENERATE) clean: - rm -f $(GENERATED) *.o _libxml.so *.pyc + rm -f $(GENERATED) *.o _libxml.so *.pyc libxml2.py diff --git a/python/generator.py b/python/generator.py index cc2c33ba..13a5ae75 100755 --- a/python/generator.py +++ b/python/generator.py @@ -672,6 +672,10 @@ for classname in function_classes.keys(): classes.write(" _libxml.%s(self._o)\n" % classes_destructors[classname]); classes.write(" self._o = None\n\n"); + classes.write(" def __repr__(self):\n") + format = "%s:%%s" % (classname) + classes.write(" return \"%s\" %% (self.name)\n\n" % ( + format)) flist = function_classes[classname] flist.sort(functionCompare) oldfile = "" diff --git a/python/libxml.c b/python/libxml.c index de31e537..61992c69 100644 --- a/python/libxml.c +++ b/python/libxml.c @@ -3,10 +3,13 @@ #include #include #include +#include +#include #include "libxml_wrap.h" #include "libxml2-py.h" /* #define DEBUG */ +/* #define DEBUG_XPATH */ /************************************************************************ * * @@ -258,6 +261,170 @@ libxml_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj) { return(ret); } +xmlXPathObjectPtr +libxml_xmlXPathObjectPtrConvert(PyObject * obj) { + xmlXPathObjectPtr ret; + +#ifdef DEBUG + printf("libxml_xmlXPathObjectPtrConvert: obj = %p\n", obj); +#endif + if (obj == NULL) { + return(NULL); + } + if PyFloat_Check(obj) { + ret = xmlXPathNewFloat((double) PyFloat_AS_DOUBLE(obj)); + } else if PyString_Check(obj) { + xmlChar *str; + + str = xmlStrndup((const xmlChar *)PyString_AS_STRING(obj), + PyString_GET_SIZE(obj)); + ret = xmlXPathWrapString(str); + } else { + printf("Unable to convert Python Object to XPath"); + } + Py_DECREF(obj); + return(ret); +} +/************************************************************************ + * * + * XPath extensions * + * * + ************************************************************************/ + +static int libxml_xpathCallbacksInitialized = 0; + +typedef struct libxml_xpathCallback { + xmlXPathContextPtr ctx; + xmlChar *name; + xmlChar *ns_uri; + PyObject *function; +} libxml_xpathCallback, *libxml_xpathCallbackPtr; +static libxml_xpathCallback libxml_xpathCallbacks[10]; +static int libxml_xpathCallbacksNb = 0; +static int libxml_xpathCallbacksMax = 10; + +/* TODO: this is not reentrant !!! MUST FIX with a per context hash */ +static PyObject *current_function = NULL; + +static void +libxml_xmlXPathFuncCallback(xmlXPathParserContextPtr ctxt, int nargs) { + PyObject *list, *cur, *result; + xmlXPathObjectPtr obj; + int i; + +#ifdef DEBUG_XPATH + printf("libxml_xmlXPathFuncCallback called\n"); +#endif + + list = PyTuple_New(nargs); + for (i = 0;i < nargs;i++) { + obj = valuePop(ctxt); + cur = libxml_xmlXPathObjectPtrWrap(obj); + PyTuple_SetItem(list, i, cur); + } + result = PyEval_CallObject(current_function, list); + Py_DECREF(list); + + obj = libxml_xmlXPathObjectPtrConvert(result); + valuePush(ctxt, obj); +} + +static xmlXPathFunction +libxml_xmlXPathFuncLookupFunc(void *ctxt, const xmlChar *name, + const xmlChar *ns_uri) { + int i; +#ifdef DEBUG_XPATH + printf("libxml_xmlXPathFuncLookupFunc(%p, %s, %s) called\n", + ctxt, name, ns_uri); +#endif + for (i = 0;i < libxml_xpathCallbacksNb;i++) { + if ((ctxt == libxml_xpathCallbacks[i].ctx) && + (xmlStrEqual(name, libxml_xpathCallbacks[i].name)) && + (xmlStrEqual(ns_uri, libxml_xpathCallbacks[i].ns_uri))) { + current_function = libxml_xpathCallbacks[i].function; + return(libxml_xmlXPathFuncCallback); + } + } + current_function = NULL; + return(NULL); +} + +static void +libxml_xpathCallbacksInitialize(void) { + int i; + + if (libxml_xpathCallbacksInitialized != 0) + return; + +#ifdef DEBUG_XPATH + printf("libxml_xpathCallbacksInitialized called\n"); +#endif + + for (i = 0;i < 10;i++) { + libxml_xpathCallbacks[i].ctx = NULL; + libxml_xpathCallbacks[i].name = NULL; + libxml_xpathCallbacks[i].ns_uri = NULL; + libxml_xpathCallbacks[i].function = NULL; + } + current_function = NULL; + libxml_xpathCallbacksInitialized = 1; +} + +PyObject * +libxml_registerXPathFunction(PyObject *self, PyObject *args) { + PyObject *py_retval; + int c_retval = 0; + xmlChar *name; + xmlChar *ns_uri; + xmlXPathContextPtr ctx; + PyObject *pyobj_ctx; + PyObject *pyobj_f; + int i; + + if (!PyArg_ParseTuple(args, "OszO:registerXPathFunction", &pyobj_ctx, + &name, &ns_uri, &pyobj_f)) + return(NULL); + + ctx = (xmlXPathContextPtr) PyxmlXPathContext_Get(pyobj_ctx); + if (libxml_xpathCallbacksInitialized == 0) + libxml_xpathCallbacksInitialize(); + xmlXPathRegisterFuncLookup(ctx, libxml_xmlXPathFuncLookupFunc, ctx); + + if ((pyobj_ctx == NULL) || (name == NULL) || (pyobj_f == NULL)) { + py_retval = libxml_intWrap(-1); + return(py_retval); + } + +#ifdef DEBUG_XPATH + printf("libxml_registerXPathFunction(%p, %s, %s) called\n", + ctx, name, ns_uri); +#endif + for (i = 0;i < libxml_xpathCallbacksNb;i++) { + if ((ctx == libxml_xpathCallbacks[i].ctx) && + (xmlStrEqual(name, libxml_xpathCallbacks[i].name)) && + (xmlStrEqual(ns_uri, libxml_xpathCallbacks[i].ns_uri))) { + Py_XINCREF(pyobj_f); + Py_XDECREF(libxml_xpathCallbacks[i].function); + libxml_xpathCallbacks[i].function = pyobj_f; + c_retval = 1; + goto done; + } + } + if (libxml_xpathCallbacksNb >= libxml_xpathCallbacksMax) { + printf("libxml_registerXPathFunction() table full\n"); + } else { + i = libxml_xpathCallbacksNb++; + Py_XINCREF(pyobj_f); + libxml_xpathCallbacks[i].ctx = ctx; + libxml_xpathCallbacks[i].name = xmlStrdup(name); + libxml_xpathCallbacks[i].ns_uri = xmlStrdup(ns_uri); + libxml_xpathCallbacks[i].function = pyobj_f; + } +done: + py_retval = libxml_intWrap((int) c_retval); + return(py_retval); +} + /************************************************************************ * * * The PyxmlNode type * @@ -777,7 +944,8 @@ static PyMethodDef libxmlMethods[] = { { "next", libxml_next, METH_VARARGS }, { "parent", libxml_parent, METH_VARARGS }, { "type", libxml_type, METH_VARARGS }, - { "doc", libxml_doc, METH_VARARGS } + { "doc", libxml_doc, METH_VARARGS }, + { "registerXPathFunction", libxml_registerXPathFunction, METH_VARARGS } }; void init_libxml(void) { diff --git a/python/libxml.py b/python/libxml.py index 476bb279..88be5d71 100644 --- a/python/libxml.py +++ b/python/libxml.py @@ -141,6 +141,12 @@ def xpathObjectRet(o): return ret return o +# +# register an XPath function +# +def registerXPathFunction(ctxt, name, ns_uri, f): + ret = _libxml.registerXPathFunction(ctxt, name, ns_uri, f) + # # Everything below this point is automatically generated #