52f22a7f62e43ab402ccea8abc71bf947e74e1ed
[platform/upstream/libxslt.git] / libxslt / preproc.c
1 /*
2  * preproc.c: Preprocessing of style operations
3  *
4  * References:
5  *   http://www.w3.org/TR/1999/REC-xslt-19991116
6  *
7  *   Michael Kay "XSLT Programmer's Reference" pp 637-643
8  *   Writing Multiple Output Files
9  *
10  *   XSLT-1.1 Working Draft
11  *   http://www.w3.org/TR/xslt11#multiple-output
12  *
13  * See Copyright for the status of this software.
14  *
15  * daniel@veillard.com
16  */
17
18 #include "libxslt.h"
19
20 #include <string.h>
21
22 #include <libxml/xmlmemory.h>
23 #include <libxml/parser.h>
24 #include <libxml/tree.h>
25 #include <libxml/valid.h>
26 #include <libxml/hash.h>
27 #include <libxml/uri.h>
28 #include <libxml/xmlerror.h>
29 #include "xslt.h"
30 #include "xsltutils.h"
31 #include "xsltInternals.h"
32 #include "transform.h"
33 #include "templates.h"
34 #include "variables.h"
35 #include "numbersInternals.h"
36 #include "preproc.h"
37 #include "extra.h"
38 #include "imports.h"
39 #include "extensions.h"
40
41 #ifdef WITH_XSLT_DEBUG
42 #define WITH_XSLT_DEBUG_PREPROC
43 #endif
44
45 const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element";
46
47 /************************************************************************
48  *                                                                      *
49  *                      handling of precomputed data                    *
50  *                                                                      *
51  ************************************************************************/
52
53 /**
54  * xsltNewStylePreComp:
55  * @style:  the XSLT stylesheet
56  * @type:  the construct type
57  *
58  * Create a new XSLT Style precomputed block
59  *
60  * Returns the newly allocated xsltStylePreCompPtr or NULL in case of error
61  */
62 static xsltStylePreCompPtr
63 xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) {
64     xsltStylePreCompPtr cur;
65
66     cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp));
67     if (cur == NULL) {
68         xsltPrintErrorContext(NULL, style, NULL);
69         xsltGenericError(xsltGenericErrorContext,
70                 "xsltNewStylePreComp : malloc failed\n");
71         style->errors++;
72         return(NULL);
73     }
74     memset(cur, 0, sizeof(xsltStylePreComp));
75
76     cur->type = type;
77     switch (cur->type) {
78         case XSLT_FUNC_COPY:
79             cur->func = (xsltTransformFunction) xsltCopy;break;
80         case XSLT_FUNC_SORT:
81             cur->func = (xsltTransformFunction) xsltSort;break;
82         case XSLT_FUNC_TEXT:
83             cur->func = (xsltTransformFunction) xsltText;break;
84         case XSLT_FUNC_ELEMENT:
85             cur->func = (xsltTransformFunction) xsltElement;break;
86         case XSLT_FUNC_ATTRIBUTE:
87             cur->func = (xsltTransformFunction) xsltAttribute;break;
88         case XSLT_FUNC_COMMENT:
89             cur->func = (xsltTransformFunction) xsltComment;break;
90         case XSLT_FUNC_PI:
91             cur->func = (xsltTransformFunction) xsltProcessingInstruction;
92             break;
93         case XSLT_FUNC_COPYOF:
94             cur->func = (xsltTransformFunction) xsltCopyOf;break;
95         case XSLT_FUNC_VALUEOF:
96             cur->func = (xsltTransformFunction) xsltValueOf;break;
97         case XSLT_FUNC_NUMBER:
98             cur->func = (xsltTransformFunction) xsltNumber;break;
99         case XSLT_FUNC_APPLYIMPORTS:
100             cur->func = (xsltTransformFunction) xsltApplyImports;break;
101         case XSLT_FUNC_CALLTEMPLATE:
102             cur->func = (xsltTransformFunction) xsltCallTemplate;break;
103         case XSLT_FUNC_APPLYTEMPLATES:
104             cur->func = (xsltTransformFunction) xsltApplyTemplates;break;
105         case XSLT_FUNC_CHOOSE:
106             cur->func = (xsltTransformFunction) xsltChoose;break;
107         case XSLT_FUNC_IF:
108             cur->func = (xsltTransformFunction) xsltIf;break;
109         case XSLT_FUNC_FOREACH:
110             cur->func = (xsltTransformFunction) xsltForEach;break;
111         case XSLT_FUNC_DOCUMENT:
112             cur->func = (xsltTransformFunction) xsltDocumentElem;break;
113         case XSLT_FUNC_WITHPARAM:
114             cur->func = NULL;break;
115         case XSLT_FUNC_PARAM:
116             cur->func = NULL;break;
117         case XSLT_FUNC_VARIABLE:
118             cur->func = NULL;break;
119         case XSLT_FUNC_WHEN:
120             cur->func = NULL;break;
121         default:
122         if (cur->func == NULL) {
123             xsltPrintErrorContext(NULL, style, NULL);
124             xsltGenericError(xsltGenericErrorContext,
125                     "xsltNewStylePreComp : no function for type %d\n", type);
126             style->errors++;
127         }
128     }
129     cur->next = style->preComps;
130     style->preComps = (xsltElemPreCompPtr) cur;
131
132     return(cur);
133 }
134
135 /**
136  * xsltFreeStylePreComp:
137  * @comp:  an XSLT Style precomputed block
138  *
139  * Free up the memory allocated by @comp
140  */
141 static void
142 xsltFreeStylePreComp(xsltStylePreCompPtr comp) {
143     if (comp == NULL)
144         return;
145     if (comp->stype != NULL)
146         xmlFree(comp->stype);
147     if (comp->order != NULL)
148         xmlFree(comp->order);
149     if (comp->use != NULL)
150         xmlFree(comp->use);
151     if (comp->name != NULL)
152         xmlFree(comp->name);
153     if (comp->ns != NULL)
154         xmlFree(comp->ns);
155     if (comp->mode != NULL)
156         xmlFree(comp->mode);
157     if (comp->modeURI != NULL)
158         xmlFree(comp->modeURI);
159     if (comp->test != NULL)
160         xmlFree(comp->test);
161     if (comp->select != NULL)
162         xmlFree(comp->select);
163
164     if (comp->filename != NULL)
165         xmlFree(comp->filename);
166
167     if (comp->numdata.level != NULL)
168         xmlFree(comp->numdata.level);
169     if (comp->numdata.count != NULL)
170         xmlFree(comp->numdata.count);
171     if (comp->numdata.from != NULL)
172         xmlFree(comp->numdata.from);
173     if (comp->numdata.value != NULL)
174         xmlFree(comp->numdata.value);
175     if (comp->numdata.format != NULL)
176         xmlFree(comp->numdata.format);
177     if (comp->comp != NULL)
178         xmlXPathFreeCompExpr(comp->comp);
179     if (comp->nsList != NULL)
180         xmlFree(comp->nsList);
181
182     xmlFree(comp);
183 }
184
185
186 /************************************************************************
187  *                                                                      *
188  *                  XSLT-1.1 extensions                                 *
189  *                                                                      *
190  ************************************************************************/
191
192 /**
193  * xsltDocumentComp:
194  * @style:  the XSLT stylesheet
195  * @inst:  the instruction in the stylesheet
196  *
197  * Pre process an XSLT-1.1 document element
198  */
199 xsltElemPreCompPtr
200 xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst,
201                  xsltTransformFunction function ATTRIBUTE_UNUSED) {
202     xsltStylePreCompPtr comp;
203     xmlChar *filename = NULL;
204     xmlChar *base = NULL;
205     xmlChar *URL = NULL;
206
207     comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);
208     if (comp == NULL)
209         return (NULL);
210     comp->inst = inst;
211     comp->ver11 = 0;
212
213     if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
214 #ifdef WITH_XSLT_DEBUG_EXTRA
215         xsltGenericDebug(xsltGenericDebugContext,
216             "Found saxon:output extension\n");
217 #endif
218         filename = xsltEvalStaticAttrValueTemplate(style, inst,
219                          (const xmlChar *)"file",
220                          XSLT_SAXON_NAMESPACE, &comp->has_filename);
221     } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
222 #ifdef WITH_XSLT_DEBUG_EXTRA
223         xsltGenericDebug(xsltGenericDebugContext,
224             "Found xalan:write extension\n");
225 #endif
226         comp->ver11 = 0; /* the filename need to be interpreted */
227     } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
228         filename = xsltEvalStaticAttrValueTemplate(style, inst,
229                          (const xmlChar *)"href",
230                          XSLT_XT_NAMESPACE, &comp->has_filename);
231         if (comp->has_filename == 0) {
232 #ifdef WITH_XSLT_DEBUG_EXTRA
233             xsltGenericDebug(xsltGenericDebugContext,
234                 "Found xslt11:document construct\n");
235 #endif
236             filename = xsltEvalStaticAttrValueTemplate(style, inst,
237                              (const xmlChar *)"href",
238                              XSLT_NAMESPACE, &comp->has_filename);
239             comp->ver11 = 1;
240         } else {
241 #ifdef WITH_XSLT_DEBUG_EXTRA
242             xsltGenericDebug(xsltGenericDebugContext,
243                 "Found xt:document extension\n");
244 #endif
245             comp->ver11 = 0;
246         }
247     }
248     if (!comp->has_filename) {
249         goto error;
250     }
251
252     if (filename != NULL) {
253         /*
254          * Compute output URL
255          */
256         base = xmlNodeGetBase(inst->doc, inst);
257         URL = xmlBuildURI(filename, base);
258         if (URL == NULL) {
259             xsltPrintErrorContext(NULL, style, inst);
260             xsltGenericError(xsltGenericErrorContext,
261                 "xsltDocumentComp: URL computation failed %s\n", filename);
262             style->warnings++;
263             comp->filename = xmlStrdup(filename);
264         } else {
265             comp->filename = URL;
266         }
267     } else {
268         comp->filename = NULL;
269     }
270
271 error:
272     if (base != NULL)
273         xmlFree(base);
274     if (filename != NULL)
275         xmlFree(filename);
276
277     return ((xsltElemPreCompPtr) comp);
278 }
279
280 /************************************************************************
281  *                                                                      *
282  *              Most of the XSLT-1.0 transformations                    *
283  *                                                                      *
284  ************************************************************************/
285
286 /**
287  * xsltSortComp:
288  * @style:  the XSLT stylesheet
289  * @inst:  the xslt sort node
290  *
291  * Process the xslt sort node on the source node
292  */
293 static void
294 xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) {
295     xsltStylePreCompPtr comp;
296
297
298     if ((style == NULL) || (inst == NULL))
299         return;
300     comp = xsltNewStylePreComp(style, XSLT_FUNC_SORT);
301     if (comp == NULL)
302         return;
303     inst->_private = comp;
304     comp->inst = inst;
305
306     comp->stype = xsltEvalStaticAttrValueTemplate(style, inst,
307                          (const xmlChar *)"data-type",
308                          XSLT_NAMESPACE, &comp->has_stype);
309     if (comp->stype != NULL) {
310         if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
311             comp->number = 0;
312         else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
313             comp->number = 1;
314         else {
315             xsltPrintErrorContext(NULL, style, inst);
316             xsltGenericError(xsltGenericErrorContext,
317                  "xsltSortComp: no support for data-type = %s\n", comp->stype);
318             comp->number = -1;
319             style->warnings++;
320         }
321     }
322     comp->order = xsltEvalStaticAttrValueTemplate(style, inst,
323                               (const xmlChar *)"order",
324                               XSLT_NAMESPACE, &comp->has_order);
325     if (comp->order != NULL) {
326         if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
327             comp->descending = 0;
328         else if (xmlStrEqual(comp->order, (const xmlChar *) "descending"))
329             comp->descending = 1;
330         else {
331             xsltPrintErrorContext(NULL, style, inst);
332             xsltGenericError(xsltGenericErrorContext,
333                  "xsltSortComp: invalid value %s for order\n", comp->order);
334             comp->descending = -1;
335             style->warnings++;
336         }
337     }
338     /* TODO: xsl:sort lang attribute */
339     /* TODO: xsl:sort case-order attribute */
340
341     comp->select = xsltGetNsProp(inst,(const xmlChar *)"select", XSLT_NAMESPACE);
342     if (comp->select == NULL) {
343         /*
344          * The default value of the select attribute is ., which will
345          * cause the string-value of the current node to be used as
346          * the sort key.
347          */
348         comp->select = xmlStrdup((const xmlChar *)".");
349     }
350     comp->comp = xmlXPathCompile(comp->select);
351     if (comp->comp == NULL) {
352         xsltPrintErrorContext(NULL, style, inst);
353         xsltGenericError(xsltGenericErrorContext,
354              "xsltSortComp: could not compile select expression '%s'\n",
355                          comp->select);
356         style->errors++;
357     }
358 }
359
360 /**
361  * xsltCopyComp:
362  * @style:  the XSLT stylesheet
363  * @inst:  the xslt copy node
364  *
365  * Process the xslt copy node on the source node
366  */
367 static void
368 xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) {
369     xsltStylePreCompPtr comp;
370
371
372     if ((style == NULL) || (inst == NULL))
373         return;
374     comp = xsltNewStylePreComp(style, XSLT_FUNC_COPY);
375     if (comp == NULL)
376         return;
377     inst->_private = comp;
378     comp->inst = inst;
379
380
381     comp->use = xsltGetNsProp(inst, (const xmlChar *)"use-attribute-sets",
382                                     XSLT_NAMESPACE);
383     if (comp->use == NULL)
384         comp->has_use = 0;
385     else
386         comp->has_use = 1;
387 }
388
389 /**
390  * xsltTextComp:
391  * @style:  a XSLT process context
392  * @inst:  the xslt text node
393  *
394  * Process the xslt text node on the source node
395  */
396 static void
397 xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) {
398     xsltStylePreCompPtr comp;
399     xmlChar *prop;
400
401     if ((style == NULL) || (inst == NULL))
402         return;
403     comp = xsltNewStylePreComp(style, XSLT_FUNC_TEXT);
404     if (comp == NULL)
405         return;
406     inst->_private = comp;
407     comp->inst = inst;
408     comp->noescape = 0;
409
410     prop = xsltGetNsProp(inst,
411             (const xmlChar *)"disable-output-escaping",
412                         XSLT_NAMESPACE);
413     if (prop != NULL) {
414         if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
415             comp->noescape = 1;
416         } else if (!xmlStrEqual(prop,
417                                 (const xmlChar *)"no")){
418             xsltPrintErrorContext(NULL, style, inst);
419             xsltGenericError(xsltGenericErrorContext,
420 "xsl:text: disable-output-escaping allows only yes or no\n");
421             style->warnings++;
422         }
423         xmlFree(prop);
424     }
425 }
426
427 /**
428  * xsltElementComp:
429  * @style:  a XSLT process context
430  * @inst:  the xslt element node
431  *
432  * Process the xslt element node on the source node
433  */
434 static void
435 xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) {
436     xsltStylePreCompPtr comp;
437
438     if ((style == NULL) || (inst == NULL))
439         return;
440     comp = xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);
441     if (comp == NULL)
442         return;
443     inst->_private = comp;
444     comp->inst = inst;
445
446     /*
447      * TODO: more computation can be done there, especially namespace lookup
448      */
449     comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
450                                  (const xmlChar *)"name",
451                                  XSLT_NAMESPACE, &comp->has_name);
452     comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
453                          (const xmlChar *)"namespace",
454                          XSLT_NAMESPACE, &comp->has_ns);
455
456     comp->use = xsltEvalStaticAttrValueTemplate(style, inst,
457                        (const xmlChar *)"use-attribute-sets",
458                        XSLT_NAMESPACE, &comp->has_use);
459 }
460
461 /**
462  * xsltAttributeComp:
463  * @style:  a XSLT process context
464  * @inst:  the xslt attribute node
465  *
466  * Process the xslt attribute node on the source node
467  */
468 static void
469 xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) {
470     xsltStylePreCompPtr comp;
471
472     if ((style == NULL) || (inst == NULL))
473         return;
474     comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE);
475     if (comp == NULL)
476         return;
477     inst->_private = comp;
478     comp->inst = inst;
479
480     /*
481      * TODO: more computation can be done there, especially namespace lookup
482      */
483     comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
484                                  (const xmlChar *)"name",
485                                  XSLT_NAMESPACE, &comp->has_name);
486     comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
487                          (const xmlChar *)"namespace",
488                          XSLT_NAMESPACE, &comp->has_ns);
489
490 }
491
492 /**
493  * xsltCommentComp:
494  * @style:  a XSLT process context
495  * @inst:  the xslt comment node
496  *
497  * Process the xslt comment node on the source node
498  */
499 static void
500 xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) {
501     xsltStylePreCompPtr comp;
502
503     if ((style == NULL) || (inst == NULL))
504         return;
505     comp = xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);
506     if (comp == NULL)
507         return;
508     inst->_private = comp;
509     comp->inst = inst;
510 }
511
512 /**
513  * xsltProcessingInstructionComp:
514  * @style:  a XSLT process context
515  * @inst:  the xslt processing-instruction node
516  *
517  * Process the xslt processing-instruction node on the source node
518  */
519 static void
520 xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) {
521     xsltStylePreCompPtr comp;
522
523     if ((style == NULL) || (inst == NULL))
524         return;
525     comp = xsltNewStylePreComp(style, XSLT_FUNC_PI);
526     if (comp == NULL)
527         return;
528     inst->_private = comp;
529     comp->inst = inst;
530
531     comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
532                                  (const xmlChar *)"name",
533                                  XSLT_NAMESPACE, &comp->has_name);
534 }
535
536 /**
537  * xsltCopyOfComp:
538  * @style:  a XSLT process context
539  * @inst:  the xslt copy-of node
540  *
541  * Process the xslt copy-of node on the source node
542  */
543 static void
544 xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
545     xsltStylePreCompPtr comp;
546
547     if ((style == NULL) || (inst == NULL))
548         return;
549     comp = xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);
550     if (comp == NULL)
551         return;
552     inst->_private = comp;
553     comp->inst = inst;
554
555     comp->select = xsltGetNsProp(inst, (const xmlChar *)"select",
556                                 XSLT_NAMESPACE);
557     if (comp->select == NULL) {
558         xsltPrintErrorContext(NULL, style, inst);
559         xsltGenericError(xsltGenericErrorContext,
560              "xsl:copy-of : select is missing\n");
561         style->errors++;
562         return;
563     }
564     comp->comp = xmlXPathCompile(comp->select);
565     if (comp->comp == NULL) {
566         xsltPrintErrorContext(NULL, style, inst);
567         xsltGenericError(xsltGenericErrorContext,
568              "xsl:copy-of : could not compile select expression '%s'\n",
569                          comp->select);
570         style->errors++;
571     }
572 }
573
574 /**
575  * xsltValueOfComp:
576  * @style:  a XSLT process context
577  * @inst:  the xslt value-of node
578  *
579  * Process the xslt value-of node on the source node
580  */
581 static void
582 xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
583     xsltStylePreCompPtr comp;
584     xmlChar *prop;
585
586     if ((style == NULL) || (inst == NULL))
587         return;
588     comp = xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);
589     if (comp == NULL)
590         return;
591     inst->_private = comp;
592     comp->inst = inst;
593
594     prop = xsltGetNsProp(inst,
595             (const xmlChar *)"disable-output-escaping",
596                         XSLT_NAMESPACE);
597     if (prop != NULL) {
598         if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
599             comp->noescape = 1;
600         } else if (!xmlStrEqual(prop,
601                                 (const xmlChar *)"no")){
602             xsltPrintErrorContext(NULL, style, inst);
603             xsltGenericError(xsltGenericErrorContext,
604 "xsl:value-of : disable-output-escaping allows only yes or no\n");
605             style->warnings++;
606         }
607         xmlFree(prop);
608     }
609     comp->select = xsltGetNsProp(inst, (const xmlChar *)"select",
610                                 XSLT_NAMESPACE);
611     if (comp->select == NULL) {
612         xsltPrintErrorContext(NULL, style, inst);
613         xsltGenericError(xsltGenericErrorContext,
614              "xsl:value-of : select is missing\n");
615         style->errors++;
616         return;
617     }
618     comp->comp = xmlXPathCompile(comp->select);
619     if (comp->comp == NULL) {
620         xsltPrintErrorContext(NULL, style, inst);
621         xsltGenericError(xsltGenericErrorContext,
622              "xsl:value-of : could not compile select expression '%s'\n",
623                          comp->select);
624         style->errors++;
625     }
626 }
627
628 /**
629  * xsltWithParamComp:
630  * @style:  a XSLT process context
631  * @inst:  the xslt with-param node
632  *
633  * Process the xslt with-param node on the source node
634  */
635 static void
636 xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
637     xsltStylePreCompPtr comp;
638     xmlChar *prop;
639
640     if ((style == NULL) || (inst == NULL))
641         return;
642     comp = xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);
643     if (comp == NULL)
644         return;
645     inst->_private = comp;
646     comp->inst = inst;
647
648     /*
649      * The full namespace resolution can be done statically
650      */
651     prop = xsltGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE);
652     if (prop == NULL) {
653         xsltPrintErrorContext(NULL, style, inst);
654         xsltGenericError(xsltGenericErrorContext,
655              "xsl:with-param : name is missing\n");
656         style->errors++;
657     } else {
658         const xmlChar *URI;
659
660         URI = xsltGetQNameURI(inst, &prop);
661         if (prop == NULL) {
662             style->errors++;
663         } else {
664             comp->name = prop;
665             comp->has_name = 1;
666             if (URI != NULL) {
667                 comp->ns = xmlStrdup(URI);
668                 comp->has_ns = 1;
669             } else {
670                 comp->has_ns = 0;
671             }
672         }
673     }
674
675     comp->select = xsltGetNsProp(inst, (const xmlChar *)"select",
676                                 XSLT_NAMESPACE);
677     if (comp->select != NULL) {
678         comp->comp = xmlXPathCompile(comp->select);
679         if (comp->comp == NULL) {
680             xsltPrintErrorContext(NULL, style, inst);
681             xsltGenericError(xsltGenericErrorContext,
682                  "xsl:param : could not compile select expression '%s'\n",
683                              comp->select);
684             style->errors++;
685         }
686         if (inst->children != NULL) {
687             xsltPrintErrorContext(NULL, style, inst);
688             xsltGenericError(xsltGenericErrorContext,
689             "xsl:param : content should be empty since select is present \n");
690             style->warnings++;
691         }
692     }
693 }
694
695 /**
696  * xsltNumberComp:
697  * @style:  a XSLT process context
698  * @cur:   the xslt number node
699  *
700  * Process the xslt number node on the source node
701  */
702 static void
703 xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) {
704     xsltStylePreCompPtr comp;
705     xmlChar *prop;
706
707     if ((style == NULL) || (cur == NULL))
708         return;
709     comp = xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);
710     if (comp == NULL)
711         return;
712     cur->_private = comp;
713
714     if ((style == NULL) || (cur == NULL))
715         return;
716
717     comp->numdata.doc = cur->doc;
718     comp->numdata.node = cur;
719     comp->numdata.value = xsltGetNsProp(cur, (const xmlChar *)"value",
720                                         XSLT_NAMESPACE);
721     
722     prop = xsltEvalStaticAttrValueTemplate(style, cur,
723                          (const xmlChar *)"format",
724                          XSLT_NAMESPACE, &comp->numdata.has_format);
725     if (comp->numdata.has_format == 0) {
726         comp->numdata.format = xmlStrdup(BAD_CAST(""));
727     } else {
728         comp->numdata.format = prop;
729     }
730
731     comp->numdata.count = xsltGetNsProp(cur, (const xmlChar *)"count",
732                                         XSLT_NAMESPACE);
733     comp->numdata.from = xsltGetNsProp(cur, (const xmlChar *)"from",
734                                         XSLT_NAMESPACE);
735     
736     prop = xsltGetNsProp(cur, (const xmlChar *)"level", XSLT_NAMESPACE);
737     if (prop != NULL) {
738         if (xmlStrEqual(prop, BAD_CAST("single")) ||
739             xmlStrEqual(prop, BAD_CAST("multiple")) ||
740             xmlStrEqual(prop, BAD_CAST("any"))) {
741             comp->numdata.level = prop;
742         } else {
743             xsltPrintErrorContext(NULL, style, cur);
744             xsltGenericError(xsltGenericErrorContext,
745                          "xsl:number : invalid value %s for level\n", prop);
746             style->warnings++;
747             xmlFree(prop);
748         }
749     }
750     
751     prop = xsltGetNsProp(cur, (const xmlChar *)"lang", XSLT_NAMESPACE);
752     if (prop != NULL) {
753         XSLT_TODO; /* xsl:number lang attribute */
754         xmlFree(prop);
755     }
756     
757     prop = xsltGetNsProp(cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE);
758     if (prop != NULL) {
759         if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) {
760             xsltPrintErrorContext(NULL, style, cur);
761             xsltGenericError(xsltGenericErrorContext,
762                  "xsl:number : letter-value 'alphabetic' not implemented\n");
763             style->warnings++;
764             XSLT_TODO; /* xsl:number letter-value attribute alphabetic */
765         } else if (xmlStrEqual(prop, BAD_CAST("traditional"))) {
766             xsltPrintErrorContext(NULL, style, cur);
767             xsltGenericError(xsltGenericErrorContext,
768                  "xsl:number : letter-value 'traditional' not implemented\n");
769             style->warnings++;
770             XSLT_TODO; /* xsl:number letter-value attribute traditional */
771         } else {
772             xsltPrintErrorContext(NULL, style, cur);
773             xsltGenericError(xsltGenericErrorContext,
774                      "xsl:number : invalid value %s for letter-value\n", prop);
775             style->warnings++;
776         }
777         xmlFree(prop);
778     }
779     
780     prop = xsltGetNsProp(cur, (const xmlChar *)"grouping-separator",
781                         XSLT_NAMESPACE);
782     if (prop != NULL) {
783         comp->numdata.groupingCharacter = prop[0];
784         xmlFree(prop);
785     }
786     
787     prop = xsltGetNsProp(cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE);
788     if (prop != NULL) {
789         sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup);
790         xmlFree(prop);
791     } else {
792         comp->numdata.groupingCharacter = 0;
793     }
794
795     /* Set default values */
796     if (comp->numdata.value == NULL) {
797         if (comp->numdata.level == NULL) {
798             comp->numdata.level = xmlStrdup(BAD_CAST("single"));
799         }
800     }
801     
802 }
803
804 /**
805  * xsltApplyImportsComp:
806  * @style:  a XSLT process context
807  * @inst:  the xslt apply-imports node
808  *
809  * Process the xslt apply-imports node on the source node
810  */
811 static void
812 xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) {
813     xsltStylePreCompPtr comp;
814
815     if ((style == NULL) || (inst == NULL))
816         return;
817     comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);
818     if (comp == NULL)
819         return;
820     inst->_private = comp;
821     comp->inst = inst;
822 }
823
824 /**
825  * xsltCallTemplateComp:
826  * @style:  a XSLT process context
827  * @inst:  the xslt call-template node
828  *
829  * Process the xslt call-template node on the source node
830  */
831 static void
832 xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) {
833     xsltStylePreCompPtr comp;
834     xmlChar *prop;
835
836     if ((style == NULL) || (inst == NULL))
837         return;
838     comp = xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);
839     if (comp == NULL)
840         return;
841     inst->_private = comp;
842     comp->inst = inst;
843
844     /*
845      * The full template resolution can be done statically
846      */
847     prop = xsltGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE);
848     if (prop == NULL) {
849         xsltPrintErrorContext(NULL, style, inst);
850         xsltGenericError(xsltGenericErrorContext,
851              "xsl:call-template : name is missing\n");
852         style->errors++;
853     } else {
854         const xmlChar *URI;
855
856         URI = xsltGetQNameURI(inst, &prop);
857         if (prop == NULL) {
858             style->errors++;
859         } else {
860             comp->name = prop;
861             comp->has_name = 1;
862             if (URI != NULL) {
863                 comp->ns = xmlStrdup(URI);
864                 comp->has_ns = 1;
865             } else {
866                 comp->has_ns = 0;
867             }
868         }
869         comp->templ = NULL;
870     }
871 }
872
873 /**
874  * xsltApplyTemplatesComp:
875  * @style:  a XSLT process context
876  * @inst:  the apply-templates node
877  *
878  * Process the apply-templates node on the source node
879  */
880 static void
881 xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) {
882     xsltStylePreCompPtr comp;
883     xmlChar *prop;
884
885     if ((style == NULL) || (inst == NULL))
886         return;
887     comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);
888     if (comp == NULL)
889         return;
890     inst->_private = comp;
891     comp->inst = inst;
892
893     /*
894      * Get mode if any
895      */
896     prop = xsltGetNsProp(inst, (const xmlChar *)"mode", XSLT_NAMESPACE);
897     if (prop != NULL) {
898         const xmlChar *URI;
899
900         URI = xsltGetQNameURI(inst, &prop);
901         if (prop == NULL) {
902             style->errors++;
903         } else {
904             comp->mode = prop;
905             if (URI != NULL) {
906                 comp->modeURI = xmlStrdup(URI);
907             } else {
908                 comp->modeURI = NULL;
909             }
910         }
911     }
912     comp->select = xsltGetNsProp(inst, (const xmlChar *)"select",
913                                 XSLT_NAMESPACE);
914     if (comp->select != NULL) {
915         comp->comp = xmlXPathCompile(comp->select);
916         if (comp->comp == NULL) {
917             xsltPrintErrorContext(NULL, style, inst);
918             xsltGenericError(xsltGenericErrorContext,
919      "xsl:apply-templates : could not compile select expression '%s'\n",
920                              comp->select);
921             style->errors++;
922         }
923     }
924
925     /* TODO: handle (or skip) the xsl:sort and xsl:with-param */
926 }
927
928 /**
929  * xsltChooseComp:
930  * @style:  a XSLT process context
931  * @inst:  the xslt choose node
932  *
933  * Process the xslt choose node on the source node
934  */
935 static void
936 xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) {
937     xsltStylePreCompPtr comp;
938
939     if ((style == NULL) || (inst == NULL))
940         return;
941     comp = xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);
942     if (comp == NULL)
943         return;
944     inst->_private = comp;
945     comp->inst = inst;
946 }
947
948 /**
949  * xsltIfComp:
950  * @style:  a XSLT process context
951  * @inst:  the xslt if node
952  *
953  * Process the xslt if node on the source node
954  */
955 static void
956 xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
957     xsltStylePreCompPtr comp;
958
959     if ((style == NULL) || (inst == NULL))
960         return;
961     comp = xsltNewStylePreComp(style, XSLT_FUNC_IF);
962     if (comp == NULL)
963         return;
964     inst->_private = comp;
965     comp->inst = inst;
966
967     comp->test = xsltGetNsProp(inst, (const xmlChar *)"test", XSLT_NAMESPACE);
968     if (comp->test == NULL) {
969         xsltPrintErrorContext(NULL, style, inst);
970         xsltGenericError(xsltGenericErrorContext,
971              "xsl:if : test is not defined\n");
972         style->errors++;
973         return;
974     }
975     comp->comp = xmlXPathCompile(comp->test);
976     if (comp->comp == NULL) {
977         xsltPrintErrorContext(NULL, style, inst);
978         xsltGenericError(xsltGenericErrorContext,
979              "xsl:if : could not compile test expression '%s'\n",
980                          comp->test);
981         style->errors++;
982     }
983 }
984
985 /**
986  * xsltWhenComp:
987  * @style:  a XSLT process context
988  * @inst:  the xslt if node
989  *
990  * Process the xslt if node on the source node
991  */
992 static void
993 xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) {
994     xsltStylePreCompPtr comp;
995
996     if ((style == NULL) || (inst == NULL))
997         return;
998     comp = xsltNewStylePreComp(style, XSLT_FUNC_WHEN);
999     if (comp == NULL)
1000         return;
1001     inst->_private = comp;
1002     comp->inst = inst;
1003
1004     comp->test = xsltGetNsProp(inst, (const xmlChar *)"test", XSLT_NAMESPACE);
1005     if (comp->test == NULL) {
1006         xsltPrintErrorContext(NULL, style, inst);
1007         xsltGenericError(xsltGenericErrorContext,
1008              "xsl:when : test is not defined\n");
1009         style->errors++;
1010         return;
1011     }
1012     comp->comp = xmlXPathCompile(comp->test);
1013     if (comp->comp == NULL) {
1014         xsltPrintErrorContext(NULL, style, inst);
1015         xsltGenericError(xsltGenericErrorContext,
1016              "xsl:when : could not compile test expression '%s'\n",
1017                          comp->test);
1018         style->errors++;
1019     }
1020 }
1021
1022 /**
1023  * xsltForEachComp:
1024  * @style:  a XSLT process context
1025  * @inst:  the xslt for-each node
1026  *
1027  * Process the xslt for-each node on the source node
1028  */
1029 static void
1030 xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1031     xsltStylePreCompPtr comp;
1032
1033     if ((style == NULL) || (inst == NULL))
1034         return;
1035     comp = xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);
1036     if (comp == NULL)
1037         return;
1038     inst->_private = comp;
1039     comp->inst = inst;
1040
1041     comp->select = xsltGetNsProp(inst, (const xmlChar *)"select",
1042                                 XSLT_NAMESPACE);
1043     if (comp->select == NULL) {
1044         xsltPrintErrorContext(NULL, style, inst);
1045         xsltGenericError(xsltGenericErrorContext,
1046                 "xsl:for-each : select is missing\n");
1047         style->errors++;
1048     } else {
1049         comp->comp = xmlXPathCompile(comp->select);
1050         if (comp->comp == NULL) {
1051             xsltPrintErrorContext(NULL, style, inst);
1052             xsltGenericError(xsltGenericErrorContext,
1053      "xsl:for-each : could not compile select expression '%s'\n",
1054                              comp->select);
1055             style->errors++;
1056         }
1057     }
1058     /* TODO: handle and skip the xsl:sort */
1059 }
1060
1061 /**
1062  * xsltVariableComp:
1063  * @style:  a XSLT process context
1064  * @inst:  the xslt variable node
1065  *
1066  * Process the xslt variable node on the source node
1067  */
1068 static void
1069 xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1070     xsltStylePreCompPtr comp;
1071     xmlChar *prop;
1072
1073     if ((style == NULL) || (inst == NULL))
1074         return;
1075     comp = xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);
1076     if (comp == NULL)
1077         return;
1078     inst->_private = comp;
1079     comp->inst = inst;
1080
1081     /*
1082      * The full template resolution can be done statically
1083      */
1084     prop = xsltGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE);
1085     if (prop == NULL) {
1086         xsltPrintErrorContext(NULL, style, inst);
1087         xsltGenericError(xsltGenericErrorContext,
1088              "xsl:variable : name is missing\n");
1089         style->errors++;
1090     } else {
1091         const xmlChar *URI;
1092
1093         URI = xsltGetQNameURI(inst, &prop);
1094         if (prop == NULL) {
1095             style->errors++;
1096         } else {
1097             comp->name = prop;
1098             comp->has_name = 1;
1099             if (URI != NULL) {
1100                 comp->ns = xmlStrdup(URI);
1101                 comp->has_ns = 1;
1102             } else {
1103                 comp->has_ns = 0;
1104             }
1105         }
1106     }
1107
1108     comp->select = xsltGetNsProp(inst, (const xmlChar *)"select",
1109                                 XSLT_NAMESPACE);
1110     if (comp->select != NULL) {
1111         comp->comp = xmlXPathCompile(comp->select);
1112         if (comp->comp == NULL) {
1113             xsltPrintErrorContext(NULL, style, inst);
1114             xsltGenericError(xsltGenericErrorContext,
1115                  "xsl:variable : could not compile select expression '%s'\n",
1116                              comp->select);
1117             style->errors++;
1118         }
1119         if (inst->children != NULL) {
1120             xsltPrintErrorContext(NULL, style, inst);
1121             xsltGenericError(xsltGenericErrorContext,
1122         "xsl:variable : content should be empty since select is present \n");
1123             style->warnings++;
1124         }
1125     }
1126 }
1127
1128 /**
1129  * xsltParamComp:
1130  * @style:  a XSLT process context
1131  * @inst:  the xslt param node
1132  *
1133  * Process the xslt param node on the source node
1134  */
1135 static void
1136 xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1137     xsltStylePreCompPtr comp;
1138     xmlChar *prop;
1139
1140     if ((style == NULL) || (inst == NULL))
1141         return;
1142     comp = xsltNewStylePreComp(style, XSLT_FUNC_PARAM);
1143     if (comp == NULL)
1144         return;
1145     inst->_private = comp;
1146     comp->inst = inst;
1147
1148     /*
1149      * The full template resolution can be done statically
1150      */
1151     prop = xsltGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE);
1152     if (prop == NULL) {
1153         xsltPrintErrorContext(NULL, style, inst);
1154         xsltGenericError(xsltGenericErrorContext,
1155              "xsl:param : name is missing\n");
1156         style->errors++;
1157     } else {
1158         const xmlChar *URI;
1159
1160         URI = xsltGetQNameURI(inst, &prop);
1161         if (prop == NULL) {
1162             style->errors++;
1163         } else {
1164             comp->name = prop;
1165             comp->has_name = 1;
1166             if (URI != NULL) {
1167                 comp->ns = xmlStrdup(URI);
1168                 comp->has_ns = 1;
1169             } else {
1170                 comp->has_ns = 0;
1171             }
1172         }
1173     }
1174
1175     comp->select = xsltGetNsProp(inst, (const xmlChar *)"select",
1176                                 XSLT_NAMESPACE);
1177     if (comp->select != NULL) {
1178         comp->comp = xmlXPathCompile(comp->select);
1179         if (comp->comp == NULL) {
1180             xsltPrintErrorContext(NULL, style, inst);
1181             xsltGenericError(xsltGenericErrorContext,
1182                  "xsl:param : could not compile select expression '%s'\n",
1183                              comp->select);
1184             style->errors++;
1185         }
1186         if (inst->children != NULL) {
1187             xsltPrintErrorContext(NULL, style, inst);
1188             xsltGenericError(xsltGenericErrorContext,
1189         "xsl:param : content should be empty since select is present \n");
1190             style->warnings++;
1191         }
1192     }
1193 }
1194
1195
1196 /************************************************************************
1197  *                                                                      *
1198  *                  Generic interface                                   *
1199  *                                                                      *
1200  ************************************************************************/
1201
1202 /**
1203  * xsltFreeStylePreComps:
1204  * @style:  an XSLT transformation context
1205  *
1206  * Free up the memory allocated by all precomputed blocks
1207  */
1208 void
1209 xsltFreeStylePreComps(xsltStylesheetPtr style) {
1210     xsltElemPreCompPtr cur, next;
1211
1212     if (style == NULL)
1213         return;
1214     cur = style->preComps;
1215     while (cur != NULL) {
1216         next = cur->next;
1217         if (cur->type == XSLT_FUNC_EXTENSION)
1218             cur->free(cur);
1219         else
1220             xsltFreeStylePreComp((xsltStylePreCompPtr) cur);
1221         cur = next;
1222     }
1223 }
1224
1225 /**
1226  * xsltStylePreCompute:
1227  * @style:  the XSLT stylesheet
1228  * @inst:  the instruction in the stylesheet
1229  *
1230  * Precompute an XSLT stylesheet element
1231  */
1232 void
1233 xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) {
1234     if (inst->_private != NULL) 
1235         return;
1236     if (IS_XSLT_ELEM(inst)) {
1237         xsltStylePreCompPtr cur;
1238
1239         if (IS_XSLT_NAME(inst, "apply-templates")) {
1240             xsltApplyTemplatesComp(style, inst);
1241         } else if (IS_XSLT_NAME(inst, "with-param")) {
1242             xsltWithParamComp(style, inst);
1243         } else if (IS_XSLT_NAME(inst, "value-of")) {
1244             xsltValueOfComp(style, inst);
1245         } else if (IS_XSLT_NAME(inst, "copy")) {
1246             xsltCopyComp(style, inst);
1247         } else if (IS_XSLT_NAME(inst, "copy-of")) {
1248             xsltCopyOfComp(style, inst);
1249         } else if (IS_XSLT_NAME(inst, "if")) {
1250             xsltIfComp(style, inst);
1251         } else if (IS_XSLT_NAME(inst, "when")) {
1252             xsltWhenComp(style, inst);
1253         } else if (IS_XSLT_NAME(inst, "choose")) {
1254             xsltChooseComp(style, inst);
1255         } else if (IS_XSLT_NAME(inst, "for-each")) {
1256             xsltForEachComp(style, inst);
1257         } else if (IS_XSLT_NAME(inst, "apply-imports")) {
1258             xsltApplyImportsComp(style, inst);
1259         } else if (IS_XSLT_NAME(inst, "attribute")) {
1260             xsltAttributeComp(style, inst);
1261         } else if (IS_XSLT_NAME(inst, "element")) {
1262             xsltElementComp(style, inst);
1263         } else if (IS_XSLT_NAME(inst, "text")) {
1264             xsltTextComp(style, inst);
1265         } else if (IS_XSLT_NAME(inst, "sort")) {
1266             xsltSortComp(style, inst);
1267         } else if (IS_XSLT_NAME(inst, "comment")) {
1268             xsltCommentComp(style, inst);
1269         } else if (IS_XSLT_NAME(inst, "number")) {
1270             xsltNumberComp(style, inst);
1271         } else if (IS_XSLT_NAME(inst, "processing-instruction")) {
1272             xsltProcessingInstructionComp(style, inst);
1273         } else if (IS_XSLT_NAME(inst, "call-template")) {
1274             xsltCallTemplateComp(style, inst);
1275         } else if (IS_XSLT_NAME(inst, "param")) {
1276             xsltParamComp(style, inst);
1277         } else if (IS_XSLT_NAME(inst, "variable")) {
1278             xsltVariableComp(style, inst);
1279         } else if (IS_XSLT_NAME(inst, "otherwise")) {
1280             /* no computation needed */
1281             return;
1282         } else if (IS_XSLT_NAME(inst, "template")) {
1283             /* no computation needed */
1284             return;
1285         } else if (IS_XSLT_NAME(inst, "output")) {
1286             /* no computation needed */
1287             return;
1288         } else if (IS_XSLT_NAME(inst, "preserve-space")) {
1289             /* no computation needed */
1290             return;
1291         } else if (IS_XSLT_NAME(inst, "strip-space")) {
1292             /* no computation needed */
1293             return;
1294         } else if (IS_XSLT_NAME(inst, "stylesheet")) {
1295             /* no computation needed */
1296             return;
1297         } else if (IS_XSLT_NAME(inst, "transform")) {
1298             /* no computation needed */
1299             return;
1300         } else if (IS_XSLT_NAME(inst, "key")) {
1301             /* no computation needed */
1302             return;
1303         } else if (IS_XSLT_NAME(inst, "message")) {
1304             /* no computation needed */
1305             return;
1306         } else if (IS_XSLT_NAME(inst, "attribute-set")) {
1307             /* no computation needed */
1308             return;
1309         } else if (IS_XSLT_NAME(inst, "namespace-alias")) {
1310             /* no computation needed */
1311             return;
1312         } else if (IS_XSLT_NAME(inst, "include")) {
1313             /* no computation needed */
1314             return;
1315         } else if (IS_XSLT_NAME(inst, "import")) {
1316             /* no computation needed */
1317             return;
1318         } else if (IS_XSLT_NAME(inst, "decimal-format")) {
1319             /* no computation needed */
1320             return;
1321         } else if (IS_XSLT_NAME(inst, "fallback")) {
1322             /* no computation needed */
1323             return;
1324         } else if (IS_XSLT_NAME(inst, "document")) {
1325             inst->_private = (void *) xsltDocumentComp(style, inst,
1326                                 (xsltTransformFunction) xsltDocumentElem);
1327         } else {
1328             xsltPrintErrorContext(NULL, style, inst);
1329             xsltGenericError(xsltGenericErrorContext,
1330                  "xsltStylePreCompute: unknown xsl:%s\n", inst->name);
1331             style->warnings++;
1332         }
1333         /*
1334          * Add the namespace lookup here, this code can be shared by
1335          * all precomputations.
1336          */
1337         cur = (xsltStylePreCompPtr) inst->_private;
1338         if (cur != NULL) {
1339             int i = 0;
1340
1341             cur->nsList = xmlGetNsList(inst->doc, inst);
1342             if (cur->nsList != NULL) {
1343                 while (cur->nsList[i] != NULL)
1344                     i++;
1345             }
1346             cur->nsNr = i;
1347         }
1348     } else {
1349         inst->_private =
1350             (void *) xsltPreComputeExtModuleElement(style, inst);
1351
1352         /*
1353          * Unknown element, maybe registered at the context
1354          * level. Mark it for later recognition.
1355          */
1356         if (inst->_private == NULL)
1357             inst->_private = (void *) xsltExtMarker;
1358     }
1359 }