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 static 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 RVT
->psvi
= XSLT_RVT_VARIABLE
;
108 * We'll restrict the lifetime of user-created fragments
109 * insinde an xsl:variable and xsl:param to the lifetime of the
112 if (ctxt
->contextVariable
!= NULL
) {
113 RVT
->next
= (xmlNodePtr
) XSLT_TCTXT_VARIABLE(ctxt
)->fragment
;
114 XSLT_TCTXT_VARIABLE(ctxt
)->fragment
= RVT
;
118 RVT
->next
= (xmlNodePtr
) ctxt
->tmpRVT
;
119 if (ctxt
->tmpRVT
!= NULL
)
120 ctxt
->tmpRVT
->prev
= (xmlNodePtr
) RVT
;
126 * xsltRegisterLocalRVT:
127 * @ctxt: an XSLT transformation context
128 * @RVT: a result value tree (Result Tree Fragment; xmlDocPtr)
130 * Registers a result value tree (XSLT 1.0 term: Result Tree Fragment)
131 * in the RVT garbage collector.
132 * The fragment will be freed when the instruction which created the
135 * Returns 0 in case of success and -1 in case of API or internal errors.
138 xsltRegisterLocalRVT(xsltTransformContextPtr ctxt
,
141 if ((ctxt
== NULL
) || (RVT
== NULL
))
147 * When evaluating "select" expressions of xsl:variable
148 * and xsl:param, we need to bind newly created tree fragments
149 * to the variable itself; otherwise the fragment will be
150 * freed before we leave the scope of a var.
152 if ((ctxt
->contextVariable
!= NULL
) &&
153 (XSLT_TCTXT_VARIABLE(ctxt
)->flags
& XSLT_VAR_IN_SELECT
))
155 RVT
->psvi
= XSLT_RVT_VARIABLE
;
156 RVT
->next
= (xmlNodePtr
) XSLT_TCTXT_VARIABLE(ctxt
)->fragment
;
157 XSLT_TCTXT_VARIABLE(ctxt
)->fragment
= RVT
;
161 * Store the fragment in the scope of the current instruction.
162 * If not reference by a returning instruction (like EXSLT's function),
163 * then this fragment will be freed, when the instruction exits.
165 RVT
->psvi
= XSLT_RVT_LOCAL
;
166 RVT
->next
= (xmlNodePtr
) ctxt
->localRVT
;
167 if (ctxt
->localRVT
!= NULL
)
168 ctxt
->localRVT
->prev
= (xmlNodePtr
) RVT
;
169 ctxt
->localRVT
= RVT
;
174 * xsltExtensionInstructionResultFinalize:
175 * @ctxt: an XSLT transformation context
177 * Finalizes the data (e.g. result tree fragments) created
178 * within a value-returning process (e.g. EXSLT's function).
179 * Tree fragments marked as being returned by a function are
180 * set to normal state, which means that the fragment garbage
181 * collector will free them after the function-calling process exits.
183 * Returns 0 in case of success and -1 in case of API or internal errors.
185 * This function is unsupported in newer releases of libxslt.
188 xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt
)
190 xmlGenericError(xmlGenericErrorContext
,
191 "xsltExtensionInstructionResultFinalize is unsupported "
192 "in this release of libxslt.\n");
197 * xsltExtensionInstructionResultRegister:
198 * @ctxt: an XSLT transformation context
199 * @obj: an XPath object to be inspected for result tree fragments
201 * Marks the result of a value-returning extension instruction
202 * in order to avoid it being garbage collected before the
203 * extension instruction exits.
204 * Note that one still has to additionally register any newly created
205 * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT().
207 * Returns 0 in case of success and -1 in case of error.
209 * It isn't necessary to call this function in newer releases of
213 xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt
,
214 xmlXPathObjectPtr obj
)
221 * @ctxt: an XSLT transformation context
222 * @obj: an XPath object to be inspected for result tree fragments
223 * @val: the flag value
225 * Updates ownership information of RVTs in @obj according to @val.
227 * @val = XSLT_RVT_FUNC_RESULT for the result of an extension function, so its
228 * RVTs won't be destroyed after leaving the returning scope.
229 * @val = XSLT_RVT_LOCAL for the result of an extension function to reset
230 * the state of its RVTs after it was returned to a new scope.
231 * @val = XSLT_RVT_GLOBAL for parts of global variables.
233 * Returns 0 in case of success and -1 in case of error.
236 xsltFlagRVTs(xsltTransformContextPtr ctxt
, xmlXPathObjectPtr obj
, void *val
) {
241 if ((ctxt
== NULL
) || (obj
== NULL
))
245 * OPTIMIZE TODO: If no local variables/params and no local tree
246 * fragments were created, then we don't need to analyse the XPath
247 * objects for tree fragments.
250 if ((obj
->type
!= XPATH_NODESET
) && (obj
->type
!= XPATH_XSLT_TREE
))
252 if ((obj
->nodesetval
== NULL
) || (obj
->nodesetval
->nodeNr
== 0))
255 for (i
= 0; i
< obj
->nodesetval
->nodeNr
; i
++) {
256 cur
= obj
->nodesetval
->nodeTab
[i
];
257 if (cur
->type
== XML_NAMESPACE_DECL
) {
259 * The XPath module sets the owner element of a ns-node on
260 * the ns->next field.
262 if ((((xmlNsPtr
) cur
)->next
!= NULL
) &&
263 (((xmlNsPtr
) cur
)->next
->type
== XML_ELEMENT_NODE
))
265 cur
= (xmlNodePtr
) ((xmlNsPtr
) cur
)->next
;
268 xsltTransformError(ctxt
, NULL
, ctxt
->inst
,
269 "Internal error in xsltFlagRVTs(): "
270 "Cannot retrieve the doc of a namespace node.\n");
277 xsltTransformError(ctxt
, NULL
, ctxt
->inst
,
278 "Internal error in xsltFlagRVTs(): "
279 "Cannot retrieve the doc of a node.\n");
282 if (doc
->name
&& (doc
->name
[0] == ' ') &&
283 doc
->psvi
!= XSLT_RVT_GLOBAL
) {
285 * This is a result tree fragment.
286 * We store ownership information in the @psvi field.
287 * TODO: How do we know if this is a doc acquired via the
288 * document() function?
290 #ifdef WITH_XSLT_DEBUG_VARIABLE
291 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
292 "Flagging RVT %p: %p -> %p\n", doc
, doc
->psvi
, val
));
295 if (val
== XSLT_RVT_LOCAL
) {
296 if (doc
->psvi
!= XSLT_RVT_FUNC_RESULT
) {
297 xmlGenericError(xmlGenericErrorContext
,
298 "xsltFlagRVTs: Invalid transition %p => LOCAL\n",
303 xsltRegisterLocalRVT(ctxt
, doc
);
304 } else if (val
== XSLT_RVT_GLOBAL
) {
305 if (doc
->psvi
!= XSLT_RVT_LOCAL
) {
306 xmlGenericError(xmlGenericErrorContext
,
307 "xsltFlagRVTs: Invalid transition %p => GLOBAL\n",
309 doc
->psvi
= XSLT_RVT_GLOBAL
;
313 /* Will be registered as persistant in xsltReleaseLocalRVTs. */
314 doc
->psvi
= XSLT_RVT_GLOBAL
;
315 } else if (val
== XSLT_RVT_FUNC_RESULT
) {
326 * @ctxt: an XSLT transformation context
327 * @RVT: a result value tree (Result Tree Fragment)
329 * Either frees the RVT (which is an xmlDoc) or stores
330 * it in the context's cache for later reuse.
333 xsltReleaseRVT(xsltTransformContextPtr ctxt
, xmlDocPtr RVT
)
338 if (ctxt
&& (ctxt
->cache
->nbRVT
< 40)) {
340 * Store the Result Tree Fragment.
341 * Free the document info.
343 if (RVT
->_private
!= NULL
) {
344 xsltFreeDocumentKeys((xsltDocumentPtr
) RVT
->_private
);
345 xmlFree(RVT
->_private
);
346 RVT
->_private
= NULL
;
349 * Clear the document tree.
350 * REVISIT TODO: Do we expect ID/IDREF tables to be existent?
352 if (RVT
->children
!= NULL
) {
353 xmlFreeNodeList(RVT
->children
);
354 RVT
->children
= NULL
;
357 if (RVT
->ids
!= NULL
) {
358 xmlFreeIDTable((xmlIDTablePtr
) RVT
->ids
);
361 if (RVT
->refs
!= NULL
) {
362 xmlFreeRefTable((xmlRefTablePtr
) RVT
->refs
);
367 * Reset the ownership information.
371 RVT
->next
= (xmlNodePtr
) ctxt
->cache
->RVT
;
372 ctxt
->cache
->RVT
= RVT
;
374 ctxt
->cache
->nbRVT
++;
376 #ifdef XSLT_DEBUG_PROFILE_CACHE
377 ctxt
->cache
->dbgCachedRVTs
++;
384 if (RVT
->_private
!= NULL
) {
385 xsltFreeDocumentKeys((xsltDocumentPtr
) RVT
->_private
);
386 xmlFree(RVT
->_private
);
392 * xsltRegisterPersistRVT:
393 * @ctxt: an XSLT transformation context
394 * @RVT: a result value tree (Result Tree Fragment)
396 * Register the result value tree (XSLT 1.0 term: Result Tree Fragment)
397 * in the fragment garbage collector.
398 * The fragment will be freed when the transformation context is
401 * Returns 0 in case of success and -1 in case of error.
404 xsltRegisterPersistRVT(xsltTransformContextPtr ctxt
, xmlDocPtr RVT
)
406 if ((ctxt
== NULL
) || (RVT
== NULL
)) return(-1);
408 RVT
->psvi
= XSLT_RVT_GLOBAL
;
410 RVT
->next
= (xmlNodePtr
) ctxt
->persistRVT
;
411 if (ctxt
->persistRVT
!= NULL
)
412 ctxt
->persistRVT
->prev
= (xmlNodePtr
) RVT
;
413 ctxt
->persistRVT
= RVT
;
419 * @ctxt: an XSLT transformation context
421 * Frees all registered result value trees (Result Tree Fragments)
422 * of the transformation. Internal function; should not be called
426 xsltFreeRVTs(xsltTransformContextPtr ctxt
)
435 cur
= ctxt
->localRVT
;
436 while (cur
!= NULL
) {
437 next
= (xmlDocPtr
) cur
->next
;
438 if (cur
->_private
!= NULL
) {
439 xsltFreeDocumentKeys(cur
->_private
);
440 xmlFree(cur
->_private
);
445 ctxt
->localRVT
= NULL
;
447 * User-created per-template fragments.
450 while (cur
!= NULL
) {
451 next
= (xmlDocPtr
) cur
->next
;
452 if (cur
->_private
!= NULL
) {
453 xsltFreeDocumentKeys(cur
->_private
);
454 xmlFree(cur
->_private
);
463 cur
= ctxt
->persistRVT
;
464 while (cur
!= NULL
) {
465 next
= (xmlDocPtr
) cur
->next
;
466 if (cur
->_private
!= NULL
) {
467 xsltFreeDocumentKeys(cur
->_private
);
468 xmlFree(cur
->_private
);
473 ctxt
->persistRVT
= NULL
;
476 /************************************************************************
478 * Module interfaces *
480 ************************************************************************/
485 * Create a new XSLT ParserContext
487 * Returns the newly allocated xsltParserStackElem or NULL in case of error
489 static xsltStackElemPtr
490 xsltNewStackElem(xsltTransformContextPtr ctxt
)
492 xsltStackElemPtr ret
;
494 * Reuse a stack item from the cache if available.
496 if (ctxt
&& ctxt
->cache
->stackItems
) {
497 ret
= ctxt
->cache
->stackItems
;
498 ctxt
->cache
->stackItems
= ret
->next
;
500 ctxt
->cache
->nbStackItems
--;
501 #ifdef XSLT_DEBUG_PROFILE_CACHE
502 ctxt
->cache
->dbgReusedVars
++;
506 ret
= (xsltStackElemPtr
) xmlMalloc(sizeof(xsltStackElem
));
508 xsltTransformError(NULL
, NULL
, NULL
,
509 "xsltNewStackElem : malloc failed\n");
512 memset(ret
, 0, sizeof(xsltStackElem
));
519 * @elem: an XSLT stack element
521 * Makes a copy of the stack element
523 * Returns the copy of NULL
525 static xsltStackElemPtr
526 xsltCopyStackElem(xsltStackElemPtr elem
) {
527 xsltStackElemPtr cur
;
529 cur
= (xsltStackElemPtr
) xmlMalloc(sizeof(xsltStackElem
));
531 xsltTransformError(NULL
, NULL
, NULL
,
532 "xsltCopyStackElem : malloc failed\n");
535 memset(cur
, 0, sizeof(xsltStackElem
));
536 cur
->context
= elem
->context
;
537 cur
->name
= elem
->name
;
538 cur
->nameURI
= elem
->nameURI
;
539 cur
->select
= elem
->select
;
540 cur
->tree
= elem
->tree
;
541 cur
->comp
= elem
->comp
;
547 * @elem: an XSLT stack element
549 * Free up the memory allocated by @elem
552 xsltFreeStackElem(xsltStackElemPtr elem
) {
555 if (elem
->value
!= NULL
)
556 xmlXPathFreeObject(elem
->value
);
558 * Release the list of temporary Result Tree Fragments.
563 while (elem
->fragment
!= NULL
) {
564 cur
= elem
->fragment
;
565 elem
->fragment
= (xmlDocPtr
) cur
->next
;
567 if (cur
->psvi
== XSLT_RVT_VARIABLE
) {
568 xsltReleaseRVT((xsltTransformContextPtr
) elem
->context
,
570 } else if (cur
->psvi
!= XSLT_RVT_FUNC_RESULT
) {
571 xmlGenericError(xmlGenericErrorContext
,
572 "xsltFreeStackElem: Unexpected RVT flag %p\n",
578 * Cache or free the variable structure.
580 if (elem
->context
&& (elem
->context
->cache
->nbStackItems
< 50)) {
582 * Store the item in the cache.
584 xsltTransformContextPtr ctxt
= elem
->context
;
585 memset(elem
, 0, sizeof(xsltStackElem
));
586 elem
->context
= ctxt
;
587 elem
->next
= ctxt
->cache
->stackItems
;
588 ctxt
->cache
->stackItems
= elem
;
589 ctxt
->cache
->nbStackItems
++;
590 #ifdef XSLT_DEBUG_PROFILE_CACHE
591 ctxt
->cache
->dbgCachedVars
++;
599 * xsltFreeStackElemList:
600 * @elem: an XSLT stack element
602 * Free up the memory allocated by @elem
605 xsltFreeStackElemList(xsltStackElemPtr elem
) {
606 xsltStackElemPtr next
;
608 while (elem
!= NULL
) {
610 xsltFreeStackElem(elem
);
617 * @ctxt: an XSLT transformation context
618 * @name: the local part of the name
619 * @nameURI: the URI part of the name
621 * Locate an element in the stack based on its name.
623 #if 0 /* TODO: Those seem to have been used for debugging. */
624 static int stack_addr
= 0;
625 static int stack_cmp
= 0;
628 static xsltStackElemPtr
629 xsltStackLookup(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
630 const xmlChar
*nameURI
) {
632 xsltStackElemPtr cur
;
634 if ((ctxt
== NULL
) || (name
== NULL
) || (ctxt
->varsNr
== 0))
638 * Do the lookup from the top of the stack, but
639 * don't use params being computed in a call-param
640 * First lookup expects the variable name and URI to
641 * come from the disctionnary and hence pointer comparison.
643 for (i
= ctxt
->varsNr
; i
> ctxt
->varsBase
; i
--) {
644 cur
= ctxt
->varsTab
[i
-1];
645 while (cur
!= NULL
) {
646 if ((cur
->name
== name
) && (cur
->nameURI
== nameURI
)) {
657 * Redo the lookup with interned string compares
658 * to avoid string compares.
660 name
= xmlDictLookup(ctxt
->dict
, name
, -1);
662 nameURI
= xmlDictLookup(ctxt
->dict
, nameURI
, -1);
664 for (i
= ctxt
->varsNr
; i
> ctxt
->varsBase
; i
--) {
665 cur
= ctxt
->varsTab
[i
-1];
666 while (cur
!= NULL
) {
667 if ((cur
->name
== name
) && (cur
->nameURI
== nameURI
)) {
680 #ifdef XSLT_REFACTORED
684 * xsltCheckStackElem:
685 * @ctxt: xn XSLT transformation context
686 * @name: the variable name
687 * @nameURI: the variable namespace URI
689 * Checks whether a variable or param is already defined.
691 * URGENT TODO: Checks for redefinition of vars/params should be
692 * done only at compilation time.
694 * Returns 1 if variable is present, 2 if param is present, 3 if this
695 * is an inherited param, 0 if not found, -1 in case of failure.
698 xsltCheckStackElem(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
699 const xmlChar
*nameURI
) {
700 xsltStackElemPtr cur
;
702 if ((ctxt
== NULL
) || (name
== NULL
))
705 cur
= xsltStackLookup(ctxt
, name
, nameURI
);
708 if (cur
->comp
!= NULL
) {
709 if (cur
->comp
->type
== XSLT_FUNC_WITHPARAM
)
711 else if (cur
->comp
->type
== XSLT_FUNC_PARAM
)
718 #endif /* XSLT_REFACTORED */
722 * @ctxt: xn XSLT transformation context
723 * @elem: a stack element
725 * Push an element (or list) onto the stack.
726 * In case of a list, each member will be pushed into
727 * a seperate slot; i.e. there's always 1 stack entry for
730 * Returns 0 in case of success, -1 in case of failure.
733 xsltAddStackElem(xsltTransformContextPtr ctxt
, xsltStackElemPtr elem
)
735 if ((ctxt
== NULL
) || (elem
== NULL
))
739 if (ctxt
->varsMax
== 0) {
742 (xsltStackElemPtr
*) xmlMalloc(ctxt
->varsMax
*
743 sizeof(ctxt
->varsTab
[0]));
744 if (ctxt
->varsTab
== NULL
) {
745 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
749 if (ctxt
->varsNr
>= ctxt
->varsMax
) {
752 (xsltStackElemPtr
*) xmlRealloc(ctxt
->varsTab
,
754 sizeof(ctxt
->varsTab
[0]));
755 if (ctxt
->varsTab
== NULL
) {
756 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
760 ctxt
->varsTab
[ctxt
->varsNr
++] = elem
;
764 } while (elem
!= NULL
);
770 * xsltAddStackElemList:
771 * @ctxt: xn XSLT transformation context
772 * @elems: a stack element list
774 * Push an element list onto the stack.
776 * Returns 0 in case of success, -1 in case of failure.
779 xsltAddStackElemList(xsltTransformContextPtr ctxt
, xsltStackElemPtr elems
)
781 return(xsltAddStackElem(ctxt
, elems
));
784 /************************************************************************
786 * Module interfaces *
788 ************************************************************************/
792 * @ctxt: the XSLT transformation context
793 * @variable: the variable or parameter item
794 * @comp: the compiled XSLT instruction
796 * Evaluate a variable value.
798 * Returns the XPath Object value or NULL in case of error
800 static xmlXPathObjectPtr
801 xsltEvalVariable(xsltTransformContextPtr ctxt
, xsltStackElemPtr variable
,
802 xsltStylePreCompPtr castedComp
)
804 #ifdef XSLT_REFACTORED
805 xsltStyleItemVariablePtr comp
=
806 (xsltStyleItemVariablePtr
) castedComp
;
808 xsltStylePreCompPtr comp
= castedComp
;
810 xmlXPathObjectPtr result
= NULL
;
813 if ((ctxt
== NULL
) || (variable
== NULL
))
817 * A variable or parameter are evaluated on demand; thus the
818 * context (of XSLT and XPath) need to be temporarily adjusted and
821 oldInst
= ctxt
->inst
;
823 #ifdef WITH_XSLT_DEBUG_VARIABLE
824 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
825 "Evaluating variable '%s'\n", variable
->name
));
827 if (variable
->select
!= NULL
) {
828 xmlXPathCompExprPtr xpExpr
= NULL
;
830 xmlNodePtr oldXPContextNode
;
831 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
832 xmlNsPtr
*oldXPNamespaces
;
833 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
834 xsltStackElemPtr oldVar
= ctxt
->contextVariable
;
836 if ((comp
!= NULL
) && (comp
->comp
!= NULL
)) {
839 xpExpr
= xmlXPathCompile(variable
->select
);
844 * Save context states.
846 oldXPDoc
= xpctxt
->doc
;
847 oldXPContextNode
= xpctxt
->node
;
848 oldXPProximityPosition
= xpctxt
->proximityPosition
;
849 oldXPContextSize
= xpctxt
->contextSize
;
850 oldXPNamespaces
= xpctxt
->namespaces
;
851 oldXPNsNr
= xpctxt
->nsNr
;
853 xpctxt
->node
= ctxt
->node
;
855 * OPTIMIZE TODO: Lame try to set the context doc.
856 * Get rid of this somehow in xpath.c.
858 if ((ctxt
->node
->type
!= XML_NAMESPACE_DECL
) &&
860 xpctxt
->doc
= ctxt
->node
->doc
;
862 * BUG TODO: The proximity position and the context size will
863 * potentially be wrong.
865 * <xsl:template select="foo">
866 * <xsl:variable name="pos" select="position()"/>
867 * <xsl:for-each select="bar">
868 * <xsl:value-of select="$pos"/>
871 * Here the proximity position and context size are changed
872 * to the context of <xsl:for-each select="bar">, but
873 * the variable needs to be evaluated in the context of
874 * <xsl:template select="foo">.
878 #ifdef XSLT_REFACTORED
879 if (comp
->inScopeNs
!= NULL
) {
880 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
881 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
883 xpctxt
->namespaces
= NULL
;
887 xpctxt
->namespaces
= comp
->nsList
;
888 xpctxt
->nsNr
= comp
->nsNr
;
891 xpctxt
->namespaces
= NULL
;
896 * We need to mark that we are "selecting" a var's value;
897 * if any tree fragments are created inside the expression,
898 * then those need to be stored inside the variable; otherwise
899 * we'll eventually free still referenced fragments, before
900 * we leave the scope of the variable.
902 ctxt
->contextVariable
= variable
;
903 variable
->flags
|= XSLT_VAR_IN_SELECT
;
905 result
= xmlXPathCompiledEval(xpExpr
, xpctxt
);
907 variable
->flags
^= XSLT_VAR_IN_SELECT
;
909 * Restore Context states.
911 ctxt
->contextVariable
= oldVar
;
913 xpctxt
->doc
= oldXPDoc
;
914 xpctxt
->node
= oldXPContextNode
;
915 xpctxt
->contextSize
= oldXPContextSize
;
916 xpctxt
->proximityPosition
= oldXPProximityPosition
;
917 xpctxt
->namespaces
= oldXPNamespaces
;
918 xpctxt
->nsNr
= oldXPNsNr
;
920 if ((comp
== NULL
) || (comp
->comp
== NULL
))
921 xmlXPathFreeCompExpr(xpExpr
);
922 if (result
== NULL
) {
923 xsltTransformError(ctxt
, NULL
,
924 (comp
!= NULL
) ? comp
->inst
: NULL
,
925 "Failed to evaluate the expression of variable '%s'.\n",
927 ctxt
->state
= XSLT_STATE_STOPPED
;
929 #ifdef WITH_XSLT_DEBUG_VARIABLE
930 #ifdef LIBXML_DEBUG_ENABLED
932 if ((xsltGenericDebugContext
== stdout
) ||
933 (xsltGenericDebugContext
== stderr
))
934 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
940 if (variable
->tree
== NULL
) {
941 result
= xmlXPathNewCString("");
943 if (variable
->tree
) {
945 xmlNodePtr oldInsert
;
947 xsltStackElemPtr oldVar
= ctxt
->contextVariable
;
950 * Generate a result tree fragment.
952 container
= xsltCreateRVT(ctxt
);
953 if (container
== NULL
)
956 * NOTE: Local Result Tree Fragments of params/variables
957 * are not registered globally anymore; the life-time
958 * is not directly dependant of the param/variable itself.
960 * OLD: xsltRegisterTmpRVT(ctxt, container);
963 * Attach the Result Tree Fragment to the variable;
964 * when the variable is freed, it will also free
965 * the Result Tree Fragment.
967 variable
->fragment
= container
;
968 container
->psvi
= XSLT_RVT_VARIABLE
;
970 oldOutput
= ctxt
->output
;
971 oldInsert
= ctxt
->insert
;
973 ctxt
->output
= container
;
974 ctxt
->insert
= (xmlNodePtr
) container
;
975 ctxt
->contextVariable
= variable
;
977 * Process the sequence constructor (variable->tree).
978 * The resulting tree will be held by @container.
980 xsltApplyOneTemplate(ctxt
, ctxt
->node
, variable
->tree
,
983 ctxt
->contextVariable
= oldVar
;
984 ctxt
->insert
= oldInsert
;
985 ctxt
->output
= oldOutput
;
987 result
= xmlXPathNewValueTree((xmlNodePtr
) container
);
989 if (result
== NULL
) {
990 result
= xmlXPathNewCString("");
993 * Freeing is not handled there anymore.
994 * QUESTION TODO: What does the above comment mean?
998 #ifdef WITH_XSLT_DEBUG_VARIABLE
999 #ifdef LIBXML_DEBUG_ENABLED
1001 if ((xsltGenericDebugContext
== stdout
) ||
1002 (xsltGenericDebugContext
== stderr
))
1003 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
1011 ctxt
->inst
= oldInst
;
1016 * xsltEvalGlobalVariable:
1017 * @elem: the variable or parameter
1018 * @ctxt: the XSLT transformation context
1020 * Evaluates a the value of a global xsl:variable or
1021 * xsl:param declaration.
1023 * Returns the XPath Object value or NULL in case of error
1025 static xmlXPathObjectPtr
1026 xsltEvalGlobalVariable(xsltStackElemPtr elem
, xsltTransformContextPtr ctxt
)
1028 xmlXPathObjectPtr result
= NULL
;
1030 const xmlChar
* oldVarName
;
1032 #ifdef XSLT_REFACTORED
1033 xsltStyleBasicItemVariablePtr comp
;
1035 xsltStylePreCompPtr comp
;
1038 if ((ctxt
== NULL
) || (elem
== NULL
))
1041 return(elem
->value
);
1044 #ifdef WITH_XSLT_DEBUG_VARIABLE
1045 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1046 "Evaluating global variable %s\n", elem
->name
));
1049 #ifdef WITH_DEBUGGER
1050 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) &&
1051 elem
->comp
&& elem
->comp
->inst
)
1052 xslHandleDebugger(elem
->comp
->inst
, NULL
, NULL
, ctxt
);
1055 oldInst
= ctxt
->inst
;
1056 #ifdef XSLT_REFACTORED
1057 comp
= (xsltStyleBasicItemVariablePtr
) elem
->comp
;
1061 oldVarName
= elem
->name
;
1062 elem
->name
= xsltComputingGlobalVarMarker
;
1064 * OPTIMIZE TODO: We should consider instantiating global vars/params
1065 * on-demand. The vars/params don't need to be evaluated if never
1066 * called; and in the case of global params, if values for such params
1067 * are provided by the user.
1069 if (elem
->select
!= NULL
) {
1070 xmlXPathCompExprPtr xpExpr
= NULL
;
1072 xmlNodePtr oldXPContextNode
;
1073 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
1074 xmlNsPtr
*oldXPNamespaces
;
1075 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
1077 if ((comp
!= NULL
) && (comp
->comp
!= NULL
)) {
1078 xpExpr
= comp
->comp
;
1080 xpExpr
= xmlXPathCompile(elem
->select
);
1087 ctxt
->inst
= comp
->inst
;
1092 * "At top-level, the expression or template specifying the
1093 * variable value is evaluated with the same context as that used
1094 * to process the root node of the source document: the current
1095 * node is the root node of the source document and the current
1096 * node list is a list containing just the root node of the source
1100 * Save context states.
1102 oldXPDoc
= xpctxt
->doc
;
1103 oldXPContextNode
= xpctxt
->node
;
1104 oldXPProximityPosition
= xpctxt
->proximityPosition
;
1105 oldXPContextSize
= xpctxt
->contextSize
;
1106 oldXPNamespaces
= xpctxt
->namespaces
;
1107 oldXPNsNr
= xpctxt
->nsNr
;
1109 xpctxt
->node
= ctxt
->initialContextNode
;
1110 xpctxt
->doc
= ctxt
->initialContextDoc
;
1111 xpctxt
->contextSize
= 1;
1112 xpctxt
->proximityPosition
= 1;
1116 #ifdef XSLT_REFACTORED
1117 if (comp
->inScopeNs
!= NULL
) {
1118 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
1119 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
1121 xpctxt
->namespaces
= NULL
;
1125 xpctxt
->namespaces
= comp
->nsList
;
1126 xpctxt
->nsNr
= comp
->nsNr
;
1129 xpctxt
->namespaces
= NULL
;
1133 result
= xmlXPathCompiledEval(xpExpr
, xpctxt
);
1136 * Restore Context states.
1138 xpctxt
->doc
= oldXPDoc
;
1139 xpctxt
->node
= oldXPContextNode
;
1140 xpctxt
->contextSize
= oldXPContextSize
;
1141 xpctxt
->proximityPosition
= oldXPProximityPosition
;
1142 xpctxt
->namespaces
= oldXPNamespaces
;
1143 xpctxt
->nsNr
= oldXPNsNr
;
1145 if ((comp
== NULL
) || (comp
->comp
== NULL
))
1146 xmlXPathFreeCompExpr(xpExpr
);
1147 if (result
== NULL
) {
1149 xsltTransformError(ctxt
, NULL
, NULL
,
1150 "Evaluating global variable %s failed\n", elem
->name
);
1152 xsltTransformError(ctxt
, NULL
, comp
->inst
,
1153 "Evaluating global variable %s failed\n", elem
->name
);
1154 ctxt
->state
= XSLT_STATE_STOPPED
;
1159 * Mark all RVTs that are referenced from result as part
1160 * of this variable so they won't be freed too early.
1162 xsltFlagRVTs(ctxt
, result
, XSLT_RVT_GLOBAL
);
1164 #ifdef WITH_XSLT_DEBUG_VARIABLE
1165 #ifdef LIBXML_DEBUG_ENABLED
1166 if ((xsltGenericDebugContext
== stdout
) ||
1167 (xsltGenericDebugContext
== stderr
))
1168 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
1173 if (elem
->tree
== NULL
) {
1174 result
= xmlXPathNewCString("");
1176 xmlDocPtr container
;
1177 xmlNodePtr oldInsert
;
1178 xmlDocPtr oldOutput
, oldXPDoc
;
1180 * Generate a result tree fragment.
1182 container
= xsltCreateRVT(ctxt
);
1183 if (container
== NULL
)
1186 * Let the lifetime of the tree fragment be handled by
1187 * the Libxslt's garbage collector.
1189 xsltRegisterPersistRVT(ctxt
, container
);
1191 oldOutput
= ctxt
->output
;
1192 oldInsert
= ctxt
->insert
;
1194 oldXPDoc
= ctxt
->xpathCtxt
->doc
;
1196 ctxt
->output
= container
;
1197 ctxt
->insert
= (xmlNodePtr
) container
;
1199 ctxt
->xpathCtxt
->doc
= ctxt
->initialContextDoc
;
1201 * Process the sequence constructor.
1203 xsltApplyOneTemplate(ctxt
, ctxt
->node
, elem
->tree
, NULL
, NULL
);
1205 ctxt
->xpathCtxt
->doc
= oldXPDoc
;
1207 ctxt
->insert
= oldInsert
;
1208 ctxt
->output
= oldOutput
;
1210 result
= xmlXPathNewValueTree((xmlNodePtr
) container
);
1211 if (result
== NULL
) {
1212 result
= xmlXPathNewCString("");
1214 result
->boolval
= 0; /* Freeing is not handled there anymore */
1216 #ifdef WITH_XSLT_DEBUG_VARIABLE
1217 #ifdef LIBXML_DEBUG_ENABLED
1218 if ((xsltGenericDebugContext
== stdout
) ||
1219 (xsltGenericDebugContext
== stderr
))
1220 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
1228 elem
->name
= oldVarName
;
1229 ctxt
->inst
= oldInst
;
1230 if (result
!= NULL
) {
1231 elem
->value
= result
;
1238 * xsltEvalGlobalVariables:
1239 * @ctxt: the XSLT transformation context
1241 * Evaluates all global variables and parameters of a stylesheet.
1242 * For internal use only. This is called at start of a transformation.
1244 * Returns 0 in case of success, -1 in case of error
1247 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt
) {
1248 xsltStackElemPtr elem
;
1249 xsltStylesheetPtr style
;
1251 if ((ctxt
== NULL
) || (ctxt
->document
== NULL
))
1254 #ifdef WITH_XSLT_DEBUG_VARIABLE
1255 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1256 "Registering global variables\n"));
1259 * Walk the list from the stylesheets and populate the hash table
1261 style
= ctxt
->style
;
1262 while (style
!= NULL
) {
1263 elem
= style
->variables
;
1265 #ifdef WITH_XSLT_DEBUG_VARIABLE
1266 if ((style
->doc
!= NULL
) && (style
->doc
->URL
!= NULL
)) {
1267 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1268 "Registering global variables from %s\n",
1273 while (elem
!= NULL
) {
1274 xsltStackElemPtr def
;
1277 * Global variables are stored in the variables pool.
1279 def
= (xsltStackElemPtr
)
1280 xmlHashLookup2(ctxt
->globalVars
,
1281 elem
->name
, elem
->nameURI
);
1284 def
= xsltCopyStackElem(elem
);
1285 xmlHashAddEntry2(ctxt
->globalVars
,
1286 elem
->name
, elem
->nameURI
, def
);
1287 } else if ((elem
->comp
!= NULL
) &&
1288 (elem
->comp
->type
== XSLT_FUNC_VARIABLE
)) {
1290 * Redefinition of variables from a different stylesheet
1291 * should not generate a message.
1293 if ((elem
->comp
->inst
!= NULL
) &&
1294 (def
->comp
!= NULL
) && (def
->comp
->inst
!= NULL
) &&
1295 (elem
->comp
->inst
->doc
== def
->comp
->inst
->doc
))
1297 xsltTransformError(ctxt
, style
, elem
->comp
->inst
,
1298 "Global variable %s already defined\n", elem
->name
);
1299 if (style
!= NULL
) style
->errors
++;
1305 style
= xsltNextImport(style
);
1309 * This part does the actual evaluation
1311 xmlHashScan(ctxt
->globalVars
,
1312 (xmlHashScanner
) xsltEvalGlobalVariable
, ctxt
);
1318 * xsltRegisterGlobalVariable:
1319 * @style: the XSLT transformation context
1320 * @name: the variable name
1321 * @ns_uri: the variable namespace URI
1322 * @sel: the expression which need to be evaluated to generate a value
1323 * @tree: the subtree if sel is NULL
1324 * @comp: the precompiled value
1325 * @value: the string value if available
1327 * Register a new variable value. If @value is NULL it unregisters
1330 * Returns 0 in case of success, -1 in case of error
1333 xsltRegisterGlobalVariable(xsltStylesheetPtr style
, const xmlChar
*name
,
1334 const xmlChar
*ns_uri
, const xmlChar
*sel
,
1335 xmlNodePtr tree
, xsltStylePreCompPtr comp
,
1336 const xmlChar
*value
) {
1337 xsltStackElemPtr elem
, tmp
;
1345 #ifdef WITH_XSLT_DEBUG_VARIABLE
1346 if (comp
->type
== XSLT_FUNC_PARAM
)
1347 xsltGenericDebug(xsltGenericDebugContext
,
1348 "Defining global param %s\n", name
);
1350 xsltGenericDebug(xsltGenericDebugContext
,
1351 "Defining global variable %s\n", name
);
1354 elem
= xsltNewStackElem(NULL
);
1358 elem
->name
= xmlDictLookup(style
->dict
, name
, -1);
1359 elem
->select
= xmlDictLookup(style
->dict
, sel
, -1);
1361 elem
->nameURI
= xmlDictLookup(style
->dict
, ns_uri
, -1);
1363 tmp
= style
->variables
;
1366 style
->variables
= elem
;
1368 while (tmp
!= NULL
) {
1369 if ((elem
->comp
->type
== XSLT_FUNC_VARIABLE
) &&
1370 (tmp
->comp
->type
== XSLT_FUNC_VARIABLE
) &&
1371 (xmlStrEqual(elem
->name
, tmp
->name
)) &&
1372 ((elem
->nameURI
== tmp
->nameURI
) ||
1373 (xmlStrEqual(elem
->nameURI
, tmp
->nameURI
))))
1375 xsltTransformError(NULL
, style
, comp
->inst
,
1376 "redefinition of global variable %s\n", elem
->name
);
1379 if (tmp
->next
== NULL
)
1386 if (value
!= NULL
) {
1388 elem
->value
= xmlXPathNewString(value
);
1394 * xsltProcessUserParamInternal
1396 * @ctxt: the XSLT transformation context
1397 * @name: a null terminated parameter name
1398 * @value: a null terminated value (may be an XPath expression)
1399 * @eval: 0 to treat the value literally, else evaluate as XPath expression
1401 * If @eval is 0 then @value is treated literally and is stored in the global
1402 * parameter/variable table without any change.
1404 * Uf @eval is 1 then @value is treated as an XPath expression and is
1405 * evaluated. In this case, if you want to pass a string which will be
1406 * interpreted literally then it must be enclosed in single or double quotes.
1407 * If the string contains single quotes (double quotes) then it cannot be
1408 * enclosed single quotes (double quotes). If the string which you want to
1409 * be treated literally contains both single and double quotes (e.g. Meet
1410 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
1411 * quoting character. You cannot use ' or " inside the string
1412 * because the replacement of character entities with their equivalents is
1413 * done at a different stage of processing. The solution is to call
1414 * xsltQuoteUserParams or xsltQuoteOneUserParam.
1416 * This needs to be done on parsed stylesheets before starting to apply
1417 * transformations. Normally this will be called (directly or indirectly)
1418 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
1419 * or xsltQuoteOneUserParam.
1421 * Returns 0 in case of success, -1 in case of error
1426 xsltProcessUserParamInternal(xsltTransformContextPtr ctxt
,
1427 const xmlChar
* name
,
1428 const xmlChar
* value
,
1431 xsltStylesheetPtr style
;
1432 const xmlChar
*prefix
;
1433 const xmlChar
*href
;
1434 xmlXPathCompExprPtr xpExpr
;
1435 xmlXPathObjectPtr result
;
1437 xsltStackElemPtr elem
;
1448 style
= ctxt
->style
;
1450 #ifdef WITH_XSLT_DEBUG_VARIABLE
1451 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1452 "Evaluating user parameter %s=%s\n", name
, value
));
1460 if (name
[0] == '{') {
1463 while ((name
[len
] != 0) && (name
[len
] != '}')) len
++;
1464 if (name
[len
] == 0) {
1465 xsltTransformError(ctxt
, style
, NULL
,
1466 "user param : malformed parameter name : %s\n", name
);
1468 href
= xmlDictLookup(ctxt
->dict
, &name
[1], len
-1);
1469 name
= xmlDictLookup(ctxt
->dict
, &name
[len
+ 1], -1);
1473 name
= xsltSplitQName(ctxt
->dict
, name
, &prefix
);
1474 if (prefix
!= NULL
) {
1477 ns
= xmlSearchNs(style
->doc
, xmlDocGetRootElement(style
->doc
),
1480 xsltTransformError(ctxt
, style
, NULL
,
1481 "user param : no namespace bound to prefix %s\n", prefix
);
1492 res_ptr
= xmlHashLookup2(ctxt
->globalVars
, name
, href
);
1494 xsltTransformError(ctxt
, style
, NULL
,
1495 "Global parameter %s already defined\n", name
);
1497 if (ctxt
->globalVars
== NULL
)
1498 ctxt
->globalVars
= xmlHashCreate(20);
1501 * do not overwrite variables with parameters from the command line
1503 while (style
!= NULL
) {
1504 elem
= ctxt
->style
->variables
;
1505 while (elem
!= NULL
) {
1506 if ((elem
->comp
!= NULL
) &&
1507 (elem
->comp
->type
== XSLT_FUNC_VARIABLE
) &&
1508 (xmlStrEqual(elem
->name
, name
)) &&
1509 (xmlStrEqual(elem
->nameURI
, href
))) {
1514 style
= xsltNextImport(style
);
1516 style
= ctxt
->style
;
1520 * Do the evaluation if @eval is non-zero.
1525 xpExpr
= xmlXPathCompile(value
);
1526 if (xpExpr
!= NULL
) {
1528 xmlNodePtr oldXPContextNode
;
1529 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
1530 xmlNsPtr
*oldXPNamespaces
;
1531 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
1534 * Save context states.
1536 oldXPDoc
= xpctxt
->doc
;
1537 oldXPContextNode
= xpctxt
->node
;
1538 oldXPProximityPosition
= xpctxt
->proximityPosition
;
1539 oldXPContextSize
= xpctxt
->contextSize
;
1540 oldXPNamespaces
= xpctxt
->namespaces
;
1541 oldXPNsNr
= xpctxt
->nsNr
;
1545 * "At top-level, the expression or template specifying the
1546 * variable value is evaluated with the same context as that used
1547 * to process the root node of the source document: the current
1548 * node is the root node of the source document and the current
1549 * node list is a list containing just the root node of the source
1552 xpctxt
->doc
= ctxt
->initialContextDoc
;
1553 xpctxt
->node
= ctxt
->initialContextNode
;
1554 xpctxt
->contextSize
= 1;
1555 xpctxt
->proximityPosition
= 1;
1557 * There is really no in scope namespace for parameters on the
1560 xpctxt
->namespaces
= NULL
;
1563 result
= xmlXPathCompiledEval(xpExpr
, xpctxt
);
1566 * Restore Context states.
1568 xpctxt
->doc
= oldXPDoc
;
1569 xpctxt
->node
= oldXPContextNode
;
1570 xpctxt
->contextSize
= oldXPContextSize
;
1571 xpctxt
->proximityPosition
= oldXPProximityPosition
;
1572 xpctxt
->namespaces
= oldXPNamespaces
;
1573 xpctxt
->nsNr
= oldXPNsNr
;
1575 xmlXPathFreeCompExpr(xpExpr
);
1577 if (result
== NULL
) {
1578 xsltTransformError(ctxt
, style
, NULL
,
1579 "Evaluating user parameter %s failed\n", name
);
1580 ctxt
->state
= XSLT_STATE_STOPPED
;
1586 * If @eval is 0 then @value is to be taken literally and result is NULL
1588 * If @eval is not 0, then @value is an XPath expression and has been
1589 * successfully evaluated and result contains the resulting value and
1592 * Now create an xsltStackElemPtr for insertion into the context's
1593 * global variable/parameter hash table.
1596 #ifdef WITH_XSLT_DEBUG_VARIABLE
1597 #ifdef LIBXML_DEBUG_ENABLED
1598 if ((xsltGenericDebugContext
== stdout
) ||
1599 (xsltGenericDebugContext
== stderr
))
1600 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext
,
1605 elem
= xsltNewStackElem(NULL
);
1608 elem
->select
= xmlDictLookup(ctxt
->dict
, value
, -1);
1610 elem
->nameURI
= xmlDictLookup(ctxt
->dict
, href
, -1);
1614 elem
->value
= xmlXPathNewString(value
);
1617 elem
->value
= result
;
1622 * Global parameters are stored in the XPath context variables pool.
1625 res
= xmlHashAddEntry2(ctxt
->globalVars
, name
, href
, elem
);
1627 xsltFreeStackElem(elem
);
1628 xsltTransformError(ctxt
, style
, NULL
,
1629 "Global parameter %s already defined\n", name
);
1635 * xsltEvalUserParams:
1637 * @ctxt: the XSLT transformation context
1638 * @params: a NULL terminated array of parameters name/value tuples
1640 * Evaluate the global variables of a stylesheet. This needs to be
1641 * done on parsed stylesheets before starting to apply transformations.
1642 * Each of the parameters is evaluated as an XPath expression and stored
1643 * in the global variables/parameter hash table. If you want your
1644 * parameter used literally, use xsltQuoteUserParams.
1646 * Returns 0 in case of success, -1 in case of error
1650 xsltEvalUserParams(xsltTransformContextPtr ctxt
, const char **params
) {
1652 const xmlChar
*name
;
1653 const xmlChar
*value
;
1657 while (params
[indx
] != NULL
) {
1658 name
= (const xmlChar
*) params
[indx
++];
1659 value
= (const xmlChar
*) params
[indx
++];
1660 if (xsltEvalOneUserParam(ctxt
, name
, value
) != 0)
1667 * xsltQuoteUserParams:
1669 * @ctxt: the XSLT transformation context
1670 * @params: a NULL terminated arry of parameters names/values tuples
1672 * Similar to xsltEvalUserParams, but the values are treated literally and
1673 * are * *not* evaluated as XPath expressions. This should be done on parsed
1674 * stylesheets before starting to apply transformations.
1676 * Returns 0 in case of success, -1 in case of error.
1680 xsltQuoteUserParams(xsltTransformContextPtr ctxt
, const char **params
) {
1682 const xmlChar
*name
;
1683 const xmlChar
*value
;
1687 while (params
[indx
] != NULL
) {
1688 name
= (const xmlChar
*) params
[indx
++];
1689 value
= (const xmlChar
*) params
[indx
++];
1690 if (xsltQuoteOneUserParam(ctxt
, name
, value
) != 0)
1697 * xsltEvalOneUserParam:
1698 * @ctxt: the XSLT transformation context
1699 * @name: a null terminated string giving the name of the parameter
1700 * @value: a null terminated string giving the XPath expression to be evaluated
1702 * This is normally called from xsltEvalUserParams to process a single
1703 * parameter from a list of parameters. The @value is evaluated as an
1704 * XPath expression and the result is stored in the context's global
1705 * variable/parameter hash table.
1707 * To have a parameter treated literally (not as an XPath expression)
1708 * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
1709 * details see description of xsltProcessOneUserParamInternal.
1711 * Returns 0 in case of success, -1 in case of error.
1715 xsltEvalOneUserParam(xsltTransformContextPtr ctxt
,
1716 const xmlChar
* name
,
1717 const xmlChar
* value
) {
1718 return xsltProcessUserParamInternal(ctxt
, name
, value
,
1719 1 /* xpath eval ? */);
1723 * xsltQuoteOneUserParam:
1724 * @ctxt: the XSLT transformation context
1725 * @name: a null terminated string giving the name of the parameter
1726 * @value: a null terminated string giving the parameter value
1728 * This is normally called from xsltQuoteUserParams to process a single
1729 * parameter from a list of parameters. The @value is stored in the
1730 * context's global variable/parameter hash table.
1732 * Returns 0 in case of success, -1 in case of error.
1736 xsltQuoteOneUserParam(xsltTransformContextPtr ctxt
,
1737 const xmlChar
* name
,
1738 const xmlChar
* value
) {
1739 return xsltProcessUserParamInternal(ctxt
, name
, value
,
1740 0 /* xpath eval ? */);
1744 * xsltBuildVariable:
1745 * @ctxt: the XSLT transformation context
1746 * @comp: the precompiled form
1747 * @tree: the tree if select is NULL
1749 * Computes a new variable value.
1751 * Returns the xsltStackElemPtr or NULL in case of error
1753 static xsltStackElemPtr
1754 xsltBuildVariable(xsltTransformContextPtr ctxt
,
1755 xsltStylePreCompPtr castedComp
,
1758 #ifdef XSLT_REFACTORED
1759 xsltStyleBasicItemVariablePtr comp
=
1760 (xsltStyleBasicItemVariablePtr
) castedComp
;
1762 xsltStylePreCompPtr comp
= castedComp
;
1764 xsltStackElemPtr elem
;
1766 #ifdef WITH_XSLT_DEBUG_VARIABLE
1767 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1768 "Building variable %s", comp
->name
));
1769 if (comp
->select
!= NULL
)
1770 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1771 " select %s", comp
->select
));
1772 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
, "\n"));
1775 elem
= xsltNewStackElem(ctxt
);
1778 elem
->comp
= (xsltStylePreCompPtr
) comp
;
1779 elem
->name
= comp
->name
;
1780 elem
->select
= comp
->select
;
1781 elem
->nameURI
= comp
->ns
;
1783 elem
->value
= xsltEvalVariable(ctxt
, elem
,
1784 (xsltStylePreCompPtr
) comp
);
1790 * xsltRegisterVariable:
1791 * @ctxt: the XSLT transformation context
1792 * @comp: the compiled XSLT-variable (or param) instruction
1793 * @tree: the tree if select is NULL
1794 * @isParam: indicates if this is a parameter
1796 * Computes and registers a new variable.
1798 * Returns 0 in case of success, -1 in case of error
1801 xsltRegisterVariable(xsltTransformContextPtr ctxt
,
1802 xsltStylePreCompPtr castedComp
,
1803 xmlNodePtr tree
, int isParam
)
1805 #ifdef XSLT_REFACTORED
1806 xsltStyleBasicItemVariablePtr comp
=
1807 (xsltStyleBasicItemVariablePtr
) castedComp
;
1809 xsltStylePreCompPtr comp
= castedComp
;
1812 xsltStackElemPtr variable
;
1814 #ifdef XSLT_REFACTORED
1816 * REFACTORED NOTE: Redefinitions of vars/params are checked
1817 * at compilation time in the refactored code.
1818 * xsl:with-param parameters are checked in xsltApplyXSLTTemplate().
1821 present
= xsltCheckStackElem(ctxt
, comp
->name
, comp
->ns
);
1823 if ((present
!= 0) && (present
!= 3)) {
1824 /* TODO: report QName. */
1825 xsltTransformError(ctxt
, NULL
, comp
->inst
,
1826 "XSLT-variable: Redefinition of variable '%s'.\n", comp
->name
);
1829 } else if (present
!= 0) {
1830 if ((present
== 1) || (present
== 2)) {
1831 /* TODO: report QName. */
1832 xsltTransformError(ctxt
, NULL
, comp
->inst
,
1833 "XSLT-param: Redefinition of parameter '%s'.\n", comp
->name
);
1836 #ifdef WITH_XSLT_DEBUG_VARIABLE
1837 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1838 "param %s defined by caller\n", comp
->name
));
1842 #endif /* else of XSLT_REFACTORED */
1844 variable
= xsltBuildVariable(ctxt
, (xsltStylePreCompPtr
) comp
, tree
);
1845 xsltAddStackElem(ctxt
, variable
);
1850 * xsltGlobalVariableLookup:
1851 * @ctxt: the XSLT transformation context
1852 * @name: the variable name
1853 * @ns_uri: the variable namespace URI
1855 * Search in the Variable array of the context for the given
1858 * Returns the value or NULL if not found
1860 static xmlXPathObjectPtr
1861 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
1862 const xmlChar
*ns_uri
) {
1863 xsltStackElemPtr elem
;
1864 xmlXPathObjectPtr ret
= NULL
;
1867 * Lookup the global variables in XPath global variable hash table
1869 if ((ctxt
->xpathCtxt
== NULL
) || (ctxt
->globalVars
== NULL
))
1871 elem
= (xsltStackElemPtr
)
1872 xmlHashLookup2(ctxt
->globalVars
, name
, ns_uri
);
1874 #ifdef WITH_XSLT_DEBUG_VARIABLE
1875 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1876 "global variable not found %s\n", name
));
1881 * URGENT TODO: Move the detection of recursive definitions
1884 if (elem
->computed
== 0) {
1885 if (elem
->name
== xsltComputingGlobalVarMarker
) {
1886 xsltTransformError(ctxt
, NULL
, elem
->comp
->inst
,
1887 "Recursive definition of %s\n", name
);
1890 ret
= xsltEvalGlobalVariable(elem
, ctxt
);
1893 return(xmlXPathObjectCopy(ret
));
1897 * xsltVariableLookup:
1898 * @ctxt: the XSLT transformation context
1899 * @name: the variable name
1900 * @ns_uri: the variable namespace URI
1902 * Search in the Variable array of the context for the given
1905 * Returns the value or NULL if not found
1908 xsltVariableLookup(xsltTransformContextPtr ctxt
, const xmlChar
*name
,
1909 const xmlChar
*ns_uri
) {
1910 xsltStackElemPtr elem
;
1915 elem
= xsltStackLookup(ctxt
, name
, ns_uri
);
1917 return(xsltGlobalVariableLookup(ctxt
, name
, ns_uri
));
1919 if (elem
->computed
== 0) {
1920 #ifdef WITH_XSLT_DEBUG_VARIABLE
1921 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1922 "uncomputed variable %s\n", name
));
1924 elem
->value
= xsltEvalVariable(ctxt
, elem
, NULL
);
1927 if (elem
->value
!= NULL
)
1928 return(xmlXPathObjectCopy(elem
->value
));
1929 #ifdef WITH_XSLT_DEBUG_VARIABLE
1930 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1931 "variable not found %s\n", name
));
1937 * xsltParseStylesheetCallerParam:
1938 * @ctxt: the XSLT transformation context
1939 * @inst: the xsl:with-param instruction element
1941 * Processes an xsl:with-param instruction at transformation time.
1942 * The value is compute, but not recorded.
1943 * NOTE that this is also called with an *xsl:param* element
1944 * from exsltFuncFunctionFunction().
1946 * Returns the new xsltStackElemPtr or NULL
1950 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt
, xmlNodePtr inst
)
1952 #ifdef XSLT_REFACTORED
1953 xsltStyleBasicItemVariablePtr comp
;
1955 xsltStylePreCompPtr comp
;
1957 xmlNodePtr tree
= NULL
; /* The first child node of the instruction or
1958 the instruction itself. */
1959 xsltStackElemPtr param
= NULL
;
1961 if ((ctxt
== NULL
) || (inst
== NULL
) || (inst
->type
!= XML_ELEMENT_NODE
))
1964 #ifdef XSLT_REFACTORED
1965 comp
= (xsltStyleBasicItemVariablePtr
) inst
->psvi
;
1967 comp
= (xsltStylePreCompPtr
) inst
->psvi
;
1971 xsltTransformError(ctxt
, NULL
, inst
,
1972 "Internal error in xsltParseStylesheetCallerParam(): "
1973 "The XSLT 'with-param' instruction was not compiled.\n");
1976 if (comp
->name
== NULL
) {
1977 xsltTransformError(ctxt
, NULL
, inst
,
1978 "Internal error in xsltParseStylesheetCallerParam(): "
1979 "XSLT 'with-param': The attribute 'name' was not compiled.\n");
1983 #ifdef WITH_XSLT_DEBUG_VARIABLE
1984 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1985 "Handling xsl:with-param %s\n", comp
->name
));
1988 if (comp
->select
== NULL
) {
1989 tree
= inst
->children
;
1991 #ifdef WITH_XSLT_DEBUG_VARIABLE
1992 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
1993 " select %s\n", comp
->select
));
1998 param
= xsltBuildVariable(ctxt
, (xsltStylePreCompPtr
) comp
, tree
);
2004 * xsltParseGlobalVariable:
2005 * @style: the XSLT stylesheet
2006 * @cur: the "variable" element
2008 * Parses a global XSLT 'variable' declaration at compilation time
2012 xsltParseGlobalVariable(xsltStylesheetPtr style
, xmlNodePtr cur
)
2014 #ifdef XSLT_REFACTORED
2015 xsltStyleItemVariablePtr comp
;
2017 xsltStylePreCompPtr comp
;
2020 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
2023 #ifdef XSLT_REFACTORED
2025 * Note that xsltStylePreCompute() will be called from
2028 comp
= (xsltStyleItemVariablePtr
) cur
->psvi
;
2030 xsltStylePreCompute(style
, cur
);
2031 comp
= (xsltStylePreCompPtr
) cur
->psvi
;
2034 xsltTransformError(NULL
, style
, cur
,
2035 "xsl:variable : compilation failed\n");
2039 if (comp
->name
== NULL
) {
2040 xsltTransformError(NULL
, style
, cur
,
2041 "xsl:variable : missing name attribute\n");
2046 * Parse the content (a sequence constructor) of xsl:variable.
2048 if (cur
->children
!= NULL
) {
2049 #ifdef XSLT_REFACTORED
2050 xsltParseSequenceConstructor(XSLT_CCTXT(style
), cur
->children
);
2052 xsltParseTemplateContent(style
, cur
);
2055 #ifdef WITH_XSLT_DEBUG_VARIABLE
2056 xsltGenericDebug(xsltGenericDebugContext
,
2057 "Registering global variable %s\n", comp
->name
);
2060 xsltRegisterGlobalVariable(style
, comp
->name
, comp
->ns
,
2061 comp
->select
, cur
->children
, (xsltStylePreCompPtr
) comp
,
2066 * xsltParseGlobalParam:
2067 * @style: the XSLT stylesheet
2068 * @cur: the "param" element
2070 * parse an XSLT transformation param declaration and record
2075 xsltParseGlobalParam(xsltStylesheetPtr style
, xmlNodePtr cur
) {
2076 #ifdef XSLT_REFACTORED
2077 xsltStyleItemParamPtr comp
;
2079 xsltStylePreCompPtr comp
;
2082 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
2085 #ifdef XSLT_REFACTORED
2087 * Note that xsltStylePreCompute() will be called from
2090 comp
= (xsltStyleItemParamPtr
) cur
->psvi
;
2092 xsltStylePreCompute(style
, cur
);
2093 comp
= (xsltStylePreCompPtr
) cur
->psvi
;
2096 xsltTransformError(NULL
, style
, cur
,
2097 "xsl:param : compilation failed\n");
2101 if (comp
->name
== NULL
) {
2102 xsltTransformError(NULL
, style
, cur
,
2103 "xsl:param : missing name attribute\n");
2108 * Parse the content (a sequence constructor) of xsl:param.
2110 if (cur
->children
!= NULL
) {
2111 #ifdef XSLT_REFACTORED
2112 xsltParseSequenceConstructor(XSLT_CCTXT(style
), cur
->children
);
2114 xsltParseTemplateContent(style
, cur
);
2118 #ifdef WITH_XSLT_DEBUG_VARIABLE
2119 xsltGenericDebug(xsltGenericDebugContext
,
2120 "Registering global param %s\n", comp
->name
);
2123 xsltRegisterGlobalVariable(style
, comp
->name
, comp
->ns
,
2124 comp
->select
, cur
->children
, (xsltStylePreCompPtr
) comp
,
2129 * xsltParseStylesheetVariable:
2130 * @ctxt: the XSLT transformation context
2131 * @inst: the xsl:variable instruction element
2133 * Registers a local XSLT 'variable' instruction at transformation time
2134 * and evaluates its value.
2137 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt
, xmlNodePtr inst
)
2139 #ifdef XSLT_REFACTORED
2140 xsltStyleItemVariablePtr comp
;
2142 xsltStylePreCompPtr comp
;
2145 if ((inst
== NULL
) || (ctxt
== NULL
) || (inst
->type
!= XML_ELEMENT_NODE
))
2150 xsltTransformError(ctxt
, NULL
, inst
,
2151 "Internal error in xsltParseStylesheetVariable(): "
2152 "The XSLT 'variable' instruction was not compiled.\n");
2155 if (comp
->name
== NULL
) {
2156 xsltTransformError(ctxt
, NULL
, inst
,
2157 "Internal error in xsltParseStylesheetVariable(): "
2158 "The attribute 'name' was not compiled.\n");
2162 #ifdef WITH_XSLT_DEBUG_VARIABLE
2163 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2164 "Registering variable '%s'\n", comp
->name
));
2167 xsltRegisterVariable(ctxt
, (xsltStylePreCompPtr
) comp
, inst
->children
, 0);
2171 * xsltParseStylesheetParam:
2172 * @ctxt: the XSLT transformation context
2173 * @cur: the XSLT 'param' element
2175 * Registers a local XSLT 'param' declaration at transformation time and
2176 * evaluates its value.
2179 xsltParseStylesheetParam(xsltTransformContextPtr ctxt
, xmlNodePtr cur
)
2181 #ifdef XSLT_REFACTORED
2182 xsltStyleItemParamPtr comp
;
2184 xsltStylePreCompPtr comp
;
2187 if ((cur
== NULL
) || (ctxt
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
2191 if ((comp
== NULL
) || (comp
->name
== NULL
)) {
2192 xsltTransformError(ctxt
, NULL
, cur
,
2193 "Internal error in xsltParseStylesheetParam(): "
2194 "The XSLT 'param' declaration was not compiled correctly.\n");
2198 #ifdef WITH_XSLT_DEBUG_VARIABLE
2199 XSLT_TRACE(ctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2200 "Registering param %s\n", comp
->name
));
2203 xsltRegisterVariable(ctxt
, (xsltStylePreCompPtr
) comp
, cur
->children
, 1);
2207 * xsltFreeGlobalVariables:
2208 * @ctxt: the XSLT transformation context
2210 * Free up the data associated to the global variables
2215 xsltFreeGlobalVariables(xsltTransformContextPtr ctxt
) {
2216 xmlHashFree(ctxt
->globalVars
, (xmlHashDeallocator
) xsltFreeStackElem
);
2220 * xsltXPathVariableLookup:
2221 * @ctxt: a void * but the the XSLT transformation context actually
2222 * @name: the variable name
2223 * @ns_uri: the variable namespace URI
2225 * This is the entry point when a varibale is needed by the XPath
2228 * Returns the value or NULL if not found
2231 xsltXPathVariableLookup(void *ctxt
, const xmlChar
*name
,
2232 const xmlChar
*ns_uri
) {
2233 xsltTransformContextPtr tctxt
;
2234 xmlXPathObjectPtr valueObj
= NULL
;
2236 if ((ctxt
== NULL
) || (name
== NULL
))
2239 #ifdef WITH_XSLT_DEBUG_VARIABLE
2240 XSLT_TRACE(((xsltTransformContextPtr
)ctxt
),XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2241 "Lookup variable '%s'\n", name
));
2244 tctxt
= (xsltTransformContextPtr
) ctxt
;
2246 * Local variables/params ---------------------------------------------
2248 * Do the lookup from the top of the stack, but
2249 * don't use params being computed in a call-param
2250 * First lookup expects the variable name and URI to
2251 * come from the disctionnary and hence pointer comparison.
2253 if (tctxt
->varsNr
!= 0) {
2255 xsltStackElemPtr variable
= NULL
, cur
;
2257 for (i
= tctxt
->varsNr
; i
> tctxt
->varsBase
; i
--) {
2258 cur
= tctxt
->varsTab
[i
-1];
2259 if ((cur
->name
== name
) && (cur
->nameURI
== ns_uri
)) {
2264 goto local_variable_found
;
2269 * Redo the lookup with interned strings to avoid string comparison.
2271 * OPTIMIZE TODO: The problem here is, that if we request a
2272 * global variable, then this will be also executed.
2275 const xmlChar
*tmpName
= name
, *tmpNsName
= ns_uri
;
2277 name
= xmlDictLookup(tctxt
->dict
, name
, -1);
2279 ns_uri
= xmlDictLookup(tctxt
->dict
, ns_uri
, -1);
2280 if ((tmpName
!= name
) || (tmpNsName
!= ns_uri
)) {
2281 for (i
= tctxt
->varsNr
; i
> tctxt
->varsBase
; i
--) {
2282 cur
= tctxt
->varsTab
[i
-1];
2283 if ((cur
->name
== name
) && (cur
->nameURI
== ns_uri
)) {
2288 goto local_variable_found
;
2294 local_variable_found
:
2297 if (variable
->computed
== 0) {
2299 #ifdef WITH_XSLT_DEBUG_VARIABLE
2300 XSLT_TRACE(tctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2301 "uncomputed variable '%s'\n", name
));
2303 variable
->value
= xsltEvalVariable(tctxt
, variable
, NULL
);
2304 variable
->computed
= 1;
2306 if (variable
->value
!= NULL
) {
2307 valueObj
= xmlXPathObjectCopy(variable
->value
);
2313 * Global variables/params --------------------------------------------
2315 if (tctxt
->globalVars
) {
2316 valueObj
= xsltGlobalVariableLookup(tctxt
, name
, ns_uri
);
2319 if (valueObj
== NULL
) {
2321 #ifdef WITH_XSLT_DEBUG_VARIABLE
2322 XSLT_TRACE(tctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2323 "variable not found '%s'\n", name
));
2327 xsltTransformError(tctxt
, NULL
, tctxt
->inst
,
2328 "Variable '{%s}%s' has not been declared.\n", ns_uri
, name
);
2330 xsltTransformError(tctxt
, NULL
, tctxt
->inst
,
2331 "Variable '%s' has not been declared.\n", name
);
2335 #ifdef WITH_XSLT_DEBUG_VARIABLE
2336 XSLT_TRACE(tctxt
,XSLT_TRACE_VARIABLES
,xsltGenericDebug(xsltGenericDebugContext
,
2337 "found variable '%s'\n", name
));