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