/* * variables.c: Implementation of the variable storage and lookup * * Reference: * http://www.w3.org/TR/1999/REC-xslt-19991116 * * See Copyright for the status of this software. * * [email protected] */ #define IN_LIBXSLT #include "libxslt.h" #include <string.h> #include <libxml/xmlmemory.h> #include <libxml/tree.h> #include <libxml/valid.h> #include <libxml/hash.h> #include <libxml/xmlerror.h> #include <libxml/xpath.h> #include <libxml/xpathInternals.h> #include <libxml/parserInternals.h> #include <libxml/dict.h> #include "xslt.h" #include "xsltInternals.h" #include "xsltutils.h" #include "variables.h" #include "transform.h" #include "imports.h" #include "preproc.h" #include "keys.h" #ifdef WITH_XSLT_DEBUG #define WITH_XSLT_DEBUG_VARIABLE #endif #ifdef XSLT_REFACTORED const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt"; #endif static const xmlChar *xsltComputingGlobalVarMarker = …; #define XSLT_VAR_GLOBAL … #define XSLT_VAR_IN_SELECT … #define XSLT_TCTXT_VARIABLE(c) … /************************************************************************ * * * Result Value Tree (Result Tree Fragment) interfaces * * * ************************************************************************/ /** * xsltCreateRVT: * @ctxt: an XSLT transformation context * * Creates a Result Value Tree * (the XSLT 1.0 term for this is "Result Tree Fragment") * * Returns the result value tree or NULL in case of API or internal errors. */ xmlDocPtr xsltCreateRVT(xsltTransformContextPtr ctxt) { … } /** * xsltRegisterTmpRVT: * @ctxt: an XSLT transformation context * @RVT: a result value tree (Result Tree Fragment) * * Registers the result value tree (XSLT 1.0 term: Result Tree Fragment) * in the garbage collector. * The fragment will be freed at the exit of the currently * instantiated xsl:template. * Obsolete; this function might produce massive memory overhead, * since the fragment is only freed when the current xsl:template * exits. Use xsltRegisterLocalRVT() instead. * * Returns 0 in case of success and -1 in case of API or internal errors. */ int xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) { … } /** * xsltRegisterLocalRVT: * @ctxt: an XSLT transformation context * @RVT: a result value tree (Result Tree Fragment; xmlDocPtr) * * Registers a result value tree (XSLT 1.0 term: Result Tree Fragment) * in the RVT garbage collector. * The fragment will be freed when the instruction which created the * fragment exits. * * Returns 0 in case of success and -1 in case of API or internal errors. */ int xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) { … } /** * xsltExtensionInstructionResultFinalize: * @ctxt: an XSLT transformation context * * Finalizes the data (e.g. result tree fragments) created * within a value-returning process (e.g. EXSLT's function). * Tree fragments marked as being returned by a function are * set to normal state, which means that the fragment garbage * collector will free them after the function-calling process exits. * * Returns 0 in case of success and -1 in case of API or internal errors. * * This function is unsupported in newer releases of libxslt. */ int xsltExtensionInstructionResultFinalize( xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED) { … } /** * xsltExtensionInstructionResultRegister: * @ctxt: an XSLT transformation context * @obj: an XPath object to be inspected for result tree fragments * * Marks the result of a value-returning extension instruction * in order to avoid it being garbage collected before the * extension instruction exits. * Note that one still has to additionally register any newly created * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT(). * * Returns 0 in case of success and -1 in case of error. * * It isn't necessary to call this function in newer releases of * libxslt. */ int xsltExtensionInstructionResultRegister( xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlXPathObjectPtr obj ATTRIBUTE_UNUSED) { … } /** * xsltFlagRVTs: * @ctxt: an XSLT transformation context * @obj: an XPath object to be inspected for result tree fragments * @val: the flag value * * Updates ownership information of RVTs in @obj according to @val. * * @val = XSLT_RVT_FUNC_RESULT for the result of an extension function, so its * RVTs won't be destroyed after leaving the returning scope. * @val = XSLT_RVT_LOCAL for the result of an extension function to reset * the state of its RVTs after it was returned to a new scope. * @val = XSLT_RVT_GLOBAL for parts of global variables. * * Returns 0 in case of success and -1 in case of error. */ int xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, int val) { … } /** * xsltReleaseRVT: * @ctxt: an XSLT transformation context * @RVT: a result value tree (Result Tree Fragment) * * Either frees the RVT (which is an xmlDoc) or stores * it in the context's cache for later reuse. */ void xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) { … } /** * xsltRegisterPersistRVT: * @ctxt: an XSLT transformation context * @RVT: a result value tree (Result Tree Fragment) * * Register the result value tree (XSLT 1.0 term: Result Tree Fragment) * in the fragment garbage collector. * The fragment will be freed when the transformation context is * freed. * * Returns 0 in case of success and -1 in case of error. */ int xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) { … } /** * xsltFreeRVTs: * @ctxt: an XSLT transformation context * * Frees all registered result value trees (Result Tree Fragments) * of the transformation. Internal function; should not be called * by user-code. */ void xsltFreeRVTs(xsltTransformContextPtr ctxt) { … } /************************************************************************ * * * Module interfaces * * * ************************************************************************/ /** * xsltNewStackElem: * * Create a new XSLT ParserContext * * Returns the newly allocated xsltParserStackElem or NULL in case of error */ static xsltStackElemPtr xsltNewStackElem(xsltTransformContextPtr ctxt) { … } /** * xsltCopyStackElem: * @elem: an XSLT stack element * * Makes a copy of the stack element * * Returns the copy of NULL */ static xsltStackElemPtr xsltCopyStackElem(xsltStackElemPtr elem) { … } /** * xsltFreeStackElem: * @elem: an XSLT stack element * * Free up the memory allocated by @elem */ static void xsltFreeStackElem(xsltStackElemPtr elem) { … } static void xsltFreeStackElemEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { … } /** * xsltFreeStackElemList: * @elem: an XSLT stack element * * Free up the memory allocated by @elem */ void xsltFreeStackElemList(xsltStackElemPtr elem) { … } /** * xsltStackLookup: * @ctxt: an XSLT transformation context * @name: the local part of the name * @nameURI: the URI part of the name * * Locate an element in the stack based on its name. */ #if 0 /* TODO: Those seem to have been used for debugging. */ static int stack_addr = 0; static int stack_cmp = 0; #endif static xsltStackElemPtr xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *nameURI) { … } #ifdef XSLT_REFACTORED #else /** * xsltCheckStackElem: * @ctxt: xn XSLT transformation context * @name: the variable name * @nameURI: the variable namespace URI * * Checks whether a variable or param is already defined. * * URGENT TODO: Checks for redefinition of vars/params should be * done only at compilation time. * * Returns 1 if variable is present, 2 if param is present, 3 if this * is an inherited param, 0 if not found, -1 in case of failure. */ static int xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *nameURI) { … } #endif /* XSLT_REFACTORED */ /** * xsltAddStackElem: * @ctxt: xn XSLT transformation context * @elem: a stack element * * Push an element (or list) onto the stack. * In case of a list, each member will be pushed into * a seperate slot; i.e. there's always 1 stack entry for * 1 stack element. * * Returns 0 in case of success, -1 in case of failure. */ static int xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) { … } /** * xsltAddStackElemList: * @ctxt: xn XSLT transformation context * @elems: a stack element list * * Push an element list onto the stack. * * Returns 0 in case of success, -1 in case of failure. */ int xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) { … } /************************************************************************ * * * Module interfaces * * * ************************************************************************/ /** * xsltEvalVariable: * @ctxt: the XSLT transformation context * @variable: the variable or parameter item * @comp: the compiled XSLT instruction * * Evaluate a variable value. * * Returns the XPath Object value or NULL in case of error */ static xmlXPathObjectPtr xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable, xsltStylePreCompPtr castedComp) { … } /** * xsltEvalGlobalVariable: * @elem: the variable or parameter * @ctxt: the XSLT transformation context * * Evaluates a the value of a global xsl:variable or * xsl:param declaration. * * Returns the XPath Object value or NULL in case of error */ static xmlXPathObjectPtr xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) { … } static void xsltEvalGlobalVariableWrapper(void *payload, void *data, const xmlChar *name ATTRIBUTE_UNUSED) { … } /** * xsltEvalGlobalVariables: * @ctxt: the XSLT transformation context * * Evaluates all global variables and parameters of a stylesheet. * For internal use only. This is called at start of a transformation. * * Returns 0 in case of success, -1 in case of error */ int xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) { … } /** * xsltRegisterGlobalVariable: * @style: the XSLT transformation context * @name: the variable name * @ns_uri: the variable namespace URI * @sel: the expression which need to be evaluated to generate a value * @tree: the subtree if sel is NULL * @comp: the precompiled value * @value: the string value if available * * Register a new variable value. If @value is NULL it unregisters * the variable * * Returns 0 in case of success, -1 in case of error */ static int xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name, const xmlChar *ns_uri, const xmlChar *sel, xmlNodePtr tree, xsltStylePreCompPtr comp, const xmlChar *value) { … } /** * xsltProcessUserParamInternal * * @ctxt: the XSLT transformation context * @name: a null terminated parameter name * @value: a null terminated value (may be an XPath expression) * @eval: 0 to treat the value literally, else evaluate as XPath expression * * If @eval is 0 then @value is treated literally and is stored in the global * parameter/variable table without any change. * * Uf @eval is 1 then @value is treated as an XPath expression and is * evaluated. In this case, if you want to pass a string which will be * interpreted literally then it must be enclosed in single or double quotes. * If the string contains single quotes (double quotes) then it cannot be * enclosed single quotes (double quotes). If the string which you want to * be treated literally contains both single and double quotes (e.g. Meet * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable * quoting character. You cannot use ' or " inside the string * because the replacement of character entities with their equivalents is * done at a different stage of processing. The solution is to call * xsltQuoteUserParams or xsltQuoteOneUserParam. * * This needs to be done on parsed stylesheets before starting to apply * transformations. Normally this will be called (directly or indirectly) * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams, * or xsltQuoteOneUserParam. * * Returns 0 in case of success, -1 in case of error */ static int xsltProcessUserParamInternal(xsltTransformContextPtr ctxt, const xmlChar * name, const xmlChar * value, int eval) { … } /** * xsltEvalUserParams: * * @ctxt: the XSLT transformation context * @params: a NULL terminated array of parameters name/value tuples * * Evaluate the global variables of a stylesheet. This needs to be * done on parsed stylesheets before starting to apply transformations. * Each of the parameters is evaluated as an XPath expression and stored * in the global variables/parameter hash table. If you want your * parameter used literally, use xsltQuoteUserParams. * * Returns 0 in case of success, -1 in case of error */ int xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) { … } /** * xsltQuoteUserParams: * * @ctxt: the XSLT transformation context * @params: a NULL terminated arry of parameters names/values tuples * * Similar to xsltEvalUserParams, but the values are treated literally and * are * *not* evaluated as XPath expressions. This should be done on parsed * stylesheets before starting to apply transformations. * * Returns 0 in case of success, -1 in case of error. */ int xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) { … } /** * xsltEvalOneUserParam: * @ctxt: the XSLT transformation context * @name: a null terminated string giving the name of the parameter * @value: a null terminated string giving the XPath expression to be evaluated * * This is normally called from xsltEvalUserParams to process a single * parameter from a list of parameters. The @value is evaluated as an * XPath expression and the result is stored in the context's global * variable/parameter hash table. * * To have a parameter treated literally (not as an XPath expression) * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more * details see description of xsltProcessOneUserParamInternal. * * Returns 0 in case of success, -1 in case of error. */ int xsltEvalOneUserParam(xsltTransformContextPtr ctxt, const xmlChar * name, const xmlChar * value) { … } /** * xsltQuoteOneUserParam: * @ctxt: the XSLT transformation context * @name: a null terminated string giving the name of the parameter * @value: a null terminated string giving the parameter value * * This is normally called from xsltQuoteUserParams to process a single * parameter from a list of parameters. The @value is stored in the * context's global variable/parameter hash table. * * Returns 0 in case of success, -1 in case of error. */ int xsltQuoteOneUserParam(xsltTransformContextPtr ctxt, const xmlChar * name, const xmlChar * value) { … } /** * xsltBuildVariable: * @ctxt: the XSLT transformation context * @comp: the precompiled form * @tree: the tree if select is NULL * * Computes a new variable value. * * Returns the xsltStackElemPtr or NULL in case of error */ static xsltStackElemPtr xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr castedComp, xmlNodePtr tree) { … } /** * xsltRegisterVariable: * @ctxt: the XSLT transformation context * @comp: the compiled XSLT-variable (or param) instruction * @tree: the tree if select is NULL * @isParam: indicates if this is a parameter * * Computes and registers a new variable. * * Returns 0 in case of success, -1 in case of error */ static int xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr castedComp, xmlNodePtr tree, int isParam) { … } /** * xsltGlobalVariableLookup: * @ctxt: the XSLT transformation context * @name: the variable name * @ns_uri: the variable namespace URI * * Search in the Variable array of the context for the given * variable value. * * Returns the value or NULL if not found */ static xmlXPathObjectPtr xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *ns_uri) { … } /** * xsltVariableLookup: * @ctxt: the XSLT transformation context * @name: the variable name * @ns_uri: the variable namespace URI * * Search in the Variable array of the context for the given * variable value. * * Returns the value or NULL if not found */ xmlXPathObjectPtr xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name, const xmlChar *ns_uri) { … } /** * xsltParseStylesheetCallerParam: * @ctxt: the XSLT transformation context * @inst: the xsl:with-param instruction element * * Processes an xsl:with-param instruction at transformation time. * The value is computed, but not recorded. * NOTE that this is also called with an *xsl:param* element * from exsltFuncFunctionFunction(). * * Returns the new xsltStackElemPtr or NULL */ xsltStackElemPtr xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst) { … } /** * xsltParseGlobalVariable: * @style: the XSLT stylesheet * @cur: the "variable" element * * Parses a global XSLT 'variable' declaration at compilation time * and registers it */ void xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) { … } /** * xsltParseGlobalParam: * @style: the XSLT stylesheet * @cur: the "param" element * * parse an XSLT transformation param declaration and record * its value. */ void xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) { … } /** * xsltParseStylesheetVariable: * @ctxt: the XSLT transformation context * @inst: the xsl:variable instruction element * * Registers a local XSLT 'variable' instruction at transformation time * and evaluates its value. */ void xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst) { … } /** * xsltParseStylesheetParam: * @ctxt: the XSLT transformation context * @cur: the XSLT 'param' element * * Registers a local XSLT 'param' declaration at transformation time and * evaluates its value. */ void xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) { … } /** * xsltFreeGlobalVariables: * @ctxt: the XSLT transformation context * * Free up the data associated to the global variables * its value. */ void xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) { … } /** * xsltXPathVariableLookup: * @ctxt: a void * but the the XSLT transformation context actually * @name: the variable name * @ns_uri: the variable namespace URI * * This is the entry point when a varibale is needed by the XPath * interpretor. * * Returns the value or NULL if not found */ xmlXPathObjectPtr xsltXPathVariableLookup(void *ctxt, const xmlChar *name, const xmlChar *ns_uri) { … }