2 * variables.c: Implementation of the variable storage and lookup
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 * See Copyright for the status of this software.
16 #include <libxml/xmlmemory.h>
17 #include <libxml/tree.h>
18 #include <libxml/valid.h>
19 #include <libxml/hash.h>
20 #include <libxml/xmlerror.h>
21 #include <libxml/xpath.h>
22 #include <libxml/xpathInternals.h>
23 #include <libxml/parserInternals.h>
25 #include "xsltInternals.h"
26 #include "xsltutils.h"
27 #include "variables.h"
28 #include "transform.h"
32 #ifdef WITH_XSLT_DEBUG
33 #define WITH_XSLT_DEBUG_VARIABLE
36 /************************************************************************
40 ************************************************************************/
45 * Create a new XSLT ParserContext
47 * Returns the newly allocated xsltParserStackElem or NULL in case of error
49 static xsltStackElemPtr
50 xsltNewStackElem(void) {
53 cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
55 xsltPrintErrorContext(NULL, NULL, NULL);
56 xsltGenericError(xsltGenericErrorContext,
57 "xsltNewStackElem : malloc failed\n");
72 * @elem: an XSLT stack element
74 * Makes a copy of the stack element
76 * Returns the copy of NULL
78 static xsltStackElemPtr
79 xsltCopyStackElem(xsltStackElemPtr elem) {
82 cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
84 xsltPrintErrorContext(NULL, NULL, NULL);
85 xsltGenericError(xsltGenericErrorContext,
86 "xsltCopyStackElem : malloc failed\n");
89 cur->name = xmlStrdup(elem->name);
90 cur->nameURI = xmlStrdup(elem->nameURI);
91 cur->select = xmlStrdup(elem->select);
92 cur->tree = elem->tree;
93 cur->comp = elem->comp;
101 * @elem: an XSLT stack element
103 * Free up the memory allocated by @elem
106 xsltFreeStackElem(xsltStackElemPtr elem) {
109 if (elem->name != NULL)
111 if (elem->nameURI != NULL)
112 xmlFree(elem->nameURI);
113 if (elem->select != NULL)
114 xmlFree(elem->select);
115 if (elem->value != NULL)
116 xmlXPathFreeObject(elem->value);
122 * xsltFreeStackElemList:
123 * @elem: an XSLT stack element
125 * Free up the memory allocated by @elem
128 xsltFreeStackElemList(xsltStackElemPtr elem) {
129 xsltStackElemPtr next;
131 while(elem != NULL) {
133 xsltFreeStackElem(elem);
139 * xsltCheckStackElem:
140 * @ctxt: xn XSLT transformation context
141 * @name: the variable name
142 * @nameURI: the variable namespace URI
144 * check wether the variable or param is already defined
146 * Returns 1 if present, 0 if not, -1 in case of failure.
149 xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
150 const xmlChar *nameURI) {
151 xsltStackElemPtr cur;
153 if ((ctxt == NULL) || (name == NULL))
157 while (cur != NULL) {
158 if (xmlStrEqual(name, cur->name)) {
159 if (((nameURI == NULL) && (cur->nameURI == NULL)) ||
160 ((nameURI != NULL) && (cur->nameURI != NULL) &&
161 (xmlStrEqual(nameURI, cur->nameURI)))) {
172 * @ctxt: xn XSLT transformation context
173 * @elem: a stack element
175 * add a new element at this level of the stack.
177 * Returns 0 in case of success, -1 in case of failure.
180 xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
181 if ((ctxt == NULL) || (elem == NULL))
184 elem->next = ctxt->varsTab[ctxt->varsNr - 1];
185 ctxt->varsTab[ctxt->varsNr - 1] = elem;
191 * xsltAddStackElemList:
192 * @ctxt: xn XSLT transformation context
193 * @elems: a stack element list
195 * add the new element list at this level of the stack.
197 * Returns 0 in case of success, -1 in case of failure.
200 xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) {
201 xsltStackElemPtr cur;
203 if ((ctxt == NULL) || (elems == NULL))
206 /* TODO: check doublons */
207 if (ctxt->varsTab[ctxt->varsNr - 1] != NULL) {
208 cur = ctxt->varsTab[ctxt->varsNr - 1];
209 while (cur->next != NULL)
213 elems->next = ctxt->varsTab[ctxt->varsNr - 1];
214 ctxt->varsTab[ctxt->varsNr - 1] = elems;
222 * @ctxt: an XSLT transformation context
223 * @name: the local part of the name
224 * @nameURI: the URI part of the name
226 * Locate an element in the stack based on its name.
228 static xsltStackElemPtr
229 xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
230 const xmlChar *nameURI) {
231 xsltStackElemPtr ret = NULL;
233 xsltStackElemPtr cur;
235 if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
239 * Do the lookup from the top of the stack, but
240 * don't use params being computed in a call-param
244 for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
245 cur = ctxt->varsTab[i-1];
246 while (cur != NULL) {
247 if (xmlStrEqual(cur->name, name)) {
248 if (nameURI == NULL) {
249 if (cur->nameURI == NULL) {
253 if ((cur->nameURI != NULL) &&
254 (xmlStrEqual(cur->nameURI, nameURI))) {
266 /************************************************************************
268 * Module interfaces *
270 ************************************************************************/
274 * @ctxt: the XSLT transformation context
275 * @elem: the variable or parameter.
276 * @precomp: pointer to precompiled data
278 * Evaluate a variable value.
280 * Returns the XPath Object value or NULL in case of error
282 static xmlXPathObjectPtr
283 xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
284 xsltStylePreCompPtr precomp) {
285 xmlXPathObjectPtr result = NULL;
286 int oldProximityPosition, oldContextSize;
287 xmlNodePtr oldInst, oldNode;
288 xsltDocumentPtr oldDoc;
290 xmlNsPtr *oldNamespaces;
292 if ((ctxt == NULL) || (elem == NULL))
295 #ifdef WITH_XSLT_DEBUG_VARIABLE
296 xsltGenericDebug(xsltGenericDebugContext,
297 "Evaluating variable %s\n", elem->name);
299 if (elem->select != NULL) {
300 xmlXPathCompExprPtr comp = NULL;
302 if ((precomp != NULL) && (precomp->comp != NULL)) {
303 comp = precomp->comp;
305 comp = xmlXPathCompile(elem->select);
309 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
310 oldContextSize = ctxt->xpathCtxt->contextSize;
311 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
312 oldDoc = ctxt->document;
313 oldNode = ctxt->node;
314 oldInst = ctxt->inst;
315 oldNsNr = ctxt->xpathCtxt->nsNr;
316 oldNamespaces = ctxt->xpathCtxt->namespaces;
317 if (precomp != NULL) {
318 ctxt->inst = precomp->inst;
319 ctxt->xpathCtxt->namespaces = precomp->nsList;
320 ctxt->xpathCtxt->nsNr = precomp->nsNr;
323 ctxt->xpathCtxt->namespaces = NULL;
324 ctxt->xpathCtxt->nsNr = 0;
326 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
327 ctxt->xpathCtxt->contextSize = oldContextSize;
328 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
329 ctxt->xpathCtxt->nsNr = oldNsNr;
330 ctxt->xpathCtxt->namespaces = oldNamespaces;
331 ctxt->inst = oldInst;
332 ctxt->node = oldNode;
333 ctxt->document = oldDoc;
334 if ((precomp == NULL) || (precomp->comp == NULL))
335 xmlXPathFreeCompExpr(comp);
336 if (result == NULL) {
337 xsltPrintErrorContext(ctxt, NULL, precomp->inst);
338 xsltGenericError(xsltGenericErrorContext,
339 "Evaluating variable %s failed\n", elem->name);
340 ctxt->state = XSLT_STATE_STOPPED;
341 #ifdef WITH_XSLT_DEBUG_VARIABLE
342 #ifdef LIBXML_DEBUG_ENABLED
344 if ((xsltGenericDebugContext == stdout) ||
345 (xsltGenericDebugContext == stderr))
346 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
352 if (elem->tree == NULL) {
353 result = xmlXPathNewCString("");
356 * This is a result tree fragment.
358 xmlNodePtr container;
359 xmlNodePtr oldInsert;
362 container = xmlNewDocNode(ctxt->document->doc, NULL,
363 (const xmlChar *) "fake node libxslt", NULL);
364 if (container == NULL)
366 container->parent = NULL;
368 oldoutput = ctxt->output;
370 oldInsert = ctxt->insert;
371 ctxt->insert = container;
372 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
373 ctxt->insert = oldInsert;
374 ctxt->output = oldoutput;
376 result = xmlXPathNewValueTree(container);
377 if (result == NULL) {
378 result = xmlXPathNewCString("");
381 * Tag the subtree for removal once consumed
385 #ifdef WITH_XSLT_DEBUG_VARIABLE
386 #ifdef LIBXML_DEBUG_ENABLED
387 if ((xsltGenericDebugContext == stdout) ||
388 (xsltGenericDebugContext == stderr))
389 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
399 * xsltEvalGlobalVariable:
400 * @elem: the variable or parameter.
401 * @ctxt: the XSLT transformation context
403 * Evaluate a global variable value.
405 * Returns the XPath Object value or NULL in case of error
407 static xmlXPathObjectPtr
408 xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
409 xmlXPathObjectPtr result = NULL;
410 xsltStylePreCompPtr precomp;
411 int oldProximityPosition, oldContextSize;
414 xmlNsPtr *oldNamespaces;
416 if ((ctxt == NULL) || (elem == NULL))
422 #ifdef WITH_XSLT_DEBUG_VARIABLE
423 xsltGenericDebug(xsltGenericDebugContext,
424 "Evaluating global variable %s\n", elem->name);
428 if ((xslDebugStatus != XSLT_DEBUG_NONE) &&
429 elem->comp && elem->comp->inst)
430 xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
433 precomp = elem->comp;
434 if (elem->select != NULL) {
435 xmlXPathCompExprPtr comp = NULL;
437 if ((precomp != NULL) && (precomp->comp != NULL)) {
438 comp = precomp->comp;
440 comp = xmlXPathCompile(elem->select);
444 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
445 oldContextSize = ctxt->xpathCtxt->contextSize;
446 oldInst = ctxt->inst;
447 oldNsNr = ctxt->xpathCtxt->nsNr;
448 oldNamespaces = ctxt->xpathCtxt->namespaces;
449 if (precomp != NULL) {
450 ctxt->inst = precomp->inst;
451 ctxt->xpathCtxt->namespaces = precomp->nsList;
452 ctxt->xpathCtxt->nsNr = precomp->nsNr;
455 ctxt->xpathCtxt->namespaces = NULL;
456 ctxt->xpathCtxt->nsNr = 0;
458 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
459 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
460 ctxt->xpathCtxt->contextSize = oldContextSize;
461 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
462 ctxt->inst = oldInst;
463 ctxt->xpathCtxt->nsNr = oldNsNr;
464 ctxt->xpathCtxt->namespaces = oldNamespaces;
465 if ((precomp == NULL) || (precomp->comp == NULL))
466 xmlXPathFreeCompExpr(comp);
467 if (result == NULL) {
468 xsltPrintErrorContext(ctxt, NULL, precomp->inst);
469 xsltGenericError(xsltGenericErrorContext,
470 "Evaluating global variable %s failed\n", elem->name);
471 ctxt->state = XSLT_STATE_STOPPED;
472 #ifdef WITH_XSLT_DEBUG_VARIABLE
473 #ifdef LIBXML_DEBUG_ENABLED
475 if ((xsltGenericDebugContext == stdout) ||
476 (xsltGenericDebugContext == stderr))
477 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
483 if (elem->tree == NULL) {
484 result = xmlXPathNewCString("");
487 * This is a result tree fragment.
489 xmlNodePtr container;
490 xmlNodePtr oldInsert;
493 container = xmlNewDocNode(ctxt->document->doc, NULL,
494 (const xmlChar *) "fake node libxslt", NULL);
495 if (container == NULL)
497 container->parent = NULL;
499 oldoutput = ctxt->output;
501 oldInsert = ctxt->insert;
502 ctxt->insert = container;
503 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
504 ctxt->insert = oldInsert;
505 ctxt->output = oldoutput;
507 result = xmlXPathNewValueTree(container);
508 if (result == NULL) {
509 result = xmlXPathNewCString("");
512 * Tag the subtree for removal once consumed
516 #ifdef WITH_XSLT_DEBUG_VARIABLE
517 #ifdef LIBXML_DEBUG_ENABLED
518 if ((xsltGenericDebugContext == stdout) ||
519 (xsltGenericDebugContext == stderr))
520 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
526 if (result != NULL) {
527 elem->value = result;
534 * xsltEvalGlobalVariables:
535 * @ctxt: the XSLT transformation context
537 * Evaluate the global variables of a stylesheet. This need to be
538 * done on parsed stylesheets before starting to apply transformations
540 * Returns 0 in case of success, -1 in case of error
543 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
544 xsltStackElemPtr elem;
545 xsltStylesheetPtr style;
550 #ifdef WITH_XSLT_DEBUG_VARIABLE
551 xsltGenericDebug(xsltGenericDebugContext,
552 "Registering global variables\n");
554 ctxt->node = (xmlNodePtr) ctxt->document->doc;
555 ctxt->xpathCtxt->contextSize = 1;
556 ctxt->xpathCtxt->proximityPosition = 1;
559 * Walk the list from the stylesheets and populate the hash table
562 while (style != NULL) {
563 elem = style->variables;
565 #ifdef WITH_XSLT_DEBUG_VARIABLE
566 if ((style->doc != NULL) && (style->doc->URL != NULL)) {
567 xsltGenericDebug(xsltGenericDebugContext,
568 "Registering global variables from %s\n",
573 while (elem != NULL) {
574 xsltStackElemPtr def;
577 * Global variables are stored in the variables pool.
579 def = (xsltStackElemPtr)
580 xmlHashLookup2(ctxt->globalVars,
581 elem->name, elem->nameURI);
585 def = xsltCopyStackElem(elem);
586 res = xmlHashAddEntry2(ctxt->globalVars,
587 elem->name, elem->nameURI, def);
588 } else if ((elem->comp != NULL) &&
589 (elem->comp->type == XSLT_FUNC_VARIABLE)) {
591 * Redefinition of variables from a different stylesheet
592 * should not generate a message.
594 if ((elem->comp->inst != NULL) &&
595 (def->comp != NULL) && (def->comp->inst != NULL) &&
596 (elem->comp->inst->doc == def->comp->inst->doc)) {
597 xsltPrintErrorContext(ctxt, style, elem->comp->inst);
598 xsltGenericError(xsltGenericErrorContext,
599 "Global variable %s already defined\n", elem->name);
605 style = xsltNextImport(style);
609 * This part does the actual evaluation
611 ctxt->node = (xmlNodePtr) ctxt->document->doc;
612 ctxt->xpathCtxt->contextSize = 1;
613 ctxt->xpathCtxt->proximityPosition = 1;
614 xmlHashScan(ctxt->globalVars,
615 (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
621 * xsltRegisterGlobalVariable:
622 * @style: the XSLT transformation context
623 * @name: the variable name
624 * @ns_uri: the variable namespace URI
625 * @select: the expression which need to be evaluated to generate a value
626 * @tree: the subtree if select is NULL
627 * @comp: the precompiled value
628 * @value: the string value if available
630 * Register a new variable value. If @value is NULL it unregisters
633 * Returns 0 in case of success, -1 in case of error
636 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
637 const xmlChar *ns_uri, const xmlChar *select,
638 xmlNodePtr tree, xsltStylePreCompPtr comp,
639 const xmlChar *value) {
640 xsltStackElemPtr elem, tmp;
648 #ifdef WITH_XSLT_DEBUG_VARIABLE
649 if (comp->type == XSLT_FUNC_PARAM)
650 xsltGenericDebug(xsltGenericDebugContext,
651 "Defining global param %s\n", name);
653 xsltGenericDebug(xsltGenericDebugContext,
654 "Defining global variable %s\n", name);
657 elem = xsltNewStackElem();
661 elem->name = xmlStrdup(name);
662 elem->select = xmlStrdup(select);
664 elem->nameURI = xmlStrdup(ns_uri);
666 tmp = style->variables;
669 style->variables = elem;
671 while (tmp->next != NULL)
678 elem->value = xmlXPathNewString(value);
684 * xsltProcessUserParamInternal
686 * @ctxt: the XSLT transformation context
687 * @name: a null terminated parameter name
688 * @value: a null terminated value (may be an XPath expression)
689 * @eval: 0 to treat the value literally, else evaluate as XPath expression
691 * If @eval is 0 then @value is treated literally and is stored in the global
692 * parameter/variable table without any change.
694 * Uf @eval is 1 then @value is treated as an XPath expression and is
695 * evaluated. In this case, if you want to pass a string which will be
696 * interpreted literally then it must be enclosed in single or double quotes.
697 * If the string contains single quotes (double quotes) then it cannot be
698 * enclosed single quotes (double quotes). If the string which you want to
699 * be treated literally contains both single and double quotes (e.g. Meet
700 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
701 * quoting character. You cannot use ' or " inside the string
702 * because the replacement of character entities with their equivalents is
703 * done at a different stage of processing. The solution is to call
704 * xsltQuoteUserParams or xsltQuoteOneUserParam.
706 * This needs to be done on parsed stylesheets before starting to apply
707 * transformations. Normally this will be called (directly or indirectly)
708 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
709 * or xsltQuoteOneUserParam.
711 * Returns 0 in case of success, -1 in case of error
716 xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
717 const xmlChar * name,
718 const xmlChar * value,
721 xsltStylesheetPtr style;
725 xmlXPathCompExprPtr comp;
726 xmlXPathObjectPtr result;
727 int oldProximityPosition;
730 xmlNsPtr *oldNamespaces;
731 xsltStackElemPtr elem;
743 #ifdef WITH_XSLT_DEBUG_VARIABLE
744 xsltGenericDebug(xsltGenericDebugContext,
745 "Evaluating user parameter %s=%s\n", name, value);
752 ncname = xmlSplitQName2(name, &prefix);
754 if (ncname != NULL) {
755 if (prefix != NULL) {
758 ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
761 xsltPrintErrorContext(ctxt, style, NULL);
762 xsltGenericError(xsltGenericErrorContext,
763 "user param : no namespace bound to prefix %s\n", prefix);
775 ncname = xmlStrdup(name);
779 * Do the evaluation if @eval is non-zero.
784 comp = xmlXPathCompile(value);
786 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
787 oldContextSize = ctxt->xpathCtxt->contextSize;
788 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
791 * There is really no in scope namespace for parameters on the
795 oldNsNr = ctxt->xpathCtxt->nsNr;
796 oldNamespaces = ctxt->xpathCtxt->namespaces;
797 ctxt->xpathCtxt->namespaces = NULL;
798 ctxt->xpathCtxt->nsNr = 0;
799 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
800 ctxt->xpathCtxt->contextSize = oldContextSize;
801 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
802 ctxt->xpathCtxt->nsNr = oldNsNr;
803 ctxt->xpathCtxt->namespaces = oldNamespaces;
804 xmlXPathFreeCompExpr(comp);
806 if (result == NULL) {
807 xsltPrintErrorContext(ctxt, style, NULL);
808 xsltGenericError(xsltGenericErrorContext,
809 "Evaluating user parameter %s failed\n", name);
810 ctxt->state = XSLT_STATE_STOPPED;
817 * If @eval is 0 then @value is to be taken literally and result is NULL
819 * If @eval is not 0, then @value is an XPath expression and has been
820 * successfully evaluated and result contains the resulting value and
823 * Now create an xsltStackElemPtr for insertion into the context's
824 * global variable/parameter hash table.
827 #ifdef WITH_XSLT_DEBUG_VARIABLE
828 #ifdef LIBXML_DEBUG_ENABLED
829 if ((xsltGenericDebugContext == stdout) ||
830 (xsltGenericDebugContext == stderr))
831 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
836 elem = xsltNewStackElem();
838 elem->name = xmlStrdup(ncname);
840 elem->select = xmlStrdup(value);
844 elem->nameURI = xmlStrdup(href);
848 elem->value = xmlXPathNewString(value);
851 elem->value = result;
856 * Global parameters are stored in the XPath context variables pool.
859 res = xmlHashAddEntry2(ctxt->globalVars, ncname, href, elem);
861 xsltFreeStackElem(elem);
862 xsltPrintErrorContext(ctxt, style, NULL);
863 xsltGenericError(xsltGenericErrorContext,
864 "Global parameter %s already defined\n", ncname);
871 * xsltEvalUserParams:
873 * @ctxt: the XSLT transformation context
874 * @params: a NULL terminated array of parameters name/value tuples
876 * Evaluate the global variables of a stylesheet. This needs to be
877 * done on parsed stylesheets before starting to apply transformations.
878 * Each of the parameters is evaluated as an XPath expression and stored
879 * in the global variables/parameter hash table. If you want your
880 * parameter used literally, use xsltQuoteUserParams.
882 * Returns 0 in case of success, -1 in case of error
886 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
889 const xmlChar *value;
893 while (params[indx] != NULL) {
894 name = (const xmlChar *) params[indx++];
895 value = (const xmlChar *) params[indx++];
896 if (xsltEvalOneUserParam(ctxt, name, value) != 0)
903 * xsltQuoteUserParams:
905 * @ctxt: the XSLT transformation context
906 * @params: a NULL terminated arry of parameters names/values tuples
908 * Similar to xsltEvalUserParams, but the values are treated literally and
909 * are * *not* evaluated as XPath expressions. This should be done on parsed
910 * stylesheets before starting to apply transformations.
912 * Returns 0 in case of success, -1 in case of error.
916 xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
919 const xmlChar *value;
923 while (params[indx] != NULL) {
924 name = (const xmlChar *) params[indx++];
925 value = (const xmlChar *) params[indx++];
926 if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
933 * xsltEvalOneUserParam:
935 * @ctxt: the XSLT transformation context
936 * @name: a null terminated string giving the name of the parameter
937 * @value a null terminated string giving the XPath expression to be evaluated
939 * This is normally called from xsltEvalUserParams to process a single
940 * parameter from a list of parameters. The @value is evaluated as an
941 * XPath expression and the result is stored in the context's global
942 * variable/parameter hash table.
944 * To have a parameter treated literally (not as an XPath expression)
945 * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
946 * details see description of xsltProcessOneUserParamInternal.
948 * Returns 0 in case of success, -1 in case of error.
952 xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
953 const xmlChar * name,
954 const xmlChar * value) {
955 return xsltProcessUserParamInternal(ctxt, name, value,
956 1 /* xpath eval ? */);
960 * xsltQuoteOneUserParam:
962 * @ctxt: the XSLT transformation context
963 * @name: a null terminated string giving the name of the parameter
964 * @value a null terminated string giving the parameter value
966 * This is normally called from xsltQuoteUserParams to process a single
967 * parameter from a list of parameters. The @value is stored in the
968 * context's global variable/parameter hash table.
970 * Returns 0 in case of success, -1 in case of error.
974 xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
975 const xmlChar * name,
976 const xmlChar * value) {
977 return xsltProcessUserParamInternal(ctxt, name, value,
978 0 /* xpath eval ? */);
983 * @ctxt: the XSLT transformation context
984 * @comp: the precompiled form
985 * @tree: the tree if select is NULL
987 * Computes a new variable value.
989 * Returns the xsltStackElemPtr or NULL in case of error
991 static xsltStackElemPtr
992 xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
994 xsltStackElemPtr elem;
996 #ifdef WITH_XSLT_DEBUG_VARIABLE
997 xsltGenericDebug(xsltGenericDebugContext,
998 "Building variable %s", comp->name);
999 if (comp->select != NULL)
1000 xsltGenericDebug(xsltGenericDebugContext,
1001 " select %s", comp->select);
1002 xsltGenericDebug(xsltGenericDebugContext, "\n");
1005 elem = xsltNewStackElem();
1009 elem->name = xmlStrdup(comp->name);
1010 if (comp->select != NULL)
1011 elem->select = xmlStrdup(comp->select);
1013 elem->select = NULL;
1015 elem->nameURI = xmlStrdup(comp->ns);
1017 if (elem->computed == 0) {
1018 elem->value = xsltEvalVariable(ctxt, elem, comp);
1019 if (elem->value != NULL)
1026 * xsltRegisterVariable:
1027 * @ctxt: the XSLT transformation context
1028 * @comp: pointer to precompiled data
1029 * @tree: the tree if select is NULL
1030 * @param: this is a parameter actually
1032 * Computes and register a new variable value.
1034 * Returns 0 in case of success, -1 in case of error
1037 xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1038 xmlNodePtr tree, int param) {
1039 xsltStackElemPtr elem;
1041 if (xsltCheckStackElem(ctxt, comp->name, comp->ns) != 0) {
1043 xsltPrintErrorContext(ctxt, NULL, comp->inst);
1044 xsltGenericError(xsltGenericErrorContext,
1045 "xsl:variable : redefining %s\n", comp->name);
1047 #ifdef WITH_XSLT_DEBUG_VARIABLE
1049 xsltGenericDebug(xsltGenericDebugContext,
1050 "param %s defined by caller\n", comp->name);
1054 elem = xsltBuildVariable(ctxt, comp, tree);
1055 xsltAddStackElem(ctxt, elem);
1060 * xsltGlobalVariableLookup:
1061 * @ctxt: the XSLT transformation context
1062 * @name: the variable name
1063 * @ns_uri: the variable namespace URI
1065 * Search in the Variable array of the context for the given
1068 * Returns the value or NULL if not found
1070 static xmlXPathObjectPtr
1071 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1072 const xmlChar *ns_uri) {
1073 xsltStackElemPtr elem;
1074 xmlXPathObjectPtr ret = NULL;
1077 * Lookup the global variables in XPath global variable hash table
1079 if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
1081 elem = (xsltStackElemPtr)
1082 xmlHashLookup2(ctxt->globalVars, name, ns_uri);
1084 #ifdef WITH_XSLT_DEBUG_VARIABLE
1085 xsltGenericDebug(xsltGenericDebugContext,
1086 "global variable not found %s\n", name);
1090 if (elem->computed == 0)
1091 ret = xsltEvalGlobalVariable(elem, ctxt);
1094 return(xmlXPathObjectCopy(ret));
1098 * xsltVariableLookup:
1099 * @ctxt: the XSLT transformation context
1100 * @name: the variable name
1101 * @ns_uri: the variable namespace URI
1103 * Search in the Variable array of the context for the given
1106 * Returns the value or NULL if not found
1109 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1110 const xmlChar *ns_uri) {
1111 xsltStackElemPtr elem;
1116 elem = xsltStackLookup(ctxt, name, ns_uri);
1118 return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
1120 if (elem->computed == 0) {
1121 #ifdef WITH_XSLT_DEBUG_VARIABLE
1122 xsltGenericDebug(xsltGenericDebugContext,
1123 "uncomputed variable %s\n", name);
1125 elem->value = xsltEvalVariable(ctxt, elem, NULL);
1128 if (elem->value != NULL)
1129 return(xmlXPathObjectCopy(elem->value));
1130 #ifdef WITH_XSLT_DEBUG_VARIABLE
1131 xsltGenericDebug(xsltGenericDebugContext,
1132 "variable not found %s\n", name);
1138 * xsltParseStylesheetCallerParam:
1139 * @ctxt: the XSLT transformation context
1140 * @cur: the "param" element
1142 * parse an XSLT transformation param declaration, compute
1143 * its value but doesn't record it.
1145 * It returns the new xsltStackElemPtr or NULL
1149 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1150 xmlNodePtr tree = NULL;
1151 xsltStackElemPtr elem = NULL;
1152 xsltStylePreCompPtr comp;
1154 if ((cur == NULL) || (ctxt == NULL))
1156 comp = (xsltStylePreCompPtr) cur->_private;
1158 xsltPrintErrorContext(ctxt, NULL, cur);
1159 xsltGenericError(xsltGenericErrorContext,
1160 "xsl:param : compilation error\n");
1164 if (comp->name == NULL) {
1165 xsltPrintErrorContext(ctxt, NULL, cur);
1166 xsltGenericError(xsltGenericErrorContext,
1167 "xsl:param : missing name attribute\n");
1171 #ifdef WITH_XSLT_DEBUG_VARIABLE
1172 xsltGenericDebug(xsltGenericDebugContext,
1173 "Handling param %s\n", comp->name);
1176 if (comp->select == NULL) {
1177 tree = cur->children;
1179 #ifdef WITH_XSLT_DEBUG_VARIABLE
1180 xsltGenericDebug(xsltGenericDebugContext,
1181 " select %s\n", comp->select);
1186 elem = xsltBuildVariable(ctxt, comp, tree);
1192 * xsltParseGlobalVariable:
1193 * @style: the XSLT stylesheet
1194 * @cur: the "variable" element
1196 * parse an XSLT transformation variable declaration and record
1201 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
1202 xsltStylePreCompPtr comp;
1204 if ((cur == NULL) || (style == NULL))
1207 xsltStylePreCompute(style, cur);
1208 comp = (xsltStylePreCompPtr) cur->_private;
1210 xsltPrintErrorContext(NULL, style, cur);
1211 xsltGenericError(xsltGenericErrorContext,
1212 "xsl:variable : compilation failed\n");
1216 if (comp->name == NULL) {
1217 xsltPrintErrorContext(NULL, style, cur);
1218 xsltGenericError(xsltGenericErrorContext,
1219 "xsl:variable : missing name attribute\n");
1223 #ifdef WITH_XSLT_DEBUG_VARIABLE
1224 xsltGenericDebug(xsltGenericDebugContext,
1225 "Registering global variable %s\n", comp->name);
1228 xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1229 cur->children, comp, NULL);
1233 * xsltParseGlobalParam:
1234 * @style: the XSLT stylesheet
1235 * @cur: the "param" element
1237 * parse an XSLT transformation param declaration and record
1242 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
1243 xsltStylePreCompPtr comp;
1245 if ((cur == NULL) || (style == NULL))
1248 xsltStylePreCompute(style, cur);
1249 comp = (xsltStylePreCompPtr) cur->_private;
1251 xsltPrintErrorContext(NULL, style, cur);
1252 xsltGenericError(xsltGenericErrorContext,
1253 "xsl:param : compilation failed\n");
1257 if (comp->name == NULL) {
1258 xsltPrintErrorContext(NULL, style, cur);
1259 xsltGenericError(xsltGenericErrorContext,
1260 "xsl:param : missing name attribute\n");
1264 #ifdef WITH_XSLT_DEBUG_VARIABLE
1265 xsltGenericDebug(xsltGenericDebugContext,
1266 "Registering global param %s\n", comp->name);
1269 xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1270 cur->children, comp, NULL);
1274 * xsltParseStylesheetVariable:
1275 * @ctxt: the XSLT transformation context
1276 * @cur: the "variable" element
1278 * parse an XSLT transformation variable declaration and record
1283 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1284 xsltStylePreCompPtr comp;
1286 if ((cur == NULL) || (ctxt == NULL))
1289 comp = (xsltStylePreCompPtr) cur->_private;
1291 xsltPrintErrorContext(ctxt, NULL, cur);
1292 xsltGenericError(xsltGenericErrorContext,
1293 "xsl:variable : compilation failed\n");
1297 if (comp->name == NULL) {
1298 xsltPrintErrorContext(ctxt, NULL, cur);
1299 xsltGenericError(xsltGenericErrorContext,
1300 "xsl:variable : missing name attribute\n");
1304 #ifdef WITH_XSLT_DEBUG_VARIABLE
1305 xsltGenericDebug(xsltGenericDebugContext,
1306 "Registering variable %s\n", comp->name);
1309 xsltRegisterVariable(ctxt, comp, cur->children, 0);
1313 * xsltParseStylesheetParam:
1314 * @ctxt: the XSLT transformation context
1315 * @cur: the "param" element
1317 * parse an XSLT transformation param declaration and record
1322 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1323 xsltStylePreCompPtr comp;
1325 if ((cur == NULL) || (ctxt == NULL))
1328 comp = (xsltStylePreCompPtr) cur->_private;
1330 xsltPrintErrorContext(ctxt, NULL, cur);
1331 xsltGenericError(xsltGenericErrorContext,
1332 "xsl:param : compilation failed\n");
1336 if (comp->name == NULL) {
1337 xsltPrintErrorContext(ctxt, NULL, cur);
1338 xsltGenericError(xsltGenericErrorContext,
1339 "xsl:param : missing name attribute\n");
1343 #ifdef WITH_XSLT_DEBUG_VARIABLE
1344 xsltGenericDebug(xsltGenericDebugContext,
1345 "Registering param %s\n", comp->name);
1348 xsltRegisterVariable(ctxt, comp, cur->children, 1);
1352 * xsltFreeGlobalVariables:
1353 * @ctxt: the XSLT transformation context
1355 * Free up the data associated to the global variables
1360 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
1361 xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
1365 * xsltXPathVariableLookup:
1366 * @ctxt: a void * but the the XSLT transformation context actually
1367 * @name: the variable name
1368 * @ns_uri: the variable namespace URI
1370 * This is the entry point when a varibale is needed by the XPath
1373 * Returns the value or NULL if not found
1376 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
1377 const xmlChar *ns_uri) {
1378 xsltTransformContextPtr context;
1379 xmlXPathObjectPtr ret;
1381 if ((ctxt == NULL) || (name == NULL))
1384 #ifdef WITH_XSLT_DEBUG_VARIABLE
1385 xsltGenericDebug(xsltGenericDebugContext,
1386 "Lookup variable %s\n", name);
1388 context = (xsltTransformContextPtr) ctxt;
1389 ret = xsltVariableLookup(context, name, ns_uri);
1391 xsltPrintErrorContext(ctxt, NULL, NULL);
1392 xsltGenericError(xsltGenericErrorContext,
1393 "unregistered variable %s\n", name);
1395 #ifdef WITH_XSLT_DEBUG_VARIABLE
1397 xsltGenericDebug(xsltGenericDebugContext,
1398 "found variable %s\n", name);