+Wed Jul 4 15:15:50 CEST 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+ * libxslt/extension.[ch] libxslt/extra.[ch] libxslt/xsltInternals.h
+ libxslt/transform.c libxslt/functions.c: Added the extension API
+ suggested by Thomas Broyer, this should allow implementation of
+ EXSLT for example.
+ * libxslt/extra.[ch]: added a fake xsltFunctionLocalTime() in Norm's
+ CVS extension namespace to avoid complaints, some cleanup
+ * configure.in tests/Makefile.am tests/extensions/*: added a test
+ for new modules testing both elements and functions registration
+
Fri Jun 29 23:32:37 CEST 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
* libxslt/pattern.c libxslt/preproc.c libxslt/transform.c
tests/REC2/Makefile
tests/REC/Makefile
tests/general/Makefile
+tests/extensions/Makefile
tests/namespaces/Makefile
tests/numbers/Makefile
tests/documents/Makefile
#include <libxml/hash.h>
#include <libxml/xmlerror.h>
#include <libxml/parserInternals.h>
+#include <libxml/xpathInternals.h>
#include "xslt.h"
#include "xsltInternals.h"
#include "xsltutils.h"
+#include "imports.h"
#include "extensions.h"
#ifdef WITH_XSLT_DEBUG
#define WITH_XSLT_DEBUG_EXTENSIONS
#endif
+/************************************************************************
+ * *
+ * Private Types and Globals *
+ * *
+ ************************************************************************/
+
typedef struct _xsltExtDef xsltExtDef;
typedef xsltExtDef *xsltExtDefPtr;
struct _xsltExtDef {
void *data;
};
+typedef struct _xsltExtModule xsltExtModule;
+typedef xsltExtModule *xsltExtModulePtr;
+struct _xsltExtModule {
+ xsltExtInitFunction initFunc;
+ xsltExtShutdownFunction shutdownFunc;
+};
+
+typedef struct _xsltExtData xsltExtData;
+typedef xsltExtData *xsltExtDataPtr;
+struct _xsltExtData {
+ xsltExtModulePtr extModule;
+ void *extData;
+};
+
+static xmlHashTablePtr xsltExtensionsHash = NULL;
+
/************************************************************************
* *
* Type functions *
* Returns the newly allocated xsltExtDefPtr or NULL in case of error
*/
static xsltExtDefPtr
-xsltNewExtDef(const xmlChar *prefix, const xmlChar *URI) {
+xsltNewExtDef(const xmlChar * prefix, const xmlChar * URI)
+{
xsltExtDefPtr cur;
cur = (xsltExtDefPtr) xmlMalloc(sizeof(xsltExtDef));
if (cur == NULL) {
xsltGenericError(xsltGenericErrorContext,
- "xsltNewExtDef : malloc failed\n");
- return(NULL);
+ "xsltNewExtDef : malloc failed\n");
+ return (NULL);
}
memset(cur, 0, sizeof(xsltExtDef));
if (prefix != NULL)
- cur->prefix = xmlStrdup(prefix);
+ cur->prefix = xmlStrdup(prefix);
if (URI != NULL)
- cur->URI = xmlStrdup(URI);
- return(cur);
+ cur->URI = xmlStrdup(URI);
+ return (cur);
}
/**
xmlFree(extensiond->prefix);
if (extensiond->URI != NULL)
xmlFree(extensiond->URI);
- memset(extensiond, -1, sizeof(xsltExtDef));
xmlFree(extensiond);
}
}
}
+/**
+ * xsltNewExtModule:
+ * @initFunc: the module initialization function
+ * @shutdownFunc: the module shutdown function
+ *
+ * Create a new XSLT extension module
+ *
+ * Returns the newly allocated xsltExtModulePtr or NULL in case of error
+ */
+static xsltExtModulePtr
+xsltNewExtModule(xsltExtInitFunction initFunc,
+ xsltExtShutdownFunction shutdownFunc)
+{
+ xsltExtModulePtr cur;
+
+ cur = (xsltExtModulePtr) xmlMalloc(sizeof(xsltExtModule));
+ if (cur == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltNewExtModule : malloc failed\n");
+ return (NULL);
+ }
+ cur->initFunc = initFunc;
+ cur->shutdownFunc = shutdownFunc;
+ return (cur);
+}
+
+/**
+ * xsltFreeExtModule:
+ * @ext: an XSLT extension module
+ *
+ * Free up the memory allocated by @ext
+ */
+static void
+xsltFreeExtModule(xsltExtModulePtr ext) {
+ if (ext == NULL)
+ return;
+ xmlFree(ext);
+}
+
+/**
+ * xsltNewExtData:
+ * @extModule: the module
+ * @extData: the associated data
+ *
+ * Create a new XSLT extension module data wrapper
+ *
+ * Returns the newly allocated xsltExtDataPtr or NULL in case of error
+ */
+static xsltExtDataPtr
+xsltNewExtData(xsltExtModulePtr extModule, void *extData)
+{
+ xsltExtDataPtr cur;
+
+ if (extModule == NULL)
+ return(NULL);
+ cur = (xsltExtDataPtr) xmlMalloc(sizeof(xsltExtData));
+ if (cur == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltNewExtData : malloc failed\n");
+ return (NULL);
+ }
+ cur->extModule = extModule;
+ cur->extData = extData;
+ return (cur);
+}
+
+/**
+ * xsltFreeExtData:
+ * @ext: an XSLT extension module data wrapper
+ *
+ * Free up the memory allocated by @ext
+ */
+static void
+xsltFreeExtData(xsltExtDataPtr ext) {
+ if (ext == NULL)
+ return;
+ xmlFree(ext);
+}
+
/************************************************************************
* *
- * The interpreter for the precompiled patterns *
+ * The stylesheet extension prefixes handling *
* *
************************************************************************/
return(0);
}
+/************************************************************************
+ * *
+ * The extensions modules interfaces *
+ * *
+ ************************************************************************/
+
/**
* xsltRegisterExtFunction:
* @ctxt: an XSLT transformation context
if ((ctxt == NULL) || (name == NULL) ||
(URI == NULL) || (function == NULL))
return(-1);
+ if (ctxt->xpathCtxt != NULL) {
+ xmlXPathRegisterFuncNS(ctxt->xpathCtxt, name, URI, function);
+ }
if (ctxt->extFunctions == NULL)
ctxt->extFunctions = xmlHashCreate(10);
return(xmlHashAddEntry2(ctxt->extFunctions, name, URI, (void *) function));
xmlHashFree(ctxt->extFunctions, NULL);
}
+/**
+ * xsltGetExtData:
+ * @ctxt: an XSLT transformation context
+ * @URI: the URI associated to the exension module
+ *
+ * Retrieve the data associated to the extension module in this given
+ * transformation.
+ *
+ * Returns the pointer or NULL if not present
+ */
+void *
+xsltGetExtData(xsltTransformContextPtr ctxt, const xmlChar * URI)
+{
+ xsltExtDataPtr data;
+
+ if ((ctxt == NULL) || (ctxt->extInfos == NULL) || (URI == NULL))
+ return (NULL);
+ data = (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos, URI);
+ if (data == NULL)
+ return (NULL);
+ return (data->extData);
+}
+
+/**
+ * xsltInitCtxtExts:
+ * @ctxt: an XSLT transformation context
+ *
+ * Initialize the set of modules associated to the extension prefixes
+ *
+ * Returns the number of modules initialized or -1 in case of error
+ */
+int
+xsltInitCtxtExts(xsltTransformContextPtr ctxt)
+{
+ int ret = 0;
+ xsltStylesheetPtr style;
+ xsltExtDefPtr def;
+ xsltExtModulePtr module;
+ xsltExtDataPtr data;
+ void *extData;
+
+ if (ctxt == NULL)
+ return (-1);
+
+ style = ctxt->style;
+ if (style == NULL)
+ return (-1);
+ while (style != NULL) {
+ def = (xsltExtDefPtr) style->nsDefs;
+ while (def != NULL) {
+ if (def->URI != NULL) {
+ if (ctxt->extInfos == NULL) {
+ ctxt->extInfos = xmlHashCreate(10);
+ if (ctxt->extInfos == NULL)
+ return (-1);
+ data = NULL;
+ } else {
+ data =
+ (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos,
+ def->URI);
+ }
+ if (data == NULL) {
+ /*
+ * Register this module
+ */
+ module = xmlHashLookup(xsltExtensionsHash, def->URI);
+ if (module == NULL) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+ xsltGenericDebug(xsltGenericDebugContext,
+ "Not registered extension module : %s\n",
+ def->URI);
+#endif
+ } else {
+ if (module->initFunc != NULL) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+ xsltGenericDebug(xsltGenericDebugContext,
+ "Initializing module : %s\n",
+ def->URI);
+#endif
+ extData = module->initFunc(ctxt, def->URI);
+ } else {
+ extData = NULL;
+ }
+ data = xsltNewExtData(module, extData);
+ if (data == NULL)
+ return (-1);
+ if (xmlHashAddEntry(ctxt->extInfos, def->URI,
+ (void *) data) < 0) {
+ xsltGenericError(xsltGenericErrorContext,
+ "Failed to register module : %s\n",
+ def->URI);
+ } else {
+ ret++;
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+ xsltGenericDebug(xsltGenericDebugContext,
+ "Registered module : %s\n",
+ def->URI);
+#endif
+ }
+
+ }
+ }
+ }
+ def = def->next;
+ }
+ style = xsltNextImport(style);
+ }
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+ xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n", ret);
+#endif
+ return (ret);
+}
+
+/**
+ * xsltShutdownCtxtExt:
+ * @data: the registered data for the module
+ * @ctxt: the XSLT transformation context
+ * @URI: the extension URI
+ *
+ * Shutdown an extension module loaded
+ */
+static void
+xsltShutdownCtxtExt(xsltExtDataPtr data, xsltTransformContextPtr ctxt,
+ const xmlChar * URI)
+{
+ xsltExtModulePtr module;
+
+ if ((data == NULL) || (ctxt == NULL) || (URI == NULL))
+ return;
+ module = data->extModule;
+ if ((module == NULL) || (module->shutdownFunc == NULL))
+ return;
+
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+ xsltGenericDebug(xsltGenericDebugContext,
+ "Shutting down module : %s\n", URI);
+#endif
+ module->shutdownFunc(ctxt, URI, data->extData);
+ xmlHashRemoveEntry(ctxt->extInfos, URI,
+ (xmlHashDeallocator) xsltFreeExtData);
+}
+
+/**
+ * xsltShutdownCtxtExts:
+ * @ctxt: an XSLT transformation context
+ *
+ * Shutdown the set of modules loaded
+ */
+void
+xsltShutdownCtxtExts(xsltTransformContextPtr ctxt)
+{
+ if (ctxt == NULL)
+ return;
+ if (ctxt->extInfos == NULL)
+ return;
+ xmlHashScan(ctxt->extInfos, (xmlHashScanner) xsltShutdownCtxtExt, ctxt);
+ xmlHashFree(ctxt->extInfos, (xmlHashDeallocator) xsltFreeExtData);
+ ctxt->extInfos = NULL;
+}
+
/**
* xsltCheckExtPrefix:
* @style: the stylesheet
return(0);
}
+/**
+ * xsltRegisterExtModule:
+ * @URI: URI associated to this module
+ * @initFunc: the module initialization function
+ * @shutdownFunc: the module shutdown function
+ *
+ * Register an XSLT extension module to the library.
+ *
+ * Returns 0 if sucessful, -1 in case of error
+ */
+int
+xsltRegisterExtModule(const xmlChar * URI,
+ xsltExtInitFunction initFunc,
+ xsltExtShutdownFunction shutdownFunc)
+{
+ int ret;
+ xsltExtModulePtr module;
+
+ if ((URI == NULL) || (initFunc == NULL))
+ return (-1);
+ if (xsltExtensionsHash == NULL)
+ xsltExtensionsHash = xmlHashCreate(10);
+
+ if (xsltExtensionsHash == NULL)
+ return (-1);
+
+ module = xmlHashLookup(xsltExtensionsHash, URI);
+ if (module != NULL) {
+ if ((module->initFunc == initFunc) &&
+ (module->shutdownFunc == shutdownFunc))
+ return (0);
+ return (-1);
+ }
+ module = xsltNewExtModule(initFunc, shutdownFunc);
+ if (module == NULL)
+ return (-1);
+ ret = xmlHashAddEntry(xsltExtensionsHash, URI, (void *) module);
+ return (ret);
+}
+
+/**
+ * xsltUnregisterExtModule:
+ * @URI: URI associated to this module
+ *
+ * Unregister an XSLT extension module from the library.
+ *
+ * Returns 0 if sucessful, -1 in case of error
+ */
+int
+xsltUnregisterExtModule(const xmlChar * URI)
+{
+ int ret;
+
+ if (URI == NULL)
+ return (-1);
+ if (xsltExtensionsHash == NULL)
+ return (-1);
+
+ ret =
+ xmlHashRemoveEntry(xsltExtensionsHash, URI,
+ (xmlHashDeallocator) xsltFreeExtModule);
+ return (ret);
+}
+
+/**
+ * xsltUnregisterExtModule:
+ *
+ * Unregister all the XSLT extension module from the library.
+ */
+void
+xsltUnregisterAllExtModules(void)
+{
+ if (xsltExtensionsHash == NULL)
+ return;
+
+ xmlHashFree(xsltExtensionsHash, (xmlHashDeallocator) xsltFreeExtModule);
+ xsltExtensionsHash = NULL;
+}
+
+/**
+ * xsltXPathGetTransformContext:
+ * @ctxt: an XPath transformation context
+ *
+ * Returns the XSLT transformation context from the XPath transformation
+ * context. This is useful when an XPath function in the extension module
+ * is called by the XPath interpreter and that the XSLT context is needed
+ * for example to retrieve the associated data pertaining to this XSLT
+ * transformation.
+ *
+ * Returns the XSLT transformation context or NULL in case of error.
+ */
+xsltTransformContextPtr
+xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt)
+{
+ if ((ctxt == NULL) || (ctxt->context == NULL))
+ return(NULL);
+ return(ctxt->context->extra);
+}
+
+
extern "C" {
#endif
-int xsltRegisterExtPrefix (xsltStylesheetPtr style,
- const xmlChar *prefix,
+/**
+ * Extension Modules API
+ */
+
+/**
+ * xsltExtInitFunction:
+ * @ctxt: an XSLT transformation context
+ * @URI: the namespace URI for the extension
+ *
+ * A function called at initialization time of an XSLT extension module
+ *
+ * Returns a pointer to the module specific data for this transformation
+ */
+typedef void * (*xsltExtInitFunction) (xsltTransformContextPtr ctxt,
const xmlChar *URI);
-int xsltCheckExtPrefix (xsltStylesheetPtr style,
- const xmlChar *prefix);
+
+/**
+ * xsltExtShutdownFunction:
+ * @ctxt: an XSLT transformation context
+ * @URI: the namespace URI for the extension
+ * @data: the data associated to this module
+ *
+ * A function called at shutdown time of an XSLT extension module
+ */
+typedef void (*xsltExtShutdownFunction) (xsltTransformContextPtr ctxt,
+ const xmlChar *URI,
+ void *data);
+
+int xsltRegisterExtModule (const xmlChar *URI,
+ xsltExtInitFunction initFunc,
+ xsltExtShutdownFunction shutdownFunc);
+
+int xsltUnregisterExtModule (const xmlChar * URI);
+
+void xsltUnregisterAllExtModules(void);
+
+void * xsltGetExtData (xsltTransformContextPtr ctxt,
+ const xmlChar *URI);
+
+void xsltShutdownCtxtExts (xsltTransformContextPtr ctxt);
+
+xsltTransformContextPtr
+ xsltXPathGetTransformContext
+ (xmlXPathParserContextPtr ctxt);
+
int xsltRegisterExtFunction (xsltTransformContextPtr ctxt,
const xmlChar *name,
const xmlChar *URI,
const xmlChar *name,
const xmlChar *URI,
xsltTransformFunction function);
+
+/**
+ * Extension Prefix handling API
+ * Those are used by the XSLT (pre)processor.
+ */
+
+int xsltRegisterExtPrefix (xsltStylesheetPtr style,
+ const xmlChar *prefix,
+ const xmlChar *URI);
+int xsltCheckExtPrefix (xsltStylesheetPtr style,
+ const xmlChar *prefix);
+int xsltInitCtxtExts (xsltTransformContextPtr ctxt);
void xsltFreeCtxtExts (xsltTransformContextPtr ctxt);
void xsltFreeExts (xsltStylesheetPtr style);
+
#ifdef __cplusplus
}
#endif
*
* Process an debug node
*/
-void
+void
xsltDebug(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
- xmlNodePtr inst ATTRIBUTE_UNUSED, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
+ xmlNodePtr inst ATTRIBUTE_UNUSED,
+ xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
+{
int i, j;
fprintf(stdout, "Templates:\n");
- for (i = 0, j = ctxt->templNr - 1;((i < 15) && (j >= 0));i++,j--) {
- fprintf(stdout, "#%d ", i);
- if (ctxt->templTab[j]->name != NULL)
- fprintf(stdout, "name %s ", ctxt->templTab[j]->name);
- if (ctxt->templTab[j]->match != NULL)
- fprintf(stdout, "name %s ", ctxt->templTab[j]->match);
- if (ctxt->templTab[j]->mode != NULL)
- fprintf(stdout, "name %s ", ctxt->templTab[j]->mode);
- fprintf(stdout, "\n");
+ for (i = 0, j = ctxt->templNr - 1; ((i < 15) && (j >= 0)); i++, j--) {
+ fprintf(stdout, "#%d ", i);
+ if (ctxt->templTab[j]->name != NULL)
+ fprintf(stdout, "name %s ", ctxt->templTab[j]->name);
+ if (ctxt->templTab[j]->match != NULL)
+ fprintf(stdout, "name %s ", ctxt->templTab[j]->match);
+ if (ctxt->templTab[j]->mode != NULL)
+ fprintf(stdout, "name %s ", ctxt->templTab[j]->mode);
+ fprintf(stdout, "\n");
}
fprintf(stdout, "Variables:\n");
- for (i = 0, j = ctxt->varsNr - 1;((i < 15) && (j >= 0));i++,j--) {
- xsltStackElemPtr cur;
+ for (i = 0, j = ctxt->varsNr - 1; ((i < 15) && (j >= 0)); i++, j--) {
+ xsltStackElemPtr cur;
- if (ctxt->varsTab[j] == NULL)
- continue;
- fprintf(stdout, "#%d\n", i);
- cur = ctxt->varsTab[j];
- while (cur != NULL) {
- if (cur->comp == NULL) {
- fprintf(stdout, "corrupted !!!\n");
- } else if (cur->comp->type == XSLT_FUNC_PARAM) {
- fprintf(stdout, "param ");
- } else if (cur->comp->type == XSLT_FUNC_VARIABLE) {
- fprintf(stdout, "var ");
- }
- if (cur->name != NULL)
- fprintf(stdout, "%s ", cur->name);
- else
- fprintf(stdout, "noname !!!!");
+ if (ctxt->varsTab[j] == NULL)
+ continue;
+ fprintf(stdout, "#%d\n", i);
+ cur = ctxt->varsTab[j];
+ while (cur != NULL) {
+ if (cur->comp == NULL) {
+ fprintf(stdout, "corrupted !!!\n");
+ } else if (cur->comp->type == XSLT_FUNC_PARAM) {
+ fprintf(stdout, "param ");
+ } else if (cur->comp->type == XSLT_FUNC_VARIABLE) {
+ fprintf(stdout, "var ");
+ }
+ if (cur->name != NULL)
+ fprintf(stdout, "%s ", cur->name);
+ else
+ fprintf(stdout, "noname !!!!");
#ifdef LIBXML_DEBUG_ENABLED
- if (cur->value != NULL) {
- xmlXPathDebugDumpObject(stdout, cur->value, 1);
- } else {
- fprintf(stdout, "NULL !!!!");
- }
+ if (cur->value != NULL) {
+ xmlXPathDebugDumpObject(stdout, cur->value, 1);
+ } else {
+ fprintf(stdout, "NULL !!!!");
+ }
#endif
- fprintf(stdout, "\n");
- cur = cur->next;
- }
-
+ fprintf(stdout, "\n");
+ cur = cur->next;
+ }
+
}
}
ctxt->value->boolval = 1;
}
+/**
+ * xsltFunctionLocalTime:
+ * @ctxt: the XPath Parser context
+ * @nargs: the number of arguments
+ *
+ * Implement the localTime XSLT function used by NORM
+ * string localTime(???)
+ *
+ * This function is available in Norm's extension namespace
+ */
+static void
+xsltFunctionLocalTime(xmlXPathParserContextPtr ctxt, int nargs) {
+ if ((nargs < 0) || (nargs > 1)) {
+ xsltGenericError(xsltGenericErrorContext,
+ "localTime() : invalid number of args %d\n", nargs);
+ ctxt->error = XPATH_INVALID_ARITY;
+ return;
+ }
+ /* TODO : Norm's localTime() extension */
+ if (nargs == 1) {
+ xmlXPathStringFunction(ctxt, 1);
+ } else {
+ valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
+ }
+}
+
/**
* xsltRegisterExtras:
* @ctxt: a XSLT process context
XSLT_SAXON_NAMESPACE, xsltFunctionNodeSet);
xsltRegisterExtFunction(ctxt, (const xmlChar *) "node-set",
XSLT_XT_NAMESPACE, xsltFunctionNodeSet);
+ xsltRegisterExtFunction(ctxt, (const xmlChar *) "localTime",
+ XSLT_NORM_SAXON_NAMESPACE, xsltFunctionLocalTime);
xsltRegisterExtElement(ctxt, (const xmlChar *) "debug",
XSLT_LIBXSLT_NAMESPACE, xsltDebug);
xsltRegisterExtElement(ctxt, (const xmlChar *) "output",
#define XSLT_XALAN_NAMESPACE ((xmlChar *) \
"org.apache.xalan.xslt.extensions.Redirect")
+/**
+ * XSLT_NORM_SAXON_NAMESPACE:
+ *
+ * This is Nom's namespace for SAXON extensions
+ */
+#define XSLT_NORM_SAXON_NAMESPACE ((xmlChar *) \
+ "http://nwalsh.com/xslt/ext/com.nwalsh.saxon.CVS")
+
+
void xsltFunctionNodeSet (xmlXPathParserContextPtr ctxt,
int nargs);
#include "xsltInternals.h"
#include "xsltutils.h"
#include "functions.h"
+#include "extensions.h"
#include "numbersInternals.h"
#include "keys.h"
#include "documents.h"
}
base = xmlNodeGetBase(target->doc, target);
} else {
- xsltTransformContextPtr tctxt = ctxt->context->extra;
+ xsltTransformContextPtr tctxt;
+
+ tctxt = xsltXPathGetTransformContext(ctxt);
if ((tctxt != NULL) && (tctxt->inst != NULL)) {
base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst);
} else if ((tctxt != NULL) && (tctxt->style != NULL) &&
} else {
xsltTransformContextPtr tctxt;
- tctxt = (xsltTransformContextPtr) ctxt->context->extra;
+ tctxt = xsltXPathGetTransformContext(ctxt);
if (tctxt == NULL) {
xsltGenericError(xsltGenericErrorContext,
"document() : internal error tctxt == NULL\n");
const xmlChar *keyURI;
xsltTransformContextPtr tctxt;
- tctxt = ((xsltTransformContextPtr)ctxt->context->extra);
-
if (nargs != 2) {
xsltGenericError(xsltGenericErrorContext,
"key() : expects two arguments\n");
obj2 = valuePop(ctxt);
value = obj2->stringval;
+ tctxt = xsltXPathGetTransformContext(ctxt);
+
nodelist = xsltGetKey(tctxt, key, keyURI, value);
valuePush(ctxt, xmlXPathWrapNodeSet(
xmlXPathNodeSetMerge(NULL, nodelist)));
xsltStylesheetPtr sheet;
xsltDecimalFormatPtr formatValues;
xmlChar *result;
+ xsltTransformContextPtr tctxt;
- sheet = ((xsltTransformContextPtr)ctxt->context->extra)->style;
+ tctxt = xsltXPathGetTransformContext(ctxt);
+ if (tctxt == NULL)
+ return;
+ sheet = tctxt->style;
+ if (sheet == NULL)
+ return;
formatValues = sheet->decimalFormat;
switch (nargs) {
xsltStylesheetPtr sheet;
xsltTransformContextPtr tctxt;
- tctxt = (xsltTransformContextPtr)ctxt->context->extra;
+ tctxt = xsltXPathGetTransformContext(ctxt);
if ((tctxt != NULL) && (tctxt->inst != NULL) &&
(xmlStrEqual(tctxt->inst->name, BAD_CAST "variable")) &&
(tctxt->inst->parent != NULL) &&
sheet = NULL;
if ((sheet != NULL) && (sheet->doc != NULL) &&
(sheet->doc->URL != NULL) &&
- (xmlStrstr(sheet->doc->URL, "chunk") != NULL)) {
+ (xmlStrstr(sheet->doc->URL,
+ (const xmlChar *)"chunk") != NULL)) {
valuePush(ctxt, xmlXPathNewString(
(const xmlChar *)"libxslt (SAXON 6.2 compatible)"));
ctxt->error = XPATH_INVALID_ARITY;
return;
}
- tctxt = (xsltTransformContextPtr) ctxt->context->extra;
+ tctxt = xsltXPathGetTransformContext(ctxt);
if (tctxt == NULL) {
xsltGenericError(xsltGenericErrorContext,
"current() : internal error tctxt == NULL\n");
}
}
+/************************************************************************
+ * *
+ * Test of the extension module API *
+ * *
+ ************************************************************************/
+
+static xmlChar *testData = NULL;
+
+/**
+ * xsltExtFunctionTest:
+ * @ctxt: the XPath Parser context
+ * @nargs: the number of arguments
+ *
+ * function libxslt:test() for testing the extensions support.
+ */
+static void
+xsltExtFunctionTest(xmlXPathParserContextPtr ctxt, int nargs)
+{
+ xsltTransformContextPtr tctxt;
+ void *data;
+
+ if (testData == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtFunctionTest: not initialized\n");
+ return;
+ }
+ tctxt = xsltXPathGetTransformContext(ctxt);
+ if (tctxt == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtFunctionTest: failed to get the transformation context\n");
+ return;
+ }
+ data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
+ if (data == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtFunctionTest: failed to get module data\n");
+ return;
+ }
+ if (data != testData) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtFunctionTest: got wrong module data\n");
+ return;
+ }
+#ifdef WITH_XSLT_DEBUG_FUNCTION
+ xsltGenericDebug(xsltGenericDebugContext,
+ "libxslt:test() called with %d args\n", nargs);
+#endif
+}
+
+/**
+ * xsltExtElementTest:
+ * @ctxt: an XSLT processing context
+ * @node: The current node
+ * @inst: the instruction in the stylesheet
+ * @comp: precomputed informations
+ *
+ * Process an debug node
+ */
+static void
+xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
+ xmlNodePtr inst,
+ xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
+{
+ xmlNodePtr comment;
+
+ if (testData == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtElementTest: not initialized\n");
+ return;
+ }
+ if (ctxt == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtElementTest: no transformation context\n");
+ return;
+ }
+ if (node == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtElementTest: no current node\n");
+ return;
+ }
+ if (inst == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtElementTest: no instruction\n");
+ return;
+ }
+ if (ctxt->insert == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtElementTest: no insertion point\n");
+ return;
+ }
+ comment =
+ xmlNewComment((const xmlChar *)
+ "libxslt:test element test worked");
+ xmlAddChild(ctxt->insert, comment);
+}
+
+/**
+ * xsltExtInitTest:
+ * @ctxt: an XSLT transformation context
+ * @URI: the namespace URI for the extension
+ *
+ * A function called at initialization time of an XSLT extension module
+ *
+ * Returns a pointer to the module specific data for this transformation
+ */
+static void *
+xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI)
+{
+ if (testData != NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtInitTest: already initialized\n");
+ return (NULL);
+ }
+ testData = (void *) "test data";
+ xsltRegisterExtFunction(ctxt, (const xmlChar *) "test",
+ (const xmlChar *) XSLT_DEFAULT_URL,
+ xsltExtFunctionTest);
+ xsltRegisterExtElement(ctxt, (const xmlChar *) "test",
+ (const xmlChar *) XSLT_DEFAULT_URL,
+ xsltExtElementTest);
+
+ xsltGenericDebug(xsltGenericDebugContext,
+ "Registered test module : %s\n", URI);
+ return (testData);
+}
+
+
+/**
+ * xsltExtShutdownTest:
+ * @ctxt: an XSLT transformation context
+ * @URI: the namespace URI for the extension
+ * @data: the data associated to this module
+ *
+ * A function called at shutdown time of an XSLT extension module
+ */
+static void
+xsltExtShutdownTest(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
+ const xmlChar * URI, void *data)
+{
+ if (testData == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtShutdownTest: not initialized\n");
+ return;
+ }
+ if (data != testData) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtShutdownTest: wrong data\n");
+ }
+ testData = NULL;
+ xsltGenericDebug(xsltGenericDebugContext,
+ "Unregistered test module : %s\n", URI);
+}
+
+/************************************************************************
+ * *
+ * Registration of XSLT and libxslt functions *
+ * *
+ ************************************************************************/
+
/**
* xsltRegisterAllFunctions:
* @ctxt: the XPath context
* Registers all default XSLT functions in this context
*/
void
-xsltRegisterAllFunctions(xmlXPathContextPtr ctxt) {
- xmlXPathRegisterFunc(ctxt, (const xmlChar *)"current",
+xsltRegisterAllFunctions(xmlXPathContextPtr ctxt)
+{
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "current",
xsltCurrentFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *)"document",
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "document",
xsltDocumentFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *)"key",
- xsltKeyFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *)"unparsed-entity-uri",
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "key", xsltKeyFunction);
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "unparsed-entity-uri",
xsltUnparsedEntityURIFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *)"format-number",
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "format-number",
xsltFormatNumberFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *)"generate-id",
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "generate-id",
xsltGenerateIdFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *)"system-property",
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "system-property",
xsltSystemPropertyFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *)"element-available",
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "element-available",
xsltElementAvailableFunction);
- xmlXPathRegisterFunc(ctxt, (const xmlChar *)"function-available",
+ xmlXPathRegisterFunc(ctxt, (const xmlChar *) "function-available",
xsltFunctionAvailableFunction);
+
+ xsltRegisterExtModule((const xmlChar *) XSLT_DEFAULT_URL,
+ xsltExtInitTest,
+ xsltExtShutdownTest);
}
xsltStackElemPtr variables;
xsltStackElemPtr vptr;
-
if ((style == NULL) || (doc == NULL))
return(NULL);
ctxt = xsltNewTransformContext(style, doc);
xsltEvalUserParams(ctxt, params);
xsltEvalGlobalVariables(ctxt);
ctxt->node = (xmlNodePtr) doc;
+ xsltInitCtxtExts(ctxt);
varsPush(ctxt, NULL);
xsltProcessOneNode(ctxt, ctxt->node);
xsltFreeStackElemList(varsPop(ctxt));
+ xsltShutdownCtxtExts(ctxt);
xsltCleanupTemplates(style); /* TODO: <- style should be read only */
*/
xmlHashTablePtr extFunctions; /* the extension functions */
xmlHashTablePtr extElements; /* the extension elements */
+ xmlHashTablePtr extInfos; /* the extension data */
const xmlChar *mode; /* the current mode */
const xmlChar *modeURI; /* the current mode URI */
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
+#include <libxslt/extensions.h>
#ifdef WIN32
#ifdef _MSC_VER
}
xsltFreeStylesheet(cur);
}
+ xsltUnregisterAllExtModules();
xmlCleanupParser();
xmlMemoryDump();
return (0);
## Process this file with automake to produce Makefile.in
SUBDIRS=docs REC1 REC2 REC general namespaces numbers documents \
- xmlspec multiple XSLTMark docbook
+ extensions xmlspec multiple XSLTMark docbook
all:
--- /dev/null
+## Process this file with automake to produce Makefile.in
+
+$(top_builddir)/libxslt/xsltproc:
+ @(cd ../../libxslt ; make xsltproc)
+
+EXTRA_DIST = \
+ module.xml module.xsl module.out
+
+
+all: test
+
+test tests: $(top_builddir)/libxslt/xsltproc
+ @(echo > .memdump)
+ @(for i in $(srcdir)/*.xml ; do \
+ if [ -d $$i ] ; then continue ; fi ; \
+ doc=`basename $$i .xml` ; \
+ for j in $(srcdir)/$$doc*.xsl ; do \
+ if [ ! -f $$j ] ; then continue ; fi ; \
+ if [ -d $$j ] ; then continue ; fi ; \
+ name=`basename $$j .xsl`; \
+ out=$(srcdir)/"$$name".out; \
+ echo Running $$j on $$i ; \
+ $(top_builddir)/libxslt/xsltproc $$j $$i > result.$$name;\
+ if [ ! -f $$out ] ; then cp result.$$name $$out ; \
+ else diff $$out result.$$name; fi ; \
+ grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0" || true;\
+ rm -f result.$$name ; \
+ done ; done)
+
--- /dev/null
+<?xml version="1.0"?>
+<!--libxslt:test element test worked-->
+SUCCESS
--- /dev/null
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:libxslt="http://xmlsoft.org/XSLT/"
+ xmlns:test="http://xmlsoft.org/XSLT/"
+ xsl:extension-element-prefixes="libxslt test"
+ version='1.0'>
+<!-- the prefix is registered twice to check single initialization -->
+<xsl:template match="/">
+<libxslt:test/>
+<xsl:value-of select="libxslt:test('SUCCESS')"/>
+</xsl:template>
+</xsl:stylesheet>