source: trunk/third/libxslt/libxslt/variables.c @ 20733

Revision 20733, 41.5 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20732, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * variables.c: Implementation of the variable storage and lookup
3 *
4 * Reference:
5 *   http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * See Copyright for the status of this software.
8 *
9 * daniel@veillard.com
10 */
11
12#define IN_LIBXSLT
13#include "libxslt.h"
14
15#include <string.h>
16
17#include <libxml/xmlmemory.h>
18#include <libxml/tree.h>
19#include <libxml/valid.h>
20#include <libxml/hash.h>
21#include <libxml/xmlerror.h>
22#include <libxml/xpath.h>
23#include <libxml/xpathInternals.h>
24#include <libxml/parserInternals.h>
25#include "xslt.h"
26#include "xsltInternals.h"
27#include "xsltutils.h"
28#include "variables.h"
29#include "transform.h"
30#include "imports.h"
31#include "preproc.h"
32#include "keys.h"
33
34#ifdef WITH_XSLT_DEBUG
35#define WITH_XSLT_DEBUG_VARIABLE
36#endif
37
38/************************************************************************
39 *                                                                      *
40 *                      Result Value Tree interfaces                    *
41 *                                                                      *
42 ************************************************************************/
43/**
44 * xsltCreateRVT:
45 * @ctxt:  an XSLT transformation context
46 *
47 * Create a result value tree
48 *
49 * Returns the result value tree or NULL in case of error
50 */
51xmlDocPtr
52xsltCreateRVT(xsltTransformContextPtr ctxt)
53{
54    xmlDocPtr container;
55
56    if (ctxt == NULL) return(NULL);
57
58    container = xmlNewDoc(NULL);
59    if (container == NULL)
60        return(NULL);
61    container->dict = ctxt->dict;
62    xmlDictReference(container->dict);
63#ifdef WITH_XSLT_DEBUG
64    xsltGenericDebug(xsltGenericDebugContext,
65                     "reusing transformation dict for RVT\n");
66#endif
67
68    container->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");
69    container->doc = container;
70    container->parent = NULL;
71    return(container);
72}
73
74/**
75 * xsltRegisterTmpRVT:
76 * @ctxt:  an XSLT transformation context
77 * @RVT:  a result value tree
78 *
79 * Register the result value tree for destruction at the end of the context
80 *
81 * Returns 0 in case of success and -1 in case of error.
82 */
83int
84xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
85{
86    if ((ctxt == NULL) || (RVT == NULL)) return(-1);
87
88    RVT->next = (xmlNodePtr) ctxt->tmpRVT;
89    if (ctxt->tmpRVT != NULL)
90        ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
91    ctxt->tmpRVT = RVT;
92    return(0);
93}
94
95/**
96 * xsltRegisterPersistRVT:
97 * @ctxt:  an XSLT transformation context
98 * @RVT:  a result value tree
99 *
100 * Register the result value tree for destruction at the end of the processing
101 *
102 * Returns 0 in case of success and -1 in case of error.
103 */
104int
105xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
106{
107    if ((ctxt == NULL) || (RVT == NULL)) return(-1);
108
109    RVT->next = (xmlNodePtr) ctxt->persistRVT;
110    if (ctxt->persistRVT != NULL)
111        ctxt->persistRVT->prev = (xmlNodePtr) RVT;
112    ctxt->persistRVT = RVT;
113    return(0);
114}
115
116/**
117 * xsltFreeRVTs:
118 * @ctxt:  an XSLT transformation context
119 *
120 * Free all the registered result value tree of the transformation
121 */
122void
123xsltFreeRVTs(xsltTransformContextPtr ctxt)
124{
125    xmlDocPtr cur, next;
126
127    if (ctxt == NULL) return;
128
129    cur = ctxt->tmpRVT;
130    while (cur != NULL) {
131        next = (xmlDocPtr) cur->next;
132        if (cur->_private != NULL) {
133            xsltFreeDocumentKeys(cur->_private);
134            xmlFree(cur->_private);
135        }
136        xmlFreeDoc(cur);
137        cur = next;
138    }
139    cur = ctxt->persistRVT;
140    while (cur != NULL) {
141        next = (xmlDocPtr) cur->next;
142        if (cur->_private != NULL) {
143            xsltFreeDocumentKeys(cur->_private);
144            xmlFree(cur->_private);
145        }
146        xmlFreeDoc(cur);
147        cur = next;
148    }
149}
150
151/************************************************************************
152 *                                                                      *
153 *                      Module interfaces                               *
154 *                                                                      *
155 ************************************************************************/
156
157/**
158 * xsltNewStackElem:
159 *
160 * Create a new XSLT ParserContext
161 *
162 * Returns the newly allocated xsltParserStackElem or NULL in case of error
163 */
164static xsltStackElemPtr
165xsltNewStackElem(void) {
166    xsltStackElemPtr cur;
167
168    cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
169    if (cur == NULL) {
170        xsltTransformError(NULL, NULL, NULL,
171                "xsltNewStackElem : malloc failed\n");
172        return(NULL);
173    }
174    cur->computed = 0;
175    cur->name = NULL;
176    cur->nameURI = NULL;
177    cur->select = NULL;
178    cur->tree = NULL;
179    cur->value = NULL;
180    cur->comp = NULL;
181    return(cur);
182}
183
184/**
185 * xsltCopyStackElem:
186 * @elem:  an XSLT stack element
187 *
188 * Makes a copy of the stack element
189 *
190 * Returns the copy of NULL
191 */
192static xsltStackElemPtr
193xsltCopyStackElem(xsltStackElemPtr elem) {
194    xsltStackElemPtr cur;
195
196    cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
197    if (cur == NULL) {
198        xsltTransformError(NULL, NULL, NULL,
199                "xsltCopyStackElem : malloc failed\n");
200        return(NULL);
201    }
202    cur->name = elem->name;
203    cur->nameURI = elem->nameURI;
204    cur->select = elem->select;
205    cur->tree = elem->tree;
206    cur->comp = elem->comp;
207    cur->computed = 0;
208    cur->value = NULL;
209    return(cur);
210}
211
212/**
213 * xsltFreeStackElem:
214 * @elem:  an XSLT stack element
215 *
216 * Free up the memory allocated by @elem
217 */
218static void
219xsltFreeStackElem(xsltStackElemPtr elem) {
220    if (elem == NULL)
221        return;
222    if (elem->value != NULL)
223        xmlXPathFreeObject(elem->value);
224
225    xmlFree(elem);
226}
227
228/**
229 * xsltFreeStackElemList:
230 * @elem:  an XSLT stack element
231 *
232 * Free up the memory allocated by @elem
233 */
234void
235xsltFreeStackElemList(xsltStackElemPtr elem) {
236    xsltStackElemPtr next;
237
238    while(elem != NULL) {
239        next = elem->next;
240        xsltFreeStackElem(elem);
241        elem = next;
242    }
243}
244
245/**
246 * xsltStackLookup:
247 * @ctxt:  an XSLT transformation context
248 * @name:  the local part of the name
249 * @nameURI:  the URI part of the name
250 *
251 * Locate an element in the stack based on its name.
252 */
253static xsltStackElemPtr
254xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
255                const xmlChar *nameURI) {
256    int i;
257    xsltStackElemPtr cur;
258
259    if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
260        return(NULL);
261
262    /*
263     * Do the lookup from the top of the stack, but
264     * don't use params being computed in a call-param
265     * First lookup expects the variable name and URI to
266     * come from the disctionnary and hence get equality
267     */
268    for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
269        cur = ctxt->varsTab[i-1];
270        while (cur != NULL) {
271            if (cur->name == name) {
272                if (nameURI == NULL) {
273                    if (cur->nameURI == NULL) {
274                        return(cur);
275                    }
276                } else {
277                    if ((cur->nameURI != NULL) &&
278                        (cur->nameURI == nameURI)) {
279                        return(cur);
280                    }
281                }
282
283            }
284            cur = cur->next;
285        }
286    }
287
288#if 0
289    if ((xmlDictOwns(ctxt->dict, name) <= 0) ||
290        ((nameURI != NULL) && (xmlDictOwns(ctxt->dict, nameURI) <= 0))) {
291        /*
292         * Redo the lookup with string compares
293         */
294        for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
295            cur = ctxt->varsTab[i-1];
296            while (cur != NULL) {
297                if (xmlStrEqual(cur->name, name)) {
298                    if (nameURI == NULL) {
299                        if (cur->nameURI == NULL) {
300                            return(cur);
301                        }
302                    } else {
303                        if ((cur->nameURI != NULL) &&
304                            (xmlStrEqual(cur->nameURI, nameURI))) {
305                            return(cur);
306                        }
307                    }
308
309                }
310                cur = cur->next;
311            }
312        }
313    }
314#else
315    /*
316     * Redo the lookup with string compares
317     */
318    for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
319        cur = ctxt->varsTab[i-1];
320        while (cur != NULL) {
321            if (xmlStrEqual(cur->name, name)) {
322                if (nameURI == NULL) {
323                    if (cur->nameURI == NULL) {
324                        return(cur);
325                    }
326                } else {
327                    if ((cur->nameURI != NULL) &&
328                        (xmlStrEqual(cur->nameURI, nameURI))) {
329                        return(cur);
330                    }
331                }
332
333            }
334            cur = cur->next;
335        }
336    }
337#endif
338    return(NULL);
339}
340
341/**
342 * xsltCheckStackElem:
343 * @ctxt:  xn XSLT transformation context
344 * @name:  the variable name
345 * @nameURI:  the variable namespace URI
346 *
347 * check wether the variable or param is already defined
348 *
349 * Returns 1 if variable is present, 2 if param is present, 3 if this
350 *         is an inherited param, 0 if not found, -1 in case of failure.
351 */
352static int
353xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
354                   const xmlChar *nameURI) {
355    xsltStackElemPtr cur;
356
357    if ((ctxt == NULL) || (name == NULL))
358        return(-1);
359
360    cur = xsltStackLookup(ctxt, name, nameURI);
361    if (cur == NULL)
362        return(0);
363    if (cur->comp != NULL) {
364        if (cur->comp->type == XSLT_FUNC_WITHPARAM)
365            return(3);
366        else if (cur->comp->type == XSLT_FUNC_PARAM)
367            return(2);
368    }
369   
370    return(1);
371}
372
373/**
374 * xsltAddStackElem:
375 * @ctxt:  xn XSLT transformation context
376 * @elem:  a stack element
377 *
378 * add a new element at this level of the stack.
379 *
380 * Returns 0 in case of success, -1 in case of failure.
381 */
382static int
383xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
384    if ((ctxt == NULL) || (elem == NULL))
385        return(-1);
386
387    elem->next = ctxt->varsTab[ctxt->varsNr - 1];
388    ctxt->varsTab[ctxt->varsNr - 1] = elem;
389    ctxt->vars = elem;
390    return(0);
391}
392
393/**
394 * xsltAddStackElemList:
395 * @ctxt:  xn XSLT transformation context
396 * @elems:  a stack element list
397 *
398 * add the new element list at this level of the stack.
399 *
400 * Returns 0 in case of success, -1 in case of failure.
401 */
402int
403xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) {
404    xsltStackElemPtr cur;
405
406    if ((ctxt == NULL) || (elems == NULL))
407        return(-1);
408
409    /* TODO: check doublons */
410    if (ctxt->varsTab[ctxt->varsNr - 1] != NULL) {
411        cur = ctxt->varsTab[ctxt->varsNr - 1];
412        while (cur->next != NULL)
413            cur = cur->next;
414        cur->next = elems;
415    } else {
416        elems->next = ctxt->varsTab[ctxt->varsNr - 1];
417        ctxt->varsTab[ctxt->varsNr - 1] = elems;
418        ctxt->vars = elems;
419    }
420    return(0);
421}
422
423/************************************************************************
424 *                                                                      *
425 *                      Module interfaces                               *
426 *                                                                      *
427 ************************************************************************/
428
429/**
430 * xsltEvalVariable:
431 * @ctxt:  the XSLT transformation context
432 * @elem:  the variable or parameter.
433 * @precomp: pointer to precompiled data
434 *
435 * Evaluate a variable value.
436 *
437 * Returns the XPath Object value or NULL in case of error
438 */
439static xmlXPathObjectPtr
440xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
441                 xsltStylePreCompPtr precomp) {
442    xmlXPathObjectPtr result = NULL;
443    int oldProximityPosition, oldContextSize;
444    xmlNodePtr oldInst, oldNode;
445    xsltDocumentPtr oldDoc;
446    int oldNsNr;
447    xmlNsPtr *oldNamespaces;
448
449    if ((ctxt == NULL) || (elem == NULL))
450        return(NULL);
451
452#ifdef WITH_XSLT_DEBUG_VARIABLE
453    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
454        "Evaluating variable %s\n", elem->name));
455#endif
456    if (elem->select != NULL) {
457        xmlXPathCompExprPtr comp = NULL;
458
459        if ((precomp != NULL) && (precomp->comp != NULL)) {
460            comp = precomp->comp;
461        } else {
462            comp = xmlXPathCompile(elem->select);
463        }
464        if (comp == NULL)
465            return(NULL);
466        oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
467        oldContextSize = ctxt->xpathCtxt->contextSize;
468        ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
469        oldDoc = ctxt->document;
470        oldNode = ctxt->node;
471        oldInst = ctxt->inst;
472        oldNsNr = ctxt->xpathCtxt->nsNr;
473        oldNamespaces = ctxt->xpathCtxt->namespaces;
474        if (precomp != NULL) {
475            ctxt->inst = precomp->inst;
476            ctxt->xpathCtxt->namespaces = precomp->nsList;
477            ctxt->xpathCtxt->nsNr = precomp->nsNr;
478        } else {
479            ctxt->inst = NULL;
480            ctxt->xpathCtxt->namespaces = NULL;
481            ctxt->xpathCtxt->nsNr = 0;
482        }
483        result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
484        ctxt->xpathCtxt->contextSize = oldContextSize;
485        ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
486        ctxt->xpathCtxt->nsNr = oldNsNr;
487        ctxt->xpathCtxt->namespaces = oldNamespaces;
488        ctxt->inst = oldInst;
489        ctxt->node = oldNode;
490        ctxt->document = oldDoc;
491        if ((precomp == NULL) || (precomp->comp == NULL))
492            xmlXPathFreeCompExpr(comp);
493        if (result == NULL) {
494            xsltTransformError(ctxt, NULL, precomp->inst,
495                "Evaluating variable %s failed\n", elem->name);
496            ctxt->state = XSLT_STATE_STOPPED;
497#ifdef WITH_XSLT_DEBUG_VARIABLE
498#ifdef LIBXML_DEBUG_ENABLED
499        } else {
500            if ((xsltGenericDebugContext == stdout) ||
501                (xsltGenericDebugContext == stderr))
502                xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
503                                        result, 0);
504#endif
505#endif
506        }
507    } else {
508        if (elem->tree == NULL) {
509            result = xmlXPathNewCString("");
510        } else {
511            /*
512             * This is a result tree fragment.
513             */
514            xmlDocPtr container;
515            xmlNodePtr oldInsert;
516            xmlDocPtr  oldoutput;
517
518            container = xsltCreateRVT(ctxt);
519            if (container == NULL)
520                return(NULL);
521            /*
522             * Tag the subtree for removal once consumed
523             */
524            xsltRegisterTmpRVT(ctxt, container);
525            oldoutput = ctxt->output;
526            ctxt->output = container;
527            oldInsert = ctxt->insert;
528            ctxt->insert = (xmlNodePtr) container;
529            xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
530            ctxt->insert = oldInsert;
531            ctxt->output = oldoutput;
532
533            result = xmlXPathNewValueTree((xmlNodePtr) container);
534            if (result == NULL) {
535                result = xmlXPathNewCString("");
536            } else {
537                result->boolval = 0; /* Freeing is not handled there anymore */
538            }
539#ifdef WITH_XSLT_DEBUG_VARIABLE
540#ifdef LIBXML_DEBUG_ENABLED
541            if ((xsltGenericDebugContext == stdout) ||
542                (xsltGenericDebugContext == stderr))
543                xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
544                                        result, 0);
545#endif
546#endif
547        }
548    }
549    return(result);
550}
551
552/**
553 * xsltEvalGlobalVariable:
554 * @elem:  the variable or parameter.
555 * @ctxt:  the XSLT transformation context
556 *
557 * Evaluate a global variable value.
558 *
559 * Returns the XPath Object value or NULL in case of error
560 */
561static xmlXPathObjectPtr
562xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
563    xmlXPathObjectPtr result = NULL;
564    xsltStylePreCompPtr precomp;
565    int oldProximityPosition, oldContextSize;
566    xmlNodePtr oldInst;
567    int oldNsNr;
568    xmlNsPtr *oldNamespaces;
569    const xmlChar *name;
570
571    if ((ctxt == NULL) || (elem == NULL))
572        return(NULL);
573    if (elem->computed)
574        return(elem->value);
575
576
577#ifdef WITH_XSLT_DEBUG_VARIABLE
578    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
579        "Evaluating global variable %s\n", elem->name));
580#endif
581
582#ifdef WITH_DEBUGGER
583    if ((ctxt->debugStatus != XSLT_DEBUG_NONE) &&
584        elem->comp && elem->comp->inst)
585        xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
586#endif
587
588    name = elem->name;
589    elem->name = BAD_CAST "  being computed ... ";
590
591    precomp = elem->comp;
592    if (elem->select != NULL) {
593        xmlXPathCompExprPtr comp = NULL;
594
595        if ((precomp != NULL) && (precomp->comp != NULL)) {
596            comp = precomp->comp;
597        } else {
598            comp = xmlXPathCompile(elem->select);
599        }
600        if (comp == NULL) {
601            elem->name = name;
602            return(NULL);
603        }
604        oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
605        oldContextSize = ctxt->xpathCtxt->contextSize;
606        oldInst = ctxt->inst;
607        oldNsNr = ctxt->xpathCtxt->nsNr;
608        oldNamespaces = ctxt->xpathCtxt->namespaces;
609        if (precomp != NULL) {
610            ctxt->inst = precomp->inst;
611            ctxt->xpathCtxt->namespaces = precomp->nsList;
612            ctxt->xpathCtxt->nsNr = precomp->nsNr;
613        } else {
614            ctxt->inst = NULL;
615            ctxt->xpathCtxt->namespaces = NULL;
616            ctxt->xpathCtxt->nsNr = 0;
617        }
618        ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
619        result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
620        ctxt->xpathCtxt->contextSize = oldContextSize;
621        ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
622        ctxt->inst = oldInst;
623        ctxt->xpathCtxt->nsNr = oldNsNr;
624        ctxt->xpathCtxt->namespaces = oldNamespaces;
625        if ((precomp == NULL) || (precomp->comp == NULL))
626            xmlXPathFreeCompExpr(comp);
627        if (result == NULL) {
628            xsltTransformError(ctxt, NULL, precomp->inst,
629                "Evaluating global variable %s failed\n", elem->name);
630            ctxt->state = XSLT_STATE_STOPPED;
631#ifdef WITH_XSLT_DEBUG_VARIABLE
632#ifdef LIBXML_DEBUG_ENABLED
633        } else {
634            if ((xsltGenericDebugContext == stdout) ||
635                (xsltGenericDebugContext == stderr))
636                xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
637                                        result, 0);
638#endif
639#endif
640        }
641    } else {
642        if (elem->tree == NULL) {
643            result = xmlXPathNewCString("");
644        } else {
645            /*
646             * This is a result tree fragment.
647             */
648            xmlDocPtr container;
649            xmlNodePtr oldInsert;
650            xmlDocPtr  oldoutput;
651
652            container = xsltCreateRVT(ctxt);
653            if (container == NULL)
654                return(NULL);
655            /*
656             * Tag the subtree for removal once consumed
657             */
658            xsltRegisterTmpRVT(ctxt, container);
659            /*
660             * Save a pointer to the global variable for later cleanup
661             */
662            container->psvi = elem;
663            oldoutput = ctxt->output;
664            ctxt->output = container;
665            oldInsert = ctxt->insert;
666            ctxt->insert = (xmlNodePtr) container;
667            xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
668            ctxt->insert = oldInsert;
669            ctxt->output = oldoutput;
670
671            result = xmlXPathNewValueTree((xmlNodePtr) container);
672            if (result == NULL) {
673                result = xmlXPathNewCString("");
674            } else {
675                result->boolval = 0; /* Freeing is not handled there anymore */
676            }
677#ifdef WITH_XSLT_DEBUG_VARIABLE
678#ifdef LIBXML_DEBUG_ENABLED
679            if ((xsltGenericDebugContext == stdout) ||
680                (xsltGenericDebugContext == stderr))
681                xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
682                                        result, 0);
683#endif
684#endif
685        }
686    }
687    if (result != NULL) {
688        elem->value = result;
689        elem->computed = 1;
690    }
691    elem->name = name;
692    return(result);
693}
694
695/**
696 * xsltEvalGlobalVariables:
697 * @ctxt:  the XSLT transformation context
698 *
699 * Evaluate the global variables of a stylesheet. This need to be
700 * done on parsed stylesheets before starting to apply transformations
701 *
702 * Returns 0 in case of success, -1 in case of error
703 */
704int
705xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
706    xsltStackElemPtr elem;
707    xsltStylesheetPtr style;
708
709    if ((ctxt == NULL) || (ctxt->document == NULL))
710        return(-1);
711 
712#ifdef WITH_XSLT_DEBUG_VARIABLE
713    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
714        "Registering global variables\n"));
715#endif
716
717    ctxt->node = (xmlNodePtr) ctxt->document->doc;
718    ctxt->xpathCtxt->contextSize = 1;
719    ctxt->xpathCtxt->proximityPosition = 1;
720
721    /*
722     * Walk the list from the stylesheets and populate the hash table
723     */
724    style = ctxt->style;
725    while (style != NULL) {
726        elem = style->variables;
727       
728#ifdef WITH_XSLT_DEBUG_VARIABLE
729        if ((style->doc != NULL) && (style->doc->URL != NULL)) {
730            XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
731                             "Registering global variables from %s\n",
732                             style->doc->URL));
733        }
734#endif
735
736        while (elem != NULL) {
737            xsltStackElemPtr def;
738
739            /*
740             * Global variables are stored in the variables pool.
741             */
742            def = (xsltStackElemPtr)
743                    xmlHashLookup2(ctxt->globalVars,
744                                 elem->name, elem->nameURI);
745            if (def == NULL) {
746
747                def = xsltCopyStackElem(elem);
748                xmlHashAddEntry2(ctxt->globalVars,
749                                 elem->name, elem->nameURI, def);
750            } else if ((elem->comp != NULL) &&
751                       (elem->comp->type == XSLT_FUNC_VARIABLE)) {
752                /*
753                 * Redefinition of variables from a different stylesheet
754                 * should not generate a message.
755                 */
756                if ((elem->comp->inst != NULL) &&
757                    (def->comp != NULL) && (def->comp->inst != NULL) &&
758                    (elem->comp->inst->doc == def->comp->inst->doc)) {
759                    xsltTransformError(ctxt, style, elem->comp->inst,
760                        "Global variable %s already defined\n", elem->name);
761                    if (style != NULL) style->errors++;
762                }
763            }
764            elem = elem->next;
765        }
766
767        style = xsltNextImport(style);
768    }
769
770    /*
771     * This part does the actual evaluation
772     */
773    ctxt->node = (xmlNodePtr) ctxt->document->doc;
774    ctxt->xpathCtxt->contextSize = 1;
775    ctxt->xpathCtxt->proximityPosition = 1;
776    xmlHashScan(ctxt->globalVars,
777                (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
778
779    return(0);
780}
781
782/**
783 * xsltRegisterGlobalVariable:
784 * @style:  the XSLT transformation context
785 * @name:  the variable name
786 * @ns_uri:  the variable namespace URI
787 * @select:  the expression which need to be evaluated to generate a value
788 * @tree:  the subtree if select is NULL
789 * @comp:  the precompiled value
790 * @value:  the string value if available
791 *
792 * Register a new variable value. If @value is NULL it unregisters
793 * the variable
794 *
795 * Returns 0 in case of success, -1 in case of error
796 */
797static int
798xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
799                     const xmlChar *ns_uri, const xmlChar *select,
800                     xmlNodePtr tree, xsltStylePreCompPtr comp,
801                     const xmlChar *value) {
802    xsltStackElemPtr elem, tmp;
803    if (style == NULL)
804        return(-1);
805    if (name == NULL)
806        return(-1);
807    if (comp == NULL)
808        return(-1);
809
810#ifdef WITH_XSLT_DEBUG_VARIABLE
811    if (comp->type == XSLT_FUNC_PARAM)
812        xsltGenericDebug(xsltGenericDebugContext,
813                         "Defining global param %s\n", name);
814    else
815        xsltGenericDebug(xsltGenericDebugContext,
816                         "Defining global variable %s\n", name);
817#endif
818
819    elem = xsltNewStackElem();
820    if (elem == NULL)
821        return(-1);
822    elem->comp = comp;
823    elem->name = xmlDictLookup(style->dict, name, -1);
824    elem->select = xmlDictLookup(style->dict, select, -1);
825    if (ns_uri)
826        elem->nameURI = xmlStrdup(ns_uri);
827    elem->tree = tree;
828    tmp = style->variables;
829    if (tmp == NULL) {
830        elem->next = NULL;
831        style->variables = elem;
832    } else {
833        while (tmp != NULL) {
834            if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
835                (tmp->comp->type == XSLT_FUNC_VARIABLE) &&
836                (xmlStrEqual(elem->name, tmp->name)) &&
837                ((elem->nameURI == tmp->nameURI) ||
838                 (xmlStrEqual(elem->nameURI, tmp->nameURI)))) {
839                xsltTransformError(NULL, style, comp->inst,
840                "redefinition of global variable %s\n", elem->name);
841                if (style != NULL) style->errors++;
842            }
843            if (tmp->next == NULL)
844                break;
845            tmp = tmp->next;
846        }
847        elem->next = NULL;
848        tmp->next = elem;
849    }
850    if (value != NULL) {
851        elem->computed = 1;
852        elem->value = xmlXPathNewString(value);
853    }
854    return(0);
855}
856
857/**
858 * xsltProcessUserParamInternal
859 *
860 * @ctxt:  the XSLT transformation context
861 * @name:  a null terminated parameter name
862 * @value: a null terminated value (may be an XPath expression)
863 * @eval:  0 to treat the value literally, else evaluate as XPath expression
864 *
865 * If @eval is 0 then @value is treated literally and is stored in the global
866 * parameter/variable table without any change.
867 *
868 * Uf @eval is 1 then @value is treated as an XPath expression and is
869 * evaluated.  In this case, if you want to pass a string which will be
870 * interpreted literally then it must be enclosed in single or double quotes.
871 * If the string contains single quotes (double quotes) then it cannot be
872 * enclosed single quotes (double quotes).  If the string which you want to
873 * be treated literally contains both single and double quotes (e.g. Meet
874 * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
875 * quoting character.  You cannot use &apos; or &quot; inside the string
876 * because the replacement of character entities with their equivalents is
877 * done at a different stage of processing.  The solution is to call
878 * xsltQuoteUserParams or xsltQuoteOneUserParam.
879 *
880 * This needs to be done on parsed stylesheets before starting to apply
881 * transformations.  Normally this will be called (directly or indirectly)
882 * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
883 * or xsltQuoteOneUserParam.
884 *
885 * Returns 0 in case of success, -1 in case of error
886 */
887
888static
889int
890xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
891                             const xmlChar * name,
892                             const xmlChar * value,
893                             int eval) {
894
895    xsltStylesheetPtr style;
896    const xmlChar *prefix;
897    const xmlChar *href;
898    xmlXPathCompExprPtr comp;
899    xmlXPathObjectPtr result;
900    int oldProximityPosition;
901    int oldContextSize;
902    int oldNsNr;
903    xmlNsPtr *oldNamespaces;
904    xsltStackElemPtr elem;
905    int res;
906    void *res_ptr;
907
908    if (ctxt == NULL)
909        return(-1);
910    if (name == NULL)
911        return(0);
912    if (value == NULL)
913        return(0);
914
915    style = ctxt->style;
916
917#ifdef WITH_XSLT_DEBUG_VARIABLE
918    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
919            "Evaluating user parameter %s=%s\n", name, value));
920#endif
921
922    /*
923     * Name lookup
924     */
925
926    name = xsltSplitQName(ctxt->dict, name, &prefix);
927    href = NULL;
928    if (prefix != NULL) {
929        xmlNsPtr ns;
930
931        ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
932                         prefix);
933        if (ns == NULL) {
934            xsltTransformError(ctxt, style, NULL,
935            "user param : no namespace bound to prefix %s\n", prefix);
936            href = NULL;
937        } else {
938            href = ns->href;
939        }
940    }
941
942    if (name == NULL)
943        return (-1);
944
945    res_ptr = xmlHashLookup2(ctxt->globalVars, name, href);
946    if (res_ptr != 0) {
947        xsltTransformError(ctxt, style, NULL,
948            "Global parameter %s already defined\n", name);
949    }
950
951    /*
952     * do not overwrite variables with parameters from the command line
953     */
954    while (style != NULL) {
955        elem = ctxt->style->variables;
956        while (elem != NULL) {
957            if ((elem->comp != NULL) &&
958                (elem->comp->type == XSLT_FUNC_VARIABLE) &&
959                (xmlStrEqual(elem->name, name)) &&
960                (xmlStrEqual(elem->nameURI, href))) {
961                return(0);
962            }
963            elem = elem->next;
964        }
965        style = xsltNextImport(style);
966    }
967    style = ctxt->style;
968    elem = NULL;
969
970    /*
971     * Do the evaluation if @eval is non-zero.
972     */
973
974    result = NULL;
975    if (eval != 0) {
976        comp = xmlXPathCompile(value);
977        if (comp != NULL) {
978            oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
979            oldContextSize = ctxt->xpathCtxt->contextSize;
980            ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
981
982            /*
983             * There is really no in scope namespace for parameters on the
984             * command line.
985             */
986
987            oldNsNr = ctxt->xpathCtxt->nsNr;
988            oldNamespaces = ctxt->xpathCtxt->namespaces;
989            ctxt->xpathCtxt->namespaces = NULL;
990            ctxt->xpathCtxt->nsNr = 0;
991            result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
992            ctxt->xpathCtxt->contextSize = oldContextSize;
993            ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
994            ctxt->xpathCtxt->nsNr = oldNsNr;
995            ctxt->xpathCtxt->namespaces = oldNamespaces;
996            xmlXPathFreeCompExpr(comp);
997        }
998        if (result == NULL) {
999            xsltTransformError(ctxt, style, NULL,
1000                "Evaluating user parameter %s failed\n", name);
1001            ctxt->state = XSLT_STATE_STOPPED;
1002            return(-1);
1003        }
1004    }
1005
1006    /*
1007     * If @eval is 0 then @value is to be taken literally and result is NULL
1008     *
1009     * If @eval is not 0, then @value is an XPath expression and has been
1010     * successfully evaluated and result contains the resulting value and
1011     * is not NULL.
1012     *
1013     * Now create an xsltStackElemPtr for insertion into the context's
1014     * global variable/parameter hash table.
1015     */
1016
1017#ifdef WITH_XSLT_DEBUG_VARIABLE
1018#ifdef LIBXML_DEBUG_ENABLED
1019    if ((xsltGenericDebugContext == stdout) ||
1020        (xsltGenericDebugContext == stderr))
1021            xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
1022                                    result, 0);
1023#endif
1024#endif
1025
1026    elem = xsltNewStackElem();
1027    if (elem != NULL) {
1028        elem->name = name;
1029        if (value != NULL)
1030            elem->select = xmlDictLookup(ctxt->dict, value, -1);
1031        else
1032            elem->select = NULL;
1033        if (href)
1034            elem->nameURI = xmlDictLookup(ctxt->dict, href, -1);
1035        elem->tree = NULL;
1036        elem->computed = 1;
1037        if (eval == 0) {
1038            elem->value = xmlXPathNewString(value);
1039        }
1040        else {
1041            elem->value = result;
1042        }
1043    }
1044
1045    /*
1046     * Global parameters are stored in the XPath context variables pool.
1047     */
1048
1049    res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem);
1050    if (res != 0) {
1051        xsltFreeStackElem(elem);
1052        xsltTransformError(ctxt, style, NULL,
1053            "Global parameter %s already defined\n", name);
1054    }
1055    return(0);
1056}
1057
1058/**
1059 * xsltEvalUserParams:
1060 *
1061 * @ctxt:  the XSLT transformation context
1062 * @params:  a NULL terminated array of parameters name/value tuples
1063 *
1064 * Evaluate the global variables of a stylesheet. This needs to be
1065 * done on parsed stylesheets before starting to apply transformations.
1066 * Each of the parameters is evaluated as an XPath expression and stored
1067 * in the global variables/parameter hash table.  If you want your
1068 * parameter used literally, use xsltQuoteUserParams.
1069 *
1070 * Returns 0 in case of success, -1 in case of error
1071 */
1072 
1073int
1074xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
1075    int indx = 0;
1076    const xmlChar *name;
1077    const xmlChar *value;
1078
1079    if (params == NULL)
1080        return(0);
1081    while (params[indx] != NULL) {
1082        name = (const xmlChar *) params[indx++];
1083        value = (const xmlChar *) params[indx++];
1084        if (xsltEvalOneUserParam(ctxt, name, value) != 0)
1085            return(-1);
1086    }
1087    return 0;
1088}
1089
1090/**
1091 * xsltQuoteUserParams:
1092 *
1093 * @ctxt:  the XSLT transformation context
1094 * @params:  a NULL terminated arry of parameters names/values tuples
1095 *
1096 * Similar to xsltEvalUserParams, but the values are treated literally and
1097 * are * *not* evaluated as XPath expressions. This should be done on parsed
1098 * stylesheets before starting to apply transformations.
1099 *
1100 * Returns 0 in case of success, -1 in case of error.
1101 */
1102 
1103int
1104xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
1105    int indx = 0;
1106    const xmlChar *name;
1107    const xmlChar *value;
1108
1109    if (params == NULL)
1110        return(0);
1111    while (params[indx] != NULL) {
1112        name = (const xmlChar *) params[indx++];
1113        value = (const xmlChar *) params[indx++];
1114        if (xsltQuoteOneUserParam(ctxt, name, value) != 0)
1115            return(-1);
1116    }
1117    return 0;
1118}
1119
1120/**
1121 * xsltEvalOneUserParam:
1122 * @ctxt:  the XSLT transformation context
1123 * @name:  a null terminated string giving the name of the parameter
1124 * @value:  a null terminated string giving the XPath expression to be evaluated
1125 *
1126 * This is normally called from xsltEvalUserParams to process a single
1127 * parameter from a list of parameters.  The @value is evaluated as an
1128 * XPath expression and the result is stored in the context's global
1129 * variable/parameter hash table.
1130 *
1131 * To have a parameter treated literally (not as an XPath expression)
1132 * use xsltQuoteUserParams (or xsltQuoteOneUserParam).  For more
1133 * details see description of xsltProcessOneUserParamInternal.
1134 *
1135 * Returns 0 in case of success, -1 in case of error.
1136 */
1137
1138int
1139xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
1140                     const xmlChar * name,
1141                     const xmlChar * value) {
1142    return xsltProcessUserParamInternal(ctxt, name, value,
1143                                        1 /* xpath eval ? */);
1144}
1145
1146/**
1147 * xsltQuoteOneUserParam:
1148 * @ctxt:  the XSLT transformation context
1149 * @name:  a null terminated string giving the name of the parameter
1150 * @value:  a null terminated string giving the parameter value
1151 *
1152 * This is normally called from xsltQuoteUserParams to process a single
1153 * parameter from a list of parameters.  The @value is stored in the
1154 * context's global variable/parameter hash table.
1155 *
1156 * Returns 0 in case of success, -1 in case of error.
1157 */
1158
1159int
1160xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
1161                         const xmlChar * name,
1162                         const xmlChar * value) {
1163    return xsltProcessUserParamInternal(ctxt, name, value,
1164                                        0 /* xpath eval ? */);
1165}
1166
1167/**
1168 * xsltBuildVariable:
1169 * @ctxt:  the XSLT transformation context
1170 * @comp:  the precompiled form
1171 * @tree:  the tree if select is NULL
1172 *
1173 * Computes a new variable value.
1174 *
1175 * Returns the xsltStackElemPtr or NULL in case of error
1176 */
1177static xsltStackElemPtr
1178xsltBuildVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1179                  xmlNodePtr tree) {
1180    xsltStackElemPtr elem;
1181
1182#ifdef WITH_XSLT_DEBUG_VARIABLE
1183    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1184                     "Building variable %s", comp->name));
1185    if (comp->select != NULL)
1186        XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1187                         " select %s", comp->select));
1188    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n"));
1189#endif
1190
1191    elem = xsltNewStackElem();
1192    if (elem == NULL)
1193        return(NULL);
1194    elem->comp = comp;
1195    elem->name = comp->name;
1196    if (comp->select != NULL)
1197        elem->select = comp->select;
1198    else
1199        elem->select = NULL;
1200    if (comp->ns)
1201        elem->nameURI = comp->ns;
1202    elem->tree = tree;
1203    if (elem->computed == 0) {
1204        elem->value = xsltEvalVariable(ctxt, elem, comp);
1205        if (elem->value != NULL)
1206            elem->computed = 1;
1207    }
1208    return(elem);
1209}
1210
1211/**
1212 * xsltRegisterVariable:
1213 * @ctxt:  the XSLT transformation context
1214 * @comp:  pointer to precompiled data
1215 * @tree:  the tree if select is NULL
1216 * @param:  this is a parameter actually
1217 *
1218 * Computes and register a new variable value.
1219 *
1220 * Returns 0 in case of success, -1 in case of error
1221 */
1222static int
1223xsltRegisterVariable(xsltTransformContextPtr ctxt, xsltStylePreCompPtr comp,
1224                     xmlNodePtr tree, int param) {
1225    xsltStackElemPtr elem;
1226    int present;
1227
1228    present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
1229    if (param == 0) {
1230        if ((present != 0) && (present != 3)) {
1231            xsltTransformError(ctxt, NULL, comp->inst,
1232                "xsl:variable : redefining %s\n", comp->name);
1233            return(0);
1234        }
1235    } else if (present != 0) {
1236        if ((present == 1) || (present == 2)) {
1237            xsltTransformError(ctxt, NULL, comp->inst,
1238                "xsl:param : redefining %s\n", comp->name);
1239            return(0);
1240        }
1241#ifdef WITH_XSLT_DEBUG_VARIABLE
1242        XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1243                 "param %s defined by caller\n", comp->name));
1244#endif
1245        return(0);
1246    }
1247    elem = xsltBuildVariable(ctxt, comp, tree);
1248    xsltAddStackElem(ctxt, elem);
1249    return(0);
1250}
1251
1252/**
1253 * xsltGlobalVariableLookup:
1254 * @ctxt:  the XSLT transformation context
1255 * @name:  the variable name
1256 * @ns_uri:  the variable namespace URI
1257 *
1258 * Search in the Variable array of the context for the given
1259 * variable value.
1260 *
1261 * Returns the value or NULL if not found
1262 */
1263static xmlXPathObjectPtr
1264xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1265                         const xmlChar *ns_uri) {
1266    xsltStackElemPtr elem;
1267    xmlXPathObjectPtr ret = NULL;
1268
1269    /*
1270     * Lookup the global variables in XPath global variable hash table
1271     */
1272    if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
1273        return(NULL);
1274    elem = (xsltStackElemPtr)
1275            xmlHashLookup2(ctxt->globalVars, name, ns_uri);
1276    if (elem == NULL) {
1277#ifdef WITH_XSLT_DEBUG_VARIABLE
1278        XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1279                         "global variable not found %s\n", name));
1280#endif
1281        return(NULL);
1282    }
1283    if (elem->computed == 0) {
1284        if (xmlStrEqual(elem->name, BAD_CAST "  being computed ... ")) {
1285            xsltTransformError(ctxt, NULL, elem->comp->inst,
1286                "Recursive definition of %s\n", name);
1287            return(NULL);
1288        }
1289        ret = xsltEvalGlobalVariable(elem, ctxt);
1290    } else
1291        ret = elem->value;
1292    return(xmlXPathObjectCopy(ret));
1293}
1294
1295/**
1296 * xsltVariableLookup:
1297 * @ctxt:  the XSLT transformation context
1298 * @name:  the variable name
1299 * @ns_uri:  the variable namespace URI
1300 *
1301 * Search in the Variable array of the context for the given
1302 * variable value.
1303 *
1304 * Returns the value or NULL if not found
1305 */
1306xmlXPathObjectPtr
1307xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
1308                   const xmlChar *ns_uri) {
1309    xsltStackElemPtr elem;
1310
1311    if (ctxt == NULL)
1312        return(NULL);
1313
1314    elem = xsltStackLookup(ctxt, name, ns_uri);
1315    if (elem == NULL) {
1316        return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
1317    }
1318    if (elem->computed == 0) {
1319#ifdef WITH_XSLT_DEBUG_VARIABLE
1320        XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1321                         "uncomputed variable %s\n", name));
1322#endif
1323        elem->value = xsltEvalVariable(ctxt, elem, NULL);
1324        elem->computed = 1;
1325    }
1326    if (elem->value != NULL)
1327        return(xmlXPathObjectCopy(elem->value));
1328#ifdef WITH_XSLT_DEBUG_VARIABLE
1329    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1330                     "variable not found %s\n", name));
1331#endif
1332    return(NULL);
1333}
1334
1335/**
1336 * xsltParseStylesheetCallerParam:
1337 * @ctxt:  the XSLT transformation context
1338 * @cur:  the "param" element
1339 *
1340 * parse an XSLT transformation param declaration, compute
1341 * its value but doesn't record it.
1342 *
1343 * Returns the new xsltStackElemPtr or NULL
1344 */
1345
1346xsltStackElemPtr
1347xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1348    xmlNodePtr tree = NULL;
1349    xsltStackElemPtr elem = NULL;
1350    xsltStylePreCompPtr comp;
1351
1352    if ((cur == NULL) || (ctxt == NULL))
1353        return(NULL);
1354    comp = (xsltStylePreCompPtr) cur->psvi;
1355    if (comp == NULL) {
1356        xsltTransformError(ctxt, NULL, cur,
1357            "xsl:param : compilation error\n");
1358        return(NULL);
1359    }
1360
1361    if (comp->name == NULL) {
1362        xsltTransformError(ctxt, NULL, cur,
1363            "xsl:param : missing name attribute\n");
1364        return(NULL);
1365    }
1366
1367#ifdef WITH_XSLT_DEBUG_VARIABLE
1368    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1369            "Handling param %s\n", comp->name));
1370#endif
1371
1372    if (comp->select == NULL) {
1373        tree = cur->children;
1374    } else {
1375#ifdef WITH_XSLT_DEBUG_VARIABLE
1376        XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1377            "        select %s\n", comp->select));
1378#endif
1379        tree = cur;
1380    }
1381
1382    elem = xsltBuildVariable(ctxt, comp, tree);
1383
1384    return(elem);
1385}
1386
1387/**
1388 * xsltParseGlobalVariable:
1389 * @style:  the XSLT stylesheet
1390 * @cur:  the "variable" element
1391 *
1392 * parse an XSLT transformation variable declaration and record
1393 * its value.
1394 */
1395
1396void
1397xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
1398    xsltStylePreCompPtr comp;
1399
1400    if ((cur == NULL) || (style == NULL))
1401        return;
1402
1403    xsltStylePreCompute(style, cur);
1404    comp = (xsltStylePreCompPtr) cur->psvi;
1405    if (comp == NULL) {
1406        xsltTransformError(NULL, style, cur,
1407             "xsl:variable : compilation failed\n");
1408        return;
1409    }
1410
1411    if (comp->name == NULL) {
1412        xsltTransformError(NULL, style, cur,
1413            "xsl:variable : missing name attribute\n");
1414        return;
1415    }
1416
1417    if (cur->children != NULL) {
1418        xsltParseTemplateContent(style, cur);
1419    }
1420#ifdef WITH_XSLT_DEBUG_VARIABLE
1421    xsltGenericDebug(xsltGenericDebugContext,
1422        "Registering global variable %s\n", comp->name);
1423#endif
1424
1425    xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1426                               cur->children, comp, NULL);
1427}
1428
1429/**
1430 * xsltParseGlobalParam:
1431 * @style:  the XSLT stylesheet
1432 * @cur:  the "param" element
1433 *
1434 * parse an XSLT transformation param declaration and record
1435 * its value.
1436 */
1437
1438void
1439xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
1440    xsltStylePreCompPtr comp;
1441
1442    if ((cur == NULL) || (style == NULL))
1443        return;
1444
1445    xsltStylePreCompute(style, cur);
1446    comp = (xsltStylePreCompPtr) cur->psvi;
1447    if (comp == NULL) {
1448        xsltTransformError(NULL, style, cur,
1449             "xsl:param : compilation failed\n");
1450        return;
1451    }
1452
1453    if (comp->name == NULL) {
1454        xsltTransformError(NULL, style, cur,
1455            "xsl:param : missing name attribute\n");
1456        return;
1457    }
1458
1459    if (cur->children != NULL) {
1460        xsltParseTemplateContent(style, cur);
1461    }
1462
1463#ifdef WITH_XSLT_DEBUG_VARIABLE
1464    xsltGenericDebug(xsltGenericDebugContext,
1465        "Registering global param %s\n", comp->name);
1466#endif
1467
1468    xsltRegisterGlobalVariable(style, comp->name, comp->ns, comp->select,
1469                               cur->children, comp, NULL);
1470}
1471
1472/**
1473 * xsltParseStylesheetVariable:
1474 * @ctxt:  the XSLT transformation context
1475 * @cur:  the "variable" element
1476 *
1477 * parse an XSLT transformation variable declaration and record
1478 * its value.
1479 */
1480
1481void
1482xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1483    xsltStylePreCompPtr comp;
1484
1485    if ((cur == NULL) || (ctxt == NULL))
1486        return;
1487
1488    comp = (xsltStylePreCompPtr) cur->psvi;
1489    if (comp == NULL) {
1490        xsltTransformError(ctxt, NULL, cur,
1491             "xsl:variable : compilation failed\n");
1492        return;
1493    }
1494
1495    if (comp->name == NULL) {
1496        xsltTransformError(ctxt, NULL, cur,
1497            "xsl:variable : missing name attribute\n");
1498        return;
1499    }
1500
1501#ifdef WITH_XSLT_DEBUG_VARIABLE
1502    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1503        "Registering variable %s\n", comp->name));
1504#endif
1505
1506    xsltRegisterVariable(ctxt, comp, cur->children, 0);
1507}
1508
1509/**
1510 * xsltParseStylesheetParam:
1511 * @ctxt:  the XSLT transformation context
1512 * @cur:  the "param" element
1513 *
1514 * parse an XSLT transformation param declaration and record
1515 * its value.
1516 */
1517
1518void
1519xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
1520    xsltStylePreCompPtr comp;
1521
1522    if ((cur == NULL) || (ctxt == NULL))
1523        return;
1524
1525    comp = (xsltStylePreCompPtr) cur->psvi;
1526    if (comp == NULL) {
1527        xsltTransformError(ctxt, NULL, cur,
1528             "xsl:param : compilation failed\n");
1529        return;
1530    }
1531
1532    if (comp->name == NULL) {
1533        xsltTransformError(ctxt, NULL, cur,
1534            "xsl:param : missing name attribute\n");
1535        return;
1536    }
1537
1538#ifdef WITH_XSLT_DEBUG_VARIABLE
1539    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1540        "Registering param %s\n", comp->name));
1541#endif
1542
1543    xsltRegisterVariable(ctxt, comp, cur->children, 1);
1544}
1545
1546/**
1547 * xsltFreeGlobalVariables:
1548 * @ctxt:  the XSLT transformation context
1549 *
1550 * Free up the data associated to the global variables
1551 * its value.
1552 */
1553
1554void
1555xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
1556    xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
1557}
1558
1559/**
1560 * xsltXPathVariableLookup:
1561 * @ctxt:  a void * but the the XSLT transformation context actually
1562 * @name:  the variable name
1563 * @ns_uri:  the variable namespace URI
1564 *
1565 * This is the entry point when a varibale is needed by the XPath
1566 * interpretor.
1567 *
1568 * Returns the value or NULL if not found
1569 */
1570xmlXPathObjectPtr
1571xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
1572                        const xmlChar *ns_uri) {
1573    xsltTransformContextPtr context;
1574    xmlXPathObjectPtr ret;
1575
1576    if ((ctxt == NULL) || (name == NULL))
1577        return(NULL);
1578
1579#ifdef WITH_XSLT_DEBUG_VARIABLE
1580    XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1581            "Lookup variable %s\n", name));
1582#endif
1583    context = (xsltTransformContextPtr) ctxt;
1584    ret = xsltVariableLookup(context, name, ns_uri);
1585    if (ret == NULL) {
1586        xsltTransformError(ctxt, NULL, NULL,
1587            "unregistered variable %s\n", name);
1588    }
1589#ifdef WITH_XSLT_DEBUG_VARIABLE
1590    if (ret != NULL)
1591        XSLT_TRACE(context,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
1592            "found variable %s\n", name));
1593#endif
1594    return(ret);
1595}
1596
1597
Note: See TracBrowser for help on using the repository browser.