VirtualBox

source: vbox/trunk/src/libs/libxslt-1.1.22/libxslt/variables.c@ 26688

Last change on this file since 26688 was 7296, checked in by vboxsync, 17 years ago

Added libxslt-1.1.22 sources.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 60.5 KB
Line 
1/*
2 * variables.c: Implementation of the variable storage and lookup
3 *
4 * Reference:
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * See Copyright for the status of this software.
8 *
9 * daniel@veillard.com
10 */
11
12#define IN_LIBXSLT
13#include "libxslt.h"
14
15#include <string.h>
16
17#include <libxml/xmlmemory.h>
18#include <libxml/tree.h>
19#include <libxml/valid.h>
20#include <libxml/hash.h>
21#include <libxml/xmlerror.h>
22#include <libxml/xpath.h>
23#include <libxml/xpathInternals.h>
24#include <libxml/parserInternals.h>
25#include <libxml/dict.h>
26#include "xslt.h"
27#include "xsltInternals.h"
28#include "xsltutils.h"
29#include "variables.h"
30#include "transform.h"
31#include "imports.h"
32#include "preproc.h"
33#include "keys.h"
34
35#ifdef WITH_XSLT_DEBUG
36 #define WITH_XSLT_DEBUG_VARIABLE
37#endif
38
39#ifdef XSLT_REFACTORED
40const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt";
41#endif
42
43const xmlChar *xsltComputingGlobalVarMarker =
44 (const xmlChar *) " var/param being computed";
45
46/************************************************************************
47 * *
48 * Result Value Tree (Result Tree Fragment) interfaces *
49 * *
50 ************************************************************************/
51/**
52 * xsltCreateRVT:
53 * @ctxt: an XSLT transformation context
54 *
55 * Creates a Result Value Tree
56 * (the XSLT 1.0 term for this is "Result Tree Fragment")
57 *
58 * Returns the result value tree or NULL in case of API or internal errors.
59 */
60xmlDocPtr
61xsltCreateRVT(xsltTransformContextPtr ctxt)
62{
63 xmlDocPtr container;
64
65 /*
66 * Question: Why is this function public?
67 * Answer: It is called by the EXSLT module.
68 */
69 if (ctxt == NULL)
70 return(NULL);
71
72 /*
73 * Reuse a RTF from the cache if available.
74 */
75 if (ctxt->cache->RVT) {
76 container = ctxt->cache->RVT;
77 ctxt->cache->RVT = (xmlDocPtr) container->next;
78 /* clear the internal pointers */
79 container->next = NULL;
80 container->prev = NULL;
81 if (ctxt->cache->nbRVT > 0)
82 ctxt->cache->nbRVT--;
83#ifdef XSLT_DEBUG_PROFILE_CACHE
84 ctxt->cache->dbgReusedRVTs++;
85#endif
86 return(container);
87 }
88
89 container = xmlNewDoc(NULL);
90 if (container == NULL)
91 return(NULL);
92 container->dict = ctxt->dict;
93 xmlDictReference(container->dict);
94 XSLT_MARK_RES_TREE_FRAG(container);
95 container->doc = container;
96 container->parent = NULL;
97 return(container);
98}
99
100/**
101 * xsltRegisterTmpRVT:
102 * @ctxt: an XSLT transformation context
103 * @RVT: a result value tree (Result Tree Fragment)
104 *
105 * Registers the result value tree (XSLT 1.0 term: Result Tree Fragment)
106 * in the garbage collector.
107 * The fragment will be freed at the exit of the currently
108 * instantiated xsl:template.
109 * Obsolete; this function might produce massive memory overhead,
110 * since the fragment is only freed when the current xsl:template
111 * exits. Use xsltRegisterLocalRVT() instead.
112 *
113 * Returns 0 in case of success and -1 in case of API or internal errors.
114 */
115int
116xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
117{
118 if ((ctxt == NULL) || (RVT == NULL))
119 return(-1);
120
121 /*
122 * We'll restrict the lifetime of user-created fragments
123 * insinde an xsl:variable and xsl:param to the lifetime of the
124 * var/param itself.
125 */
126 if (ctxt->contextVariable != NULL) {
127 RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
128 XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
129 return(0);
130 }
131
132 RVT->next = (xmlNodePtr) ctxt->tmpRVT;
133 if (ctxt->tmpRVT != NULL)
134 ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
135 ctxt->tmpRVT = RVT;
136 return(0);
137}
138
139/**
140 * xsltRegisterLocalRVT:
141 * @ctxt: an XSLT transformation context
142 * @RVT: a result value tree (Result Tree Fragment; xmlDocPtr)
143 *
144 * Registers a result value tree (XSLT 1.0 term: Result Tree Fragment)
145 * in the RVT garbage collector.
146 * The fragment will be freed when the instruction which created the
147 * fragment exits.
148 *
149 * Returns 0 in case of success and -1 in case of API or internal errors.
150 */
151int
152xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
153 xmlDocPtr RVT)
154{
155 if ((ctxt == NULL) || (RVT == NULL))
156 return(-1);
157
158 /*
159 * When evaluating "select" expressions of xsl:variable
160 * and xsl:param, we need to bind newly created tree fragments
161 * to the variable itself; otherwise the tragment will be
162 * freed before we leave the scope of a var.
163 */
164 if ((ctxt->contextVariable != NULL) &&
165 (XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT))
166 {
167 RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
168 XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
169 return(0);
170 }
171 /*
172 * Store the fragment in the scope of the current instruction.
173 * If not reference by a returning instruction (like EXSLT's function),
174 * then this fragment will be freed, when the instruction exits.
175 */
176 RVT->next = (xmlNodePtr) ctxt->localRVT;
177 if (ctxt->localRVT != NULL)
178 ctxt->localRVT->prev = (xmlNodePtr) RVT;
179 ctxt->localRVT = RVT;
180 /*
181 * We need to keep track of the first registered fragment
182 * for extension instructions which return fragments
183 * (e.g. EXSLT'S function), in order to let
184 * xsltExtensionInstructionResultFinalize() clear the
185 * preserving flag on the fragments.
186 */
187 if (ctxt->localRVTBase == NULL)
188 ctxt->localRVTBase = RVT;
189 return(0);
190}
191
192/**
193 * xsltExtensionInstructionResultFinalize:
194 * @ctxt: an XSLT transformation context
195 *
196 * Finalizes the data (e.g. result tree fragments) created
197 * within a value-returning process (e.g. EXSLT's function).
198 * Tree fragments marked as being returned by a function are
199 * set to normal state, which means that the fragment garbage
200 * collector will free them after the function-calling process exits.
201 *
202 * Returns 0 in case of success and -1 in case of API or internal errors.
203 */
204int
205xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt)
206{
207 xmlDocPtr cur;
208
209 if (ctxt == NULL)
210 return(-1);
211 if (ctxt->localRVTBase == NULL)
212 return(0);
213 /*
214 * Enable remaining local tree fragments to be freed
215 * by the fragment garbage collector.
216 */
217 cur = ctxt->localRVTBase;
218 do {
219 cur->psvi = NULL;
220 cur = (xmlDocPtr) cur->next;
221 } while (cur != NULL);
222 return(0);
223}
224
225/**
226 * xsltExtensionInstructionResultRegister:
227 * @ctxt: an XSLT transformation context
228 * @obj: an XPath object to be inspected for result tree fragments
229 *
230 * Marks the result of a value-returning extension instruction
231 * in order to avoid it being garbage collected before the
232 * extension instruction exits.
233 * Note that one still has to additionally register any newly created
234 * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT().
235 *
236 * Returns 0 in case of success and -1 in case of error.
237 */
238int
239xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt,
240 xmlXPathObjectPtr obj)
241{
242 int i;
243 xmlNodePtr cur;
244 xmlDocPtr doc;
245
246 if ((ctxt == NULL) || (obj == NULL))
247 return(-1);
248
249 /*
250 * OPTIMIZE TODO: If no local variables/params and no local tree
251 * fragments were created, then we don't need to analyse the XPath
252 * objects for tree fragments.
253 */
254
255 if ((obj->type != XPATH_NODESET) && (obj->type != XPATH_XSLT_TREE))
256 return(0);
257 if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0))
258 return(0);
259
260 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
261 cur = obj->nodesetval->nodeTab[i];
262 if (cur->type == XML_NAMESPACE_DECL) {
263 /*
264 * The XPath module sets the owner element of a ns-node on
265 * the ns->next field.
266 */
267 if ((((xmlNsPtr) cur)->next != NULL) &&
268 (((xmlNsPtr) cur)->next->type == XML_ELEMENT_NODE))
269 {
270 cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
271 doc = cur->doc;
272 } else {
273 xsltTransformError(ctxt, NULL, ctxt->inst,
274 "Internal error in "
275 "xsltExtensionInstructionResultRegister(): "
276 "Cannot retrieve the doc of a namespace node.\n");
277 goto error;
278 }
279 } else {
280 doc = cur->doc;
281 }
282 if (doc == NULL) {
283 xsltTransformError(ctxt, NULL, ctxt->inst,
284 "Internal error in "
285 "xsltExtensionInstructionResultRegister(): "
286 "Cannot retrieve the doc of a node.\n");
287 goto error;
288 }
289 if (doc->name && (doc->name[0] == ' ')) {
290 /*
291 * This is a result tree fragment.
292 * We'll use the @psvi field for reference counting.
293 * TODO: How do we know if this is a value of a
294 * global variable or a doc acquired via the
295 * document() function?
296 */
297 doc->psvi = (void *) ((long) 1);
298 }
299 }
300
301 return(0);
302error:
303 return(-1);
304}
305
306/**
307 * xsltReleaseRVT:
308 * @ctxt: an XSLT transformation context
309 * @RVT: a result value tree (Result Tree Fragment)
310 *
311 * Either frees the RVT (which is an xmlDoc) or stores
312 * it in the context's cache for later reuse.
313 */
314void
315xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
316{
317 if (RVT == NULL)
318 return;
319
320 if (ctxt && (ctxt->cache->nbRVT < 40)) {
321 /*
322 * Store the Result Tree Fragment.
323 * Free the document info.
324 */
325 if (RVT->_private != NULL) {
326 xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
327 xmlFree(RVT->_private);
328 RVT->_private = NULL;
329 }
330 /*
331 * Clear the document tree.
332 * REVISIT TODO: Do we expect ID/IDREF tables to be existent?
333 */
334 if (RVT->children != NULL) {
335 xmlFreeNodeList(RVT->children);
336 RVT->children = NULL;
337 RVT->last = NULL;
338 }
339 if (RVT->ids != NULL) {
340 xmlFreeIDTable((xmlIDTablePtr) RVT->ids);
341 RVT->ids = NULL;
342 }
343 if (RVT->refs != NULL) {
344 xmlFreeRefTable((xmlRefTablePtr) RVT->refs);
345 RVT->refs = NULL;
346 }
347
348 /*
349 * Reset the reference counter.
350 */
351 RVT->psvi = 0;
352
353 RVT->next = (xmlNodePtr) ctxt->cache->RVT;
354 ctxt->cache->RVT = RVT;
355
356 ctxt->cache->nbRVT++;
357
358#ifdef XSLT_DEBUG_PROFILE_CACHE
359 ctxt->cache->dbgCachedRVTs++;
360#endif
361 return;
362 }
363 /*
364 * Free it.
365 */
366 if (RVT->_private != NULL) {
367 xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
368 xmlFree(RVT->_private);
369 }
370 xmlFreeDoc(RVT);
371}
372
373/**
374 * xsltRegisterPersistRVT:
375 * @ctxt: an XSLT transformation context
376 * @RVT: a result value tree (Result Tree Fragment)
377 *
378 * Register the result value tree (XSLT 1.0 term: Result Tree Fragment)
379 * in the fragment garbage collector.
380 * The fragment will be freed when the transformation context is
381 * freed.
382 *
383 * Returns 0 in case of success and -1 in case of error.
384 */
385int
386xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
387{
388 if ((ctxt == NULL) || (RVT == NULL)) return(-1);
389
390 RVT->next = (xmlNodePtr) ctxt->persistRVT;
391 if (ctxt->persistRVT != NULL)
392 ctxt->persistRVT->prev = (xmlNodePtr) RVT;
393 ctxt->persistRVT = RVT;
394 return(0);
395}
396
397/**
398 * xsltFreeRVTs:
399 * @ctxt: an XSLT transformation context
400 *
401 * Frees all registered result value trees (Result Tree Fragments)
402 * of the transformation. Internal function; should not be called
403 * by user-code.
404 */
405void
406xsltFreeRVTs(xsltTransformContextPtr ctxt)
407{
408 xmlDocPtr cur, next;
409
410 if (ctxt == NULL)
411 return;
412 /*
413 * Local fragments.
414 */
415 cur = ctxt->localRVT;
416 while (cur != NULL) {
417 next = (xmlDocPtr) cur->next;
418 if (cur->_private != NULL) {
419 xsltFreeDocumentKeys(cur->_private);
420 xmlFree(cur->_private);
421 }
422 xmlFreeDoc(cur);
423 cur = next;
424 }
425 ctxt->localRVT = NULL;
426 /*
427 * User-created per-template fragments.
428 */
429 cur = ctxt->tmpRVT;
430 while (cur != NULL) {
431 next = (xmlDocPtr) cur->next;
432 if (cur->_private != NULL) {
433 xsltFreeDocumentKeys(cur->_private);
434 xmlFree(cur->_private);
435 }
436 xmlFreeDoc(cur);
437 cur = next;
438 }
439 ctxt->tmpRVT = NULL;
440 /*
441 * Global fragments.
442 */
443 cur = ctxt->persistRVT;
444 while (cur != NULL) {
445 next = (xmlDocPtr) cur->next;
446 if (cur->_private != NULL) {
447 xsltFreeDocumentKeys(cur->_private);
448 xmlFree(cur->_private);
449 }
450 xmlFreeDoc(cur);
451 cur = next;
452 }
453 ctxt->persistRVT = NULL;
454}
455
456/************************************************************************
457 * *
458 * Module interfaces *
459 * *
460 ************************************************************************/
461
462/**
463 * xsltNewStackElem:
464 *
465 * Create a new XSLT ParserContext
466 *
467 * Returns the newly allocated xsltParserStackElem or NULL in case of error
468 */
469static xsltStackElemPtr
470xsltNewStackElem(xsltTransformContextPtr ctxt)
471{
472 xsltStackElemPtr ret;
473 /*
474 * Reuse a stack item from the cache if available.
475 */
476 if (ctxt && ctxt->cache->stackItems) {
477 ret = ctxt->cache->stackItems;
478 ctxt->cache->stackItems = ret->next;
479 ret->next = NULL;
480 ctxt->cache->nbStackItems--;
481#ifdef XSLT_DEBUG_PROFILE_CACHE
482 ctxt->cache->dbgReusedVars++;
483#endif
484 return(ret);
485 }
486 ret = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
487 if (ret == NULL) {
488 xsltTransformError(NULL, NULL, NULL,
489 "xsltNewStackElem : malloc failed\n");
490 return(NULL);
491 }
492 memset(ret, 0, sizeof(xsltStackElem));
493 ret->context = ctxt;
494 return(ret);
495}
496
497/**
498 * xsltCopyStackElem:
499 * @elem: an XSLT stack element
500 *
501 * Makes a copy of the stack element
502 *
503 * Returns the copy of NULL
504 */
505static xsltStackElemPtr
506xsltCopyStackElem(xsltStackElemPtr elem) {
507 xsltStackElemPtr cur;
508
509 cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
510 if (cur == NULL) {
511 xsltTransformError(NULL, NULL, NULL,
512 "xsltCopyStackElem : malloc failed\n");
513 return(NULL);
514 }
515 memset(cur, 0, sizeof(xsltStackElem));
516 cur->context = elem->context;
517 cur->name = elem->name;
518 cur->nameURI = elem->nameURI;
519 cur->select = elem->select;
520 cur->tree = elem->tree;
521 cur->comp = elem->comp;
522 return(cur);
523}
524
525/**
526 * xsltFreeStackElem:
527 * @elem: an XSLT stack element
528 *
529 * Free up the memory allocated by @elem
530 */
531static void
532xsltFreeStackElem(xsltStackElemPtr elem) {
533 if (elem == NULL)
534 return;
535 if (elem->value != NULL)
536 xmlXPathFreeObject(elem->value);
537 /*
538 * Release the list of temporary Result Tree Fragments.
539 */
540 if (elem->fragment) {
541 xmlDocPtr cur;
542
543 while (elem->fragment != NULL) {
544 cur = elem->fragment;
545 elem->fragment = (xmlDocPtr) cur->next;
546
547 if (elem->context &&
548 (cur->psvi == (void *) ((long) 1)))
549 {
550 /*
551 * This fragment is a result of an extension instruction
552 * (e.g. XSLT's function) and needs to be preserved until
553 * the instruction exits.
554 * Example: The fragment of the variable must not be freed
555 * since it is returned by the EXSLT function:
556 * <f:function name="foo">
557 * <xsl:variable name="bar">
558 * <bar/>
559 * </xsl:variable>
560 * <f:result select="$bar"/>
561 * </f:function>
562 *
563 */
564 xsltRegisterLocalRVT(elem->context, cur);
565 } else {
566 xsltReleaseRVT((xsltTransformContextPtr) elem->context,
567 cur);
568 }
569 }
570 }
571 /*
572 * Cache or free the variable structure.
573 */
574 if (elem->context && (elem->context->cache->nbStackItems < 50)) {
575 /*
576 * Store the item in the cache.
577 */
578 xsltTransformContextPtr ctxt = elem->context;
579 memset(elem, 0, sizeof(xsltStackElem));
580 elem->context = ctxt;
581 elem->next = ctxt->cache->stackItems;
582 ctxt->cache->stackItems = elem;
583 ctxt->cache->nbStackItems++;
584#ifdef XSLT_DEBUG_PROFILE_CACHE
585 ctxt->cache->dbgCachedVars++;
586#endif
587 return;
588 }
589 xmlFree(elem);
590}
591
592/**
593 * xsltFreeStackElemList:
594 * @elem: an XSLT stack element
595 *
596 * Free up the memory allocated by @elem
597 */
598void
599xsltFreeStackElemList(xsltStackElemPtr elem) {
600 xsltStackElemPtr next;
601
602 while (elem != NULL) {
603 next = elem->next;
604 xsltFreeStackElem(elem);
605 elem = next;
606 }
607}
608
609/**
610 * xsltStackLookup:
611 * @ctxt: an XSLT transformation context
612 * @name: the local part of the name
613 * @nameURI: the URI part of the name
614 *
615 * Locate an element in the stack based on its name.
616 */
617#if 0 /* TODO: Those seem to have been used for debugging. */
618static int stack_addr = 0;
619static int stack_cmp = 0;
620#endif
621
622static xsltStackElemPtr
623xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
624 const xmlChar *nameURI) {
625 int i;
626 xsltStackElemPtr cur;
627
628 if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
629 return(NULL);
630
631 /*
632 * Do the lookup from the top of the stack, but
633 * don't use params being computed in a call-param
634 * First lookup expects the variable name and URI to
635 * come from the disctionnary and hence pointer comparison.
636 */
637 for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
638 cur = ctxt->varsTab[i-1];
639 while (cur != NULL) {
640 if ((cur->name == name) && (cur->nameURI == nameURI)) {
641#if 0
642 stack_addr++;
643#endif
644 return(cur);
645 }
646 cur = cur->next;
647 }
648 }
649
650 /*
651 * Redo the lookup with interned string compares
652 * to avoid string compares.
653 */
654 name = xmlDictLookup(ctxt->dict, name, -1);
655 if (nameURI != NULL)
656 nameURI = xmlDictLookup(ctxt->dict, nameURI, -1);
657
658 for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
659 cur = ctxt->varsTab[i-1];
660 while (cur != NULL) {
661 if ((cur->name == name) && (cur->nameURI == nameURI)) {
662#if 0
663 stack_cmp++;
664#endif
665 return(cur);
666 }
667 cur = cur->next;
668 }
669 }
670
671 return(NULL);
672}
673
674/**
675 * xsltCheckStackElem:
676 * @ctxt: xn XSLT transformation context
677 * @name: the variable name
678 * @nameURI: the variable namespace URI
679 *
680 * Checks whether a variable or param is already defined.
681 *
682 * URGENT TODO: Checks for redefinition of vars/params should be
683 * done only at compilation time.
684 *
685 * Returns 1 if variable is present, 2 if param is present, 3 if this
686 * is an inherited param, 0 if not found, -1 in case of failure.
687 */
688static int
689xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
690 const xmlChar *nameURI) {
691 xsltStackElemPtr cur;
692
693 if ((ctxt == NULL) || (name == NULL))
694 return(-1);
695
696 cur = xsltStackLookup(ctxt, name, nameURI);
697 if (cur == NULL)
698 return(0);
699 if (cur->comp != NULL) {
700 if (cur->comp->type == XSLT_FUNC_WITHPARAM)
701 return(3);
702 else if (cur->comp->type == XSLT_FUNC_PARAM)
703 return(2);
704 }
705
706 return(1);
707}
708
709/**
710 * xsltAddStackElem:
711 * @ctxt: xn XSLT transformation context
712 * @elem: a stack element
713 *
714 * Push an element (or list) onto the stack.
715 * In case of a list, each member will be pushed into
716 * a seperate slot; i.e. there's always 1 stack entry for
717 * 1 stack element.
718 *
719 * Returns 0 in case of success, -1 in case of failure.
720 */
721static int
722xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem)
723{
724 if ((ctxt == NULL) || (elem == NULL))
725 return(-1);
726
727 do {
728 if (ctxt->varsMax == 0) {
729 ctxt->varsMax = 10;
730 ctxt->varsTab =
731 (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
732 sizeof(ctxt->varsTab[0]));
733 if (ctxt->varsTab == NULL) {
734 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
735 return (-1);
736 }
737 }
738 if (ctxt->varsNr >= ctxt->varsMax) {
739 ctxt->varsMax *= 2;
740 ctxt->varsTab =
741 (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
742 ctxt->varsMax *
743 sizeof(ctxt->varsTab[0]));
744 if (ctxt->varsTab == NULL) {
745 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
746 return (-1);
747 }
748 }
749 ctxt->varsTab[ctxt->varsNr++] = elem;
750 ctxt->vars = elem;
751
752 elem = elem->next;
753 } while (elem != NULL);
754
755 return(0);
756}
757
758/**
759 * xsltAddStackElemList:
760 * @ctxt: xn XSLT transformation context
761 * @elems: a stack element list
762 *
763 * Push an element list onto the stack.
764 *
765 * Returns 0 in case of success, -1 in case of failure.
766 */
767int
768xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems)
769{
770 return(xsltAddStackElem(ctxt, elems));
771}
772
773/************************************************************************
774 * *
775 * Module interfaces *
776 * *
777 ************************************************************************/
778
779/**
780 * xsltEvalVariable:
781 * @ctxt: the XSLT transformation context
782 * @variable: the variable or parameter item
783 * @comp: the compiled XSLT instruction
784 *
785 * Evaluate a variable value.
786 *
787 * Returns the XPath Object value or NULL in case of error
788 */
789static xmlXPathObjectPtr
790xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable,
791 xsltStylePreCompPtr castedComp)
792{
793#ifdef XSLT_REFACTORED
794 xsltStyleItemVariablePtr comp =
795 (xsltStyleItemVariablePtr) castedComp;
796#else
797 xsltStylePreCompPtr comp = castedComp;
798#endif
799 xmlXPathObjectPtr result = NULL;
800 xmlNodePtr oldInst;
801
802 if ((ctxt == NULL) || (variable == NULL))
803 return(NULL);
804
805 /*
806 * A variable or parameter are evaluated on demand; thus the
807 * context (of XSLT and XPath) need to be temporarily adjusted and
808 * restored on exit.
809 */
810 oldInst = ctxt->inst;
811
812#ifdef WITH_XSLT_DEBUG_VARIABLE
813 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
814 "Evaluating variable '%s'\n", variable->name));
815#endif
816 if (variable->select != NULL) {
817 xmlXPathCompExprPtr xpExpr = NULL;
818 xmlDocPtr oldXPDoc;
819 xmlNodePtr oldXPContextNode;
820 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
821 xmlNsPtr *oldXPNamespaces;
822 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
823 xsltStackElemPtr oldVar = ctxt->contextVariable;
824
825 if ((comp != NULL) && (comp->comp != NULL)) {
826 xpExpr = comp->comp;
827 } else {
828 xpExpr = xmlXPathCompile(variable->select);
829 }
830 if (xpExpr == NULL)
831 return(NULL);
832 /*
833 * Save context states.
834 */
835 oldXPDoc = xpctxt->doc;
836 oldXPContextNode = xpctxt->node;
837 oldXPProximityPosition = xpctxt->proximityPosition;
838 oldXPContextSize = xpctxt->contextSize;
839 oldXPNamespaces = xpctxt->namespaces;
840 oldXPNsNr = xpctxt->nsNr;
841
842 xpctxt->node = ctxt->node;
843 /*
844 * OPTIMIZE TODO: Lame try to set the context doc.
845 * Get rid of this somehow in xpath.c.
846 */
847 if ((ctxt->node->type != XML_NAMESPACE_DECL) &&
848 ctxt->node->doc)
849 xpctxt->doc = ctxt->node->doc;
850 /*
851 * BUG TODO: The proximity position and the context size will
852 * potentially be wrong.
853 * Example:
854 * <xsl:template select="foo">
855 * <xsl:variable name="pos" select="position()"/>
856 * <xsl:for-each select="bar">
857 * <xsl:value-of select="$pos"/>
858 * </xsl:for-each>
859 * </xsl:template>
860 * Here the proximity position and context size are changed
861 * to the context of <xsl:for-each select="bar">, but
862 * the variable needs to be evaluated in the context of
863 * <xsl:template select="foo">.
864 */
865 if (comp != NULL) {
866
867#ifdef XSLT_REFACTORED
868 if (comp->inScopeNs != NULL) {
869 xpctxt->namespaces = comp->inScopeNs->list;
870 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
871 } else {
872 xpctxt->namespaces = NULL;
873 xpctxt->nsNr = 0;
874 }
875#else
876 xpctxt->namespaces = comp->nsList;
877 xpctxt->nsNr = comp->nsNr;
878#endif
879 } else {
880 xpctxt->namespaces = NULL;
881 xpctxt->nsNr = 0;
882 }
883
884 /*
885 * We need to mark that we are "selecting" a var's value;
886 * if any tree fragments are created inside the expression,
887 * then those need to be stored inside the variable; otherwise
888 * we'll eventually free still referenced fragments, before
889 * we leave the scope of the variable.
890 */
891 ctxt->contextVariable = variable;
892 variable->flags |= XSLT_VAR_IN_SELECT;
893
894 result = xmlXPathCompiledEval(xpExpr, xpctxt);
895
896 variable->flags ^= XSLT_VAR_IN_SELECT;
897 /*
898 * Restore Context states.
899 */
900 ctxt->contextVariable = oldVar;
901
902 xpctxt->doc = oldXPDoc;
903 xpctxt->node = oldXPContextNode;
904 xpctxt->contextSize = oldXPContextSize;
905 xpctxt->proximityPosition = oldXPProximityPosition;
906 xpctxt->namespaces = oldXPNamespaces;
907 xpctxt->nsNr = oldXPNsNr;
908
909 if ((comp == NULL) || (comp->comp == NULL))
910 xmlXPathFreeCompExpr(xpExpr);
911 if (result == NULL) {
912 xsltTransformError(ctxt, NULL,
913 (comp != NULL) ? comp->inst : NULL,
914 "Failed to evaluate the expression of variable '%s'.\n",
915 variable->name);
916 ctxt->state = XSLT_STATE_STOPPED;
917
918#ifdef WITH_XSLT_DEBUG_VARIABLE
919#ifdef LIBXML_DEBUG_ENABLED
920 } else {
921 if ((xsltGenericDebugContext == stdout) ||
922 (xsltGenericDebugContext == stderr))
923 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
924 result, 0);
925#endif
926#endif
927 }
928 } else {
929 if (variable->tree == NULL) {
930 result = xmlXPathNewCString("");
931 } else {
932 if (variable->tree) {
933 xmlDocPtr container;
934 xmlNodePtr oldInsert;
935 xmlDocPtr oldOutput;
936 xsltStackElemPtr oldVar = ctxt->contextVariable;
937
938 /*
939 * Generate a result tree fragment.
940 */
941 container = xsltCreateRVT(ctxt);
942 if (container == NULL)
943 goto error;
944 /*
945 * NOTE: Local Result Tree Fragments of params/variables
946 * are not registered globally anymore; the life-time
947 * is not directly dependant of the param/variable itself.
948 *
949 * OLD: xsltRegisterTmpRVT(ctxt, container);
950 */
951 /*
952 * Attach the Result Tree Fragment to the variable;
953 * when the variable is freed, it will also free
954 * the Result Tree Fragment.
955 */
956 variable->fragment = container;
957
958 oldOutput = ctxt->output;
959 oldInsert = ctxt->insert;
960
961 ctxt->output = container;
962 ctxt->insert = (xmlNodePtr) container;
963 ctxt->contextVariable = variable;
964 /*
965 * Process the sequence constructor (variable->tree).
966 * The resulting tree will be held by @container.
967 */
968 xsltApplyOneTemplate(ctxt, ctxt->node, variable->tree,
969 NULL, NULL);
970
971 ctxt->contextVariable = oldVar;
972 ctxt->insert = oldInsert;
973 ctxt->output = oldOutput;
974
975 result = xmlXPathNewValueTree((xmlNodePtr) container);
976 }
977 if (result == NULL) {
978 result = xmlXPathNewCString("");
979 } else {
980 /*
981 * Freeing is not handled there anymore.
982 * QUESTION TODO: What does the above comment mean?
983 */
984 result->boolval = 0;
985 }
986#ifdef WITH_XSLT_DEBUG_VARIABLE
987#ifdef LIBXML_DEBUG_ENABLED
988
989 if ((xsltGenericDebugContext == stdout) ||
990 (xsltGenericDebugContext == stderr))
991 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
992 result, 0);
993#endif
994#endif
995 }
996 }
997
998error:
999 ctxt->inst = oldInst;
1000 return(result);
1001}
1002
1003/**
1004 * xsltEvalGlobalVariable:
1005 * @elem: the variable or parameter
1006 * @ctxt: the XSLT transformation context
1007 *
1008 * Evaluates a the value of a global xsl:variable or
1009 * xsl:param declaration.
1010 *
1011 * Returns the XPath Object value or NULL in case of error
1012 */
1013static xmlXPathObjectPtr
1014xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt)
1015{
1016 xmlXPathObjectPtr result = NULL;
1017 xmlNodePtr oldInst;
1018 const xmlChar* oldVarName;
1019
1020#ifdef XSLT_REFACTORED
1021 xsltStyleBasicItemVariablePtr comp;
1022#else
1023 xsltStylePreCompPtr comp;
1024#endif
1025
1026 if ((ctxt == NULL) || (elem == NULL))
1027 return(NULL);
1028 if (elem->computed)
1029 return(elem->value);
1030
1031
1032#ifdef WITH_XSLT_DEBUG_VARIABLE
1033 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1034 "Evaluating global variable %s\n", elem->name));
1035#endif
1036
1037#ifdef WITH_DEBUGGER
1038 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) &&
1039 elem->comp && elem->comp->inst)
1040 xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
1041#endif
1042
1043 oldInst = ctxt->inst;
1044 comp = elem->comp;
1045 oldVarName = elem->name;
1046 elem->name = xsltComputingGlobalVarMarker;
1047 /*
1048 * OPTIMIZE TODO: We should consider instantiating global vars/params
1049 * on-demand. The vars/params don't need to be evaluated if never
1050 * called; and in the case of global params, if values for such params
1051 * are provided by the user.
1052 */
1053 if (elem->select != NULL) {
1054 xmlXPathCompExprPtr xpExpr = NULL;
1055 xmlDocPtr oldXPDoc;
1056 xmlNodePtr oldXPContextNode;
1057 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
1058 xmlNsPtr *oldXPNamespaces;
1059 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
1060
1061 if ((comp != NULL) && (comp->comp != NULL)) {
1062 xpExpr = comp->comp;
1063 } else {
1064 xpExpr = xmlXPathCompile(elem->select);
1065 }
1066 if (xpExpr == NULL)
1067 goto error;
1068
1069
1070 if (comp != NULL)
1071 ctxt->inst = comp->inst;
1072 else
1073 ctxt->inst = NULL;
1074 /*
1075 * SPEC XSLT 1.0:
1076 * "At top-level, the expression or template specifying the
1077 * variable value is evaluated with the same context as that used
1078 * to process the root node of the source document: the current
1079 * node is the root node of the source document and the current
1080 * node list is a list containing just the root node of the source
1081 * document."
1082 */
1083 /*
1084 * Save context states.
1085 */
1086 oldXPDoc = xpctxt->doc;
1087 oldXPContextNode = xpctxt->node;
1088 oldXPProximityPosition = xpctxt->proximityPosition;
1089 oldXPContextSize = xpctxt->contextSize;
1090 oldXPNamespaces = xpctxt->namespaces;
1091 oldXPNsNr = xpctxt->nsNr;
1092
1093 xpctxt->node = ctxt->initialContextNode;
1094 xpctxt->doc = ctxt->initialContextDoc;
1095 xpctxt->contextSize = 1;
1096 xpctxt->proximityPosition = 1;
1097
1098 if (comp != NULL) {
1099
1100#ifdef XSLT_REFACTORED
1101 if (comp->inScopeNs != NULL) {
1102 xpctxt->namespaces = comp->inScopeNs->list;
1103 xpctxt->nsNr = comp->inScopeNs->xpathNumber;
1104 } else {
1105 xpctxt->namespaces = NULL;
1106 xpctxt->nsNr = 0;
1107 }
1108#else
1109 xpctxt->namespaces = comp->nsList;
1110 xpctxt->nsNr = comp->nsNr;
1111#endif
1112 } else {
1113 xpctxt->namespaces = NULL;
1114 xpctxt->nsNr = 0;
1115 }
1116
1117 result = xmlXPathCompiledEval(xpExpr, xpctxt);
1118
1119 /*
1120 * Restore Context states.
1121 */
1122 xpctxt->doc = oldXPDoc;
1123 xpctxt->node = oldXPContextNode;
1124 xpctxt->contextSize = oldXPContextSize;
1125 xpctxt->proximityPosition = oldXPProximityPosition;
1126 xpctxt->namespaces = oldXPNamespaces;
1127 xpctxt->nsNr = oldXPNsNr;
1128
1129 if ((comp == NULL) || (comp->comp == NULL))
1130 xmlXPathFreeCompExpr(xpExpr);
1131 if (result == NULL) {
1132 if (comp == NULL)
1133 xsltTransformError(ctxt, NULL, NULL,
1134 "Evaluating global variable %s failed\n", elem->name);
1135 else
1136 xsltTransformError(ctxt, NULL, comp->inst,
1137 "Evaluating global variable %s failed\n", elem->name);
1138 ctxt->state = XSLT_STATE_STOPPED;
1139#ifdef WITH_XSLT_DEBUG_VARIABLE
1140#ifdef LIBXML_DEBUG_ENABLED
1141 } else {
1142 if ((xsltGenericDebugContext == stdout) ||
1143 (xsltGenericDebugContext == stderr))
1144 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1145 result, 0);
1146#endif
1147#endif
1148 }
1149 } else {
1150 if (elem->tree == NULL) {
1151 result = xmlXPathNewCString("");
1152 } else {
1153 xmlDocPtr container;
1154 xmlNodePtr oldInsert;
1155 xmlDocPtr oldOutput, oldXPDoc;
1156 /*
1157 * Generate a result tree fragment.
1158 */
1159 container = xsltCreateRVT(ctxt);
1160 if (container == NULL)
1161 goto error;
1162 /*
1163 * Let the lifetime of the tree fragment be handled by
1164 * the Libxslt's garbage collector.
1165 */
1166 xsltRegisterPersistRVT(ctxt, container);
1167
1168 oldOutput = ctxt->output;
1169 oldInsert = ctxt->insert;
1170
1171 oldXPDoc = ctxt->xpathCtxt->doc;
1172
1173 ctxt->output = container;
1174 ctxt->insert = (xmlNodePtr) container;
1175
1176 ctxt->xpathCtxt->doc = ctxt->initialContextDoc;
1177 /*
1178 * Process the sequence constructor.
1179 */
1180 xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
1181
1182 ctxt->xpathCtxt->doc = oldXPDoc;
1183
1184 ctxt->insert = oldInsert;
1185 ctxt->output = oldOutput;
1186
1187 result = xmlXPathNewValueTree((xmlNodePtr) container);
1188 if (result == NULL) {
1189 result = xmlXPathNewCString("");
1190 } else {
1191 result->boolval = 0; /* Freeing is not handled there anymore */
1192 }
1193#ifdef WITH_XSLT_DEBUG_VARIABLE
1194#ifdef LIBXML_DEBUG_ENABLED
1195 if ((xsltGenericDebugContext == stdout) ||
1196 (xsltGenericDebugContext == stderr))
1197 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1198 result, 0);
1199#endif
1200#endif
1201 }
1202 }
1203
1204error:
1205 elem->name = oldVarName;
1206 ctxt->inst = oldInst;
1207 if (result != NULL) {
1208 elem->value = result;
1209 elem->computed = 1;
1210 }
1211 return(result);
1212}
1213
1214/**
1215 * xsltEvalGlobalVariables:
1216 * @ctxt: the XSLT transformation context
1217 *
1218 * Evaluates all global variables and parameters of a stylesheet.
1219 * For internal use only. This is called at start of a transformation.
1220 *
1221 * Returns 0 in case of success, -1 in case of error
1222 */
1223int
1224xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
1225 xsltStackElemPtr elem;
1226 xsltStylesheetPtr style;
1227
1228 if ((ctxt == NULL) || (ctxt->document == NULL))
1229 return(-1);
1230
1231#ifdef WITH_XSLT_DEBUG_VARIABLE
1232 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1233 "Registering global variables\n"));
1234#endif
1235 /*
1236 * Walk the list from the stylesheets and populate the hash table
1237 */
1238 style = ctxt->style;
1239 while (style != NULL) {
1240 elem = style->variables;
1241
1242#ifdef WITH_XSLT_DEBUG_VARIABLE
1243 if ((style->doc != NULL) && (style->doc->URL != NULL)) {
1244 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1245 "Registering global variables from %s\n",
1246 style->doc->URL));
1247 }
1248#endif
1249
1250 while (elem != NULL) {
1251 xsltStackElemPtr def;
1252
1253 /*
1254 * Global variables are stored in the variables pool.
1255 */
1256 def = (xsltStackElemPtr)
1257 xmlHashLookup2(ctxt->globalVars,
1258 elem->name, elem->nameURI);
1259 if (def == NULL) {
1260
1261 def = xsltCopyStackElem(elem);
1262 xmlHashAddEntry2(ctxt->globalVars,
1263 elem->name, elem->nameURI, def);
1264 } else if ((elem->comp != NULL) &&
1265 (elem->comp->type == XSLT_FUNC_VARIABLE)) {
1266 /*
1267 * Redefinition of variables from a different stylesheet
1268 * should not generate a message.
1269 */
1270 if ((elem->comp->inst != NULL) &&
1271 (def->comp != NULL) && (def->comp->inst != NULL) &&
1272 (elem->comp->inst->doc == def->comp->inst->doc))
1273 {
1274 xsltTransformError(ctxt, style, elem->comp->inst,
1275 "Global variable %s already defined\n", elem->name);
1276 if (style != NULL) style->errors++;
1277 }
1278 }
1279 elem = elem->next;
1280 }
1281
1282 style = xsltNextImport(style);
1283 }
1284
1285 /*
1286 * This part does the actual evaluation
1287 */
1288 xmlHashScan(ctxt->globalVars,
1289 (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
1290
1291 return(0);
1292}
1293
1294/**
1295 * xsltRegisterGlobalVariable:
1296 * @style: the XSLT transformation context
1297 * @name: the variable name
1298 * @ns_uri: the variable namespace URI
1299 * @sel: the expression which need to be evaluated to generate a value
1300 * @tree: the subtree if sel is NULL
1301 * @comp: the precompiled value
1302 * @value: the string value if available
1303 *
1304 * Register a new variable value. If @value is NULL it unregisters
1305 * the variable
1306 *
1307 * Returns 0 in case of success, -1 in case of error
1308 */
1309static int
1310xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
1311 const xmlChar *ns_uri, const xmlChar *sel,
1312 xmlNodePtr tree, xsltStylePreCompPtr comp,
1313 const xmlChar *value) {
1314 xsltStackElemPtr elem, tmp;
1315 if (style == NULL)
1316 return(-1);
1317 if (name == NULL)
1318 return(-1);
1319 if (comp == NULL)
1320 return(-1);
1321
1322#ifdef WITH_XSLT_DEBUG_VARIABLE
1323 if (comp->type == XSLT_FUNC_PARAM)
1324 xsltGenericDebug(xsltGenericDebugContext,
1325 "Defining global param %s\n", name);
1326 else
1327 xsltGenericDebug(xsltGenericDebugContext,
1328 "Defining global variable %s\n", name);
1329#endif
1330
1331 elem = xsltNewStackElem(NULL);
1332 if (elem == NULL)
1333 return(-1);
1334 elem->comp = comp;
1335 elem->name = xmlDictLookup(style->dict, name, -1);
1336 elem->select = xmlDictLookup(style->dict, sel, -1);
1337 if (ns_uri)
1338 elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1);
1339 elem->tree = tree;
1340 tmp = style->variables;
1341 if (tmp == NULL) {
1342 elem->next = NULL;
1343 style->variables = elem;
1344 } else {
1345 while (tmp != NULL) {
1346 if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
1347 (tmp->comp->type == XSLT_FUNC_VARIABLE) &&
1348 (xmlStrEqual(elem->name, tmp->name)) &&
1349 ((elem->nameURI == tmp->nameURI) ||
1350 (xmlStrEqual(elem->nameURI, tmp->nameURI))))
1351 {
1352 xsltTransformError(NULL, style, comp->inst,
1353 "redefinition of global variable %s\n", elem->name);
1354 style->errors++;
1355 }
1356 if (tmp->next == NULL)
1357 break;
1358 tmp = tmp->next;
1359 }
1360 elem->next = NULL;
1361 tmp->next = elem;
1362 }
1363 if (value != NULL) {
1364 elem->computed = 1;
1365 elem->value = xmlXPathNewString(value);
1366 }
1367 return(0);
1368}
1369
1370/**
1371 * xsltProcessUserParamInternal
1372 *
1373 * @ctxt: the XSLT transformation context
1374 * @name: a null terminated parameter name
1375 * @value: a null terminated value (may be an XPath expression)
1376 * @eval: 0 to treat the value literally, else evaluate as XPath expression
1377 *
1378 * If @eval is 0 then @value is treated literally and is stored in the global
1379 * parameter/variable table without any change.
1380 *
1381 * Uf @eval is 1 then @value is treated as an XPath expression and is
1382 * evaluated. In this case, if you want to pass a string which will be
1383 * interpreted literally then it must be enclosed in single or double quotes.
1384 * If the string contains single quotes (double quotes) then it cannot be
1385 * enclosed single quotes (double quotes). If the string which you want to
1386 * be treated literally contains both single and double quotes (e.g. Meet
1387 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
1388 * quoting character. You cannot use &apos; or &quot; inside the string
1389 * because the replacement of character entities with their equivalents is
1390 * done at a different stage of processing. The solution is to call
1391 * xsltQuoteUserParams or xsltQuoteOneUserParam.
1392 *
1393 * This needs to be done on parsed stylesheets before starting to apply
1394 * transformations. Normally this will be called (directly or indirectly)
1395 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
1396 * or xsltQuoteOneUserParam.
1397 *
1398 * Returns 0 in case of success, -1 in case of error
1399 */
1400
1401static
1402int
1403xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
1404 const xmlChar * name,
1405 const xmlChar * value,
1406 int eval) {
1407
1408 xsltStylesheetPtr style;
1409 const xmlChar *prefix;
1410 const xmlChar *href;
1411 xmlXPathCompExprPtr xpExpr;
1412 xmlXPathObjectPtr result;
1413
1414 xsltStackElemPtr elem;
1415 int res;
1416 void *res_ptr;
1417
1418 if (ctxt == NULL)
1419 return(-1);
1420 if (name == NULL)
1421 return(0);
1422 if (value == NULL)
1423 return(0);
1424
1425 style = ctxt->style;
1426
1427#ifdef WITH_XSLT_DEBUG_VARIABLE
1428 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1429 "Evaluating user parameter %s=%s\n", name, value));
1430#endif
1431
1432 /*
1433 * Name lookup
1434 */
1435
1436 name = xsltSplitQName(ctxt->dict, name, &prefix);
1437 href = NULL;
1438 if (prefix != NULL) {
1439 xmlNsPtr ns;
1440
1441 ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
1442 prefix);
1443 if (ns == NULL) {
1444 xsltTransformError(ctxt, style, NULL,
1445 "user param : no namespace bound to prefix %s\n", prefix);
1446 href = NULL;
1447 } else {
1448 href = ns->href;
1449 }
1450 }
1451
1452 if (name == NULL)
1453 return (-1);
1454
1455 res_ptr = xmlHashLookup2(ctxt->globalVars, name, href);
1456 if (res_ptr != 0) {
1457 xsltTransformError(ctxt, style, NULL,
1458 "Global parameter %s already defined\n", name);
1459 }
1460 if (ctxt->globalVars == NULL)
1461 ctxt->globalVars = xmlHashCreate(20);
1462
1463 /*
1464 * do not overwrite variables with parameters from the command line
1465 */
1466 while (style != NULL) {
1467 elem = ctxt->style->variables;
1468 while (elem != NULL) {
1469 if ((elem->comp != NULL) &&
1470 (elem->comp->type == XSLT_FUNC_VARIABLE) &&
1471 (xmlStrEqual(elem->name, name)) &&
1472 (xmlStrEqual(elem->nameURI, href))) {
1473 return(0);
1474 }
1475 elem = elem->next;
1476 }
1477 style = xsltNextImport(style);
1478 }
1479 style = ctxt->style;
1480 elem = NULL;
1481
1482 /*
1483 * Do the evaluation if @eval is non-zero.
1484 */
1485
1486 result = NULL;
1487 if (eval != 0) {
1488 xpExpr = xmlXPathCompile(value);
1489 if (xpExpr != NULL) {
1490 xmlDocPtr oldXPDoc;
1491 xmlNodePtr oldXPContextNode;
1492 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
1493 xmlNsPtr *oldXPNamespaces;
1494 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
1495
1496 /*
1497 * Save context states.
1498 */
1499 oldXPDoc = xpctxt->doc;
1500 oldXPContextNode = xpctxt->node;
1501 oldXPProximityPosition = xpctxt->proximityPosition;
1502 oldXPContextSize = xpctxt->contextSize;
1503 oldXPNamespaces = xpctxt->namespaces;
1504 oldXPNsNr = xpctxt->nsNr;
1505
1506 /*
1507 * SPEC XSLT 1.0:
1508 * "At top-level, the expression or template specifying the
1509 * variable value is evaluated with the same context as that used
1510 * to process the root node of the source document: the current
1511 * node is the root node of the source document and the current
1512 * node list is a list containing just the root node of the source
1513 * document."
1514 */
1515 xpctxt->doc = ctxt->initialContextDoc;
1516 xpctxt->node = ctxt->initialContextNode;
1517 xpctxt->contextSize = 1;
1518 xpctxt->proximityPosition = 1;
1519 /*
1520 * There is really no in scope namespace for parameters on the
1521 * command line.
1522 */
1523 xpctxt->namespaces = NULL;
1524 xpctxt->nsNr = 0;
1525
1526 result = xmlXPathCompiledEval(xpExpr, xpctxt);
1527
1528 /*
1529 * Restore Context states.
1530 */
1531 xpctxt->doc = oldXPDoc;
1532 xpctxt->node = oldXPContextNode;
1533 xpctxt->contextSize = oldXPContextSize;
1534 xpctxt->proximityPosition = oldXPProximityPosition;
1535 xpctxt->namespaces = oldXPNamespaces;
1536 xpctxt->nsNr = oldXPNsNr;
1537
1538 xmlXPathFreeCompExpr(xpExpr);
1539 }
1540 if (result == NULL) {
1541 xsltTransformError(ctxt, style, NULL,
1542 "Evaluating user parameter %s failed\n", name);
1543 ctxt->state = XSLT_STATE_STOPPED;
1544 return(-1);
1545 }
1546 }
1547
1548 /*
1549 * If @eval is 0 then @value is to be taken literally and result is NULL
1550 *
1551 * If @eval is not 0, then @value is an XPath expression and has been
1552 * successfully evaluated and result contains the resulting value and
1553 * is not NULL.
1554 *
1555 * Now create an xsltStackElemPtr for insertion into the context's
1556 * global variable/parameter hash table.
1557 */
1558
1559#ifdef WITH_XSLT_DEBUG_VARIABLE
1560#ifdef LIBXML_DEBUG_ENABLED
1561 if ((xsltGenericDebugContext == stdout) ||
1562 (xsltGenericDebugContext == stderr))
1563 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1564 result, 0);
1565#endif
1566#endif
1567
1568 elem = xsltNewStackElem(NULL);
1569 if (elem != NULL) {
1570 elem->name = name;
1571 elem->select = xmlDictLookup(ctxt->dict, value, -1);
1572 if (href != NULL)
1573 elem->nameURI = xmlDictLookup(ctxt->dict, href, -1);
1574 elem->tree = NULL;
1575 elem->computed = 1;
1576 if (eval == 0) {
1577 elem->value = xmlXPathNewString(value);
1578 }
1579 else {
1580 elem->value = result;
1581 }
1582 }
1583
1584 /*
1585 * Global parameters are stored in the XPath context variables pool.
1586 */
1587
1588 res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem);
1589 if (res != 0) {
1590 xsltFreeStackElem(elem);
1591 xsltTransformError(ctxt, style, NULL,
1592 "Global parameter %s already defined\n", name);
1593 }
1594 return(0);
1595}
1596
1597/**
1598 * xsltEvalUserParams:
1599 *
1600 * @ctxt: the XSLT transformation context
1601 * @params: a NULL terminated array of parameters name/value tuples
1602 *
1603 * Evaluate the global variables of a stylesheet. This needs to be
1604 * done on parsed stylesheets before starting to apply transformations.
1605 * Each of the parameters is evaluated as an XPath expression and stored
1606 * in the global variables/parameter hash table. If you want your
1607 * parameter used literally, use xsltQuoteUserParams.
1608 *
1609 * Returns 0 in case of success, -1 in case of error
1610 */
1611
1612int
1613xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
1614 int indx = 0;
1615 const xmlChar *name;
1616 const xmlChar *value;
1617
1618 if (params == NULL)
1619 return(0);
1620 while (params[indx] != NULL) {
1621 name = (const xmlChar *) params[indx++];
1622 value = (const xmlChar *) params[indx++];
1623 if (xsltEvalOneUserParam(ctxt, name, value) != 0)
1624 return(-1);
1625 }
1626 return 0;
1627}
1628
1629/**
1630 * xsltQuoteUserParams:
1631 *
1632 * @ctxt: the XSLT transformation context
1633 * @params: a NULL terminated arry of parameters names/values tuples
1634 *
1635 * Similar to xsltEvalUserParams, but the values are treated literally and
1636 * are * *not* evaluated as XPath expressions. This should be done on parsed
1637 * stylesheets before starting to apply transformations.
1638 *
1639 * Returns 0 in case of success, -1 in case of error.
1640 */
1641
1642int
1643xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
1644 int indx = 0;
1645 const xmlChar *name;
1646 const xmlChar *value;
1647
1648 if (params == NULL)
1649 return(0);
1650 while (params[indx] != NULL) {
1651 name = (const xmlChar *) params[indx++];
1652 value = (const xmlChar *) params[indx++];
1653 if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
1654 return(-1);
1655 }
1656 return 0;
1657}
1658
1659/**
1660 * xsltEvalOneUserParam:
1661 * @ctxt: the XSLT transformation context
1662 * @name: a null terminated string giving the name of the parameter
1663 * @value: a null terminated string giving the XPath expression to be evaluated
1664 *
1665 * This is normally called from xsltEvalUserParams to process a single
1666 * parameter from a list of parameters. The @value is evaluated as an
1667 * XPath expression and the result is stored in the context's global
1668 * variable/parameter hash table.
1669 *
1670 * To have a parameter treated literally (not as an XPath expression)
1671 * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more
1672 * details see description of xsltProcessOneUserParamInternal.
1673 *
1674 * Returns 0 in case of success, -1 in case of error.
1675 */
1676
1677int
1678xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
1679 const xmlChar * name,
1680 const xmlChar * value) {
1681 return xsltProcessUserParamInternal(ctxt, name, value,
1682 1 /* xpath eval ? */);
1683}
1684
1685/**
1686 * xsltQuoteOneUserParam:
1687 * @ctxt: the XSLT transformation context
1688 * @name: a null terminated string giving the name of the parameter
1689 * @value: a null terminated string giving the parameter value
1690 *
1691 * This is normally called from xsltQuoteUserParams to process a single
1692 * parameter from a list of parameters. The @value is stored in the
1693 * context's global variable/parameter hash table.
1694 *
1695 * Returns 0 in case of success, -1 in case of error.
1696 */
1697
1698int
1699xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
1700 const xmlChar * name,
1701 const xmlChar * value) {
1702 return xsltProcessUserParamInternal(ctxt, name, value,
1703 0 /* xpath eval ? */);
1704}
1705
1706/**
1707 * xsltBuildVariable:
1708 * @ctxt: the XSLT transformation context
1709 * @comp: the precompiled form
1710 * @tree: the tree if select is NULL
1711 *
1712 * Computes a new variable value.
1713 *
1714 * Returns the xsltStackElemPtr or NULL in case of error
1715 */
1716static xsltStackElemPtr
1717xsltBuildVariable(xsltTransformContextPtr ctxt,
1718 xsltStylePreCompPtr castedComp,
1719 xmlNodePtr tree)
1720{
1721#ifdef XSLT_REFACTORED
1722 xsltStyleBasicItemVariablePtr comp =
1723 (xsltStyleBasicItemVariablePtr) castedComp;
1724#else
1725 xsltStylePreCompPtr comp = castedComp;
1726#endif
1727 xsltStackElemPtr elem;
1728
1729#ifdef WITH_XSLT_DEBUG_VARIABLE
1730 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1731 "Building variable %s", comp->name));
1732 if (comp->select != NULL)
1733 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1734 " select %s", comp->select));
1735 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n"));
1736#endif
1737
1738 elem = xsltNewStackElem(ctxt);
1739 if (elem == NULL)
1740 return(NULL);
1741 elem->comp = (xsltStylePreCompPtr) comp;
1742 elem->name = comp->name;
1743 elem->select = comp->select;
1744 elem->nameURI = comp->ns;
1745 elem->tree = tree;
1746 elem->value = xsltEvalVariable(ctxt, elem,
1747 (xsltStylePreCompPtr) comp);
1748 if (elem->value != NULL)
1749 elem->computed = 1;
1750 return(elem);
1751}
1752
1753/**
1754 * xsltRegisterVariable:
1755 * @ctxt: the XSLT transformation context
1756 * @comp: the compiled XSLT-variable (or param) instruction
1757 * @tree: the tree if select is NULL
1758 * @isParam: indicates if this is a parameter
1759 *
1760 * Computes and registers a new variable.
1761 *
1762 * Returns 0 in case of success, -1 in case of error
1763 */
1764static int
1765xsltRegisterVariable(xsltTransformContextPtr ctxt,
1766 xsltStylePreCompPtr castedComp,
1767 xmlNodePtr tree, int isParam)
1768{
1769#ifdef XSLT_REFACTORED
1770 xsltStyleBasicItemVariablePtr comp =
1771 (xsltStyleBasicItemVariablePtr) castedComp;
1772#else
1773 xsltStylePreCompPtr comp = castedComp;
1774 int present;
1775#endif
1776 xsltStackElemPtr variable;
1777
1778#ifdef XSLT_REFACTORED
1779 /*
1780 * REFACTORED NOTE: Redefinitions of vars/params are checked
1781 * at compilation time in the refactored code.
1782 * xsl:with-param parameters are checked in xsltApplyXSLTTemplate().
1783 */
1784#else
1785 present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
1786 if (isParam == 0) {
1787 if ((present != 0) && (present != 3)) {
1788 /* TODO: report QName. */
1789 xsltTransformError(ctxt, NULL, comp->inst,
1790 "XSLT-variable: Redefinition of variable '%s'.\n", comp->name);
1791 return(0);
1792 }
1793 } else if (present != 0) {
1794 if ((present == 1) || (present == 2)) {
1795 /* TODO: report QName. */
1796 xsltTransformError(ctxt, NULL, comp->inst,
1797 "XSLT-param: Redefinition of parameter '%s'.\n", comp->name);
1798 return(0);
1799 }
1800#ifdef WITH_XSLT_DEBUG_VARIABLE
1801 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1802 "param %s defined by caller\n", comp->name));
1803#endif
1804 return(0);
1805 }
1806#endif /* else of XSLT_REFACTORED */
1807
1808 variable = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
1809 xsltAddStackElem(ctxt, variable);
1810 return(0);
1811}
1812
1813/**
1814 * xsltGlobalVariableLookup:
1815 * @ctxt: the XSLT transformation context
1816 * @name: the variable name
1817 * @ns_uri: the variable namespace URI
1818 *
1819 * Search in the Variable array of the context for the given
1820 * variable value.
1821 *
1822 * Returns the value or NULL if not found
1823 */
1824static xmlXPathObjectPtr
1825xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1826 const xmlChar *ns_uri) {
1827 xsltStackElemPtr elem;
1828 xmlXPathObjectPtr ret = NULL;
1829
1830 /*
1831 * Lookup the global variables in XPath global variable hash table
1832 */
1833 if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
1834 return(NULL);
1835 elem = (xsltStackElemPtr)
1836 xmlHashLookup2(ctxt->globalVars, name, ns_uri);
1837 if (elem == NULL) {
1838#ifdef WITH_XSLT_DEBUG_VARIABLE
1839 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1840 "global variable not found %s\n", name));
1841#endif
1842 return(NULL);
1843 }
1844 /*
1845 * URGENT TODO: Move the detection of recursive definitions
1846 * to compile-time.
1847 */
1848 if (elem->computed == 0) {
1849 if (elem->name == xsltComputingGlobalVarMarker) {
1850 xsltTransformError(ctxt, NULL, elem->comp->inst,
1851 "Recursive definition of %s\n", name);
1852 return(NULL);
1853 }
1854 ret = xsltEvalGlobalVariable(elem, ctxt);
1855 } else
1856 ret = elem->value;
1857 return(xmlXPathObjectCopy(ret));
1858}
1859
1860/**
1861 * xsltVariableLookup:
1862 * @ctxt: the XSLT transformation context
1863 * @name: the variable name
1864 * @ns_uri: the variable namespace URI
1865 *
1866 * Search in the Variable array of the context for the given
1867 * variable value.
1868 *
1869 * Returns the value or NULL if not found
1870 */
1871xmlXPathObjectPtr
1872xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1873 const xmlChar *ns_uri) {
1874 xsltStackElemPtr elem;
1875
1876 if (ctxt == NULL)
1877 return(NULL);
1878
1879 elem = xsltStackLookup(ctxt, name, ns_uri);
1880 if (elem == NULL) {
1881 return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
1882 }
1883 if (elem->computed == 0) {
1884#ifdef WITH_XSLT_DEBUG_VARIABLE
1885 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1886 "uncomputed variable %s\n", name));
1887#endif
1888 elem->value = xsltEvalVariable(ctxt, elem, NULL);
1889 elem->computed = 1;
1890 }
1891 if (elem->value != NULL)
1892 return(xmlXPathObjectCopy(elem->value));
1893#ifdef WITH_XSLT_DEBUG_VARIABLE
1894 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1895 "variable not found %s\n", name));
1896#endif
1897 return(NULL);
1898}
1899
1900/**
1901 * xsltParseStylesheetCallerParam:
1902 * @ctxt: the XSLT transformation context
1903 * @inst: the xsl:with-param instruction element
1904 *
1905 * Processes an xsl:with-param instruction at transformation time.
1906 * The value is compute, but not recorded.
1907 * NOTE that this is also called with an *xsl:param* element
1908 * from exsltFuncFunctionFunction().
1909 *
1910 * Returns the new xsltStackElemPtr or NULL
1911 */
1912
1913xsltStackElemPtr
1914xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst)
1915{
1916#ifdef XSLT_REFACTORED
1917 xsltStyleBasicItemVariablePtr comp;
1918#else
1919 xsltStylePreCompPtr comp;
1920#endif
1921 xmlNodePtr tree = NULL; /* The first child node of the instruction or
1922 the instruction itself. */
1923 xsltStackElemPtr param = NULL;
1924
1925 if ((ctxt == NULL) || (inst == NULL))
1926 return(NULL);
1927
1928#ifdef XSLT_REFACTORED
1929 comp = (xsltStyleBasicItemVariablePtr) inst->psvi;
1930#else
1931 comp = (xsltStylePreCompPtr) inst->psvi;
1932#endif
1933
1934 if (comp == NULL) {
1935 xsltTransformError(ctxt, NULL, inst,
1936 "Internal error in xsltParseStylesheetCallerParam(): "
1937 "The XSLT 'with-param' instruction was not compiled.\n");
1938 return(NULL);
1939 }
1940 if (comp->name == NULL) {
1941 xsltTransformError(ctxt, NULL, inst,
1942 "Internal error in xsltParseStylesheetCallerParam(): "
1943 "XSLT 'with-param': The attribute 'name' was not compiled.\n");
1944 return(NULL);
1945 }
1946
1947#ifdef WITH_XSLT_DEBUG_VARIABLE
1948 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1949 "Handling xsl:with-param %s\n", comp->name));
1950#endif
1951
1952 if (comp->select == NULL) {
1953 tree = inst->children;
1954 } else {
1955#ifdef WITH_XSLT_DEBUG_VARIABLE
1956 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1957 " select %s\n", comp->select));
1958#endif
1959 tree = inst;
1960 }
1961
1962 param = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
1963
1964 return(param);
1965}
1966
1967/**
1968 * xsltParseGlobalVariable:
1969 * @style: the XSLT stylesheet
1970 * @cur: the "variable" element
1971 *
1972 * Parses a global XSLT 'variable' declaration at compilation time
1973 * and registers it
1974 */
1975void
1976xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur)
1977{
1978#ifdef XSLT_REFACTORED
1979 xsltStyleItemVariablePtr comp;
1980#else
1981 xsltStylePreCompPtr comp;
1982#endif
1983
1984 if ((cur == NULL) || (style == NULL))
1985 return;
1986
1987#ifdef XSLT_REFACTORED
1988 /*
1989 * Note that xsltStylePreCompute() will be called from
1990 * xslt.c only.
1991 */
1992 comp = (xsltStyleItemVariablePtr) cur->psvi;
1993#else
1994 xsltStylePreCompute(style, cur);
1995 comp = (xsltStylePreCompPtr) cur->psvi;
1996#endif
1997 if (comp == NULL) {
1998 xsltTransformError(NULL, style, cur,
1999 "xsl:variable : compilation failed\n");
2000 return;
2001 }
2002
2003 if (comp->name == NULL) {
2004 xsltTransformError(NULL, style, cur,
2005 "xsl:variable : missing name attribute\n");
2006 return;
2007 }
2008
2009 /*
2010 * Parse the content (a sequence constructor) of xsl:variable.
2011 */
2012 if (cur->children != NULL) {
2013#ifdef XSLT_REFACTORED
2014 xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
2015#else
2016 xsltParseTemplateContent(style, cur);
2017#endif
2018 }
2019#ifdef WITH_XSLT_DEBUG_VARIABLE
2020 xsltGenericDebug(xsltGenericDebugContext,
2021 "Registering global variable %s\n", comp->name);
2022#endif
2023
2024 xsltRegisterGlobalVariable(style, comp->name, comp->ns,
2025 comp->select, cur->children, (xsltStylePreCompPtr) comp,
2026 NULL);
2027}
2028
2029/**
2030 * xsltParseGlobalParam:
2031 * @style: the XSLT stylesheet
2032 * @cur: the "param" element
2033 *
2034 * parse an XSLT transformation param declaration and record
2035 * its value.
2036 */
2037
2038void
2039xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
2040#ifdef XSLT_REFACTORED
2041 xsltStyleItemParamPtr comp;
2042#else
2043 xsltStylePreCompPtr comp;
2044#endif
2045
2046 if ((cur == NULL) || (style == NULL))
2047 return;
2048
2049#ifdef XSLT_REFACTORED
2050 /*
2051 * Note that xsltStylePreCompute() will be called from
2052 * xslt.c only.
2053 */
2054 comp = (xsltStyleItemParamPtr) cur->psvi;
2055#else
2056 xsltStylePreCompute(style, cur);
2057 comp = (xsltStylePreCompPtr) cur->psvi;
2058#endif
2059 if (comp == NULL) {
2060 xsltTransformError(NULL, style, cur,
2061 "xsl:param : compilation failed\n");
2062 return;
2063 }
2064
2065 if (comp->name == NULL) {
2066 xsltTransformError(NULL, style, cur,
2067 "xsl:param : missing name attribute\n");
2068 return;
2069 }
2070
2071 /*
2072 * Parse the content (a sequence constructor) of xsl:param.
2073 */
2074 if (cur->children != NULL) {
2075#ifdef XSLT_REFACTORED
2076 xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
2077#else
2078 xsltParseTemplateContent(style, cur);
2079#endif
2080 }
2081
2082#ifdef WITH_XSLT_DEBUG_VARIABLE
2083 xsltGenericDebug(xsltGenericDebugContext,
2084 "Registering global param %s\n", comp->name);
2085#endif
2086
2087 xsltRegisterGlobalVariable(style, comp->name, comp->ns,
2088 comp->select, cur->children, (xsltStylePreCompPtr) comp,
2089 NULL);
2090}
2091
2092/**
2093 * xsltParseStylesheetVariable:
2094 * @ctxt: the XSLT transformation context
2095 * @inst: the xsl:variable instruction element
2096 *
2097 * Registers a local XSLT 'variable' instruction at transformation time
2098 * and evaluates its value.
2099 */
2100void
2101xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst)
2102{
2103#ifdef XSLT_REFACTORED
2104 xsltStyleItemVariablePtr comp;
2105#else
2106 xsltStylePreCompPtr comp;
2107#endif
2108
2109 if ((inst == NULL) || (ctxt == NULL))
2110 return;
2111
2112 comp = inst->psvi;
2113 if (comp == NULL) {
2114 xsltTransformError(ctxt, NULL, inst,
2115 "Internal error in xsltParseStylesheetVariable(): "
2116 "The XSLT 'variable' instruction was not compiled.\n");
2117 return;
2118 }
2119 if (comp->name == NULL) {
2120 xsltTransformError(ctxt, NULL, inst,
2121 "Internal error in xsltParseStylesheetVariable(): "
2122 "The attribute 'name' was not compiled.\n");
2123 return;
2124 }
2125
2126#ifdef WITH_XSLT_DEBUG_VARIABLE
2127 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2128 "Registering variable '%s'\n", comp->name));
2129#endif
2130
2131 xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, inst->children, 0);
2132}
2133
2134/**
2135 * xsltParseStylesheetParam:
2136 * @ctxt: the XSLT transformation context
2137 * @cur: the XSLT 'param' element
2138 *
2139 * Registers a local XSLT 'param' declaration at transformation time and
2140 * evaluates its value.
2141 */
2142void
2143xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur)
2144{
2145#ifdef XSLT_REFACTORED
2146 xsltStyleItemParamPtr comp;
2147#else
2148 xsltStylePreCompPtr comp;
2149#endif
2150
2151 if ((cur == NULL) || (ctxt == NULL))
2152 return;
2153
2154 comp = cur->psvi;
2155 if ((comp == NULL) || (comp->name == NULL)) {
2156 xsltTransformError(ctxt, NULL, cur,
2157 "Internal error in xsltParseStylesheetParam(): "
2158 "The XSLT 'param' declaration was not compiled correctly.\n");
2159 return;
2160 }
2161
2162#ifdef WITH_XSLT_DEBUG_VARIABLE
2163 XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2164 "Registering param %s\n", comp->name));
2165#endif
2166
2167 xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1);
2168}
2169
2170/**
2171 * xsltFreeGlobalVariables:
2172 * @ctxt: the XSLT transformation context
2173 *
2174 * Free up the data associated to the global variables
2175 * its value.
2176 */
2177
2178void
2179xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
2180 xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
2181}
2182
2183/**
2184 * xsltXPathVariableLookup:
2185 * @ctxt: a void * but the the XSLT transformation context actually
2186 * @name: the variable name
2187 * @ns_uri: the variable namespace URI
2188 *
2189 * This is the entry point when a varibale is needed by the XPath
2190 * interpretor.
2191 *
2192 * Returns the value or NULL if not found
2193 */
2194xmlXPathObjectPtr
2195xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
2196 const xmlChar *ns_uri) {
2197 xsltTransformContextPtr tctxt;
2198 xmlXPathObjectPtr valueObj = NULL;
2199
2200 if ((ctxt == NULL) || (name == NULL))
2201 return(NULL);
2202
2203#ifdef WITH_XSLT_DEBUG_VARIABLE
2204 XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2205 "Lookup variable '%s'\n", name));
2206#endif
2207
2208 tctxt = (xsltTransformContextPtr) ctxt;
2209 /*
2210 * Local variables/params ---------------------------------------------
2211 *
2212 * Do the lookup from the top of the stack, but
2213 * don't use params being computed in a call-param
2214 * First lookup expects the variable name and URI to
2215 * come from the disctionnary and hence pointer comparison.
2216 */
2217 if (tctxt->varsNr != 0) {
2218 int i;
2219 xsltStackElemPtr variable = NULL, cur;
2220
2221 for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
2222 cur = tctxt->varsTab[i-1];
2223 if ((cur->name == name) && (cur->nameURI == ns_uri)) {
2224#if 0
2225 stack_addr++;
2226#endif
2227 variable = cur;
2228 goto local_variable_found;
2229 }
2230 cur = cur->next;
2231 }
2232 /*
2233 * Redo the lookup with interned strings to avoid string comparison.
2234 *
2235 * OPTIMIZE TODO: The problem here is, that if we request a
2236 * global variable, then this will be also executed.
2237 */
2238 {
2239 const xmlChar *tmpName = name, *tmpNsName = ns_uri;
2240
2241 name = xmlDictLookup(tctxt->dict, name, -1);
2242 if (ns_uri)
2243 ns_uri = xmlDictLookup(tctxt->dict, ns_uri, -1);
2244 if ((tmpName != name) || (tmpNsName != ns_uri)) {
2245 for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
2246 cur = tctxt->varsTab[i-1];
2247 if ((cur->name == name) && (cur->nameURI == ns_uri)) {
2248#if 0
2249 stack_cmp++;
2250#endif
2251 variable = cur;
2252 goto local_variable_found;
2253 }
2254 }
2255 }
2256 }
2257
2258local_variable_found:
2259
2260 if (variable) {
2261 if (variable->computed == 0) {
2262
2263#ifdef WITH_XSLT_DEBUG_VARIABLE
2264 XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2265 "uncomputed variable '%s'\n", name));
2266#endif
2267 variable->value = xsltEvalVariable(tctxt, variable, NULL);
2268 variable->computed = 1;
2269 }
2270 if (variable->value != NULL) {
2271 valueObj = xmlXPathObjectCopy(variable->value);
2272 }
2273 return(valueObj);
2274 }
2275 }
2276 /*
2277 * Global variables/params --------------------------------------------
2278 */
2279 if (tctxt->globalVars) {
2280 valueObj = xsltGlobalVariableLookup(tctxt, name, ns_uri);
2281 }
2282
2283 if (valueObj == NULL) {
2284
2285#ifdef WITH_XSLT_DEBUG_VARIABLE
2286 XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2287 "variable not found '%s'\n", name));
2288#endif
2289
2290 if (ns_uri) {
2291 xsltTransformError(tctxt, NULL, tctxt->inst,
2292 "Variable '{%s}%s' has not been declared.\n", ns_uri, name);
2293 } else {
2294 xsltTransformError(tctxt, NULL, tctxt->inst,
2295 "Variable '%s' has not been declared.\n", name);
2296 }
2297 } else {
2298
2299#ifdef WITH_XSLT_DEBUG_VARIABLE
2300 XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
2301 "found variable '%s'\n", name));
2302#endif
2303 }
2304
2305 return(valueObj);
2306}
2307
2308
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette