The XML Rec formatting test starts looking okay, also added
[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 "xslt.h"
25 #include "xsltInternals.h"
26 #include "xsltutils.h"
27 #include "variables.h"
28 #include "transform.h"
29 #include "imports.h"
30
31 #define DEBUG_VARIABLE
32
33 /*
34  * Types are private:
35  */
36
37 typedef struct _xsltStack xsltStack;
38 typedef xsltStack *xsltStackPtr;
39 struct _xsltStack {
40     int cur;
41     int max;
42     xsltStackElemPtr elems[50];
43 };
44
45
46 /************************************************************************
47  *                                                                      *
48  *                      Module interfaces                               *
49  *                                                                      *
50  ************************************************************************/
51
52 /**
53  * xsltNewParserContext:
54  *
55  * Create a new XSLT ParserContext
56  *
57  * Returns the newly allocated xsltParserStackElem or NULL in case of error
58  */
59 xsltStackElemPtr
60 xsltNewStackElem(void) {
61     xsltStackElemPtr cur;
62
63     cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
64     if (cur == NULL) {
65         xsltGenericError(xsltGenericErrorContext,
66                 "xsltNewStackElem : malloc failed\n");
67         return(NULL);
68     }
69     memset(cur, 0, sizeof(xsltStackElem));
70     cur->computed = 0;
71     return(cur);
72 }
73
74 /**
75  * xsltFreeStackElem:
76  * @elem:  an XSLT stack element
77  *
78  * Free up the memory allocated by @elem
79  */
80 void
81 xsltFreeStackElem(xsltStackElemPtr elem) {
82     if (elem == NULL)
83         return;
84     if (elem->name != NULL)
85         xmlFree(elem->name);
86     if (elem->nameURI != NULL)
87         xmlFree(elem->nameURI);
88     if (elem->select != NULL)
89         xmlFree(elem->select);
90     if (elem->value != NULL)
91         xmlXPathFreeObject(elem->value);
92
93     memset(elem, -1, sizeof(xsltStackElem));
94     xmlFree(elem);
95 }
96
97 /**
98  * xsltFreeStackElemList:
99  * @elem:  an XSLT stack element
100  *
101  * Free up the memory allocated by @elem
102  */
103 void
104 xsltFreeStackElemList(xsltStackElemPtr elem) {
105     xsltStackElemPtr next;
106
107     while(elem != NULL) {
108         next = elem->next;
109         xsltFreeStackElem(elem);
110         elem = next;
111     }
112 }
113
114 /**
115  * xsltAddStackElem:
116  * @ctxt:  xn XSLT transformation context
117  * @elem:  a stack element
118  *
119  * add a new element at this level of the stack.
120  *
121  * Returns 0 in case of success, -1 in case of failure.
122  */
123 int
124 xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
125     xsltStackPtr stack;
126     xsltStackElemPtr cur;
127
128     if ((ctxt == NULL) || (elem == NULL))
129         return(-1);
130
131     stack = ctxt->variablesHash;
132     if (stack == NULL) {
133         /* TODO make stack size dynamic !!! */
134         stack = xmlMalloc(sizeof (xsltStack));
135         if (stack == NULL) {
136             xsltGenericError(xsltGenericErrorContext,
137                 "xsltPushStack : malloc failed\n");
138             return(-1);
139         }
140         memset(stack, 0, sizeof(xsltStack));
141         ctxt->variablesHash = stack;
142         stack->cur = 0;
143         stack->max = 50;
144     }
145     /* TODO: check that there is no conflict with existing values
146      * at that level */
147     cur = stack->elems[stack->cur];
148     while (cur != NULL) {
149         if (xmlStrEqual(elem->name, cur->name)) {
150             if (((elem->nameURI == NULL) && (cur->nameURI == NULL)) ||
151                 ((elem->nameURI != NULL) && (cur->nameURI != NULL) &&
152                  (xmlStrEqual(elem->nameURI, cur->nameURI)))) {
153                 xsltGenericError(xsltGenericErrorContext,
154                     "redefinition of param or variable %s\n", elem->name);
155                 xsltFreeStackElem(elem);
156             }
157         }
158         cur = cur->next;
159     }
160
161     elem->next = stack->elems[stack->cur];
162     stack->elems[stack->cur] = elem;
163     return(0);
164 }
165
166 /**
167  * xsltPushStack:
168  * @ctxt:  xn XSLT transformation context
169  *
170  * Push a new level on the ctxtsheet interprestation stack
171  */
172 void
173 xsltPushStack(xsltTransformContextPtr ctxt) {
174     xsltStackPtr stack;
175
176     if (ctxt == NULL)
177         return;
178
179     stack = ctxt->variablesHash;
180     if (stack == NULL) {
181         /* TODO make stack size dynamic !!! */
182         stack = xmlMalloc(sizeof (xsltStack));
183         if (stack == NULL) {
184             xsltGenericError(xsltGenericErrorContext,
185                 "xsltPushStack : malloc failed\n");
186             return;
187         }
188         memset(stack, 0, sizeof(xsltStack));
189         ctxt->variablesHash = stack;
190         stack->cur = 0;
191         stack->max = 50;
192     }
193     if (stack->cur >= stack->max + 1) {
194         TODO /* make stack size dynamic !!! */
195         xsltGenericError(xsltGenericErrorContext,
196             "xsltPushStack : overflow\n");
197         return;
198     }
199     stack->cur++;
200     stack->elems[stack->cur] = NULL;
201 }
202
203 /**
204  * xsltPopStack:
205  * @ctxt:  an XSLT transformation context
206  *
207  * Pop a level on the ctxtsheet interprestation stack
208  */
209 void
210 xsltPopStack(xsltTransformContextPtr ctxt) {
211     xsltStackPtr stack;
212
213     if (ctxt == NULL)
214         return;
215
216     stack = ctxt->variablesHash;
217     if (stack == NULL)
218         return;
219
220     xsltFreeStackElemList(stack->elems[stack->cur]);
221     stack->elems[stack->cur] = NULL;
222     stack->cur--;
223 }
224
225 /**
226  * xsltStackLookup:
227  * @ctxt:  an XSLT transformation context
228  * @name:  the local part of the name
229  * @nameURI:  the URI part of the name
230  *
231  * Locate an element in the stack based on its name.
232  */
233 xsltStackElemPtr
234 xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
235                 const xmlChar *nameURI) {
236     xsltStackElemPtr ret = NULL;
237     xsltStackPtr stack;
238     int i;
239     xsltStackElemPtr cur;
240
241     if ((ctxt == NULL) || (name == NULL))
242         return(NULL);
243
244     stack = ctxt->variablesHash;
245     if (stack == NULL)
246         return(NULL);
247
248     for (i = stack->cur;i >= 0;i--) {
249         cur = stack->elems[i];
250         while (cur != NULL) {
251             if (xmlStrEqual(cur->name, name)) {
252                 /* TODO: double check param binding */
253                 if (nameURI == NULL) {
254                     if (cur->nameURI == NULL) {
255                         if (cur->type == XSLT_ELEM_PARAM)
256                             ret = cur;
257                         else
258                             return(cur);
259                     }
260                 } else {
261                     if ((cur->nameURI != NULL) &&
262                         (xmlStrEqual(cur->nameURI, nameURI))) {
263                         if (cur->type == XSLT_ELEM_PARAM)
264                             ret = cur;
265                         else
266                             return(cur);
267                     }
268                 }
269
270             }
271             cur = cur->next;
272         }
273     }
274     return(ret);
275 }
276
277 /************************************************************************
278  *                                                                      *
279  *                      Module interfaces                               *
280  *                                                                      *
281  ************************************************************************/
282
283 /**
284  * xsltEvalVariable:
285  * @ctxt:  the XSLT transformation context
286  * @elem:  the variable or parameter.
287  *
288  * Evaluate a variable value.
289  *
290  * Returns 0 in case of success, -1 in case of error
291  */
292 int
293 xsltEvalVariables(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
294     xmlXPathParserContextPtr xpathParserCtxt;
295
296     if ((ctxt == NULL) || (elem == NULL))
297         return(-1);
298
299 #ifdef DEBUG_VARIABLE
300     xsltGenericDebug(xsltGenericDebugContext,
301         "Evaluating variable %s\n", elem->name);
302 #endif
303     if (elem->select != NULL) {
304         xmlXPathObjectPtr result, tmp;
305
306         xpathParserCtxt = xmlXPathNewParserContext(elem->select,
307                                                    ctxt->xpathCtxt);
308         if (xpathParserCtxt == NULL)
309             return(-1);
310         ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
311         xmlXPathEvalExpr(xpathParserCtxt);
312         result = valuePop(xpathParserCtxt);
313         do {
314             tmp = valuePop(xpathParserCtxt);
315             if (tmp != NULL) {
316                 xmlXPathFreeObject(tmp);
317             }
318         } while (tmp != NULL);
319
320         if (result == NULL) {
321             xsltGenericError(xsltGenericErrorContext,
322                 "Evaluating global variable %s failed\n");
323         }
324         if (xpathParserCtxt != NULL)
325             xmlXPathFreeParserContext(xpathParserCtxt);
326         if (result != NULL) {
327 #ifdef DEBUG_VARIABLE
328             if ((xsltGenericDebugContext == stdout) ||
329                 (xsltGenericDebugContext == stderr))
330                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
331                                         result, 0);
332 #endif
333             if (elem->value != NULL)
334                 xmlXPathFreeObject(elem->value);
335             elem->value = result;
336             elem->computed = 1;
337         }
338     } else {
339         if (elem->tree == NULL) {
340             elem->value = xmlXPathNewCString("");
341             elem->computed = 1;
342         } else {
343             /*
344              * This is a result tree fragment.
345              */
346             xmlNodePtr container;
347             xmlNodePtr oldInsert, oldNode;
348
349             container = xmlNewDocNode(ctxt->output, NULL,
350                                       (const xmlChar *) "fake", NULL);
351             if (container == NULL)
352                 return(-1);
353             oldInsert = ctxt->insert;
354             oldNode = ctxt->node;
355             ctxt->insert = container;
356
357             xsltApplyOneTemplate(ctxt, ctxt->node, NULL, elem->tree);
358
359             ctxt->insert = oldInsert;
360             ctxt->node = oldNode;
361             elem->value = xmlXPathNewValueTree(container);
362             elem->computed = 1;
363         }
364     }
365     return(0);
366 }
367 /**
368  * xsltEvalGlobalVariables:
369  * @ctxt:  the XSLT transformation context
370  *
371  * Evaluate the global variables of a stylesheet. This need to be
372  * done on parsed stylesheets before starting to apply transformations
373  *
374  * Returns 0 in case of success, -1 in case of error
375  */
376 int
377 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
378     xsltStackElemPtr elem;
379     xsltStylesheetPtr style;
380
381     if (ctxt == NULL)
382         return(-1);
383  
384 #ifdef DEBUG_VARIABLE
385     xsltGenericDebug(xsltGenericDebugContext,
386         "Evaluating global variables\n");
387 #endif
388     ctxt->node = (xmlNodePtr) ctxt->document->doc;
389     style = ctxt->style;
390     /* TODO: handle the stylesheet cascade */
391     if (style != NULL) {
392         elem = style->variables;
393         
394         while (elem != NULL) {
395             xsltEvalVariables(ctxt, elem);
396             elem = elem->next;
397         }
398     }
399     return(0);
400 }
401
402 /**
403  * xsltRegisterGlobalVariable:
404  * @style:  the XSLT transformation context
405  * @name:  the variable name
406  * @ns_uri:  the variable namespace URI
407  * @select:  the expression which need to be evaluated to generate a value
408  * @tree:  the subtree if select is NULL
409  * @param:  this is a parameter actually
410  *
411  * Register a new variable value. If @value is NULL it unregisters
412  * the variable
413  *
414  * Returns 0 in case of success, -1 in case of error
415  */
416 int
417 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
418                      const xmlChar *ns_uri, const xmlChar *select,
419                      xmlNodePtr tree, int param) {
420     xsltStackElemPtr elem;
421     if (style == NULL)
422         return(-1);
423     if (name == NULL)
424         return(-1);
425
426 #ifdef DEBUG_VARIABLE
427     if (param)
428         xsltGenericDebug(xsltGenericDebugContext,
429                          "Defineing global param %s\n", name);
430     else
431         xsltGenericDebug(xsltGenericDebugContext,
432                          "Defineing global variable %s\n", name);
433 #endif
434     elem = xsltNewStackElem();
435     if (elem == NULL)
436         return(-1);
437     if (param)
438         elem->type = XSLT_ELEM_PARAM;
439     else
440         elem->type = XSLT_ELEM_VARIABLE;
441     elem->name = xmlStrdup(name);
442     elem->select = xmlStrdup(select);
443     if (ns_uri)
444         elem->nameURI = xmlStrdup(ns_uri);
445     elem->tree = tree;
446     elem->next = style->variables;
447     style->variables = elem;
448     return(0);
449 }
450
451 /**
452  * xsltRegisterVariable:
453  * @ctxt:  the XSLT transformation context
454  * @name:  the variable name
455  * @ns_uri:  the variable namespace URI
456  * @select:  the expression which need to be evaluated to generate a value
457  * @tree:  the tree if select is NULL
458  * @param:  this is a parameter actually
459  *
460  * Register a new variable value. If @value is NULL it unregisters
461  * the variable
462  *
463  * Returns 0 in case of success, -1 in case of error
464  */
465 int
466 xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name,
467                      const xmlChar *ns_uri, const xmlChar *select,
468                      xmlNodePtr tree, int param) {
469     xsltStackElemPtr elem;
470     if (ctxt == NULL)
471         return(-1);
472     if (name == NULL)
473         return(-1);
474
475 #ifdef DEBUG_VARIABLE
476     xsltGenericDebug(xsltGenericDebugContext,
477                      "Defineing variable %s", name);
478     if (select != NULL)
479         xsltGenericDebug(xsltGenericDebugContext,
480                          " select %s",  select);
481     xsltGenericDebug(xsltGenericDebugContext, "\n");
482 #endif
483     elem = xsltNewStackElem();
484     if (elem == NULL)
485         return(-1);
486     if (param)
487         elem->type = XSLT_ELEM_PARAM;
488     else
489         elem->type = XSLT_ELEM_VARIABLE;
490     elem->name = xmlStrdup(name);
491     if (select != NULL)
492         elem->select = xmlStrdup(select);
493     else
494         elem->select = NULL;
495     if (ns_uri)
496         elem->nameURI = xmlStrdup(ns_uri);
497     elem->tree = tree;
498     xsltAddStackElem(ctxt, elem);
499     xsltEvalVariables(ctxt, elem);
500     return(0);
501 }
502
503 /**
504  * xsltGlobalVariableLookup:
505  * @ctxt:  the XSLT transformation context
506  * @name:  the variable name
507  * @ns_uri:  the variable namespace URI
508  *
509  * Search in the Variable array of the context for the given
510  * variable value.
511  *
512  * Returns the value or NULL if not found
513  */
514 xmlXPathObjectPtr
515 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
516                          const xmlChar *ns_uri) {
517     xsltStylesheetPtr style;
518     xsltStackElemPtr elem = NULL;
519
520     style = ctxt->style;
521     while (style != NULL) {
522         elem = style->variables;
523         
524         while (elem != NULL) {
525             if (xmlStrEqual(elem->name, name)) {
526                 /* TODO: double check param binding */
527                 if (ns_uri == NULL) {
528                     if (elem->nameURI == NULL)
529                         break;
530                 } else {
531                     if ((elem->nameURI != NULL) &&
532                         (xmlStrEqual(elem->nameURI, ns_uri)))
533                         break;
534                 }
535
536             }
537             elem = elem->next;
538         }
539
540         style = xsltNextImport(style);
541     }
542     if (elem == NULL)
543         return(NULL);
544
545     if (!elem->computed) {
546 #ifdef DEBUG_VARIABLE
547         xsltGenericDebug(xsltGenericDebugContext,
548                          "uncomputed global variable %s\n", name);
549 #endif
550         xsltEvalVariables(ctxt, elem);
551     }
552     if (elem->value != NULL)
553         return(xmlXPathObjectCopy(elem->value));
554 #ifdef DEBUG_VARIABLE
555     xsltGenericDebug(xsltGenericDebugContext,
556                      "global variable not found %s\n", name);
557 #endif
558     return(NULL);
559 }
560
561 /**
562  * xsltVariableLookup:
563  * @ctxt:  the XSLT transformation context
564  * @name:  the variable name
565  * @ns_uri:  the variable namespace URI
566  *
567  * Search in the Variable array of the context for the given
568  * variable value.
569  *
570  * Returns the value or NULL if not found
571  */
572 xmlXPathObjectPtr
573 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
574                    const xmlChar *ns_uri) {
575     xsltStackElemPtr elem;
576
577     if (ctxt == NULL)
578         return(NULL);
579
580     elem = xsltStackLookup(ctxt, name, ns_uri);
581     if (elem == NULL) {
582         return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
583     }
584     if (!elem->computed) {
585 #ifdef DEBUG_VARIABLE
586         xsltGenericDebug(xsltGenericDebugContext,
587                          "uncomputed variable %s\n", name);
588 #endif
589         xsltEvalVariables(ctxt, elem);
590     }
591     if (elem->value != NULL)
592         return(xmlXPathObjectCopy(elem->value));
593 #ifdef DEBUG_VARIABLE
594     xsltGenericDebug(xsltGenericDebugContext,
595                      "variable not found %s\n", name);
596 #endif
597     return(NULL);
598 }
599
600
601 /**
602  * xsltFreeVariableHashes:
603  * @ctxt: an XSLT transformation context
604  *
605  * Free up the memory used by xsltAddVariable/xsltGetVariable mechanism
606  */
607 void
608 xsltFreeVariableHashes(xsltTransformContextPtr ctxt) {
609     xsltStackPtr stack;
610     int i;
611
612     if (ctxt == NULL)
613         return;
614
615     stack = ctxt->variablesHash;
616     if (stack == NULL)
617         return;
618
619     for (i = 0; i <= stack->cur;i++) {
620         xsltFreeStackElemList(stack->elems[i]);
621     }
622     xmlFree(stack);
623
624 }
625
626 /**
627  * xsltParseStylesheetParam:
628  * @ctxt:  the XSLT transformation context
629  * @cur:  the "param" element
630  *
631  * parse an XSLT transformation param declaration and record
632  * its value.
633  */
634
635 void
636 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
637     xmlChar *name, *ncname, *prefix;
638     xmlChar *select;
639     xmlNodePtr tree = NULL;
640
641     if ((cur == NULL) || (ctxt == NULL))
642         return;
643
644     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
645     if (name == NULL) {
646         xsltGenericError(xsltGenericErrorContext,
647             "xsl:param : missing name attribute\n");
648         return;
649     }
650
651 #ifdef DEBUG_VARIABLE
652     xsltGenericDebug(xsltGenericDebugContext,
653         "Parsing param %s\n", name);
654 #endif
655
656     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
657     if (select == NULL) {
658         tree = cur->children;
659     } else {
660         if (cur->children != NULL)
661             xsltGenericError(xsltGenericErrorContext,
662             "xsl:param : content shuld be empty since select is present \n");
663     }
664
665     ncname = xmlSplitQName2(name, &prefix);
666
667     if (ncname != NULL) {
668         if (prefix != NULL) {
669             xmlNsPtr ns;
670
671             ns = xmlSearchNs(cur->doc, cur, prefix);
672             if (ns == NULL) {
673                 xsltGenericError(xsltGenericErrorContext,
674                     "xsl:param : no namespace bound to prefix %s\n", prefix);
675             } else {
676                 xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 1);
677             }
678             xmlFree(prefix);
679         } else {
680             xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 1);
681         }
682         xmlFree(ncname);
683     } else {
684         xsltRegisterVariable(ctxt, name, NULL, select, tree, 1);
685     }
686
687     xmlFree(name);
688     if (select != NULL)
689         xmlFree(select);
690
691 }
692
693 /**
694  * xsltParseGlobalVariable:
695  * @style:  the XSLT stylesheet
696  * @cur:  the "variable" element
697  *
698  * parse an XSLT transformation variable declaration and record
699  * its value.
700  */
701
702 void
703 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
704     xmlChar *name, *ncname, *prefix;
705     xmlChar *select;
706     xmlNodePtr tree = NULL;
707
708     if ((cur == NULL) || (style == NULL))
709         return;
710
711     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
712     if (name == NULL) {
713         xsltGenericError(xsltGenericErrorContext,
714             "xsl:variable : missing name attribute\n");
715         return;
716     }
717
718 #ifdef DEBUG_VARIABLE
719     xsltGenericDebug(xsltGenericDebugContext,
720         "Parsing global variable %s\n", name);
721 #endif
722
723     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
724     if (select == NULL) {
725         tree = cur->children;
726     } else {
727         if (cur->children != NULL)
728             xsltGenericError(xsltGenericErrorContext,
729             "xsl:variable : content shuld be empty since select is present \n");
730     }
731
732     ncname = xmlSplitQName2(name, &prefix);
733
734     if (ncname != NULL) {
735         if (prefix != NULL) {
736             xmlNsPtr ns;
737
738             ns = xmlSearchNs(cur->doc, cur, prefix);
739             if (ns == NULL) {
740                 xsltGenericError(xsltGenericErrorContext,
741                     "xsl:variable : no namespace bound to prefix %s\n", prefix);
742             } else {
743                 xsltRegisterGlobalVariable(style, ncname, ns->href, select, tree, 0);
744             }
745             xmlFree(prefix);
746         } else {
747             xsltRegisterGlobalVariable(style, ncname, NULL, select, tree, 0);
748         }
749         xmlFree(ncname);
750     } else {
751         xsltRegisterGlobalVariable(style, name, NULL, select, tree, 0);
752     }
753
754     xmlFree(name);
755     if (select != NULL)
756         xmlFree(select);
757
758 }
759
760 /**
761  * xsltParseGlobalParam:
762  * @style:  the XSLT stylesheet
763  * @cur:  the "param" element
764  *
765  * parse an XSLT transformation param declaration and record
766  * its value.
767  */
768
769 void
770 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
771     xmlChar *name, *ncname, *prefix;
772     xmlChar *select;
773     xmlNodePtr tree = NULL;
774
775     if ((cur == NULL) || (style == NULL))
776         return;
777
778     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
779     if (name == NULL) {
780         xsltGenericError(xsltGenericErrorContext,
781             "xsl:param : missing name attribute\n");
782         return;
783     }
784
785 #ifdef DEBUG_VARIABLE
786     xsltGenericDebug(xsltGenericDebugContext,
787         "Parsing global param %s\n", name);
788 #endif
789
790     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
791     if (select == NULL) {
792         tree = cur->children;
793     } else {
794         if (cur->children != NULL)
795             xsltGenericError(xsltGenericErrorContext,
796             "xsl:param : content shuld be empty since select is present \n");
797     }
798
799     ncname = xmlSplitQName2(name, &prefix);
800
801     if (ncname != NULL) {
802         if (prefix != NULL) {
803             xmlNsPtr ns;
804
805             ns = xmlSearchNs(cur->doc, cur, prefix);
806             if (ns == NULL) {
807                 xsltGenericError(xsltGenericErrorContext,
808                     "xsl:param : no namespace bound to prefix %s\n", prefix);
809             } else {
810                 xsltRegisterGlobalVariable(style, ncname, ns->href, select, tree, 1);
811             }
812             xmlFree(prefix);
813         } else {
814             xsltRegisterGlobalVariable(style, ncname, NULL, select, tree, 1);
815         }
816         xmlFree(ncname);
817     } else {
818         xsltRegisterGlobalVariable(style, name, NULL, select, tree, 1);
819     }
820
821     xmlFree(name);
822     if (select != NULL)
823         xmlFree(select);
824 }
825
826 /**
827  * xsltParseStylesheetVariable:
828  * @ctxt:  the XSLT transformation context
829  * @cur:  the "variable" element
830  *
831  * parse an XSLT transformation variable declaration and record
832  * its value.
833  */
834
835 void
836 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
837     xmlChar *name, *ncname, *prefix;
838     xmlChar *select;
839     xmlNodePtr tree = NULL;
840
841     if ((cur == NULL) || (ctxt == NULL))
842         return;
843
844     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
845     if (name == NULL) {
846         xsltGenericError(xsltGenericErrorContext,
847             "xsl:variable : missing name attribute\n");
848         return;
849     }
850
851 #ifdef DEBUG_VARIABLE
852     xsltGenericDebug(xsltGenericDebugContext,
853         "Parsing variable %s\n", name);
854 #endif
855
856     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
857     if (select == NULL) {
858         tree = cur->children;
859     } else {
860         if (cur->children != NULL)
861             xsltGenericError(xsltGenericErrorContext,
862         "xsl:variable : content should be empty since select is present \n");
863     }
864
865     ncname = xmlSplitQName2(name, &prefix);
866
867     if (ncname != NULL) {
868         if (prefix != NULL) {
869             xmlNsPtr ns;
870
871             ns = xmlSearchNs(cur->doc, cur, prefix);
872             if (ns == NULL) {
873                 xsltGenericError(xsltGenericErrorContext,
874                     "xsl:variable : no namespace bound to prefix %s\n", prefix);
875             } else {
876                 xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 0);
877             }
878             xmlFree(prefix);
879         } else {
880             xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 0);
881         }
882         xmlFree(ncname);
883     } else {
884         xsltRegisterVariable(ctxt, name, NULL, select, tree, 0);
885     }
886
887     xmlFree(name);
888     if (select != NULL)
889         xmlFree(select);
890
891 }
892
893 /**
894  * xsltVariableLookup:
895  * @ctxt:  a void * but the the XSLT transformation context actually
896  * @name:  the variable name
897  * @ns_uri:  the variable namespace URI
898  *
899  * This is the entry point when a varibale is needed by the XPath
900  * interpretor.
901  *
902  * Returns the value or NULL if not found
903  */
904 xmlXPathObjectPtr
905 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
906                         const xmlChar *ns_uri) {
907     xsltTransformContextPtr context;
908     xmlXPathObjectPtr ret;
909
910     if ((ctxt == NULL) || (name == NULL))
911         return(NULL);
912
913 #ifdef DEBUG_VARIABLE
914     xsltGenericDebug(xsltGenericDebugContext,
915             "Lookup variable %s\n", name);
916 #endif
917     context = (xsltTransformContextPtr) ctxt;
918     ret = xsltVariableLookup(context, name, ns_uri);
919     if (ret == NULL) {
920         xsltGenericError(xsltGenericErrorContext,
921             "unregistered variable %s\n", name);
922     }
923 #ifdef DEBUG_VARIABLE
924     if (ret != NULL)
925         xsltGenericDebug(xsltGenericDebugContext,
926             "found variable %s\n", name);
927 #endif
928     return(ret);
929 }
930