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.
14 #ifdef WITH_XSLT_DEBUG
15 #define WITH_XSLT_DEBUG_VARIABLE
18 #ifdef XSLT_REFACTORED
19 const xmlChar
*xsltDocFragFake
= (const xmlChar
*) " fake node libxslt";
22 const xmlChar
*xsltComputingGlobalVarMarker
=
23 (const xmlChar
*) " var/param being computed";
25 #define XSLT_VAR_GLOBAL 1<<0
26 #define XSLT_VAR_IN_SELECT 1<<1
27 #define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable)
29 /************************************************************************
31 * Result Value Tree (Result Tree Fragment) interfaces *
33 ************************************************************************/
36 * @ctxt: an XSLT transformation context
38 * Creates a Result Value Tree
39 * (the XSLT 1.0 term for this is "Result Tree Fragment")
41 * Returns the result value tree or NULL in case of API or internal errors.
44 xsltCreateRVT(xsltTransformContextPtr ctxt
)
49 * Question: Why is this function public?
50 * Answer: It is called by the EXSLT module.
56 * Reuse a RTF from the cache if available.
58 if (ctxt
->cache
->RVT
) {
59 container
= ctxt
->cache
->RVT
;
60 ctxt
->cache
->RVT
= (xmlDocPtr
) container
->next
;
61 /* clear the internal pointers */
62 container
->next
= NULL
;
63 container
->prev
= NULL
;
64 if (ctxt
->cache
->nbRVT
> 0)
66 #ifdef XSLT_DEBUG_PROFILE_CACHE
67 ctxt
->cache
->dbgReusedRVTs
++;
72 container
= xmlNewDoc(NULL
);
73 if (container
== NULL
)
75 container
->dict
= ctxt
->dict
;
76 xmlDictReference(container
->dict
);
77 XSLT_MARK_RES_TREE_FRAG(container
);
78 container
->doc
= container
;
79 container
->parent
= NULL
;
85 * @ctxt: an XSLT transformation context
86 * @RVT: a result value tree (Result Tree Fragment)
88 * Registers the result value tree (XSLT 1.0 term: Result Tree Fragment)
89 * in the garbage collector.
90 * The fragment will be freed at the exit of the currently
91 * instantiated xsl:template.
92 * Obsolete; this function might produce massive memory overhead,
93 * since the fragment is only freed when the current xsl:template
94 * exits. Use xsltRegisterLocalRVT() instead.
96 * Returns 0 in case of success and -1 in case of API or internal errors.
99 xsltRegisterTmpRVT(xsltTransformContextPtr ctxt
, xmlDocPtr RVT
)
101 if ((ctxt
== NULL
) || (RVT
== NULL
))
105 * We'll restrict the lifetime of user-created fragments
106 * insinde an xsl:variable and xsl:param to the lifetime of the
109 if (ctxt
->contextVariable
!= NULL
) {
110 RVT
->next
= (xmlNodePtr
) XSLT_TCTXT_VARIABLE(ctxt
)->fragment
;
111 XSLT_TCTXT_VARIABLE(ctxt
)->fragment
= RVT
;
115 RVT
->next
= (xmlNodePtr
) ctxt
->tmpRVT
;
116 if (ctxt
->tmpRVT
!= NULL
)
117 ctxt
->tmpRVT
->prev
= (xmlNodePtr
) RVT
;
123 * xsltRegisterLocalRVT:
124 * @ctxt: an XSLT transformation context
125 * @RVT: a result value tree (Result Tree Fragment; xmlDocPtr)
127 * Registers a result value tree (XSLT 1.0 term: Result Tree Fragment)
128 * in the RVT garbage collector.
129 * The fragment will be freed when the instruction which created the
132 * Returns 0 in case of success and -1 in case of API or internal errors.
135 xsltRegisterLocalRVT(xsltTransformContextPtr ctxt
,
138 if ((ctxt
== NULL
) || (RVT
== NULL
))
142 * When evaluating "select" expressions of xsl:variable
143 * and xsl:param, we need to bind newly created tree fragments
144 * to the variable itself; otherwise the tragment will be
145 * freed before we leave the scope of a var.
147 if ((ctxt
->contextVariable
!= NULL
) &&
148 (XSLT_TCTXT_VARIABLE(ctxt
)->flags
& XSLT_VAR_IN_SELECT
))
150 RVT
->next
= (xmlNodePtr
) XSLT_TCTXT_VARIABLE(ctxt
)->fragment
;
151 XSLT_TCTXT_VARIABLE(ctxt
)->fragment
= RVT
;
155 * Store the fragment in the scope of the current instruction.
156 * If not reference by a returning instruction (like EXSLT's function),
157 * then this fragment will be freed, when the instruction exits.
159 RVT
->next
= (xmlNodePtr
) ctxt
->localRVT
;
160 if (ctxt
->localRVT
!= NULL
)
161 ctxt
->localRVT
->prev
= (xmlNodePtr
) RVT
;
162 ctxt
->localRVT
= RVT
;
164 * We need to keep track of the first registered fragment
165 * for extension instructions which return fragments
166 * (e.g. EXSLT'S function), in order to let
167 * xsltExtensionInstructionResultFinalize() clear the
168 * preserving flag on the fragments.
170 if (ctxt
->localRVTBase
== NULL
)
171 ctxt
->localRVTBase
= RVT
;
176 * xsltExtensionInstructionResultFinalize:
177 * @ctxt: an XSLT transformation context
179 * Finalizes the data (e.g. result tree fragments) created
180 * within a value-returning process (e.g. EXSLT's function).
181 * Tree fragments marked as being returned by a function are
182 * set to normal state, which means that the fragment garbage
183 * collector will free them after the function-calling process exits.
185 * Returns 0 in case of success and -1 in case of API or internal errors.
188 xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt
)
194 if (ctxt
->localRVTBase
== NULL
)
197 * Enable remaining local tree fragments to be freed
198 * by the fragment garbage collector.
200 cur
= ctxt
->localRVTBase
;
203 cur
= (xmlDocPtr
) cur
->next
;
204 } while (cur
!= NULL
);
209 * xsltExtensionInstructionResultRegister:
210 * @ctxt: an XSLT transformation context
211 * @obj: an XPath object to be inspected for result tree fragments
213 * Marks the result of a value-returning extension instruction
214 * in order to avoid it being garbage collected before the
215 * extension instruction exits.
216 * Note that one still has to additionally register any newly created
217 * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT().
219 * Returns 0 in case of success and -1 in case of error.
222 xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt
,
223 xmlXPathObjectPtr obj
)
229 if ((ctxt
== NULL
) || (obj
== NULL
))
233 * OPTIMIZE TODO: If no local variables/params and no local tree
234 * fragments were created, then we don't need to analyse the XPath
235 * objects for tree fragments.
238 if ((obj
->type
!= XPATH_NODESET
) && (obj
->type
!= XPATH_XSLT_TREE
))
240 if ((obj
->nodesetval
== NULL
) || (obj
->nodesetval
->nodeNr
== 0))
243 for (i
= 0; i
< obj
->nodesetval
->nodeNr
; i
++) {
244 cur
= obj
->nodesetval
->nodeTab
[i
];
245 if (cur
->type
== XML_NAMESPACE_DECL
) {
247 * The XPath module sets the owner element of a ns-node on
248 * the ns->next field.
250 if ((((xmlNsPtr
) cur
)->next
!= NULL
) &&
251 (((xmlNsPtr
) cur
)->next
->type
== XML_ELEMENT_NODE
))
253 cur
= (xmlNodePtr
) ((xmlNsPtr
) cur
)->next
;
256 xsltTransformError(ctxt
, NULL
, ctxt
->inst
,
258 "xsltExtensionInstructionResultRegister(): "
259 "Cannot retrieve the doc of a namespace node.\n");
266 xsltTransformError(ctxt
, NULL
, ctxt
->inst
,
268 "xsltExtensionInstructionResultRegister(): "
269 "Cannot retrieve the doc of a node.\n");
272 if (doc
->name
&& (doc
->name
[0] == ' ')) {
274 * This is a result tree fragment.
275 * We'll use the @psvi field for reference counting.
276 * TODO: How do we know if this is a value of a
277 * global variable or a doc acquired via the
278 * document() function?
280 doc
->psvi
= (void *) ((long) 1);
291 * @ctxt: an XSLT transformation context
292 * @RVT: a result value tree (Result Tree Fragment)
294 * Either frees the RVT (which is an xmlDoc) or stores
295 * it in the context's cache for later reuse.
298 xsltReleaseRVT(xsltTransformContextPtr ctxt
, xmlDocPtr RVT
)
303 if (ctxt
&& (ctxt
->cache
->nbRVT
< 40)) {
305 * Store the Result Tree Fragment.
306 * Free the document info.
308 if (RVT
->_private
!= NULL
) {
309 xsltFreeDocumentKeys((xsltDocumentPtr
) RVT
->_private
);
310 xmlFree(RVT
->_private
);
311 RVT
->_private
= NULL
;
314 * Clear the document tree.
315 * REVISIT TODO: Do we expect ID/IDREF tables to be existent?
317 if (RVT
->children
!= NULL
) {
318 xmlFreeNodeList(RVT
->children
);
319 RVT
->children
= NULL
;
322 if (RVT
->ids
!= NULL
) {
323 xmlFreeIDTable((xmlIDTablePtr
) RVT
->ids
);
326 if (RVT
->refs
!= NULL
) {
327 xmlFreeRefTable((xmlRefTablePtr
) RVT
->refs
);
332 * Reset the reference counter.
336 RVT
->next
= (xmlNodePtr
) ctxt
->cache
->RVT
;
337 ctxt
->cache
->RVT
= RVT
;
339 ctxt
->cache
->nbRVT
++;
341 #ifdef XSLT_DEBUG_PROFILE_CACHE
342 ctxt
->cache
->dbgCachedRVTs
++;
349 if (RVT
->_private
!= NULL
) {
350 xsltFreeDocumentKeys((xsltDocumentPtr
) RVT
->_private
);
351 xmlFree(RVT
->_private
);
357 * xsltRegisterPersistRVT:
358 * @ctxt: an XSLT transformation context
359 * @RVT: a result value tree (Result Tree Fragment)
361 * Register the result value tree (XSLT 1.0 term: Result Tree Fragment)
362 * in the fragment garbage collector.
363 * The fragment will be freed when the transformation context is
366 * Returns 0 in case of success and -1 in case of error.
369 xsltRegisterPersistRVT(xsltTransformContextPtr ctxt
, xmlDocPtr RVT
)
371 if ((ctxt
== NULL
) || (RVT
== NULL
)) return(-1);
373 RVT
->next
= (xmlNodePtr
) ctxt
->persistRVT
;
374 if (ctxt
->persistRVT
!= NULL
)
375 ctxt
->persistRVT
->prev
= (xmlNodePtr
) RVT
;
376 ctxt
->persistRVT
= RVT
;
382 * @ctxt: an XSLT transformation context
384 * Frees all registered result value trees (Result Tree Fragments)
385 * of the transformation. Internal function; should not be called
389 xsltFreeRVTs(xsltTransformContextPtr ctxt
)
398 cur
= ctxt
->localRVT
;
399 while (cur
!= NULL
) {
400 next
= (xmlDocPtr
) cur
->next
;
401 if (cur
->_private
!= NULL
) {
402 xsltFreeDocumentKeys(cur
->_private
);
403 xmlFree(cur
->_private
);
408 ctxt
->localRVT
= NULL
;
410 * User-created per-template fragments.
413 while (cur
!= NULL
) {
414 next
= (xmlDocPtr
) cur
->next
;
415 if (cur
->_private
!= NULL
) {
416 xsltFreeDocumentKeys(cur
->_private
);
417 xmlFree(cur
->_private
);
426 cur
= ctxt
->persistRVT
;
427 while (cur
!= NULL
) {
428 next
= (xmlDocPtr
) cur
->next
;
429 if (cur
->_private
!= NULL
) {
430 xsltFreeDocumentKeys(cur
->_private
);
431 xmlFree(cur
->_private
);
436 ctxt
->persistRVT
= NULL
;
439 /************************************************************************
441 * Module interfaces *
443 ************************************************************************/
448 * Create a new XSLT ParserContext
450 * Returns the newly allocated xsltParserStackElem or NULL in case of error
452 static xsltStackElemPtr
453 xsltNewStackElem(xsltTransformContextPtr ctxt
)
455 xsltStackElemPtr ret
;
457 * Reuse a stack item from the cache if available.
459 if (ctxt
&& ctxt
->cache
->stackItems
) {
460 ret
= ctxt
->cache
->stackItems
;
461 ctxt
->cache
->stackItems
= ret
->next
;
463 ctxt
->cache
->nbStackItems
--;
464 #ifdef XSLT_DEBUG_PROFILE_CACHE
465 ctxt
->cache
->dbgReusedVars
++;
469 ret
= (xsltStackElemPtr
) xmlMalloc(sizeof(xsltStackElem
));
471 xsltTransformError(NULL
, NULL
, NULL
,
472 "xsltNewStackElem : malloc failed\n");
475 memset(ret
, 0, sizeof(xsltStackElem
));
482 * @elem: an XSLT stack element
484 * Makes a copy of the stack element
486 * Returns the copy of NULL
488 static xsltStackElemPtr
489 xsltCopyStackElem(xsltStackElemPtr elem
) {
490 xsltStackElemPtr cur
;
492 cur
= (xsltStackElemPtr
) xmlMalloc(sizeof(xsltStackElem
));
494 xsltTransformError(NULL
, NULL
, NULL
,
495 "xsltCopyStackElem : malloc failed\n");
498 memset(cur
, 0, sizeof(xsltStackElem
));
499 cur
->context
= elem
->context
;
500 cur
->name
= elem
->name
;
501 cur
->nameURI
= elem
->nameURI
;
502 cur
->select
= elem
->select
;
503 cur
->tree
= elem
->tree
;
504 cur
->comp
= elem
->comp
;
510 * @elem: an XSLT stack element
512 * Free up the memory allocated by @elem
515 xsltFreeStackElem(xsltStackElemPtr elem
) {
518 if (elem
->value
!= NULL
)
519 xmlXPathFreeObject(elem
->value
);
521 * Release the list of temporary Result Tree Fragments.
523 if (elem
->fragment
) {
526 while (elem
->fragment
!= NULL
) {
527 cur
= elem
->fragment
;
528 elem
->fragment
= (xmlDocPtr
) cur
->next
;
531 (cur
->psvi
== (void *) ((long) 1)))
534 * This fragment is a result of an extension instruction
535 * (e.g. XSLT's function) and needs to be preserved until
536 * the instruction exits.
537 * Example: The fragment of the variable must not be freed
538 * since it is returned by the EXSLT function:
539 * <f:function name="foo">
540 * <xsl:variable name="bar">
543 * <f:result select="$bar"/>
547 xsltRegisterLocalRVT(elem
->context
, cur
);
549 xsltReleaseRVT((xsltTransformContextPtr
) elem
->context
,
555 * Cache or free the variable structure.
557 if (elem
->context
&& (elem
->context
->cache
->nbStackItems
< 50)) {
559 * Store the item in the cache.
561 xsltTransformContextPtr ctxt
= elem
->context
;
562 memset(elem
, 0, sizeof(xsltStackElem
));
563 elem
->context
= ctxt
;
564 elem
->next
= ctxt
->cache
->stackItems
;
565 ctxt
->cache
->stackItems
= elem
;
566 ctxt
->cache
->nbStackItems
++;
567 #ifdef XSLT_DEBUG_PROFILE_CACHE
568 ctxt
->cache
->dbgCachedVars
++;
576 * xsltFreeStackElemList:
577 * @elem: an XSLT stack element
579 * Free up the memory allocated by @elem
582 xsltFreeStackElemList(xsltStackElemPtr elem
) {
583 xsltStackElemPtr next
;
585 while (elem
!= NULL
) {
587 xsltFreeStackElem(elem
);
594 * @ctxt: an XSLT transformation context
595 * @name: the local part of the name
596 * @nameURI: the URI part of the name
598 * Locate an element in the stack based on its name.
600 #if 0 /* TODO: Those seem to have been used for debugging. */
601 static int stack_addr
= 0;
602 static int stack_cmp
= 0;
605 static xsltStackElemPtr
606 xsltStackLookup(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
607 const xmlChar
*nameURI
) {
609 xsltStackElemPtr cur
;
611 if ((ctxt
== NULL
) || (name
== NULL
) || (ctxt
->varsNr
== 0))
615 * Do the lookup from the top of the stack, but
616 * don't use params being computed in a call-param
617 * First lookup expects the variable name and URI to
618 * come from the disctionnary and hence pointer comparison.
620 for (i
= ctxt
->varsNr
; i
> ctxt
->varsBase
; i
--) {
621 cur
= ctxt
->varsTab
[i
-1];
622 while (cur
!= NULL
) {
623 if ((cur
->name
== name
) && (cur
->nameURI
== nameURI
)) {
634 * Redo the lookup with interned string compares
635 * to avoid string compares.
637 name
= xmlDictLookup(ctxt
->dict
, name
, -1);
639 nameURI
= xmlDictLookup(ctxt
->dict
, nameURI
, -1);
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
)) {
657 #ifdef XSLT_REFACTORED
661 * xsltCheckStackElem:
662 * @ctxt: xn XSLT transformation context
663 * @name: the variable name
664 * @nameURI: the variable namespace URI
666 * Checks whether a variable or param is already defined.
668 * URGENT TODO: Checks for redefinition of vars/params should be
669 * done only at compilation time.
671 * Returns 1 if variable is present, 2 if param is present, 3 if this
672 * is an inherited param, 0 if not found, -1 in case of failure.
675 xsltCheckStackElem(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
676 const xmlChar
*nameURI
) {
677 xsltStackElemPtr cur
;
679 if ((ctxt
== NULL
) || (name
== NULL
))
682 cur
= xsltStackLookup(ctxt
, name
, nameURI
);
685 if (cur
->comp
!= NULL
) {
686 if (cur
->comp
->type
== XSLT_FUNC_WITHPARAM
)
688 else if (cur
->comp
->type
== XSLT_FUNC_PARAM
)
695 #endif /* XSLT_REFACTORED */
699 * @ctxt: xn XSLT transformation context
700 * @elem: a stack element
702 * Push an element (or list) onto the stack.
703 * In case of a list, each member will be pushed into
704 * a seperate slot; i.e. there's always 1 stack entry for
707 * Returns 0 in case of success, -1 in case of failure.
710 xsltAddStackElem(xsltTransformContextPtr ctxt
, xsltStackElemPtr elem
)
712 if ((ctxt
== NULL
) || (elem
== NULL
))
716 if (ctxt
->varsMax
== 0) {
719 (xsltStackElemPtr
*) xmlMalloc(ctxt
->varsMax
*
720 sizeof(ctxt
->varsTab
[0]));
721 if (ctxt
->varsTab
== NULL
) {
722 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
726 if (ctxt
->varsNr
>= ctxt
->varsMax
) {
729 (xsltStackElemPtr
*) xmlRealloc(ctxt
->varsTab
,
731 sizeof(ctxt
->varsTab
[0]));
732 if (ctxt
->varsTab
== NULL
) {
733 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
737 ctxt
->varsTab
[ctxt
->varsNr
++] = elem
;
741 } while (elem
!= NULL
);
747 * xsltAddStackElemList:
748 * @ctxt: xn XSLT transformation context
749 * @elems: a stack element list
751 * Push an element list onto the stack.
753 * Returns 0 in case of success, -1 in case of failure.
756 xsltAddStackElemList(xsltTransformContextPtr ctxt
, xsltStackElemPtr elems
)
758 return(xsltAddStackElem(ctxt
, elems
));
761 /************************************************************************
763 * Module interfaces *
765 ************************************************************************/
769 * @ctxt: the XSLT transformation context
770 * @variable: the variable or parameter item
771 * @comp: the compiled XSLT instruction
773 * Evaluate a variable value.
775 * Returns the XPath Object value or NULL in case of error
777 static xmlXPathObjectPtr
778 xsltEvalVariable(xsltTransformContextPtr ctxt
, xsltStackElemPtr variable
,
779 xsltStylePreCompPtr castedComp
)
781 #ifdef XSLT_REFACTORED
782 xsltStyleItemVariablePtr comp
=
783 (xsltStyleItemVariablePtr
) castedComp
;
785 xsltStylePreCompPtr comp
= castedComp
;
787 xmlXPathObjectPtr result
= NULL
;
790 if ((ctxt
== NULL
) || (variable
== NULL
))
794 * A variable or parameter are evaluated on demand; thus the
795 * context (of XSLT and XPath) need to be temporarily adjusted and
798 oldInst
= ctxt
->inst
;
800 #ifdef WITH_XSLT_DEBUG_VARIABLE
801 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
802 "Evaluating variable '%s'\n", variable
->name
));
804 if (variable
->select
!= NULL
) {
805 xmlXPathCompExprPtr xpExpr
= NULL
;
807 xmlNodePtr oldXPContextNode
;
808 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
809 xmlNsPtr
*oldXPNamespaces
;
810 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
811 xsltStackElemPtr oldVar
= ctxt
->contextVariable
;
813 if ((comp
!= NULL
) && (comp
->comp
!= NULL
)) {
816 xpExpr
= xmlXPathCompile(variable
->select
);
821 * Save context states.
823 oldXPDoc
= xpctxt
->doc
;
824 oldXPContextNode
= xpctxt
->node
;
825 oldXPProximityPosition
= xpctxt
->proximityPosition
;
826 oldXPContextSize
= xpctxt
->contextSize
;
827 oldXPNamespaces
= xpctxt
->namespaces
;
828 oldXPNsNr
= xpctxt
->nsNr
;
830 xpctxt
->node
= ctxt
->node
;
832 * OPTIMIZE TODO: Lame try to set the context doc.
833 * Get rid of this somehow in xpath.c.
835 if ((ctxt
->node
->type
!= XML_NAMESPACE_DECL
) &&
837 xpctxt
->doc
= ctxt
->node
->doc
;
839 * BUG TODO: The proximity position and the context size will
840 * potentially be wrong.
842 * <xsl:template select="foo">
843 * <xsl:variable name="pos" select="position()"/>
844 * <xsl:for-each select="bar">
845 * <xsl:value-of select="$pos"/>
848 * Here the proximity position and context size are changed
849 * to the context of <xsl:for-each select="bar">, but
850 * the variable needs to be evaluated in the context of
851 * <xsl:template select="foo">.
855 #ifdef XSLT_REFACTORED
856 if (comp
->inScopeNs
!= NULL
) {
857 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
858 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
860 xpctxt
->namespaces
= NULL
;
864 xpctxt
->namespaces
= comp
->nsList
;
865 xpctxt
->nsNr
= comp
->nsNr
;
868 xpctxt
->namespaces
= NULL
;
873 * We need to mark that we are "selecting" a var's value;
874 * if any tree fragments are created inside the expression,
875 * then those need to be stored inside the variable; otherwise
876 * we'll eventually free still referenced fragments, before
877 * we leave the scope of the variable.
879 ctxt
->contextVariable
= variable
;
880 variable
->flags
|= XSLT_VAR_IN_SELECT
;
882 result
= xmlXPathCompiledEval(xpExpr
, xpctxt
);
884 variable
->flags
^= XSLT_VAR_IN_SELECT
;
886 * Restore Context states.
888 ctxt
->contextVariable
= oldVar
;
890 xpctxt
->doc
= oldXPDoc
;
891 xpctxt
->node
= oldXPContextNode
;
892 xpctxt
->contextSize
= oldXPContextSize
;
893 xpctxt
->proximityPosition
= oldXPProximityPosition
;
894 xpctxt
->namespaces
= oldXPNamespaces
;
895 xpctxt
->nsNr
= oldXPNsNr
;
897 if ((comp
== NULL
) || (comp
->comp
== NULL
))
898 xmlXPathFreeCompExpr(xpExpr
);
899 if (result
== NULL
) {
900 xsltTransformError(ctxt
, NULL
,
901 (comp
!= NULL
) ? comp
->inst
: NULL
,
902 "Failed to evaluate the expression of variable '%s'.\n",
904 ctxt
->state
= XSLT_STATE_STOPPED
;
906 #ifdef WITH_XSLT_DEBUG_VARIABLE
907 #ifdef LIBXML_DEBUG_ENABLED
909 if ((xsltGenericDebugContext
== stdout
) ||
910 (xsltGenericDebugContext
== stderr
))
911 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
917 if (variable
->tree
== NULL
) {
918 result
= xmlXPathNewCString("");
920 if (variable
->tree
) {
922 xmlNodePtr oldInsert
;
924 xsltStackElemPtr oldVar
= ctxt
->contextVariable
;
927 * Generate a result tree fragment.
929 container
= xsltCreateRVT(ctxt
);
930 if (container
== NULL
)
933 * NOTE: Local Result Tree Fragments of params/variables
934 * are not registered globally anymore; the life-time
935 * is not directly dependant of the param/variable itself.
937 * OLD: xsltRegisterTmpRVT(ctxt, container);
940 * Attach the Result Tree Fragment to the variable;
941 * when the variable is freed, it will also free
942 * the Result Tree Fragment.
944 variable
->fragment
= container
;
946 oldOutput
= ctxt
->output
;
947 oldInsert
= ctxt
->insert
;
949 ctxt
->output
= container
;
950 ctxt
->insert
= (xmlNodePtr
) container
;
951 ctxt
->contextVariable
= variable
;
953 * Process the sequence constructor (variable->tree).
954 * The resulting tree will be held by @container.
956 xsltApplyOneTemplate(ctxt
, ctxt
->node
, variable
->tree
,
959 ctxt
->contextVariable
= oldVar
;
960 ctxt
->insert
= oldInsert
;
961 ctxt
->output
= oldOutput
;
963 result
= xmlXPathNewValueTree((xmlNodePtr
) container
);
965 if (result
== NULL
) {
966 result
= xmlXPathNewCString("");
969 * Freeing is not handled there anymore.
970 * QUESTION TODO: What does the above comment mean?
974 #ifdef WITH_XSLT_DEBUG_VARIABLE
975 #ifdef LIBXML_DEBUG_ENABLED
977 if ((xsltGenericDebugContext
== stdout
) ||
978 (xsltGenericDebugContext
== stderr
))
979 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
987 ctxt
->inst
= oldInst
;
992 * xsltEvalGlobalVariable:
993 * @elem: the variable or parameter
994 * @ctxt: the XSLT transformation context
996 * Evaluates a the value of a global xsl:variable or
997 * xsl:param declaration.
999 * Returns the XPath Object value or NULL in case of error
1001 static xmlXPathObjectPtr
1002 xsltEvalGlobalVariable(xsltStackElemPtr elem
, xsltTransformContextPtr ctxt
)
1004 xmlXPathObjectPtr result
= NULL
;
1006 const xmlChar
* oldVarName
;
1008 #ifdef XSLT_REFACTORED
1009 xsltStyleBasicItemVariablePtr comp
;
1011 xsltStylePreCompPtr comp
;
1014 if ((ctxt
== NULL
) || (elem
== NULL
))
1017 return(elem
->value
);
1020 #ifdef WITH_XSLT_DEBUG_VARIABLE
1021 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1022 "Evaluating global variable %s\n", elem
->name
));
1025 #ifdef WITH_DEBUGGER
1026 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) &&
1027 elem
->comp
&& elem
->comp
->inst
)
1028 xslHandleDebugger(elem
->comp
->inst
, NULL
, NULL
, ctxt
);
1031 oldInst
= ctxt
->inst
;
1032 #ifdef XSLT_REFACTORED
1033 comp
= (xsltStyleBasicItemVariablePtr
) elem
->comp
;
1037 oldVarName
= elem
->name
;
1038 elem
->name
= xsltComputingGlobalVarMarker
;
1040 * OPTIMIZE TODO: We should consider instantiating global vars/params
1041 * on-demand. The vars/params don't need to be evaluated if never
1042 * called; and in the case of global params, if values for such params
1043 * are provided by the user.
1045 if (elem
->select
!= NULL
) {
1046 xmlXPathCompExprPtr xpExpr
= NULL
;
1048 xmlNodePtr oldXPContextNode
;
1049 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
1050 xmlNsPtr
*oldXPNamespaces
;
1051 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
1053 if ((comp
!= NULL
) && (comp
->comp
!= NULL
)) {
1054 xpExpr
= comp
->comp
;
1056 xpExpr
= xmlXPathCompile(elem
->select
);
1063 ctxt
->inst
= comp
->inst
;
1068 * "At top-level, the expression or template specifying the
1069 * variable value is evaluated with the same context as that used
1070 * to process the root node of the source document: the current
1071 * node is the root node of the source document and the current
1072 * node list is a list containing just the root node of the source
1076 * Save context states.
1078 oldXPDoc
= xpctxt
->doc
;
1079 oldXPContextNode
= xpctxt
->node
;
1080 oldXPProximityPosition
= xpctxt
->proximityPosition
;
1081 oldXPContextSize
= xpctxt
->contextSize
;
1082 oldXPNamespaces
= xpctxt
->namespaces
;
1083 oldXPNsNr
= xpctxt
->nsNr
;
1085 xpctxt
->node
= ctxt
->initialContextNode
;
1086 xpctxt
->doc
= ctxt
->initialContextDoc
;
1087 xpctxt
->contextSize
= 1;
1088 xpctxt
->proximityPosition
= 1;
1092 #ifdef XSLT_REFACTORED
1093 if (comp
->inScopeNs
!= NULL
) {
1094 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
1095 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
1097 xpctxt
->namespaces
= NULL
;
1101 xpctxt
->namespaces
= comp
->nsList
;
1102 xpctxt
->nsNr
= comp
->nsNr
;
1105 xpctxt
->namespaces
= NULL
;
1109 result
= xmlXPathCompiledEval(xpExpr
, xpctxt
);
1112 * Restore Context states.
1114 xpctxt
->doc
= oldXPDoc
;
1115 xpctxt
->node
= oldXPContextNode
;
1116 xpctxt
->contextSize
= oldXPContextSize
;
1117 xpctxt
->proximityPosition
= oldXPProximityPosition
;
1118 xpctxt
->namespaces
= oldXPNamespaces
;
1119 xpctxt
->nsNr
= oldXPNsNr
;
1121 if ((comp
== NULL
) || (comp
->comp
== NULL
))
1122 xmlXPathFreeCompExpr(xpExpr
);
1123 if (result
== NULL
) {
1125 xsltTransformError(ctxt
, NULL
, NULL
,
1126 "Evaluating global variable %s failed\n", elem
->name
);
1128 xsltTransformError(ctxt
, NULL
, comp
->inst
,
1129 "Evaluating global variable %s failed\n", elem
->name
);
1130 ctxt
->state
= XSLT_STATE_STOPPED
;
1131 #ifdef WITH_XSLT_DEBUG_VARIABLE
1132 #ifdef LIBXML_DEBUG_ENABLED
1134 if ((xsltGenericDebugContext
== stdout
) ||
1135 (xsltGenericDebugContext
== stderr
))
1136 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
1142 if (elem
->tree
== NULL
) {
1143 result
= xmlXPathNewCString("");
1145 xmlDocPtr container
;
1146 xmlNodePtr oldInsert
;
1147 xmlDocPtr oldOutput
, oldXPDoc
;
1149 * Generate a result tree fragment.
1151 container
= xsltCreateRVT(ctxt
);
1152 if (container
== NULL
)
1155 * Let the lifetime of the tree fragment be handled by
1156 * the Libxslt's garbage collector.
1158 xsltRegisterPersistRVT(ctxt
, container
);
1160 oldOutput
= ctxt
->output
;
1161 oldInsert
= ctxt
->insert
;
1163 oldXPDoc
= ctxt
->xpathCtxt
->doc
;
1165 ctxt
->output
= container
;
1166 ctxt
->insert
= (xmlNodePtr
) container
;
1168 ctxt
->xpathCtxt
->doc
= ctxt
->initialContextDoc
;
1170 * Process the sequence constructor.
1172 xsltApplyOneTemplate(ctxt
, ctxt
->node
, elem
->tree
, NULL
, NULL
);
1174 ctxt
->xpathCtxt
->doc
= oldXPDoc
;
1176 ctxt
->insert
= oldInsert
;
1177 ctxt
->output
= oldOutput
;
1179 result
= xmlXPathNewValueTree((xmlNodePtr
) container
);
1180 if (result
== NULL
) {
1181 result
= xmlXPathNewCString("");
1183 result
->boolval
= 0; /* Freeing is not handled there anymore */
1185 #ifdef WITH_XSLT_DEBUG_VARIABLE
1186 #ifdef LIBXML_DEBUG_ENABLED
1187 if ((xsltGenericDebugContext
== stdout
) ||
1188 (xsltGenericDebugContext
== stderr
))
1189 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
1197 elem
->name
= oldVarName
;
1198 ctxt
->inst
= oldInst
;
1199 if (result
!= NULL
) {
1200 elem
->value
= result
;
1207 * xsltEvalGlobalVariables:
1208 * @ctxt: the XSLT transformation context
1210 * Evaluates all global variables and parameters of a stylesheet.
1211 * For internal use only. This is called at start of a transformation.
1213 * Returns 0 in case of success, -1 in case of error
1216 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt
) {
1217 xsltStackElemPtr elem
;
1218 xsltStylesheetPtr style
;
1220 if ((ctxt
== NULL
) || (ctxt
->document
== NULL
))
1223 #ifdef WITH_XSLT_DEBUG_VARIABLE
1224 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1225 "Registering global variables\n"));
1228 * Walk the list from the stylesheets and populate the hash table
1230 style
= ctxt
->style
;
1231 while (style
!= NULL
) {
1232 elem
= style
->variables
;
1234 #ifdef WITH_XSLT_DEBUG_VARIABLE
1235 if ((style
->doc
!= NULL
) && (style
->doc
->URL
!= NULL
)) {
1236 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1237 "Registering global variables from %s\n",
1242 while (elem
!= NULL
) {
1243 xsltStackElemPtr def
;
1246 * Global variables are stored in the variables pool.
1248 def
= (xsltStackElemPtr
)
1249 xmlHashLookup2(ctxt
->globalVars
,
1250 elem
->name
, elem
->nameURI
);
1253 def
= xsltCopyStackElem(elem
);
1254 xmlHashAddEntry2(ctxt
->globalVars
,
1255 elem
->name
, elem
->nameURI
, def
);
1256 } else if ((elem
->comp
!= NULL
) &&
1257 (elem
->comp
->type
== XSLT_FUNC_VARIABLE
)) {
1259 * Redefinition of variables from a different stylesheet
1260 * should not generate a message.
1262 if ((elem
->comp
->inst
!= NULL
) &&
1263 (def
->comp
!= NULL
) && (def
->comp
->inst
!= NULL
) &&
1264 (elem
->comp
->inst
->doc
== def
->comp
->inst
->doc
))
1266 xsltTransformError(ctxt
, style
, elem
->comp
->inst
,
1267 "Global variable %s already defined\n", elem
->name
);
1268 if (style
!= NULL
) style
->errors
++;
1274 style
= xsltNextImport(style
);
1278 * This part does the actual evaluation
1280 xmlHashScan(ctxt
->globalVars
,
1281 (xmlHashScanner
) xsltEvalGlobalVariable
, ctxt
);
1287 * xsltRegisterGlobalVariable:
1288 * @style: the XSLT transformation context
1289 * @name: the variable name
1290 * @ns_uri: the variable namespace URI
1291 * @sel: the expression which need to be evaluated to generate a value
1292 * @tree: the subtree if sel is NULL
1293 * @comp: the precompiled value
1294 * @value: the string value if available
1296 * Register a new variable value. If @value is NULL it unregisters
1299 * Returns 0 in case of success, -1 in case of error
1302 xsltRegisterGlobalVariable(xsltStylesheetPtr style
, const xmlChar
*name
,
1303 const xmlChar
*ns_uri
, const xmlChar
*sel
,
1304 xmlNodePtr tree
, xsltStylePreCompPtr comp
,
1305 const xmlChar
*value
) {
1306 xsltStackElemPtr elem
, tmp
;
1314 #ifdef WITH_XSLT_DEBUG_VARIABLE
1315 if (comp
->type
== XSLT_FUNC_PARAM
)
1316 xsltGenericDebug(xsltGenericDebugContext
,
1317 "Defining global param %s\n", name
);
1319 xsltGenericDebug(xsltGenericDebugContext
,
1320 "Defining global variable %s\n", name
);
1323 elem
= xsltNewStackElem(NULL
);
1327 elem
->name
= xmlDictLookup(style
->dict
, name
, -1);
1328 elem
->select
= xmlDictLookup(style
->dict
, sel
, -1);
1330 elem
->nameURI
= xmlDictLookup(style
->dict
, ns_uri
, -1);
1332 tmp
= style
->variables
;
1335 style
->variables
= elem
;
1337 while (tmp
!= NULL
) {
1338 if ((elem
->comp
->type
== XSLT_FUNC_VARIABLE
) &&
1339 (tmp
->comp
->type
== XSLT_FUNC_VARIABLE
) &&
1340 (xmlStrEqual(elem
->name
, tmp
->name
)) &&
1341 ((elem
->nameURI
== tmp
->nameURI
) ||
1342 (xmlStrEqual(elem
->nameURI
, tmp
->nameURI
))))
1344 xsltTransformError(NULL
, style
, comp
->inst
,
1345 "redefinition of global variable %s\n", elem
->name
);
1348 if (tmp
->next
== NULL
)
1355 if (value
!= NULL
) {
1357 elem
->value
= xmlXPathNewString(value
);
1363 * xsltProcessUserParamInternal
1365 * @ctxt: the XSLT transformation context
1366 * @name: a null terminated parameter name
1367 * @value: a null terminated value (may be an XPath expression)
1368 * @eval: 0 to treat the value literally, else evaluate as XPath expression
1370 * If @eval is 0 then @value is treated literally and is stored in the global
1371 * parameter/variable table without any change.
1373 * Uf @eval is 1 then @value is treated as an XPath expression and is
1374 * evaluated. In this case, if you want to pass a string which will be
1375 * interpreted literally then it must be enclosed in single or double quotes.
1376 * If the string contains single quotes (double quotes) then it cannot be
1377 * enclosed single quotes (double quotes). If the string which you want to
1378 * be treated literally contains both single and double quotes (e.g. Meet
1379 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
1380 * quoting character. You cannot use ' or " inside the string
1381 * because the replacement of character entities with their equivalents is
1382 * done at a different stage of processing. The solution is to call
1383 * xsltQuoteUserParams or xsltQuoteOneUserParam.
1385 * This needs to be done on parsed stylesheets before starting to apply
1386 * transformations. Normally this will be called (directly or indirectly)
1387 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
1388 * or xsltQuoteOneUserParam.
1390 * Returns 0 in case of success, -1 in case of error
1395 xsltProcessUserParamInternal(xsltTransformContextPtr ctxt
,
1396 const xmlChar
* name
,
1397 const xmlChar
* value
,
1400 xsltStylesheetPtr style
;
1401 const xmlChar
*prefix
;
1402 const xmlChar
*href
;
1403 xmlXPathCompExprPtr xpExpr
;
1404 xmlXPathObjectPtr result
;
1406 xsltStackElemPtr elem
;
1417 style
= ctxt
->style
;
1419 #ifdef WITH_XSLT_DEBUG_VARIABLE
1420 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1421 "Evaluating user parameter %s=%s\n", name
, value
));
1428 name
= xsltSplitQName(ctxt
->dict
, name
, &prefix
);
1430 if (prefix
!= NULL
) {
1433 ns
= xmlSearchNs(style
->doc
, xmlDocGetRootElement(style
->doc
),
1436 xsltTransformError(ctxt
, style
, NULL
,
1437 "user param : no namespace bound to prefix %s\n", prefix
);
1447 res_ptr
= xmlHashLookup2(ctxt
->globalVars
, name
, href
);
1449 xsltTransformError(ctxt
, style
, NULL
,
1450 "Global parameter %s already defined\n", name
);
1452 if (ctxt
->globalVars
== NULL
)
1453 ctxt
->globalVars
= xmlHashCreate(20);
1456 * do not overwrite variables with parameters from the command line
1458 while (style
!= NULL
) {
1459 elem
= ctxt
->style
->variables
;
1460 while (elem
!= NULL
) {
1461 if ((elem
->comp
!= NULL
) &&
1462 (elem
->comp
->type
== XSLT_FUNC_VARIABLE
) &&
1463 (xmlStrEqual(elem
->name
, name
)) &&
1464 (xmlStrEqual(elem
->nameURI
, href
))) {
1469 style
= xsltNextImport(style
);
1471 style
= ctxt
->style
;
1475 * Do the evaluation if @eval is non-zero.
1480 xpExpr
= xmlXPathCompile(value
);
1481 if (xpExpr
!= NULL
) {
1483 xmlNodePtr oldXPContextNode
;
1484 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
1485 xmlNsPtr
*oldXPNamespaces
;
1486 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
1489 * Save context states.
1491 oldXPDoc
= xpctxt
->doc
;
1492 oldXPContextNode
= xpctxt
->node
;
1493 oldXPProximityPosition
= xpctxt
->proximityPosition
;
1494 oldXPContextSize
= xpctxt
->contextSize
;
1495 oldXPNamespaces
= xpctxt
->namespaces
;
1496 oldXPNsNr
= xpctxt
->nsNr
;
1500 * "At top-level, the expression or template specifying the
1501 * variable value is evaluated with the same context as that used
1502 * to process the root node of the source document: the current
1503 * node is the root node of the source document and the current
1504 * node list is a list containing just the root node of the source
1507 xpctxt
->doc
= ctxt
->initialContextDoc
;
1508 xpctxt
->node
= ctxt
->initialContextNode
;
1509 xpctxt
->contextSize
= 1;
1510 xpctxt
->proximityPosition
= 1;
1512 * There is really no in scope namespace for parameters on the
1515 xpctxt
->namespaces
= NULL
;
1518 result
= xmlXPathCompiledEval(xpExpr
, xpctxt
);
1521 * Restore Context states.
1523 xpctxt
->doc
= oldXPDoc
;
1524 xpctxt
->node
= oldXPContextNode
;
1525 xpctxt
->contextSize
= oldXPContextSize
;
1526 xpctxt
->proximityPosition
= oldXPProximityPosition
;
1527 xpctxt
->namespaces
= oldXPNamespaces
;
1528 xpctxt
->nsNr
= oldXPNsNr
;
1530 xmlXPathFreeCompExpr(xpExpr
);
1532 if (result
== NULL
) {
1533 xsltTransformError(ctxt
, style
, NULL
,
1534 "Evaluating user parameter %s failed\n", name
);
1535 ctxt
->state
= XSLT_STATE_STOPPED
;
1541 * If @eval is 0 then @value is to be taken literally and result is NULL
1543 * If @eval is not 0, then @value is an XPath expression and has been
1544 * successfully evaluated and result contains the resulting value and
1547 * Now create an xsltStackElemPtr for insertion into the context's
1548 * global variable/parameter hash table.
1551 #ifdef WITH_XSLT_DEBUG_VARIABLE
1552 #ifdef LIBXML_DEBUG_ENABLED
1553 if ((xsltGenericDebugContext
== stdout
) ||
1554 (xsltGenericDebugContext
== stderr
))
1555 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
1560 elem
= xsltNewStackElem(NULL
);
1563 elem
->select
= xmlDictLookup(ctxt
->dict
, value
, -1);
1565 elem
->nameURI
= xmlDictLookup(ctxt
->dict
, href
, -1);
1569 elem
->value
= xmlXPathNewString(value
);
1572 elem
->value
= result
;
1577 * Global parameters are stored in the XPath context variables pool.
1580 res
= xmlHashAddEntry2(ctxt
->globalVars
, name
, href
, elem
);
1582 xsltFreeStackElem(elem
);
1583 xsltTransformError(ctxt
, style
, NULL
,
1584 "Global parameter %s already defined\n", name
);
1590 * xsltEvalUserParams:
1592 * @ctxt: the XSLT transformation context
1593 * @params: a NULL terminated array of parameters name/value tuples
1595 * Evaluate the global variables of a stylesheet. This needs to be
1596 * done on parsed stylesheets before starting to apply transformations.
1597 * Each of the parameters is evaluated as an XPath expression and stored
1598 * in the global variables/parameter hash table. If you want your
1599 * parameter used literally, use xsltQuoteUserParams.
1601 * Returns 0 in case of success, -1 in case of error
1605 xsltEvalUserParams(xsltTransformContextPtr ctxt
, const char **params
) {
1607 const xmlChar
*name
;
1608 const xmlChar
*value
;
1612 while (params
[indx
] != NULL
) {
1613 name
= (const xmlChar
*) params
[indx
++];
1614 value
= (const xmlChar
*) params
[indx
++];
1615 if (xsltEvalOneUserParam(ctxt
, name
, value
) != 0)
1622 * xsltQuoteUserParams:
1624 * @ctxt: the XSLT transformation context
1625 * @params: a NULL terminated arry of parameters names/values tuples
1627 * Similar to xsltEvalUserParams, but the values are treated literally and
1628 * are * *not* evaluated as XPath expressions. This should be done on parsed
1629 * stylesheets before starting to apply transformations.
1631 * Returns 0 in case of success, -1 in case of error.
1635 xsltQuoteUserParams(xsltTransformContextPtr ctxt
, const char **params
) {
1637 const xmlChar
*name
;
1638 const xmlChar
*value
;
1642 while (params
[indx
] != NULL
) {
1643 name
= (const xmlChar
*) params
[indx
++];
1644 value
= (const xmlChar
*) params
[indx
++];
1645 if (xsltQuoteOneUserParam(ctxt
, name
, value
) != 0)
1652 * xsltEvalOneUserParam:
1653 * @ctxt: the XSLT transformation context
1654 * @name: a null terminated string giving the name of the parameter
1655 * @value: a null terminated string giving the XPath expression to be evaluated
1657 * This is normally called from xsltEvalUserParams to process a single
1658 * parameter from a list of parameters. The @value is evaluated as an
1659 * XPath expression and the result is stored in the context's global
1660 * variable/parameter hash table.
1662 * To have a parameter treated literally (not as an XPath expression)
1663 * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
1664 * details see description of xsltProcessOneUserParamInternal.
1666 * Returns 0 in case of success, -1 in case of error.
1670 xsltEvalOneUserParam(xsltTransformContextPtr ctxt
,
1671 const xmlChar
* name
,
1672 const xmlChar
* value
) {
1673 return xsltProcessUserParamInternal(ctxt
, name
, value
,
1674 1 /* xpath eval ? */);
1678 * xsltQuoteOneUserParam:
1679 * @ctxt: the XSLT transformation context
1680 * @name: a null terminated string giving the name of the parameter
1681 * @value: a null terminated string giving the parameter value
1683 * This is normally called from xsltQuoteUserParams to process a single
1684 * parameter from a list of parameters. The @value is stored in the
1685 * context's global variable/parameter hash table.
1687 * Returns 0 in case of success, -1 in case of error.
1691 xsltQuoteOneUserParam(xsltTransformContextPtr ctxt
,
1692 const xmlChar
* name
,
1693 const xmlChar
* value
) {
1694 return xsltProcessUserParamInternal(ctxt
, name
, value
,
1695 0 /* xpath eval ? */);
1699 * xsltBuildVariable:
1700 * @ctxt: the XSLT transformation context
1701 * @comp: the precompiled form
1702 * @tree: the tree if select is NULL
1704 * Computes a new variable value.
1706 * Returns the xsltStackElemPtr or NULL in case of error
1708 static xsltStackElemPtr
1709 xsltBuildVariable(xsltTransformContextPtr ctxt
,
1710 xsltStylePreCompPtr castedComp
,
1713 #ifdef XSLT_REFACTORED
1714 xsltStyleBasicItemVariablePtr comp
=
1715 (xsltStyleBasicItemVariablePtr
) castedComp
;
1717 xsltStylePreCompPtr comp
= castedComp
;
1719 xsltStackElemPtr elem
;
1721 #ifdef WITH_XSLT_DEBUG_VARIABLE
1722 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1723 "Building variable %s", comp
->name
));
1724 if (comp
->select
!= NULL
)
1725 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1726 " select %s", comp
->select
));
1727 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
, "\n"));
1730 elem
= xsltNewStackElem(ctxt
);
1733 elem
->comp
= (xsltStylePreCompPtr
) comp
;
1734 elem
->name
= comp
->name
;
1735 elem
->select
= comp
->select
;
1736 elem
->nameURI
= comp
->ns
;
1738 elem
->value
= xsltEvalVariable(ctxt
, elem
,
1739 (xsltStylePreCompPtr
) comp
);
1740 if (elem
->value
!= NULL
)
1746 * xsltRegisterVariable:
1747 * @ctxt: the XSLT transformation context
1748 * @comp: the compiled XSLT-variable (or param) instruction
1749 * @tree: the tree if select is NULL
1750 * @isParam: indicates if this is a parameter
1752 * Computes and registers a new variable.
1754 * Returns 0 in case of success, -1 in case of error
1757 xsltRegisterVariable(xsltTransformContextPtr ctxt
,
1758 xsltStylePreCompPtr castedComp
,
1759 xmlNodePtr tree
, int isParam
)
1761 #ifdef XSLT_REFACTORED
1762 xsltStyleBasicItemVariablePtr comp
=
1763 (xsltStyleBasicItemVariablePtr
) castedComp
;
1765 xsltStylePreCompPtr comp
= castedComp
;
1768 xsltStackElemPtr variable
;
1770 #ifdef XSLT_REFACTORED
1772 * REFACTORED NOTE: Redefinitions of vars/params are checked
1773 * at compilation time in the refactored code.
1774 * xsl:with-param parameters are checked in xsltApplyXSLTTemplate().
1777 present
= xsltCheckStackElem(ctxt
, comp
->name
, comp
->ns
);
1779 if ((present
!= 0) && (present
!= 3)) {
1780 /* TODO: report QName. */
1781 xsltTransformError(ctxt
, NULL
, comp
->inst
,
1782 "XSLT-variable: Redefinition of variable '%s'.\n", comp
->name
);
1785 } else if (present
!= 0) {
1786 if ((present
== 1) || (present
== 2)) {
1787 /* TODO: report QName. */
1788 xsltTransformError(ctxt
, NULL
, comp
->inst
,
1789 "XSLT-param: Redefinition of parameter '%s'.\n", comp
->name
);
1792 #ifdef WITH_XSLT_DEBUG_VARIABLE
1793 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1794 "param %s defined by caller\n", comp
->name
));
1798 #endif /* else of XSLT_REFACTORED */
1800 variable
= xsltBuildVariable(ctxt
, (xsltStylePreCompPtr
) comp
, tree
);
1801 xsltAddStackElem(ctxt
, variable
);
1806 * xsltGlobalVariableLookup:
1807 * @ctxt: the XSLT transformation context
1808 * @name: the variable name
1809 * @ns_uri: the variable namespace URI
1811 * Search in the Variable array of the context for the given
1814 * Returns the value or NULL if not found
1816 static xmlXPathObjectPtr
1817 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
1818 const xmlChar
*ns_uri
) {
1819 xsltStackElemPtr elem
;
1820 xmlXPathObjectPtr ret
= NULL
;
1823 * Lookup the global variables in XPath global variable hash table
1825 if ((ctxt
->xpathCtxt
== NULL
) || (ctxt
->globalVars
== NULL
))
1827 elem
= (xsltStackElemPtr
)
1828 xmlHashLookup2(ctxt
->globalVars
, name
, ns_uri
);
1830 #ifdef WITH_XSLT_DEBUG_VARIABLE
1831 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1832 "global variable not found %s\n", name
));
1837 * URGENT TODO: Move the detection of recursive definitions
1840 if (elem
->computed
== 0) {
1841 if (elem
->name
== xsltComputingGlobalVarMarker
) {
1842 xsltTransformError(ctxt
, NULL
, elem
->comp
->inst
,
1843 "Recursive definition of %s\n", name
);
1846 ret
= xsltEvalGlobalVariable(elem
, ctxt
);
1849 return(xmlXPathObjectCopy(ret
));
1853 * xsltVariableLookup:
1854 * @ctxt: the XSLT transformation context
1855 * @name: the variable name
1856 * @ns_uri: the variable namespace URI
1858 * Search in the Variable array of the context for the given
1861 * Returns the value or NULL if not found
1864 xsltVariableLookup(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
1865 const xmlChar
*ns_uri
) {
1866 xsltStackElemPtr elem
;
1871 elem
= xsltStackLookup(ctxt
, name
, ns_uri
);
1873 return(xsltGlobalVariableLookup(ctxt
, name
, ns_uri
));
1875 if (elem
->computed
== 0) {
1876 #ifdef WITH_XSLT_DEBUG_VARIABLE
1877 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1878 "uncomputed variable %s\n", name
));
1880 elem
->value
= xsltEvalVariable(ctxt
, elem
, NULL
);
1883 if (elem
->value
!= NULL
)
1884 return(xmlXPathObjectCopy(elem
->value
));
1885 #ifdef WITH_XSLT_DEBUG_VARIABLE
1886 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1887 "variable not found %s\n", name
));
1893 * xsltParseStylesheetCallerParam:
1894 * @ctxt: the XSLT transformation context
1895 * @inst: the xsl:with-param instruction element
1897 * Processes an xsl:with-param instruction at transformation time.
1898 * The value is compute, but not recorded.
1899 * NOTE that this is also called with an *xsl:param* element
1900 * from exsltFuncFunctionFunction().
1902 * Returns the new xsltStackElemPtr or NULL
1906 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt
, xmlNodePtr inst
)
1908 #ifdef XSLT_REFACTORED
1909 xsltStyleBasicItemVariablePtr comp
;
1911 xsltStylePreCompPtr comp
;
1913 xmlNodePtr tree
= NULL
; /* The first child node of the instruction or
1914 the instruction itself. */
1915 xsltStackElemPtr param
= NULL
;
1917 if ((ctxt
== NULL
) || (inst
== NULL
) || (inst
->type
!= XML_ELEMENT_NODE
))
1920 #ifdef XSLT_REFACTORED
1921 comp
= (xsltStyleBasicItemVariablePtr
) inst
->psvi
;
1923 comp
= (xsltStylePreCompPtr
) inst
->psvi
;
1927 xsltTransformError(ctxt
, NULL
, inst
,
1928 "Internal error in xsltParseStylesheetCallerParam(): "
1929 "The XSLT 'with-param' instruction was not compiled.\n");
1932 if (comp
->name
== NULL
) {
1933 xsltTransformError(ctxt
, NULL
, inst
,
1934 "Internal error in xsltParseStylesheetCallerParam(): "
1935 "XSLT 'with-param': The attribute 'name' was not compiled.\n");
1939 #ifdef WITH_XSLT_DEBUG_VARIABLE
1940 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1941 "Handling xsl:with-param %s\n", comp
->name
));
1944 if (comp
->select
== NULL
) {
1945 tree
= inst
->children
;
1947 #ifdef WITH_XSLT_DEBUG_VARIABLE
1948 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1949 " select %s\n", comp
->select
));
1954 param
= xsltBuildVariable(ctxt
, (xsltStylePreCompPtr
) comp
, tree
);
1960 * xsltParseGlobalVariable:
1961 * @style: the XSLT stylesheet
1962 * @cur: the "variable" element
1964 * Parses a global XSLT 'variable' declaration at compilation time
1968 xsltParseGlobalVariable(xsltStylesheetPtr style
, xmlNodePtr cur
)
1970 #ifdef XSLT_REFACTORED
1971 xsltStyleItemVariablePtr comp
;
1973 xsltStylePreCompPtr comp
;
1976 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1979 #ifdef XSLT_REFACTORED
1981 * Note that xsltStylePreCompute() will be called from
1984 comp
= (xsltStyleItemVariablePtr
) cur
->psvi
;
1986 xsltStylePreCompute(style
, cur
);
1987 comp
= (xsltStylePreCompPtr
) cur
->psvi
;
1990 xsltTransformError(NULL
, style
, cur
,
1991 "xsl:variable : compilation failed\n");
1995 if (comp
->name
== NULL
) {
1996 xsltTransformError(NULL
, style
, cur
,
1997 "xsl:variable : missing name attribute\n");
2002 * Parse the content (a sequence constructor) of xsl:variable.
2004 if (cur
->children
!= NULL
) {
2005 #ifdef XSLT_REFACTORED
2006 xsltParseSequenceConstructor(XSLT_CCTXT(style
), cur
->children
);
2008 xsltParseTemplateContent(style
, cur
);
2011 #ifdef WITH_XSLT_DEBUG_VARIABLE
2012 xsltGenericDebug(xsltGenericDebugContext
,
2013 "Registering global variable %s\n", comp
->name
);
2016 xsltRegisterGlobalVariable(style
, comp
->name
, comp
->ns
,
2017 comp
->select
, cur
->children
, (xsltStylePreCompPtr
) comp
,
2022 * xsltParseGlobalParam:
2023 * @style: the XSLT stylesheet
2024 * @cur: the "param" element
2026 * parse an XSLT transformation param declaration and record
2031 xsltParseGlobalParam(xsltStylesheetPtr style
, xmlNodePtr cur
) {
2032 #ifdef XSLT_REFACTORED
2033 xsltStyleItemParamPtr comp
;
2035 xsltStylePreCompPtr comp
;
2038 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
2041 #ifdef XSLT_REFACTORED
2043 * Note that xsltStylePreCompute() will be called from
2046 comp
= (xsltStyleItemParamPtr
) cur
->psvi
;
2048 xsltStylePreCompute(style
, cur
);
2049 comp
= (xsltStylePreCompPtr
) cur
->psvi
;
2052 xsltTransformError(NULL
, style
, cur
,
2053 "xsl:param : compilation failed\n");
2057 if (comp
->name
== NULL
) {
2058 xsltTransformError(NULL
, style
, cur
,
2059 "xsl:param : missing name attribute\n");
2064 * Parse the content (a sequence constructor) of xsl:param.
2066 if (cur
->children
!= NULL
) {
2067 #ifdef XSLT_REFACTORED
2068 xsltParseSequenceConstructor(XSLT_CCTXT(style
), cur
->children
);
2070 xsltParseTemplateContent(style
, cur
);
2074 #ifdef WITH_XSLT_DEBUG_VARIABLE
2075 xsltGenericDebug(xsltGenericDebugContext
,
2076 "Registering global param %s\n", comp
->name
);
2079 xsltRegisterGlobalVariable(style
, comp
->name
, comp
->ns
,
2080 comp
->select
, cur
->children
, (xsltStylePreCompPtr
) comp
,
2085 * xsltParseStylesheetVariable:
2086 * @ctxt: the XSLT transformation context
2087 * @inst: the xsl:variable instruction element
2089 * Registers a local XSLT 'variable' instruction at transformation time
2090 * and evaluates its value.
2093 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt
, xmlNodePtr inst
)
2095 #ifdef XSLT_REFACTORED
2096 xsltStyleItemVariablePtr comp
;
2098 xsltStylePreCompPtr comp
;
2101 if ((inst
== NULL
) || (ctxt
== NULL
) || (inst
->type
!= XML_ELEMENT_NODE
))
2106 xsltTransformError(ctxt
, NULL
, inst
,
2107 "Internal error in xsltParseStylesheetVariable(): "
2108 "The XSLT 'variable' instruction was not compiled.\n");
2111 if (comp
->name
== NULL
) {
2112 xsltTransformError(ctxt
, NULL
, inst
,
2113 "Internal error in xsltParseStylesheetVariable(): "
2114 "The attribute 'name' was not compiled.\n");
2118 #ifdef WITH_XSLT_DEBUG_VARIABLE
2119 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2120 "Registering variable '%s'\n", comp
->name
));
2123 xsltRegisterVariable(ctxt
, (xsltStylePreCompPtr
) comp
, inst
->children
, 0);
2127 * xsltParseStylesheetParam:
2128 * @ctxt: the XSLT transformation context
2129 * @cur: the XSLT 'param' element
2131 * Registers a local XSLT 'param' declaration at transformation time and
2132 * evaluates its value.
2135 xsltParseStylesheetParam(xsltTransformContextPtr ctxt
, xmlNodePtr cur
)
2137 #ifdef XSLT_REFACTORED
2138 xsltStyleItemParamPtr comp
;
2140 xsltStylePreCompPtr comp
;
2143 if ((cur
== NULL
) || (ctxt
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
2147 if ((comp
== NULL
) || (comp
->name
== NULL
)) {
2148 xsltTransformError(ctxt
, NULL
, cur
,
2149 "Internal error in xsltParseStylesheetParam(): "
2150 "The XSLT 'param' declaration was not compiled correctly.\n");
2154 #ifdef WITH_XSLT_DEBUG_VARIABLE
2155 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2156 "Registering param %s\n", comp
->name
));
2159 xsltRegisterVariable(ctxt
, (xsltStylePreCompPtr
) comp
, cur
->children
, 1);
2163 * xsltFreeGlobalVariables:
2164 * @ctxt: the XSLT transformation context
2166 * Free up the data associated to the global variables
2171 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt
) {
2172 xmlHashFree(ctxt
->globalVars
, (xmlHashDeallocator
) xsltFreeStackElem
);
2176 * xsltXPathVariableLookup:
2177 * @ctxt: a void * but the the XSLT transformation context actually
2178 * @name: the variable name
2179 * @ns_uri: the variable namespace URI
2181 * This is the entry point when a varibale is needed by the XPath
2184 * Returns the value or NULL if not found
2187 xsltXPathVariableLookup(void *ctxt
, const xmlChar
*name
,
2188 const xmlChar
*ns_uri
) {
2189 xsltTransformContextPtr tctxt
;
2190 xmlXPathObjectPtr valueObj
= NULL
;
2192 if ((ctxt
== NULL
) || (name
== NULL
))
2195 #ifdef WITH_XSLT_DEBUG_VARIABLE
2196 XSLT_TRACE(((xsltTransformContextPtr
)ctxt
),XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2197 "Lookup variable '%s'\n", name
));
2200 tctxt
= (xsltTransformContextPtr
) ctxt
;
2202 * Local variables/params ---------------------------------------------
2204 * Do the lookup from the top of the stack, but
2205 * don't use params being computed in a call-param
2206 * First lookup expects the variable name and URI to
2207 * come from the disctionnary and hence pointer comparison.
2209 if (tctxt
->varsNr
!= 0) {
2211 xsltStackElemPtr variable
= NULL
, cur
;
2213 for (i
= tctxt
->varsNr
; i
> tctxt
->varsBase
; i
--) {
2214 cur
= tctxt
->varsTab
[i
-1];
2215 if ((cur
->name
== name
) && (cur
->nameURI
== ns_uri
)) {
2220 goto local_variable_found
;
2225 * Redo the lookup with interned strings to avoid string comparison.
2227 * OPTIMIZE TODO: The problem here is, that if we request a
2228 * global variable, then this will be also executed.
2231 const xmlChar
*tmpName
= name
, *tmpNsName
= ns_uri
;
2233 name
= xmlDictLookup(tctxt
->dict
, name
, -1);
2235 ns_uri
= xmlDictLookup(tctxt
->dict
, ns_uri
, -1);
2236 if ((tmpName
!= name
) || (tmpNsName
!= ns_uri
)) {
2237 for (i
= tctxt
->varsNr
; i
> tctxt
->varsBase
; i
--) {
2238 cur
= tctxt
->varsTab
[i
-1];
2239 if ((cur
->name
== name
) && (cur
->nameURI
== ns_uri
)) {
2244 goto local_variable_found
;
2250 local_variable_found
:
2253 if (variable
->computed
== 0) {
2255 #ifdef WITH_XSLT_DEBUG_VARIABLE
2256 XSLT_TRACE(tctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2257 "uncomputed variable '%s'\n", name
));
2259 variable
->value
= xsltEvalVariable(tctxt
, variable
, NULL
);
2260 variable
->computed
= 1;
2262 if (variable
->value
!= NULL
) {
2263 valueObj
= xmlXPathObjectCopy(variable
->value
);
2269 * Global variables/params --------------------------------------------
2271 if (tctxt
->globalVars
) {
2272 valueObj
= xsltGlobalVariableLookup(tctxt
, name
, ns_uri
);
2275 if (valueObj
== NULL
) {
2277 #ifdef WITH_XSLT_DEBUG_VARIABLE
2278 XSLT_TRACE(tctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2279 "variable not found '%s'\n", name
));
2283 xsltTransformError(tctxt
, NULL
, tctxt
->inst
,
2284 "Variable '{%s}%s' has not been declared.\n", ns_uri
, name
);
2286 xsltTransformError(tctxt
, NULL
, tctxt
->inst
,
2287 "Variable '%s' has not been declared.\n", name
);
2291 #ifdef WITH_XSLT_DEBUG_VARIABLE
2292 XSLT_TRACE(tctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2293 "found variable '%s'\n", name
));