Implementation of stylesheet parameter passing:
[platform/upstream/libxslt.git] / libxslt / variables.c
1 /*
2  * variables.c: Implementation of the variable storage and lookup
3  *
4  * Reference:
5  *   http://www.w3.org/TR/1999/REC-xslt-19991116
6  *
7  * See Copyright for the status of this software.
8  *
9  * Daniel.Veillard@imag.fr
10  */
11
12 #include "xsltconfig.h"
13
14 #include <string.h>
15
16 #include <libxml/xmlmemory.h>
17 #include <libxml/tree.h>
18 #include <libxml/valid.h>
19 #include <libxml/hash.h>
20 #include <libxml/xmlerror.h>
21 #include <libxml/xpath.h>
22 #include <libxml/xpathInternals.h>
23 #include <libxml/parserInternals.h>
24 #include <libxml/xmlversion.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
32 #define DEBUG_VARIABLE
33
34 /************************************************************************
35  *                                                                      *
36  *                      Module interfaces                               *
37  *                                                                      *
38  ************************************************************************/
39
40 /**
41  * xsltNewStackElem:
42  *
43  * Create a new XSLT ParserContext
44  *
45  * Returns the newly allocated xsltParserStackElem or NULL in case of error
46  */
47 static xsltStackElemPtr
48 xsltNewStackElem(void) {
49     xsltStackElemPtr cur;
50
51     cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
52     if (cur == NULL) {
53         xsltGenericError(xsltGenericErrorContext,
54                 "xsltNewStackElem : malloc failed\n");
55         return(NULL);
56     }
57     memset(cur, 0, sizeof(xsltStackElem));
58     cur->computed = 0;
59     return(cur);
60 }
61
62 /**
63  * xsltFreeStackElem:
64  * @elem:  an XSLT stack element
65  *
66  * Free up the memory allocated by @elem
67  */
68 static void
69 xsltFreeStackElem(xsltStackElemPtr elem) {
70     if (elem == NULL)
71         return;
72     if (elem->name != NULL)
73         xmlFree(elem->name);
74     if (elem->nameURI != NULL)
75         xmlFree(elem->nameURI);
76     if (elem->select != NULL)
77         xmlFree(elem->select);
78     if (elem->value != NULL)
79         xmlXPathFreeObject(elem->value);
80
81     memset(elem, -1, sizeof(xsltStackElem));
82     xmlFree(elem);
83 }
84
85 /**
86  * xsltFreeStackElemList:
87  * @elem:  an XSLT stack element
88  *
89  * Free up the memory allocated by @elem
90  */
91 void
92 xsltFreeStackElemList(xsltStackElemPtr elem) {
93     xsltStackElemPtr next;
94
95     while(elem != NULL) {
96         next = elem->next;
97         xsltFreeStackElem(elem);
98         elem = next;
99     }
100 }
101
102 /**
103  * xsltCheckStackElem:
104  * @ctxt:  xn XSLT transformation context
105  * @name:  the variable name
106  * @nameURI:  the variable namespace URI
107  *
108  * check wether the variable or param is already defined
109  *
110  * Returns 1 if present, 0 if not, -1 in case of failure.
111  */
112 static int
113 xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
114                    const xmlChar *nameURI) {
115     xsltStackElemPtr cur;
116
117     if ((ctxt == NULL) || (name == NULL))
118         return(-1);
119
120     cur = ctxt->vars;
121     while (cur != NULL) {
122         if (xmlStrEqual(name, cur->name)) {
123             if (((nameURI == NULL) && (cur->nameURI == NULL)) ||
124                 ((nameURI != NULL) && (cur->nameURI != NULL) &&
125                  (xmlStrEqual(nameURI, cur->nameURI)))) {
126                 return(1);
127             }
128         }
129         cur = cur->next;
130     }
131     return(0);
132 }
133
134 /**
135  * xsltAddStackElem:
136  * @ctxt:  xn XSLT transformation context
137  * @elem:  a stack element
138  *
139  * add a new element at this level of the stack.
140  *
141  * Returns 0 in case of success, -1 in case of failure.
142  */
143 static int
144 xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
145     if ((ctxt == NULL) || (elem == NULL))
146         return(-1);
147
148     elem->next = ctxt->varsTab[ctxt->varsNr - 1];
149     ctxt->varsTab[ctxt->varsNr - 1] = elem;
150     ctxt->vars = elem;
151     return(0);
152 }
153
154 /**
155  * xsltAddStackElemList:
156  * @ctxt:  xn XSLT transformation context
157  * @elems:  a stack element list
158  *
159  * add the new element list at this level of the stack.
160  *
161  * Returns 0 in case of success, -1 in case of failure.
162  */
163 int
164 xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) {
165     xsltStackElemPtr cur;
166
167     if ((ctxt == NULL) || (elems == NULL))
168         return(-1);
169
170     /* TODO: check doublons */
171     if (ctxt->varsTab[ctxt->varsNr - 1] != NULL) {
172         cur = ctxt->varsTab[ctxt->varsNr - 1];
173         while (cur->next != NULL)
174             cur = cur->next;
175         cur->next = elems;
176     } else {
177         elems->next = ctxt->varsTab[ctxt->varsNr - 1];
178         ctxt->varsTab[ctxt->varsNr - 1] = elems;
179         ctxt->vars = elems;
180     }
181     return(0);
182 }
183
184 /**
185  * xsltStackLookup:
186  * @ctxt:  an XSLT transformation context
187  * @name:  the local part of the name
188  * @nameURI:  the URI part of the name
189  *
190  * Locate an element in the stack based on its name.
191  */
192 static xsltStackElemPtr
193 xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
194                 const xmlChar *nameURI) {
195     xsltStackElemPtr ret = NULL;
196     int i;
197     xsltStackElemPtr cur;
198
199     if ((ctxt == NULL) || (name == NULL))
200         return(NULL);
201
202     /*
203      * Do the lookup from the top of the stack, but
204      * don't use params being computed in a call-param
205      */
206     i = ctxt->varsNr - 1;
207
208     for (;i >= 0;i--) {
209         cur = ctxt->varsTab[i];
210         while (cur != NULL) {
211             if (xmlStrEqual(cur->name, name)) {
212                 if (nameURI == NULL) {
213                     if (cur->nameURI == NULL) {
214                         return(cur);
215                     }
216                 } else {
217                     if ((cur->nameURI != NULL) &&
218                         (xmlStrEqual(cur->nameURI, nameURI))) {
219                         return(cur);
220                     }
221                 }
222
223             }
224             cur = cur->next;
225         }
226     }
227     return(ret);
228 }
229
230 /************************************************************************
231  *                                                                      *
232  *                      Module interfaces                               *
233  *                                                                      *
234  ************************************************************************/
235
236 /**
237  * xsltEvalVariable:
238  * @ctxt:  the XSLT transformation context
239  * @elem:  the variable or parameter.
240  *
241  * Evaluate a variable value.
242  *
243  * Returns 0 in case of success, -1 in case of error
244  */
245 static int
246 xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
247     if ((ctxt == NULL) || (elem == NULL))
248         return(-1);
249
250 #ifdef DEBUG_VARIABLE
251     xsltGenericDebug(xsltGenericDebugContext,
252         "Evaluating variable %s\n", elem->name);
253 #endif
254     if (elem->select != NULL) {
255         xmlXPathCompExprPtr comp;
256         xmlXPathObjectPtr result;
257
258         comp = xmlXPathCompile(elem->select);
259         if (comp == NULL)
260             return(-1);
261         ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
262         result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
263         xmlXPathFreeCompExpr(comp);
264         if (result == NULL) {
265             xsltGenericError(xsltGenericErrorContext,
266                 "Evaluating global variable %s failed\n");
267         } else {
268 #ifdef DEBUG_VARIABLE
269 #ifdef LIBXML_DEBUG_ENABLED
270             if ((xsltGenericDebugContext == stdout) ||
271                 (xsltGenericDebugContext == stderr))
272                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
273                                         result, 0);
274 #endif
275 #endif
276             if (elem->value != NULL)
277                 xmlXPathFreeObject(elem->value);
278             elem->value = result;
279         }
280         elem->computed = 1;
281     } else {
282         if (elem->tree == NULL) {
283             elem->value = xmlXPathNewCString("");
284         } else {
285             /*
286              * This is a result tree fragment.
287              */
288             xmlNodePtr container;
289             xmlNodePtr oldInsert, oldNode;
290
291             container = xmlNewDocNode(ctxt->output, NULL,
292                                       (const xmlChar *) "fake", NULL);
293             if (container == NULL)
294                 return(-1);
295
296             oldInsert = ctxt->insert;
297             oldNode = ctxt->node;
298             ctxt->insert = container;
299             xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, 0);
300             ctxt->insert = oldInsert;
301             ctxt->node = oldNode;
302
303             if (elem->value != NULL)
304                 xmlXPathFreeObject(elem->value);
305             elem->value = xmlXPathNewValueTree(container);
306             if (elem->value == NULL) {
307                 elem->value = xmlXPathNewCString("");
308             }
309 #ifdef DEBUG_VARIABLE
310 #ifdef LIBXML_DEBUG_ENABLED
311             if ((xsltGenericDebugContext == stdout) ||
312                 (xsltGenericDebugContext == stderr))
313                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
314                                         elem->value, 0);
315 #endif
316 #endif
317         }
318         elem->computed = 1;
319     }
320     return(0);
321 }
322
323 /**
324  * xsltEvalGlobalVariables:
325  * @ctxt:  the XSLT transformation context
326  *
327  * Evaluate the global variables of a stylesheet. This need to be
328  * done on parsed stylesheets before starting to apply transformations
329  *
330  * Returns 0 in case of success, -1 in case of error
331  */
332 int
333 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
334     xsltStackElemPtr elem;
335     xsltStylesheetPtr style;
336
337     if (ctxt == NULL)
338         return(-1);
339  
340 #ifdef DEBUG_VARIABLE
341     xsltGenericDebug(xsltGenericDebugContext,
342         "Evaluating global variables\n");
343 #endif
344     ctxt->node = (xmlNodePtr) ctxt->document->doc;
345     style = ctxt->style;
346     while (style != NULL) {
347         elem = style->variables;
348         
349         while (elem != NULL) {
350             if (elem->computed == 0)
351                 xsltEvalVariable(ctxt, elem);
352             elem = elem->next;
353         }
354
355         style = xsltNextImport(style);
356     }
357     return(0);
358 }
359
360 /**
361  * xsltRegisterGlobalVariable:
362  * @style:  the XSLT transformation context
363  * @name:  the variable name
364  * @ns_uri:  the variable namespace URI
365  * @select:  the expression which need to be evaluated to generate a value
366  * @tree:  the subtree if select is NULL
367  * @param:  this is a parameter actually
368  * @value:  the string value if available
369  *
370  * Register a new variable value. If @value is NULL it unregisters
371  * the variable
372  *
373  * Returns 0 in case of success, -1 in case of error
374  */
375 static int
376 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
377                      const xmlChar *ns_uri, const xmlChar *select,
378                      xmlNodePtr tree, int param, const xmlChar *value) {
379     xsltStackElemPtr elem;
380     if (style == NULL)
381         return(-1);
382     if (name == NULL)
383         return(-1);
384
385 #ifdef DEBUG_VARIABLE
386     if (param)
387         xsltGenericDebug(xsltGenericDebugContext,
388                          "Defineing global param %s\n", name);
389     else
390         xsltGenericDebug(xsltGenericDebugContext,
391                          "Defineing global variable %s\n", name);
392 #endif
393     elem = xsltNewStackElem();
394     if (elem == NULL)
395         return(-1);
396     if (param)
397         elem->type = XSLT_ELEM_PARAM;
398     else
399         elem->type = XSLT_ELEM_VARIABLE;
400     elem->name = xmlStrdup(name);
401     elem->select = xmlStrdup(select);
402     if (ns_uri)
403         elem->nameURI = xmlStrdup(ns_uri);
404     elem->tree = tree;
405     elem->next = style->variables;
406     style->variables = elem;
407     if (value != NULL) {
408         elem->computed = 1;
409         elem->value = xmlXPathNewString(value);
410     }
411     return(0);
412 }
413
414 /**
415  * xsltEvalUserParams:
416  * @ctxt:  the XSLT transformation context
417  * @params:  a NULL terminated arry of parameters names/values tuples
418  *
419  * Evaluate the global variables of a stylesheet. This need to be
420  * done on parsed stylesheets before starting to apply transformations
421  *
422  * Returns 0 in case of success, -1 in case of error
423  */
424 int
425 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
426     xsltStylesheetPtr style;
427     int indx = 0;
428     const xmlChar *name;
429     const xmlChar *value;
430     xmlChar *ncname, *prefix;
431
432     if (ctxt == NULL)
433         return(-1);
434     if (params == NULL)
435         return(0);
436  
437     style = ctxt->style;
438     while (params[indx] != NULL) {
439         name = (const xmlChar *)params[indx++];
440         value = (const xmlChar *)params[indx++];
441         if ((name == NULL) || (value == NULL))
442             break;
443
444 #ifdef DEBUG_VARIABLE
445         xsltGenericDebug(xsltGenericDebugContext,
446             "Evaluating user parameter %s=%s\n", name, value);
447 #endif
448         ncname = xmlSplitQName2(name, &prefix);
449         if (ncname != NULL) {
450             if (prefix != NULL) {
451                 xmlNsPtr ns;
452
453                 ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
454                                  prefix);
455                 if (ns == NULL) {
456                     xsltGenericError(xsltGenericErrorContext,
457                         "user param : no namespace bound to prefix %s\n", prefix);
458                 } else {
459                     xsltRegisterGlobalVariable(style, ncname, ns->href, NULL,
460                                                NULL, 1, value);
461                 }
462                 xmlFree(prefix);
463             } else {
464                 xsltRegisterGlobalVariable(style, ncname, NULL, NULL, NULL,
465                                            1, value);
466             }
467             xmlFree(ncname);
468         } else {
469             xsltRegisterGlobalVariable(style, name, NULL, NULL, NULL, 1, value);
470         }
471
472     }
473
474     return(0);
475 }
476
477 /**
478  * xsltBuildVariable:
479  * @ctxt:  the XSLT transformation context
480  * @name:  the variable name
481  * @ns_uri:  the variable namespace URI
482  * @select:  the expression which need to be evaluated to generate a value
483  * @tree:  the tree if select is NULL
484  * @param:  this is a parameter actually
485  *
486  * Computes a new variable value.
487  *
488  * Returns the xsltStackElemPtr or NULL in case of error
489  */
490 static xsltStackElemPtr
491 xsltBuildVariable(xsltTransformContextPtr ctxt, const xmlChar *name,
492                      const xmlChar *ns_uri, const xmlChar *select,
493                      xmlNodePtr tree, int param) {
494     xsltStackElemPtr elem;
495     if (ctxt == NULL)
496         return(NULL);
497     if (name == NULL)
498         return(NULL);
499
500 #ifdef DEBUG_VARIABLE
501     xsltGenericDebug(xsltGenericDebugContext,
502                      "Building variable %s", name);
503     if (select != NULL)
504         xsltGenericDebug(xsltGenericDebugContext,
505                          " select %s",  select);
506     xsltGenericDebug(xsltGenericDebugContext, "\n");
507 #endif
508     elem = xsltNewStackElem();
509     if (elem == NULL)
510         return(NULL);
511     if (param)
512         elem->type = XSLT_ELEM_PARAM;
513     else
514         elem->type = XSLT_ELEM_VARIABLE;
515     elem->name = xmlStrdup(name);
516     if (select != NULL)
517         elem->select = xmlStrdup(select);
518     else
519         elem->select = NULL;
520     if (ns_uri)
521         elem->nameURI = xmlStrdup(ns_uri);
522     elem->tree = tree;
523     xsltEvalVariable(ctxt, elem);
524     return(elem);
525 }
526
527 /**
528  * xsltRegisterVariable:
529  * @ctxt:  the XSLT transformation context
530  * @name:  the variable name
531  * @ns_uri:  the variable namespace URI
532  * @select:  the expression which need to be evaluated to generate a value
533  * @tree:  the tree if select is NULL
534  * @param:  this is a parameter actually
535  *
536  * Computes and register a new variable value. 
537  *
538  * Returns 0 in case of success, -1 in case of error
539  */
540 int
541 xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name,
542                      const xmlChar *ns_uri, const xmlChar *select,
543                      xmlNodePtr tree, int param) {
544     xsltStackElemPtr elem;
545     if (ctxt == NULL)
546         return(-1);
547     if (name == NULL)
548         return(-1);
549
550     if (xsltCheckStackElem(ctxt, name, ns_uri) != 0) {
551         if (!param) {
552             xsltGenericError(xsltGenericErrorContext,
553             "xsl:variable : redefining %s\n", name);
554         }
555 #ifdef DEBUG_VARIABLE
556         else
557             xsltGenericDebug(xsltGenericDebugContext,
558                      "param %s defined by caller", name);
559 #endif
560         return(0);
561     }
562     elem = xsltBuildVariable(ctxt, name, ns_uri, select, tree, param);
563     xsltAddStackElem(ctxt, elem);
564     return(0);
565 }
566
567 /**
568  * xsltGlobalVariableLookup:
569  * @ctxt:  the XSLT transformation context
570  * @name:  the variable name
571  * @ns_uri:  the variable namespace URI
572  *
573  * Search in the Variable array of the context for the given
574  * variable value.
575  *
576  * Returns the value or NULL if not found
577  */
578 static xmlXPathObjectPtr
579 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
580                          const xmlChar *ns_uri) {
581     xsltStylesheetPtr style;
582     xsltStackElemPtr elem = NULL;
583
584     style = ctxt->style;
585     while (style != NULL) {
586         elem = style->variables;
587         
588         while (elem != NULL) {
589             if (xmlStrEqual(elem->name, name)) {
590                 if (ns_uri == NULL) {
591                     if (elem->nameURI == NULL)
592                         break;
593                 } else {
594                     if ((elem->nameURI != NULL) &&
595                         (xmlStrEqual(elem->nameURI, ns_uri)))
596                         break;
597                 }
598
599             }
600             elem = elem->next;
601         }
602         if (elem != NULL) break;
603
604         style = xsltNextImport(style);
605     }
606     if (elem == NULL)
607         return(NULL);
608
609     if (!elem->computed) {
610 #ifdef DEBUG_VARIABLE
611         xsltGenericDebug(xsltGenericDebugContext,
612                          "uncomputed global variable %s\n", name);
613 #endif
614         xsltEvalVariable(ctxt, elem);
615     }
616     if (elem->value != NULL)
617         return(xmlXPathObjectCopy(elem->value));
618 #ifdef DEBUG_VARIABLE
619     xsltGenericDebug(xsltGenericDebugContext,
620                      "global variable not found %s\n", name);
621 #endif
622     return(NULL);
623 }
624
625 /**
626  * xsltVariableLookup:
627  * @ctxt:  the XSLT transformation context
628  * @name:  the variable name
629  * @ns_uri:  the variable namespace URI
630  *
631  * Search in the Variable array of the context for the given
632  * variable value.
633  *
634  * Returns the value or NULL if not found
635  */
636 xmlXPathObjectPtr
637 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
638                    const xmlChar *ns_uri) {
639     xsltStackElemPtr elem;
640
641     if (ctxt == NULL)
642         return(NULL);
643
644     elem = xsltStackLookup(ctxt, name, ns_uri);
645     if (elem == NULL) {
646         return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
647     }
648     if (!elem->computed) {
649 #ifdef DEBUG_VARIABLE
650         xsltGenericDebug(xsltGenericDebugContext,
651                          "uncomputed variable %s\n", name);
652 #endif
653         xsltEvalVariable(ctxt, elem);
654     }
655     if (elem->value != NULL)
656         return(xmlXPathObjectCopy(elem->value));
657 #ifdef DEBUG_VARIABLE
658     xsltGenericDebug(xsltGenericDebugContext,
659                      "variable not found %s\n", name);
660 #endif
661     return(NULL);
662 }
663
664 /**
665  * xsltParseStylesheetCallerParam:
666  * @ctxt:  the XSLT transformation context
667  * @cur:  the "param" element
668  *
669  * parse an XSLT transformation param declaration, compute
670  * its value but doesn't record it.
671  *
672  * It returns the new xsltStackElemPtr or NULL
673  */
674
675 xsltStackElemPtr
676 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
677     xmlChar *name, *ncname, *prefix;
678     xmlChar *select;
679     xmlNodePtr tree = NULL;
680     xsltStackElemPtr elem = NULL;
681
682     if ((cur == NULL) || (ctxt == NULL))
683         return(NULL);
684
685     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
686     if (name == NULL) {
687         xsltGenericError(xsltGenericErrorContext,
688             "xsl:param : missing name attribute\n");
689         return(NULL);
690     }
691
692 #ifdef DEBUG_VARIABLE
693     xsltGenericDebug(xsltGenericDebugContext,
694         "Parsing param %s\n", name);
695 #endif
696
697     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
698     if (select == NULL) {
699         tree = cur->children;
700     } else {
701 #ifdef DEBUG_VARIABLE
702         xsltGenericDebug(xsltGenericDebugContext,
703             "        select %s\n", select);
704 #endif
705         if (cur->children != NULL)
706             xsltGenericError(xsltGenericErrorContext,
707             "xsl:param : content shuld be empty since select is present \n");
708     }
709
710     ncname = xmlSplitQName2(name, &prefix);
711
712     if (ncname != NULL) {
713         if (prefix != NULL) {
714             xmlNsPtr ns;
715
716             ns = xmlSearchNs(cur->doc, cur, prefix);
717             if (ns == NULL) {
718                 xsltGenericError(xsltGenericErrorContext,
719                     "xsl:param : no namespace bound to prefix %s\n", prefix);
720             } else {
721                 elem = xsltBuildVariable(ctxt, ncname, ns->href, select,
722                                          tree, 1);
723             }
724             xmlFree(prefix);
725         } else {
726             elem = xsltBuildVariable(ctxt, ncname, NULL, select, tree, 1);
727         }
728         xmlFree(ncname);
729     } else {
730         elem = xsltBuildVariable(ctxt, name, NULL, select, tree, 1);
731     }
732
733     xmlFree(name);
734     if (select != NULL)
735         xmlFree(select);
736     return(elem);
737 }
738
739 /**
740  * xsltParseStylesheetParam:
741  * @ctxt:  the XSLT transformation context
742  * @cur:  the "param" element
743  *
744  * parse an XSLT transformation param declaration and record
745  * its value.
746  */
747
748 void
749 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
750     xmlChar *name, *ncname, *prefix;
751     xmlChar *select;
752     xmlNodePtr tree = NULL;
753
754     if ((cur == NULL) || (ctxt == NULL))
755         return;
756
757     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
758     if (name == NULL) {
759         xsltGenericError(xsltGenericErrorContext,
760             "xsl:param : missing name attribute\n");
761         return;
762     }
763
764 #ifdef DEBUG_VARIABLE
765     xsltGenericDebug(xsltGenericDebugContext,
766         "Parsing param %s\n", name);
767 #endif
768
769     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
770     if (select == NULL) {
771         tree = cur->children;
772     } else {
773 #ifdef DEBUG_VARIABLE
774         xsltGenericDebug(xsltGenericDebugContext,
775             "        select %s\n", select);
776 #endif
777         if (cur->children != NULL)
778             xsltGenericError(xsltGenericErrorContext,
779             "xsl:param : content shuld be empty since select is present \n");
780     }
781
782     ncname = xmlSplitQName2(name, &prefix);
783
784     if (ncname != NULL) {
785         if (prefix != NULL) {
786             xmlNsPtr ns;
787
788             ns = xmlSearchNs(cur->doc, cur, prefix);
789             if (ns == NULL) {
790                 xsltGenericError(xsltGenericErrorContext,
791                     "xsl:param : no namespace bound to prefix %s\n", prefix);
792             } else {
793                 xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 1);
794             }
795             xmlFree(prefix);
796         } else {
797             xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 1);
798         }
799         xmlFree(ncname);
800     } else {
801         xsltRegisterVariable(ctxt, name, NULL, select, tree, 1);
802     }
803
804     xmlFree(name);
805     if (select != NULL)
806         xmlFree(select);
807
808 }
809
810 /**
811  * xsltParseGlobalVariable:
812  * @style:  the XSLT stylesheet
813  * @cur:  the "variable" element
814  *
815  * parse an XSLT transformation variable declaration and record
816  * its value.
817  */
818
819 void
820 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
821     xmlChar *name, *ncname, *prefix;
822     xmlChar *select;
823     xmlNodePtr tree = NULL;
824
825     if ((cur == NULL) || (style == NULL))
826         return;
827
828     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
829     if (name == NULL) {
830         xsltGenericError(xsltGenericErrorContext,
831             "xsl:variable : missing name attribute\n");
832         return;
833     }
834
835 #ifdef DEBUG_VARIABLE
836     xsltGenericDebug(xsltGenericDebugContext,
837         "Parsing global variable %s\n", name);
838 #endif
839
840     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
841     if (select == NULL) {
842         tree = cur->children;
843     } else {
844         if (cur->children != NULL)
845             xsltGenericError(xsltGenericErrorContext,
846             "xsl:variable : content shuld be empty since select is present \n");
847     }
848
849     ncname = xmlSplitQName2(name, &prefix);
850
851     if (ncname != NULL) {
852         if (prefix != NULL) {
853             xmlNsPtr ns;
854
855             ns = xmlSearchNs(cur->doc, cur, prefix);
856             if (ns == NULL) {
857                 xsltGenericError(xsltGenericErrorContext,
858                     "xsl:variable : no namespace bound to prefix %s\n", prefix);
859             } else {
860                 xsltRegisterGlobalVariable(style, ncname, ns->href, select,
861                                            tree, 0, NULL);
862             }
863             xmlFree(prefix);
864         } else {
865             xsltRegisterGlobalVariable(style, ncname, NULL, select, tree,
866                                        0, NULL);
867         }
868         xmlFree(ncname);
869     } else {
870         xsltRegisterGlobalVariable(style, name, NULL, select, tree, 0, NULL);
871     }
872
873     xmlFree(name);
874     if (select != NULL)
875         xmlFree(select);
876
877 }
878
879 /**
880  * xsltParseGlobalParam:
881  * @style:  the XSLT stylesheet
882  * @cur:  the "param" element
883  *
884  * parse an XSLT transformation param declaration and record
885  * its value.
886  */
887
888 void
889 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
890     xmlChar *name, *ncname, *prefix;
891     xmlChar *select;
892     xmlNodePtr tree = NULL;
893
894     if ((cur == NULL) || (style == NULL))
895         return;
896
897     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
898     if (name == NULL) {
899         xsltGenericError(xsltGenericErrorContext,
900             "xsl:param : missing name attribute\n");
901         return;
902     }
903
904 #ifdef DEBUG_VARIABLE
905     xsltGenericDebug(xsltGenericDebugContext,
906         "Parsing global param %s\n", name);
907 #endif
908
909     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
910     if (select == NULL) {
911         tree = cur->children;
912     } else {
913         if (cur->children != NULL)
914             xsltGenericError(xsltGenericErrorContext,
915             "xsl:param : content shuld be empty since select is present \n");
916     }
917
918     ncname = xmlSplitQName2(name, &prefix);
919
920     if (ncname != NULL) {
921         if (prefix != NULL) {
922             xmlNsPtr ns;
923
924             ns = xmlSearchNs(cur->doc, cur, prefix);
925             if (ns == NULL) {
926                 xsltGenericError(xsltGenericErrorContext,
927                     "xsl:param : no namespace bound to prefix %s\n", prefix);
928             } else {
929                 xsltRegisterGlobalVariable(style, ncname, ns->href, select,
930                                            tree, 1, NULL);
931             }
932             xmlFree(prefix);
933         } else {
934             xsltRegisterGlobalVariable(style, ncname, NULL, select, tree,
935                                        1, NULL);
936         }
937         xmlFree(ncname);
938     } else {
939         xsltRegisterGlobalVariable(style, name, NULL, select, tree, 1, NULL);
940     }
941
942     xmlFree(name);
943     if (select != NULL)
944         xmlFree(select);
945 }
946
947 /**
948  * xsltParseStylesheetVariable:
949  * @ctxt:  the XSLT transformation context
950  * @cur:  the "variable" element
951  *
952  * parse an XSLT transformation variable declaration and record
953  * its value.
954  */
955
956 void
957 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
958     xmlChar *name, *ncname, *prefix;
959     xmlChar *select;
960     xmlNodePtr tree = NULL;
961
962     if ((cur == NULL) || (ctxt == NULL))
963         return;
964
965     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
966     if (name == NULL) {
967         xsltGenericError(xsltGenericErrorContext,
968             "xsl:variable : missing name attribute\n");
969         return;
970     }
971
972 #ifdef DEBUG_VARIABLE
973     xsltGenericDebug(xsltGenericDebugContext,
974         "Parsing variable %s\n", name);
975 #endif
976
977     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
978     if (select == NULL) {
979         tree = cur->children;
980     } else {
981         if (cur->children != NULL)
982             xsltGenericError(xsltGenericErrorContext,
983         "xsl:variable : content should be empty since select is present \n");
984     }
985
986     ncname = xmlSplitQName2(name, &prefix);
987
988     if (ncname != NULL) {
989         if (prefix != NULL) {
990             xmlNsPtr ns;
991
992             ns = xmlSearchNs(cur->doc, cur, prefix);
993             if (ns == NULL) {
994                 xsltGenericError(xsltGenericErrorContext,
995                     "xsl:variable : no namespace bound to prefix %s\n", prefix);
996             } else {
997                 xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 0);
998             }
999             xmlFree(prefix);
1000         } else {
1001             xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 0);
1002         }
1003         xmlFree(ncname);
1004     } else {
1005         xsltRegisterVariable(ctxt, name, NULL, select, tree, 0);
1006     }
1007
1008     xmlFree(name);
1009     if (select != NULL)
1010         xmlFree(select);
1011
1012 }
1013
1014 /**
1015  * xsltVariableLookup:
1016  * @ctxt:  a void * but the the XSLT transformation context actually
1017  * @name:  the variable name
1018  * @ns_uri:  the variable namespace URI
1019  *
1020  * This is the entry point when a varibale is needed by the XPath
1021  * interpretor.
1022  *
1023  * Returns the value or NULL if not found
1024  */
1025 xmlXPathObjectPtr
1026 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
1027                         const xmlChar *ns_uri) {
1028     xsltTransformContextPtr context;
1029     xmlXPathObjectPtr ret;
1030
1031     if ((ctxt == NULL) || (name == NULL))
1032         return(NULL);
1033
1034 #ifdef DEBUG_VARIABLE
1035     xsltGenericDebug(xsltGenericDebugContext,
1036             "Lookup variable %s\n", name);
1037 #endif
1038     context = (xsltTransformContextPtr) ctxt;
1039     ret = xsltVariableLookup(context, name, ns_uri);
1040     if (ret == NULL) {
1041         xsltGenericError(xsltGenericErrorContext,
1042             "unregistered variable %s\n", name);
1043     }
1044 #ifdef DEBUG_VARIABLE
1045     if (ret != NULL)
1046         xsltGenericDebug(xsltGenericDebugContext,
1047             "found variable %s\n", name);
1048 #endif
1049     return(ret);
1050 }
1051