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