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