/* #define DEBUG_ERROR */
/* #define DEBUG_MEMORY */
/* #define DEBUG_EXTENSIONS */
+/* #define DEBUG_EXTENSIONS */
void initlibxsltmod(void);
return(ret);
}
+PyObject *
+libxslt_xsltElemPreCompPtrWrap(xsltElemPreCompPtr ctxt) {
+ PyObject *ret;
+
+#ifdef DEBUG
+ printf("libxslt_xsltElemPreCompPtrWrap: ctxt = %p\n", ctxt);
+#endif
+ if (ctxt == NULL) {
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+ ret = PyCObject_FromVoidPtrAndDesc((void *) ctxt,
+ (char *)"xsltElemPreCompPtr", NULL);
+ return(ret);
+}
+
/************************************************************************
* *
* Extending the API *
************************************************************************/
static xmlHashTablePtr libxslt_extModuleFunctions = NULL;
+static xmlHashTablePtr libxslt_extModuleElements = NULL;
+static xmlHashTablePtr libxslt_extModuleElementPreComp = NULL;
+
+static void
+deallocateCallback(void *payload, xmlChar *name ATTRIBUTE_UNUSED) {
+ PyObject *function = (PyObject *) payload;
+
+#ifdef DEBUG_EXTENSIONS
+ printf("deallocateCallback(%s) called\n", name);
+#endif
+
+ Py_XDECREF(function);
+}
+
+static void
+deallocateClasse(void *payload, xmlChar *name ATTRIBUTE_UNUSED) {
+ PyObject *class = (PyObject *) payload;
+
+#ifdef DEBUG_EXTENSIONS
+ printf("deallocateClasse(%s) called\n", name);
+#endif
+
+ Py_XDECREF(class);
+}
+
+
+/**
+ * libxslt_xsltElementPreCompCallback
+ * @style: the stylesheet
+ * @inst: the instruction in the stylesheet
+ *
+ * Callback for preprocessing of a custom element
+ */
+static xsltElemPreCompPtr
+libxslt_xsltElementPreCompCallback(xsltStylesheetPtr style, xmlNodePtr inst,
+ xsltTransformFunction function) {
+ xsltElemPreCompPtr ret;
+ const xmlChar *name;
+ PyObject *args;
+ PyObject *result;
+ PyObject *pyobj_element_f;
+ PyObject *pyobj_precomp_f;
+
+ const xmlChar *ns_uri;
+
+
+#ifdef DEBUG_EXTENSIONS
+ printf("libxslt_xsltElementPreCompCallback called\n");
+#endif
+
+ if (style == NULL) {
+ xsltTransformError(NULL, NULL, inst,
+ "libxslt_xsltElementPreCompCallback: no transformation context\n");
+ return (NULL);
+ }
+
+ if (inst == NULL) {
+ xsltTransformError(NULL, style, inst,
+ "libxslt_xsltElementPreCompCallback: no instruction\n");
+ if (style != NULL) style->errors++;
+ return (NULL);
+ }
+
+ if (style == NULL)
+ return (NULL);
+
+ if (inst != NULL && inst->ns != NULL) {
+ name = inst->name;
+ ns_uri = inst->ns->href;
+ } else {
+ xsltTransformError(NULL, style, inst,
+ "libxslt_xsltElementPreCompCallback: internal error bad parameter\n");
+ printf("libxslt_xsltElementPreCompCallback: internal error bad parameter\n");
+ if (style != NULL) style->errors++;
+ return (NULL);
+ }
+
+ /*
+ * Find the functions, they should be there it was there at lookup
+ */
+ pyobj_precomp_f = xmlHashLookup2(libxslt_extModuleElementPreComp,
+ name, ns_uri);
+ if (pyobj_precomp_f == NULL) {
+ xsltTransformError(NULL, style, inst,
+ "libxslt_xsltElementPreCompCallback: internal error, could not find precompile python function!\n");
+ if (style != NULL) style->errors++;
+ return (NULL);
+ }
+
+ pyobj_element_f = xmlHashLookup2(libxslt_extModuleElements,
+ name, ns_uri);
+ if (pyobj_element_f == NULL) {
+ xsltTransformError(NULL, style, inst,
+ "libxslt_xsltElementPreCompCallback: internal error, could not find element python function!\n");
+ if (style != NULL) style->errors++;
+ return (NULL);
+ }
+
+ args = Py_BuildValue("(OOO)",
+ libxslt_xsltStylesheetPtrWrap(style),
+ libxml_xmlNodePtrWrap(inst),
+ pyobj_element_f);
+
+ Py_INCREF(pyobj_precomp_f); /* Protect refcount against reentrant manipulation of callback hash */
+ result = PyEval_CallObject(pyobj_precomp_f, args);
+ Py_DECREF(pyobj_precomp_f);
+ Py_DECREF(args);
+
+ /* FIXME allow callbacks to return meaningful information to modify compile process */
+ /* If error, do we need to check the result and throw exception? */
+
+ Py_XDECREF(result);
+
+ ret = xsltNewElemPreComp (style, inst, function);
+ return (ret);
+}
+
+
+static void
+libxslt_xsltElementTransformCallback(xsltTransformContextPtr ctxt,
+ xmlNodePtr node,
+ xmlNodePtr inst,
+ xsltElemPreCompPtr comp)
+{
+ PyObject *args, *result;
+ PyObject *func = NULL;
+ const xmlChar *name;
+ const xmlChar *ns_uri;
+
+ if (ctxt == NULL)
+ return;
+
+ if (inst != NULL && inst->name != NULL && inst->ns != NULL && inst->ns->href != NULL) {
+ name = inst->name;
+ ns_uri = inst->ns->href;
+ } else {
+ printf("libxslt_xsltElementTransformCallback: internal error bad parameter\n");
+ return;
+ }
+
+#ifdef DEBUG_EXTENSIONS
+ printf("libxslt_xsltElementTransformCallback called name %s URI %s\n", name, ns_uri);
+#endif
+
+ /*
+ * Find the function, it should be there it was there at lookup
+ */
+ func = xmlHashLookup2(libxslt_extModuleElements,
+ name, ns_uri);
+ if (func == NULL) {
+ printf("libxslt_xsltElementTransformCallback: internal error %s not found !\n",
+ name);
+ return;
+ }
+
+ args = Py_BuildValue("OOOO",
+ libxslt_xsltTransformContextPtrWrap(ctxt),
+ libxml_xmlNodePtrWrap(node),
+ libxml_xmlNodePtrWrap(inst),
+ libxslt_xsltElemPreCompPtrWrap(comp));
+
+ Py_INCREF(func); /* Protect refcount against reentrant manipulation of callback hash */
+ result = PyEval_CallObject(func, args);
+ Py_DECREF(func);
+ Py_DECREF(args);
+
+ /* FIXME Check result of callobject and set exception if fail */
+
+ Py_XDECREF(result);
+}
+
+PyObject *
+libxslt_xsltRegisterExtModuleElement(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args) {
+ PyObject *py_retval;
+ int ret = 0;
+ xmlChar *name;
+ xmlChar *ns_uri;
+ PyObject *pyobj_element_f;
+ PyObject *pyobj_precomp_f;
+#ifdef DEBUG_EXTENSIONS
+ printf("libxslt_xsltRegisterExtModuleElement called\n",
+ name, ns_uri);
+#endif
+
+ if (!PyArg_ParseTuple(args, (char *)"szOO:registerExtModuleElement",
+ &name, &ns_uri, &pyobj_precomp_f, &pyobj_element_f))
+ return(NULL);
+
+ if ((name == NULL) || (pyobj_element_f == NULL) || (pyobj_precomp_f == NULL)) {
+ py_retval = libxml_intWrap(-1);
+ return(py_retval);
+ }
+
+#ifdef DEBUG_EXTENSIONS
+ printf("libxslt_xsltRegisterExtModuleElement(%s, %s) called\n",
+ name, ns_uri);
+#endif
+
+ if (libxslt_extModuleElements == NULL)
+ libxslt_extModuleElements = xmlHashCreate(10);
+
+ if (libxslt_extModuleElementPreComp == NULL)
+ libxslt_extModuleElementPreComp = xmlHashCreate(10);
+
+ if (libxslt_extModuleElements == NULL || libxslt_extModuleElementPreComp == NULL) {
+ py_retval = libxml_intWrap(-1);
+ return(py_retval);
+ }
+
+ ret = xmlHashAddEntry2(libxslt_extModuleElements, name, ns_uri, pyobj_element_f);
+ if (ret != 0) {
+ py_retval = libxml_intWrap(-1);
+ return(py_retval);
+ }
+ Py_XINCREF(pyobj_element_f);
+
+ ret = xmlHashAddEntry2(libxslt_extModuleElementPreComp, name, ns_uri, pyobj_precomp_f);
+ if (ret != 0) {
+ xmlHashRemoveEntry2(libxslt_extModuleElements, name, ns_uri, deallocateCallback);
+ py_retval = libxml_intWrap(-1);
+ return(py_retval);
+ }
+ Py_XINCREF(pyobj_precomp_f);
+
+ ret = xsltRegisterExtModuleElement(name, ns_uri,
+ libxslt_xsltElementPreCompCallback,
+ libxslt_xsltElementTransformCallback);
+ py_retval = libxml_intWrap((int) ret);
+ return(py_retval);
+}
static void
libxslt_xmlXPathFuncCallback(xmlXPathParserContextPtr ctxt, int nargs) {
PyObject *list, *cur, *result;
cur = libxml_xmlXPathObjectPtrWrap(obj);
PyTuple_SetItem(list, i + 1, cur);
}
+
+ Py_INCREF(current_function);
result = PyEval_CallObject(current_function, list);
+ Py_DECREF(current_function);
Py_DECREF(list);
- obj = libxml_xmlXPathObjectPtrConvert(result);
- valuePush(ctxt, obj);
+ /* Check for null in case of exception */
+ if (result != NULL) {
+ obj = libxml_xmlXPathObjectPtrConvert(result);
+ valuePush(ctxt, obj);
+ }
}
PyObject *
return(py_retval);
}
-static void
-deallocateCallback(void *payload, xmlChar *name ATTRIBUTE_UNUSED) {
- PyObject *function = (PyObject *) payload;
-
-#ifdef DEBUG_XPATH
- printf("deallocateCallback(%s) called\n", name);
-#endif
-
- Py_XDECREF(function);
-}
-
/************************************************************************
* *
* Some customized front-ends *
libxslt_xsltSaveResultToString(PyObject *self, PyObject *args) {
PyObject *py_retval; /* our final return value, a python string */
xmlChar *buffer;
- xmlChar *tmp;
int size = 0;
int emitted = 0;
xmlDocPtr result;
static void *
libxslt_xsltPythonExtModuleStyleInit(xsltStylesheetPtr style,
const xmlChar * URI) {
- PyObject *result;
+ PyObject *result = NULL;
PyObject *class = NULL;
#ifdef DEBUG_EXTENSIONS
static void *
libxslt_xsltPythonExtModuleCtxtInit(xsltTransformContextPtr ctxt,
const xmlChar * URI) {
- PyObject *result;
+ PyObject *result = NULL;
PyObject *class = NULL;
#ifdef DEBUG_EXTENSIONS
PyObject *args) {
PyObject *py_retval;
int ret = 0;
- xmlChar *name;
xmlChar *ns_uri;
PyObject *pyobj_c;
return(py_retval);
}
-static void
-deallocateClasse(void *payload, xmlChar *name ATTRIBUTE_UNUSED) {
- PyObject *class = (PyObject *) payload;
-
-#ifdef DEBUG_EXTENSIONS
- printf("deallocateClasse(%s) called\n", name);
-#endif
-
- Py_XDECREF(class);
-}
-
/************************************************************************
* *
* Integrated cleanup *
if (libxslt_extModuleFunctions != NULL) {
xmlHashFree(libxslt_extModuleFunctions, deallocateCallback);
}
+ if (libxslt_extModuleElements != NULL) {
+ xmlHashFree(libxslt_extModuleElements, deallocateCallback);
+ }
+ if (libxslt_extModuleElementPreComp != NULL) {
+ xmlHashFree(libxslt_extModuleElementPreComp, deallocateCallback);
+ }
if (libxslt_extModuleClasses != NULL) {
xmlHashFree(libxslt_extModuleClasses, deallocateClasse);
}
--- /dev/null
+#!/usr/bin/python -u
+import sys
+import string
+import StringIO
+import libxml2
+# Memory debug specific
+libxml2.debugMemory(1)
+import libxslt
+
+EXT_URL="http://example.com/foo"
+
+insertNodeName = None
+transformNodeName = None
+
+def compile_test(style, inst, func):
+ pass
+
+def transform_test(ctx, node, inst, comp):
+ global insertNodeName
+
+ #
+ # Small check to verify the context is correcly accessed
+ #
+ try:
+ #
+ # FIXME add some more sanity checks
+ #
+ tctxt = libxslt.transformCtxt(_obj=ctx)
+ insertNodeName = tctxt.insertNode().name
+
+ # FIXME find and confirm the note being replaced is called 'test'
+ # transformNodeName = libxml2.xmlNode(inst).name
+ except:
+ pass
+
+ tctxt.insertNode().addContent('SUCCESS')
+
+
+
+styledoc = libxml2.parseDoc("""
+<xsl:stylesheet version='1.0'
+ xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
+ xmlns:foo='%s'
+ xsl:extension-element-prefixes='foo'>
+
+ <xsl:template match='/'>
+ <article><foo:test>FAILURE</foo:test></article>
+ <deeper><article><foo:test>something<foo:test>nested</foo:test>even</foo:test></article></deeper>
+ </xsl:template>
+</xsl:stylesheet>
+""" % EXT_URL)
+
+style = libxslt.parseStylesheetDoc(styledoc)
+libxslt.registerExtModuleElement("test", EXT_URL, compile_test, transform_test)
+doc = libxml2.parseDoc("<doc/>")
+result = style.applyStylesheet(doc, None)
+style.freeStylesheet()
+doc.freeDoc()
+
+
+extensions = StringIO.StringIO()
+libxslt.debugDumpExtensions(extensions)
+
+if 0 and extensions.buf.find(EXT_URL) < 0:
+ print "Element extension not registered (or dumping broken)"
+ sys.exit(1)
+
+root = result.children
+
+if root.name != "article":
+ print "Unexpected root node name"
+ sys.exit(1)
+if root.content != "SUCCESS":
+ print "Unexpected root node content, extension function failed"
+ sys.exit(1)
+if insertNodeName != 'article':
+ print "The function callback failed to access its context"
+ sys.exit(1)
+
+result.dump(sys.stdout)
+result.freeDoc()
+
+# Memory debug specific
+libxslt.cleanup()
+if libxml2.debugMemory(1) == 0:
+ print "OK"
+else:
+ print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+ libxml2.dumpMemory()