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"
33 #ifdef WITH_XSLT_DEBUG
34 #define WITH_XSLT_DEBUG_VARIABLE
37 /************************************************************************
39 * Result Value Tree interfaces *
41 ************************************************************************/
44 * @ctxt: an XSLT transformation context
46 * Create a result value tree
48 * Returns the result value tree or NULL in case of error
51 xsltCreateRVT(xsltTransformContextPtr ctxt)
55 if (ctxt == NULL) return(NULL);
57 container = xmlNewDoc(NULL);
58 if (container == NULL)
61 container->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");
62 container->doc = container;
63 container->parent = NULL;
69 * @ctxt: an XSLT transformation context
70 * @RVT: a result value tree
72 * Register the result value tree for destruction at the end of the context
74 * Returns 0 in case of success and -1 in case of error.
77 xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
79 if ((ctxt == NULL) || (RVT == NULL)) return(-1);
81 RVT->next = (xmlNodePtr) ctxt->tmpRVT;
82 if (ctxt->tmpRVT != NULL)
83 ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
89 * xsltRegisterPersistRVT:
90 * @ctxt: an XSLT transformation context
91 * @RVT: a result value tree
93 * Register the result value tree for destruction at the end of the processing
95 * Returns 0 in case of success and -1 in case of error.
98 xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
100 if ((ctxt == NULL) || (RVT == NULL)) return(-1);
102 RVT->next = (xmlNodePtr) ctxt->persistRVT;
103 if (ctxt->persistRVT != NULL)
104 ctxt->persistRVT->prev = (xmlNodePtr) RVT;
105 ctxt->persistRVT = RVT;
111 * @ctxt: an XSLT transformation context
113 * Free all the registered result value tree of the transformation
116 xsltFreeRVTs(xsltTransformContextPtr ctxt)
120 if (ctxt == NULL) return;
123 while (cur != NULL) {
124 next = (xmlDocPtr) cur->next;
128 cur = ctxt->persistRVT;
129 while (cur != NULL) {
130 next = (xmlDocPtr) cur->next;
136 /************************************************************************
138 * Module interfaces *
140 ************************************************************************/
145 * Create a new XSLT ParserContext
147 * Returns the newly allocated xsltParserStackElem or NULL in case of error
149 static xsltStackElemPtr
150 xsltNewStackElem(void) {
151 xsltStackElemPtr cur;
153 cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
155 xsltTransformError(NULL, NULL, NULL,
156 "xsltNewStackElem : malloc failed\n");
171 * @elem: an XSLT stack element
173 * Makes a copy of the stack element
175 * Returns the copy of NULL
177 static xsltStackElemPtr
178 xsltCopyStackElem(xsltStackElemPtr elem) {
179 xsltStackElemPtr cur;
181 cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
183 xsltTransformError(NULL, NULL, NULL,
184 "xsltCopyStackElem : malloc failed\n");
187 cur->name = xmlStrdup(elem->name);
188 cur->nameURI = xmlStrdup(elem->nameURI);
189 cur->select = xmlStrdup(elem->select);
190 cur->tree = elem->tree;
191 cur->comp = elem->comp;
199 * @elem: an XSLT stack element
201 * Free up the memory allocated by @elem
204 xsltFreeStackElem(xsltStackElemPtr elem) {
207 if (elem->name != NULL)
209 if (elem->nameURI != NULL)
210 xmlFree(elem->nameURI);
211 if (elem->select != NULL)
212 xmlFree(elem->select);
213 if (elem->value != NULL)
214 xmlXPathFreeObject(elem->value);
220 * xsltFreeStackElemList:
221 * @elem: an XSLT stack element
223 * Free up the memory allocated by @elem
226 xsltFreeStackElemList(xsltStackElemPtr elem) {
227 xsltStackElemPtr next;
229 while(elem != NULL) {
231 xsltFreeStackElem(elem);
238 * @ctxt: an XSLT transformation context
239 * @name: the local part of the name
240 * @nameURI: the URI part of the name
242 * Locate an element in the stack based on its name.
244 static xsltStackElemPtr
245 xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
246 const xmlChar *nameURI) {
247 xsltStackElemPtr ret = NULL;
249 xsltStackElemPtr cur;
251 if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
255 * Do the lookup from the top of the stack, but
256 * don't use params being computed in a call-param
260 for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
261 cur = ctxt->varsTab[i-1];
262 while (cur != NULL) {
263 if (xmlStrEqual(cur->name, name)) {
264 if (nameURI == NULL) {
265 if (cur->nameURI == NULL) {
269 if ((cur->nameURI != NULL) &&
270 (xmlStrEqual(cur->nameURI, nameURI))) {
283 * xsltCheckStackElem:
284 * @ctxt: xn XSLT transformation context
285 * @name: the variable name
286 * @nameURI: the variable namespace URI
288 * check wether the variable or param is already defined
290 * Returns 1 if variable is present, 2 if param is present, 3 if this
291 * is an inherited param, 0 if not found, -1 in case of failure.
294 xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
295 const xmlChar *nameURI) {
296 xsltStackElemPtr cur;
298 if ((ctxt == NULL) || (name == NULL))
301 cur = xsltStackLookup(ctxt, name, nameURI);
304 if (cur->comp != NULL) {
305 if (cur->comp->type == XSLT_FUNC_WITHPARAM)
307 else if (cur->comp->type == XSLT_FUNC_PARAM)
316 * @ctxt: xn XSLT transformation context
317 * @elem: a stack element
319 * add a new element at this level of the stack.
321 * Returns 0 in case of success, -1 in case of failure.
324 xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
325 if ((ctxt == NULL) || (elem == NULL))
328 elem->next = ctxt->varsTab[ctxt->varsNr - 1];
329 ctxt->varsTab[ctxt->varsNr - 1] = elem;
335 * xsltAddStackElemList:
336 * @ctxt: xn XSLT transformation context
337 * @elems: a stack element list
339 * add the new element list at this level of the stack.
341 * Returns 0 in case of success, -1 in case of failure.
344 xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) {
345 xsltStackElemPtr cur;
347 if ((ctxt == NULL) || (elems == NULL))
350 /* TODO: check doublons */
351 if (ctxt->varsTab[ctxt->varsNr - 1] != NULL) {
352 cur = ctxt->varsTab[ctxt->varsNr - 1];
353 while (cur->next != NULL)
357 elems->next = ctxt->varsTab[ctxt->varsNr - 1];
358 ctxt->varsTab[ctxt->varsNr - 1] = elems;
364 /************************************************************************
366 * Module interfaces *
368 ************************************************************************/
372 * @ctxt: the XSLT transformation context
373 * @elem: the variable or parameter.
374 * @precomp: pointer to precompiled data
376 * Evaluate a variable value.
378 * Returns the XPath Object value or NULL in case of error
380 static xmlXPathObjectPtr
381 xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
382 xsltStylePreCompPtr precomp) {
383 xmlXPathObjectPtr result = NULL;
384 int oldProximityPosition, oldContextSize;
385 xmlNodePtr oldInst, oldNode;
386 xsltDocumentPtr oldDoc;
388 xmlNsPtr *oldNamespaces;
390 if ((ctxt == NULL) || (elem == NULL))
393 #ifdef WITH_XSLT_DEBUG_VARIABLE
394 xsltGenericDebug(xsltGenericDebugContext,
395 "Evaluating variable %s\n", elem->name);
397 if (elem->select != NULL) {
398 xmlXPathCompExprPtr comp = NULL;
400 if ((precomp != NULL) && (precomp->comp != NULL)) {
401 comp = precomp->comp;
403 comp = xmlXPathCompile(elem->select);
407 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
408 oldContextSize = ctxt->xpathCtxt->contextSize;
409 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
410 oldDoc = ctxt->document;
411 oldNode = ctxt->node;
412 oldInst = ctxt->inst;
413 oldNsNr = ctxt->xpathCtxt->nsNr;
414 oldNamespaces = ctxt->xpathCtxt->namespaces;
415 if (precomp != NULL) {
416 ctxt->inst = precomp->inst;
417 ctxt->xpathCtxt->namespaces = precomp->nsList;
418 ctxt->xpathCtxt->nsNr = precomp->nsNr;
421 ctxt->xpathCtxt->namespaces = NULL;
422 ctxt->xpathCtxt->nsNr = 0;
424 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
425 ctxt->xpathCtxt->contextSize = oldContextSize;
426 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
427 ctxt->xpathCtxt->nsNr = oldNsNr;
428 ctxt->xpathCtxt->namespaces = oldNamespaces;
429 ctxt->inst = oldInst;
430 ctxt->node = oldNode;
431 ctxt->document = oldDoc;
432 if ((precomp == NULL) || (precomp->comp == NULL))
433 xmlXPathFreeCompExpr(comp);
434 if (result == NULL) {
435 xsltTransformError(ctxt, NULL, precomp->inst,
436 "Evaluating variable %s failed\n", elem->name);
437 ctxt->state = XSLT_STATE_STOPPED;
438 #ifdef WITH_XSLT_DEBUG_VARIABLE
439 #ifdef LIBXML_DEBUG_ENABLED
441 if ((xsltGenericDebugContext == stdout) ||
442 (xsltGenericDebugContext == stderr))
443 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
449 if (elem->tree == NULL) {
450 result = xmlXPathNewCString("");
453 * This is a result tree fragment.
456 xmlNodePtr oldInsert;
459 container = xsltCreateRVT(ctxt);
460 if (container == NULL)
463 * Tag the subtree for removal once consumed
465 xsltRegisterTmpRVT(ctxt, container);
466 oldoutput = ctxt->output;
467 ctxt->output = container;
468 oldInsert = ctxt->insert;
469 ctxt->insert = (xmlNodePtr) container;
470 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
471 ctxt->insert = oldInsert;
472 ctxt->output = oldoutput;
474 result = xmlXPathNewValueTree((xmlNodePtr) container);
475 if (result == NULL) {
476 result = xmlXPathNewCString("");
478 result->boolval = 0; /* Freeing is not handled there anymore */
480 #ifdef WITH_XSLT_DEBUG_VARIABLE
481 #ifdef LIBXML_DEBUG_ENABLED
482 if ((xsltGenericDebugContext == stdout) ||
483 (xsltGenericDebugContext == stderr))
484 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
494 * xsltEvalGlobalVariable:
495 * @elem: the variable or parameter.
496 * @ctxt: the XSLT transformation context
498 * Evaluate a global variable value.
500 * Returns the XPath Object value or NULL in case of error
502 static xmlXPathObjectPtr
503 xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
504 xmlXPathObjectPtr result = NULL;
505 xsltStylePreCompPtr precomp;
506 int oldProximityPosition, oldContextSize;
509 xmlNsPtr *oldNamespaces;
512 if ((ctxt == NULL) || (elem == NULL))
518 #ifdef WITH_XSLT_DEBUG_VARIABLE
519 xsltGenericDebug(xsltGenericDebugContext,
520 "Evaluating global variable %s\n", elem->name);
524 if ((xslDebugStatus != XSLT_DEBUG_NONE) &&
525 elem->comp && elem->comp->inst)
526 xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
530 elem->name = BAD_CAST " being computed ... ";
532 precomp = elem->comp;
533 if (elem->select != NULL) {
534 xmlXPathCompExprPtr comp = NULL;
536 if ((precomp != NULL) && (precomp->comp != NULL)) {
537 comp = precomp->comp;
539 comp = xmlXPathCompile(elem->select);
545 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
546 oldContextSize = ctxt->xpathCtxt->contextSize;
547 oldInst = ctxt->inst;
548 oldNsNr = ctxt->xpathCtxt->nsNr;
549 oldNamespaces = ctxt->xpathCtxt->namespaces;
550 if (precomp != NULL) {
551 ctxt->inst = precomp->inst;
552 ctxt->xpathCtxt->namespaces = precomp->nsList;
553 ctxt->xpathCtxt->nsNr = precomp->nsNr;
556 ctxt->xpathCtxt->namespaces = NULL;
557 ctxt->xpathCtxt->nsNr = 0;
559 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
560 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
561 ctxt->xpathCtxt->contextSize = oldContextSize;
562 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
563 ctxt->inst = oldInst;
564 ctxt->xpathCtxt->nsNr = oldNsNr;
565 ctxt->xpathCtxt->namespaces = oldNamespaces;
566 if ((precomp == NULL) || (precomp->comp == NULL))
567 xmlXPathFreeCompExpr(comp);
568 if (result == NULL) {
569 xsltTransformError(ctxt, NULL, precomp->inst,
570 "Evaluating global variable %s failed\n", elem->name);
571 ctxt->state = XSLT_STATE_STOPPED;
572 #ifdef WITH_XSLT_DEBUG_VARIABLE
573 #ifdef LIBXML_DEBUG_ENABLED
575 if ((xsltGenericDebugContext == stdout) ||
576 (xsltGenericDebugContext == stderr))
577 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
583 if (elem->tree == NULL) {
584 result = xmlXPathNewCString("");
587 * This is a result tree fragment.
590 xmlNodePtr oldInsert;
593 container = xsltCreateRVT(ctxt);
594 if (container == NULL)
597 * Tag the subtree for removal once consumed
599 xsltRegisterTmpRVT(ctxt, container);
601 * Save a pointer to the global variable for later cleanup
603 container->_private = elem;
604 oldoutput = ctxt->output;
605 ctxt->output = container;
606 oldInsert = ctxt->insert;
607 ctxt->insert = (xmlNodePtr) container;
608 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
609 ctxt->insert = oldInsert;
610 ctxt->output = oldoutput;
612 result = xmlXPathNewValueTree((xmlNodePtr) container);
613 if (result == NULL) {
614 result = xmlXPathNewCString("");
616 result->boolval = 0; /* Freeing is not handled there anymore */
618 #ifdef WITH_XSLT_DEBUG_VARIABLE
619 #ifdef LIBXML_DEBUG_ENABLED
620 if ((xsltGenericDebugContext == stdout) ||
621 (xsltGenericDebugContext == stderr))
622 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
628 if (result != NULL) {
629 elem->value = result;
637 * xsltEvalGlobalVariables:
638 * @ctxt: the XSLT transformation context
640 * Evaluate the global variables of a stylesheet. This need to be
641 * done on parsed stylesheets before starting to apply transformations
643 * Returns 0 in case of success, -1 in case of error
646 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
647 xsltStackElemPtr elem;
648 xsltStylesheetPtr style;
650 if ((ctxt == NULL) || (ctxt->document == NULL))
653 #ifdef WITH_XSLT_DEBUG_VARIABLE
654 xsltGenericDebug(xsltGenericDebugContext,
655 "Registering global variables\n");
658 ctxt->node = (xmlNodePtr) ctxt->document->doc;
659 ctxt->xpathCtxt->contextSize = 1;
660 ctxt->xpathCtxt->proximityPosition = 1;
663 * Walk the list from the stylesheets and populate the hash table
666 while (style != NULL) {
667 elem = style->variables;
669 #ifdef WITH_XSLT_DEBUG_VARIABLE
670 if ((style->doc != NULL) && (style->doc->URL != NULL)) {
671 xsltGenericDebug(xsltGenericDebugContext,
672 "Registering global variables from %s\n",
677 while (elem != NULL) {
678 xsltStackElemPtr def;
681 * Global variables are stored in the variables pool.
683 def = (xsltStackElemPtr)
684 xmlHashLookup2(ctxt->globalVars,
685 elem->name, elem->nameURI);
688 def = xsltCopyStackElem(elem);
689 xmlHashAddEntry2(ctxt->globalVars,
690 elem->name, elem->nameURI, def);
691 } else if ((elem->comp != NULL) &&
692 (elem->comp->type == XSLT_FUNC_VARIABLE)) {
694 * Redefinition of variables from a different stylesheet
695 * should not generate a message.
697 if ((elem->comp->inst != NULL) &&
698 (def->comp != NULL) && (def->comp->inst != NULL) &&
699 (elem->comp->inst->doc == def->comp->inst->doc)) {
700 xsltTransformError(ctxt, style, elem->comp->inst,
701 "Global variable %s already defined\n", elem->name);
702 if (style != NULL) style->errors++;
708 style = xsltNextImport(style);
712 * This part does the actual evaluation
714 ctxt->node = (xmlNodePtr) ctxt->document->doc;
715 ctxt->xpathCtxt->contextSize = 1;
716 ctxt->xpathCtxt->proximityPosition = 1;
717 xmlHashScan(ctxt->globalVars,
718 (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
724 * xsltRegisterGlobalVariable:
725 * @style: the XSLT transformation context
726 * @name: the variable name
727 * @ns_uri: the variable namespace URI
728 * @select: the expression which need to be evaluated to generate a value
729 * @tree: the subtree if select is NULL
730 * @comp: the precompiled value
731 * @value: the string value if available
733 * Register a new variable value. If @value is NULL it unregisters
736 * Returns 0 in case of success, -1 in case of error
739 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
740 const xmlChar *ns_uri, const xmlChar *select,
741 xmlNodePtr tree, xsltStylePreCompPtr comp,
742 const xmlChar *value) {
743 xsltStackElemPtr elem, tmp;
751 #ifdef WITH_XSLT_DEBUG_VARIABLE
752 if (comp->type == XSLT_FUNC_PARAM)
753 xsltGenericDebug(xsltGenericDebugContext,
754 "Defining global param %s\n", name);
756 xsltGenericDebug(xsltGenericDebugContext,
757 "Defining global variable %s\n", name);
760 elem = xsltNewStackElem();
764 elem->name = xmlStrdup(name);
765 elem->select = xmlStrdup(select);
767 elem->nameURI = xmlStrdup(ns_uri);
769 tmp = style->variables;
772 style->variables = elem;
774 while (tmp != NULL) {
775 if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
776 (tmp->comp->type == XSLT_FUNC_VARIABLE) &&
777 (xmlStrEqual(elem->name, tmp->name)) &&
778 ((elem->nameURI == tmp->nameURI) ||
779 (xmlStrEqual(elem->nameURI, tmp->nameURI)))) {
780 xsltTransformError(NULL, style, comp->inst,
781 "redefinition of global variable %s\n", elem->name);
782 if (style != NULL) style->errors++;
784 if (tmp->next == NULL)
793 elem->value = xmlXPathNewString(value);
799 * xsltProcessUserParamInternal
801 * @ctxt: the XSLT transformation context
802 * @name: a null terminated parameter name
803 * @value: a null terminated value (may be an XPath expression)
804 * @eval: 0 to treat the value literally, else evaluate as XPath expression
806 * If @eval is 0 then @value is treated literally and is stored in the global
807 * parameter/variable table without any change.
809 * Uf @eval is 1 then @value is treated as an XPath expression and is
810 * evaluated. In this case, if you want to pass a string which will be
811 * interpreted literally then it must be enclosed in single or double quotes.
812 * If the string contains single quotes (double quotes) then it cannot be
813 * enclosed single quotes (double quotes). If the string which you want to
814 * be treated literally contains both single and double quotes (e.g. Meet
815 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
816 * quoting character. You cannot use ' or " inside the string
817 * because the replacement of character entities with their equivalents is
818 * done at a different stage of processing. The solution is to call
819 * xsltQuoteUserParams or xsltQuoteOneUserParam.
821 * This needs to be done on parsed stylesheets before starting to apply
822 * transformations. Normally this will be called (directly or indirectly)
823 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
824 * or xsltQuoteOneUserParam.
826 * Returns 0 in case of success, -1 in case of error
831 xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
832 const xmlChar * name,
833 const xmlChar * value,
836 xsltStylesheetPtr style;
840 xmlXPathCompExprPtr comp;
841 xmlXPathObjectPtr result;
842 int oldProximityPosition;
845 xmlNsPtr *oldNamespaces;
846 xsltStackElemPtr elem;
859 #ifdef WITH_XSLT_DEBUG_VARIABLE
860 xsltGenericDebug(xsltGenericDebugContext,
861 "Evaluating user parameter %s=%s\n", name, value);
868 ncname = xmlSplitQName2(name, &prefix);
870 if (ncname != NULL) {
871 if (prefix != NULL) {
874 ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
877 xsltTransformError(ctxt, style, NULL,
878 "user param : no namespace bound to prefix %s\n", prefix);
892 ncname = xmlStrdup(name);
898 res_ptr = xmlHashLookup2(ctxt->globalVars, ncname, href);
900 xsltTransformError(ctxt, style, NULL,
901 "Global parameter %s already defined\n", ncname);
905 * do not overwrite variables with parameters from the command line
907 while (style != NULL) {
908 elem = ctxt->style->variables;
909 while (elem != NULL) {
910 if ((elem->comp != NULL) &&
911 (elem->comp->type == XSLT_FUNC_VARIABLE) &&
912 (xmlStrEqual(elem->name, ncname)) &&
913 (xmlStrEqual(elem->nameURI, href))) {
919 style = xsltNextImport(style);
925 * Do the evaluation if @eval is non-zero.
930 comp = xmlXPathCompile(value);
932 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
933 oldContextSize = ctxt->xpathCtxt->contextSize;
934 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
937 * There is really no in scope namespace for parameters on the
941 oldNsNr = ctxt->xpathCtxt->nsNr;
942 oldNamespaces = ctxt->xpathCtxt->namespaces;
943 ctxt->xpathCtxt->namespaces = NULL;
944 ctxt->xpathCtxt->nsNr = 0;
945 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
946 ctxt->xpathCtxt->contextSize = oldContextSize;
947 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
948 ctxt->xpathCtxt->nsNr = oldNsNr;
949 ctxt->xpathCtxt->namespaces = oldNamespaces;
950 xmlXPathFreeCompExpr(comp);
952 if (result == NULL) {
953 xsltTransformError(ctxt, style, NULL,
954 "Evaluating user parameter %s failed\n", name);
955 ctxt->state = XSLT_STATE_STOPPED;
962 * If @eval is 0 then @value is to be taken literally and result is NULL
964 * If @eval is not 0, then @value is an XPath expression and has been
965 * successfully evaluated and result contains the resulting value and
968 * Now create an xsltStackElemPtr for insertion into the context's
969 * global variable/parameter hash table.
972 #ifdef WITH_XSLT_DEBUG_VARIABLE
973 #ifdef LIBXML_DEBUG_ENABLED
974 if ((xsltGenericDebugContext == stdout) ||
975 (xsltGenericDebugContext == stderr))
976 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
981 elem = xsltNewStackElem();
983 elem->name = xmlStrdup(ncname);
985 elem->select = xmlStrdup(value);
989 elem->nameURI = xmlStrdup(href);
993 elem->value = xmlXPathNewString(value);
996 elem->value = result;
1001 * Global parameters are stored in the XPath context variables pool.
1004 res = xmlHashAddEntry2(ctxt->globalVars, ncname, href, elem);
1006 xsltFreeStackElem(elem);
1007 xsltTransformError(ctxt, style, NULL,
1008 "Global parameter %s already defined\n", ncname);
1015 * xsltEvalUserParams:
1017 * @ctxt: the XSLT transformation context
1018 * @params: a NULL terminated array of parameters name/value tuples
1020 * Evaluate the global variables of a stylesheet. This needs to be
1021 * done on parsed stylesheets before starting to apply transformations.
1022 * Each of the parameters is evaluated as an XPath expression and stored
1023 * in the global variables/parameter hash table. If you want your
1024 * parameter used literally, use xsltQuoteUserParams.
1026 * Returns 0 in case of success, -1 in case of error
1030 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
1032 const xmlChar *name;
1033 const xmlChar *value;
1037 while (params[indx] != NULL) {
1038 name = (const xmlChar *) params[indx++];
1039 value = (const xmlChar *) params[indx++];
1040 if (xsltEvalOneUserParam(ctxt, name, value) != 0)
1047 * xsltQuoteUserParams:
1049 * @ctxt: the XSLT transformation context
1050 * @params: a NULL terminated arry of parameters names/values tuples
1052 * Similar to xsltEvalUserParams, but the values are treated literally and
1053 * are * *not* evaluated as XPath expressions. This should be done on parsed
1054 * stylesheets before starting to apply transformations.
1056 * Returns 0 in case of success, -1 in case of error.
1060 xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
1062 const xmlChar *name;
1063 const xmlChar *value;
1067 while (params[indx] != NULL) {
1068 name = (const xmlChar *) params[indx++];
1069 value = (const xmlChar *) params[indx++];
1070 if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
1077 * xsltEvalOneUserParam:
1078 * @ctxt: the XSLT transformation context
1079 * @name: a null terminated string giving the name of the parameter
1080 * @value: a null terminated string giving the XPath expression to be evaluated
1082 * This is normally called from xsltEvalUserParams to process a single
1083 * parameter from a list of parameters. The @value is evaluated as an
1084 * XPath expression and the result is stored in the context's global
1085 * variable/parameter hash table.
1087 * To have a parameter treated literally (not as an XPath expression)
1088 * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
1089 * details see description of xsltProcessOneUserParamInternal.
1091 * Returns 0 in case of success, -1 in case of error.
1095 xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
1096 const xmlChar * name,
1097 const xmlChar * value) {
1098 return xsltProcessUserParamInternal(ctxt, name, value,
1099 1 /* xpath eval ? */);
1103 * xsltQuoteOneUserParam:
1104 * @ctxt: the XSLT transformation context
1105 * @name: a null terminated string giving the name of the parameter
1106 * @value: a null terminated string giving the parameter value
1108 * This is normally called from xsltQuoteUserParams to process a single
1109 * parameter from a list of parameters. The @value is stored in the
1110 * context's global variable/parameter hash table.
1112 * Returns 0 in case of success, -1 in case of error.
1116 xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
1117 const xmlChar * name,
1118 const xmlChar * value) {
1119 return xsltProcessUserParamInternal(ctxt, name, value,
1120 0 /* xpath eval ? */);
1124 * xsltBuildVariable:
1125 * @ctxt: the XSLT transformation context
1126 * @comp: the precompiled form
1127 * @tree: the tree if select is NULL
1129 * Computes a new variable value.
1131 * Returns the xsltStackElemPtr or NULL in case of error
1133 static xsltStackElemPtr
1134 xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1136 xsltStackElemPtr elem;
1138 #ifdef WITH_XSLT_DEBUG_VARIABLE
1139 xsltGenericDebug(xsltGenericDebugContext,
1140 "Building variable %s", comp->name);
1141 if (comp->select != NULL)
1142 xsltGenericDebug(xsltGenericDebugContext,
1143 " select %s", comp->select);
1144 xsltGenericDebug(xsltGenericDebugContext, "\n");
1147 elem = xsltNewStackElem();
1151 elem->name = xmlStrdup(comp->name);
1152 if (comp->select != NULL)
1153 elem->select = xmlStrdup(comp->select);
1155 elem->select = NULL;
1157 elem->nameURI = xmlStrdup(comp->ns);
1159 if (elem->computed == 0) {
1160 elem->value = xsltEvalVariable(ctxt, elem, comp);
1161 if (elem->value != NULL)
1168 * xsltRegisterVariable:
1169 * @ctxt: the XSLT transformation context
1170 * @comp: pointer to precompiled data
1171 * @tree: the tree if select is NULL
1172 * @param: this is a parameter actually
1174 * Computes and register a new variable value.
1176 * Returns 0 in case of success, -1 in case of error
1179 xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1180 xmlNodePtr tree, int param) {
1181 xsltStackElemPtr elem;
1184 present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
1186 if ((present != 0) && (present != 3)) {
1187 xsltTransformError(ctxt, NULL, comp->inst,
1188 "xsl:variable : redefining %s\n", comp->name);
1191 } else if (present != 0) {
1192 if ((present == 1) || (present == 2)) {
1193 xsltTransformError(ctxt, NULL, comp->inst,
1194 "xsl:param : redefining %s\n", comp->name);
1197 #ifdef WITH_XSLT_DEBUG_VARIABLE
1198 xsltGenericDebug(xsltGenericDebugContext,
1199 "param %s defined by caller\n", comp->name);
1203 elem = xsltBuildVariable(ctxt, comp, tree);
1204 xsltAddStackElem(ctxt, elem);
1209 * xsltGlobalVariableLookup:
1210 * @ctxt: the XSLT transformation context
1211 * @name: the variable name
1212 * @ns_uri: the variable namespace URI
1214 * Search in the Variable array of the context for the given
1217 * Returns the value or NULL if not found
1219 static xmlXPathObjectPtr
1220 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1221 const xmlChar *ns_uri) {
1222 xsltStackElemPtr elem;
1223 xmlXPathObjectPtr ret = NULL;
1226 * Lookup the global variables in XPath global variable hash table
1228 if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
1230 elem = (xsltStackElemPtr)
1231 xmlHashLookup2(ctxt->globalVars, name, ns_uri);
1233 #ifdef WITH_XSLT_DEBUG_VARIABLE
1234 xsltGenericDebug(xsltGenericDebugContext,
1235 "global variable not found %s\n", name);
1239 if (elem->computed == 0) {
1240 if (xmlStrEqual(elem->name, BAD_CAST " being computed ... ")) {
1241 xsltTransformError(ctxt, NULL, elem->comp->inst,
1242 "Recursive definition of %s\n", name);
1245 ret = xsltEvalGlobalVariable(elem, ctxt);
1248 return(xmlXPathObjectCopy(ret));
1252 * xsltVariableLookup:
1253 * @ctxt: the XSLT transformation context
1254 * @name: the variable name
1255 * @ns_uri: the variable namespace URI
1257 * Search in the Variable array of the context for the given
1260 * Returns the value or NULL if not found
1263 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1264 const xmlChar *ns_uri) {
1265 xsltStackElemPtr elem;
1270 elem = xsltStackLookup(ctxt, name, ns_uri);
1272 return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
1274 if (elem->computed == 0) {
1275 #ifdef WITH_XSLT_DEBUG_VARIABLE
1276 xsltGenericDebug(xsltGenericDebugContext,
1277 "uncomputed variable %s\n", name);
1279 elem->value = xsltEvalVariable(ctxt, elem, NULL);
1282 if (elem->value != NULL)
1283 return(xmlXPathObjectCopy(elem->value));
1284 #ifdef WITH_XSLT_DEBUG_VARIABLE
1285 xsltGenericDebug(xsltGenericDebugContext,
1286 "variable not found %s\n", name);
1292 * xsltParseStylesheetCallerParam:
1293 * @ctxt: the XSLT transformation context
1294 * @cur: the "param" element
1296 * parse an XSLT transformation param declaration, compute
1297 * its value but doesn't record it.
1299 * Returns the new xsltStackElemPtr or NULL
1303 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1304 xmlNodePtr tree = NULL;
1305 xsltStackElemPtr elem = NULL;
1306 xsltStylePreCompPtr comp;
1308 if ((cur == NULL) || (ctxt == NULL))
1310 comp = (xsltStylePreCompPtr) cur->_private;
1312 xsltTransformError(ctxt, NULL, cur,
1313 "xsl:param : compilation error\n");
1317 if (comp->name == NULL) {
1318 xsltTransformError(ctxt, NULL, cur,
1319 "xsl:param : missing name attribute\n");
1323 #ifdef WITH_XSLT_DEBUG_VARIABLE
1324 xsltGenericDebug(xsltGenericDebugContext,
1325 "Handling param %s\n", comp->name);
1328 if (comp->select == NULL) {
1329 tree = cur->children;
1331 #ifdef WITH_XSLT_DEBUG_VARIABLE
1332 xsltGenericDebug(xsltGenericDebugContext,
1333 " select %s\n", comp->select);
1338 elem = xsltBuildVariable(ctxt, comp, tree);
1344 * xsltParseGlobalVariable:
1345 * @style: the XSLT stylesheet
1346 * @cur: the "variable" element
1348 * parse an XSLT transformation variable declaration and record
1353 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
1354 xsltStylePreCompPtr comp;
1356 if ((cur == NULL) || (style == NULL))
1359 xsltStylePreCompute(style, cur);
1360 comp = (xsltStylePreCompPtr) cur->_private;
1362 xsltTransformError(NULL, style, cur,
1363 "xsl:variable : compilation failed\n");
1367 if (comp->name == NULL) {
1368 xsltTransformError(NULL, style, cur,
1369 "xsl:variable : missing name attribute\n");
1373 #ifdef WITH_XSLT_DEBUG_VARIABLE
1374 xsltGenericDebug(xsltGenericDebugContext,
1375 "Registering global variable %s\n", comp->name);
1378 xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1379 cur->children, comp, NULL);
1383 * xsltParseGlobalParam:
1384 * @style: the XSLT stylesheet
1385 * @cur: the "param" element
1387 * parse an XSLT transformation param declaration and record
1392 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
1393 xsltStylePreCompPtr comp;
1395 if ((cur == NULL) || (style == NULL))
1398 xsltStylePreCompute(style, cur);
1399 comp = (xsltStylePreCompPtr) cur->_private;
1401 xsltTransformError(NULL, style, cur,
1402 "xsl:param : compilation failed\n");
1406 if (comp->name == NULL) {
1407 xsltTransformError(NULL, style, cur,
1408 "xsl:param : missing name attribute\n");
1412 #ifdef WITH_XSLT_DEBUG_VARIABLE
1413 xsltGenericDebug(xsltGenericDebugContext,
1414 "Registering global param %s\n", comp->name);
1417 xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1418 cur->children, comp, NULL);
1422 * xsltParseStylesheetVariable:
1423 * @ctxt: the XSLT transformation context
1424 * @cur: the "variable" element
1426 * parse an XSLT transformation variable declaration and record
1431 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1432 xsltStylePreCompPtr comp;
1434 if ((cur == NULL) || (ctxt == NULL))
1437 comp = (xsltStylePreCompPtr) cur->_private;
1439 xsltTransformError(ctxt, NULL, cur,
1440 "xsl:variable : compilation failed\n");
1444 if (comp->name == NULL) {
1445 xsltTransformError(ctxt, NULL, cur,
1446 "xsl:variable : missing name attribute\n");
1450 #ifdef WITH_XSLT_DEBUG_VARIABLE
1451 xsltGenericDebug(xsltGenericDebugContext,
1452 "Registering variable %s\n", comp->name);
1455 xsltRegisterVariable(ctxt, comp, cur->children, 0);
1459 * xsltParseStylesheetParam:
1460 * @ctxt: the XSLT transformation context
1461 * @cur: the "param" element
1463 * parse an XSLT transformation param declaration and record
1468 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1469 xsltStylePreCompPtr comp;
1471 if ((cur == NULL) || (ctxt == NULL))
1474 comp = (xsltStylePreCompPtr) cur->_private;
1476 xsltTransformError(ctxt, NULL, cur,
1477 "xsl:param : compilation failed\n");
1481 if (comp->name == NULL) {
1482 xsltTransformError(ctxt, NULL, cur,
1483 "xsl:param : missing name attribute\n");
1487 #ifdef WITH_XSLT_DEBUG_VARIABLE
1488 xsltGenericDebug(xsltGenericDebugContext,
1489 "Registering param %s\n", comp->name);
1492 xsltRegisterVariable(ctxt, comp, cur->children, 1);
1496 * xsltFreeGlobalVariables:
1497 * @ctxt: the XSLT transformation context
1499 * Free up the data associated to the global variables
1504 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
1505 xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
1509 * xsltXPathVariableLookup:
1510 * @ctxt: a void * but the the XSLT transformation context actually
1511 * @name: the variable name
1512 * @ns_uri: the variable namespace URI
1514 * This is the entry point when a varibale is needed by the XPath
1517 * Returns the value or NULL if not found
1520 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
1521 const xmlChar *ns_uri) {
1522 xsltTransformContextPtr context;
1523 xmlXPathObjectPtr ret;
1525 if ((ctxt == NULL) || (name == NULL))
1528 #ifdef WITH_XSLT_DEBUG_VARIABLE
1529 xsltGenericDebug(xsltGenericDebugContext,
1530 "Lookup variable %s\n", name);
1532 context = (xsltTransformContextPtr) ctxt;
1533 ret = xsltVariableLookup(context, name, ns_uri);
1535 xsltTransformError(ctxt, NULL, NULL,
1536 "unregistered variable %s\n", name);
1538 #ifdef WITH_XSLT_DEBUG_VARIABLE
1540 xsltGenericDebug(xsltGenericDebugContext,
1541 "found variable %s\n", name);