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 xsltPrintErrorContext(NULL, NULL, NULL);
57 xsltGenericError(xsltGenericErrorContext,
58 "xsltNewStackElem : malloc failed\n");
73 * @elem: an XSLT stack element
75 * Makes a copy of the stack element
77 * Returns the copy of NULL
79 static xsltStackElemPtr
80 xsltCopyStackElem(xsltStackElemPtr elem) {
83 cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
85 xsltPrintErrorContext(NULL, NULL, NULL);
86 xsltGenericError(xsltGenericErrorContext,
87 "xsltCopyStackElem : malloc failed\n");
90 cur->name = xmlStrdup(elem->name);
91 cur->nameURI = xmlStrdup(elem->nameURI);
92 cur->select = xmlStrdup(elem->select);
93 cur->tree = elem->tree;
94 cur->comp = elem->comp;
102 * @elem: an XSLT stack element
104 * Free up the memory allocated by @elem
107 xsltFreeStackElem(xsltStackElemPtr elem) {
110 if (elem->name != NULL)
112 if (elem->nameURI != NULL)
113 xmlFree(elem->nameURI);
114 if (elem->select != NULL)
115 xmlFree(elem->select);
116 if (elem->value != NULL)
117 xmlXPathFreeObject(elem->value);
123 * xsltFreeStackElemList:
124 * @elem: an XSLT stack element
126 * Free up the memory allocated by @elem
129 xsltFreeStackElemList(xsltStackElemPtr elem) {
130 xsltStackElemPtr next;
132 while(elem != NULL) {
134 xsltFreeStackElem(elem);
140 * xsltCheckStackElem:
141 * @ctxt: xn XSLT transformation context
142 * @name: the variable name
143 * @nameURI: the variable namespace URI
145 * check wether the variable or param is already defined
147 * Returns 1 if present, 0 if not, -1 in case of failure.
150 xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
151 const xmlChar *nameURI) {
152 xsltStackElemPtr cur;
154 if ((ctxt == NULL) || (name == NULL))
158 while (cur != NULL) {
159 if (xmlStrEqual(name, cur->name)) {
160 if (((nameURI == NULL) && (cur->nameURI == NULL)) ||
161 ((nameURI != NULL) && (cur->nameURI != NULL) &&
162 (xmlStrEqual(nameURI, cur->nameURI)))) {
173 * @ctxt: xn XSLT transformation context
174 * @elem: a stack element
176 * add a new element at this level of the stack.
178 * Returns 0 in case of success, -1 in case of failure.
181 xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
182 if ((ctxt == NULL) || (elem == NULL))
185 elem->next = ctxt->varsTab[ctxt->varsNr - 1];
186 ctxt->varsTab[ctxt->varsNr - 1] = elem;
192 * xsltAddStackElemList:
193 * @ctxt: xn XSLT transformation context
194 * @elems: a stack element list
196 * add the new element list at this level of the stack.
198 * Returns 0 in case of success, -1 in case of failure.
201 xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) {
202 xsltStackElemPtr cur;
204 if ((ctxt == NULL) || (elems == NULL))
207 /* TODO: check doublons */
208 if (ctxt->varsTab[ctxt->varsNr - 1] != NULL) {
209 cur = ctxt->varsTab[ctxt->varsNr - 1];
210 while (cur->next != NULL)
214 elems->next = ctxt->varsTab[ctxt->varsNr - 1];
215 ctxt->varsTab[ctxt->varsNr - 1] = elems;
223 * @ctxt: an XSLT transformation context
224 * @name: the local part of the name
225 * @nameURI: the URI part of the name
227 * Locate an element in the stack based on its name.
229 static xsltStackElemPtr
230 xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
231 const xmlChar *nameURI) {
232 xsltStackElemPtr ret = NULL;
234 xsltStackElemPtr cur;
236 if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
240 * Do the lookup from the top of the stack, but
241 * don't use params being computed in a call-param
245 for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
246 cur = ctxt->varsTab[i-1];
247 while (cur != NULL) {
248 if (xmlStrEqual(cur->name, name)) {
249 if (nameURI == NULL) {
250 if (cur->nameURI == NULL) {
254 if ((cur->nameURI != NULL) &&
255 (xmlStrEqual(cur->nameURI, nameURI))) {
267 /************************************************************************
269 * Module interfaces *
271 ************************************************************************/
275 * @ctxt: the XSLT transformation context
276 * @elem: the variable or parameter.
277 * @precomp: pointer to precompiled data
279 * Evaluate a variable value.
281 * Returns the XPath Object value or NULL in case of error
283 static xmlXPathObjectPtr
284 xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
285 xsltStylePreCompPtr precomp) {
286 xmlXPathObjectPtr result = NULL;
287 int oldProximityPosition, oldContextSize;
288 xmlNodePtr oldInst, oldNode;
289 xsltDocumentPtr oldDoc;
291 xmlNsPtr *oldNamespaces;
293 if ((ctxt == NULL) || (elem == NULL))
296 #ifdef WITH_XSLT_DEBUG_VARIABLE
297 xsltGenericDebug(xsltGenericDebugContext,
298 "Evaluating variable %s\n", elem->name);
300 if (elem->select != NULL) {
301 xmlXPathCompExprPtr comp = NULL;
303 if ((precomp != NULL) && (precomp->comp != NULL)) {
304 comp = precomp->comp;
306 comp = xmlXPathCompile(elem->select);
310 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
311 oldContextSize = ctxt->xpathCtxt->contextSize;
312 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
313 oldDoc = ctxt->document;
314 oldNode = ctxt->node;
315 oldInst = ctxt->inst;
316 oldNsNr = ctxt->xpathCtxt->nsNr;
317 oldNamespaces = ctxt->xpathCtxt->namespaces;
318 if (precomp != NULL) {
319 ctxt->inst = precomp->inst;
320 ctxt->xpathCtxt->namespaces = precomp->nsList;
321 ctxt->xpathCtxt->nsNr = precomp->nsNr;
324 ctxt->xpathCtxt->namespaces = NULL;
325 ctxt->xpathCtxt->nsNr = 0;
327 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
328 ctxt->xpathCtxt->contextSize = oldContextSize;
329 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
330 ctxt->xpathCtxt->nsNr = oldNsNr;
331 ctxt->xpathCtxt->namespaces = oldNamespaces;
332 ctxt->inst = oldInst;
333 ctxt->node = oldNode;
334 ctxt->document = oldDoc;
335 if ((precomp == NULL) || (precomp->comp == NULL))
336 xmlXPathFreeCompExpr(comp);
337 if (result == NULL) {
338 xsltPrintErrorContext(ctxt, NULL, precomp->inst);
339 xsltGenericError(xsltGenericErrorContext,
340 "Evaluating variable %s failed\n", elem->name);
341 ctxt->state = XSLT_STATE_STOPPED;
342 #ifdef WITH_XSLT_DEBUG_VARIABLE
343 #ifdef LIBXML_DEBUG_ENABLED
345 if ((xsltGenericDebugContext == stdout) ||
346 (xsltGenericDebugContext == stderr))
347 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
353 if (elem->tree == NULL) {
354 result = xmlXPathNewCString("");
357 * This is a result tree fragment.
359 xmlNodePtr container;
360 xmlNodePtr oldInsert;
363 container = xmlNewDocNode(ctxt->document->doc, NULL,
364 (const xmlChar *) "fake node libxslt", NULL);
365 if (container == NULL)
367 container->parent = NULL;
369 oldoutput = ctxt->output;
371 oldInsert = ctxt->insert;
372 ctxt->insert = container;
373 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
374 ctxt->insert = oldInsert;
375 ctxt->output = oldoutput;
377 result = xmlXPathNewValueTree(container);
378 if (result == NULL) {
379 result = xmlXPathNewCString("");
382 * Tag the subtree for removal once consumed
386 #ifdef WITH_XSLT_DEBUG_VARIABLE
387 #ifdef LIBXML_DEBUG_ENABLED
388 if ((xsltGenericDebugContext == stdout) ||
389 (xsltGenericDebugContext == stderr))
390 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
400 * xsltEvalGlobalVariable:
401 * @elem: the variable or parameter.
402 * @ctxt: the XSLT transformation context
404 * Evaluate a global variable value.
406 * Returns the XPath Object value or NULL in case of error
408 static xmlXPathObjectPtr
409 xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
410 xmlXPathObjectPtr result = NULL;
411 xsltStylePreCompPtr precomp;
412 int oldProximityPosition, oldContextSize;
415 xmlNsPtr *oldNamespaces;
417 if ((ctxt == NULL) || (elem == NULL))
423 #ifdef WITH_XSLT_DEBUG_VARIABLE
424 xsltGenericDebug(xsltGenericDebugContext,
425 "Evaluating global variable %s\n", elem->name);
429 if ((xslDebugStatus != XSLT_DEBUG_NONE) &&
430 elem->comp && elem->comp->inst)
431 xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
434 precomp = elem->comp;
435 if (elem->select != NULL) {
436 xmlXPathCompExprPtr comp = NULL;
438 if ((precomp != NULL) && (precomp->comp != NULL)) {
439 comp = precomp->comp;
441 comp = xmlXPathCompile(elem->select);
445 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
446 oldContextSize = ctxt->xpathCtxt->contextSize;
447 oldInst = ctxt->inst;
448 oldNsNr = ctxt->xpathCtxt->nsNr;
449 oldNamespaces = ctxt->xpathCtxt->namespaces;
450 if (precomp != NULL) {
451 ctxt->inst = precomp->inst;
452 ctxt->xpathCtxt->namespaces = precomp->nsList;
453 ctxt->xpathCtxt->nsNr = precomp->nsNr;
456 ctxt->xpathCtxt->namespaces = NULL;
457 ctxt->xpathCtxt->nsNr = 0;
459 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
460 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
461 ctxt->xpathCtxt->contextSize = oldContextSize;
462 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
463 ctxt->inst = oldInst;
464 ctxt->xpathCtxt->nsNr = oldNsNr;
465 ctxt->xpathCtxt->namespaces = oldNamespaces;
466 if ((precomp == NULL) || (precomp->comp == NULL))
467 xmlXPathFreeCompExpr(comp);
468 if (result == NULL) {
469 xsltPrintErrorContext(ctxt, NULL, precomp->inst);
470 xsltGenericError(xsltGenericErrorContext,
471 "Evaluating global variable %s failed\n", elem->name);
472 ctxt->state = XSLT_STATE_STOPPED;
473 #ifdef WITH_XSLT_DEBUG_VARIABLE
474 #ifdef LIBXML_DEBUG_ENABLED
476 if ((xsltGenericDebugContext == stdout) ||
477 (xsltGenericDebugContext == stderr))
478 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
484 if (elem->tree == NULL) {
485 result = xmlXPathNewCString("");
488 * This is a result tree fragment.
490 xmlNodePtr container;
491 xmlNodePtr oldInsert;
494 container = xmlNewDocNode(ctxt->document->doc, NULL,
495 (const xmlChar *) "fake node libxslt", NULL);
496 if (container == NULL)
498 container->parent = NULL;
500 oldoutput = ctxt->output;
502 oldInsert = ctxt->insert;
503 ctxt->insert = container;
504 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
505 ctxt->insert = oldInsert;
506 ctxt->output = oldoutput;
508 result = xmlXPathNewValueTree(container);
509 if (result == NULL) {
510 result = xmlXPathNewCString("");
513 * Tag the subtree for removal once consumed
517 #ifdef WITH_XSLT_DEBUG_VARIABLE
518 #ifdef LIBXML_DEBUG_ENABLED
519 if ((xsltGenericDebugContext == stdout) ||
520 (xsltGenericDebugContext == stderr))
521 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
527 if (result != NULL) {
528 elem->value = result;
535 * xsltEvalGlobalVariables:
536 * @ctxt: the XSLT transformation context
538 * Evaluate the global variables of a stylesheet. This need to be
539 * done on parsed stylesheets before starting to apply transformations
541 * Returns 0 in case of success, -1 in case of error
544 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
545 xsltStackElemPtr elem;
546 xsltStylesheetPtr style;
551 #ifdef WITH_XSLT_DEBUG_VARIABLE
552 xsltGenericDebug(xsltGenericDebugContext,
553 "Registering global variables\n");
555 ctxt->node = (xmlNodePtr) ctxt->document->doc;
556 ctxt->xpathCtxt->contextSize = 1;
557 ctxt->xpathCtxt->proximityPosition = 1;
560 * Walk the list from the stylesheets and populate the hash table
563 while (style != NULL) {
564 elem = style->variables;
566 #ifdef WITH_XSLT_DEBUG_VARIABLE
567 if ((style->doc != NULL) && (style->doc->URL != NULL)) {
568 xsltGenericDebug(xsltGenericDebugContext,
569 "Registering global variables from %s\n",
574 while (elem != NULL) {
575 xsltStackElemPtr def;
578 * Global variables are stored in the variables pool.
580 def = (xsltStackElemPtr)
581 xmlHashLookup2(ctxt->globalVars,
582 elem->name, elem->nameURI);
586 def = xsltCopyStackElem(elem);
587 res = xmlHashAddEntry2(ctxt->globalVars,
588 elem->name, elem->nameURI, def);
589 } else if ((elem->comp != NULL) &&
590 (elem->comp->type == XSLT_FUNC_VARIABLE)) {
592 * Redefinition of variables from a different stylesheet
593 * should not generate a message.
595 if ((elem->comp->inst != NULL) &&
596 (def->comp != NULL) && (def->comp->inst != NULL) &&
597 (elem->comp->inst->doc == def->comp->inst->doc)) {
598 xsltPrintErrorContext(ctxt, style, elem->comp->inst);
599 xsltGenericError(xsltGenericErrorContext,
600 "Global variable %s already defined\n", elem->name);
606 style = xsltNextImport(style);
610 * This part does the actual evaluation
612 ctxt->node = (xmlNodePtr) ctxt->document->doc;
613 ctxt->xpathCtxt->contextSize = 1;
614 ctxt->xpathCtxt->proximityPosition = 1;
615 xmlHashScan(ctxt->globalVars,
616 (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
622 * xsltRegisterGlobalVariable:
623 * @style: the XSLT transformation context
624 * @name: the variable name
625 * @ns_uri: the variable namespace URI
626 * @select: the expression which need to be evaluated to generate a value
627 * @tree: the subtree if select is NULL
628 * @comp: the precompiled value
629 * @value: the string value if available
631 * Register a new variable value. If @value is NULL it unregisters
634 * Returns 0 in case of success, -1 in case of error
637 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
638 const xmlChar *ns_uri, const xmlChar *select,
639 xmlNodePtr tree, xsltStylePreCompPtr comp,
640 const xmlChar *value) {
641 xsltStackElemPtr elem, tmp;
649 #ifdef WITH_XSLT_DEBUG_VARIABLE
650 if (comp->type == XSLT_FUNC_PARAM)
651 xsltGenericDebug(xsltGenericDebugContext,
652 "Defining global param %s\n", name);
654 xsltGenericDebug(xsltGenericDebugContext,
655 "Defining global variable %s\n", name);
658 elem = xsltNewStackElem();
662 elem->name = xmlStrdup(name);
663 elem->select = xmlStrdup(select);
665 elem->nameURI = xmlStrdup(ns_uri);
667 tmp = style->variables;
670 style->variables = elem;
672 while (tmp->next != NULL)
679 elem->value = xmlXPathNewString(value);
685 * xsltProcessUserParamInternal
687 * @ctxt: the XSLT transformation context
688 * @name: a null terminated parameter name
689 * @value: a null terminated value (may be an XPath expression)
690 * @eval: 0 to treat the value literally, else evaluate as XPath expression
692 * If @eval is 0 then @value is treated literally and is stored in the global
693 * parameter/variable table without any change.
695 * Uf @eval is 1 then @value is treated as an XPath expression and is
696 * evaluated. In this case, if you want to pass a string which will be
697 * interpreted literally then it must be enclosed in single or double quotes.
698 * If the string contains single quotes (double quotes) then it cannot be
699 * enclosed single quotes (double quotes). If the string which you want to
700 * be treated literally contains both single and double quotes (e.g. Meet
701 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
702 * quoting character. You cannot use ' or " inside the string
703 * because the replacement of character entities with their equivalents is
704 * done at a different stage of processing. The solution is to call
705 * xsltQuoteUserParams or xsltQuoteOneUserParam.
707 * This needs to be done on parsed stylesheets before starting to apply
708 * transformations. Normally this will be called (directly or indirectly)
709 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
710 * or xsltQuoteOneUserParam.
712 * Returns 0 in case of success, -1 in case of error
717 xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
718 const xmlChar * name,
719 const xmlChar * value,
722 xsltStylesheetPtr style;
726 xmlXPathCompExprPtr comp;
727 xmlXPathObjectPtr result;
728 int oldProximityPosition;
731 xmlNsPtr *oldNamespaces;
732 xsltStackElemPtr elem;
744 #ifdef WITH_XSLT_DEBUG_VARIABLE
745 xsltGenericDebug(xsltGenericDebugContext,
746 "Evaluating user parameter %s=%s\n", name, value);
753 ncname = xmlSplitQName2(name, &prefix);
755 if (ncname != NULL) {
756 if (prefix != NULL) {
759 ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
762 xsltPrintErrorContext(ctxt, style, NULL);
763 xsltGenericError(xsltGenericErrorContext,
764 "user param : no namespace bound to prefix %s\n", prefix);
778 ncname = xmlStrdup(name);
782 * Do the evaluation if @eval is non-zero.
787 comp = xmlXPathCompile(value);
789 oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
790 oldContextSize = ctxt->xpathCtxt->contextSize;
791 ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
794 * There is really no in scope namespace for parameters on the
798 oldNsNr = ctxt->xpathCtxt->nsNr;
799 oldNamespaces = ctxt->xpathCtxt->namespaces;
800 ctxt->xpathCtxt->namespaces = NULL;
801 ctxt->xpathCtxt->nsNr = 0;
802 result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
803 ctxt->xpathCtxt->contextSize = oldContextSize;
804 ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
805 ctxt->xpathCtxt->nsNr = oldNsNr;
806 ctxt->xpathCtxt->namespaces = oldNamespaces;
807 xmlXPathFreeCompExpr(comp);
809 if (result == NULL) {
810 xsltPrintErrorContext(ctxt, style, NULL);
811 xsltGenericError(xsltGenericErrorContext,
812 "Evaluating user parameter %s failed\n", name);
813 ctxt->state = XSLT_STATE_STOPPED;
820 * If @eval is 0 then @value is to be taken literally and result is NULL
822 * If @eval is not 0, then @value is an XPath expression and has been
823 * successfully evaluated and result contains the resulting value and
826 * Now create an xsltStackElemPtr for insertion into the context's
827 * global variable/parameter hash table.
830 #ifdef WITH_XSLT_DEBUG_VARIABLE
831 #ifdef LIBXML_DEBUG_ENABLED
832 if ((xsltGenericDebugContext == stdout) ||
833 (xsltGenericDebugContext == stderr))
834 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
839 elem = xsltNewStackElem();
841 elem->name = xmlStrdup(ncname);
843 elem->select = xmlStrdup(value);
847 elem->nameURI = xmlStrdup(href);
851 elem->value = xmlXPathNewString(value);
854 elem->value = result;
859 * Global parameters are stored in the XPath context variables pool.
862 res = xmlHashAddEntry2(ctxt->globalVars, ncname, href, elem);
864 xsltFreeStackElem(elem);
865 xsltPrintErrorContext(ctxt, style, NULL);
866 xsltGenericError(xsltGenericErrorContext,
867 "Global parameter %s already defined\n", ncname);
874 * xsltEvalUserParams:
876 * @ctxt: the XSLT transformation context
877 * @params: a NULL terminated array of parameters name/value tuples
879 * Evaluate the global variables of a stylesheet. This needs to be
880 * done on parsed stylesheets before starting to apply transformations.
881 * Each of the parameters is evaluated as an XPath expression and stored
882 * in the global variables/parameter hash table. If you want your
883 * parameter used literally, use xsltQuoteUserParams.
885 * Returns 0 in case of success, -1 in case of error
889 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
892 const xmlChar *value;
896 while (params[indx] != NULL) {
897 name = (const xmlChar *) params[indx++];
898 value = (const xmlChar *) params[indx++];
899 if (xsltEvalOneUserParam(ctxt, name, value) != 0)
906 * xsltQuoteUserParams:
908 * @ctxt: the XSLT transformation context
909 * @params: a NULL terminated arry of parameters names/values tuples
911 * Similar to xsltEvalUserParams, but the values are treated literally and
912 * are * *not* evaluated as XPath expressions. This should be done on parsed
913 * stylesheets before starting to apply transformations.
915 * Returns 0 in case of success, -1 in case of error.
919 xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
922 const xmlChar *value;
926 while (params[indx] != NULL) {
927 name = (const xmlChar *) params[indx++];
928 value = (const xmlChar *) params[indx++];
929 if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
936 * xsltEvalOneUserParam:
938 * @ctxt: the XSLT transformation context
939 * @name: a null terminated string giving the name of the parameter
940 * @value a null terminated string giving the XPath expression to be evaluated
942 * This is normally called from xsltEvalUserParams to process a single
943 * parameter from a list of parameters. The @value is evaluated as an
944 * XPath expression and the result is stored in the context's global
945 * variable/parameter hash table.
947 * To have a parameter treated literally (not as an XPath expression)
948 * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
949 * details see description of xsltProcessOneUserParamInternal.
951 * Returns 0 in case of success, -1 in case of error.
955 xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
956 const xmlChar * name,
957 const xmlChar * value) {
958 return xsltProcessUserParamInternal(ctxt, name, value,
959 1 /* xpath eval ? */);
963 * xsltQuoteOneUserParam:
965 * @ctxt: the XSLT transformation context
966 * @name: a null terminated string giving the name of the parameter
967 * @value a null terminated string giving the parameter value
969 * This is normally called from xsltQuoteUserParams to process a single
970 * parameter from a list of parameters. The @value is stored in the
971 * context's global variable/parameter hash table.
973 * Returns 0 in case of success, -1 in case of error.
977 xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
978 const xmlChar * name,
979 const xmlChar * value) {
980 return xsltProcessUserParamInternal(ctxt, name, value,
981 0 /* xpath eval ? */);
986 * @ctxt: the XSLT transformation context
987 * @comp: the precompiled form
988 * @tree: the tree if select is NULL
990 * Computes a new variable value.
992 * Returns the xsltStackElemPtr or NULL in case of error
994 static xsltStackElemPtr
995 xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
997 xsltStackElemPtr elem;
999 #ifdef WITH_XSLT_DEBUG_VARIABLE
1000 xsltGenericDebug(xsltGenericDebugContext,
1001 "Building variable %s", comp->name);
1002 if (comp->select != NULL)
1003 xsltGenericDebug(xsltGenericDebugContext,
1004 " select %s", comp->select);
1005 xsltGenericDebug(xsltGenericDebugContext, "\n");
1008 elem = xsltNewStackElem();
1012 elem->name = xmlStrdup(comp->name);
1013 if (comp->select != NULL)
1014 elem->select = xmlStrdup(comp->select);
1016 elem->select = NULL;
1018 elem->nameURI = xmlStrdup(comp->ns);
1020 if (elem->computed == 0) {
1021 elem->value = xsltEvalVariable(ctxt, elem, comp);
1022 if (elem->value != NULL)
1029 * xsltRegisterVariable:
1030 * @ctxt: the XSLT transformation context
1031 * @comp: pointer to precompiled data
1032 * @tree: the tree if select is NULL
1033 * @param: this is a parameter actually
1035 * Computes and register a new variable value.
1037 * Returns 0 in case of success, -1 in case of error
1040 xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1041 xmlNodePtr tree, int param) {
1042 xsltStackElemPtr elem;
1044 if (xsltCheckStackElem(ctxt, comp->name, comp->ns) != 0) {
1046 xsltPrintErrorContext(ctxt, NULL, comp->inst);
1047 xsltGenericError(xsltGenericErrorContext,
1048 "xsl:variable : redefining %s\n", comp->name);
1050 #ifdef WITH_XSLT_DEBUG_VARIABLE
1052 xsltGenericDebug(xsltGenericDebugContext,
1053 "param %s defined by caller\n", comp->name);
1057 elem = xsltBuildVariable(ctxt, comp, tree);
1058 xsltAddStackElem(ctxt, elem);
1063 * xsltGlobalVariableLookup:
1064 * @ctxt: the XSLT transformation context
1065 * @name: the variable name
1066 * @ns_uri: the variable namespace URI
1068 * Search in the Variable array of the context for the given
1071 * Returns the value or NULL if not found
1073 static xmlXPathObjectPtr
1074 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1075 const xmlChar *ns_uri) {
1076 xsltStackElemPtr elem;
1077 xmlXPathObjectPtr ret = NULL;
1080 * Lookup the global variables in XPath global variable hash table
1082 if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
1084 elem = (xsltStackElemPtr)
1085 xmlHashLookup2(ctxt->globalVars, name, ns_uri);
1087 #ifdef WITH_XSLT_DEBUG_VARIABLE
1088 xsltGenericDebug(xsltGenericDebugContext,
1089 "global variable not found %s\n", name);
1093 if (elem->computed == 0)
1094 ret = xsltEvalGlobalVariable(elem, ctxt);
1097 return(xmlXPathObjectCopy(ret));
1101 * xsltVariableLookup:
1102 * @ctxt: the XSLT transformation context
1103 * @name: the variable name
1104 * @ns_uri: the variable namespace URI
1106 * Search in the Variable array of the context for the given
1109 * Returns the value or NULL if not found
1112 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1113 const xmlChar *ns_uri) {
1114 xsltStackElemPtr elem;
1119 elem = xsltStackLookup(ctxt, name, ns_uri);
1121 return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
1123 if (elem->computed == 0) {
1124 #ifdef WITH_XSLT_DEBUG_VARIABLE
1125 xsltGenericDebug(xsltGenericDebugContext,
1126 "uncomputed variable %s\n", name);
1128 elem->value = xsltEvalVariable(ctxt, elem, NULL);
1131 if (elem->value != NULL)
1132 return(xmlXPathObjectCopy(elem->value));
1133 #ifdef WITH_XSLT_DEBUG_VARIABLE
1134 xsltGenericDebug(xsltGenericDebugContext,
1135 "variable not found %s\n", name);
1141 * xsltParseStylesheetCallerParam:
1142 * @ctxt: the XSLT transformation context
1143 * @cur: the "param" element
1145 * parse an XSLT transformation param declaration, compute
1146 * its value but doesn't record it.
1148 * It returns the new xsltStackElemPtr or NULL
1152 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1153 xmlNodePtr tree = NULL;
1154 xsltStackElemPtr elem = NULL;
1155 xsltStylePreCompPtr comp;
1157 if ((cur == NULL) || (ctxt == NULL))
1159 comp = (xsltStylePreCompPtr) cur->_private;
1161 xsltPrintErrorContext(ctxt, NULL, cur);
1162 xsltGenericError(xsltGenericErrorContext,
1163 "xsl:param : compilation error\n");
1167 if (comp->name == NULL) {
1168 xsltPrintErrorContext(ctxt, NULL, cur);
1169 xsltGenericError(xsltGenericErrorContext,
1170 "xsl:param : missing name attribute\n");
1174 #ifdef WITH_XSLT_DEBUG_VARIABLE
1175 xsltGenericDebug(xsltGenericDebugContext,
1176 "Handling param %s\n", comp->name);
1179 if (comp->select == NULL) {
1180 tree = cur->children;
1182 #ifdef WITH_XSLT_DEBUG_VARIABLE
1183 xsltGenericDebug(xsltGenericDebugContext,
1184 " select %s\n", comp->select);
1189 elem = xsltBuildVariable(ctxt, comp, tree);
1195 * xsltParseGlobalVariable:
1196 * @style: the XSLT stylesheet
1197 * @cur: the "variable" element
1199 * parse an XSLT transformation variable declaration and record
1204 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
1205 xsltStylePreCompPtr comp;
1207 if ((cur == NULL) || (style == NULL))
1210 xsltStylePreCompute(style, cur);
1211 comp = (xsltStylePreCompPtr) cur->_private;
1213 xsltPrintErrorContext(NULL, style, cur);
1214 xsltGenericError(xsltGenericErrorContext,
1215 "xsl:variable : compilation failed\n");
1219 if (comp->name == NULL) {
1220 xsltPrintErrorContext(NULL, style, cur);
1221 xsltGenericError(xsltGenericErrorContext,
1222 "xsl:variable : missing name attribute\n");
1226 #ifdef WITH_XSLT_DEBUG_VARIABLE
1227 xsltGenericDebug(xsltGenericDebugContext,
1228 "Registering global variable %s\n", comp->name);
1231 xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1232 cur->children, comp, NULL);
1236 * xsltParseGlobalParam:
1237 * @style: the XSLT stylesheet
1238 * @cur: the "param" element
1240 * parse an XSLT transformation param declaration and record
1245 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
1246 xsltStylePreCompPtr comp;
1248 if ((cur == NULL) || (style == NULL))
1251 xsltStylePreCompute(style, cur);
1252 comp = (xsltStylePreCompPtr) cur->_private;
1254 xsltPrintErrorContext(NULL, style, cur);
1255 xsltGenericError(xsltGenericErrorContext,
1256 "xsl:param : compilation failed\n");
1260 if (comp->name == NULL) {
1261 xsltPrintErrorContext(NULL, style, cur);
1262 xsltGenericError(xsltGenericErrorContext,
1263 "xsl:param : missing name attribute\n");
1267 #ifdef WITH_XSLT_DEBUG_VARIABLE
1268 xsltGenericDebug(xsltGenericDebugContext,
1269 "Registering global param %s\n", comp->name);
1272 xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1273 cur->children, comp, NULL);
1277 * xsltParseStylesheetVariable:
1278 * @ctxt: the XSLT transformation context
1279 * @cur: the "variable" element
1281 * parse an XSLT transformation variable declaration and record
1286 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1287 xsltStylePreCompPtr comp;
1289 if ((cur == NULL) || (ctxt == NULL))
1292 comp = (xsltStylePreCompPtr) cur->_private;
1294 xsltPrintErrorContext(ctxt, NULL, cur);
1295 xsltGenericError(xsltGenericErrorContext,
1296 "xsl:variable : compilation failed\n");
1300 if (comp->name == NULL) {
1301 xsltPrintErrorContext(ctxt, NULL, cur);
1302 xsltGenericError(xsltGenericErrorContext,
1303 "xsl:variable : missing name attribute\n");
1307 #ifdef WITH_XSLT_DEBUG_VARIABLE
1308 xsltGenericDebug(xsltGenericDebugContext,
1309 "Registering variable %s\n", comp->name);
1312 xsltRegisterVariable(ctxt, comp, cur->children, 0);
1316 * xsltParseStylesheetParam:
1317 * @ctxt: the XSLT transformation context
1318 * @cur: the "param" element
1320 * parse an XSLT transformation param declaration and record
1325 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1326 xsltStylePreCompPtr comp;
1328 if ((cur == NULL) || (ctxt == NULL))
1331 comp = (xsltStylePreCompPtr) cur->_private;
1333 xsltPrintErrorContext(ctxt, NULL, cur);
1334 xsltGenericError(xsltGenericErrorContext,
1335 "xsl:param : compilation failed\n");
1339 if (comp->name == NULL) {
1340 xsltPrintErrorContext(ctxt, NULL, cur);
1341 xsltGenericError(xsltGenericErrorContext,
1342 "xsl:param : missing name attribute\n");
1346 #ifdef WITH_XSLT_DEBUG_VARIABLE
1347 xsltGenericDebug(xsltGenericDebugContext,
1348 "Registering param %s\n", comp->name);
1351 xsltRegisterVariable(ctxt, comp, cur->children, 1);
1355 * xsltFreeGlobalVariables:
1356 * @ctxt: the XSLT transformation context
1358 * Free up the data associated to the global variables
1363 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
1364 xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
1368 * xsltXPathVariableLookup:
1369 * @ctxt: a void * but the the XSLT transformation context actually
1370 * @name: the variable name
1371 * @ns_uri: the variable namespace URI
1373 * This is the entry point when a varibale is needed by the XPath
1376 * Returns the value or NULL if not found
1379 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
1380 const xmlChar *ns_uri) {
1381 xsltTransformContextPtr context;
1382 xmlXPathObjectPtr ret;
1384 if ((ctxt == NULL) || (name == NULL))
1387 #ifdef WITH_XSLT_DEBUG_VARIABLE
1388 xsltGenericDebug(xsltGenericDebugContext,
1389 "Lookup variable %s\n", name);
1391 context = (xsltTransformContextPtr) ctxt;
1392 ret = xsltVariableLookup(context, name, ns_uri);
1394 xsltPrintErrorContext(ctxt, NULL, NULL);
1395 xsltGenericError(xsltGenericErrorContext,
1396 "unregistered variable %s\n", name);
1398 #ifdef WITH_XSLT_DEBUG_VARIABLE
1400 xsltGenericDebug(xsltGenericDebugContext,
1401 "found variable %s\n", name);