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>
25 #include <libxml/dict.h>
27 #include "xsltInternals.h"
28 #include "xsltutils.h"
29 #include "variables.h"
30 #include "transform.h"
35 #ifdef WITH_XSLT_DEBUG
36 #define WITH_XSLT_DEBUG_VARIABLE
39 #ifdef XSLT_REFACTORED
40 const xmlChar
*xsltDocFragFake
= (const xmlChar
*) " fake node libxslt";
43 const xmlChar
*xsltComputingGlobalVarMarker
=
44 (const xmlChar
*) " var/param being computed";
46 #define XSLT_VAR_GLOBAL 1<<0
47 #define XSLT_VAR_IN_SELECT 1<<1
48 #define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable)
50 /************************************************************************
52 * Result Value Tree (Result Tree Fragment) interfaces *
54 ************************************************************************/
57 * @ctxt: an XSLT transformation context
59 * Creates a Result Value Tree
60 * (the XSLT 1.0 term for this is "Result Tree Fragment")
62 * Returns the result value tree or NULL in case of API or internal errors.
65 xsltCreateRVT(xsltTransformContextPtr ctxt
)
70 * Question: Why is this function public?
71 * Answer: It is called by the EXSLT module.
77 * Reuse a RTF from the cache if available.
79 if (ctxt
->cache
->RVT
) {
80 container
= ctxt
->cache
->RVT
;
81 ctxt
->cache
->RVT
= (xmlDocPtr
) container
->next
;
82 /* clear the internal pointers */
83 container
->next
= NULL
;
84 container
->prev
= NULL
;
85 if (ctxt
->cache
->nbRVT
> 0)
87 #ifdef XSLT_DEBUG_PROFILE_CACHE
88 ctxt
->cache
->dbgReusedRVTs
++;
93 container
= xmlNewDoc(NULL
);
94 if (container
== NULL
)
96 container
->dict
= ctxt
->dict
;
97 xmlDictReference(container
->dict
);
98 XSLT_MARK_RES_TREE_FRAG(container
);
99 container
->doc
= container
;
100 container
->parent
= NULL
;
105 * xsltRegisterTmpRVT:
106 * @ctxt: an XSLT transformation context
107 * @RVT: a result value tree (Result Tree Fragment)
109 * Registers the result value tree (XSLT 1.0 term: Result Tree Fragment)
110 * in the garbage collector.
111 * The fragment will be freed at the exit of the currently
112 * instantiated xsl:template.
113 * Obsolete; this function might produce massive memory overhead,
114 * since the fragment is only freed when the current xsl:template
115 * exits. Use xsltRegisterLocalRVT() instead.
117 * Returns 0 in case of success and -1 in case of API or internal errors.
120 xsltRegisterTmpRVT(xsltTransformContextPtr ctxt
, xmlDocPtr RVT
)
122 if ((ctxt
== NULL
) || (RVT
== NULL
))
126 * We'll restrict the lifetime of user-created fragments
127 * insinde an xsl:variable and xsl:param to the lifetime of the
130 if (ctxt
->contextVariable
!= NULL
) {
131 RVT
->next
= (xmlNodePtr
) XSLT_TCTXT_VARIABLE(ctxt
)->fragment
;
132 XSLT_TCTXT_VARIABLE(ctxt
)->fragment
= RVT
;
136 RVT
->next
= (xmlNodePtr
) ctxt
->tmpRVT
;
137 if (ctxt
->tmpRVT
!= NULL
)
138 ctxt
->tmpRVT
->prev
= (xmlNodePtr
) RVT
;
144 * xsltRegisterLocalRVT:
145 * @ctxt: an XSLT transformation context
146 * @RVT: a result value tree (Result Tree Fragment; xmlDocPtr)
148 * Registers a result value tree (XSLT 1.0 term: Result Tree Fragment)
149 * in the RVT garbage collector.
150 * The fragment will be freed when the instruction which created the
153 * Returns 0 in case of success and -1 in case of API or internal errors.
156 xsltRegisterLocalRVT(xsltTransformContextPtr ctxt
,
159 if ((ctxt
== NULL
) || (RVT
== NULL
))
163 * When evaluating "select" expressions of xsl:variable
164 * and xsl:param, we need to bind newly created tree fragments
165 * to the variable itself; otherwise the tragment will be
166 * freed before we leave the scope of a var.
168 if ((ctxt
->contextVariable
!= NULL
) &&
169 (XSLT_TCTXT_VARIABLE(ctxt
)->flags
& XSLT_VAR_IN_SELECT
))
171 RVT
->next
= (xmlNodePtr
) XSLT_TCTXT_VARIABLE(ctxt
)->fragment
;
172 XSLT_TCTXT_VARIABLE(ctxt
)->fragment
= RVT
;
176 * Store the fragment in the scope of the current instruction.
177 * If not reference by a returning instruction (like EXSLT's function),
178 * then this fragment will be freed, when the instruction exits.
180 RVT
->next
= (xmlNodePtr
) ctxt
->localRVT
;
181 if (ctxt
->localRVT
!= NULL
)
182 ctxt
->localRVT
->prev
= (xmlNodePtr
) RVT
;
183 ctxt
->localRVT
= RVT
;
185 * We need to keep track of the first registered fragment
186 * for extension instructions which return fragments
187 * (e.g. EXSLT'S function), in order to let
188 * xsltExtensionInstructionResultFinalize() clear the
189 * preserving flag on the fragments.
191 if (ctxt
->localRVTBase
== NULL
)
192 ctxt
->localRVTBase
= RVT
;
197 * xsltExtensionInstructionResultFinalize:
198 * @ctxt: an XSLT transformation context
200 * Finalizes the data (e.g. result tree fragments) created
201 * within a value-returning process (e.g. EXSLT's function).
202 * Tree fragments marked as being returned by a function are
203 * set to normal state, which means that the fragment garbage
204 * collector will free them after the function-calling process exits.
206 * Returns 0 in case of success and -1 in case of API or internal errors.
209 xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt
)
215 if (ctxt
->localRVTBase
== NULL
)
218 * Enable remaining local tree fragments to be freed
219 * by the fragment garbage collector.
221 cur
= ctxt
->localRVTBase
;
224 cur
= (xmlDocPtr
) cur
->next
;
225 } while (cur
!= NULL
);
230 * xsltExtensionInstructionResultRegister:
231 * @ctxt: an XSLT transformation context
232 * @obj: an XPath object to be inspected for result tree fragments
234 * Marks the result of a value-returning extension instruction
235 * in order to avoid it being garbage collected before the
236 * extension instruction exits.
237 * Note that one still has to additionally register any newly created
238 * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT().
240 * Returns 0 in case of success and -1 in case of error.
243 xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt
,
244 xmlXPathObjectPtr obj
)
250 if ((ctxt
== NULL
) || (obj
== NULL
))
254 * OPTIMIZE TODO: If no local variables/params and no local tree
255 * fragments were created, then we don't need to analyse the XPath
256 * objects for tree fragments.
259 if ((obj
->type
!= XPATH_NODESET
) && (obj
->type
!= XPATH_XSLT_TREE
))
261 if ((obj
->nodesetval
== NULL
) || (obj
->nodesetval
->nodeNr
== 0))
264 for (i
= 0; i
< obj
->nodesetval
->nodeNr
; i
++) {
265 cur
= obj
->nodesetval
->nodeTab
[i
];
266 if (cur
->type
== XML_NAMESPACE_DECL
) {
268 * The XPath module sets the owner element of a ns-node on
269 * the ns->next field.
271 if ((((xmlNsPtr
) cur
)->next
!= NULL
) &&
272 (((xmlNsPtr
) cur
)->next
->type
== XML_ELEMENT_NODE
))
274 cur
= (xmlNodePtr
) ((xmlNsPtr
) cur
)->next
;
277 xsltTransformError(ctxt
, NULL
, ctxt
->inst
,
279 "xsltExtensionInstructionResultRegister(): "
280 "Cannot retrieve the doc of a namespace node.\n");
287 xsltTransformError(ctxt
, NULL
, ctxt
->inst
,
289 "xsltExtensionInstructionResultRegister(): "
290 "Cannot retrieve the doc of a node.\n");
293 if (doc
->name
&& (doc
->name
[0] == ' ')) {
295 * This is a result tree fragment.
296 * We'll use the @psvi field for reference counting.
297 * TODO: How do we know if this is a value of a
298 * global variable or a doc acquired via the
299 * document() function?
301 doc
->psvi
= (void *) ((long) 1);
312 * @ctxt: an XSLT transformation context
313 * @RVT: a result value tree (Result Tree Fragment)
315 * Either frees the RVT (which is an xmlDoc) or stores
316 * it in the context's cache for later reuse.
319 xsltReleaseRVT(xsltTransformContextPtr ctxt
, xmlDocPtr RVT
)
324 if (ctxt
&& (ctxt
->cache
->nbRVT
< 40)) {
326 * Store the Result Tree Fragment.
327 * Free the document info.
329 if (RVT
->_private
!= NULL
) {
330 xsltFreeDocumentKeys((xsltDocumentPtr
) RVT
->_private
);
331 xmlFree(RVT
->_private
);
332 RVT
->_private
= NULL
;
335 * Clear the document tree.
336 * REVISIT TODO: Do we expect ID/IDREF tables to be existent?
338 if (RVT
->children
!= NULL
) {
339 xmlFreeNodeList(RVT
->children
);
340 RVT
->children
= NULL
;
343 if (RVT
->ids
!= NULL
) {
344 xmlFreeIDTable((xmlIDTablePtr
) RVT
->ids
);
347 if (RVT
->refs
!= NULL
) {
348 xmlFreeRefTable((xmlRefTablePtr
) RVT
->refs
);
353 * Reset the reference counter.
357 RVT
->next
= (xmlNodePtr
) ctxt
->cache
->RVT
;
358 ctxt
->cache
->RVT
= RVT
;
360 ctxt
->cache
->nbRVT
++;
362 #ifdef XSLT_DEBUG_PROFILE_CACHE
363 ctxt
->cache
->dbgCachedRVTs
++;
370 if (RVT
->_private
!= NULL
) {
371 xsltFreeDocumentKeys((xsltDocumentPtr
) RVT
->_private
);
372 xmlFree(RVT
->_private
);
378 * xsltRegisterPersistRVT:
379 * @ctxt: an XSLT transformation context
380 * @RVT: a result value tree (Result Tree Fragment)
382 * Register the result value tree (XSLT 1.0 term: Result Tree Fragment)
383 * in the fragment garbage collector.
384 * The fragment will be freed when the transformation context is
387 * Returns 0 in case of success and -1 in case of error.
390 xsltRegisterPersistRVT(xsltTransformContextPtr ctxt
, xmlDocPtr RVT
)
392 if ((ctxt
== NULL
) || (RVT
== NULL
)) return(-1);
394 RVT
->next
= (xmlNodePtr
) ctxt
->persistRVT
;
395 if (ctxt
->persistRVT
!= NULL
)
396 ctxt
->persistRVT
->prev
= (xmlNodePtr
) RVT
;
397 ctxt
->persistRVT
= RVT
;
403 * @ctxt: an XSLT transformation context
405 * Frees all registered result value trees (Result Tree Fragments)
406 * of the transformation. Internal function; should not be called
410 xsltFreeRVTs(xsltTransformContextPtr ctxt
)
419 cur
= ctxt
->localRVT
;
420 while (cur
!= NULL
) {
421 next
= (xmlDocPtr
) cur
->next
;
422 if (cur
->_private
!= NULL
) {
423 xsltFreeDocumentKeys(cur
->_private
);
424 xmlFree(cur
->_private
);
429 ctxt
->localRVT
= NULL
;
431 * User-created per-template fragments.
434 while (cur
!= NULL
) {
435 next
= (xmlDocPtr
) cur
->next
;
436 if (cur
->_private
!= NULL
) {
437 xsltFreeDocumentKeys(cur
->_private
);
438 xmlFree(cur
->_private
);
447 cur
= ctxt
->persistRVT
;
448 while (cur
!= NULL
) {
449 next
= (xmlDocPtr
) cur
->next
;
450 if (cur
->_private
!= NULL
) {
451 xsltFreeDocumentKeys(cur
->_private
);
452 xmlFree(cur
->_private
);
457 ctxt
->persistRVT
= NULL
;
460 /************************************************************************
462 * Module interfaces *
464 ************************************************************************/
469 * Create a new XSLT ParserContext
471 * Returns the newly allocated xsltParserStackElem or NULL in case of error
473 static xsltStackElemPtr
474 xsltNewStackElem(xsltTransformContextPtr ctxt
)
476 xsltStackElemPtr ret
;
478 * Reuse a stack item from the cache if available.
480 if (ctxt
&& ctxt
->cache
->stackItems
) {
481 ret
= ctxt
->cache
->stackItems
;
482 ctxt
->cache
->stackItems
= ret
->next
;
484 ctxt
->cache
->nbStackItems
--;
485 #ifdef XSLT_DEBUG_PROFILE_CACHE
486 ctxt
->cache
->dbgReusedVars
++;
490 ret
= (xsltStackElemPtr
) xmlMalloc(sizeof(xsltStackElem
));
492 xsltTransformError(NULL
, NULL
, NULL
,
493 "xsltNewStackElem : malloc failed\n");
496 memset(ret
, 0, sizeof(xsltStackElem
));
503 * @elem: an XSLT stack element
505 * Makes a copy of the stack element
507 * Returns the copy of NULL
509 static xsltStackElemPtr
510 xsltCopyStackElem(xsltStackElemPtr elem
) {
511 xsltStackElemPtr cur
;
513 cur
= (xsltStackElemPtr
) xmlMalloc(sizeof(xsltStackElem
));
515 xsltTransformError(NULL
, NULL
, NULL
,
516 "xsltCopyStackElem : malloc failed\n");
519 memset(cur
, 0, sizeof(xsltStackElem
));
520 cur
->context
= elem
->context
;
521 cur
->name
= elem
->name
;
522 cur
->nameURI
= elem
->nameURI
;
523 cur
->select
= elem
->select
;
524 cur
->tree
= elem
->tree
;
525 cur
->comp
= elem
->comp
;
531 * @elem: an XSLT stack element
533 * Free up the memory allocated by @elem
536 xsltFreeStackElem(xsltStackElemPtr elem
) {
539 if (elem
->value
!= NULL
)
540 xmlXPathFreeObject(elem
->value
);
542 * Release the list of temporary Result Tree Fragments.
544 if (elem
->fragment
) {
547 while (elem
->fragment
!= NULL
) {
548 cur
= elem
->fragment
;
549 elem
->fragment
= (xmlDocPtr
) cur
->next
;
552 (cur
->psvi
== (void *) ((long) 1)))
555 * This fragment is a result of an extension instruction
556 * (e.g. XSLT's function) and needs to be preserved until
557 * the instruction exits.
558 * Example: The fragment of the variable must not be freed
559 * since it is returned by the EXSLT function:
560 * <f:function name="foo">
561 * <xsl:variable name="bar">
564 * <f:result select="$bar"/>
568 xsltRegisterLocalRVT(elem
->context
, cur
);
570 xsltReleaseRVT((xsltTransformContextPtr
) elem
->context
,
576 * Cache or free the variable structure.
578 if (elem
->context
&& (elem
->context
->cache
->nbStackItems
< 50)) {
580 * Store the item in the cache.
582 xsltTransformContextPtr ctxt
= elem
->context
;
583 memset(elem
, 0, sizeof(xsltStackElem
));
584 elem
->context
= ctxt
;
585 elem
->next
= ctxt
->cache
->stackItems
;
586 ctxt
->cache
->stackItems
= elem
;
587 ctxt
->cache
->nbStackItems
++;
588 #ifdef XSLT_DEBUG_PROFILE_CACHE
589 ctxt
->cache
->dbgCachedVars
++;
597 * xsltFreeStackElemList:
598 * @elem: an XSLT stack element
600 * Free up the memory allocated by @elem
603 xsltFreeStackElemList(xsltStackElemPtr elem
) {
604 xsltStackElemPtr next
;
606 while (elem
!= NULL
) {
608 xsltFreeStackElem(elem
);
615 * @ctxt: an XSLT transformation context
616 * @name: the local part of the name
617 * @nameURI: the URI part of the name
619 * Locate an element in the stack based on its name.
621 #if 0 /* TODO: Those seem to have been used for debugging. */
622 static int stack_addr
= 0;
623 static int stack_cmp
= 0;
626 static xsltStackElemPtr
627 xsltStackLookup(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
628 const xmlChar
*nameURI
) {
630 xsltStackElemPtr cur
;
632 if ((ctxt
== NULL
) || (name
== NULL
) || (ctxt
->varsNr
== 0))
636 * Do the lookup from the top of the stack, but
637 * don't use params being computed in a call-param
638 * First lookup expects the variable name and URI to
639 * come from the disctionnary and hence pointer comparison.
641 for (i
= ctxt
->varsNr
; i
> ctxt
->varsBase
; i
--) {
642 cur
= ctxt
->varsTab
[i
-1];
643 while (cur
!= NULL
) {
644 if ((cur
->name
== name
) && (cur
->nameURI
== nameURI
)) {
655 * Redo the lookup with interned string compares
656 * to avoid string compares.
658 name
= xmlDictLookup(ctxt
->dict
, name
, -1);
660 nameURI
= xmlDictLookup(ctxt
->dict
, nameURI
, -1);
662 for (i
= ctxt
->varsNr
; i
> ctxt
->varsBase
; i
--) {
663 cur
= ctxt
->varsTab
[i
-1];
664 while (cur
!= NULL
) {
665 if ((cur
->name
== name
) && (cur
->nameURI
== nameURI
)) {
679 * xsltCheckStackElem:
680 * @ctxt: xn XSLT transformation context
681 * @name: the variable name
682 * @nameURI: the variable namespace URI
684 * Checks whether a variable or param is already defined.
686 * URGENT TODO: Checks for redefinition of vars/params should be
687 * done only at compilation time.
689 * Returns 1 if variable is present, 2 if param is present, 3 if this
690 * is an inherited param, 0 if not found, -1 in case of failure.
693 xsltCheckStackElem(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
694 const xmlChar
*nameURI
) {
695 xsltStackElemPtr cur
;
697 if ((ctxt
== NULL
) || (name
== NULL
))
700 cur
= xsltStackLookup(ctxt
, name
, nameURI
);
703 if (cur
->comp
!= NULL
) {
704 if (cur
->comp
->type
== XSLT_FUNC_WITHPARAM
)
706 else if (cur
->comp
->type
== XSLT_FUNC_PARAM
)
715 * @ctxt: xn XSLT transformation context
716 * @elem: a stack element
718 * Push an element (or list) onto the stack.
719 * In case of a list, each member will be pushed into
720 * a seperate slot; i.e. there's always 1 stack entry for
723 * Returns 0 in case of success, -1 in case of failure.
726 xsltAddStackElem(xsltTransformContextPtr ctxt
, xsltStackElemPtr elem
)
728 if ((ctxt
== NULL
) || (elem
== NULL
))
732 if (ctxt
->varsMax
== 0) {
735 (xsltStackElemPtr
*) xmlMalloc(ctxt
->varsMax
*
736 sizeof(ctxt
->varsTab
[0]));
737 if (ctxt
->varsTab
== NULL
) {
738 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
742 if (ctxt
->varsNr
>= ctxt
->varsMax
) {
745 (xsltStackElemPtr
*) xmlRealloc(ctxt
->varsTab
,
747 sizeof(ctxt
->varsTab
[0]));
748 if (ctxt
->varsTab
== NULL
) {
749 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
753 ctxt
->varsTab
[ctxt
->varsNr
++] = elem
;
757 } while (elem
!= NULL
);
763 * xsltAddStackElemList:
764 * @ctxt: xn XSLT transformation context
765 * @elems: a stack element list
767 * Push an element list onto the stack.
769 * Returns 0 in case of success, -1 in case of failure.
772 xsltAddStackElemList(xsltTransformContextPtr ctxt
, xsltStackElemPtr elems
)
774 return(xsltAddStackElem(ctxt
, elems
));
777 /************************************************************************
779 * Module interfaces *
781 ************************************************************************/
785 * @ctxt: the XSLT transformation context
786 * @variable: the variable or parameter item
787 * @comp: the compiled XSLT instruction
789 * Evaluate a variable value.
791 * Returns the XPath Object value or NULL in case of error
793 static xmlXPathObjectPtr
794 xsltEvalVariable(xsltTransformContextPtr ctxt
, xsltStackElemPtr variable
,
795 xsltStylePreCompPtr castedComp
)
797 #ifdef XSLT_REFACTORED
798 xsltStyleItemVariablePtr comp
=
799 (xsltStyleItemVariablePtr
) castedComp
;
801 xsltStylePreCompPtr comp
= castedComp
;
803 xmlXPathObjectPtr result
= NULL
;
806 if ((ctxt
== NULL
) || (variable
== NULL
))
810 * A variable or parameter are evaluated on demand; thus the
811 * context (of XSLT and XPath) need to be temporarily adjusted and
814 oldInst
= ctxt
->inst
;
816 #ifdef WITH_XSLT_DEBUG_VARIABLE
817 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
818 "Evaluating variable '%s'\n", variable
->name
));
820 if (variable
->select
!= NULL
) {
821 xmlXPathCompExprPtr xpExpr
= NULL
;
823 xmlNodePtr oldXPContextNode
;
824 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
825 xmlNsPtr
*oldXPNamespaces
;
826 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
827 xsltStackElemPtr oldVar
= ctxt
->contextVariable
;
829 if ((comp
!= NULL
) && (comp
->comp
!= NULL
)) {
832 xpExpr
= xmlXPathCompile(variable
->select
);
837 * Save context states.
839 oldXPDoc
= xpctxt
->doc
;
840 oldXPContextNode
= xpctxt
->node
;
841 oldXPProximityPosition
= xpctxt
->proximityPosition
;
842 oldXPContextSize
= xpctxt
->contextSize
;
843 oldXPNamespaces
= xpctxt
->namespaces
;
844 oldXPNsNr
= xpctxt
->nsNr
;
846 xpctxt
->node
= ctxt
->node
;
848 * OPTIMIZE TODO: Lame try to set the context doc.
849 * Get rid of this somehow in xpath.c.
851 if ((ctxt
->node
->type
!= XML_NAMESPACE_DECL
) &&
853 xpctxt
->doc
= ctxt
->node
->doc
;
855 * BUG TODO: The proximity position and the context size will
856 * potentially be wrong.
858 * <xsl:template select="foo">
859 * <xsl:variable name="pos" select="position()"/>
860 * <xsl:for-each select="bar">
861 * <xsl:value-of select="$pos"/>
864 * Here the proximity position and context size are changed
865 * to the context of <xsl:for-each select="bar">, but
866 * the variable needs to be evaluated in the context of
867 * <xsl:template select="foo">.
871 #ifdef XSLT_REFACTORED
872 if (comp
->inScopeNs
!= NULL
) {
873 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
874 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
876 xpctxt
->namespaces
= NULL
;
880 xpctxt
->namespaces
= comp
->nsList
;
881 xpctxt
->nsNr
= comp
->nsNr
;
884 xpctxt
->namespaces
= NULL
;
889 * We need to mark that we are "selecting" a var's value;
890 * if any tree fragments are created inside the expression,
891 * then those need to be stored inside the variable; otherwise
892 * we'll eventually free still referenced fragments, before
893 * we leave the scope of the variable.
895 ctxt
->contextVariable
= variable
;
896 variable
->flags
|= XSLT_VAR_IN_SELECT
;
898 result
= xmlXPathCompiledEval(xpExpr
, xpctxt
);
900 variable
->flags
^= XSLT_VAR_IN_SELECT
;
902 * Restore Context states.
904 ctxt
->contextVariable
= oldVar
;
906 xpctxt
->doc
= oldXPDoc
;
907 xpctxt
->node
= oldXPContextNode
;
908 xpctxt
->contextSize
= oldXPContextSize
;
909 xpctxt
->proximityPosition
= oldXPProximityPosition
;
910 xpctxt
->namespaces
= oldXPNamespaces
;
911 xpctxt
->nsNr
= oldXPNsNr
;
913 if ((comp
== NULL
) || (comp
->comp
== NULL
))
914 xmlXPathFreeCompExpr(xpExpr
);
915 if (result
== NULL
) {
916 xsltTransformError(ctxt
, NULL
,
917 (comp
!= NULL
) ? comp
->inst
: NULL
,
918 "Failed to evaluate the expression of variable '%s'.\n",
920 ctxt
->state
= XSLT_STATE_STOPPED
;
922 #ifdef WITH_XSLT_DEBUG_VARIABLE
923 #ifdef LIBXML_DEBUG_ENABLED
925 if ((xsltGenericDebugContext
== stdout
) ||
926 (xsltGenericDebugContext
== stderr
))
927 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
933 if (variable
->tree
== NULL
) {
934 result
= xmlXPathNewCString("");
936 if (variable
->tree
) {
938 xmlNodePtr oldInsert
;
940 xsltStackElemPtr oldVar
= ctxt
->contextVariable
;
943 * Generate a result tree fragment.
945 container
= xsltCreateRVT(ctxt
);
946 if (container
== NULL
)
949 * NOTE: Local Result Tree Fragments of params/variables
950 * are not registered globally anymore; the life-time
951 * is not directly dependant of the param/variable itself.
953 * OLD: xsltRegisterTmpRVT(ctxt, container);
956 * Attach the Result Tree Fragment to the variable;
957 * when the variable is freed, it will also free
958 * the Result Tree Fragment.
960 variable
->fragment
= container
;
962 oldOutput
= ctxt
->output
;
963 oldInsert
= ctxt
->insert
;
965 ctxt
->output
= container
;
966 ctxt
->insert
= (xmlNodePtr
) container
;
967 ctxt
->contextVariable
= variable
;
969 * Process the sequence constructor (variable->tree).
970 * The resulting tree will be held by @container.
972 xsltApplyOneTemplate(ctxt
, ctxt
->node
, variable
->tree
,
975 ctxt
->contextVariable
= oldVar
;
976 ctxt
->insert
= oldInsert
;
977 ctxt
->output
= oldOutput
;
979 result
= xmlXPathNewValueTree((xmlNodePtr
) container
);
981 if (result
== NULL
) {
982 result
= xmlXPathNewCString("");
985 * Freeing is not handled there anymore.
986 * QUESTION TODO: What does the above comment mean?
990 #ifdef WITH_XSLT_DEBUG_VARIABLE
991 #ifdef LIBXML_DEBUG_ENABLED
993 if ((xsltGenericDebugContext
== stdout
) ||
994 (xsltGenericDebugContext
== stderr
))
995 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
1003 ctxt
->inst
= oldInst
;
1008 * xsltEvalGlobalVariable:
1009 * @elem: the variable or parameter
1010 * @ctxt: the XSLT transformation context
1012 * Evaluates a the value of a global xsl:variable or
1013 * xsl:param declaration.
1015 * Returns the XPath Object value or NULL in case of error
1017 static xmlXPathObjectPtr
1018 xsltEvalGlobalVariable(xsltStackElemPtr elem
, xsltTransformContextPtr ctxt
)
1020 xmlXPathObjectPtr result
= NULL
;
1022 const xmlChar
* oldVarName
;
1024 #ifdef XSLT_REFACTORED
1025 xsltStyleBasicItemVariablePtr comp
;
1027 xsltStylePreCompPtr comp
;
1030 if ((ctxt
== NULL
) || (elem
== NULL
))
1033 return(elem
->value
);
1036 #ifdef WITH_XSLT_DEBUG_VARIABLE
1037 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1038 "Evaluating global variable %s\n", elem
->name
));
1041 #ifdef WITH_DEBUGGER
1042 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) &&
1043 elem
->comp
&& elem
->comp
->inst
)
1044 xslHandleDebugger(elem
->comp
->inst
, NULL
, NULL
, ctxt
);
1047 oldInst
= ctxt
->inst
;
1049 oldVarName
= elem
->name
;
1050 elem
->name
= xsltComputingGlobalVarMarker
;
1052 * OPTIMIZE TODO: We should consider instantiating global vars/params
1053 * on-demand. The vars/params don't need to be evaluated if never
1054 * called; and in the case of global params, if values for such params
1055 * are provided by the user.
1057 if (elem
->select
!= NULL
) {
1058 xmlXPathCompExprPtr xpExpr
= NULL
;
1060 xmlNodePtr oldXPContextNode
;
1061 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
1062 xmlNsPtr
*oldXPNamespaces
;
1063 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
1065 if ((comp
!= NULL
) && (comp
->comp
!= NULL
)) {
1066 xpExpr
= comp
->comp
;
1068 xpExpr
= xmlXPathCompile(elem
->select
);
1075 ctxt
->inst
= comp
->inst
;
1080 * "At top-level, the expression or template specifying the
1081 * variable value is evaluated with the same context as that used
1082 * to process the root node of the source document: the current
1083 * node is the root node of the source document and the current
1084 * node list is a list containing just the root node of the source
1088 * Save context states.
1090 oldXPDoc
= xpctxt
->doc
;
1091 oldXPContextNode
= xpctxt
->node
;
1092 oldXPProximityPosition
= xpctxt
->proximityPosition
;
1093 oldXPContextSize
= xpctxt
->contextSize
;
1094 oldXPNamespaces
= xpctxt
->namespaces
;
1095 oldXPNsNr
= xpctxt
->nsNr
;
1097 xpctxt
->node
= ctxt
->initialContextNode
;
1098 xpctxt
->doc
= ctxt
->initialContextDoc
;
1099 xpctxt
->contextSize
= 1;
1100 xpctxt
->proximityPosition
= 1;
1104 #ifdef XSLT_REFACTORED
1105 if (comp
->inScopeNs
!= NULL
) {
1106 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
1107 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
1109 xpctxt
->namespaces
= NULL
;
1113 xpctxt
->namespaces
= comp
->nsList
;
1114 xpctxt
->nsNr
= comp
->nsNr
;
1117 xpctxt
->namespaces
= NULL
;
1121 result
= xmlXPathCompiledEval(xpExpr
, xpctxt
);
1124 * Restore Context states.
1126 xpctxt
->doc
= oldXPDoc
;
1127 xpctxt
->node
= oldXPContextNode
;
1128 xpctxt
->contextSize
= oldXPContextSize
;
1129 xpctxt
->proximityPosition
= oldXPProximityPosition
;
1130 xpctxt
->namespaces
= oldXPNamespaces
;
1131 xpctxt
->nsNr
= oldXPNsNr
;
1133 if ((comp
== NULL
) || (comp
->comp
== NULL
))
1134 xmlXPathFreeCompExpr(xpExpr
);
1135 if (result
== NULL
) {
1137 xsltTransformError(ctxt
, NULL
, NULL
,
1138 "Evaluating global variable %s failed\n", elem
->name
);
1140 xsltTransformError(ctxt
, NULL
, comp
->inst
,
1141 "Evaluating global variable %s failed\n", elem
->name
);
1142 ctxt
->state
= XSLT_STATE_STOPPED
;
1143 #ifdef WITH_XSLT_DEBUG_VARIABLE
1144 #ifdef LIBXML_DEBUG_ENABLED
1146 if ((xsltGenericDebugContext
== stdout
) ||
1147 (xsltGenericDebugContext
== stderr
))
1148 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
1154 if (elem
->tree
== NULL
) {
1155 result
= xmlXPathNewCString("");
1157 xmlDocPtr container
;
1158 xmlNodePtr oldInsert
;
1159 xmlDocPtr oldOutput
, oldXPDoc
;
1161 * Generate a result tree fragment.
1163 container
= xsltCreateRVT(ctxt
);
1164 if (container
== NULL
)
1167 * Let the lifetime of the tree fragment be handled by
1168 * the Libxslt's garbage collector.
1170 xsltRegisterPersistRVT(ctxt
, container
);
1172 oldOutput
= ctxt
->output
;
1173 oldInsert
= ctxt
->insert
;
1175 oldXPDoc
= ctxt
->xpathCtxt
->doc
;
1177 ctxt
->output
= container
;
1178 ctxt
->insert
= (xmlNodePtr
) container
;
1180 ctxt
->xpathCtxt
->doc
= ctxt
->initialContextDoc
;
1182 * Process the sequence constructor.
1184 xsltApplyOneTemplate(ctxt
, ctxt
->node
, elem
->tree
, NULL
, NULL
);
1186 ctxt
->xpathCtxt
->doc
= oldXPDoc
;
1188 ctxt
->insert
= oldInsert
;
1189 ctxt
->output
= oldOutput
;
1191 result
= xmlXPathNewValueTree((xmlNodePtr
) container
);
1192 if (result
== NULL
) {
1193 result
= xmlXPathNewCString("");
1195 result
->boolval
= 0; /* Freeing is not handled there anymore */
1197 #ifdef WITH_XSLT_DEBUG_VARIABLE
1198 #ifdef LIBXML_DEBUG_ENABLED
1199 if ((xsltGenericDebugContext
== stdout
) ||
1200 (xsltGenericDebugContext
== stderr
))
1201 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
1209 elem
->name
= oldVarName
;
1210 ctxt
->inst
= oldInst
;
1211 if (result
!= NULL
) {
1212 elem
->value
= result
;
1219 * xsltEvalGlobalVariables:
1220 * @ctxt: the XSLT transformation context
1222 * Evaluates all global variables and parameters of a stylesheet.
1223 * For internal use only. This is called at start of a transformation.
1225 * Returns 0 in case of success, -1 in case of error
1228 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt
) {
1229 xsltStackElemPtr elem
;
1230 xsltStylesheetPtr style
;
1232 if ((ctxt
== NULL
) || (ctxt
->document
== NULL
))
1235 #ifdef WITH_XSLT_DEBUG_VARIABLE
1236 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1237 "Registering global variables\n"));
1240 * Walk the list from the stylesheets and populate the hash table
1242 style
= ctxt
->style
;
1243 while (style
!= NULL
) {
1244 elem
= style
->variables
;
1246 #ifdef WITH_XSLT_DEBUG_VARIABLE
1247 if ((style
->doc
!= NULL
) && (style
->doc
->URL
!= NULL
)) {
1248 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1249 "Registering global variables from %s\n",
1254 while (elem
!= NULL
) {
1255 xsltStackElemPtr def
;
1258 * Global variables are stored in the variables pool.
1260 def
= (xsltStackElemPtr
)
1261 xmlHashLookup2(ctxt
->globalVars
,
1262 elem
->name
, elem
->nameURI
);
1265 def
= xsltCopyStackElem(elem
);
1266 xmlHashAddEntry2(ctxt
->globalVars
,
1267 elem
->name
, elem
->nameURI
, def
);
1268 } else if ((elem
->comp
!= NULL
) &&
1269 (elem
->comp
->type
== XSLT_FUNC_VARIABLE
)) {
1271 * Redefinition of variables from a different stylesheet
1272 * should not generate a message.
1274 if ((elem
->comp
->inst
!= NULL
) &&
1275 (def
->comp
!= NULL
) && (def
->comp
->inst
!= NULL
) &&
1276 (elem
->comp
->inst
->doc
== def
->comp
->inst
->doc
))
1278 xsltTransformError(ctxt
, style
, elem
->comp
->inst
,
1279 "Global variable %s already defined\n", elem
->name
);
1280 if (style
!= NULL
) style
->errors
++;
1286 style
= xsltNextImport(style
);
1290 * This part does the actual evaluation
1292 xmlHashScan(ctxt
->globalVars
,
1293 (xmlHashScanner
) xsltEvalGlobalVariable
, ctxt
);
1299 * xsltRegisterGlobalVariable:
1300 * @style: the XSLT transformation context
1301 * @name: the variable name
1302 * @ns_uri: the variable namespace URI
1303 * @sel: the expression which need to be evaluated to generate a value
1304 * @tree: the subtree if sel is NULL
1305 * @comp: the precompiled value
1306 * @value: the string value if available
1308 * Register a new variable value. If @value is NULL it unregisters
1311 * Returns 0 in case of success, -1 in case of error
1314 xsltRegisterGlobalVariable(xsltStylesheetPtr style
, const xmlChar
*name
,
1315 const xmlChar
*ns_uri
, const xmlChar
*sel
,
1316 xmlNodePtr tree
, xsltStylePreCompPtr comp
,
1317 const xmlChar
*value
) {
1318 xsltStackElemPtr elem
, tmp
;
1326 #ifdef WITH_XSLT_DEBUG_VARIABLE
1327 if (comp
->type
== XSLT_FUNC_PARAM
)
1328 xsltGenericDebug(xsltGenericDebugContext
,
1329 "Defining global param %s\n", name
);
1331 xsltGenericDebug(xsltGenericDebugContext
,
1332 "Defining global variable %s\n", name
);
1335 elem
= xsltNewStackElem(NULL
);
1339 elem
->name
= xmlDictLookup(style
->dict
, name
, -1);
1340 elem
->select
= xmlDictLookup(style
->dict
, sel
, -1);
1342 elem
->nameURI
= xmlDictLookup(style
->dict
, ns_uri
, -1);
1344 tmp
= style
->variables
;
1347 style
->variables
= elem
;
1349 while (tmp
!= NULL
) {
1350 if ((elem
->comp
->type
== XSLT_FUNC_VARIABLE
) &&
1351 (tmp
->comp
->type
== XSLT_FUNC_VARIABLE
) &&
1352 (xmlStrEqual(elem
->name
, tmp
->name
)) &&
1353 ((elem
->nameURI
== tmp
->nameURI
) ||
1354 (xmlStrEqual(elem
->nameURI
, tmp
->nameURI
))))
1356 xsltTransformError(NULL
, style
, comp
->inst
,
1357 "redefinition of global variable %s\n", elem
->name
);
1360 if (tmp
->next
== NULL
)
1367 if (value
!= NULL
) {
1369 elem
->value
= xmlXPathNewString(value
);
1375 * xsltProcessUserParamInternal
1377 * @ctxt: the XSLT transformation context
1378 * @name: a null terminated parameter name
1379 * @value: a null terminated value (may be an XPath expression)
1380 * @eval: 0 to treat the value literally, else evaluate as XPath expression
1382 * If @eval is 0 then @value is treated literally and is stored in the global
1383 * parameter/variable table without any change.
1385 * Uf @eval is 1 then @value is treated as an XPath expression and is
1386 * evaluated. In this case, if you want to pass a string which will be
1387 * interpreted literally then it must be enclosed in single or double quotes.
1388 * If the string contains single quotes (double quotes) then it cannot be
1389 * enclosed single quotes (double quotes). If the string which you want to
1390 * be treated literally contains both single and double quotes (e.g. Meet
1391 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
1392 * quoting character. You cannot use ' or " inside the string
1393 * because the replacement of character entities with their equivalents is
1394 * done at a different stage of processing. The solution is to call
1395 * xsltQuoteUserParams or xsltQuoteOneUserParam.
1397 * This needs to be done on parsed stylesheets before starting to apply
1398 * transformations. Normally this will be called (directly or indirectly)
1399 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
1400 * or xsltQuoteOneUserParam.
1402 * Returns 0 in case of success, -1 in case of error
1407 xsltProcessUserParamInternal(xsltTransformContextPtr ctxt
,
1408 const xmlChar
* name
,
1409 const xmlChar
* value
,
1412 xsltStylesheetPtr style
;
1413 const xmlChar
*prefix
;
1414 const xmlChar
*href
;
1415 xmlXPathCompExprPtr xpExpr
;
1416 xmlXPathObjectPtr result
;
1418 xsltStackElemPtr elem
;
1429 style
= ctxt
->style
;
1431 #ifdef WITH_XSLT_DEBUG_VARIABLE
1432 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1433 "Evaluating user parameter %s=%s\n", name
, value
));
1440 name
= xsltSplitQName(ctxt
->dict
, name
, &prefix
);
1442 if (prefix
!= NULL
) {
1445 ns
= xmlSearchNs(style
->doc
, xmlDocGetRootElement(style
->doc
),
1448 xsltTransformError(ctxt
, style
, NULL
,
1449 "user param : no namespace bound to prefix %s\n", prefix
);
1459 res_ptr
= xmlHashLookup2(ctxt
->globalVars
, name
, href
);
1461 xsltTransformError(ctxt
, style
, NULL
,
1462 "Global parameter %s already defined\n", name
);
1464 if (ctxt
->globalVars
== NULL
)
1465 ctxt
->globalVars
= xmlHashCreate(20);
1468 * do not overwrite variables with parameters from the command line
1470 while (style
!= NULL
) {
1471 elem
= ctxt
->style
->variables
;
1472 while (elem
!= NULL
) {
1473 if ((elem
->comp
!= NULL
) &&
1474 (elem
->comp
->type
== XSLT_FUNC_VARIABLE
) &&
1475 (xmlStrEqual(elem
->name
, name
)) &&
1476 (xmlStrEqual(elem
->nameURI
, href
))) {
1481 style
= xsltNextImport(style
);
1483 style
= ctxt
->style
;
1487 * Do the evaluation if @eval is non-zero.
1492 xpExpr
= xmlXPathCompile(value
);
1493 if (xpExpr
!= NULL
) {
1495 xmlNodePtr oldXPContextNode
;
1496 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
1497 xmlNsPtr
*oldXPNamespaces
;
1498 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
1501 * Save context states.
1503 oldXPDoc
= xpctxt
->doc
;
1504 oldXPContextNode
= xpctxt
->node
;
1505 oldXPProximityPosition
= xpctxt
->proximityPosition
;
1506 oldXPContextSize
= xpctxt
->contextSize
;
1507 oldXPNamespaces
= xpctxt
->namespaces
;
1508 oldXPNsNr
= xpctxt
->nsNr
;
1512 * "At top-level, the expression or template specifying the
1513 * variable value is evaluated with the same context as that used
1514 * to process the root node of the source document: the current
1515 * node is the root node of the source document and the current
1516 * node list is a list containing just the root node of the source
1519 xpctxt
->doc
= ctxt
->initialContextDoc
;
1520 xpctxt
->node
= ctxt
->initialContextNode
;
1521 xpctxt
->contextSize
= 1;
1522 xpctxt
->proximityPosition
= 1;
1524 * There is really no in scope namespace for parameters on the
1527 xpctxt
->namespaces
= NULL
;
1530 result
= xmlXPathCompiledEval(xpExpr
, xpctxt
);
1533 * Restore Context states.
1535 xpctxt
->doc
= oldXPDoc
;
1536 xpctxt
->node
= oldXPContextNode
;
1537 xpctxt
->contextSize
= oldXPContextSize
;
1538 xpctxt
->proximityPosition
= oldXPProximityPosition
;
1539 xpctxt
->namespaces
= oldXPNamespaces
;
1540 xpctxt
->nsNr
= oldXPNsNr
;
1542 xmlXPathFreeCompExpr(xpExpr
);
1544 if (result
== NULL
) {
1545 xsltTransformError(ctxt
, style
, NULL
,
1546 "Evaluating user parameter %s failed\n", name
);
1547 ctxt
->state
= XSLT_STATE_STOPPED
;
1553 * If @eval is 0 then @value is to be taken literally and result is NULL
1555 * If @eval is not 0, then @value is an XPath expression and has been
1556 * successfully evaluated and result contains the resulting value and
1559 * Now create an xsltStackElemPtr for insertion into the context's
1560 * global variable/parameter hash table.
1563 #ifdef WITH_XSLT_DEBUG_VARIABLE
1564 #ifdef LIBXML_DEBUG_ENABLED
1565 if ((xsltGenericDebugContext
== stdout
) ||
1566 (xsltGenericDebugContext
== stderr
))
1567 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
1572 elem
= xsltNewStackElem(NULL
);
1575 elem
->select
= xmlDictLookup(ctxt
->dict
, value
, -1);
1577 elem
->nameURI
= xmlDictLookup(ctxt
->dict
, href
, -1);
1581 elem
->value
= xmlXPathNewString(value
);
1584 elem
->value
= result
;
1589 * Global parameters are stored in the XPath context variables pool.
1592 res
= xmlHashAddEntry2(ctxt
->globalVars
, name
, href
, elem
);
1594 xsltFreeStackElem(elem
);
1595 xsltTransformError(ctxt
, style
, NULL
,
1596 "Global parameter %s already defined\n", name
);
1602 * xsltEvalUserParams:
1604 * @ctxt: the XSLT transformation context
1605 * @params: a NULL terminated array of parameters name/value tuples
1607 * Evaluate the global variables of a stylesheet. This needs to be
1608 * done on parsed stylesheets before starting to apply transformations.
1609 * Each of the parameters is evaluated as an XPath expression and stored
1610 * in the global variables/parameter hash table. If you want your
1611 * parameter used literally, use xsltQuoteUserParams.
1613 * Returns 0 in case of success, -1 in case of error
1617 xsltEvalUserParams(xsltTransformContextPtr ctxt
, const char **params
) {
1619 const xmlChar
*name
;
1620 const xmlChar
*value
;
1624 while (params
[indx
] != NULL
) {
1625 name
= (const xmlChar
*) params
[indx
++];
1626 value
= (const xmlChar
*) params
[indx
++];
1627 if (xsltEvalOneUserParam(ctxt
, name
, value
) != 0)
1634 * xsltQuoteUserParams:
1636 * @ctxt: the XSLT transformation context
1637 * @params: a NULL terminated arry of parameters names/values tuples
1639 * Similar to xsltEvalUserParams, but the values are treated literally and
1640 * are * *not* evaluated as XPath expressions. This should be done on parsed
1641 * stylesheets before starting to apply transformations.
1643 * Returns 0 in case of success, -1 in case of error.
1647 xsltQuoteUserParams(xsltTransformContextPtr ctxt
, const char **params
) {
1649 const xmlChar
*name
;
1650 const xmlChar
*value
;
1654 while (params
[indx
] != NULL
) {
1655 name
= (const xmlChar
*) params
[indx
++];
1656 value
= (const xmlChar
*) params
[indx
++];
1657 if (xsltQuoteOneUserParam(ctxt
, name
, value
) != 0)
1664 * xsltEvalOneUserParam:
1665 * @ctxt: the XSLT transformation context
1666 * @name: a null terminated string giving the name of the parameter
1667 * @value: a null terminated string giving the XPath expression to be evaluated
1669 * This is normally called from xsltEvalUserParams to process a single
1670 * parameter from a list of parameters. The @value is evaluated as an
1671 * XPath expression and the result is stored in the context's global
1672 * variable/parameter hash table.
1674 * To have a parameter treated literally (not as an XPath expression)
1675 * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
1676 * details see description of xsltProcessOneUserParamInternal.
1678 * Returns 0 in case of success, -1 in case of error.
1682 xsltEvalOneUserParam(xsltTransformContextPtr ctxt
,
1683 const xmlChar
* name
,
1684 const xmlChar
* value
) {
1685 return xsltProcessUserParamInternal(ctxt
, name
, value
,
1686 1 /* xpath eval ? */);
1690 * xsltQuoteOneUserParam:
1691 * @ctxt: the XSLT transformation context
1692 * @name: a null terminated string giving the name of the parameter
1693 * @value: a null terminated string giving the parameter value
1695 * This is normally called from xsltQuoteUserParams to process a single
1696 * parameter from a list of parameters. The @value is stored in the
1697 * context's global variable/parameter hash table.
1699 * Returns 0 in case of success, -1 in case of error.
1703 xsltQuoteOneUserParam(xsltTransformContextPtr ctxt
,
1704 const xmlChar
* name
,
1705 const xmlChar
* value
) {
1706 return xsltProcessUserParamInternal(ctxt
, name
, value
,
1707 0 /* xpath eval ? */);
1711 * xsltBuildVariable:
1712 * @ctxt: the XSLT transformation context
1713 * @comp: the precompiled form
1714 * @tree: the tree if select is NULL
1716 * Computes a new variable value.
1718 * Returns the xsltStackElemPtr or NULL in case of error
1720 static xsltStackElemPtr
1721 xsltBuildVariable(xsltTransformContextPtr ctxt
,
1722 xsltStylePreCompPtr castedComp
,
1725 #ifdef XSLT_REFACTORED
1726 xsltStyleBasicItemVariablePtr comp
=
1727 (xsltStyleBasicItemVariablePtr
) castedComp
;
1729 xsltStylePreCompPtr comp
= castedComp
;
1731 xsltStackElemPtr elem
;
1733 #ifdef WITH_XSLT_DEBUG_VARIABLE
1734 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1735 "Building variable %s", comp
->name
));
1736 if (comp
->select
!= NULL
)
1737 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1738 " select %s", comp
->select
));
1739 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
, "\n"));
1742 elem
= xsltNewStackElem(ctxt
);
1745 elem
->comp
= (xsltStylePreCompPtr
) comp
;
1746 elem
->name
= comp
->name
;
1747 elem
->select
= comp
->select
;
1748 elem
->nameURI
= comp
->ns
;
1750 elem
->value
= xsltEvalVariable(ctxt
, elem
,
1751 (xsltStylePreCompPtr
) comp
);
1752 if (elem
->value
!= NULL
)
1758 * xsltRegisterVariable:
1759 * @ctxt: the XSLT transformation context
1760 * @comp: the compiled XSLT-variable (or param) instruction
1761 * @tree: the tree if select is NULL
1762 * @isParam: indicates if this is a parameter
1764 * Computes and registers a new variable.
1766 * Returns 0 in case of success, -1 in case of error
1769 xsltRegisterVariable(xsltTransformContextPtr ctxt
,
1770 xsltStylePreCompPtr castedComp
,
1771 xmlNodePtr tree
, int isParam
)
1773 #ifdef XSLT_REFACTORED
1774 xsltStyleBasicItemVariablePtr comp
=
1775 (xsltStyleBasicItemVariablePtr
) castedComp
;
1777 xsltStylePreCompPtr comp
= castedComp
;
1780 xsltStackElemPtr variable
;
1782 #ifdef XSLT_REFACTORED
1784 * REFACTORED NOTE: Redefinitions of vars/params are checked
1785 * at compilation time in the refactored code.
1786 * xsl:with-param parameters are checked in xsltApplyXSLTTemplate().
1789 present
= xsltCheckStackElem(ctxt
, comp
->name
, comp
->ns
);
1791 if ((present
!= 0) && (present
!= 3)) {
1792 /* TODO: report QName. */
1793 xsltTransformError(ctxt
, NULL
, comp
->inst
,
1794 "XSLT-variable: Redefinition of variable '%s'.\n", comp
->name
);
1797 } else if (present
!= 0) {
1798 if ((present
== 1) || (present
== 2)) {
1799 /* TODO: report QName. */
1800 xsltTransformError(ctxt
, NULL
, comp
->inst
,
1801 "XSLT-param: Redefinition of parameter '%s'.\n", comp
->name
);
1804 #ifdef WITH_XSLT_DEBUG_VARIABLE
1805 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1806 "param %s defined by caller\n", comp
->name
));
1810 #endif /* else of XSLT_REFACTORED */
1812 variable
= xsltBuildVariable(ctxt
, (xsltStylePreCompPtr
) comp
, tree
);
1813 xsltAddStackElem(ctxt
, variable
);
1818 * xsltGlobalVariableLookup:
1819 * @ctxt: the XSLT transformation context
1820 * @name: the variable name
1821 * @ns_uri: the variable namespace URI
1823 * Search in the Variable array of the context for the given
1826 * Returns the value or NULL if not found
1828 static xmlXPathObjectPtr
1829 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
1830 const xmlChar
*ns_uri
) {
1831 xsltStackElemPtr elem
;
1832 xmlXPathObjectPtr ret
= NULL
;
1835 * Lookup the global variables in XPath global variable hash table
1837 if ((ctxt
->xpathCtxt
== NULL
) || (ctxt
->globalVars
== NULL
))
1839 elem
= (xsltStackElemPtr
)
1840 xmlHashLookup2(ctxt
->globalVars
, name
, ns_uri
);
1842 #ifdef WITH_XSLT_DEBUG_VARIABLE
1843 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1844 "global variable not found %s\n", name
));
1849 * URGENT TODO: Move the detection of recursive definitions
1852 if (elem
->computed
== 0) {
1853 if (elem
->name
== xsltComputingGlobalVarMarker
) {
1854 xsltTransformError(ctxt
, NULL
, elem
->comp
->inst
,
1855 "Recursive definition of %s\n", name
);
1858 ret
= xsltEvalGlobalVariable(elem
, ctxt
);
1861 return(xmlXPathObjectCopy(ret
));
1865 * xsltVariableLookup:
1866 * @ctxt: the XSLT transformation context
1867 * @name: the variable name
1868 * @ns_uri: the variable namespace URI
1870 * Search in the Variable array of the context for the given
1873 * Returns the value or NULL if not found
1876 xsltVariableLookup(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
1877 const xmlChar
*ns_uri
) {
1878 xsltStackElemPtr elem
;
1883 elem
= xsltStackLookup(ctxt
, name
, ns_uri
);
1885 return(xsltGlobalVariableLookup(ctxt
, name
, ns_uri
));
1887 if (elem
->computed
== 0) {
1888 #ifdef WITH_XSLT_DEBUG_VARIABLE
1889 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1890 "uncomputed variable %s\n", name
));
1892 elem
->value
= xsltEvalVariable(ctxt
, elem
, NULL
);
1895 if (elem
->value
!= NULL
)
1896 return(xmlXPathObjectCopy(elem
->value
));
1897 #ifdef WITH_XSLT_DEBUG_VARIABLE
1898 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1899 "variable not found %s\n", name
));
1905 * xsltParseStylesheetCallerParam:
1906 * @ctxt: the XSLT transformation context
1907 * @inst: the xsl:with-param instruction element
1909 * Processes an xsl:with-param instruction at transformation time.
1910 * The value is compute, but not recorded.
1911 * NOTE that this is also called with an *xsl:param* element
1912 * from exsltFuncFunctionFunction().
1914 * Returns the new xsltStackElemPtr or NULL
1918 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt
, xmlNodePtr inst
)
1920 #ifdef XSLT_REFACTORED
1921 xsltStyleBasicItemVariablePtr comp
;
1923 xsltStylePreCompPtr comp
;
1925 xmlNodePtr tree
= NULL
; /* The first child node of the instruction or
1926 the instruction itself. */
1927 xsltStackElemPtr param
= NULL
;
1929 if ((ctxt
== NULL
) || (inst
== NULL
))
1932 #ifdef XSLT_REFACTORED
1933 comp
= (xsltStyleBasicItemVariablePtr
) inst
->psvi
;
1935 comp
= (xsltStylePreCompPtr
) inst
->psvi
;
1939 xsltTransformError(ctxt
, NULL
, inst
,
1940 "Internal error in xsltParseStylesheetCallerParam(): "
1941 "The XSLT 'with-param' instruction was not compiled.\n");
1944 if (comp
->name
== NULL
) {
1945 xsltTransformError(ctxt
, NULL
, inst
,
1946 "Internal error in xsltParseStylesheetCallerParam(): "
1947 "XSLT 'with-param': The attribute 'name' was not compiled.\n");
1951 #ifdef WITH_XSLT_DEBUG_VARIABLE
1952 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1953 "Handling xsl:with-param %s\n", comp
->name
));
1956 if (comp
->select
== NULL
) {
1957 tree
= inst
->children
;
1959 #ifdef WITH_XSLT_DEBUG_VARIABLE
1960 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1961 " select %s\n", comp
->select
));
1966 param
= xsltBuildVariable(ctxt
, (xsltStylePreCompPtr
) comp
, tree
);
1972 * xsltParseGlobalVariable:
1973 * @style: the XSLT stylesheet
1974 * @cur: the "variable" element
1976 * Parses a global XSLT 'variable' declaration at compilation time
1980 xsltParseGlobalVariable(xsltStylesheetPtr style
, xmlNodePtr cur
)
1982 #ifdef XSLT_REFACTORED
1983 xsltStyleItemVariablePtr comp
;
1985 xsltStylePreCompPtr comp
;
1988 if ((cur
== NULL
) || (style
== NULL
))
1991 #ifdef XSLT_REFACTORED
1993 * Note that xsltStylePreCompute() will be called from
1996 comp
= (xsltStyleItemVariablePtr
) cur
->psvi
;
1998 xsltStylePreCompute(style
, cur
);
1999 comp
= (xsltStylePreCompPtr
) cur
->psvi
;
2002 xsltTransformError(NULL
, style
, cur
,
2003 "xsl:variable : compilation failed\n");
2007 if (comp
->name
== NULL
) {
2008 xsltTransformError(NULL
, style
, cur
,
2009 "xsl:variable : missing name attribute\n");
2014 * Parse the content (a sequence constructor) of xsl:variable.
2016 if (cur
->children
!= NULL
) {
2017 #ifdef XSLT_REFACTORED
2018 xsltParseSequenceConstructor(XSLT_CCTXT(style
), cur
->children
);
2020 xsltParseTemplateContent(style
, cur
);
2023 #ifdef WITH_XSLT_DEBUG_VARIABLE
2024 xsltGenericDebug(xsltGenericDebugContext
,
2025 "Registering global variable %s\n", comp
->name
);
2028 xsltRegisterGlobalVariable(style
, comp
->name
, comp
->ns
,
2029 comp
->select
, cur
->children
, (xsltStylePreCompPtr
) comp
,
2034 * xsltParseGlobalParam:
2035 * @style: the XSLT stylesheet
2036 * @cur: the "param" element
2038 * parse an XSLT transformation param declaration and record
2043 xsltParseGlobalParam(xsltStylesheetPtr style
, xmlNodePtr cur
) {
2044 #ifdef XSLT_REFACTORED
2045 xsltStyleItemParamPtr comp
;
2047 xsltStylePreCompPtr comp
;
2050 if ((cur
== NULL
) || (style
== NULL
))
2053 #ifdef XSLT_REFACTORED
2055 * Note that xsltStylePreCompute() will be called from
2058 comp
= (xsltStyleItemParamPtr
) cur
->psvi
;
2060 xsltStylePreCompute(style
, cur
);
2061 comp
= (xsltStylePreCompPtr
) cur
->psvi
;
2064 xsltTransformError(NULL
, style
, cur
,
2065 "xsl:param : compilation failed\n");
2069 if (comp
->name
== NULL
) {
2070 xsltTransformError(NULL
, style
, cur
,
2071 "xsl:param : missing name attribute\n");
2076 * Parse the content (a sequence constructor) of xsl:param.
2078 if (cur
->children
!= NULL
) {
2079 #ifdef XSLT_REFACTORED
2080 xsltParseSequenceConstructor(XSLT_CCTXT(style
), cur
->children
);
2082 xsltParseTemplateContent(style
, cur
);
2086 #ifdef WITH_XSLT_DEBUG_VARIABLE
2087 xsltGenericDebug(xsltGenericDebugContext
,
2088 "Registering global param %s\n", comp
->name
);
2091 xsltRegisterGlobalVariable(style
, comp
->name
, comp
->ns
,
2092 comp
->select
, cur
->children
, (xsltStylePreCompPtr
) comp
,
2097 * xsltParseStylesheetVariable:
2098 * @ctxt: the XSLT transformation context
2099 * @inst: the xsl:variable instruction element
2101 * Registers a local XSLT 'variable' instruction at transformation time
2102 * and evaluates its value.
2105 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt
, xmlNodePtr inst
)
2107 #ifdef XSLT_REFACTORED
2108 xsltStyleItemVariablePtr comp
;
2110 xsltStylePreCompPtr comp
;
2113 if ((inst
== NULL
) || (ctxt
== NULL
))
2118 xsltTransformError(ctxt
, NULL
, inst
,
2119 "Internal error in xsltParseStylesheetVariable(): "
2120 "The XSLT 'variable' instruction was not compiled.\n");
2123 if (comp
->name
== NULL
) {
2124 xsltTransformError(ctxt
, NULL
, inst
,
2125 "Internal error in xsltParseStylesheetVariable(): "
2126 "The attribute 'name' was not compiled.\n");
2130 #ifdef WITH_XSLT_DEBUG_VARIABLE
2131 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2132 "Registering variable '%s'\n", comp
->name
));
2135 xsltRegisterVariable(ctxt
, (xsltStylePreCompPtr
) comp
, inst
->children
, 0);
2139 * xsltParseStylesheetParam:
2140 * @ctxt: the XSLT transformation context
2141 * @cur: the XSLT 'param' element
2143 * Registers a local XSLT 'param' declaration at transformation time and
2144 * evaluates its value.
2147 xsltParseStylesheetParam(xsltTransformContextPtr ctxt
, xmlNodePtr cur
)
2149 #ifdef XSLT_REFACTORED
2150 xsltStyleItemParamPtr comp
;
2152 xsltStylePreCompPtr comp
;
2155 if ((cur
== NULL
) || (ctxt
== NULL
))
2159 if ((comp
== NULL
) || (comp
->name
== NULL
)) {
2160 xsltTransformError(ctxt
, NULL
, cur
,
2161 "Internal error in xsltParseStylesheetParam(): "
2162 "The XSLT 'param' declaration was not compiled correctly.\n");
2166 #ifdef WITH_XSLT_DEBUG_VARIABLE
2167 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2168 "Registering param %s\n", comp
->name
));
2171 xsltRegisterVariable(ctxt
, (xsltStylePreCompPtr
) comp
, cur
->children
, 1);
2175 * xsltFreeGlobalVariables:
2176 * @ctxt: the XSLT transformation context
2178 * Free up the data associated to the global variables
2183 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt
) {
2184 xmlHashFree(ctxt
->globalVars
, (xmlHashDeallocator
) xsltFreeStackElem
);
2188 * xsltXPathVariableLookup:
2189 * @ctxt: a void * but the the XSLT transformation context actually
2190 * @name: the variable name
2191 * @ns_uri: the variable namespace URI
2193 * This is the entry point when a varibale is needed by the XPath
2196 * Returns the value or NULL if not found
2199 xsltXPathVariableLookup(void *ctxt
, const xmlChar
*name
,
2200 const xmlChar
*ns_uri
) {
2201 xsltTransformContextPtr tctxt
;
2202 xmlXPathObjectPtr valueObj
= NULL
;
2204 if ((ctxt
== NULL
) || (name
== NULL
))
2207 #ifdef WITH_XSLT_DEBUG_VARIABLE
2208 XSLT_TRACE(((xsltTransformContextPtr
)ctxt
),XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2209 "Lookup variable '%s'\n", name
));
2212 tctxt
= (xsltTransformContextPtr
) ctxt
;
2214 * Local variables/params ---------------------------------------------
2216 * Do the lookup from the top of the stack, but
2217 * don't use params being computed in a call-param
2218 * First lookup expects the variable name and URI to
2219 * come from the disctionnary and hence pointer comparison.
2221 if (tctxt
->varsNr
!= 0) {
2223 xsltStackElemPtr variable
= NULL
, cur
;
2225 for (i
= tctxt
->varsNr
; i
> tctxt
->varsBase
; i
--) {
2226 cur
= tctxt
->varsTab
[i
-1];
2227 if ((cur
->name
== name
) && (cur
->nameURI
== ns_uri
)) {
2232 goto local_variable_found
;
2237 * Redo the lookup with interned strings to avoid string comparison.
2239 * OPTIMIZE TODO: The problem here is, that if we request a
2240 * global variable, then this will be also executed.
2243 const xmlChar
*tmpName
= name
, *tmpNsName
= ns_uri
;
2245 name
= xmlDictLookup(tctxt
->dict
, name
, -1);
2247 ns_uri
= xmlDictLookup(tctxt
->dict
, ns_uri
, -1);
2248 if ((tmpName
!= name
) || (tmpNsName
!= ns_uri
)) {
2249 for (i
= tctxt
->varsNr
; i
> tctxt
->varsBase
; i
--) {
2250 cur
= tctxt
->varsTab
[i
-1];
2251 if ((cur
->name
== name
) && (cur
->nameURI
== ns_uri
)) {
2256 goto local_variable_found
;
2262 local_variable_found
:
2265 if (variable
->computed
== 0) {
2267 #ifdef WITH_XSLT_DEBUG_VARIABLE
2268 XSLT_TRACE(tctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2269 "uncomputed variable '%s'\n", name
));
2271 variable
->value
= xsltEvalVariable(tctxt
, variable
, NULL
);
2272 variable
->computed
= 1;
2274 if (variable
->value
!= NULL
) {
2275 valueObj
= xmlXPathObjectCopy(variable
->value
);
2281 * Global variables/params --------------------------------------------
2283 if (tctxt
->globalVars
) {
2284 valueObj
= xsltGlobalVariableLookup(tctxt
, name
, ns_uri
);
2287 if (valueObj
== NULL
) {
2289 #ifdef WITH_XSLT_DEBUG_VARIABLE
2290 XSLT_TRACE(tctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2291 "variable not found '%s'\n", name
));
2295 xsltTransformError(tctxt
, NULL
, tctxt
->inst
,
2296 "Variable '{%s}%s' has not been declared.\n", ns_uri
, name
);
2298 xsltTransformError(tctxt
, NULL
, tctxt
->inst
,
2299 "Variable '%s' has not been declared.\n", name
);
2303 #ifdef WITH_XSLT_DEBUG_VARIABLE
2304 XSLT_TRACE(tctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2305 "found variable '%s'\n", name
));