This should speed up and correct a few problems:
[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     /*
190      * Do the lookup from the top of the stack, but
191      * don't use params being computed in a call-param
192      */
193     i = ctxt->varsNr - 1;
194     if (ctxt->varsComputed)
195         i--;
196
197     for (;i >= 0;i--) {
198         cur = ctxt->varsTab[i];
199         while (cur != NULL) {
200             if (xmlStrEqual(cur->name, name)) {
201                 if (nameURI == NULL) {
202                     if (cur->nameURI == NULL) {
203                         return(cur);
204                     }
205                 } else {
206                     if ((cur->nameURI != NULL) &&
207                         (xmlStrEqual(cur->nameURI, nameURI))) {
208                         return(cur);
209                     }
210                 }
211
212             }
213             cur = cur->next;
214         }
215     }
216     return(ret);
217 }
218
219 /************************************************************************
220  *                                                                      *
221  *                      Module interfaces                               *
222  *                                                                      *
223  ************************************************************************/
224
225 /**
226  * xsltEvalVariable:
227  * @ctxt:  the XSLT transformation context
228  * @elem:  the variable or parameter.
229  *
230  * Evaluate a variable value.
231  *
232  * Returns 0 in case of success, -1 in case of error
233  */
234 int
235 xsltEvalVariables(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) {
236     xmlXPathParserContextPtr xpathParserCtxt;
237
238     if ((ctxt == NULL) || (elem == NULL))
239         return(-1);
240
241 #ifdef DEBUG_VARIABLE
242     xsltGenericDebug(xsltGenericDebugContext,
243         "Evaluating variable %s\n", elem->name);
244 #endif
245     if (elem->select != NULL) {
246         xmlXPathObjectPtr result, tmp;
247
248         xpathParserCtxt = xmlXPathNewParserContext(elem->select,
249                                                    ctxt->xpathCtxt);
250         if (xpathParserCtxt == NULL)
251             return(-1);
252         ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
253         xmlXPathEvalExpr(xpathParserCtxt);
254         result = valuePop(xpathParserCtxt);
255         do {
256             tmp = valuePop(xpathParserCtxt);
257             if (tmp != NULL) {
258                 xmlXPathFreeObject(tmp);
259             }
260         } while (tmp != NULL);
261
262         if (result == NULL) {
263             xsltGenericError(xsltGenericErrorContext,
264                 "Evaluating global variable %s failed\n");
265         }
266         if (xpathParserCtxt != NULL)
267             xmlXPathFreeParserContext(xpathParserCtxt);
268         if (result != NULL) {
269 #ifdef DEBUG_VARIABLE
270             if ((xsltGenericDebugContext == stdout) ||
271                 (xsltGenericDebugContext == stderr))
272                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
273                                         result, 0);
274 #endif
275             if (elem->value != NULL)
276                 xmlXPathFreeObject(elem->value);
277             elem->value = result;
278         }
279         elem->computed = 1;
280     } else {
281         if (elem->tree == NULL) {
282             elem->value = xmlXPathNewCString("");
283             elem->computed = 1;
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             oldInsert = ctxt->insert;
296             oldNode = ctxt->node;
297             ctxt->insert = container;
298
299             xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, 0);
300
301             ctxt->insert = oldInsert;
302             ctxt->node = oldNode;
303             elem->value = xmlXPathNewValueTree(container);
304             elem->computed = 1;
305         }
306     }
307     return(0);
308 }
309 /**
310  * xsltEvalGlobalVariables:
311  * @ctxt:  the XSLT transformation context
312  *
313  * Evaluate the global variables of a stylesheet. This need to be
314  * done on parsed stylesheets before starting to apply transformations
315  *
316  * Returns 0 in case of success, -1 in case of error
317  */
318 int
319 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
320     xsltStackElemPtr elem;
321     xsltStylesheetPtr style;
322
323     if (ctxt == NULL)
324         return(-1);
325  
326 #ifdef DEBUG_VARIABLE
327     xsltGenericDebug(xsltGenericDebugContext,
328         "Evaluating global variables\n");
329 #endif
330     ctxt->node = (xmlNodePtr) ctxt->document->doc;
331     style = ctxt->style;
332     /* TODO: handle the stylesheet cascade */
333     if (style != NULL) {
334         elem = style->variables;
335         
336         while (elem != NULL) {
337             xsltEvalVariables(ctxt, elem);
338             elem = elem->next;
339         }
340     }
341     return(0);
342 }
343
344 /**
345  * xsltRegisterGlobalVariable:
346  * @style:  the XSLT transformation context
347  * @name:  the variable name
348  * @ns_uri:  the variable namespace URI
349  * @select:  the expression which need to be evaluated to generate a value
350  * @tree:  the subtree if select is NULL
351  * @param:  this is a parameter actually
352  *
353  * Register a new variable value. If @value is NULL it unregisters
354  * the variable
355  *
356  * Returns 0 in case of success, -1 in case of error
357  */
358 int
359 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
360                      const xmlChar *ns_uri, const xmlChar *select,
361                      xmlNodePtr tree, int param) {
362     xsltStackElemPtr elem;
363     if (style == NULL)
364         return(-1);
365     if (name == NULL)
366         return(-1);
367
368 #ifdef DEBUG_VARIABLE
369     if (param)
370         xsltGenericDebug(xsltGenericDebugContext,
371                          "Defineing global param %s\n", name);
372     else
373         xsltGenericDebug(xsltGenericDebugContext,
374                          "Defineing global variable %s\n", name);
375 #endif
376     elem = xsltNewStackElem();
377     if (elem == NULL)
378         return(-1);
379     if (param)
380         elem->type = XSLT_ELEM_PARAM;
381     else
382         elem->type = XSLT_ELEM_VARIABLE;
383     elem->name = xmlStrdup(name);
384     elem->select = xmlStrdup(select);
385     if (ns_uri)
386         elem->nameURI = xmlStrdup(ns_uri);
387     elem->tree = tree;
388     elem->next = style->variables;
389     style->variables = elem;
390     return(0);
391 }
392
393 /**
394  * xsltRegisterVariable:
395  * @ctxt:  the XSLT transformation context
396  * @name:  the variable name
397  * @ns_uri:  the variable namespace URI
398  * @select:  the expression which need to be evaluated to generate a value
399  * @tree:  the tree if select is NULL
400  * @param:  this is a parameter actually
401  *
402  * Register a new variable value. If @value is NULL it unregisters
403  * the variable
404  *
405  * Returns 0 in case of success, -1 in case of error
406  */
407 int
408 xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name,
409                      const xmlChar *ns_uri, const xmlChar *select,
410                      xmlNodePtr tree, int param) {
411     xsltStackElemPtr elem;
412     if (ctxt == NULL)
413         return(-1);
414     if (name == NULL)
415         return(-1);
416
417     if (xsltCheckStackElem(ctxt, name, ns_uri) != 0) {
418         if (!param) {
419             xsltGenericError(xsltGenericErrorContext,
420             "xsl:variable : redefining %s\n", name);
421         }
422 #ifdef DEBUG_VARIABLE
423         else
424             xsltGenericDebug(xsltGenericDebugContext,
425                      "param %s defined by caller", name);
426 #endif
427         return(0);
428     }
429 #ifdef DEBUG_VARIABLE
430     xsltGenericDebug(xsltGenericDebugContext,
431                      "Defineing variable %s", name);
432     if (select != NULL)
433         xsltGenericDebug(xsltGenericDebugContext,
434                          " select %s",  select);
435     xsltGenericDebug(xsltGenericDebugContext, "\n");
436 #endif
437     elem = xsltNewStackElem();
438     if (elem == NULL)
439         return(-1);
440     if (param)
441         elem->type = XSLT_ELEM_PARAM;
442     else
443         elem->type = XSLT_ELEM_VARIABLE;
444     elem->name = xmlStrdup(name);
445     if (select != NULL)
446         elem->select = xmlStrdup(select);
447     else
448         elem->select = NULL;
449     if (ns_uri)
450         elem->nameURI = xmlStrdup(ns_uri);
451     elem->tree = tree;
452     xsltEvalVariables(ctxt, elem);
453     xsltAddStackElem(ctxt, elem);
454     return(0);
455 }
456
457 /**
458  * xsltGlobalVariableLookup:
459  * @ctxt:  the XSLT transformation context
460  * @name:  the variable name
461  * @ns_uri:  the variable namespace URI
462  *
463  * Search in the Variable array of the context for the given
464  * variable value.
465  *
466  * Returns the value or NULL if not found
467  */
468 xmlXPathObjectPtr
469 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
470                          const xmlChar *ns_uri) {
471     xsltStylesheetPtr style;
472     xsltStackElemPtr elem = NULL;
473
474     style = ctxt->style;
475     while (style != NULL) {
476         elem = style->variables;
477         
478         while (elem != NULL) {
479             if (xmlStrEqual(elem->name, name)) {
480                 /* TODO: double check param binding */
481                 if (ns_uri == NULL) {
482                     if (elem->nameURI == NULL)
483                         break;
484                 } else {
485                     if ((elem->nameURI != NULL) &&
486                         (xmlStrEqual(elem->nameURI, ns_uri)))
487                         break;
488                 }
489
490             }
491             elem = elem->next;
492         }
493
494         style = xsltNextImport(style);
495     }
496     if (elem == NULL)
497         return(NULL);
498
499     if (!elem->computed) {
500 #ifdef DEBUG_VARIABLE
501         xsltGenericDebug(xsltGenericDebugContext,
502                          "uncomputed global variable %s\n", name);
503 #endif
504         xsltEvalVariables(ctxt, elem);
505     }
506     if (elem->value != NULL)
507         return(xmlXPathObjectCopy(elem->value));
508 #ifdef DEBUG_VARIABLE
509     xsltGenericDebug(xsltGenericDebugContext,
510                      "global variable not found %s\n", name);
511 #endif
512     return(NULL);
513 }
514
515 /**
516  * xsltVariableLookup:
517  * @ctxt:  the XSLT transformation context
518  * @name:  the variable name
519  * @ns_uri:  the variable namespace URI
520  *
521  * Search in the Variable array of the context for the given
522  * variable value.
523  *
524  * Returns the value or NULL if not found
525  */
526 xmlXPathObjectPtr
527 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
528                    const xmlChar *ns_uri) {
529     xsltStackElemPtr elem;
530
531     if (ctxt == NULL)
532         return(NULL);
533
534     elem = xsltStackLookup(ctxt, name, ns_uri);
535     if (elem == NULL) {
536         return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
537     }
538     if (!elem->computed) {
539 #ifdef DEBUG_VARIABLE
540         xsltGenericDebug(xsltGenericDebugContext,
541                          "uncomputed variable %s\n", name);
542 #endif
543         xsltEvalVariables(ctxt, elem);
544     }
545     if (elem->value != NULL)
546         return(xmlXPathObjectCopy(elem->value));
547 #ifdef DEBUG_VARIABLE
548     xsltGenericDebug(xsltGenericDebugContext,
549                      "variable not found %s\n", name);
550 #endif
551     return(NULL);
552 }
553
554 /**
555  * xsltParseStylesheetParam:
556  * @ctxt:  the XSLT transformation context
557  * @cur:  the "param" element
558  *
559  * parse an XSLT transformation param declaration and record
560  * its value.
561  */
562
563 void
564 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
565     xmlChar *name, *ncname, *prefix;
566     xmlChar *select;
567     xmlNodePtr tree = NULL;
568
569     if ((cur == NULL) || (ctxt == NULL))
570         return;
571
572     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
573     if (name == NULL) {
574         xsltGenericError(xsltGenericErrorContext,
575             "xsl:param : missing name attribute\n");
576         return;
577     }
578
579 #ifdef DEBUG_VARIABLE
580     xsltGenericDebug(xsltGenericDebugContext,
581         "Parsing param %s\n", name);
582 #endif
583
584     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
585     if (select == NULL) {
586         tree = cur->children;
587     } else {
588 #ifdef DEBUG_VARIABLE
589         xsltGenericDebug(xsltGenericDebugContext,
590             "        select %s\n", select);
591 #endif
592         if (cur->children != NULL)
593             xsltGenericError(xsltGenericErrorContext,
594             "xsl:param : content shuld be empty since select is present \n");
595     }
596
597     ncname = xmlSplitQName2(name, &prefix);
598
599     if (ncname != NULL) {
600         if (prefix != NULL) {
601             xmlNsPtr ns;
602
603             ns = xmlSearchNs(cur->doc, cur, prefix);
604             if (ns == NULL) {
605                 xsltGenericError(xsltGenericErrorContext,
606                     "xsl:param : no namespace bound to prefix %s\n", prefix);
607             } else {
608                 xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 1);
609             }
610             xmlFree(prefix);
611         } else {
612             xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 1);
613         }
614         xmlFree(ncname);
615     } else {
616         xsltRegisterVariable(ctxt, name, NULL, select, tree, 1);
617     }
618
619     xmlFree(name);
620     if (select != NULL)
621         xmlFree(select);
622
623 }
624
625 /**
626  * xsltParseGlobalVariable:
627  * @style:  the XSLT stylesheet
628  * @cur:  the "variable" element
629  *
630  * parse an XSLT transformation variable declaration and record
631  * its value.
632  */
633
634 void
635 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
636     xmlChar *name, *ncname, *prefix;
637     xmlChar *select;
638     xmlNodePtr tree = NULL;
639
640     if ((cur == NULL) || (style == NULL))
641         return;
642
643     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
644     if (name == NULL) {
645         xsltGenericError(xsltGenericErrorContext,
646             "xsl:variable : missing name attribute\n");
647         return;
648     }
649
650 #ifdef DEBUG_VARIABLE
651     xsltGenericDebug(xsltGenericDebugContext,
652         "Parsing global variable %s\n", name);
653 #endif
654
655     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
656     if (select == NULL) {
657         tree = cur->children;
658     } else {
659         if (cur->children != NULL)
660             xsltGenericError(xsltGenericErrorContext,
661             "xsl:variable : content shuld be empty since select is present \n");
662     }
663
664     ncname = xmlSplitQName2(name, &prefix);
665
666     if (ncname != NULL) {
667         if (prefix != NULL) {
668             xmlNsPtr ns;
669
670             ns = xmlSearchNs(cur->doc, cur, prefix);
671             if (ns == NULL) {
672                 xsltGenericError(xsltGenericErrorContext,
673                     "xsl:variable : no namespace bound to prefix %s\n", prefix);
674             } else {
675                 xsltRegisterGlobalVariable(style, ncname, ns->href, select, tree, 0);
676             }
677             xmlFree(prefix);
678         } else {
679             xsltRegisterGlobalVariable(style, ncname, NULL, select, tree, 0);
680         }
681         xmlFree(ncname);
682     } else {
683         xsltRegisterGlobalVariable(style, name, NULL, select, tree, 0);
684     }
685
686     xmlFree(name);
687     if (select != NULL)
688         xmlFree(select);
689
690 }
691
692 /**
693  * xsltParseGlobalParam:
694  * @style:  the XSLT stylesheet
695  * @cur:  the "param" element
696  *
697  * parse an XSLT transformation param declaration and record
698  * its value.
699  */
700
701 void
702 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
703     xmlChar *name, *ncname, *prefix;
704     xmlChar *select;
705     xmlNodePtr tree = NULL;
706
707     if ((cur == NULL) || (style == NULL))
708         return;
709
710     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
711     if (name == NULL) {
712         xsltGenericError(xsltGenericErrorContext,
713             "xsl:param : missing name attribute\n");
714         return;
715     }
716
717 #ifdef DEBUG_VARIABLE
718     xsltGenericDebug(xsltGenericDebugContext,
719         "Parsing global param %s\n", name);
720 #endif
721
722     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
723     if (select == NULL) {
724         tree = cur->children;
725     } else {
726         if (cur->children != NULL)
727             xsltGenericError(xsltGenericErrorContext,
728             "xsl:param : content shuld be empty since select is present \n");
729     }
730
731     ncname = xmlSplitQName2(name, &prefix);
732
733     if (ncname != NULL) {
734         if (prefix != NULL) {
735             xmlNsPtr ns;
736
737             ns = xmlSearchNs(cur->doc, cur, prefix);
738             if (ns == NULL) {
739                 xsltGenericError(xsltGenericErrorContext,
740                     "xsl:param : no namespace bound to prefix %s\n", prefix);
741             } else {
742                 xsltRegisterGlobalVariable(style, ncname, ns->href, select, tree, 1);
743             }
744             xmlFree(prefix);
745         } else {
746             xsltRegisterGlobalVariable(style, ncname, NULL, select, tree, 1);
747         }
748         xmlFree(ncname);
749     } else {
750         xsltRegisterGlobalVariable(style, name, NULL, select, tree, 1);
751     }
752
753     xmlFree(name);
754     if (select != NULL)
755         xmlFree(select);
756 }
757
758 /**
759  * xsltParseStylesheetVariable:
760  * @ctxt:  the XSLT transformation context
761  * @cur:  the "variable" element
762  *
763  * parse an XSLT transformation variable declaration and record
764  * its value.
765  */
766
767 void
768 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
769     xmlChar *name, *ncname, *prefix;
770     xmlChar *select;
771     xmlNodePtr tree = NULL;
772
773     if ((cur == NULL) || (ctxt == NULL))
774         return;
775
776     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
777     if (name == NULL) {
778         xsltGenericError(xsltGenericErrorContext,
779             "xsl:variable : missing name attribute\n");
780         return;
781     }
782
783 #ifdef DEBUG_VARIABLE
784     xsltGenericDebug(xsltGenericDebugContext,
785         "Parsing variable %s\n", name);
786 #endif
787
788     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
789     if (select == NULL) {
790         tree = cur->children;
791     } else {
792         if (cur->children != NULL)
793             xsltGenericError(xsltGenericErrorContext,
794         "xsl:variable : content should be empty since select is present \n");
795     }
796
797     ncname = xmlSplitQName2(name, &prefix);
798
799     if (ncname != NULL) {
800         if (prefix != NULL) {
801             xmlNsPtr ns;
802
803             ns = xmlSearchNs(cur->doc, cur, prefix);
804             if (ns == NULL) {
805                 xsltGenericError(xsltGenericErrorContext,
806                     "xsl:variable : no namespace bound to prefix %s\n", prefix);
807             } else {
808                 xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 0);
809             }
810             xmlFree(prefix);
811         } else {
812             xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 0);
813         }
814         xmlFree(ncname);
815     } else {
816         xsltRegisterVariable(ctxt, name, NULL, select, tree, 0);
817     }
818
819     xmlFree(name);
820     if (select != NULL)
821         xmlFree(select);
822
823 }
824
825 /**
826  * xsltVariableLookup:
827  * @ctxt:  a void * but the the XSLT transformation context actually
828  * @name:  the variable name
829  * @ns_uri:  the variable namespace URI
830  *
831  * This is the entry point when a varibale is needed by the XPath
832  * interpretor.
833  *
834  * Returns the value or NULL if not found
835  */
836 xmlXPathObjectPtr
837 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
838                         const xmlChar *ns_uri) {
839     xsltTransformContextPtr context;
840     xmlXPathObjectPtr ret;
841
842     if ((ctxt == NULL) || (name == NULL))
843         return(NULL);
844
845 #ifdef DEBUG_VARIABLE
846     xsltGenericDebug(xsltGenericDebugContext,
847             "Lookup variable %s\n", name);
848 #endif
849     context = (xsltTransformContextPtr) ctxt;
850     ret = xsltVariableLookup(context, name, ns_uri);
851     if (ret == NULL) {
852         xsltGenericError(xsltGenericErrorContext,
853             "unregistered variable %s\n", name);
854     }
855 #ifdef DEBUG_VARIABLE
856     if (ret != NULL)
857         xsltGenericDebug(xsltGenericDebugContext,
858             "found variable %s\n", name);
859 #endif
860     return(ret);
861 }
862