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.
17 #include <libxml/xmlmemory.h>
18 #include <libxml/tree.h>
19 #include <libxml/valid.h>
20 #include <libxml/hash.h>
21 #include <libxml/xmlerror.h>
22 #include <libxml/xpath.h>
23 #include <libxml/xpathInternals.h>
24 #include <libxml/parserInternals.h>
26 #include "xsltInternals.h"
27 #include "xsltutils.h"
28 #include "variables.h"
29 #include "transform.h"
34 #ifdef WITH_XSLT_DEBUG
35 #define WITH_XSLT_DEBUG_VARIABLE
38 /************************************************************************
40 * Result Value Tree interfaces *
42 ************************************************************************/
45 * @ctxt: an XSLT transformation context
47 * Create a result value tree
49 * Returns the result value tree or NULL in case of error
52 xsltCreateRVT(xsltTransformContextPtr ctxt)
56 if (ctxt == NULL) return(NULL);
58 container = xmlNewDoc(NULL);
59 if (container == NULL)
61 container->dict = ctxt->dict;
62 xmlDictReference(container->dict);
63 #ifdef WITH_XSLT_DEBUG
64 xsltGenericDebug(xsltGenericDebugContext,
65 "reusing transformation dict for RVT\n");
68 container->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");
69 container->doc = container;
70 container->parent = NULL;
76 * @ctxt: an XSLT transformation context
77 * @RVT: a result value tree
79 * Register the result value tree for destruction at the end of the context
81 * Returns 0 in case of success and -1 in case of error.
84 xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
86 if ((ctxt == NULL) || (RVT == NULL)) return(-1);
88 RVT->next = (xmlNodePtr) ctxt->tmpRVT;
89 if (ctxt->tmpRVT != NULL)
90 ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
96 * xsltRegisterPersistRVT:
97 * @ctxt: an XSLT transformation context
98 * @RVT: a result value tree
100 * Register the result value tree for destruction at the end of the processing
102 * Returns 0 in case of success and -1 in case of error.
105 xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
107 if ((ctxt == NULL) || (RVT == NULL)) return(-1);
109 RVT->next = (xmlNodePtr) ctxt->persistRVT;
110 if (ctxt->persistRVT != NULL)
111 ctxt->persistRVT->prev = (xmlNodePtr) RVT;
112 ctxt->persistRVT = RVT;
118 * @ctxt: an XSLT transformation context
120 * Free all the registered result value tree of the transformation
123 xsltFreeRVTs(xsltTransformContextPtr ctxt)
127 if (ctxt == NULL) return;
130 while (cur != NULL) {
131 next = (xmlDocPtr) cur->next;
132 if (cur->_private != NULL) {
133 xsltFreeDocumentKeys(cur->_private);
134 xmlFree(cur->_private);
139 cur = ctxt->persistRVT;
140 while (cur != NULL) {
141 next = (xmlDocPtr) cur->next;
142 if (cur->_private != NULL) {
143 xsltFreeDocumentKeys(cur->_private);
144 xmlFree(cur->_private);
151 /************************************************************************
153 * Module interfaces *
155 ************************************************************************/
160 * Create a new XSLT ParserContext
162 * Returns the newly allocated xsltParserStackElem or NULL in case of error
164 static xsltStackElemPtr
165 xsltNewStackElem(void) {
166 xsltStackElemPtr cur;
168 cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
170 xsltTransformError(NULL, NULL, NULL,
171 "xsltNewStackElem : malloc failed\n");
186 * @elem: an XSLT stack element
188 * Makes a copy of the stack element
190 * Returns the copy of NULL
192 static xsltStackElemPtr
193 xsltCopyStackElem(xsltStackElemPtr elem) {
194 xsltStackElemPtr cur;
196 cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
198 xsltTransformError(NULL, NULL, NULL,
199 "xsltCopyStackElem : malloc failed\n");
202 cur->name = elem->name;
203 cur->nameURI = elem->nameURI;
204 cur->select = elem->select;
205 cur->tree = elem->tree;
206 cur->comp = elem->comp;
214 * @elem: an XSLT stack element
216 * Free up the memory allocated by @elem
219 xsltFreeStackElem(xsltStackElemPtr elem) {
222 if (elem->value != NULL)
223 xmlXPathFreeObject(elem->value);
229 * xsltFreeStackElemList:
230 * @elem: an XSLT stack element
232 * Free up the memory allocated by @elem
235 xsltFreeStackElemList(xsltStackElemPtr elem) {
236 xsltStackElemPtr next;
238 while(elem != NULL) {
240 xsltFreeStackElem(elem);
247 * @ctxt: an XSLT transformation context
248 * @name: the local part of the name
249 * @nameURI: the URI part of the name
251 * Locate an element in the stack based on its name.
253 static xsltStackElemPtr
254 xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
255 const xmlChar *nameURI) {
257 xsltStackElemPtr cur;
259 if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
263 * Do the lookup from the top of the stack, but
264 * don't use params being computed in a call-param
265 * First lookup expects the variable name and URI to
266 * come from the disctionnary and hence get equality
268 for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
269 cur = ctxt->varsTab[i-1];
270 while (cur != NULL) {
271 if (cur->name == name) {
272 if (nameURI == NULL) {
273 if (cur->nameURI == NULL) {
277 if ((cur->nameURI != NULL) &&
278 (cur->nameURI == nameURI)) {
289 if ((xmlDictOwns(ctxt->dict, name) <= 0) ||
290 ((nameURI != NULL) && (xmlDictOwns(ctxt->dict, nameURI) <= 0))) {
292 * Redo the lookup with string compares
294 for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
295 cur = ctxt->varsTab[i-1];
296 while (cur != NULL) {
297 if (xmlStrEqual(cur->name, name)) {
298 if (nameURI == NULL) {
299 if (cur->nameURI == NULL) {
303 if ((cur->nameURI != NULL) &&
304 (xmlStrEqual(cur->nameURI, nameURI))) {
316 * Redo the lookup with string compares
318 for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
319 cur = ctxt->varsTab[i-1];
320 while (cur != NULL) {
321 if (xmlStrEqual(cur->name, name)) {
322 if (nameURI == NULL) {
323 if (cur->nameURI == NULL) {
327 if ((cur->nameURI != NULL) &&
328 (xmlStrEqual(cur->nameURI, nameURI))) {
342 * xsltCheckStackElem:
343 * @ctxt: xn XSLT transformation context
344 * @name: the variable name
345 * @nameURI: the variable namespace URI
347 * check wether the variable or param is already defined
349 * Returns 1 if variable is present, 2 if param is present, 3 if this
350 * is an inherited param, 0 if not found, -1 in case of failure.
353 xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
354 const xmlChar *nameURI) {
355 xsltStackElemPtr cur;
357 if ((ctxt == NULL) || (name == NULL))
360 cur = xsltStackLookup(ctxt, name, nameURI);
363 if (cur->comp != NULL) {
364 if (cur->comp->type == XSLT_FUNC_WITHPARAM)
366 else if (cur->comp->type == XSLT_FUNC_PARAM)
375 * @ctxt: xn XSLT transformation context
376 * @elem: a stack element
378 * add a new element at this level of the stack.
380 * Returns 0 in case of success, -1 in case of failure.
383 xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
384 if ((ctxt == NULL) || (elem == NULL))
387 elem->next = ctxt->varsTab[ctxt->varsNr - 1];
388 ctxt->varsTab[ctxt->varsNr - 1] = elem;
394 * xsltAddStackElemList:
395 * @ctxt: xn XSLT transformation context
396 * @elems: a stack element list
398 * add the new element list at this level of the stack.
400 * Returns 0 in case of success, -1 in case of failure.
403 xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) {
404 xsltStackElemPtr cur;
406 if ((ctxt == NULL) || (elems == NULL))
409 /* TODO: check doublons */
410 if (ctxt->varsTab[ctxt->varsNr - 1] != NULL) {
411 cur = ctxt->varsTab[ctxt->varsNr - 1];
412 while (cur->next != NULL)
416 elems->next = ctxt->varsTab[ctxt->varsNr - 1];
417 ctxt->varsTab[ctxt->varsNr - 1] = elems;
423 /************************************************************************
425 * Module interfaces *
427 ************************************************************************/
431 * @ctxt: the XSLT transformation context
432 * @elem: the variable or parameter.
433 * @precomp: pointer to precompiled data
435 * Evaluate a variable value.
437 * Returns the XPath Object value or NULL in case of error
439 static xmlXPathObjectPtr
440 xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
441 xsltStylePreCompPtr precomp) {
442 xmlXPathObjectPtr result = NULL;
443 int oldProximityPosition, oldContextSize;
444 xmlNodePtr oldInst, oldNode;
445 xsltDocumentPtr oldDoc;
447 xmlNsPtr *oldNamespaces;
449 if ((ctxt == NULL) || (elem == NULL))
452 #ifdef WITH_XSLT_DEBUG_VARIABLE
453 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
454 "Evaluating variable %s\n", elem->name));
456 if (elem->select != NULL) {
457 xmlXPathCompExprPtr comp = NULL;
459 if ((precomp != NULL) && (precomp->comp != NULL)) {
460 comp = precomp->comp;
462 comp = xmlXPathCompile(elem->select);
466 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
467 oldContextSize = ctxt->xpathCtxt->contextSize;
468 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
469 oldDoc = ctxt->document;
470 oldNode = ctxt->node;
471 oldInst = ctxt->inst;
472 oldNsNr = ctxt->xpathCtxt->nsNr;
473 oldNamespaces = ctxt->xpathCtxt->namespaces;
474 if (precomp != NULL) {
475 ctxt->inst = precomp->inst;
476 ctxt->xpathCtxt->namespaces = precomp->nsList;
477 ctxt->xpathCtxt->nsNr = precomp->nsNr;
480 ctxt->xpathCtxt->namespaces = NULL;
481 ctxt->xpathCtxt->nsNr = 0;
483 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
484 ctxt->xpathCtxt->contextSize = oldContextSize;
485 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
486 ctxt->xpathCtxt->nsNr = oldNsNr;
487 ctxt->xpathCtxt->namespaces = oldNamespaces;
488 ctxt->inst = oldInst;
489 ctxt->node = oldNode;
490 ctxt->document = oldDoc;
491 if ((precomp == NULL) || (precomp->comp == NULL))
492 xmlXPathFreeCompExpr(comp);
493 if (result == NULL) {
494 xsltTransformError(ctxt, NULL, precomp->inst,
495 "Evaluating variable %s failed\n", elem->name);
496 ctxt->state = XSLT_STATE_STOPPED;
497 #ifdef WITH_XSLT_DEBUG_VARIABLE
498 #ifdef LIBXML_DEBUG_ENABLED
500 if ((xsltGenericDebugContext == stdout) ||
501 (xsltGenericDebugContext == stderr))
502 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
508 if (elem->tree == NULL) {
509 result = xmlXPathNewCString("");
512 * This is a result tree fragment.
515 xmlNodePtr oldInsert;
518 container = xsltCreateRVT(ctxt);
519 if (container == NULL)
522 * Tag the subtree for removal once consumed
524 xsltRegisterTmpRVT(ctxt, container);
525 oldoutput = ctxt->output;
526 ctxt->output = container;
527 oldInsert = ctxt->insert;
528 ctxt->insert = (xmlNodePtr) container;
529 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
530 ctxt->insert = oldInsert;
531 ctxt->output = oldoutput;
533 result = xmlXPathNewValueTree((xmlNodePtr) container);
534 if (result == NULL) {
535 result = xmlXPathNewCString("");
537 result->boolval = 0; /* Freeing is not handled there anymore */
539 #ifdef WITH_XSLT_DEBUG_VARIABLE
540 #ifdef LIBXML_DEBUG_ENABLED
541 if ((xsltGenericDebugContext == stdout) ||
542 (xsltGenericDebugContext == stderr))
543 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
553 * xsltEvalGlobalVariable:
554 * @elem: the variable or parameter.
555 * @ctxt: the XSLT transformation context
557 * Evaluate a global variable value.
559 * Returns the XPath Object value or NULL in case of error
561 static xmlXPathObjectPtr
562 xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
563 xmlXPathObjectPtr result = NULL;
564 xsltStylePreCompPtr precomp;
565 int oldProximityPosition, oldContextSize;
569 xmlNsPtr *oldNamespaces;
572 if ((ctxt == NULL) || (elem == NULL))
578 #ifdef WITH_XSLT_DEBUG_VARIABLE
579 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
580 "Evaluating global variable %s\n", elem->name));
584 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) &&
585 elem->comp && elem->comp->inst)
586 xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
590 elem->name = BAD_CAST " being computed ... ";
592 precomp = elem->comp;
593 if (elem->select != NULL) {
594 xmlXPathCompExprPtr comp = NULL;
596 if ((precomp != NULL) && (precomp->comp != NULL)) {
597 comp = precomp->comp;
599 comp = xmlXPathCompile(elem->select);
605 oldDoc = ctxt->xpathCtxt->doc;
606 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
607 oldContextSize = ctxt->xpathCtxt->contextSize;
608 oldInst = ctxt->inst;
609 oldNsNr = ctxt->xpathCtxt->nsNr;
610 oldNamespaces = ctxt->xpathCtxt->namespaces;
612 if (precomp != NULL) {
613 ctxt->inst = precomp->inst;
614 ctxt->xpathCtxt->namespaces = precomp->nsList;
615 ctxt->xpathCtxt->nsNr = precomp->nsNr;
618 ctxt->xpathCtxt->namespaces = NULL;
619 ctxt->xpathCtxt->nsNr = 0;
621 ctxt->xpathCtxt->doc = ctxt->tmpDoc;
622 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->tmpDoc;
623 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
625 ctxt->xpathCtxt->doc = oldDoc;
626 ctxt->xpathCtxt->contextSize = oldContextSize;
627 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
628 ctxt->inst = oldInst;
629 ctxt->xpathCtxt->nsNr = oldNsNr;
630 ctxt->xpathCtxt->namespaces = oldNamespaces;
631 if ((precomp == NULL) || (precomp->comp == NULL))
632 xmlXPathFreeCompExpr(comp);
633 if (result == NULL) {
634 xsltTransformError(ctxt, NULL, precomp->inst,
635 "Evaluating global variable %s failed\n", elem->name);
636 ctxt->state = XSLT_STATE_STOPPED;
637 #ifdef WITH_XSLT_DEBUG_VARIABLE
638 #ifdef LIBXML_DEBUG_ENABLED
640 if ((xsltGenericDebugContext == stdout) ||
641 (xsltGenericDebugContext == stderr))
642 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
648 if (elem->tree == NULL) {
649 result = xmlXPathNewCString("");
652 * This is a result tree fragment.
655 xmlNodePtr oldInsert;
658 container = xsltCreateRVT(ctxt);
659 if (container == NULL)
662 * Tag the subtree for removal once consumed
664 xsltRegisterTmpRVT(ctxt, container);
666 * Save a pointer to the global variable for later cleanup
668 container->psvi = elem;
669 oldoutput = ctxt->output;
670 ctxt->output = container;
671 oldInsert = ctxt->insert;
672 ctxt->insert = (xmlNodePtr) container;
673 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
674 ctxt->insert = oldInsert;
675 ctxt->output = oldoutput;
677 result = xmlXPathNewValueTree((xmlNodePtr) container);
678 if (result == NULL) {
679 result = xmlXPathNewCString("");
681 result->boolval = 0; /* Freeing is not handled there anymore */
683 #ifdef WITH_XSLT_DEBUG_VARIABLE
684 #ifdef LIBXML_DEBUG_ENABLED
685 if ((xsltGenericDebugContext == stdout) ||
686 (xsltGenericDebugContext == stderr))
687 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
693 if (result != NULL) {
694 elem->value = result;
702 * xsltEvalGlobalVariables:
703 * @ctxt: the XSLT transformation context
705 * Evaluate the global variables of a stylesheet. This need to be
706 * done on parsed stylesheets before starting to apply transformations
708 * Returns 0 in case of success, -1 in case of error
711 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
712 xsltStackElemPtr elem;
713 xsltStylesheetPtr style;
715 if ((ctxt == NULL) || (ctxt->document == NULL))
718 #ifdef WITH_XSLT_DEBUG_VARIABLE
719 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
720 "Registering global variables\n"));
723 ctxt->tmpDoc = ctxt->document->doc;
724 ctxt->node = (xmlNodePtr) ctxt->document->doc;
725 ctxt->xpathCtxt->contextSize = 1;
726 ctxt->xpathCtxt->proximityPosition = 1;
729 * Walk the list from the stylesheets and populate the hash table
732 while (style != NULL) {
733 elem = style->variables;
735 #ifdef WITH_XSLT_DEBUG_VARIABLE
736 if ((style->doc != NULL) && (style->doc->URL != NULL)) {
737 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
738 "Registering global variables from %s\n",
743 while (elem != NULL) {
744 xsltStackElemPtr def;
747 * Global variables are stored in the variables pool.
749 def = (xsltStackElemPtr)
750 xmlHashLookup2(ctxt->globalVars,
751 elem->name, elem->nameURI);
754 def = xsltCopyStackElem(elem);
755 xmlHashAddEntry2(ctxt->globalVars,
756 elem->name, elem->nameURI, def);
757 } else if ((elem->comp != NULL) &&
758 (elem->comp->type == XSLT_FUNC_VARIABLE)) {
760 * Redefinition of variables from a different stylesheet
761 * should not generate a message.
763 if ((elem->comp->inst != NULL) &&
764 (def->comp != NULL) && (def->comp->inst != NULL) &&
765 (elem->comp->inst->doc == def->comp->inst->doc)) {
766 xsltTransformError(ctxt, style, elem->comp->inst,
767 "Global variable %s already defined\n", elem->name);
768 if (style != NULL) style->errors++;
774 style = xsltNextImport(style);
778 * This part does the actual evaluation
780 ctxt->node = (xmlNodePtr) ctxt->document->doc;
781 ctxt->xpathCtxt->contextSize = 1;
782 ctxt->xpathCtxt->proximityPosition = 1;
783 xmlHashScan(ctxt->globalVars,
784 (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
790 * xsltRegisterGlobalVariable:
791 * @style: the XSLT transformation context
792 * @name: the variable name
793 * @ns_uri: the variable namespace URI
794 * @sel: the expression which need to be evaluated to generate a value
795 * @tree: the subtree if sel is NULL
796 * @comp: the precompiled value
797 * @value: the string value if available
799 * Register a new variable value. If @value is NULL it unregisters
802 * Returns 0 in case of success, -1 in case of error
805 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
806 const xmlChar *ns_uri, const xmlChar *sel,
807 xmlNodePtr tree, xsltStylePreCompPtr comp,
808 const xmlChar *value) {
809 xsltStackElemPtr elem, tmp;
817 #ifdef WITH_XSLT_DEBUG_VARIABLE
818 if (comp->type == XSLT_FUNC_PARAM)
819 xsltGenericDebug(xsltGenericDebugContext,
820 "Defining global param %s\n", name);
822 xsltGenericDebug(xsltGenericDebugContext,
823 "Defining global variable %s\n", name);
826 elem = xsltNewStackElem();
830 elem->name = xmlDictLookup(style->dict, name, -1);
831 elem->select = xmlDictLookup(style->dict, sel, -1);
833 elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1);
835 tmp = style->variables;
838 style->variables = elem;
840 while (tmp != NULL) {
841 if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
842 (tmp->comp->type == XSLT_FUNC_VARIABLE) &&
843 (xmlStrEqual(elem->name, tmp->name)) &&
844 ((elem->nameURI == tmp->nameURI) ||
845 (xmlStrEqual(elem->nameURI, tmp->nameURI)))) {
846 xsltTransformError(NULL, style, comp->inst,
847 "redefinition of global variable %s\n", elem->name);
848 if (style != NULL) style->errors++;
850 if (tmp->next == NULL)
859 elem->value = xmlXPathNewString(value);
865 * xsltProcessUserParamInternal
867 * @ctxt: the XSLT transformation context
868 * @name: a null terminated parameter name
869 * @value: a null terminated value (may be an XPath expression)
870 * @eval: 0 to treat the value literally, else evaluate as XPath expression
872 * If @eval is 0 then @value is treated literally and is stored in the global
873 * parameter/variable table without any change.
875 * Uf @eval is 1 then @value is treated as an XPath expression and is
876 * evaluated. In this case, if you want to pass a string which will be
877 * interpreted literally then it must be enclosed in single or double quotes.
878 * If the string contains single quotes (double quotes) then it cannot be
879 * enclosed single quotes (double quotes). If the string which you want to
880 * be treated literally contains both single and double quotes (e.g. Meet
881 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
882 * quoting character. You cannot use ' or " inside the string
883 * because the replacement of character entities with their equivalents is
884 * done at a different stage of processing. The solution is to call
885 * xsltQuoteUserParams or xsltQuoteOneUserParam.
887 * This needs to be done on parsed stylesheets before starting to apply
888 * transformations. Normally this will be called (directly or indirectly)
889 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
890 * or xsltQuoteOneUserParam.
892 * Returns 0 in case of success, -1 in case of error
897 xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
898 const xmlChar * name,
899 const xmlChar * value,
902 xsltStylesheetPtr style;
903 const xmlChar *prefix;
905 xmlXPathCompExprPtr comp;
906 xmlXPathObjectPtr result;
907 int oldProximityPosition;
910 xmlNsPtr *oldNamespaces;
911 xsltStackElemPtr elem;
924 #ifdef WITH_XSLT_DEBUG_VARIABLE
925 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
926 "Evaluating user parameter %s=%s\n", name, value));
933 name = xsltSplitQName(ctxt->dict, name, &prefix);
935 if (prefix != NULL) {
938 ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
941 xsltTransformError(ctxt, style, NULL,
942 "user param : no namespace bound to prefix %s\n", prefix);
952 res_ptr = xmlHashLookup2(ctxt->globalVars, name, href);
954 xsltTransformError(ctxt, style, NULL,
955 "Global parameter %s already defined\n", name);
959 * do not overwrite variables with parameters from the command line
961 while (style != NULL) {
962 elem = ctxt->style->variables;
963 while (elem != NULL) {
964 if ((elem->comp != NULL) &&
965 (elem->comp->type == XSLT_FUNC_VARIABLE) &&
966 (xmlStrEqual(elem->name, name)) &&
967 (xmlStrEqual(elem->nameURI, href))) {
972 style = xsltNextImport(style);
978 * Do the evaluation if @eval is non-zero.
983 comp = xmlXPathCompile(value);
985 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
986 oldContextSize = ctxt->xpathCtxt->contextSize;
987 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
990 * There is really no in scope namespace for parameters on the
994 oldNsNr = ctxt->xpathCtxt->nsNr;
995 oldNamespaces = ctxt->xpathCtxt->namespaces;
996 ctxt->xpathCtxt->namespaces = NULL;
997 ctxt->xpathCtxt->nsNr = 0;
998 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
999 ctxt->xpathCtxt->contextSize = oldContextSize;
1000 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
1001 ctxt->xpathCtxt->nsNr = oldNsNr;
1002 ctxt->xpathCtxt->namespaces = oldNamespaces;
1003 xmlXPathFreeCompExpr(comp);
1005 if (result == NULL) {
1006 xsltTransformError(ctxt, style, NULL,
1007 "Evaluating user parameter %s failed\n", name);
1008 ctxt->state = XSLT_STATE_STOPPED;
1014 * If @eval is 0 then @value is to be taken literally and result is NULL
1016 * If @eval is not 0, then @value is an XPath expression and has been
1017 * successfully evaluated and result contains the resulting value and
1020 * Now create an xsltStackElemPtr for insertion into the context's
1021 * global variable/parameter hash table.
1024 #ifdef WITH_XSLT_DEBUG_VARIABLE
1025 #ifdef LIBXML_DEBUG_ENABLED
1026 if ((xsltGenericDebugContext == stdout) ||
1027 (xsltGenericDebugContext == stderr))
1028 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1033 elem = xsltNewStackElem();
1037 elem->select = xmlDictLookup(ctxt->dict, value, -1);
1039 elem->select = NULL;
1041 elem->nameURI = xmlDictLookup(ctxt->dict, href, -1);
1045 elem->value = xmlXPathNewString(value);
1048 elem->value = result;
1053 * Global parameters are stored in the XPath context variables pool.
1056 res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem);
1058 xsltFreeStackElem(elem);
1059 xsltTransformError(ctxt, style, NULL,
1060 "Global parameter %s already defined\n", name);
1066 * xsltEvalUserParams:
1068 * @ctxt: the XSLT transformation context
1069 * @params: a NULL terminated array of parameters name/value tuples
1071 * Evaluate the global variables of a stylesheet. This needs to be
1072 * done on parsed stylesheets before starting to apply transformations.
1073 * Each of the parameters is evaluated as an XPath expression and stored
1074 * in the global variables/parameter hash table. If you want your
1075 * parameter used literally, use xsltQuoteUserParams.
1077 * Returns 0 in case of success, -1 in case of error
1081 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
1083 const xmlChar *name;
1084 const xmlChar *value;
1088 while (params[indx] != NULL) {
1089 name = (const xmlChar *) params[indx++];
1090 value = (const xmlChar *) params[indx++];
1091 if (xsltEvalOneUserParam(ctxt, name, value) != 0)
1098 * xsltQuoteUserParams:
1100 * @ctxt: the XSLT transformation context
1101 * @params: a NULL terminated arry of parameters names/values tuples
1103 * Similar to xsltEvalUserParams, but the values are treated literally and
1104 * are * *not* evaluated as XPath expressions. This should be done on parsed
1105 * stylesheets before starting to apply transformations.
1107 * Returns 0 in case of success, -1 in case of error.
1111 xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
1113 const xmlChar *name;
1114 const xmlChar *value;
1118 while (params[indx] != NULL) {
1119 name = (const xmlChar *) params[indx++];
1120 value = (const xmlChar *) params[indx++];
1121 if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
1128 * xsltEvalOneUserParam:
1129 * @ctxt: the XSLT transformation context
1130 * @name: a null terminated string giving the name of the parameter
1131 * @value: a null terminated string giving the XPath expression to be evaluated
1133 * This is normally called from xsltEvalUserParams to process a single
1134 * parameter from a list of parameters. The @value is evaluated as an
1135 * XPath expression and the result is stored in the context's global
1136 * variable/parameter hash table.
1138 * To have a parameter treated literally (not as an XPath expression)
1139 * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
1140 * details see description of xsltProcessOneUserParamInternal.
1142 * Returns 0 in case of success, -1 in case of error.
1146 xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
1147 const xmlChar * name,
1148 const xmlChar * value) {
1149 return xsltProcessUserParamInternal(ctxt, name, value,
1150 1 /* xpath eval ? */);
1154 * xsltQuoteOneUserParam:
1155 * @ctxt: the XSLT transformation context
1156 * @name: a null terminated string giving the name of the parameter
1157 * @value: a null terminated string giving the parameter value
1159 * This is normally called from xsltQuoteUserParams to process a single
1160 * parameter from a list of parameters. The @value is stored in the
1161 * context's global variable/parameter hash table.
1163 * Returns 0 in case of success, -1 in case of error.
1167 xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
1168 const xmlChar * name,
1169 const xmlChar * value) {
1170 return xsltProcessUserParamInternal(ctxt, name, value,
1171 0 /* xpath eval ? */);
1175 * xsltBuildVariable:
1176 * @ctxt: the XSLT transformation context
1177 * @comp: the precompiled form
1178 * @tree: the tree if select is NULL
1180 * Computes a new variable value.
1182 * Returns the xsltStackElemPtr or NULL in case of error
1184 static xsltStackElemPtr
1185 xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1187 xsltStackElemPtr elem;
1189 #ifdef WITH_XSLT_DEBUG_VARIABLE
1190 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1191 "Building variable %s", comp->name));
1192 if (comp->select != NULL)
1193 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1194 " select %s", comp->select));
1195 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n"));
1198 elem = xsltNewStackElem();
1202 elem->name = comp->name;
1203 if (comp->select != NULL)
1204 elem->select = comp->select;
1206 elem->select = NULL;
1208 elem->nameURI = comp->ns;
1210 if (elem->computed == 0) {
1211 elem->value = xsltEvalVariable(ctxt, elem, comp);
1212 if (elem->value != NULL)
1219 * xsltRegisterVariable:
1220 * @ctxt: the XSLT transformation context
1221 * @comp: pointer to precompiled data
1222 * @tree: the tree if select is NULL
1223 * @param: this is a parameter actually
1225 * Computes and register a new variable value.
1227 * Returns 0 in case of success, -1 in case of error
1230 xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1231 xmlNodePtr tree, int param) {
1232 xsltStackElemPtr elem;
1235 present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
1237 if ((present != 0) && (present != 3)) {
1238 xsltTransformError(ctxt, NULL, comp->inst,
1239 "xsl:variable : redefining %s\n", comp->name);
1242 } else if (present != 0) {
1243 if ((present == 1) || (present == 2)) {
1244 xsltTransformError(ctxt, NULL, comp->inst,
1245 "xsl:param : redefining %s\n", comp->name);
1248 #ifdef WITH_XSLT_DEBUG_VARIABLE
1249 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1250 "param %s defined by caller\n", comp->name));
1254 elem = xsltBuildVariable(ctxt, comp, tree);
1255 xsltAddStackElem(ctxt, elem);
1260 * xsltGlobalVariableLookup:
1261 * @ctxt: the XSLT transformation context
1262 * @name: the variable name
1263 * @ns_uri: the variable namespace URI
1265 * Search in the Variable array of the context for the given
1268 * Returns the value or NULL if not found
1270 static xmlXPathObjectPtr
1271 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1272 const xmlChar *ns_uri) {
1273 xsltStackElemPtr elem;
1274 xmlXPathObjectPtr ret = NULL;
1277 * Lookup the global variables in XPath global variable hash table
1279 if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
1281 elem = (xsltStackElemPtr)
1282 xmlHashLookup2(ctxt->globalVars, name, ns_uri);
1284 #ifdef WITH_XSLT_DEBUG_VARIABLE
1285 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1286 "global variable not found %s\n", name));
1290 if (elem->computed == 0) {
1291 if (xmlStrEqual(elem->name, BAD_CAST " being computed ... ")) {
1292 xsltTransformError(ctxt, NULL, elem->comp->inst,
1293 "Recursive definition of %s\n", name);
1296 ret = xsltEvalGlobalVariable(elem, ctxt);
1299 return(xmlXPathObjectCopy(ret));
1303 * xsltVariableLookup:
1304 * @ctxt: the XSLT transformation context
1305 * @name: the variable name
1306 * @ns_uri: the variable namespace URI
1308 * Search in the Variable array of the context for the given
1311 * Returns the value or NULL if not found
1314 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1315 const xmlChar *ns_uri) {
1316 xsltStackElemPtr elem;
1321 elem = xsltStackLookup(ctxt, name, ns_uri);
1323 return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
1325 if (elem->computed == 0) {
1326 #ifdef WITH_XSLT_DEBUG_VARIABLE
1327 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1328 "uncomputed variable %s\n", name));
1330 elem->value = xsltEvalVariable(ctxt, elem, NULL);
1333 if (elem->value != NULL)
1334 return(xmlXPathObjectCopy(elem->value));
1335 #ifdef WITH_XSLT_DEBUG_VARIABLE
1336 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1337 "variable not found %s\n", name));
1343 * xsltParseStylesheetCallerParam:
1344 * @ctxt: the XSLT transformation context
1345 * @cur: the "param" element
1347 * parse an XSLT transformation param declaration, compute
1348 * its value but doesn't record it.
1350 * Returns the new xsltStackElemPtr or NULL
1354 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1355 xmlNodePtr tree = NULL;
1356 xsltStackElemPtr elem = NULL;
1357 xsltStylePreCompPtr comp;
1359 if ((cur == NULL) || (ctxt == NULL))
1361 comp = (xsltStylePreCompPtr) cur->psvi;
1363 xsltTransformError(ctxt, NULL, cur,
1364 "xsl:param : compilation error\n");
1368 if (comp->name == NULL) {
1369 xsltTransformError(ctxt, NULL, cur,
1370 "xsl:param : missing name attribute\n");
1374 #ifdef WITH_XSLT_DEBUG_VARIABLE
1375 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1376 "Handling param %s\n", comp->name));
1379 if (comp->select == NULL) {
1380 tree = cur->children;
1382 #ifdef WITH_XSLT_DEBUG_VARIABLE
1383 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1384 " select %s\n", comp->select));
1389 elem = xsltBuildVariable(ctxt, comp, tree);
1395 * xsltParseGlobalVariable:
1396 * @style: the XSLT stylesheet
1397 * @cur: the "variable" element
1399 * parse an XSLT transformation variable declaration and record
1404 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
1405 xsltStylePreCompPtr comp;
1407 if ((cur == NULL) || (style == NULL))
1410 xsltStylePreCompute(style, cur);
1411 comp = (xsltStylePreCompPtr) cur->psvi;
1413 xsltTransformError(NULL, style, cur,
1414 "xsl:variable : compilation failed\n");
1418 if (comp->name == NULL) {
1419 xsltTransformError(NULL, style, cur,
1420 "xsl:variable : missing name attribute\n");
1424 if (cur->children != NULL) {
1425 xsltParseTemplateContent(style, cur);
1427 #ifdef WITH_XSLT_DEBUG_VARIABLE
1428 xsltGenericDebug(xsltGenericDebugContext,
1429 "Registering global variable %s\n", comp->name);
1432 xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1433 cur->children, comp, NULL);
1437 * xsltParseGlobalParam:
1438 * @style: the XSLT stylesheet
1439 * @cur: the "param" element
1441 * parse an XSLT transformation param declaration and record
1446 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
1447 xsltStylePreCompPtr comp;
1449 if ((cur == NULL) || (style == NULL))
1452 xsltStylePreCompute(style, cur);
1453 comp = (xsltStylePreCompPtr) cur->psvi;
1455 xsltTransformError(NULL, style, cur,
1456 "xsl:param : compilation failed\n");
1460 if (comp->name == NULL) {
1461 xsltTransformError(NULL, style, cur,
1462 "xsl:param : missing name attribute\n");
1466 if (cur->children != NULL) {
1467 xsltParseTemplateContent(style, cur);
1470 #ifdef WITH_XSLT_DEBUG_VARIABLE
1471 xsltGenericDebug(xsltGenericDebugContext,
1472 "Registering global param %s\n", comp->name);
1475 xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1476 cur->children, comp, NULL);
1480 * xsltParseStylesheetVariable:
1481 * @ctxt: the XSLT transformation context
1482 * @cur: the "variable" element
1484 * parse an XSLT transformation variable declaration and record
1489 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1490 xsltStylePreCompPtr comp;
1492 if ((cur == NULL) || (ctxt == NULL))
1495 comp = (xsltStylePreCompPtr) cur->psvi;
1497 xsltTransformError(ctxt, NULL, cur,
1498 "xsl:variable : compilation failed\n");
1502 if (comp->name == NULL) {
1503 xsltTransformError(ctxt, NULL, cur,
1504 "xsl:variable : missing name attribute\n");
1508 #ifdef WITH_XSLT_DEBUG_VARIABLE
1509 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1510 "Registering variable %s\n", comp->name));
1513 xsltRegisterVariable(ctxt, comp, cur->children, 0);
1517 * xsltParseStylesheetParam:
1518 * @ctxt: the XSLT transformation context
1519 * @cur: the "param" element
1521 * parse an XSLT transformation param declaration and record
1526 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1527 xsltStylePreCompPtr comp;
1529 if ((cur == NULL) || (ctxt == NULL))
1532 comp = (xsltStylePreCompPtr) cur->psvi;
1534 xsltTransformError(ctxt, NULL, cur,
1535 "xsl:param : compilation failed\n");
1539 if (comp->name == NULL) {
1540 xsltTransformError(ctxt, NULL, cur,
1541 "xsl:param : missing name attribute\n");
1545 #ifdef WITH_XSLT_DEBUG_VARIABLE
1546 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1547 "Registering param %s\n", comp->name));
1550 xsltRegisterVariable(ctxt, comp, cur->children, 1);
1554 * xsltFreeGlobalVariables:
1555 * @ctxt: the XSLT transformation context
1557 * Free up the data associated to the global variables
1562 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
1563 xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
1567 * xsltXPathVariableLookup:
1568 * @ctxt: a void * but the the XSLT transformation context actually
1569 * @name: the variable name
1570 * @ns_uri: the variable namespace URI
1572 * This is the entry point when a varibale is needed by the XPath
1575 * Returns the value or NULL if not found
1578 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
1579 const xmlChar *ns_uri) {
1580 xsltTransformContextPtr context;
1581 xmlXPathObjectPtr ret;
1583 if ((ctxt == NULL) || (name == NULL))
1586 #ifdef WITH_XSLT_DEBUG_VARIABLE
1587 XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1588 "Lookup variable %s\n", name));
1590 context = (xsltTransformContextPtr) ctxt;
1591 ret = xsltVariableLookup(context, name, ns_uri);
1593 xsltTransformError(ctxt, NULL, NULL,
1594 "unregistered variable %s\n", name);
1596 #ifdef WITH_XSLT_DEBUG_VARIABLE
1598 XSLT_TRACE(context,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1599 "found variable %s\n", name));