Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: third_party/libxslt/libxslt/variables.c

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

Powered by Google App Engine
This is Rietveld 408576698