diff --git a/ChangeLog b/ChangeLog index ffd311be..289018e9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +Thu Jul 26 19:05:48 CEST 2001 Thomas Broyer + + * libxslt/extensions.[ch] libxslt/functions.[ch] libxslt/preproc.c + libxslt/transform.[ch] libxslt/variables.c libxslt/xslt.c + libxslt/xsltInternals.h: new extension framework. + Added stylesheet module data, top-level and extension elements + precomputing, global registration of top-level elements and + extension elements and functions. + Extensions are no longer initialized from extension-element-prefixes + declarations but when modules need the data. + init/shutdown functions registered with xsltRegisterExtModule{,Full} + only allocate and free module data, they shouldn't register the + elements and functions any more. + * libxslt/xsltutils.c: fixed a bug in xsltPrintErrorContext when + @node wasn't NULL. + * libxslt/xslt.c: fixed xsltPrecomputeStylesheetTop which allowed + non-XSLT top-level elements before any xsl:import element. + * libexslt/common.c libexslt/functions.c libexslt/math.c + libexslt/sets.c: adapted to use the new extension framework. + * libxslt/functions.c libxslt/extensions[ch] xsltproc/xsltproc.c: + moved the test module from functions.c to extensions.[ch], + modified it to use the new extension framework. Updated xsltproc + to register the test module. + Thu Jul 26 10:20:19 EDT 2001 Daniel Veillard * libxslt/pattern.c: fixed an ugly problem with namespaces diff --git a/libexslt/common.c b/libexslt/common.c index 07614796..1b2e474b 100644 --- a/libexslt/common.c +++ b/libexslt/common.c @@ -52,19 +52,6 @@ exsltObjectTypeFunction (xmlXPathParserContextPtr ctxt, int nargs) { } -static void * -exsltCommonInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { - xsltRegisterExtFunction (ctxt, (const xmlChar *) "node-set", - URI, xsltFunctionNodeSet); - xsltRegisterExtFunction (ctxt, (const xmlChar *) "object-type", - URI, exsltObjectTypeFunction); - - xsltRegisterExtElement (ctxt, (const xmlChar *) "document", - URI, xsltDocumentElem); - - return(NULL); -} - /** * exsltCommonRegister: * @@ -73,6 +60,13 @@ exsltCommonInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { void exsltCommonRegister (void) { - xsltRegisterExtModule (EXSLT_COMMON_NAMESPACE, - exsltCommonInit, NULL); + xsltRegisterExtModuleFunction((const xmlChar *) "node-set", + EXSLT_COMMON_NAMESPACE, + xsltFunctionNodeSet); + xsltRegisterExtModuleFunction((const xmlChar *) "object-type", + EXSLT_COMMON_NAMESPACE, + exsltObjectTypeFunction); + xsltRegisterExtModuleElement((const xmlChar *) "document", + EXSLT_COMMON_NAMESPACE, + NULL, xsltDocumentElem); } diff --git a/libexslt/functions.c b/libexslt/functions.c index 1fc93719..c5910eaf 100644 --- a/libexslt/functions.c +++ b/libexslt/functions.c @@ -23,12 +23,32 @@ struct _exsltFuncData { int error; }; -static void exsltFuncFunctionElem (xsltTransformContextPtr ctxt, - xmlNodePtr node, xmlNodePtr inst, - xsltStylePreCompPtr comp); -static void exsltFuncResultElem (xsltTransformContextPtr ctxt, - xmlNodePtr node, xmlNodePtr inst, - xsltStylePreCompPtr comp); + +static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, + int nargs); + +/** + * exsltFuncRegisterFunc: + * @func: the #exsltFuncFunctionData for the function + * @ctxt: an XSLT transformation context + * @URI: the function namespace URI + * @name: the function name + * + * Registers a function declared by a func:function element + */ +static void +exsltFuncRegisterFunc (exsltFuncFunctionData *data, + xsltTransformContextPtr ctxt, + const xmlChar *URI, const xmlChar *name) { + if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL)) + return; + + xsltGenericDebug(xsltGenericDebugContext, + "exsltFuncRegisterFunc: register {%s}%s\n", + URI, name); + xsltRegisterExtFunction(ctxt, name, URI, + exsltFuncFunctionFunction); +} /** * exsltFuncInit: @@ -41,6 +61,7 @@ static void exsltFuncResultElem (xsltTransformContextPtr ctxt, */ static exsltFuncData * exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { + xmlHashTablePtr hash; exsltFuncData *ret; ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData)); @@ -51,15 +72,13 @@ exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { } memset(ret, 0, sizeof(exsltFuncData)); - ret->funcs = xmlHashCreate(1); ret->result = NULL; ret->error = 0; - xsltRegisterExtElement (ctxt, (const xmlChar *) "function", - URI, exsltFuncFunctionElem); - xsltRegisterExtElement (ctxt, (const xmlChar *) "result", - URI, exsltFuncResultElem); + hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI); + xmlHashScanFull(hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt); + ret->funcs = hash; return(ret); } @@ -67,7 +86,7 @@ exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { /** * exsltFuncShutdown: * @ctxt: an XSLT transformation context - * @URI: the namespace URI fir the extension + * @URI: the namespace URI for the extension * @data: the module data to free up * * Shutdown the EXSLT - Functions module @@ -76,23 +95,39 @@ static void exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, const xmlChar *URI ATTRIBUTE_UNUSED, exsltFuncData *data) { - if (data->funcs != NULL) - xmlHashFree(data->funcs, (xmlHashDeallocator) xmlFree); if (data->result != NULL) xmlXPathFreeObject(data->result); xmlFree(data); } /** - * exsltFuncRegister: + * exsltFuncStyleInit: + * @style: an XSLT stylesheet + * @URI: the namespace URI for the extension * - * Registers the EXSLT - Functions module + * Allocates the styleshet data for EXSLT - Function + * + * Returns the allocated data */ -void -exsltFuncRegister (void) { - xsltRegisterExtModule (EXSLT_FUNCTIONS_NAMESPACE, - (xsltExtInitFunction) exsltFuncInit, - (xsltExtShutdownFunction) exsltFuncShutdown); +static xmlHashTablePtr +exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED, + const xmlChar *URI ATTRIBUTE_UNUSED) { + return xmlHashCreate(1); +} + +/** + * exsltFuncStyleShutdown: + * @style: an XSLT stylesheet + * @URI: the namespace URI for the extension + * @data: the stylesheet data to free up + * + * Shutdown the EXSLT - Function module + */ +static void +exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED, + const xmlChar *URI ATTRIBUTE_UNUSED, + xmlHashTablePtr data) { + xmlHashFree(data, NULL); } /** @@ -112,6 +147,7 @@ exsltFuncNewFunctionData (void) { "exsltFuncNewFunctionData: not enough memory\n"); return (NULL); } + memset(ret, 0, sizeof(exsltFuncFunctionData)); ret->nargs = 0; ret->content = NULL; @@ -124,11 +160,12 @@ exsltFuncNewFunctionData (void) { * @ctxt: an XPath parser context * @nargs: the number of arguments * - * Evaluates the func:function element defining the called function. + * Evaluates the func:function element that defines the called function. */ static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr obj, oldResult, ret; + xmlHashTablePtr funcs; exsltFuncData *data; exsltFuncFunctionData *func; xmlNodePtr paramNode, oldInsert, fake; @@ -215,6 +252,7 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) { * the generation of result nodes. */ if (fake->children != NULL) { + xmlDebugDumpNode (stderr, fake, 1); xsltGenericError(xsltGenericErrorContext, "{%s}%s: cannot write to result tree while " "executing a function\n", @@ -224,16 +262,15 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) { valuePush(ctxt, ret); } + static void -exsltFuncFunctionElem (xsltTransformContextPtr ctxt, xmlNodePtr node, - xmlNodePtr inst, xsltStylePreCompPtr comp) { +exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) { xmlChar *name, *prefix; xmlNsPtr ns; - exsltFuncData *data; + xmlHashTablePtr data; exsltFuncFunctionData *func; - xsltStylePreCompPtr param_comp; - if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) + if ((style == NULL) || (inst == NULL)) return; { @@ -267,27 +304,36 @@ exsltFuncFunctionElem (xsltTransformContextPtr ctxt, xmlNodePtr node, */ func = exsltFuncNewFunctionData(); func->content = inst->children; - param_comp = (xsltStylePreCompPtr) func->content->_private; - while ((param_comp != NULL) && (param_comp->type == XSLT_FUNC_PARAM)) { + while (IS_XSLT_ELEM(func->content) && + IS_XSLT_NAME(func->content, "param")) { func->content = func->content->next; func->nargs++; - param_comp = (xsltStylePreCompPtr) func->content->_private; } + xsltParseTemplateContent(style, inst); + /* * Register the function data such that it can be retrieved * by exslFuncFunctionFunction */ - data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE); - xmlHashAddEntry2 (data->funcs, ns->href, name, func); - - /* - * Register the function such that it is available for use in XPath - * expressions. - */ - xsltRegisterExtFunction (ctxt, name, ns->href, - exsltFuncFunctionFunction); + data = (xmlHashTablePtr) xsltStyleGetExtData (style, + EXSLT_FUNCTIONS_NAMESPACE); + if (data == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncFunctionComp: no stylesheet data\n"); + xmlFree(name); + return; + } + if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) { + xsltGenericError(xsltGenericErrorContext, + "Failed to register function {%s}%s\n", + ns->href, name); + } else { + xsltGenericDebug(xsltGenericDebugContext, + "exsltFuncFunctionComp: register {%s}%s\n", + ns->href, name); + } xmlFree(name); } @@ -416,3 +462,25 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt, xmlNodePtr node, } data->result = ret; } + +/** + * exsltFuncRegister: + * + * Registers the EXSLT - Functions module + */ +void +exsltFuncRegister (void) { + xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE, + (xsltExtInitFunction) exsltFuncInit, + (xsltExtShutdownFunction) exsltFuncShutdown, + (xsltStyleExtInitFunction) exsltFuncStyleInit, + (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown); + + xsltRegisterExtModuleTopLevel ((const xmlChar *) "function", + EXSLT_FUNCTIONS_NAMESPACE, + exsltFuncFunctionComp); + xsltRegisterExtModuleElement ((const xmlChar *) "result", + EXSLT_FUNCTIONS_NAMESPACE, + NULL, + exsltFuncResultElem); +} diff --git a/libexslt/math.c b/libexslt/math.c index c9bb1a8d..ddb2fbdb 100644 --- a/libexslt/math.c +++ b/libexslt/math.c @@ -271,19 +271,6 @@ exsltMathLowestFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathReturnNodeSet(ctxt, ret); } -static void * -exsltMathInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { - xsltRegisterExtFunction (ctxt, (const xmlChar *) "min", - URI, exsltMathMinFunction); - xsltRegisterExtFunction (ctxt, (const xmlChar *) "max", - URI, exsltMathMaxFunction); - xsltRegisterExtFunction (ctxt, (const xmlChar *) "highest", - URI, exsltMathHighestFunction); - xsltRegisterExtFunction (ctxt, (const xmlChar *) "lowest", - URI, exsltMathLowestFunction); - return(NULL); -} - /** * exsltMathRegister: * @@ -292,5 +279,16 @@ exsltMathInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { void exsltMathRegister (void) { - xsltRegisterExtModule (EXSLT_MATH_NAMESPACE, exsltMathInit, NULL); + xsltRegisterExtModuleFunction ((const xmlChar *) "min", + EXSLT_MATH_NAMESPACE, + exsltMathMinFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "max", + EXSLT_MATH_NAMESPACE, + exsltMathMaxFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "highest", + EXSLT_MATH_NAMESPACE, + exsltMathHighestFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "lowest", + EXSLT_MATH_NAMESPACE, + exsltMathLowestFunction); } diff --git a/libexslt/sets.c b/libexslt/sets.c index f53e5758..7668d64c 100644 --- a/libexslt/sets.c +++ b/libexslt/sets.c @@ -221,24 +221,6 @@ exsltSetsTrailingFunction (xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathReturnNodeSet(ctxt, ret); } -static void * -exsltSetsInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { - xsltRegisterExtFunction (ctxt, (const xmlChar *) "difference", - URI, exsltSetsDifferenceFunction); - xsltRegisterExtFunction (ctxt, (const xmlChar *) "intersection", - URI, exsltSetsIntersectionFunction); - xsltRegisterExtFunction (ctxt, (const xmlChar *) "distinct", - URI, exsltSetsDistinctFunction); - xsltRegisterExtFunction (ctxt, (const xmlChar *) "has-same-nodes", - URI, exsltSetsHasSameNodesFunction); - xsltRegisterExtFunction (ctxt, (const xmlChar *) "leading", - URI, exsltSetsLeadingFunction); - xsltRegisterExtFunction (ctxt, (const xmlChar *) "trailing", - URI, exsltSetsTrailingFunction); - - return(NULL); -} - /** * exsltCommonRegister: * @@ -247,5 +229,22 @@ exsltSetsInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { void exsltSetsRegister (void) { - xsltRegisterExtModule (EXSLT_SETS_NAMESPACE, exsltSetsInit, NULL); + xsltRegisterExtModuleFunction ((const xmlChar *) "difference", + EXSLT_SETS_NAMESPACE, + exsltSetsDifferenceFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "intersection", + EXSLT_SETS_NAMESPACE, + exsltSetsIntersectionFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "distinct", + EXSLT_SETS_NAMESPACE, + exsltSetsDistinctFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "has-same-nodes", + EXSLT_SETS_NAMESPACE, + exsltSetsHasSameNodesFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "leading", + EXSLT_SETS_NAMESPACE, + exsltSetsLeadingFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "trailing", + EXSLT_SETS_NAMESPACE, + exsltSetsTrailingFunction); } diff --git a/libxslt/extensions.c b/libxslt/extensions.c index d5c56b13..39f70b3f 100644 --- a/libxslt/extensions.c +++ b/libxslt/extensions.c @@ -49,6 +49,8 @@ typedef xsltExtModule *xsltExtModulePtr; struct _xsltExtModule { xsltExtInitFunction initFunc; xsltExtShutdownFunction shutdownFunc; + xsltStyleExtInitFunction styleInitFunc; + xsltStyleExtShutdownFunction styleShutdownFunc; }; typedef struct _xsltExtData xsltExtData; @@ -58,7 +60,17 @@ struct _xsltExtData { void *extData; }; +typedef struct _xsltExtElement xsltExtElement; +typedef xsltExtElement *xsltExtElementPtr; +struct _xsltExtElement { + xsltPreComputeFunction precomp; + xsltTransformFunction transform; +}; + static xmlHashTablePtr xsltExtensionsHash = NULL; +static xmlHashTablePtr xsltFunctionsHash = NULL; +static xmlHashTablePtr xsltElementsHash = NULL; +static xmlHashTablePtr xsltTopLevelsHash = NULL; /************************************************************************ * * @@ -133,6 +145,8 @@ xsltFreeExtDefList(xsltExtDefPtr extensiond) { * xsltNewExtModule: * @initFunc: the module initialization function * @shutdownFunc: the module shutdown function + * @styleInitFunc: the stylesheet module data allocator function + * @styleShutdownFunc: the stylesheet module data free function * * Create a new XSLT extension module * @@ -140,7 +154,9 @@ xsltFreeExtDefList(xsltExtDefPtr extensiond) { */ static xsltExtModulePtr xsltNewExtModule(xsltExtInitFunction initFunc, - xsltExtShutdownFunction shutdownFunc) + xsltExtShutdownFunction shutdownFunc, + xsltStyleExtInitFunction styleInitFunc, + xsltStyleExtShutdownFunction styleShutdownFunc) { xsltExtModulePtr cur; @@ -153,6 +169,8 @@ xsltNewExtModule(xsltExtInitFunction initFunc, } cur->initFunc = initFunc; cur->shutdownFunc = shutdownFunc; + cur->styleInitFunc = styleInitFunc; + cur->styleShutdownFunc = styleShutdownFunc; return (cur); } @@ -210,6 +228,49 @@ xsltFreeExtData(xsltExtDataPtr ext) { xmlFree(ext); } +/** + * xsltNewExtElement: + * @precomp: the pre-computation function + * @transform: the transformation function + * + * Create a new XSLT extension element + * + * Returns the newly allocated xsltExtElementPtr or NULL in case of + * error + */ +static xsltExtElementPtr +xsltNewExtElement (xsltPreComputeFunction precomp, + xsltTransformFunction transform) { + xsltExtElementPtr cur; + + if (transform == NULL) + return(NULL); + + cur = (xsltExtElementPtr) xmlMalloc(sizeof(xsltExtElement)); + if (cur == NULL) { + xsltPrintErrorContext(NULL, NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "xsltNewExtElement : malloc failed\n"); + return (NULL); + } + cur->precomp = precomp; + cur->transform = transform; + return(cur); +} + +/** + * xsltFreeExtElement: + * @ext: an XSLT extension element + * + * Frees up the memory allocated by @ext + */ +static void +xsltFreeExtElement (xsltExtElementPtr ext) { + if (ext == NULL) + return; + xmlFree(ext); +} + /************************************************************************ * * @@ -290,6 +351,8 @@ xsltRegisterExtFunction(xsltTransformContextPtr ctxt, const xmlChar *name, } if (ctxt->extFunctions == NULL) ctxt->extFunctions = xmlHashCreate(10); + if (ctxt->extFunctions == NULL) + return(-1); return(xmlHashAddEntry2(ctxt->extFunctions, name, URI, (void *) function)); } @@ -312,6 +375,8 @@ xsltRegisterExtElement(xsltTransformContextPtr ctxt, const xmlChar *name, return(-1); if (ctxt->extElements == NULL) ctxt->extElements = xmlHashCreate(10); + if (ctxt->extElements == NULL) + return(-1); return(xmlHashAddEntry2(ctxt->extElements, name, URI, (void *) function)); } @@ -329,6 +394,71 @@ xsltFreeCtxtExts(xsltTransformContextPtr ctxt) { xmlHashFree(ctxt->extFunctions, NULL); } +/** + * xsltStyleGetExtData: + * @style: an XSLT stylesheet + * @URI: the URI associated to the exension module + * + * Retrieve the data associated to the extension module in this given + * stylesheet. + * + * Returns the pointer or NULL if not present + */ +void * +xsltStyleGetExtData(xsltStylesheetPtr style, const xmlChar * URI) { + xsltExtDataPtr data; + + if ((style == NULL) || (URI == NULL)) + return (NULL); + if (style->extInfos == NULL) { + style->extInfos = xmlHashCreate(10); + if (style->extInfos == NULL) + return(NULL); + data = NULL; + } else { + data = (xsltExtDataPtr) xmlHashLookup(style->extInfos, URI); + } + if (data == NULL) { + void *extData; + xsltExtModulePtr module; + + module = xmlHashLookup(xsltExtensionsHash, URI); + if (module == NULL) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Not registered extension module: %s\n", URI); +#endif + return(NULL); + } else { + if (module->styleInitFunc == NULL) + return(NULL); + +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Initializing module: %s\n", URI); +#endif + + extData = module->styleInitFunc(style, URI); + if (extData == NULL) + return(NULL); + + data = xsltNewExtData(module, extData); + if (data == NULL) + return (NULL); + if (xmlHashAddEntry(style->extInfos, URI, + (void *) data) < 0) { + xsltGenericError(xsltGenericErrorContext, + "Failed to register module data: %s\n", URI); + if (module->styleShutdownFunc) + module->styleShutdownFunc(style, URI, extData); + xsltFreeExtData(data); + return(NULL); + } + } + } + return (data->extData); +} + /** * xsltGetExtData: * @ctxt: an XSLT transformation context @@ -340,35 +470,149 @@ xsltFreeCtxtExts(xsltTransformContextPtr ctxt) { * Returns the pointer or NULL if not present */ void * -xsltGetExtData(xsltTransformContextPtr ctxt, const xmlChar * URI) -{ +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) + if ((ctxt == NULL) || (URI == NULL)) return (NULL); + if (ctxt->extInfos == NULL) { + ctxt->extInfos = xmlHashCreate(10); + if (ctxt->extInfos == NULL) + return(NULL); + data = NULL; + } else { + data = (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos, URI); + } + if (data == NULL) { + void *extData; + xsltExtModulePtr module; + + module = xmlHashLookup(xsltExtensionsHash, URI); + if (module == NULL) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Not registered extension module: %s\n", URI); +#endif + return(NULL); + } else { + if (module->initFunc == NULL) + return(NULL); + +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Initializing module: %s\n", URI); +#endif + + extData = module->initFunc(ctxt, URI); + if (extData == NULL) + return(NULL); + + data = xsltNewExtData(module, extData); + if (data == NULL) + return (NULL); + if (xmlHashAddEntry(ctxt->extInfos, URI, + (void *) data) < 0) { + xsltPrintErrorContext(ctxt, NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "Failed to register module data: %s\n", URI); + if (module->shutdownFunc) + module->shutdownFunc(ctxt, URI, extData); + xsltFreeExtData(data); + return(NULL); + } + } + } return (data->extData); } +typedef struct _xsltInitExtCtxt xsltInitExtCtxt; +struct _xsltInitExtCtxt { + xsltTransformContextPtr ctxt; + int ret; +}; + +/** + * xsltInitCtxtExt: + * @styleData: the registered stylesheet data for the module + * @ctxt: the XSLT transformation context + the return value + * @URI: the extension URI + * + * Initializes an extension module + */ +static void +xsltInitCtxtExt (xsltExtDataPtr styleData, xsltInitExtCtxt *ctxt, + const xmlChar *URI) { + xsltExtModulePtr module; + xsltExtDataPtr ctxtData; + void *extData; + + if ((styleData == NULL) || (ctxt == NULL) || (URI == NULL) || + (ctxt->ret == -1)) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "xsltInitCtxtExt: NULL param or error\n"); +#endif + return; + } + module = styleData->extModule; + if ((module == NULL) || (module->initFunc == NULL)) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "xsltInitCtxtExt: no module or no initFunc\n"); +#endif + return; + } + + extData = module->initFunc(ctxt->ctxt, URI); + if (extData == NULL) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "xsltInitCtxtExt: no extData\n"); +#endif + return; + } + ctxtData = xsltNewExtData(module, extData); + if (ctxtData == NULL) { + ctxt->ret = -1; + return; + } + + if (ctxt->ctxt->extInfos == NULL) + ctxt->ctxt->extInfos = xmlHashCreate(10); + if (ctxt->ctxt->extInfos == NULL) { + ctxt->ret = -1; + return; + } + + if (xmlHashAddEntry(ctxt->ctxt->extInfos, URI, ctxtData) < 0) { + xsltGenericError(xsltGenericErrorContext, + "Failed to register module data: %s\n", URI); + if (module->shutdownFunc) + module->shutdownFunc(ctxt->ctxt, URI, extData); + xsltFreeExtData(ctxtData); + ctxt->ret = -1; + return; + } +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, "Registered module %s\n", + URI); +#endif + ctxt->ret++; +} + /** * xsltInitCtxtExts: * @ctxt: an XSLT transformation context * - * Initialize the set of modules associated to the extension prefixes + * Initialize the set of modules with registered stylesheet data * * 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; + xsltInitExtCtxt ctx; if (ctxt == NULL) return (-1); @@ -376,71 +620,24 @@ xsltInitCtxtExts(xsltTransformContextPtr ctxt) 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) { - xsltPrintErrorContext(ctxt, NULL, NULL); - 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; - } + ctx.ctxt = ctxt; + ctx.ret = 0; + + while (style != NULL) { + if (style->extInfos != NULL) { + xmlHashScan(style->extInfos, + (xmlHashScanner) xsltInitCtxtExt, &ctx); + if (ctx.ret == -1) + return(-1); + } style = xsltNextImport(style); } #ifdef WITH_XSLT_DEBUG_EXTENSIONS - xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n", ret); + xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n", + ctx.ret); #endif - return (ret); + return (ctx.ret); } /** @@ -490,6 +687,53 @@ xsltShutdownCtxtExts(xsltTransformContextPtr ctxt) ctxt->extInfos = NULL; } +/** + * xsltShutdownExt: + * @data: the registered data for the module + * @ctxt: the XSLT stylesheet + * @URI: the extension URI + * + * Shutdown an extension module loaded + */ +static void +xsltShutdownExt(xsltExtDataPtr data, xsltStylesheetPtr style, + const xmlChar * URI) +{ + xsltExtModulePtr module; + + if ((data == NULL) || (style == NULL) || (URI == NULL)) + return; + module = data->extModule; + if ((module == NULL) || (module->styleShutdownFunc == NULL)) + return; + +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Shutting down module : %s\n", URI); +#endif + module->styleShutdownFunc(style, URI, data->extData); + xmlHashRemoveEntry(style->extInfos, URI, + (xmlHashDeallocator) xsltFreeExtData); +} + +/** + * xsltShutdownExts: + * @style: an XSLT stylesheet + * + * Shutdown the set of modules loaded + */ +void +xsltShutdownExts(xsltStylesheetPtr style) +{ + if (style == NULL) + return; + if (style->extInfos == NULL) + return; + xmlHashScan(style->extInfos, (xmlHashScanner) xsltShutdownExt, style); + xmlHashFree(style->extInfos, (xmlHashDeallocator) xsltFreeExtData); + style->extInfos = NULL; +} + /** * xsltCheckExtPrefix: * @style: the stylesheet @@ -516,19 +760,23 @@ xsltCheckExtPrefix(xsltStylesheetPtr style, const xmlChar *prefix) { } /** - * xsltRegisterExtModule: + * xsltRegisterExtModuleFull: * @URI: URI associated to this module * @initFunc: the module initialization function * @shutdownFunc: the module shutdown function + * @styleInitFunc: the module initialization function + * @styleShutdownFunc: 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) +xsltRegisterExtModuleFull(const xmlChar * URI, + xsltExtInitFunction initFunc, + xsltExtShutdownFunction shutdownFunc, + xsltStyleExtInitFunction styleInitFunc, + xsltStyleExtShutdownFunction styleShutdownFunc) { int ret; xsltExtModulePtr module; @@ -548,13 +796,32 @@ xsltRegisterExtModule(const xmlChar * URI, return (0); return (-1); } - module = xsltNewExtModule(initFunc, shutdownFunc); + module = xsltNewExtModule(initFunc, shutdownFunc, + styleInitFunc, styleShutdownFunc); if (module == NULL) return (-1); ret = xmlHashAddEntry(xsltExtensionsHash, URI, (void *) module); return (ret); } +/** + * 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) { + return xsltRegisterExtModuleFull(URI, initFunc, shutdownFunc, + NULL, NULL); +} + /** * xsltUnregisterExtModule: * @URI: URI associated to this module @@ -614,4 +881,552 @@ xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt) return(ctxt->context->extra); } +/** + * xsltRegisterExtModuleFunction: + * @name: the function name + * @URI: the function namespace URI + * @function: the function callback + * + * Registers an extension module function. + * + * Returns 0 if successful, -1 in case of error. + */ +int +xsltRegisterExtModuleFunction (const xmlChar *name, const xmlChar *URI, + xmlXPathFunction function) { + if ((name == NULL) || (URI == NULL) || (function == NULL)) + return(-1); + if (xsltFunctionsHash == NULL) + xsltFunctionsHash = xmlHashCreate(10); + if (xsltFunctionsHash == NULL) + return(-1); + + xmlHashUpdateEntry2(xsltFunctionsHash, name, URI, + (void *) function, NULL); + + return(0); +} + +/** + * xsltExtModuleFunctionLookup: + * @name: the function name + * @URI: the function namespace URI + * + * Looks up an extension module function + * + * Returns the function if found, NULL otherwise. + */ +xmlXPathFunction +xsltExtModuleFunctionLookup (const xmlChar *name, const xmlChar *URI) { + if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL)) + return(NULL); + + return (xmlXPathFunction) xmlHashLookup2(xsltFunctionsHash, name, URI); +} + +/** + * xsltUnregisterExtModuleFunction: + * @name: the function name + * @URI: the function namespace URI + * + * Unregisters an extension module function + * + * Returns 0 if successful, -1 in case of error. + */ +int +xsltUnregisterExtModuleFunction (const xmlChar *name, + const xmlChar *URI) { + if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL)) + return(-1); + + return xmlHashRemoveEntry2 (xsltFunctionsHash, name, URI, NULL); +} + +/** + * xsltRegisterExtModuleElement: + * @name: the element name + * @URI: the element namespace URI + * @precomp: the pre-computation callback + * @transform: the transformation callback + * + * Registers an extension module element. + * + * Returns 0 if successful, -1 in case of error. + */ +int +xsltRegisterExtModuleElement (const xmlChar *name, const xmlChar *URI, + xsltPreComputeFunction precomp, + xsltTransformFunction transform) { + xsltExtElementPtr ext; + + if ((name == NULL) || (URI == NULL) || (transform == NULL)) + return(-1); + + if (xsltElementsHash == NULL) + xsltElementsHash = xmlHashCreate(10); + if (xsltElementsHash == NULL) + return(-1); + + ext = xsltNewExtElement(precomp, transform); + if (ext == NULL) + return(-1); + + xmlHashUpdateEntry2(xsltElementsHash, name, URI, (void *) ext, + (xmlHashDeallocator) xsltFreeExtElement); + + return(0); +} + +/** + * xsltExtElementLookup: + * @ctxt: an XSLT process context + * @name: the element name + * @URI: the element namespace URI + * + * Looks up an extension element. @ctxt can be NULL to search only in + * module elements. + * + * Returns the element callback or NULL if not found + */ +xsltTransformFunction +xsltExtElementLookup (xsltTransformContextPtr ctxt, + const xmlChar *name, const xmlChar *URI) { + xsltTransformFunction ret; + + if ((name == NULL) || (URI == NULL)) + return(NULL); + + if ((ctxt != NULL) && (ctxt->extElements != NULL)) { + ret = (xsltTransformFunction) + xmlHashLookup2(ctxt->extElements, name, URI); + if (ret != NULL) + return(ret); + } + return xsltExtModuleElementLookup(name, URI); +} + +/** + * xsltExtModuleElementLookup: + * @name: the element name + * @URI: the element namespace URI + * + * Looks up an extension module element + * + * Returns the callback function if found, NULL otherwise. + */ +xsltTransformFunction +xsltExtModuleElementLookup (const xmlChar *name, const xmlChar *URI) { + xsltExtElementPtr ext; + + if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) + return(NULL); + + ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI); + + if (ext == NULL) + return(NULL); + return(ext->transform); +} + +/** + * xsltExtModuleElementPreComputeLookup: + * @name: the element name + * @URI: the element namespace URI + * + * Looks up an extension module element pre-computation function + * + * Returns the callback function if found, NULL otherwise. + */ +xsltPreComputeFunction +xsltExtModuleElementPreComputeLookup (const xmlChar *name, + const xmlChar *URI) { + xsltExtElementPtr ext; + + if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) + return(NULL); + + ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI); + + if (ext == NULL) + return(NULL); + return(ext->precomp); +} + +/** + * xsltUnregisterExtModuleElement: + * @name: the element name + * @URI: the element namespace URI + * + * Unregisters an extension module element + * + * Returns 0 if successful, -1 in case of error. + */ +int +xsltUnregisterExtModuleElement (const xmlChar *name, + const xmlChar *URI) { + if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) + return(-1); + + return xmlHashRemoveEntry2 (xsltElementsHash, name, URI, + (xmlHashDeallocator) xsltFreeExtElement); +} + +/** + * xsltRegisterExtModuleTopLevel: + * @name: the top-level element name + * @URI: the top-level element namespace URI + * @function: the top-level element callback + * + * Registers an extension module top-level element. + * + * Returns 0 if successful, -1 in case of error. + */ +int +xsltRegisterExtModuleTopLevel (const xmlChar *name, const xmlChar *URI, + xsltPreComputeFunction function) { + if ((name == NULL) || (URI == NULL) || (function == NULL)) + return(-1); + + if (xsltTopLevelsHash == NULL) + xsltTopLevelsHash = xmlHashCreate(10); + if (xsltTopLevelsHash == NULL) + return(-1); + + xmlHashUpdateEntry2(xsltTopLevelsHash, name, URI, + (void *) function, NULL); + + return(0); +} + +/** + * xsltExtModuleTopLevelLookup: + * @name: the top-level element name + * @URI: the top-level element namespace URI + * + * Looks up an extension module top-level element + * + * Returns the callback function if found, NULL otherwise. + */ +xsltPreComputeFunction +xsltExtModuleTopLevelLookup (const xmlChar *name, const xmlChar *URI) { + if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL)) + return(NULL); + + return xmlHashLookup2(xsltTopLevelsHash, name, URI); +} + +/** + * xsltUnregisterExtModuleTopLevel: + * @name: the top-level element name + * @URI: the top-level element namespace URI + * + * Unregisters an extension module top-level element + * + * Returns 0 if successful, -1 in case of error. + */ +int +xsltUnregisterExtModuleTopLevel (const xmlChar *name, + const xmlChar *URI) { + if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL)) + return(-1); + + return xmlHashRemoveEntry2 (xsltTopLevelsHash, name, URI, NULL); +} + + +/************************************************************************ + * * + * Test module http://xmlsoft.org/XSLT/ * + * * + ************************************************************************/ + +/************************************************************************ + * * + * Test of the extension module API * + * * + ************************************************************************/ + +static xmlChar *testData = NULL; +static xmlChar *testStyleData = 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; + + tctxt = xsltXPathGetTransformContext(ctxt); + + if (testData == NULL) { + xsltGenericDebug(xsltGenericDebugContext, + "xsltExtFunctionTest: not initialized," + " calling xsltGetExtData\n"); + data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL); + if (data == NULL) { + xsltPrintErrorContext(tctxt, NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "xsltExtElementTest: not initialized\n"); + return; + } + } + if (tctxt == NULL) { + xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "xsltExtFunctionTest: failed to get the transformation context\n"); + return; + } + if (data == NULL) + data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL); + if (data == NULL) { + xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "xsltExtFunctionTest: failed to get module data\n"); + return; + } + if (data != testData) { + xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); + 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 +} + +/** + * xsltExtElementPreCompTest: + * @style: the stylesheet + * @inst: the instruction in the stylesheet + * + * Process a libxslt:test node + */ +static void +xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst) { + if (style == NULL) { + xsltPrintErrorContext(NULL, NULL, inst); + xsltGenericError(xsltGenericErrorContext, + "xsltExtElementTest: no transformation context\n"); + return; + } + if (testStyleData == NULL) { + xsltGenericDebug(xsltGenericDebugContext, + "xsltExtElementPreCompTest: not initialized," + " calling xsltStyleGetExtData\n"); + xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL); + if (testStyleData == NULL) { + xsltPrintErrorContext(NULL, NULL, inst); + xsltGenericError(xsltGenericErrorContext, + "xsltExtElementPreCompTest: not initialized\n"); + style->errors++; + return; + } + } + if (inst == NULL) { + xsltPrintErrorContext(NULL, NULL, inst); + xsltGenericError(xsltGenericErrorContext, + "xsltExtElementPreCompTest: no instruction\n"); + style->errors++; + return; + } +} + +/** + * xsltExtElementTest: + * @ctxt: an XSLT processing context + * @node: The current node + * @inst: the instruction in the stylesheet + * @comp: precomputed informations + * + * Process a libxslt:test node + */ +static void +xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, + xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) +{ + xmlNodePtr comment; + + if (testData == NULL) { + xsltGenericDebug(xsltGenericDebugContext, + "xsltExtElementTest: not initialized," + " calling xsltGetExtData\n"); + xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL); + if (testData == NULL) { + xsltPrintErrorContext(ctxt, NULL, inst); + xsltGenericError(xsltGenericErrorContext, + "xsltExtElementTest: not initialized\n"); + return; + } + } + if (ctxt == NULL) { + xsltPrintErrorContext(ctxt, NULL, inst); + xsltGenericError(xsltGenericErrorContext, + "xsltExtElementTest: no transformation context\n"); + return; + } + if (node == NULL) { + xsltPrintErrorContext(ctxt, NULL, inst); + xsltGenericError(xsltGenericErrorContext, + "xsltExtElementTest: no current node\n"); + return; + } + if (inst == NULL) { + xsltPrintErrorContext(ctxt, NULL, inst); + xsltGenericError(xsltGenericErrorContext, + "xsltExtElementTest: no instruction\n"); + return; + } + if (ctxt->insert == NULL) { + xsltPrintErrorContext(ctxt, NULL, inst); + 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 (testStyleData == NULL) { + xsltGenericDebug(xsltGenericErrorContext, + "xsltExtInitTest: not initialized," + " calling xsltStyleGetExtData\n"); + xsltStyleGetExtData(ctxt->style, URI); + if (testStyleData == NULL) { + xsltPrintErrorContext(ctxt, NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "xsltExtInitTest: not initialized\n"); + return (NULL); + } + } + if (testData != NULL) { + xsltPrintErrorContext(ctxt, NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "xsltExtInitTest: already initialized\n"); + return (NULL); + } + testData = (void *) "test data"; + 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, + const xmlChar * URI, void *data) { + if (testData == NULL) { + xsltPrintErrorContext(ctxt, NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "xsltExtShutdownTest: not initialized\n"); + return; + } + if (data != testData) { + xsltPrintErrorContext(ctxt, NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "xsltExtShutdownTest: wrong data\n"); + } + testData = NULL; + xsltGenericDebug(xsltGenericDebugContext, + "Unregistered test module : %s\n", URI); +} +/** + * xsltExtStyleInitTest: + * @style: an XSLT stylesheet + * @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 * +xsltExtStyleInitTest(xsltStylesheetPtr style, const xmlChar * URI) +{ + if (testStyleData != NULL) { + xsltPrintErrorContext(NULL, NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "xsltExtInitTest: already initialized\n"); + return (NULL); + } + testStyleData = (void *) "test data"; + xsltGenericDebug(xsltGenericDebugContext, + "Registered test module : %s\n", URI); + return (testStyleData); +} + + +/** + * xsltExtStyleShutdownTest: + * @style: an XSLT stylesheet + * @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 +xsltExtStyleShutdownTest(xsltStylesheetPtr style, + const xmlChar * URI, void *data) { + if (testStyleData == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltExtShutdownTest: not initialized\n"); + return; + } + if (data != testStyleData) { + xsltPrintErrorContext(NULL, NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "xsltExtShutdownTest: wrong data\n"); + } + testStyleData = NULL; + xsltGenericDebug(xsltGenericDebugContext, + "Unregistered test module : %s\n", URI); +} + +/** + * xsltRegisterTestModule: + * + * Registers the test module + */ +void +xsltRegisterTestModule (void) { + xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL, + xsltExtInitTest, xsltExtShutdownTest, + xsltExtStyleInitTest, + xsltExtStyleShutdownTest); + xsltRegisterExtModuleFunction((const xmlChar *) "test", + (const xmlChar *) XSLT_DEFAULT_URL, + xsltExtFunctionTest); + xsltRegisterExtModuleElement((const xmlChar *) "test", + (const xmlChar *) XSLT_DEFAULT_URL, + xsltExtElementPreCompTest , + xsltExtElementTest); +} diff --git a/libxslt/extensions.h b/libxslt/extensions.h index c3241ca9..7af52353 100644 --- a/libxslt/extensions.h +++ b/libxslt/extensions.h @@ -20,6 +20,30 @@ extern "C" { * Extension Modules API */ +/** + * xsltStyleExtInitFunction: + * @ctxt: an XSLT stylesheet + * @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 * (*xsltStyleExtInitFunction) (xsltStylesheetPtr style, + const xmlChar *URI); + +/** + * xsltStyleExtShutdownFunction: + * @ctxt: an XSLT stylesheet + * @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 (*xsltStyleExtShutdownFunction) (xsltStylesheetPtr style, + const xmlChar *URI, + void *data); + /** * xsltExtInitFunction: * @ctxt: an XSLT transformation context @@ -47,6 +71,12 @@ typedef void (*xsltExtShutdownFunction) (xsltTransformContextPtr ctxt, int xsltRegisterExtModule (const xmlChar *URI, xsltExtInitFunction initFunc, xsltExtShutdownFunction shutdownFunc); +int xsltRegisterExtModuleFull + (const xmlChar * URI, + xsltExtInitFunction initFunc, + xsltExtShutdownFunction shutdownFunc, + xsltStyleExtInitFunction styleInitFunc, + xsltStyleExtShutdownFunction styleShutdownFunc); int xsltUnregisterExtModule (const xmlChar * URI); @@ -55,16 +85,76 @@ void xsltUnregisterAllExtModules(void); void * xsltGetExtData (xsltTransformContextPtr ctxt, const xmlChar *URI); +void * xsltStyleGetExtData (xsltStylesheetPtr style, + const xmlChar *URI); + void xsltShutdownCtxtExts (xsltTransformContextPtr ctxt); +void xsltShutdownExts (xsltStylesheetPtr style); + xsltTransformContextPtr xsltXPathGetTransformContext (xmlXPathParserContextPtr ctxt); +/* + * extension functions +*/ +int xsltRegisterExtModuleFunction (const xmlChar *name, + const xmlChar *URI, + xmlXPathFunction function); +xmlXPathFunction + xsltExtFunctionLookup (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *URI); +xmlXPathFunction + xsltExtModuleFunctionLookup (const xmlChar *name, + const xmlChar *URI); +int xsltUnregisterExtModuleFunction (const xmlChar *name, + const xmlChar *URI); + +/* + * extension elements + */ +typedef void + (*xsltPreComputeFunction) (xsltStylesheetPtr ctxt, + xmlNodePtr inst); + +int xsltRegisterExtModuleElement (const xmlChar *name, + const xmlChar *URI, + xsltPreComputeFunction precomp, + xsltTransformFunction transform); +xsltTransformFunction + xsltExtElementLookup (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *URI); +xsltTransformFunction + xsltExtModuleElementLookup (const xmlChar *name, + const xmlChar *URI); +xsltPreComputeFunction + xsltExtModuleElementPreComputeLookup + (const xmlChar *name, + const xmlChar *URI); +int xsltUnregisterExtModuleElement (const xmlChar *name, + const xmlChar *URI); + +/* + * top-level elements + */ +int xsltRegisterExtModuleTopLevel (const xmlChar *name, + const xmlChar *URI, + xsltPreComputeFunction function); +xsltPreComputeFunction + xsltExtModuleTopLevelLookup (const xmlChar *name, + const xmlChar *URI); +int xsltUnregisterExtModuleTopLevel (const xmlChar *name, + const xmlChar *URI); + + +/* These 2 functions are deprecated for use within modules */ int xsltRegisterExtFunction (xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *URI, - xmlXPathEvalFunc function); + xmlXPathFunction function); int xsltRegisterExtElement (xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *URI, @@ -85,6 +175,11 @@ void xsltFreeCtxtExts (xsltTransformContextPtr ctxt); void xsltFreeExts (xsltStylesheetPtr style); +/** + * Test module http://xmlsoft.org/XSLT/ + */ +void xsltRegisterTestModule (void); + #ifdef __cplusplus } #endif diff --git a/libxslt/functions.c b/libxslt/functions.c index d3f01f4a..4e9a6f9c 100644 --- a/libxslt/functions.c +++ b/libxslt/functions.c @@ -51,6 +51,41 @@ */ #define DOCBOOK_XSL_HACK +/** + * xsltXPathFunctionLookup: + * @ctxt: a void * but the XSLT transformation context actually + * @name: the function name + * @ns_uri: the function namespace URI + * + * This is the entry point when a function is needed by the XPath + * interpretor. + * + * Returns the callback function or NULL if not found + */ +xmlXPathFunction +xsltXPathFunctionLookup (void *ctxt ATTRIBUTE_UNUSED, + const xmlChar *name, const xmlChar *ns_uri) { + xmlXPathFunction ret; + + if ((name == NULL) || (ns_uri == NULL)) + return (NULL); + +#ifdef WITH_XSLT_DEBUG_FUNCTION + xsltGenericDebug(xsltGenericDebugContext, + "Lookup function {%s}%s\n", ns_uri, name); +#endif + + ret = xsltExtModuleFunctionLookup(name, ns_uri); + +#ifdef WITH_XSLT_DEBUG_FUNCTION + if (ret != NULL) + xsltGenericDebug(xsltGenericDebugContext, + "found function %s\n", name); +#endif + return(ret); +} + + /************************************************************************ * * * Module interfaces * @@ -625,7 +660,11 @@ xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){ name = xmlSplitQName2(obj->stringval, &prefix); if (name == NULL) { + xmlNsPtr ns; + name = xmlStrdup(obj->stringval); + ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL); + nsURI = xmlStrdup(ns->href); } else { nsURI = xmlXPathNsLookup(ctxt->context, prefix); if (nsURI == NULL) { @@ -636,7 +675,7 @@ xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){ } } - if (xmlHashLookup2(tctxt->extElements, name, nsURI) != NULL) { + if (xsltExtElementLookup(tctxt, name, nsURI) != NULL) { valuePush(ctxt, xmlXPathNewBoolean(1)); } else { valuePush(ctxt, xmlXPathNewBoolean(0)); @@ -735,171 +774,6 @@ 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) { - xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); - xsltGenericError(xsltGenericErrorContext, - "xsltExtFunctionTest: not initialized\n"); - return; - } - tctxt = xsltXPathGetTransformContext(ctxt); - if (tctxt == NULL) { - xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); - xsltGenericError(xsltGenericErrorContext, - "xsltExtFunctionTest: failed to get the transformation context\n"); - return; - } - data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL); - if (data == NULL) { - xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); - xsltGenericError(xsltGenericErrorContext, - "xsltExtFunctionTest: failed to get module data\n"); - return; - } - if (data != testData) { - xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); - 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 a libxslt:test node - */ -static void -xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node, - xmlNodePtr inst, - xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) -{ - xmlNodePtr comment; - - if (testData == NULL) { - xsltPrintErrorContext(ctxt, NULL, inst); - xsltGenericError(xsltGenericErrorContext, - "xsltExtElementTest: not initialized\n"); - return; - } - if (ctxt == NULL) { - xsltPrintErrorContext(ctxt, NULL, inst); - xsltGenericError(xsltGenericErrorContext, - "xsltExtElementTest: no transformation context\n"); - return; - } - if (node == NULL) { - xsltPrintErrorContext(ctxt, NULL, inst); - xsltGenericError(xsltGenericErrorContext, - "xsltExtElementTest: no current node\n"); - return; - } - if (inst == NULL) { - xsltPrintErrorContext(ctxt, NULL, inst); - xsltGenericError(xsltGenericErrorContext, - "xsltExtElementTest: no instruction\n"); - return; - } - if (ctxt->insert == NULL) { - xsltPrintErrorContext(ctxt, NULL, inst); - 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) { - xsltPrintErrorContext(ctxt, NULL, 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) { - xsltPrintErrorContext(ctxt, NULL, NULL); - xsltGenericError(xsltGenericErrorContext, - "xsltExtShutdownTest: not initialized\n"); - return; - } - if (data != testData) { - xsltPrintErrorContext(ctxt, NULL, NULL); - xsltGenericError(xsltGenericErrorContext, - "xsltExtShutdownTest: wrong data\n"); - } - testData = NULL; - xsltGenericDebug(xsltGenericDebugContext, - "Unregistered test module : %s\n", URI); -} - /************************************************************************ * * * Registration of XSLT and libxslt functions * @@ -932,8 +806,4 @@ xsltRegisterAllFunctions(xmlXPathContextPtr ctxt) xsltElementAvailableFunction); xmlXPathRegisterFunc(ctxt, (const xmlChar *) "function-available", xsltFunctionAvailableFunction); - - xsltRegisterExtModule((const xmlChar *) XSLT_DEFAULT_URL, - xsltExtInitTest, - xsltExtShutdownTest); } diff --git a/libxslt/functions.h b/libxslt/functions.h index db2d24ba..a52470eb 100644 --- a/libxslt/functions.h +++ b/libxslt/functions.h @@ -18,6 +18,19 @@ extern "C" { #endif +/** + * XSLT_REGISTER_FUNCTION_LOOKUP: + * + * registering macro, not general purpose at all but used in different modules + */ +#define XSLT_REGISTER_FUNCTION_LOOKUP(ctxt) \ + xmlXPathRegisterFuncLookup((ctxt)->xpathCtxt, \ + xsltXPathFunctionLookup, (void *)(ctxt)); + +xmlXPathFunction + xsltXPathFunctionLookup (void *ctxt, const xmlChar *name, + const xmlChar *ns_uri); + /* * Interfaces for the functions implementations */ diff --git a/libxslt/preproc.c b/libxslt/preproc.c index 7170cc6c..f75822be 100644 --- a/libxslt/preproc.c +++ b/libxslt/preproc.c @@ -36,6 +36,7 @@ #include "preproc.h" #include "extra.h" #include "imports.h" +#include "extensions.h" #ifdef WITH_XSLT_DEBUG #define WITH_XSLT_DEBUG_PREPROC @@ -1343,6 +1344,15 @@ xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) { if (IS_XSLT_NAME(inst, "document")) { xsltDocumentComp(style, inst); } else { + xsltPreComputeFunction function; + /* + * Precompute the element + */ + function = + xsltExtModuleElementPreComputeLookup(inst->name, + inst->ns->href); + if (function != NULL) + function(style, inst); /* * Mark the element for later recognition. */ diff --git a/libxslt/transform.c b/libxslt/transform.c index 7992b9f8..1498d6ae 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -233,6 +233,7 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) { cur->xpathCtxt->proximityPosition = 0; cur->xpathCtxt->contextSize = 0; XSLT_REGISTER_VARIABLE_LOOKUP(cur); + XSLT_REGISTER_FUNCTION_LOOKUP(cur); cur->xpathCtxt->nsHash = style->nsHash; docu = xsltNewDocument(cur, doc); if (docu == NULL) { @@ -632,7 +633,7 @@ xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node, ************************************************************************/ void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node, - xsltStackElemPtr params); + xsltStackElemPtr params); /** * xsltDefaultProcessOneNode: * @ctxt: a XSLT process context @@ -1129,8 +1130,7 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, * Flagged as an extension element */ function = (xsltTransformFunction) - xmlHashLookup2(ctxt->extElements, cur->name, - cur->ns->href); + xsltExtElementLookup(ctxt, cur->name, cur->ns->href); if (function == NULL) { xmlNodePtr child; int found = 0; diff --git a/libxslt/transform.h b/libxslt/transform.h index dd4b3e96..a6765451 100644 --- a/libxslt/transform.h +++ b/libxslt/transform.h @@ -26,6 +26,11 @@ int xsltGetXIncludeDefault (void); /** * Private Interfaces */ +xsltTransformFunction + xsltExtElementLookup (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *URI); + xmlDocPtr xsltApplyStylesheet (xsltStylesheetPtr style, xmlDocPtr doc, const char **params); diff --git a/libxslt/variables.c b/libxslt/variables.c index 6626fe4b..4d4a9290 100644 --- a/libxslt/variables.c +++ b/libxslt/variables.c @@ -358,7 +358,7 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem, xmlNodePtr oldInsert; container = xmlNewDocNode(ctxt->output, NULL, - (const xmlChar *) "fake", NULL); + (const xmlChar *) "fake", NULL); if (container == NULL) return(NULL); @@ -472,7 +472,7 @@ xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) { xmlNodePtr oldInsert; container = xmlNewDocNode(ctxt->output, NULL, - (const xmlChar *) "fake", NULL); + (const xmlChar *) "fake", NULL); if (container == NULL) return(NULL); diff --git a/libxslt/xslt.c b/libxslt/xslt.c index 55629d09..1a3f6c67 100644 --- a/libxslt/xslt.c +++ b/libxslt/xslt.c @@ -328,6 +328,7 @@ xsltNewStylesheet(void) { cur->exclPrefixNr = 0; cur->exclPrefixMax = 0; cur->exclPrefixTab = NULL; + cur->extInfos = NULL; return(cur); } @@ -369,6 +370,7 @@ xsltFreeStylesheet(xsltStylesheetPtr sheet) xsltFreeNamespaceAliasHashes(sheet); xsltFreeStyleDocuments(sheet); xsltFreeStylePreComps(sheet); + xsltShutdownExts(sheet); if (sheet->doc != NULL) xmlFreeDoc(sheet->doc); if (sheet->variables != NULL) @@ -1247,24 +1249,21 @@ xsltGatherNamespaces(xsltStylesheetPtr style) { /** * xsltParseTemplateContent: * @style: the XSLT stylesheet - * @ret: the "template" structure * @template: the container node (can be a document for literal results) * - * parse an XSLT template element content + * parse a template content-model * Clean-up the template content from unwanted ignorable blank nodes * and process xslt:text */ -static void -xsltParseTemplateContent(xsltStylesheetPtr style, xsltTemplatePtr ret, - xmlNodePtr template) { +void +xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr template) { xmlNodePtr cur, delete; /* * This content comes from the stylesheet * For stylesheets, the set of whitespace-preserving * element names consists of just xsl:text. */ - ret->elem = template; cur = template->children; delete = NULL; while (cur != NULL) { @@ -1412,8 +1411,6 @@ skip_children: break; cur = cur->next; } - - ret->content = template->children; } /** @@ -1599,7 +1596,9 @@ xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { /* * parse the content and register the pattern */ - xsltParseTemplateContent(style, ret, template); + xsltParseTemplateContent(style, template); + ret->elem = template; + ret->content = template->children; xsltAddTemplate(style, ret, mode, modeURI); error: @@ -1652,28 +1651,44 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { cur = top->children; + /* + * process xsl:import elements + */ while (cur != NULL) { if (IS_BLANK_NODE(cur)) { cur = cur->next; continue; } - if (!(IS_XSLT_ELEM(cur))) { -#ifdef WITH_XSLT_DEBUG_PARSING - xsltGenericDebug(xsltGenericDebugContext, - "xsltParseStylesheetTop : found foreign element %s\n", - cur->name); -#endif - cur = cur->next; - continue; - } - if (IS_XSLT_NAME(cur, "import")) { + if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) { xsltParseStylesheetImport(style, cur); } else break; cur = cur->next; } + /* + * process other top-level elements + */ while (cur != NULL) { + if (IS_BLANK_NODE(cur)) { + cur = cur->next; + continue; + } + if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) { + xsltGenericError(xsltGenericErrorContext, + "Found a top-level element %s with null namespace URI\n", + cur->name); + style->errors++; + cur = cur->next; + continue; + } if (!(IS_XSLT_ELEM(cur))) { + xsltPreComputeFunction function; + + function = xsltExtModuleTopLevelLookup(cur->name, + cur->ns->href); + if (function != NULL) + function(style, cur); + #ifdef WITH_XSLT_DEBUG_PARSING xsltGenericDebug(xsltGenericDebugContext, "xsltParseStylesheetTop : found foreign element %s\n", @@ -1819,7 +1834,9 @@ xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) { /* * parse the content and register the pattern */ - xsltParseTemplateContent(ret, template, (xmlNodePtr) doc); + xsltParseTemplateContent(ret, (xmlNodePtr) doc); + template->elem = (xmlNodePtr) doc; + template->content = doc->children; xsltAddTemplate(ret, template, NULL, NULL); } diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index dc3a80e2..56be65bc 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -323,6 +323,11 @@ struct _xsltStylesheet { int exclPrefixMax; /* size of the array */ void *_private; /* user defined data */ + + /* + * Extensions + */ + xmlHashTablePtr extInfos; /* the extension data */ }; /* @@ -449,6 +454,9 @@ xmlXPathError xsltFormatNumberConversion(xsltDecimalFormatPtr self, double number, xmlChar **result); +void xsltParseTemplateContent(xsltStylesheetPtr style, + xmlNodePtr template); + #ifdef __cplusplus } #endif diff --git a/libxslt/xsltutils.c b/libxslt/xsltutils.c index e303cf3f..d4e584df 100644 --- a/libxslt/xsltutils.c +++ b/libxslt/xsltutils.c @@ -288,7 +288,7 @@ xsltPrintErrorContext(xsltTransformContextPtr ctxt, const xmlChar *name = NULL; const char *type = "error"; - if ((node != NULL) && (ctxt != NULL)) + if ((node == NULL) && (ctxt != NULL)) node = ctxt->inst; if (node != NULL) { diff --git a/xsltproc/xsltproc.c b/xsltproc/xsltproc.c index f939906a..0ebfac84 100644 --- a/xsltproc/xsltproc.c +++ b/xsltproc/xsltproc.c @@ -406,9 +406,10 @@ main(int argc, char **argv) xmlSubstituteEntitiesDefault(1); /* - * Register the EXSLT extensions + * Register the EXSLT extensions and the test module */ exsltRegisterAll(); + xsltRegisterTestModule(); for (i = 1; i < argc; i++) { if ((!strcmp(argv[i], "-maxdepth")) ||