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