- libxslt/keys.c libxslt/preproc.c libxslt/templates.c
[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 int     oldProximityPosition, oldContextSize;
248     if ((ctxt == NULL) || (elem == NULL))
249         return(-1);
250
251 #ifdef DEBUG_VARIABLE
252     xsltGenericDebug(xsltGenericDebugContext,
253         "Evaluating variable %s\n", elem->name);
254 #endif
255     if (elem->select != NULL) {
256         xmlXPathCompExprPtr comp;
257         xmlXPathObjectPtr result;
258
259         comp = xmlXPathCompile(elem->select);
260         if (comp == NULL)
261             return(-1);
262         oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
263         oldContextSize = ctxt->xpathCtxt->contextSize;
264         ctxt->xpathCtxt->node = (xmlNodePtr) ctxt->node;
265         /* TODO: do we need to propagate the namespaces here ? */
266         ctxt->xpathCtxt->namespaces = NULL;
267         ctxt->xpathCtxt->nsNr = 0;
268         result = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
269         ctxt->xpathCtxt->contextSize = oldContextSize;
270         ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
271         xmlXPathFreeCompExpr(comp);
272         if (result == NULL) {
273             xsltGenericError(xsltGenericErrorContext,
274                 "Evaluating variable %s failed\n", elem->name);
275         } else {
276 #ifdef DEBUG_VARIABLE
277 #ifdef LIBXML_DEBUG_ENABLED
278             if ((xsltGenericDebugContext == stdout) ||
279                 (xsltGenericDebugContext == stderr))
280                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
281                                         result, 0);
282 #endif
283 #endif
284             if (elem->value != NULL)
285                 xmlXPathFreeObject(elem->value);
286             elem->value = result;
287         }
288         elem->computed = 1;
289     } else {
290         if (elem->tree == NULL) {
291             elem->value = xmlXPathNewCString("");
292         } else {
293             /*
294              * This is a result tree fragment.
295              */
296             xmlNodePtr container;
297             xmlNodePtr oldInsert, oldNode;
298
299             container = xmlNewDocNode(ctxt->output, NULL,
300                                       (const xmlChar *) "fake", NULL);
301             if (container == NULL)
302                 return(-1);
303
304             oldInsert = ctxt->insert;
305             oldNode = ctxt->node;
306             ctxt->insert = container;
307             xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, 0);
308             ctxt->insert = oldInsert;
309             ctxt->node = oldNode;
310
311             if (elem->value != NULL)
312                 xmlXPathFreeObject(elem->value);
313             elem->value = xmlXPathNewValueTree(container);
314             if (elem->value == NULL) {
315                 elem->value = xmlXPathNewCString("");
316             }
317 #ifdef DEBUG_VARIABLE
318 #ifdef LIBXML_DEBUG_ENABLED
319             if ((xsltGenericDebugContext == stdout) ||
320                 (xsltGenericDebugContext == stderr))
321                 xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
322                                         elem->value, 0);
323 #endif
324 #endif
325         }
326         elem->computed = 1;
327     }
328     return(0);
329 }
330
331 /**
332  * xsltEvalGlobalVariables:
333  * @ctxt:  the XSLT transformation context
334  *
335  * Evaluate the global variables of a stylesheet. This need to be
336  * done on parsed stylesheets before starting to apply transformations
337  *
338  * Returns 0 in case of success, -1 in case of error
339  */
340 int
341 xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
342     xsltStackElemPtr elem;
343     xsltStylesheetPtr style;
344
345     if (ctxt == NULL)
346         return(-1);
347  
348 #ifdef DEBUG_VARIABLE
349     xsltGenericDebug(xsltGenericDebugContext,
350         "Evaluating global variables\n");
351 #endif
352     ctxt->node = (xmlNodePtr) ctxt->document->doc;
353     style = ctxt->style;
354     while (style != NULL) {
355         elem = style->variables;
356         
357         while (elem != NULL) {
358             if (elem->computed == 0)
359                 xsltEvalVariable(ctxt, elem);
360             elem = elem->next;
361         }
362
363         style = xsltNextImport(style);
364     }
365     return(0);
366 }
367
368 /**
369  * xsltRegisterGlobalVariable:
370  * @style:  the XSLT transformation context
371  * @name:  the variable name
372  * @ns_uri:  the variable namespace URI
373  * @select:  the expression which need to be evaluated to generate a value
374  * @tree:  the subtree if select is NULL
375  * @param:  this is a parameter actually
376  * @value:  the string value if available
377  *
378  * Register a new variable value. If @value is NULL it unregisters
379  * the variable
380  *
381  * Returns 0 in case of success, -1 in case of error
382  */
383 static int
384 xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
385                      const xmlChar *ns_uri, const xmlChar *select,
386                      xmlNodePtr tree, int param, const xmlChar *value) {
387     xsltStackElemPtr elem;
388     if (style == NULL)
389         return(-1);
390     if (name == NULL)
391         return(-1);
392
393 #ifdef DEBUG_VARIABLE
394     if (param)
395         xsltGenericDebug(xsltGenericDebugContext,
396                          "Defining global param %s\n", name);
397     else
398         xsltGenericDebug(xsltGenericDebugContext,
399                          "Defining global variable %s\n", name);
400 #endif
401     elem = xsltNewStackElem();
402     if (elem == NULL)
403         return(-1);
404     if (param)
405         elem->type = XSLT_ELEM_PARAM;
406     else
407         elem->type = XSLT_ELEM_VARIABLE;
408     elem->name = xmlStrdup(name);
409     elem->select = xmlStrdup(select);
410     if (ns_uri)
411         elem->nameURI = xmlStrdup(ns_uri);
412     elem->tree = tree;
413     elem->next = style->variables;
414     style->variables = elem;
415     if (value != NULL) {
416         elem->computed = 1;
417         elem->value = xmlXPathNewString(value);
418     }
419     return(0);
420 }
421
422 /**
423  * xsltEvalUserParams:
424  * @ctxt:  the XSLT transformation context
425  * @params:  a NULL terminated arry of parameters names/values tuples
426  *
427  * Evaluate the global variables of a stylesheet. This need to be
428  * done on parsed stylesheets before starting to apply transformations
429  *
430  * Returns 0 in case of success, -1 in case of error
431  */
432 int
433 xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
434     xsltStylesheetPtr style;
435     int indx = 0;
436     const xmlChar *name;
437     const xmlChar *value;
438     xmlChar *ncname, *prefix;
439
440     if (ctxt == NULL)
441         return(-1);
442     if (params == NULL)
443         return(0);
444  
445     style = ctxt->style;
446     while (params[indx] != NULL) {
447         name = (const xmlChar *)params[indx++];
448         value = (const xmlChar *)params[indx++];
449         if ((name == NULL) || (value == NULL))
450             break;
451
452 #ifdef DEBUG_VARIABLE
453         xsltGenericDebug(xsltGenericDebugContext,
454             "Evaluating user parameter %s=%s\n", name, value);
455 #endif
456         ncname = xmlSplitQName2(name, &prefix);
457         if (ncname != NULL) {
458             if (prefix != NULL) {
459                 xmlNsPtr ns;
460
461                 ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
462                                  prefix);
463                 if (ns == NULL) {
464                     xsltGenericError(xsltGenericErrorContext,
465                         "user param : no namespace bound to prefix %s\n", prefix);
466                 } else {
467                     xsltRegisterGlobalVariable(style, ncname, ns->href, NULL,
468                                                NULL, 1, value);
469                 }
470                 xmlFree(prefix);
471             } else {
472                 xsltRegisterGlobalVariable(style, ncname, NULL, NULL, NULL,
473                                            1, value);
474             }
475             xmlFree(ncname);
476         } else {
477             xsltRegisterGlobalVariable(style, name, NULL, NULL, NULL, 1, value);
478         }
479
480     }
481
482     return(0);
483 }
484
485 /**
486  * xsltBuildVariable:
487  * @ctxt:  the XSLT transformation context
488  * @name:  the variable name
489  * @ns_uri:  the variable namespace URI
490  * @select:  the expression which need to be evaluated to generate a value
491  * @tree:  the tree if select is NULL
492  * @param:  this is a parameter actually
493  *
494  * Computes a new variable value.
495  *
496  * Returns the xsltStackElemPtr or NULL in case of error
497  */
498 static xsltStackElemPtr
499 xsltBuildVariable(xsltTransformContextPtr ctxt, const xmlChar *name,
500                      const xmlChar *ns_uri, const xmlChar *select,
501                      xmlNodePtr tree, int param) {
502     xsltStackElemPtr elem;
503     if (ctxt == NULL)
504         return(NULL);
505     if (name == NULL)
506         return(NULL);
507
508 #ifdef DEBUG_VARIABLE
509     xsltGenericDebug(xsltGenericDebugContext,
510                      "Building variable %s", name);
511     if (select != NULL)
512         xsltGenericDebug(xsltGenericDebugContext,
513                          " select %s",  select);
514     xsltGenericDebug(xsltGenericDebugContext, "\n");
515 #endif
516     elem = xsltNewStackElem();
517     if (elem == NULL)
518         return(NULL);
519     if (param)
520         elem->type = XSLT_ELEM_PARAM;
521     else
522         elem->type = XSLT_ELEM_VARIABLE;
523     elem->name = xmlStrdup(name);
524     if (select != NULL)
525         elem->select = xmlStrdup(select);
526     else
527         elem->select = NULL;
528     if (ns_uri)
529         elem->nameURI = xmlStrdup(ns_uri);
530     elem->tree = tree;
531     xsltEvalVariable(ctxt, elem);
532     return(elem);
533 }
534
535 /**
536  * xsltRegisterVariable:
537  * @ctxt:  the XSLT transformation context
538  * @name:  the variable name
539  * @ns_uri:  the variable namespace URI
540  * @select:  the expression which need to be evaluated to generate a value
541  * @tree:  the tree if select is NULL
542  * @param:  this is a parameter actually
543  *
544  * Computes and register a new variable value. 
545  *
546  * Returns 0 in case of success, -1 in case of error
547  */
548 int
549 xsltRegisterVariable(xsltTransformContextPtr ctxt, const xmlChar *name,
550                      const xmlChar *ns_uri, const xmlChar *select,
551                      xmlNodePtr tree, int param) {
552     xsltStackElemPtr elem;
553     if (ctxt == NULL)
554         return(-1);
555     if (name == NULL)
556         return(-1);
557
558     if (xsltCheckStackElem(ctxt, name, ns_uri) != 0) {
559         if (!param) {
560             xsltGenericError(xsltGenericErrorContext,
561             "xsl:variable : redefining %s\n", name);
562         }
563 #ifdef DEBUG_VARIABLE
564         else
565             xsltGenericDebug(xsltGenericDebugContext,
566                      "param %s defined by caller", name);
567 #endif
568         return(0);
569     }
570     elem = xsltBuildVariable(ctxt, name, ns_uri, select, tree, param);
571     xsltAddStackElem(ctxt, elem);
572     return(0);
573 }
574
575 /**
576  * xsltGlobalVariableLookup:
577  * @ctxt:  the XSLT transformation context
578  * @name:  the variable name
579  * @ns_uri:  the variable namespace URI
580  *
581  * Search in the Variable array of the context for the given
582  * variable value.
583  *
584  * Returns the value or NULL if not found
585  */
586 static xmlXPathObjectPtr
587 xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
588                          const xmlChar *ns_uri) {
589     xsltStylesheetPtr style;
590     xsltStackElemPtr elem = NULL;
591
592     style = ctxt->style;
593     while (style != NULL) {
594         elem = style->variables;
595         
596         while (elem != NULL) {
597             if (xmlStrEqual(elem->name, name)) {
598                 if (ns_uri == NULL) {
599                     if (elem->nameURI == NULL)
600                         break;
601                 } else {
602                     if ((elem->nameURI != NULL) &&
603                         (xmlStrEqual(elem->nameURI, ns_uri)))
604                         break;
605                 }
606
607             }
608             elem = elem->next;
609         }
610         if (elem != NULL) break;
611
612         style = xsltNextImport(style);
613     }
614     if (elem == NULL)
615         return(NULL);
616
617     if (!elem->computed) {
618 #ifdef DEBUG_VARIABLE
619         xsltGenericDebug(xsltGenericDebugContext,
620                          "uncomputed global variable %s\n", name);
621 #endif
622         xsltEvalVariable(ctxt, elem);
623     }
624     if (elem->value != NULL)
625         return(xmlXPathObjectCopy(elem->value));
626 #ifdef DEBUG_VARIABLE
627     xsltGenericDebug(xsltGenericDebugContext,
628                      "global variable not found %s\n", name);
629 #endif
630     return(NULL);
631 }
632
633 /**
634  * xsltVariableLookup:
635  * @ctxt:  the XSLT transformation context
636  * @name:  the variable name
637  * @ns_uri:  the variable namespace URI
638  *
639  * Search in the Variable array of the context for the given
640  * variable value.
641  *
642  * Returns the value or NULL if not found
643  */
644 xmlXPathObjectPtr
645 xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
646                    const xmlChar *ns_uri) {
647     xsltStackElemPtr elem;
648
649     if (ctxt == NULL)
650         return(NULL);
651
652     elem = xsltStackLookup(ctxt, name, ns_uri);
653     if (elem == NULL) {
654         return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
655     }
656     if (!elem->computed) {
657 #ifdef DEBUG_VARIABLE
658         xsltGenericDebug(xsltGenericDebugContext,
659                          "uncomputed variable %s\n", name);
660 #endif
661         xsltEvalVariable(ctxt, elem);
662     }
663     if (elem->value != NULL)
664         return(xmlXPathObjectCopy(elem->value));
665 #ifdef DEBUG_VARIABLE
666     xsltGenericDebug(xsltGenericDebugContext,
667                      "variable not found %s\n", name);
668 #endif
669     return(NULL);
670 }
671
672 /**
673  * xsltParseStylesheetCallerParam:
674  * @ctxt:  the XSLT transformation context
675  * @cur:  the "param" element
676  *
677  * parse an XSLT transformation param declaration, compute
678  * its value but doesn't record it.
679  *
680  * It returns the new xsltStackElemPtr or NULL
681  */
682
683 xsltStackElemPtr
684 xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
685     xmlChar *name, *ncname, *prefix;
686     xmlChar *select;
687     xmlNodePtr tree = NULL;
688     xsltStackElemPtr elem = NULL;
689
690     if ((cur == NULL) || (ctxt == NULL))
691         return(NULL);
692
693     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
694     if (name == NULL) {
695         xsltGenericError(xsltGenericErrorContext,
696             "xsl:param : missing name attribute\n");
697         return(NULL);
698     }
699
700 #ifdef DEBUG_VARIABLE
701     xsltGenericDebug(xsltGenericDebugContext,
702         "Parsing param %s\n", name);
703 #endif
704
705     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
706     if (select == NULL) {
707         tree = cur->children;
708     } else {
709 #ifdef DEBUG_VARIABLE
710         xsltGenericDebug(xsltGenericDebugContext,
711             "        select %s\n", select);
712 #endif
713         if (cur->children != NULL)
714             xsltGenericError(xsltGenericErrorContext,
715             "xsl:param : content shuld be empty since select is present \n");
716     }
717
718     ncname = xmlSplitQName2(name, &prefix);
719
720     if (ncname != NULL) {
721         if (prefix != NULL) {
722             xmlNsPtr ns;
723
724             ns = xmlSearchNs(cur->doc, cur, prefix);
725             if (ns == NULL) {
726                 xsltGenericError(xsltGenericErrorContext,
727                     "xsl:param : no namespace bound to prefix %s\n", prefix);
728             } else {
729                 elem = xsltBuildVariable(ctxt, ncname, ns->href, select,
730                                          tree, 1);
731             }
732             xmlFree(prefix);
733         } else {
734             elem = xsltBuildVariable(ctxt, ncname, NULL, select, tree, 1);
735         }
736         xmlFree(ncname);
737     } else {
738         elem = xsltBuildVariable(ctxt, name, NULL, select, tree, 1);
739     }
740
741     xmlFree(name);
742     if (select != NULL)
743         xmlFree(select);
744     return(elem);
745 }
746
747 /**
748  * xsltParseStylesheetParam:
749  * @ctxt:  the XSLT transformation context
750  * @cur:  the "param" element
751  *
752  * parse an XSLT transformation param declaration and record
753  * its value.
754  */
755
756 void
757 xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
758     xmlChar *name, *ncname, *prefix;
759     xmlChar *select;
760     xmlNodePtr tree = NULL;
761
762     if ((cur == NULL) || (ctxt == NULL))
763         return;
764
765     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
766     if (name == NULL) {
767         xsltGenericError(xsltGenericErrorContext,
768             "xsl:param : missing name attribute\n");
769         return;
770     }
771
772 #ifdef DEBUG_VARIABLE
773     xsltGenericDebug(xsltGenericDebugContext,
774         "Parsing param %s\n", name);
775 #endif
776
777     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
778     if (select == NULL) {
779         tree = cur->children;
780     } else {
781 #ifdef DEBUG_VARIABLE
782         xsltGenericDebug(xsltGenericDebugContext,
783             "        select %s\n", select);
784 #endif
785         if (cur->children != NULL)
786             xsltGenericError(xsltGenericErrorContext,
787             "xsl:param : content shuld be empty since select is present \n");
788     }
789
790     ncname = xmlSplitQName2(name, &prefix);
791
792     if (ncname != NULL) {
793         if (prefix != NULL) {
794             xmlNsPtr ns;
795
796             ns = xmlSearchNs(cur->doc, cur, prefix);
797             if (ns == NULL) {
798                 xsltGenericError(xsltGenericErrorContext,
799                     "xsl:param : no namespace bound to prefix %s\n", prefix);
800             } else {
801                 xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 1);
802             }
803             xmlFree(prefix);
804         } else {
805             xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 1);
806         }
807         xmlFree(ncname);
808     } else {
809         xsltRegisterVariable(ctxt, name, NULL, select, tree, 1);
810     }
811
812     xmlFree(name);
813     if (select != NULL)
814         xmlFree(select);
815
816 }
817
818 /**
819  * xsltParseGlobalVariable:
820  * @style:  the XSLT stylesheet
821  * @cur:  the "variable" element
822  *
823  * parse an XSLT transformation variable declaration and record
824  * its value.
825  */
826
827 void
828 xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) {
829     xmlChar *name, *ncname, *prefix;
830     xmlChar *select;
831     xmlNodePtr tree = NULL;
832
833     if ((cur == NULL) || (style == NULL))
834         return;
835
836     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
837     if (name == NULL) {
838         xsltGenericError(xsltGenericErrorContext,
839             "xsl:variable : missing name attribute\n");
840         return;
841     }
842
843 #ifdef DEBUG_VARIABLE
844     xsltGenericDebug(xsltGenericDebugContext,
845         "Parsing global variable %s\n", name);
846 #endif
847
848     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
849     if (select == NULL) {
850         tree = cur->children;
851     } else {
852         if (cur->children != NULL)
853             xsltGenericError(xsltGenericErrorContext,
854             "xsl:variable : content shuld be empty since select is present \n");
855     }
856
857     ncname = xmlSplitQName2(name, &prefix);
858
859     if (ncname != NULL) {
860         if (prefix != NULL) {
861             xmlNsPtr ns;
862
863             ns = xmlSearchNs(cur->doc, cur, prefix);
864             if (ns == NULL) {
865                 xsltGenericError(xsltGenericErrorContext,
866                     "xsl:variable : no namespace bound to prefix %s\n", prefix);
867             } else {
868                 xsltRegisterGlobalVariable(style, ncname, ns->href, select,
869                                            tree, 0, NULL);
870             }
871             xmlFree(prefix);
872         } else {
873             xsltRegisterGlobalVariable(style, ncname, NULL, select, tree,
874                                        0, NULL);
875         }
876         xmlFree(ncname);
877     } else {
878         xsltRegisterGlobalVariable(style, name, NULL, select, tree, 0, NULL);
879     }
880
881     xmlFree(name);
882     if (select != NULL)
883         xmlFree(select);
884
885 }
886
887 /**
888  * xsltParseGlobalParam:
889  * @style:  the XSLT stylesheet
890  * @cur:  the "param" element
891  *
892  * parse an XSLT transformation param declaration and record
893  * its value.
894  */
895
896 void
897 xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
898     xmlChar *name, *ncname, *prefix;
899     xmlChar *select;
900     xmlNodePtr tree = NULL;
901
902     if ((cur == NULL) || (style == NULL))
903         return;
904
905     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
906     if (name == NULL) {
907         xsltGenericError(xsltGenericErrorContext,
908             "xsl:param : missing name attribute\n");
909         return;
910     }
911
912 #ifdef DEBUG_VARIABLE
913     xsltGenericDebug(xsltGenericDebugContext,
914         "Parsing global param %s\n", name);
915 #endif
916
917     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
918     if (select == NULL) {
919         tree = cur->children;
920     } else {
921         if (cur->children != NULL)
922             xsltGenericError(xsltGenericErrorContext,
923             "xsl:param : content shuld be empty since select is present \n");
924     }
925
926     ncname = xmlSplitQName2(name, &prefix);
927
928     if (ncname != NULL) {
929         if (prefix != NULL) {
930             xmlNsPtr ns;
931
932             ns = xmlSearchNs(cur->doc, cur, prefix);
933             if (ns == NULL) {
934                 xsltGenericError(xsltGenericErrorContext,
935                     "xsl:param : no namespace bound to prefix %s\n", prefix);
936             } else {
937                 xsltRegisterGlobalVariable(style, ncname, ns->href, select,
938                                            tree, 1, NULL);
939             }
940             xmlFree(prefix);
941         } else {
942             xsltRegisterGlobalVariable(style, ncname, NULL, select, tree,
943                                        1, NULL);
944         }
945         xmlFree(ncname);
946     } else {
947         xsltRegisterGlobalVariable(style, name, NULL, select, tree, 1, NULL);
948     }
949
950     xmlFree(name);
951     if (select != NULL)
952         xmlFree(select);
953 }
954
955 /**
956  * xsltParseStylesheetVariable:
957  * @ctxt:  the XSLT transformation context
958  * @cur:  the "variable" element
959  *
960  * parse an XSLT transformation variable declaration and record
961  * its value.
962  */
963
964 void
965 xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
966     xmlChar *name, *ncname, *prefix;
967     xmlChar *select;
968     xmlNodePtr tree = NULL;
969
970     if ((cur == NULL) || (ctxt == NULL))
971         return;
972
973     name = xmlGetNsProp(cur, (const xmlChar *)"name", XSLT_NAMESPACE);
974     if (name == NULL) {
975         xsltGenericError(xsltGenericErrorContext,
976             "xsl:variable : missing name attribute\n");
977         return;
978     }
979
980 #ifdef DEBUG_VARIABLE
981     xsltGenericDebug(xsltGenericDebugContext,
982         "Parsing variable %s\n", name);
983 #endif
984
985     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
986     if (select == NULL) {
987         tree = cur->children;
988     } else {
989         if (cur->children != NULL)
990             xsltGenericError(xsltGenericErrorContext,
991         "xsl:variable : content should be empty since select is present \n");
992     }
993
994     ncname = xmlSplitQName2(name, &prefix);
995
996     if (ncname != NULL) {
997         if (prefix != NULL) {
998             xmlNsPtr ns;
999
1000             ns = xmlSearchNs(cur->doc, cur, prefix);
1001             if (ns == NULL) {
1002                 xsltGenericError(xsltGenericErrorContext,
1003                     "xsl:variable : no namespace bound to prefix %s\n", prefix);
1004             } else {
1005                 xsltRegisterVariable(ctxt, ncname, ns->href, select, tree, 0);
1006             }
1007             xmlFree(prefix);
1008         } else {
1009             xsltRegisterVariable(ctxt, ncname, NULL, select, tree, 0);
1010         }
1011         xmlFree(ncname);
1012     } else {
1013         xsltRegisterVariable(ctxt, name, NULL, select, tree, 0);
1014     }
1015
1016     xmlFree(name);
1017     if (select != NULL)
1018         xmlFree(select);
1019
1020 }
1021
1022 /**
1023  * xsltVariableLookup:
1024  * @ctxt:  a void * but the the XSLT transformation context actually
1025  * @name:  the variable name
1026  * @ns_uri:  the variable namespace URI
1027  *
1028  * This is the entry point when a varibale is needed by the XPath
1029  * interpretor.
1030  *
1031  * Returns the value or NULL if not found
1032  */
1033 xmlXPathObjectPtr
1034 xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
1035                         const xmlChar *ns_uri) {
1036     xsltTransformContextPtr context;
1037     xmlXPathObjectPtr ret;
1038
1039     if ((ctxt == NULL) || (name == NULL))
1040         return(NULL);
1041
1042 #ifdef DEBUG_VARIABLE
1043     xsltGenericDebug(xsltGenericDebugContext,
1044             "Lookup variable %s\n", name);
1045 #endif
1046     context = (xsltTransformContextPtr) ctxt;
1047     ret = xsltVariableLookup(context, name, ns_uri);
1048     if (ret == NULL) {
1049         xsltGenericError(xsltGenericErrorContext,
1050             "unregistered variable %s\n", name);
1051     }
1052 #ifdef DEBUG_VARIABLE
1053     if (ret != NULL)
1054         xsltGenericDebug(xsltGenericDebugContext,
1055             "found variable %s\n", name);
1056 #endif
1057     return(ret);
1058 }
1059