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 /************************************************************************
41 ************************************************************************/
46 * Create a new XSLT ParserContext
48 * Returns the newly allocated xsltParserStackElem or NULL in case of error
50 static xsltStackElemPtr
51 xsltNewStackElem(void) {
54 cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
56 xsltTransformError(NULL, NULL, NULL,
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 xsltTransformError(NULL, NULL, NULL,
85 "xsltCopyStackElem : malloc failed\n");
88 cur->name = xmlStrdup(elem->name);
89 cur->nameURI = xmlStrdup(elem->nameURI);
90 cur->select = xmlStrdup(elem->select);
91 cur->tree = elem->tree;
92 cur->comp = elem->comp;
100 * @elem: an XSLT stack element
102 * Free up the memory allocated by @elem
105 xsltFreeStackElem(xsltStackElemPtr elem) {
108 if (elem->name != NULL)
110 if (elem->nameURI != NULL)
111 xmlFree(elem->nameURI);
112 if (elem->select != NULL)
113 xmlFree(elem->select);
114 if (elem->value != NULL)
115 xmlXPathFreeObject(elem->value);
121 * xsltFreeStackElemList:
122 * @elem: an XSLT stack element
124 * Free up the memory allocated by @elem
127 xsltFreeStackElemList(xsltStackElemPtr elem) {
128 xsltStackElemPtr next;
130 while(elem != NULL) {
132 xsltFreeStackElem(elem);
138 * xsltCheckStackElem:
139 * @ctxt: xn XSLT transformation context
140 * @name: the variable name
141 * @nameURI: the variable namespace URI
143 * check wether the variable or param is already defined
145 * Returns 1 if variable is present, 2 if param is present, 3 if this
146 * is an inherited param, 0 if not found, -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)))) {
162 if ((cur->comp != NULL) &&
163 (cur->comp->type == XSLT_FUNC_WITHPARAM))
165 if ((cur->comp != NULL) &&
166 (cur->comp->type == XSLT_FUNC_PARAM))
178 * @ctxt: xn XSLT transformation context
179 * @elem: a stack element
181 * add a new element at this level of the stack.
183 * Returns 0 in case of success, -1 in case of failure.
186 xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
187 if ((ctxt == NULL) || (elem == NULL))
190 elem->next = ctxt->varsTab[ctxt->varsNr - 1];
191 ctxt->varsTab[ctxt->varsNr - 1] = elem;
197 * xsltAddStackElemList:
198 * @ctxt: xn XSLT transformation context
199 * @elems: a stack element list
201 * add the new element list at this level of the stack.
203 * Returns 0 in case of success, -1 in case of failure.
206 xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) {
207 xsltStackElemPtr cur;
209 if ((ctxt == NULL) || (elems == NULL))
212 /* TODO: check doublons */
213 if (ctxt->varsTab[ctxt->varsNr - 1] != NULL) {
214 cur = ctxt->varsTab[ctxt->varsNr - 1];
215 while (cur->next != NULL)
219 elems->next = ctxt->varsTab[ctxt->varsNr - 1];
220 ctxt->varsTab[ctxt->varsNr - 1] = elems;
228 * @ctxt: an XSLT transformation context
229 * @name: the local part of the name
230 * @nameURI: the URI part of the name
232 * Locate an element in the stack based on its name.
234 static xsltStackElemPtr
235 xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
236 const xmlChar *nameURI) {
237 xsltStackElemPtr ret = NULL;
239 xsltStackElemPtr cur;
241 if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
245 * Do the lookup from the top of the stack, but
246 * don't use params being computed in a call-param
250 for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
251 cur = ctxt->varsTab[i-1];
252 while (cur != NULL) {
253 if (xmlStrEqual(cur->name, name)) {
254 if (nameURI == NULL) {
255 if (cur->nameURI == NULL) {
259 if ((cur->nameURI != NULL) &&
260 (xmlStrEqual(cur->nameURI, nameURI))) {
272 /************************************************************************
274 * Module interfaces *
276 ************************************************************************/
280 * @ctxt: the XSLT transformation context
281 * @elem: the variable or parameter.
282 * @precomp: pointer to precompiled data
284 * Evaluate a variable value.
286 * Returns the XPath Object value or NULL in case of error
288 static xmlXPathObjectPtr
289 xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
290 xsltStylePreCompPtr precomp) {
291 xmlXPathObjectPtr result = NULL;
292 int oldProximityPosition, oldContextSize;
293 xmlNodePtr oldInst, oldNode;
294 xsltDocumentPtr oldDoc;
296 xmlNsPtr *oldNamespaces;
298 if ((ctxt == NULL) || (elem == NULL))
301 #ifdef WITH_XSLT_DEBUG_VARIABLE
302 xsltGenericDebug(xsltGenericDebugContext,
303 "Evaluating variable %s\n", elem->name);
305 if (elem->select != NULL) {
306 xmlXPathCompExprPtr comp = NULL;
308 if ((precomp != NULL) && (precomp->comp != NULL)) {
309 comp = precomp->comp;
311 comp = xmlXPathCompile(elem->select);
315 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
316 oldContextSize = ctxt->xpathCtxt->contextSize;
317 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
318 oldDoc = ctxt->document;
319 oldNode = ctxt->node;
320 oldInst = ctxt->inst;
321 oldNsNr = ctxt->xpathCtxt->nsNr;
322 oldNamespaces = ctxt->xpathCtxt->namespaces;
323 if (precomp != NULL) {
324 ctxt->inst = precomp->inst;
325 ctxt->xpathCtxt->namespaces = precomp->nsList;
326 ctxt->xpathCtxt->nsNr = precomp->nsNr;
329 ctxt->xpathCtxt->namespaces = NULL;
330 ctxt->xpathCtxt->nsNr = 0;
332 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
333 ctxt->xpathCtxt->contextSize = oldContextSize;
334 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
335 ctxt->xpathCtxt->nsNr = oldNsNr;
336 ctxt->xpathCtxt->namespaces = oldNamespaces;
337 ctxt->inst = oldInst;
338 ctxt->node = oldNode;
339 ctxt->document = oldDoc;
340 if ((precomp == NULL) || (precomp->comp == NULL))
341 xmlXPathFreeCompExpr(comp);
342 if (result == NULL) {
343 xsltTransformError(ctxt, NULL, precomp->inst,
344 "Evaluating variable %s failed\n", elem->name);
345 ctxt->state = XSLT_STATE_STOPPED;
346 #ifdef WITH_XSLT_DEBUG_VARIABLE
347 #ifdef LIBXML_DEBUG_ENABLED
349 if ((xsltGenericDebugContext == stdout) ||
350 (xsltGenericDebugContext == stderr))
351 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
357 if (elem->tree == NULL) {
358 result = xmlXPathNewCString("");
361 * This is a result tree fragment.
363 xmlNodePtr container;
364 xmlNodePtr oldInsert;
367 container = xmlNewDocNode(ctxt->document->doc, NULL,
368 (const xmlChar *) "fake node libxslt", NULL);
369 if (container == NULL)
371 container->parent = NULL;
373 oldoutput = ctxt->output;
375 oldInsert = ctxt->insert;
376 ctxt->insert = container;
377 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
378 ctxt->insert = oldInsert;
379 ctxt->output = oldoutput;
381 result = xmlXPathNewValueTree(container);
382 if (result == NULL) {
383 result = xmlXPathNewCString("");
386 * Tag the subtree for removal once consumed
390 #ifdef WITH_XSLT_DEBUG_VARIABLE
391 #ifdef LIBXML_DEBUG_ENABLED
392 if ((xsltGenericDebugContext == stdout) ||
393 (xsltGenericDebugContext == stderr))
394 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
404 * xsltEvalGlobalVariable:
405 * @elem: the variable or parameter.
406 * @ctxt: the XSLT transformation context
408 * Evaluate a global variable value.
410 * Returns the XPath Object value or NULL in case of error
412 static xmlXPathObjectPtr
413 xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
414 xmlXPathObjectPtr result = NULL;
415 xsltStylePreCompPtr precomp;
416 int oldProximityPosition, oldContextSize;
419 xmlNsPtr *oldNamespaces;
421 if ((ctxt == NULL) || (elem == NULL))
427 #ifdef WITH_XSLT_DEBUG_VARIABLE
428 xsltGenericDebug(xsltGenericDebugContext,
429 "Evaluating global variable %s\n", elem->name);
433 if ((xslDebugStatus != XSLT_DEBUG_NONE) &&
434 elem->comp && elem->comp->inst)
435 xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
438 precomp = elem->comp;
439 if (elem->select != NULL) {
440 xmlXPathCompExprPtr comp = NULL;
442 if ((precomp != NULL) && (precomp->comp != NULL)) {
443 comp = precomp->comp;
445 comp = xmlXPathCompile(elem->select);
449 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
450 oldContextSize = ctxt->xpathCtxt->contextSize;
451 oldInst = ctxt->inst;
452 oldNsNr = ctxt->xpathCtxt->nsNr;
453 oldNamespaces = ctxt->xpathCtxt->namespaces;
454 if (precomp != NULL) {
455 ctxt->inst = precomp->inst;
456 ctxt->xpathCtxt->namespaces = precomp->nsList;
457 ctxt->xpathCtxt->nsNr = precomp->nsNr;
460 ctxt->xpathCtxt->namespaces = NULL;
461 ctxt->xpathCtxt->nsNr = 0;
463 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
464 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
465 ctxt->xpathCtxt->contextSize = oldContextSize;
466 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
467 ctxt->inst = oldInst;
468 ctxt->xpathCtxt->nsNr = oldNsNr;
469 ctxt->xpathCtxt->namespaces = oldNamespaces;
470 if ((precomp == NULL) || (precomp->comp == NULL))
471 xmlXPathFreeCompExpr(comp);
472 if (result == NULL) {
473 xsltTransformError(ctxt, NULL, precomp->inst,
474 "Evaluating global variable %s failed\n", elem->name);
475 ctxt->state = XSLT_STATE_STOPPED;
476 #ifdef WITH_XSLT_DEBUG_VARIABLE
477 #ifdef LIBXML_DEBUG_ENABLED
479 if ((xsltGenericDebugContext == stdout) ||
480 (xsltGenericDebugContext == stderr))
481 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
487 if (elem->tree == NULL) {
488 result = xmlXPathNewCString("");
491 * This is a result tree fragment.
493 xmlNodePtr container;
494 xmlNodePtr oldInsert;
497 container = xmlNewDocNode(ctxt->document->doc, NULL,
498 (const xmlChar *) "fake node libxslt", NULL);
499 if (container == NULL)
501 container->parent = NULL;
503 oldoutput = ctxt->output;
505 oldInsert = ctxt->insert;
506 ctxt->insert = container;
507 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
508 ctxt->insert = oldInsert;
509 ctxt->output = oldoutput;
511 result = xmlXPathNewValueTree(container);
512 if (result == NULL) {
513 result = xmlXPathNewCString("");
516 * Tag the subtree for removal once consumed
520 #ifdef WITH_XSLT_DEBUG_VARIABLE
521 #ifdef LIBXML_DEBUG_ENABLED
522 if ((xsltGenericDebugContext == stdout) ||
523 (xsltGenericDebugContext == stderr))
524 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
530 if (result != NULL) {
531 elem->value = result;
538 * xsltEvalGlobalVariables:
539 * @ctxt: the XSLT transformation context
541 * Evaluate the global variables of a stylesheet. This need to be
542 * done on parsed stylesheets before starting to apply transformations
544 * Returns 0 in case of success, -1 in case of error
547 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
548 xsltStackElemPtr elem;
549 xsltStylesheetPtr style;
554 #ifdef WITH_XSLT_DEBUG_VARIABLE
555 xsltGenericDebug(xsltGenericDebugContext,
556 "Registering global variables\n");
558 ctxt->node = (xmlNodePtr) ctxt->document->doc;
559 ctxt->xpathCtxt->contextSize = 1;
560 ctxt->xpathCtxt->proximityPosition = 1;
563 * Walk the list from the stylesheets and populate the hash table
566 while (style != NULL) {
567 elem = style->variables;
569 #ifdef WITH_XSLT_DEBUG_VARIABLE
570 if ((style->doc != NULL) && (style->doc->URL != NULL)) {
571 xsltGenericDebug(xsltGenericDebugContext,
572 "Registering global variables from %s\n",
577 while (elem != NULL) {
578 xsltStackElemPtr def;
581 * Global variables are stored in the variables pool.
583 def = (xsltStackElemPtr)
584 xmlHashLookup2(ctxt->globalVars,
585 elem->name, elem->nameURI);
589 def = xsltCopyStackElem(elem);
590 res = xmlHashAddEntry2(ctxt->globalVars,
591 elem->name, elem->nameURI, def);
592 } else if ((elem->comp != NULL) &&
593 (elem->comp->type == XSLT_FUNC_VARIABLE)) {
595 * Redefinition of variables from a different stylesheet
596 * should not generate a message.
598 if ((elem->comp->inst != NULL) &&
599 (def->comp != NULL) && (def->comp->inst != NULL) &&
600 (elem->comp->inst->doc == def->comp->inst->doc)) {
601 xsltTransformError(ctxt, style, elem->comp->inst,
602 "Global variable %s already defined\n", elem->name);
609 style = xsltNextImport(style);
613 * This part does the actual evaluation
615 ctxt->node = (xmlNodePtr) ctxt->document->doc;
616 ctxt->xpathCtxt->contextSize = 1;
617 ctxt->xpathCtxt->proximityPosition = 1;
618 xmlHashScan(ctxt->globalVars,
619 (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
625 * xsltRegisterGlobalVariable:
626 * @style: the XSLT transformation context
627 * @name: the variable name
628 * @ns_uri: the variable namespace URI
629 * @select: the expression which need to be evaluated to generate a value
630 * @tree: the subtree if select is NULL
631 * @comp: the precompiled value
632 * @value: the string value if available
634 * Register a new variable value. If @value is NULL it unregisters
637 * Returns 0 in case of success, -1 in case of error
640 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
641 const xmlChar *ns_uri, const xmlChar *select,
642 xmlNodePtr tree, xsltStylePreCompPtr comp,
643 const xmlChar *value) {
644 xsltStackElemPtr elem, tmp;
652 #ifdef WITH_XSLT_DEBUG_VARIABLE
653 if (comp->type == XSLT_FUNC_PARAM)
654 xsltGenericDebug(xsltGenericDebugContext,
655 "Defining global param %s\n", name);
657 xsltGenericDebug(xsltGenericDebugContext,
658 "Defining global variable %s\n", name);
661 elem = xsltNewStackElem();
665 elem->name = xmlStrdup(name);
666 elem->select = xmlStrdup(select);
668 elem->nameURI = xmlStrdup(ns_uri);
670 tmp = style->variables;
673 style->variables = elem;
675 while (tmp != NULL) {
676 if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
677 (tmp->comp->type == XSLT_FUNC_VARIABLE) &&
678 (xmlStrEqual(elem->name, tmp->name)) &&
679 ((elem->nameURI == tmp->nameURI) ||
680 (xmlStrEqual(elem->nameURI, tmp->nameURI)))) {
681 xsltTransformError(NULL, style, comp->inst,
682 "redefinition of global variable %s\n", elem->name);
685 if (tmp->next == NULL)
694 elem->value = xmlXPathNewString(value);
700 * xsltProcessUserParamInternal
702 * @ctxt: the XSLT transformation context
703 * @name: a null terminated parameter name
704 * @value: a null terminated value (may be an XPath expression)
705 * @eval: 0 to treat the value literally, else evaluate as XPath expression
707 * If @eval is 0 then @value is treated literally and is stored in the global
708 * parameter/variable table without any change.
710 * Uf @eval is 1 then @value is treated as an XPath expression and is
711 * evaluated. In this case, if you want to pass a string which will be
712 * interpreted literally then it must be enclosed in single or double quotes.
713 * If the string contains single quotes (double quotes) then it cannot be
714 * enclosed single quotes (double quotes). If the string which you want to
715 * be treated literally contains both single and double quotes (e.g. Meet
716 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
717 * quoting character. You cannot use ' or " inside the string
718 * because the replacement of character entities with their equivalents is
719 * done at a different stage of processing. The solution is to call
720 * xsltQuoteUserParams or xsltQuoteOneUserParam.
722 * This needs to be done on parsed stylesheets before starting to apply
723 * transformations. Normally this will be called (directly or indirectly)
724 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
725 * or xsltQuoteOneUserParam.
727 * Returns 0 in case of success, -1 in case of error
732 xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
733 const xmlChar * name,
734 const xmlChar * value,
737 xsltStylesheetPtr style;
741 xmlXPathCompExprPtr comp;
742 xmlXPathObjectPtr result;
743 int oldProximityPosition;
746 xmlNsPtr *oldNamespaces;
747 xsltStackElemPtr elem;
759 #ifdef WITH_XSLT_DEBUG_VARIABLE
760 xsltGenericDebug(xsltGenericDebugContext,
761 "Evaluating user parameter %s=%s\n", name, value);
768 ncname = xmlSplitQName2(name, &prefix);
770 if (ncname != NULL) {
771 if (prefix != NULL) {
774 ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
777 xsltTransformError(ctxt, style, NULL,
778 "user param : no namespace bound to prefix %s\n", prefix);
792 ncname = xmlStrdup(name);
799 * Do the evaluation if @eval is non-zero.
804 comp = xmlXPathCompile(value);
806 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
807 oldContextSize = ctxt->xpathCtxt->contextSize;
808 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
811 * There is really no in scope namespace for parameters on the
815 oldNsNr = ctxt->xpathCtxt->nsNr;
816 oldNamespaces = ctxt->xpathCtxt->namespaces;
817 ctxt->xpathCtxt->namespaces = NULL;
818 ctxt->xpathCtxt->nsNr = 0;
819 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
820 ctxt->xpathCtxt->contextSize = oldContextSize;
821 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
822 ctxt->xpathCtxt->nsNr = oldNsNr;
823 ctxt->xpathCtxt->namespaces = oldNamespaces;
824 xmlXPathFreeCompExpr(comp);
826 if (result == NULL) {
827 xsltTransformError(ctxt, style, NULL,
828 "Evaluating user parameter %s failed\n", name);
829 ctxt->state = XSLT_STATE_STOPPED;
836 * If @eval is 0 then @value is to be taken literally and result is NULL
838 * If @eval is not 0, then @value is an XPath expression and has been
839 * successfully evaluated and result contains the resulting value and
842 * Now create an xsltStackElemPtr for insertion into the context's
843 * global variable/parameter hash table.
846 #ifdef WITH_XSLT_DEBUG_VARIABLE
847 #ifdef LIBXML_DEBUG_ENABLED
848 if ((xsltGenericDebugContext == stdout) ||
849 (xsltGenericDebugContext == stderr))
850 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
855 elem = xsltNewStackElem();
857 elem->name = xmlStrdup(ncname);
859 elem->select = xmlStrdup(value);
863 elem->nameURI = xmlStrdup(href);
867 elem->value = xmlXPathNewString(value);
870 elem->value = result;
875 * Global parameters are stored in the XPath context variables pool.
878 res = xmlHashAddEntry2(ctxt->globalVars, ncname, href, elem);
880 xsltFreeStackElem(elem);
881 xsltTransformError(ctxt, style, NULL,
882 "Global parameter %s already defined\n", ncname);
889 * xsltEvalUserParams:
891 * @ctxt: the XSLT transformation context
892 * @params: a NULL terminated array of parameters name/value tuples
894 * Evaluate the global variables of a stylesheet. This needs to be
895 * done on parsed stylesheets before starting to apply transformations.
896 * Each of the parameters is evaluated as an XPath expression and stored
897 * in the global variables/parameter hash table. If you want your
898 * parameter used literally, use xsltQuoteUserParams.
900 * Returns 0 in case of success, -1 in case of error
904 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
907 const xmlChar *value;
911 while (params[indx] != NULL) {
912 name = (const xmlChar *) params[indx++];
913 value = (const xmlChar *) params[indx++];
914 if (xsltEvalOneUserParam(ctxt, name, value) != 0)
921 * xsltQuoteUserParams:
923 * @ctxt: the XSLT transformation context
924 * @params: a NULL terminated arry of parameters names/values tuples
926 * Similar to xsltEvalUserParams, but the values are treated literally and
927 * are * *not* evaluated as XPath expressions. This should be done on parsed
928 * stylesheets before starting to apply transformations.
930 * Returns 0 in case of success, -1 in case of error.
934 xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
937 const xmlChar *value;
941 while (params[indx] != NULL) {
942 name = (const xmlChar *) params[indx++];
943 value = (const xmlChar *) params[indx++];
944 if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
951 * xsltEvalOneUserParam:
952 * @ctxt: the XSLT transformation context
953 * @name: a null terminated string giving the name of the parameter
954 * @value: a null terminated string giving the XPath expression to be evaluated
956 * This is normally called from xsltEvalUserParams to process a single
957 * parameter from a list of parameters. The @value is evaluated as an
958 * XPath expression and the result is stored in the context's global
959 * variable/parameter hash table.
961 * To have a parameter treated literally (not as an XPath expression)
962 * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
963 * details see description of xsltProcessOneUserParamInternal.
965 * Returns 0 in case of success, -1 in case of error.
969 xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
970 const xmlChar * name,
971 const xmlChar * value) {
972 return xsltProcessUserParamInternal(ctxt, name, value,
973 1 /* xpath eval ? */);
977 * xsltQuoteOneUserParam:
978 * @ctxt: the XSLT transformation context
979 * @name: a null terminated string giving the name of the parameter
980 * @value: a null terminated string giving the parameter value
982 * This is normally called from xsltQuoteUserParams to process a single
983 * parameter from a list of parameters. The @value is stored in the
984 * context's global variable/parameter hash table.
986 * Returns 0 in case of success, -1 in case of error.
990 xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
991 const xmlChar * name,
992 const xmlChar * value) {
993 return xsltProcessUserParamInternal(ctxt, name, value,
994 0 /* xpath eval ? */);
999 * @ctxt: the XSLT transformation context
1000 * @comp: the precompiled form
1001 * @tree: the tree if select is NULL
1003 * Computes a new variable value.
1005 * Returns the xsltStackElemPtr or NULL in case of error
1007 static xsltStackElemPtr
1008 xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1010 xsltStackElemPtr elem;
1012 #ifdef WITH_XSLT_DEBUG_VARIABLE
1013 xsltGenericDebug(xsltGenericDebugContext,
1014 "Building variable %s", comp->name);
1015 if (comp->select != NULL)
1016 xsltGenericDebug(xsltGenericDebugContext,
1017 " select %s", comp->select);
1018 xsltGenericDebug(xsltGenericDebugContext, "\n");
1021 elem = xsltNewStackElem();
1025 elem->name = xmlStrdup(comp->name);
1026 if (comp->select != NULL)
1027 elem->select = xmlStrdup(comp->select);
1029 elem->select = NULL;
1031 elem->nameURI = xmlStrdup(comp->ns);
1033 if (elem->computed == 0) {
1034 elem->value = xsltEvalVariable(ctxt, elem, comp);
1035 if (elem->value != NULL)
1042 * xsltRegisterVariable:
1043 * @ctxt: the XSLT transformation context
1044 * @comp: pointer to precompiled data
1045 * @tree: the tree if select is NULL
1046 * @param: this is a parameter actually
1048 * Computes and register a new variable value.
1050 * Returns 0 in case of success, -1 in case of error
1053 xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1054 xmlNodePtr tree, int param) {
1055 xsltStackElemPtr elem;
1058 present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
1060 if ((present != 0) && (present != 3)) {
1061 xsltTransformError(ctxt, NULL, comp->inst,
1062 "xsl:variable : redefining %s\n", comp->name);
1065 } else if (present != 0) {
1066 if ((present == 1) || (present == 2)) {
1067 xsltTransformError(ctxt, NULL, comp->inst,
1068 "xsl:param : redefining %s\n", comp->name);
1071 #ifdef WITH_XSLT_DEBUG_VARIABLE
1072 xsltGenericDebug(xsltGenericDebugContext,
1073 "param %s defined by caller\n", comp->name);
1077 elem = xsltBuildVariable(ctxt, comp, tree);
1078 xsltAddStackElem(ctxt, elem);
1083 * xsltGlobalVariableLookup:
1084 * @ctxt: the XSLT transformation context
1085 * @name: the variable name
1086 * @ns_uri: the variable namespace URI
1088 * Search in the Variable array of the context for the given
1091 * Returns the value or NULL if not found
1093 static xmlXPathObjectPtr
1094 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1095 const xmlChar *ns_uri) {
1096 xsltStackElemPtr elem;
1097 xmlXPathObjectPtr ret = NULL;
1100 * Lookup the global variables in XPath global variable hash table
1102 if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
1104 elem = (xsltStackElemPtr)
1105 xmlHashLookup2(ctxt->globalVars, name, ns_uri);
1107 #ifdef WITH_XSLT_DEBUG_VARIABLE
1108 xsltGenericDebug(xsltGenericDebugContext,
1109 "global variable not found %s\n", name);
1113 if (elem->computed == 0)
1114 ret = xsltEvalGlobalVariable(elem, ctxt);
1117 return(xmlXPathObjectCopy(ret));
1121 * xsltVariableLookup:
1122 * @ctxt: the XSLT transformation context
1123 * @name: the variable name
1124 * @ns_uri: the variable namespace URI
1126 * Search in the Variable array of the context for the given
1129 * Returns the value or NULL if not found
1132 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1133 const xmlChar *ns_uri) {
1134 xsltStackElemPtr elem;
1139 elem = xsltStackLookup(ctxt, name, ns_uri);
1141 return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
1143 if (elem->computed == 0) {
1144 #ifdef WITH_XSLT_DEBUG_VARIABLE
1145 xsltGenericDebug(xsltGenericDebugContext,
1146 "uncomputed variable %s\n", name);
1148 elem->value = xsltEvalVariable(ctxt, elem, NULL);
1151 if (elem->value != NULL)
1152 return(xmlXPathObjectCopy(elem->value));
1153 #ifdef WITH_XSLT_DEBUG_VARIABLE
1154 xsltGenericDebug(xsltGenericDebugContext,
1155 "variable not found %s\n", name);
1161 * xsltParseStylesheetCallerParam:
1162 * @ctxt: the XSLT transformation context
1163 * @cur: the "param" element
1165 * parse an XSLT transformation param declaration, compute
1166 * its value but doesn't record it.
1168 * Returns the new xsltStackElemPtr or NULL
1172 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1173 xmlNodePtr tree = NULL;
1174 xsltStackElemPtr elem = NULL;
1175 xsltStylePreCompPtr comp;
1177 if ((cur == NULL) || (ctxt == NULL))
1179 comp = (xsltStylePreCompPtr) cur->_private;
1181 xsltTransformError(ctxt, NULL, cur,
1182 "xsl:param : compilation error\n");
1186 if (comp->name == NULL) {
1187 xsltTransformError(ctxt, NULL, cur,
1188 "xsl:param : missing name attribute\n");
1192 #ifdef WITH_XSLT_DEBUG_VARIABLE
1193 xsltGenericDebug(xsltGenericDebugContext,
1194 "Handling param %s\n", comp->name);
1197 if (comp->select == NULL) {
1198 tree = cur->children;
1200 #ifdef WITH_XSLT_DEBUG_VARIABLE
1201 xsltGenericDebug(xsltGenericDebugContext,
1202 " select %s\n", comp->select);
1207 elem = xsltBuildVariable(ctxt, comp, tree);
1213 * xsltParseGlobalVariable:
1214 * @style: the XSLT stylesheet
1215 * @cur: the "variable" element
1217 * parse an XSLT transformation variable declaration and record
1222 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
1223 xsltStylePreCompPtr comp;
1225 if ((cur == NULL) || (style == NULL))
1228 xsltStylePreCompute(style, cur);
1229 comp = (xsltStylePreCompPtr) cur->_private;
1231 xsltTransformError(NULL, style, cur,
1232 "xsl:variable : compilation failed\n");
1236 if (comp->name == NULL) {
1237 xsltTransformError(NULL, style, cur,
1238 "xsl:variable : missing name attribute\n");
1242 #ifdef WITH_XSLT_DEBUG_VARIABLE
1243 xsltGenericDebug(xsltGenericDebugContext,
1244 "Registering global variable %s\n", comp->name);
1247 xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1248 cur->children, comp, NULL);
1252 * xsltParseGlobalParam:
1253 * @style: the XSLT stylesheet
1254 * @cur: the "param" element
1256 * parse an XSLT transformation param declaration and record
1261 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
1262 xsltStylePreCompPtr comp;
1264 if ((cur == NULL) || (style == NULL))
1267 xsltStylePreCompute(style, cur);
1268 comp = (xsltStylePreCompPtr) cur->_private;
1270 xsltTransformError(NULL, style, cur,
1271 "xsl:param : compilation failed\n");
1275 if (comp->name == NULL) {
1276 xsltTransformError(NULL, style, cur,
1277 "xsl:param : missing name attribute\n");
1281 #ifdef WITH_XSLT_DEBUG_VARIABLE
1282 xsltGenericDebug(xsltGenericDebugContext,
1283 "Registering global param %s\n", comp->name);
1286 xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1287 cur->children, comp, NULL);
1291 * xsltParseStylesheetVariable:
1292 * @ctxt: the XSLT transformation context
1293 * @cur: the "variable" element
1295 * parse an XSLT transformation variable declaration and record
1300 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1301 xsltStylePreCompPtr comp;
1303 if ((cur == NULL) || (ctxt == NULL))
1306 comp = (xsltStylePreCompPtr) cur->_private;
1308 xsltTransformError(ctxt, NULL, cur,
1309 "xsl:variable : compilation failed\n");
1313 if (comp->name == NULL) {
1314 xsltTransformError(ctxt, NULL, cur,
1315 "xsl:variable : missing name attribute\n");
1319 #ifdef WITH_XSLT_DEBUG_VARIABLE
1320 xsltGenericDebug(xsltGenericDebugContext,
1321 "Registering variable %s\n", comp->name);
1324 xsltRegisterVariable(ctxt, comp, cur->children, 0);
1328 * xsltParseStylesheetParam:
1329 * @ctxt: the XSLT transformation context
1330 * @cur: the "param" element
1332 * parse an XSLT transformation param declaration and record
1337 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1338 xsltStylePreCompPtr comp;
1340 if ((cur == NULL) || (ctxt == NULL))
1343 comp = (xsltStylePreCompPtr) cur->_private;
1345 xsltTransformError(ctxt, NULL, cur,
1346 "xsl:param : compilation failed\n");
1350 if (comp->name == NULL) {
1351 xsltTransformError(ctxt, NULL, cur,
1352 "xsl:param : missing name attribute\n");
1356 #ifdef WITH_XSLT_DEBUG_VARIABLE
1357 xsltGenericDebug(xsltGenericDebugContext,
1358 "Registering param %s\n", comp->name);
1361 xsltRegisterVariable(ctxt, comp, cur->children, 1);
1365 * xsltFreeGlobalVariables:
1366 * @ctxt: the XSLT transformation context
1368 * Free up the data associated to the global variables
1373 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
1374 xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
1378 * xsltXPathVariableLookup:
1379 * @ctxt: a void * but the the XSLT transformation context actually
1380 * @name: the variable name
1381 * @ns_uri: the variable namespace URI
1383 * This is the entry point when a varibale is needed by the XPath
1386 * Returns the value or NULL if not found
1389 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
1390 const xmlChar *ns_uri) {
1391 xsltTransformContextPtr context;
1392 xmlXPathObjectPtr ret;
1394 if ((ctxt == NULL) || (name == NULL))
1397 #ifdef WITH_XSLT_DEBUG_VARIABLE
1398 xsltGenericDebug(xsltGenericDebugContext,
1399 "Lookup variable %s\n", name);
1401 context = (xsltTransformContextPtr) ctxt;
1402 ret = xsltVariableLookup(context, name, ns_uri);
1404 xsltTransformError(ctxt, NULL, NULL,
1405 "unregistered variable %s\n", name);
1407 #ifdef WITH_XSLT_DEBUG_VARIABLE
1409 xsltGenericDebug(xsltGenericDebugContext,
1410 "found variable %s\n", name);