- 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
Daniel
This commit is contained in:
Daniel Veillard 2001-07-04 13:22:40 +00:00
parent 1e4297d54d
commit ffc52efd1d
15 changed files with 769 additions and 71 deletions

View File

@ -1,3 +1,14 @@
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

View File

@ -185,6 +185,7 @@ tests/REC1/Makefile
tests/REC2/Makefile
tests/REC/Makefile
tests/general/Makefile
tests/extensions/Makefile
tests/namespaces/Makefile
tests/numbers/Makefile
tests/documents/Makefile

View File

@ -18,15 +18,23 @@
#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 {
@ -36,6 +44,22 @@ 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 *
@ -52,21 +76,22 @@ struct _xsltExtDef {
* 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);
}
/**
@ -83,7 +108,6 @@ xsltFreeExtDef(xsltExtDefPtr extensiond) {
xmlFree(extensiond->prefix);
if (extensiond->URI != NULL)
xmlFree(extensiond->URI);
memset(extensiond, -1, sizeof(xsltExtDef));
xmlFree(extensiond);
}
@ -104,10 +128,89 @@ xsltFreeExtDefList(xsltExtDefPtr 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 *
* *
************************************************************************/
@ -156,6 +259,12 @@ xsltRegisterExtPrefix(xsltStylesheetPtr style,
return(0);
}
/************************************************************************
* *
* The extensions modules interfaces *
* *
************************************************************************/
/**
* xsltRegisterExtFunction:
* @ctxt: an XSLT transformation context
@ -173,6 +282,9 @@ xsltRegisterExtFunction(xsltTransformContextPtr ctxt, const xmlChar *name,
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));
@ -214,6 +326,166 @@ xsltFreeCtxtExts(xsltTransformContextPtr ctxt) {
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
@ -239,3 +511,103 @@ xsltCheckExtPrefix(xsltStylesheetPtr style, const xmlChar *prefix) {
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);
}

View File

@ -16,11 +16,51 @@
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,
@ -29,9 +69,22 @@ int xsltRegisterExtElement (xsltTransformContextPtr ctxt,
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

View File

@ -46,53 +46,55 @@
*
* 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;
}
}
}
@ -130,6 +132,32 @@ xsltFunctionNodeSet(xmlXPathParserContextPtr ctxt, int nargs){
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
@ -144,6 +172,8 @@ xsltRegisterExtras(xsltTransformContextPtr ctxt) {
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",

View File

@ -45,6 +45,15 @@ extern "C" {
#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);

View File

@ -35,6 +35,7 @@
#include "xsltInternals.h"
#include "xsltutils.h"
#include "functions.h"
#include "extensions.h"
#include "numbersInternals.h"
#include "keys.h"
#include "documents.h"
@ -153,7 +154,9 @@ xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs){
}
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) &&
@ -170,7 +173,7 @@ xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs){
} else {
xsltTransformContextPtr tctxt;
tctxt = (xsltTransformContextPtr) ctxt->context->extra;
tctxt = xsltXPathGetTransformContext(ctxt);
if (tctxt == NULL) {
xsltGenericError(xsltGenericErrorContext,
"document() : internal error tctxt == NULL\n");
@ -209,8 +212,6 @@ xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
const xmlChar *keyURI;
xsltTransformContextPtr tctxt;
tctxt = ((xsltTransformContextPtr)ctxt->context->extra);
if (nargs != 2) {
xsltGenericError(xsltGenericErrorContext,
"key() : expects two arguments\n");
@ -292,6 +293,8 @@ xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
obj2 = valuePop(ctxt);
value = obj2->stringval;
tctxt = xsltXPathGetTransformContext(ctxt);
nodelist = xsltGetKey(tctxt, key, keyURI, value);
valuePush(ctxt, xmlXPathWrapNodeSet(
xmlXPathNodeSetMerge(NULL, nodelist)));
@ -366,8 +369,14 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
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) {
@ -503,7 +512,7 @@ xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int 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) &&
@ -514,7 +523,8 @@ xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){
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)"));
@ -646,7 +656,7 @@ xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){
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");
@ -656,6 +666,165 @@ xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){
}
}
/************************************************************************
* *
* 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
@ -663,23 +832,27 @@ xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){
* 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);
}

View File

@ -2897,7 +2897,6 @@ xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
xsltStackElemPtr variables;
xsltStackElemPtr vptr;
if ((style == NULL) || (doc == NULL))
return(NULL);
ctxt = xsltNewTransformContext(style, doc);
@ -2971,9 +2970,11 @@ xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr 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 */

View File

@ -344,6 +344,7 @@ struct _xsltTransformContext {
*/
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 */

View File

@ -36,6 +36,7 @@
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
#include <libxslt/extensions.h>
#ifdef WIN32
#ifdef _MSC_VER
@ -442,6 +443,7 @@ main(int argc, char **argv)
}
xsltFreeStylesheet(cur);
}
xsltUnregisterAllExtModules();
xmlCleanupParser();
xmlMemoryDump();
return (0);

View File

@ -1,7 +1,7 @@
## 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:

View File

@ -0,0 +1,29 @@
## 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)

View File

@ -0,0 +1,3 @@
<?xml version="1.0"?>
<!--libxslt:test element test worked-->
SUCCESS

View File

@ -0,0 +1 @@
<doc/>

View File

@ -0,0 +1,12 @@
<?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>