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;
422 if ((ctxt == NULL) || (elem == NULL))
428 #ifdef WITH_XSLT_DEBUG_VARIABLE
429 xsltGenericDebug(xsltGenericDebugContext,
430 "Evaluating global variable %s\n", elem->name);
434 if ((xslDebugStatus != XSLT_DEBUG_NONE) &&
435 elem->comp && elem->comp->inst)
436 xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
440 elem->name = BAD_CAST " being computed ... ";
442 precomp = elem->comp;
443 if (elem->select != NULL) {
444 xmlXPathCompExprPtr comp = NULL;
446 if ((precomp != NULL) && (precomp->comp != NULL)) {
447 comp = precomp->comp;
449 comp = xmlXPathCompile(elem->select);
455 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
456 oldContextSize = ctxt->xpathCtxt->contextSize;
457 oldInst = ctxt->inst;
458 oldNsNr = ctxt->xpathCtxt->nsNr;
459 oldNamespaces = ctxt->xpathCtxt->namespaces;
460 if (precomp != NULL) {
461 ctxt->inst = precomp->inst;
462 ctxt->xpathCtxt->namespaces = precomp->nsList;
463 ctxt->xpathCtxt->nsNr = precomp->nsNr;
466 ctxt->xpathCtxt->namespaces = NULL;
467 ctxt->xpathCtxt->nsNr = 0;
469 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
470 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
471 ctxt->xpathCtxt->contextSize = oldContextSize;
472 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
473 ctxt->inst = oldInst;
474 ctxt->xpathCtxt->nsNr = oldNsNr;
475 ctxt->xpathCtxt->namespaces = oldNamespaces;
476 if ((precomp == NULL) || (precomp->comp == NULL))
477 xmlXPathFreeCompExpr(comp);
478 if (result == NULL) {
479 xsltTransformError(ctxt, NULL, precomp->inst,
480 "Evaluating global variable %s failed\n", elem->name);
481 ctxt->state = XSLT_STATE_STOPPED;
482 #ifdef WITH_XSLT_DEBUG_VARIABLE
483 #ifdef LIBXML_DEBUG_ENABLED
485 if ((xsltGenericDebugContext == stdout) ||
486 (xsltGenericDebugContext == stderr))
487 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
493 if (elem->tree == NULL) {
494 result = xmlXPathNewCString("");
497 * This is a result tree fragment.
499 xmlNodePtr container;
500 xmlNodePtr oldInsert;
503 container = xmlNewDocNode(ctxt->document->doc, NULL,
504 (const xmlChar *) " fake node libxslt", NULL);
505 if (container == NULL) {
509 container->parent = NULL;
511 oldoutput = ctxt->output;
513 oldInsert = ctxt->insert;
514 ctxt->insert = container;
515 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
516 ctxt->insert = oldInsert;
517 ctxt->output = oldoutput;
519 result = xmlXPathNewValueTree(container);
520 if (result == NULL) {
521 result = xmlXPathNewCString("");
524 * Tag the subtree for removal once consumed
528 #ifdef WITH_XSLT_DEBUG_VARIABLE
529 #ifdef LIBXML_DEBUG_ENABLED
530 if ((xsltGenericDebugContext == stdout) ||
531 (xsltGenericDebugContext == stderr))
532 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
538 if (result != NULL) {
539 elem->value = result;
547 * xsltEvalGlobalVariables:
548 * @ctxt: the XSLT transformation context
550 * Evaluate the global variables of a stylesheet. This need to be
551 * done on parsed stylesheets before starting to apply transformations
553 * Returns 0 in case of success, -1 in case of error
556 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
557 xsltStackElemPtr elem;
558 xsltStylesheetPtr style;
563 #ifdef WITH_XSLT_DEBUG_VARIABLE
564 xsltGenericDebug(xsltGenericDebugContext,
565 "Registering global variables\n");
567 ctxt->node = (xmlNodePtr) ctxt->document->doc;
568 ctxt->xpathCtxt->contextSize = 1;
569 ctxt->xpathCtxt->proximityPosition = 1;
572 * Walk the list from the stylesheets and populate the hash table
575 while (style != NULL) {
576 elem = style->variables;
578 #ifdef WITH_XSLT_DEBUG_VARIABLE
579 if ((style->doc != NULL) && (style->doc->URL != NULL)) {
580 xsltGenericDebug(xsltGenericDebugContext,
581 "Registering global variables from %s\n",
586 while (elem != NULL) {
587 xsltStackElemPtr def;
590 * Global variables are stored in the variables pool.
592 def = (xsltStackElemPtr)
593 xmlHashLookup2(ctxt->globalVars,
594 elem->name, elem->nameURI);
598 def = xsltCopyStackElem(elem);
599 res = xmlHashAddEntry2(ctxt->globalVars,
600 elem->name, elem->nameURI, def);
601 } else if ((elem->comp != NULL) &&
602 (elem->comp->type == XSLT_FUNC_VARIABLE)) {
604 * Redefinition of variables from a different stylesheet
605 * should not generate a message.
607 if ((elem->comp->inst != NULL) &&
608 (def->comp != NULL) && (def->comp->inst != NULL) &&
609 (elem->comp->inst->doc == def->comp->inst->doc)) {
610 xsltTransformError(ctxt, style, elem->comp->inst,
611 "Global variable %s already defined\n", elem->name);
612 if (style != NULL) style->errors++;
618 style = xsltNextImport(style);
622 * This part does the actual evaluation
624 ctxt->node = (xmlNodePtr) ctxt->document->doc;
625 ctxt->xpathCtxt->contextSize = 1;
626 ctxt->xpathCtxt->proximityPosition = 1;
627 xmlHashScan(ctxt->globalVars,
628 (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
634 * xsltRegisterGlobalVariable:
635 * @style: the XSLT transformation context
636 * @name: the variable name
637 * @ns_uri: the variable namespace URI
638 * @select: the expression which need to be evaluated to generate a value
639 * @tree: the subtree if select is NULL
640 * @comp: the precompiled value
641 * @value: the string value if available
643 * Register a new variable value. If @value is NULL it unregisters
646 * Returns 0 in case of success, -1 in case of error
649 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
650 const xmlChar *ns_uri, const xmlChar *select,
651 xmlNodePtr tree, xsltStylePreCompPtr comp,
652 const xmlChar *value) {
653 xsltStackElemPtr elem, tmp;
661 #ifdef WITH_XSLT_DEBUG_VARIABLE
662 if (comp->type == XSLT_FUNC_PARAM)
663 xsltGenericDebug(xsltGenericDebugContext,
664 "Defining global param %s\n", name);
666 xsltGenericDebug(xsltGenericDebugContext,
667 "Defining global variable %s\n", name);
670 elem = xsltNewStackElem();
674 elem->name = xmlStrdup(name);
675 elem->select = xmlStrdup(select);
677 elem->nameURI = xmlStrdup(ns_uri);
679 tmp = style->variables;
682 style->variables = elem;
684 while (tmp != NULL) {
685 if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
686 (tmp->comp->type == XSLT_FUNC_VARIABLE) &&
687 (xmlStrEqual(elem->name, tmp->name)) &&
688 ((elem->nameURI == tmp->nameURI) ||
689 (xmlStrEqual(elem->nameURI, tmp->nameURI)))) {
690 xsltTransformError(NULL, style, comp->inst,
691 "redefinition of global variable %s\n", elem->name);
692 if (style != NULL) style->errors++;
694 if (tmp->next == NULL)
703 elem->value = xmlXPathNewString(value);
709 * xsltProcessUserParamInternal
711 * @ctxt: the XSLT transformation context
712 * @name: a null terminated parameter name
713 * @value: a null terminated value (may be an XPath expression)
714 * @eval: 0 to treat the value literally, else evaluate as XPath expression
716 * If @eval is 0 then @value is treated literally and is stored in the global
717 * parameter/variable table without any change.
719 * Uf @eval is 1 then @value is treated as an XPath expression and is
720 * evaluated. In this case, if you want to pass a string which will be
721 * interpreted literally then it must be enclosed in single or double quotes.
722 * If the string contains single quotes (double quotes) then it cannot be
723 * enclosed single quotes (double quotes). If the string which you want to
724 * be treated literally contains both single and double quotes (e.g. Meet
725 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
726 * quoting character. You cannot use ' or " inside the string
727 * because the replacement of character entities with their equivalents is
728 * done at a different stage of processing. The solution is to call
729 * xsltQuoteUserParams or xsltQuoteOneUserParam.
731 * This needs to be done on parsed stylesheets before starting to apply
732 * transformations. Normally this will be called (directly or indirectly)
733 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
734 * or xsltQuoteOneUserParam.
736 * Returns 0 in case of success, -1 in case of error
741 xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
742 const xmlChar * name,
743 const xmlChar * value,
746 xsltStylesheetPtr style;
750 xmlXPathCompExprPtr comp;
751 xmlXPathObjectPtr result;
752 int oldProximityPosition;
755 xmlNsPtr *oldNamespaces;
756 xsltStackElemPtr elem;
768 #ifdef WITH_XSLT_DEBUG_VARIABLE
769 xsltGenericDebug(xsltGenericDebugContext,
770 "Evaluating user parameter %s=%s\n", name, value);
777 ncname = xmlSplitQName2(name, &prefix);
779 if (ncname != NULL) {
780 if (prefix != NULL) {
783 ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
786 xsltTransformError(ctxt, style, NULL,
787 "user param : no namespace bound to prefix %s\n", prefix);
801 ncname = xmlStrdup(name);
808 * Do the evaluation if @eval is non-zero.
813 comp = xmlXPathCompile(value);
815 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
816 oldContextSize = ctxt->xpathCtxt->contextSize;
817 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
820 * There is really no in scope namespace for parameters on the
824 oldNsNr = ctxt->xpathCtxt->nsNr;
825 oldNamespaces = ctxt->xpathCtxt->namespaces;
826 ctxt->xpathCtxt->namespaces = NULL;
827 ctxt->xpathCtxt->nsNr = 0;
828 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
829 ctxt->xpathCtxt->contextSize = oldContextSize;
830 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
831 ctxt->xpathCtxt->nsNr = oldNsNr;
832 ctxt->xpathCtxt->namespaces = oldNamespaces;
833 xmlXPathFreeCompExpr(comp);
835 if (result == NULL) {
836 xsltTransformError(ctxt, style, NULL,
837 "Evaluating user parameter %s failed\n", name);
838 ctxt->state = XSLT_STATE_STOPPED;
845 * If @eval is 0 then @value is to be taken literally and result is NULL
847 * If @eval is not 0, then @value is an XPath expression and has been
848 * successfully evaluated and result contains the resulting value and
851 * Now create an xsltStackElemPtr for insertion into the context's
852 * global variable/parameter hash table.
855 #ifdef WITH_XSLT_DEBUG_VARIABLE
856 #ifdef LIBXML_DEBUG_ENABLED
857 if ((xsltGenericDebugContext == stdout) ||
858 (xsltGenericDebugContext == stderr))
859 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
864 elem = xsltNewStackElem();
866 elem->name = xmlStrdup(ncname);
868 elem->select = xmlStrdup(value);
872 elem->nameURI = xmlStrdup(href);
876 elem->value = xmlXPathNewString(value);
879 elem->value = result;
884 * Global parameters are stored in the XPath context variables pool.
887 res = xmlHashAddEntry2(ctxt->globalVars, ncname, href, elem);
889 xsltFreeStackElem(elem);
890 xsltTransformError(ctxt, style, NULL,
891 "Global parameter %s already defined\n", ncname);
898 * xsltEvalUserParams:
900 * @ctxt: the XSLT transformation context
901 * @params: a NULL terminated array of parameters name/value tuples
903 * Evaluate the global variables of a stylesheet. This needs to be
904 * done on parsed stylesheets before starting to apply transformations.
905 * Each of the parameters is evaluated as an XPath expression and stored
906 * in the global variables/parameter hash table. If you want your
907 * parameter used literally, use xsltQuoteUserParams.
909 * Returns 0 in case of success, -1 in case of error
913 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
916 const xmlChar *value;
920 while (params[indx] != NULL) {
921 name = (const xmlChar *) params[indx++];
922 value = (const xmlChar *) params[indx++];
923 if (xsltEvalOneUserParam(ctxt, name, value) != 0)
930 * xsltQuoteUserParams:
932 * @ctxt: the XSLT transformation context
933 * @params: a NULL terminated arry of parameters names/values tuples
935 * Similar to xsltEvalUserParams, but the values are treated literally and
936 * are * *not* evaluated as XPath expressions. This should be done on parsed
937 * stylesheets before starting to apply transformations.
939 * Returns 0 in case of success, -1 in case of error.
943 xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
946 const xmlChar *value;
950 while (params[indx] != NULL) {
951 name = (const xmlChar *) params[indx++];
952 value = (const xmlChar *) params[indx++];
953 if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
960 * xsltEvalOneUserParam:
961 * @ctxt: the XSLT transformation context
962 * @name: a null terminated string giving the name of the parameter
963 * @value: a null terminated string giving the XPath expression to be evaluated
965 * This is normally called from xsltEvalUserParams to process a single
966 * parameter from a list of parameters. The @value is evaluated as an
967 * XPath expression and the result is stored in the context's global
968 * variable/parameter hash table.
970 * To have a parameter treated literally (not as an XPath expression)
971 * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
972 * details see description of xsltProcessOneUserParamInternal.
974 * Returns 0 in case of success, -1 in case of error.
978 xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
979 const xmlChar * name,
980 const xmlChar * value) {
981 return xsltProcessUserParamInternal(ctxt, name, value,
982 1 /* xpath eval ? */);
986 * xsltQuoteOneUserParam:
987 * @ctxt: the XSLT transformation context
988 * @name: a null terminated string giving the name of the parameter
989 * @value: a null terminated string giving the parameter value
991 * This is normally called from xsltQuoteUserParams to process a single
992 * parameter from a list of parameters. The @value is stored in the
993 * context's global variable/parameter hash table.
995 * Returns 0 in case of success, -1 in case of error.
999 xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
1000 const xmlChar * name,
1001 const xmlChar * value) {
1002 return xsltProcessUserParamInternal(ctxt, name, value,
1003 0 /* xpath eval ? */);
1007 * xsltBuildVariable:
1008 * @ctxt: the XSLT transformation context
1009 * @comp: the precompiled form
1010 * @tree: the tree if select is NULL
1012 * Computes a new variable value.
1014 * Returns the xsltStackElemPtr or NULL in case of error
1016 static xsltStackElemPtr
1017 xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1019 xsltStackElemPtr elem;
1021 #ifdef WITH_XSLT_DEBUG_VARIABLE
1022 xsltGenericDebug(xsltGenericDebugContext,
1023 "Building variable %s", comp->name);
1024 if (comp->select != NULL)
1025 xsltGenericDebug(xsltGenericDebugContext,
1026 " select %s", comp->select);
1027 xsltGenericDebug(xsltGenericDebugContext, "\n");
1030 elem = xsltNewStackElem();
1034 elem->name = xmlStrdup(comp->name);
1035 if (comp->select != NULL)
1036 elem->select = xmlStrdup(comp->select);
1038 elem->select = NULL;
1040 elem->nameURI = xmlStrdup(comp->ns);
1042 if (elem->computed == 0) {
1043 elem->value = xsltEvalVariable(ctxt, elem, comp);
1044 if (elem->value != NULL)
1051 * xsltRegisterVariable:
1052 * @ctxt: the XSLT transformation context
1053 * @comp: pointer to precompiled data
1054 * @tree: the tree if select is NULL
1055 * @param: this is a parameter actually
1057 * Computes and register a new variable value.
1059 * Returns 0 in case of success, -1 in case of error
1062 xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1063 xmlNodePtr tree, int param) {
1064 xsltStackElemPtr elem;
1067 present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
1069 if ((present != 0) && (present != 3)) {
1070 xsltTransformError(ctxt, NULL, comp->inst,
1071 "xsl:variable : redefining %s\n", comp->name);
1074 } else if (present != 0) {
1075 if ((present == 1) || (present == 2)) {
1076 xsltTransformError(ctxt, NULL, comp->inst,
1077 "xsl:param : redefining %s\n", comp->name);
1080 #ifdef WITH_XSLT_DEBUG_VARIABLE
1081 xsltGenericDebug(xsltGenericDebugContext,
1082 "param %s defined by caller\n", comp->name);
1086 elem = xsltBuildVariable(ctxt, comp, tree);
1087 xsltAddStackElem(ctxt, elem);
1092 * xsltGlobalVariableLookup:
1093 * @ctxt: the XSLT transformation context
1094 * @name: the variable name
1095 * @ns_uri: the variable namespace URI
1097 * Search in the Variable array of the context for the given
1100 * Returns the value or NULL if not found
1102 static xmlXPathObjectPtr
1103 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1104 const xmlChar *ns_uri) {
1105 xsltStackElemPtr elem;
1106 xmlXPathObjectPtr ret = NULL;
1109 * Lookup the global variables in XPath global variable hash table
1111 if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
1113 elem = (xsltStackElemPtr)
1114 xmlHashLookup2(ctxt->globalVars, name, ns_uri);
1116 #ifdef WITH_XSLT_DEBUG_VARIABLE
1117 xsltGenericDebug(xsltGenericDebugContext,
1118 "global variable not found %s\n", name);
1122 if (elem->computed == 0) {
1123 if (xmlStrEqual(elem->name, BAD_CAST " being computed ... ")) {
1124 xsltTransformError(ctxt, NULL, elem->comp->inst,
1125 "Recursive definition of %s\n", name);
1128 ret = xsltEvalGlobalVariable(elem, ctxt);
1131 return(xmlXPathObjectCopy(ret));
1135 * xsltVariableLookup:
1136 * @ctxt: the XSLT transformation context
1137 * @name: the variable name
1138 * @ns_uri: the variable namespace URI
1140 * Search in the Variable array of the context for the given
1143 * Returns the value or NULL if not found
1146 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1147 const xmlChar *ns_uri) {
1148 xsltStackElemPtr elem;
1153 elem = xsltStackLookup(ctxt, name, ns_uri);
1155 return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
1157 if (elem->computed == 0) {
1158 #ifdef WITH_XSLT_DEBUG_VARIABLE
1159 xsltGenericDebug(xsltGenericDebugContext,
1160 "uncomputed variable %s\n", name);
1162 elem->value = xsltEvalVariable(ctxt, elem, NULL);
1165 if (elem->value != NULL)
1166 return(xmlXPathObjectCopy(elem->value));
1167 #ifdef WITH_XSLT_DEBUG_VARIABLE
1168 xsltGenericDebug(xsltGenericDebugContext,
1169 "variable not found %s\n", name);
1175 * xsltParseStylesheetCallerParam:
1176 * @ctxt: the XSLT transformation context
1177 * @cur: the "param" element
1179 * parse an XSLT transformation param declaration, compute
1180 * its value but doesn't record it.
1182 * Returns the new xsltStackElemPtr or NULL
1186 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1187 xmlNodePtr tree = NULL;
1188 xsltStackElemPtr elem = NULL;
1189 xsltStylePreCompPtr comp;
1191 if ((cur == NULL) || (ctxt == NULL))
1193 comp = (xsltStylePreCompPtr) cur->_private;
1195 xsltTransformError(ctxt, NULL, cur,
1196 "xsl:param : compilation error\n");
1200 if (comp->name == NULL) {
1201 xsltTransformError(ctxt, NULL, cur,
1202 "xsl:param : missing name attribute\n");
1206 #ifdef WITH_XSLT_DEBUG_VARIABLE
1207 xsltGenericDebug(xsltGenericDebugContext,
1208 "Handling param %s\n", comp->name);
1211 if (comp->select == NULL) {
1212 tree = cur->children;
1214 #ifdef WITH_XSLT_DEBUG_VARIABLE
1215 xsltGenericDebug(xsltGenericDebugContext,
1216 " select %s\n", comp->select);
1221 elem = xsltBuildVariable(ctxt, comp, tree);
1227 * xsltParseGlobalVariable:
1228 * @style: the XSLT stylesheet
1229 * @cur: the "variable" element
1231 * parse an XSLT transformation variable declaration and record
1236 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
1237 xsltStylePreCompPtr comp;
1239 if ((cur == NULL) || (style == NULL))
1242 xsltStylePreCompute(style, cur);
1243 comp = (xsltStylePreCompPtr) cur->_private;
1245 xsltTransformError(NULL, style, cur,
1246 "xsl:variable : compilation failed\n");
1250 if (comp->name == NULL) {
1251 xsltTransformError(NULL, style, cur,
1252 "xsl:variable : missing name attribute\n");
1256 #ifdef WITH_XSLT_DEBUG_VARIABLE
1257 xsltGenericDebug(xsltGenericDebugContext,
1258 "Registering global variable %s\n", comp->name);
1261 xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1262 cur->children, comp, NULL);
1266 * xsltParseGlobalParam:
1267 * @style: the XSLT stylesheet
1268 * @cur: the "param" element
1270 * parse an XSLT transformation param declaration and record
1275 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
1276 xsltStylePreCompPtr comp;
1278 if ((cur == NULL) || (style == NULL))
1281 xsltStylePreCompute(style, cur);
1282 comp = (xsltStylePreCompPtr) cur->_private;
1284 xsltTransformError(NULL, style, cur,
1285 "xsl:param : compilation failed\n");
1289 if (comp->name == NULL) {
1290 xsltTransformError(NULL, style, cur,
1291 "xsl:param : missing name attribute\n");
1295 #ifdef WITH_XSLT_DEBUG_VARIABLE
1296 xsltGenericDebug(xsltGenericDebugContext,
1297 "Registering global param %s\n", comp->name);
1300 xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1301 cur->children, comp, NULL);
1305 * xsltParseStylesheetVariable:
1306 * @ctxt: the XSLT transformation context
1307 * @cur: the "variable" element
1309 * parse an XSLT transformation variable declaration and record
1314 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1315 xsltStylePreCompPtr comp;
1317 if ((cur == NULL) || (ctxt == NULL))
1320 comp = (xsltStylePreCompPtr) cur->_private;
1322 xsltTransformError(ctxt, NULL, cur,
1323 "xsl:variable : compilation failed\n");
1327 if (comp->name == NULL) {
1328 xsltTransformError(ctxt, NULL, cur,
1329 "xsl:variable : missing name attribute\n");
1333 #ifdef WITH_XSLT_DEBUG_VARIABLE
1334 xsltGenericDebug(xsltGenericDebugContext,
1335 "Registering variable %s\n", comp->name);
1338 xsltRegisterVariable(ctxt, comp, cur->children, 0);
1342 * xsltParseStylesheetParam:
1343 * @ctxt: the XSLT transformation context
1344 * @cur: the "param" element
1346 * parse an XSLT transformation param declaration and record
1351 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1352 xsltStylePreCompPtr comp;
1354 if ((cur == NULL) || (ctxt == NULL))
1357 comp = (xsltStylePreCompPtr) cur->_private;
1359 xsltTransformError(ctxt, NULL, cur,
1360 "xsl:param : compilation failed\n");
1364 if (comp->name == NULL) {
1365 xsltTransformError(ctxt, NULL, cur,
1366 "xsl:param : missing name attribute\n");
1370 #ifdef WITH_XSLT_DEBUG_VARIABLE
1371 xsltGenericDebug(xsltGenericDebugContext,
1372 "Registering param %s\n", comp->name);
1375 xsltRegisterVariable(ctxt, comp, cur->children, 1);
1379 * xsltFreeGlobalVariables:
1380 * @ctxt: the XSLT transformation context
1382 * Free up the data associated to the global variables
1387 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
1388 xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
1392 * xsltXPathVariableLookup:
1393 * @ctxt: a void * but the the XSLT transformation context actually
1394 * @name: the variable name
1395 * @ns_uri: the variable namespace URI
1397 * This is the entry point when a varibale is needed by the XPath
1400 * Returns the value or NULL if not found
1403 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
1404 const xmlChar *ns_uri) {
1405 xsltTransformContextPtr context;
1406 xmlXPathObjectPtr ret;
1408 if ((ctxt == NULL) || (name == NULL))
1411 #ifdef WITH_XSLT_DEBUG_VARIABLE
1412 xsltGenericDebug(xsltGenericDebugContext,
1413 "Lookup variable %s\n", name);
1415 context = (xsltTransformContextPtr) ctxt;
1416 ret = xsltVariableLookup(context, name, ns_uri);
1418 xsltTransformError(ctxt, NULL, NULL,
1419 "unregistered variable %s\n", name);
1421 #ifdef WITH_XSLT_DEBUG_VARIABLE
1423 xsltGenericDebug(xsltGenericDebugContext,
1424 "found variable %s\n", name);