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