diff --git a/ChangeLog b/ChangeLog index b1bc6f57..32178166 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Sun Aug 5 09:37:14 CEST 2001 Thomas Broyer + + * libxslt/extensions.[ch] libxslt/preproc.[ch] libxslt/transform.c + libxslt/xslt.c libxslt/xsltInternals.h: modified extension framework + to easify extension element precomputation. + * libexslt/functions.c: uses the new framework and precomputes + func:result elements. + Sat Aug 4 20:42:32 CEST 2001 Daniel Veillard * libxslt/transform.c: bug fix on output="text" from Nicolas Marsgui diff --git a/libexslt/functions.c b/libexslt/functions.c index 2f813fb0..8d93f30d 100644 --- a/libexslt/functions.c +++ b/libexslt/functions.c @@ -29,6 +29,11 @@ struct _exsltFuncData { int error; /* did an error occur? */ }; +typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp; +struct _exsltFuncResultPreComp { + xsltElemPreComp comp; + xmlXPathCompExprPtr select; +}; static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs); @@ -161,6 +166,22 @@ exsltFuncNewFunctionData (void) { return(ret); } +/** + * exsltFreeFuncResultPreComp: + * @comp: the #exsltFuncResultPreComp to free up + * + * Deallocates an #exsltFuncResultPreComp + */ +static void +exsltFreeFuncResultPreComp (exsltFuncResultPreComp *comp) { + if (comp == NULL) + return; + + if (comp->select != NULL) + xmlXPathFreeCompExpr (comp->select); + xmlFree(comp); +} + /** * exsltFuncFunctionFunction: * @ctxt: an XPath parser context @@ -348,14 +369,12 @@ exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) { xmlFree(name); } -static void -exsltFuncResultElem (xsltTransformContextPtr ctxt, - xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst, - xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) { +static xsltElemPreCompPtr +exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst, + xsltTransformFunction function) { xmlNodePtr test; xmlChar *select; - exsltFuncData *data; - xmlXPathObjectPtr ret; + exsltFuncResultPreComp *ret; /* * "Validity" checking @@ -371,7 +390,7 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt, xsltGenericError(xsltGenericErrorContext, "exsltFuncResultElem: only xsl:fallback is " "allowed to follow func:result\n"); - return; + return (NULL); } /* it is an error for a func:result element to not be a descendant * of func:function. @@ -391,7 +410,7 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt, xsltGenericError(xsltGenericErrorContext, "func:result element not allowed within" " another func:result element\n"); - return; + return (NULL); } } if (IS_XSLT_ELEM(test) && @@ -400,9 +419,46 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt, xsltGenericError(xsltGenericErrorContext, "func:result element not allowed within" " a variable binding element\n"); - return; + return (NULL); } } + + /* + * Precomputation + */ + ret = (exsltFuncResultPreComp *) + xmlMalloc (sizeof(exsltFuncResultPreComp)); + if (ret == NULL) { + xsltPrintErrorContext(NULL, NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "exsltFuncResultComp : malloc failed\n"); + return (NULL); + } + memset(ret, 0, sizeof(exsltFuncResultPreComp)); + + xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function, + (xsltElemPreCompDeallocator) exsltFreeFuncResultPreComp); + ret->select = NULL; + + /* + * Precompute the select attribute + */ + select = xmlGetNsProp(inst, (const xmlChar *) "select", NULL); + if (select != NULL) { + ret->select = xmlXPathCompile (select); + xmlFree(select); + } + + return ((xsltElemPreCompPtr) ret); +} + +static void +exsltFuncResultElem (xsltTransformContextPtr ctxt, + xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst, + exsltFuncResultPreComp *comp) { + exsltFuncData *data; + xmlXPathObjectPtr ret; + /* It is an error if instantiating the content of the * func:function element results in the instantiation of more than * one func:result elements. @@ -419,12 +475,10 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt, data->error = 1; return; } - /* * Processing */ - select = xmlGetProp(inst, (const xmlChar *) "select"); - if (select != NULL) { + if (comp->select != NULL) { /* If the func:result element has a select attribute, then the * value of the attribute must be an expression and the * returned value is the object that results from evaluating @@ -435,17 +489,15 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt, "func:result content must be empty if it" " has a select attribute\n"); data->error = 1; - xmlFree(select); return; } - ret = xmlXPathEvalExpression(select, ctxt->xpathCtxt); - xmlFree(select); + ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt); if (ret == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltFuncResultElem: ret == NULL\n"); return; } - } else if (test->children != NULL) { + } else if (inst->children != NULL) { /* If the func:result element does not have a select attribute * and has non-empty content (i.e. the func:result element has * one or more child nodes), then the content of the @@ -494,7 +546,7 @@ exsltFuncRegister (void) { EXSLT_FUNCTIONS_NAMESPACE, exsltFuncFunctionComp); xsltRegisterExtModuleElement ((const xmlChar *) "result", - EXSLT_FUNCTIONS_NAMESPACE, - NULL, - exsltFuncResultElem); + EXSLT_FUNCTIONS_NAMESPACE, + (xsltPreComputeFunction)exsltFuncResultComp, + (xsltTransformFunction) exsltFuncResultElem); } diff --git a/libxslt/extensions.c b/libxslt/extensions.c index 0adbc592..c621ae56 100644 --- a/libxslt/extensions.c +++ b/libxslt/extensions.c @@ -342,7 +342,7 @@ xsltRegisterExtPrefix(xsltStylesheetPtr style, */ int xsltRegisterExtFunction(xsltTransformContextPtr ctxt, const xmlChar *name, - const xmlChar *URI, xmlXPathEvalFunc function) { + const xmlChar *URI, xmlXPathFunction function) { if ((ctxt == NULL) || (name == NULL) || (URI == NULL) || (function == NULL)) return(-1); @@ -954,6 +954,96 @@ xsltUnregisterAllExtModuleFunction (void) { xsltFunctionsHash = NULL; } + +/** + * xsltNewElemPreComp: + * @style: the XSLT stylesheet + * @inst: the element node + * @function: the transform function + * + * Creates and initializes an #xsltElemPreComp + * + * Returns the new and initialized #xsltElemPreComp + */ +xsltElemPreCompPtr +xsltNewElemPreComp (xsltStylesheetPtr style, xmlNodePtr inst, + xsltTransformFunction function) { + xsltElemPreCompPtr cur; + + cur = (xsltElemPreCompPtr) xmlMalloc (sizeof(xsltElemPreComp)); + if (cur == NULL) { + xsltPrintErrorContext(style, NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "xsltNewExtElement : malloc failed\n"); + return (NULL); + } + memset(cur, 0, sizeof(xsltElemPreComp)); + + xsltInitElemPreComp (cur, style, inst, function, + (xsltElemPreCompDeallocator) xmlFree); + + return (cur); +} + +/** + * xsltInitElemPreComp: + * @comp: an #xsltElemPreComp (or generally a derived structure) + * @style: the XSLT stylesheet + * @inst: the element node + * @function: the transform function + * @freeFunc: the @comp deallocator + * + * Initializes an existing #xsltElemPreComp structure. This is usefull + * when extending an #xsltElemPreComp to store precomputed data. + * This function MUST be called on any extension element precomputed + * data struct. + */ +void +xsltInitElemPreComp (xsltElemPreCompPtr comp, xsltStylesheetPtr style, + xmlNodePtr inst, xsltTransformFunction function, + xsltElemPreCompDeallocator freeFunc) { + comp->type = XSLT_FUNC_EXTENSION; + comp->func = function; + comp->inst = inst; + comp->free = freeFunc; + + comp->next = style->preComps; + style->preComps = comp; +} + +/** + * xsltPreComputeExtModuleElement: + * @style: the stylesheet + * @inst: the element node + * + * Precomputes an extension module element + * + * Returns the precomputed data + */ +xsltElemPreCompPtr +xsltPreComputeExtModuleElement (xsltStylesheetPtr style, + xmlNodePtr inst) { + xsltExtElementPtr ext; + xsltElemPreCompPtr comp = NULL; + + if ((style == NULL) || (inst == NULL) || + (inst->type != XML_ELEMENT_NODE) || (inst->ns == NULL)) + return (NULL); + + ext = (xsltExtElementPtr) + xmlHashLookup2 (xsltElementsHash, inst->name, + inst->ns->href); + if (ext == NULL) + return (NULL); + + if (ext->precomp != NULL) + comp = ext->precomp(style, inst, ext->transform); + if (comp == NULL) + comp = xsltNewElemPreComp (style, inst, ext->transform); + + return (comp); +} + /** * xsltRegisterExtModuleElement: * @name: the element name @@ -1106,7 +1196,7 @@ xsltUnregisterAllExtModuleElement (void) { */ int xsltRegisterExtModuleTopLevel (const xmlChar *name, const xmlChar *URI, - xsltPreComputeFunction function) { + xsltTopLevelFunction function) { if ((name == NULL) || (URI == NULL) || (function == NULL)) return(-1); @@ -1130,12 +1220,12 @@ xsltRegisterExtModuleTopLevel (const xmlChar *name, const xmlChar *URI, * * Returns the callback function if found, NULL otherwise. */ -xsltPreComputeFunction +xsltTopLevelFunction xsltExtModuleTopLevelLookup (const xmlChar *name, const xmlChar *URI) { if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL)) return(NULL); - return((xsltPreComputeFunction) + return((xsltTopLevelFunction) xmlHashLookup2(xsltTopLevelsHash, name, URI)); } @@ -1244,8 +1334,11 @@ xsltExtFunctionTest(xmlXPathParserContextPtr ctxt, int nargs ATTRIBUTE_UNUSED) * * Process a libxslt:test node */ -static void -xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst) { +static xsltElemPreCompPtr +xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst, + xsltTransformFunction function) { + xsltElemPreCompPtr ret; + if (style == NULL) { xsltPrintErrorContext(NULL, NULL, inst); xsltGenericError(xsltGenericErrorContext, @@ -1272,6 +1365,8 @@ xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst) { style->errors++; return; } + ret = xsltNewElemPreComp (style, inst, function); + return (ret); } /** @@ -1286,7 +1381,7 @@ xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst) { static void xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, - xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) + xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) { xmlNodePtr comment; diff --git a/libxslt/extensions.h b/libxslt/extensions.h index 4f64e24c..537994a7 100644 --- a/libxslt/extensions.h +++ b/libxslt/extensions.h @@ -113,9 +113,20 @@ int xsltUnregisterExtModuleFunction (const xmlChar *name, /* * extension elements */ -typedef void - (*xsltPreComputeFunction) (xsltStylesheetPtr ctxt, - xmlNodePtr inst); +typedef xsltElemPreCompPtr + (*xsltPreComputeFunction) (xsltStylesheetPtr style, + xmlNodePtr inst, + xsltTransformFunction function); + +xsltElemPreCompPtr + xsltNewElemPreComp (xsltStylesheetPtr style, + xmlNodePtr inst, + xsltTransformFunction function); +void xsltInitElemPreComp (xsltElemPreCompPtr comp, + xsltStylesheetPtr style, + xmlNodePtr inst, + xsltTransformFunction function, + xsltElemPreCompDeallocator freeFunc); int xsltRegisterExtModuleElement (const xmlChar *name, const xmlChar *URI, @@ -138,10 +149,14 @@ int xsltUnregisterExtModuleElement (const xmlChar *name, /* * top-level elements */ +typedef void + (*xsltTopLevelFunction) (xsltStylesheetPtr style, + xmlNodePtr inst); + int xsltRegisterExtModuleTopLevel (const xmlChar *name, const xmlChar *URI, - xsltPreComputeFunction function); -xsltPreComputeFunction + xsltTopLevelFunction function); +xsltTopLevelFunction xsltExtModuleTopLevelLookup (const xmlChar *name, const xmlChar *URI); int xsltUnregisterExtModuleTopLevel (const xmlChar *name, @@ -172,6 +187,9 @@ int xsltInitCtxtExts (xsltTransformContextPtr ctxt); void xsltFreeCtxtExts (xsltTransformContextPtr ctxt); void xsltFreeExts (xsltStylesheetPtr style); +xsltElemPreCompPtr + xsltPreComputeExtModuleElement (xsltStylesheetPtr style, + xmlNodePtr inst); /** * Test module http://xmlsoft.org/XSLT/ diff --git a/libxslt/preproc.c b/libxslt/preproc.c index f75822be..dd978476 100644 --- a/libxslt/preproc.c +++ b/libxslt/preproc.c @@ -1213,7 +1213,10 @@ xsltFreeStylePreComps(xsltStylesheetPtr style) { cur = style->preComps; while (cur != NULL) { next = cur->next; - xsltFreeStylePreComp(cur); + if (cur->type == XSLT_FUNC_EXTENSION) + ((xsltElemPreCompPtr)cur)->free(cur); + else + xsltFreeStylePreComp(cur); cur = next; } } @@ -1341,20 +1344,16 @@ xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) { cur->nsNr = i; } } else { + /* FIXME */ if (IS_XSLT_NAME(inst, "document")) { xsltDocumentComp(style, inst); } else { - xsltPreComputeFunction function; + inst->_private = + (void *) xsltPreComputeExtModuleElement(style, inst); + /* - * Precompute the element - */ - function = - xsltExtModuleElementPreComputeLookup(inst->name, - inst->ns->href); - if (function != NULL) - function(style, inst); - /* - * Mark the element for later recognition. + * Unknown element, maybe registered at the context + * level. Mark it for later recognition. */ if (inst->_private == NULL) inst->_private = (void *) xsltExtMarker; diff --git a/libxslt/preproc.h b/libxslt/preproc.h index e3857463..cd7f2031 100644 --- a/libxslt/preproc.h +++ b/libxslt/preproc.h @@ -19,6 +19,8 @@ extern "C" { /* * Interfaces */ +extern const xmlChar *xsltExtMarker; + void xsltStylePreCompute (xsltStylesheetPtr style, xmlNodePtr inst); void xsltFreeStylePreComps (xsltStylesheetPtr style); diff --git a/libxslt/transform.c b/libxslt/transform.c index 8b73cab5..e9d9b08d 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -1129,8 +1129,12 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, /* * Flagged as an extension element */ - function = (xsltTransformFunction) - xsltExtElementLookup(ctxt, cur->name, cur->ns->href); + if (cur->_private == xsltExtMarker) + function = (xsltTransformFunction) + xsltExtElementLookup(ctxt, cur->name, cur->ns->href); + else + function = ((xsltElemPreCompPtr)cur->_private)->func; + if (function == NULL) { xmlNodePtr child; int found = 0; diff --git a/libxslt/xslt.c b/libxslt/xslt.c index 00a976e5..00424989 100644 --- a/libxslt/xslt.c +++ b/libxslt/xslt.c @@ -1682,7 +1682,7 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { continue; } if (!(IS_XSLT_ELEM(cur))) { - xsltPreComputeFunction function; + xsltTopLevelFunction function; function = xsltExtModuleTopLevelLookup(cur->name, cur->ns->href); diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index 02c7f7ca..0e5f8fb3 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -107,14 +107,13 @@ typedef struct _xsltTransformContext xsltTransformContext; typedef xsltTransformContext *xsltTransformContextPtr; /** - * xsltStylePreComp: + * xsltElemPreComp: * - * The in-memory structure corresponding to XSLT stylesheet constructs - * precomputed data. + * The in-memory structure corresponding to element precomputed data, + * designed to be extended by extension implementors. */ - -typedef struct _xsltStylePreComp xsltStylePreComp; -typedef xsltStylePreComp *xsltStylePreCompPtr; +typedef struct _xsltElemPreComp xsltElemPreComp; +typedef xsltElemPreComp *xsltElemPreCompPtr; /** * xsltTransformFunction: @@ -129,7 +128,7 @@ typedef xsltStylePreComp *xsltStylePreCompPtr; typedef void (*xsltTransformFunction) (xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, - xsltStylePreCompPtr comp); + xsltElemPreCompPtr comp); typedef enum { XSLT_FUNC_COPY=1, @@ -152,17 +151,44 @@ typedef enum { XSLT_FUNC_WITHPARAM, XSLT_FUNC_PARAM, XSLT_FUNC_VARIABLE, - XSLT_FUNC_WHEN + XSLT_FUNC_WHEN, + XSLT_FUNC_EXTENSION } xsltStyleType; +/** + * xsltElemPreCompDeallocator: + * @comp: the #xsltElemPreComp to free up + * + * Deallocates an #xsltElemPreComp structure + */ +typedef void (*xsltElemPreCompDeallocator) (xsltElemPreCompPtr comp); + +/** + * xsltElemPreComp: + * + * The in-memory structure corresponding to element precomputed data, + * designed to be extended by extension implementors. + */ +struct _xsltElemPreComp { + xsltElemPreCompPtr next; /* chained list */ + xsltStyleType type; /* type of the element */ + xsltTransformFunction func; /* handling function */ + xmlNodePtr inst; /* the instruction */ + + /* end of common part */ + xsltElemPreCompDeallocator free; /* the deallocator */ +}; + /** * xsltStylePreComp: * * The in-memory structure corresponding to XSLT stylesheet constructs * precomputed data. */ +typedef struct _xsltStylePreComp xsltStylePreComp; +typedef xsltStylePreComp *xsltStylePreCompPtr; struct _xsltStylePreComp { - struct _xsltStylePreComp *next;/* chained list */ + xsltElemPreCompPtr next; /* chained list */ xsltStyleType type; /* type of the element */ xsltTransformFunction func; /* handling function */ xmlNodePtr inst; /* the instruction */