e0f08cb7099ed13b368a6a1670af30db32102edb
[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@imag.fr
16  */
17
18 #include "xsltconfig.h"
19
20 #include <string.h>
21
22 #include <libxml/xmlmemory.h>
23 #include <libxml/parser.h>
24 #include <libxml/tree.h>
25 #include <libxml/valid.h>
26 #include <libxml/hash.h>
27 #include <libxml/uri.h>
28 #include <libxml/xmlerror.h>
29 #include "xslt.h"
30 #include "xsltutils.h"
31 #include "xsltInternals.h"
32 #include "transform.h"
33 #include "templates.h"
34 #include "variables.h"
35 #include "numbersInternals.h"
36 #include "preproc.h"
37 #include "extra.h"
38 #include "imports.h"
39
40 #define DEBUG_PREPROC
41
42
43 /************************************************************************
44  *                                                                      *
45  *                      handling of precomputed data                    *
46  *                                                                      *
47  ************************************************************************/
48
49 /**
50  * xsltNewStylePreComp:
51  * @ctxt:  an XSLT processing context
52  * @type:  the construct type
53  *
54  * Create a new XSLT Style precomputed block
55  *
56  * Returns the newly allocated xsltStylePreCompPtr or NULL in case of error
57  */
58 static xsltStylePreCompPtr
59 xsltNewStylePreComp(xsltTransformContextPtr ctxt, xsltStyleType type) {
60     xsltStylePreCompPtr cur;
61
62     cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp));
63     if (cur == NULL) {
64         xsltGenericError(xsltGenericErrorContext,
65                 "xsltNewStylePreComp : malloc failed\n");
66         return(NULL);
67     }
68     memset(cur, 0, sizeof(xsltStylePreComp));
69
70     cur->type = type;
71     switch (cur->type) {
72         case XSLT_FUNC_COPY:
73             cur->func = xsltCopy;break;
74         case XSLT_FUNC_SORT:
75             cur->func = xsltSort;break;
76         case XSLT_FUNC_TEXT:
77             cur->func = xsltText;break;
78         case XSLT_FUNC_ELEMENT:
79             cur->func = xsltElement;break;
80         case XSLT_FUNC_ATTRIBUTE:
81             cur->func = xsltAttribute;break;
82         case XSLT_FUNC_COMMENT:
83             cur->func = xsltComment;break;
84         case XSLT_FUNC_PI:
85             cur->func = xsltProcessingInstruction;break;
86         case XSLT_FUNC_COPYOF:
87             cur->func = xsltCopyOf;break;
88         case XSLT_FUNC_VALUEOF:
89             cur->func = xsltValueOf;break;
90         case XSLT_FUNC_NUMBER:
91             cur->func = xsltNumber;break;
92         case XSLT_FUNC_APPLYIMPORTS:
93             cur->func = xsltApplyImports;break;
94         case XSLT_FUNC_CALLTEMPLATE:
95             cur->func = xsltCallTemplate;break;
96         case XSLT_FUNC_APPLYTEMPLATES:
97             cur->func = xsltApplyTemplates;break;
98         case XSLT_FUNC_CHOOSE:
99             cur->func = xsltChoose;break;
100         case XSLT_FUNC_IF:
101             cur->func = xsltIf;break;
102         case XSLT_FUNC_FOREACH:
103             cur->func = xsltForEach;break;
104         case XSLT_FUNC_DOCUMENT:
105             cur->func = xsltDocumentElem;break;
106     }
107     if (cur->func == NULL) {
108         xsltGenericError(xsltGenericErrorContext,
109                 "xsltNewStylePreComp : no function for type %d\n", type);
110     }
111     cur->next = ctxt->preComps;
112     ctxt->preComps = cur;
113
114     return(cur);
115 }
116
117 /**
118  * xsltFreeStylePreComp:
119  * @comp:  an XSLT Style precomputed block
120  *
121  * Free up the memory allocated by @comp
122  */
123 static void
124 xsltFreeStylePreComp(xsltStylePreCompPtr comp) {
125     if (comp == NULL)
126         return;
127     if (comp->inst != NULL)
128         comp->inst->_private = NULL;
129     if (comp->stype != NULL)
130         xmlFree(comp->stype);
131     if (comp->order != NULL)
132         xmlFree(comp->order);
133     if (comp->use != NULL)
134         xmlFree(comp->use);
135     if (comp->name != NULL)
136         xmlFree(comp->name);
137     if (comp->ns != NULL)
138         xmlFree(comp->ns);
139     if (comp->mode != NULL)
140         xmlFree(comp->mode);
141     if (comp->modeURI != NULL)
142         xmlFree(comp->modeURI);
143     if (comp->test != NULL)
144         xmlFree(comp->test);
145     if (comp->select != NULL)
146         xmlFree(comp->select);
147
148     if (comp->filename != NULL)
149         xmlFree(comp->filename);
150
151     if (comp->numdata.level != NULL)
152         xmlFree(comp->numdata.level);
153     if (comp->numdata.count != NULL)
154         xmlFree(comp->numdata.count);
155     if (comp->numdata.from != NULL)
156         xmlFree(comp->numdata.from);
157     if (comp->numdata.value != NULL)
158         xmlFree(comp->numdata.value);
159     if (comp->numdata.format != NULL)
160         xmlFree(comp->numdata.format);
161     if (comp->comp != NULL)
162         xmlXPathFreeCompExpr(comp->comp);
163     if (comp->nsList != NULL)
164         xmlFree(comp->nsList);
165
166     memset(comp, -1, sizeof(xsltStylePreComp));
167
168     xmlFree(comp);
169 }
170
171
172 /************************************************************************
173  *                                                                      *
174  *                  XSLT-1.1 extensions                                 *
175  *                                                                      *
176  ************************************************************************/
177
178 /**
179  * xsltDocumentComp:
180  * @ctxt:  an XSLT processing context
181  * @inst:  the instruction in the stylesheet
182  *
183  * Pre process an XSLT-1.1 document element
184  */
185 static void
186 xsltDocumentComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
187     xsltStylePreCompPtr comp;
188     xmlChar *filename = NULL;
189     xmlChar *base = NULL;
190     xmlChar *URL = NULL;
191
192     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_DOCUMENT);
193     if (comp == NULL)
194         return;
195     inst->_private = comp;
196     comp->inst = inst;
197     comp->ver11 = 0;
198
199     if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
200 #ifdef DEBUG_EXTRA
201         xsltGenericDebug(xsltGenericDebugContext,
202             "Found saxon:output extension\n");
203 #endif
204         filename = xsltEvalStaticAttrValueTemplate(ctxt, inst,
205                          (const xmlChar *)"file",
206                          XSLT_SAXON_NAMESPACE, &comp->has_filename);
207     } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
208 #ifdef DEBUG_EXTRA
209         xsltGenericDebug(xsltGenericDebugContext,
210             "Found xalan:write extension\n");
211 #endif
212         filename = xsltEvalStaticAttrValueTemplate(ctxt, inst,
213                          (const xmlChar *)"select",
214                          XSLT_XALAN_NAMESPACE, &comp->has_filename);
215     } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
216         filename = xsltEvalStaticAttrValueTemplate(ctxt, inst,
217                          (const xmlChar *)"href",
218                          XSLT_XT_NAMESPACE, &comp->has_filename);
219         if (filename == NULL) {
220 #ifdef DEBUG_EXTRA
221             xsltGenericDebug(xsltGenericDebugContext,
222                 "Found xslt11:document construct\n");
223 #endif
224             filename = xsltEvalStaticAttrValueTemplate(ctxt, inst,
225                              (const xmlChar *)"href",
226                              XSLT_NAMESPACE, &comp->has_filename);
227             comp->ver11 = 1;
228         } else {
229 #ifdef DEBUG_EXTRA
230             xsltGenericDebug(xsltGenericDebugContext,
231                 "Found xt:document extension\n");
232 #endif
233             comp->ver11 = 0;
234         }
235     }
236     if (!comp->has_filename) {
237         xsltGenericError(xsltGenericErrorContext,
238             "xsltDocumentComp: could not find the href\n");
239         goto error;
240     }
241
242     if (filename != NULL) {
243         /*
244          * Compute output URL
245          */
246         base = xmlNodeGetBase(inst->doc, inst);
247         URL = xmlBuildURI(filename, base);
248         if (URL == NULL) {
249             xsltGenericError(xsltGenericErrorContext,
250                 "xsltDocumentComp: URL computation failed %s\n", filename);
251             comp->filename = xmlStrdup(filename);
252         } else {
253             comp->filename = URL;
254         }
255     } else {
256         comp->filename = NULL;
257     }
258
259 error:
260     if (base != NULL)
261         xmlFree(base);
262     if (filename != NULL)
263         xmlFree(filename);
264 }
265
266 /************************************************************************
267  *                                                                      *
268  *              Most of the XSLT-1.0 transformations                    *
269  *                                                                      *
270  ************************************************************************/
271
272 /**
273  * xsltSortComp:
274  * @ctxt:  a XSLT process context
275  * @inst:  the xslt sort node
276  *
277  * Process the xslt sort node on the source node
278  */
279 static void
280 xsltSortComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
281     xsltStylePreCompPtr comp;
282
283
284     if ((ctxt == NULL) || (inst == NULL))
285         return;
286     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_SORT);
287     if (comp == NULL)
288         return;
289     inst->_private = comp;
290     comp->inst = inst;
291
292     comp->stype = xsltEvalStaticAttrValueTemplate(ctxt, inst,
293                          (const xmlChar *)"data-type",
294                          XSLT_NAMESPACE, &comp->has_stype);
295     if (comp->stype != NULL) {
296         if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
297             comp->number = 0;
298         else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
299             comp->number = 1;
300         else {
301             xsltGenericError(xsltGenericErrorContext,
302                  "xsltSortComp: no support for data-type = %s\n", comp->stype);
303             comp->number = -1;
304         }
305     }
306     comp->order = xsltEvalStaticAttrValueTemplate(ctxt, inst,
307                               (const xmlChar *)"order",
308                               XSLT_NAMESPACE, &comp->has_order);
309     if (comp->order != NULL) {
310         if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
311             comp->descending = 0;
312         else if (xmlStrEqual(comp->order, (const xmlChar *) "descending"))
313             comp->descending = 1;
314         else {
315             xsltGenericError(xsltGenericErrorContext,
316                  "xsltSortComp: invalid value %s for order\n", comp->order);
317             comp->descending = -1;
318         }
319     }
320     /* TODO: xsl:sort lang attribute */
321     /* TODO: xsl:sort case-order attribute */
322
323     comp->select = xmlGetNsProp(inst,(const xmlChar *)"select", XSLT_NAMESPACE);
324     if (comp->select == NULL) {
325         comp->select = xmlNodeGetContent(inst);
326         if (comp->select == NULL) {
327             xsltGenericError(xsltGenericErrorContext,
328                  "xsltSortComp: select is not defined\n");
329         }
330     }
331 }
332
333 /**
334  * xsltCopyComp:
335  * @ctxt:  a XSLT process context
336  * @inst:  the xslt copy node
337  *
338  * Process the xslt copy node on the source node
339  */
340 static void
341 xsltCopyComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
342     xsltStylePreCompPtr comp;
343
344
345     if ((ctxt == NULL) || (inst == NULL))
346         return;
347     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_COPY);
348     if (comp == NULL)
349         return;
350     inst->_private = comp;
351     comp->inst = inst;
352
353
354     comp->use = xmlGetNsProp(inst, (const xmlChar *)"use-attribute-sets",
355                                     XSLT_NAMESPACE);
356     if (comp->use == NULL)
357         comp->has_use = 0;
358     else
359         comp->has_use = 1;
360 }
361
362 /**
363  * xsltTextComp:
364  * @ctxt:  a XSLT process context
365  * @inst:  the xslt text node
366  *
367  * Process the xslt text node on the source node
368  */
369 static void
370 xsltTextComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
371     xsltStylePreCompPtr comp;
372     xmlChar *prop;
373
374     if ((ctxt == NULL) || (inst == NULL))
375         return;
376     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_TEXT);
377     if (comp == NULL)
378         return;
379     inst->_private = comp;
380     comp->inst = inst;
381     comp->noescape = 0;
382
383     prop = xmlGetNsProp(inst,
384             (const xmlChar *)"disable-output-escaping",
385                         XSLT_NAMESPACE);
386     if (prop != NULL) {
387         if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
388             comp->noescape = 1;
389         } else if (!xmlStrEqual(prop,
390                                 (const xmlChar *)"no")){
391             xsltGenericError(xsltGenericErrorContext,
392 "xslt:text: disable-output-escaping allow only yes or no\n");
393         }
394         xmlFree(prop);
395     }
396 }
397
398 /**
399  * xsltElementComp:
400  * @ctxt:  a XSLT process context
401  * @inst:  the xslt element node
402  *
403  * Process the xslt element node on the source node
404  */
405 static void
406 xsltElementComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
407     xsltStylePreCompPtr comp;
408
409     if ((ctxt == NULL) || (inst == NULL))
410         return;
411     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_ELEMENT);
412     if (comp == NULL)
413         return;
414     inst->_private = comp;
415     comp->inst = inst;
416
417     /*
418      * TODO: more computation can be done there, especially namespace lookup
419      */
420     comp->name = xsltEvalStaticAttrValueTemplate(ctxt, inst,
421                                  (const xmlChar *)"name",
422                                  XSLT_NAMESPACE, &comp->has_name);
423     comp->ns = xsltEvalStaticAttrValueTemplate(ctxt, inst,
424                          (const xmlChar *)"namespace",
425                          XSLT_NAMESPACE, &comp->has_ns);
426
427     comp->use = xsltEvalStaticAttrValueTemplate(ctxt, inst,
428                        (const xmlChar *)"use-attribute-sets",
429                        XSLT_NAMESPACE, &comp->has_use);
430 }
431
432 /**
433  * xsltAttributeComp:
434  * @ctxt:  a XSLT process context
435  * @inst:  the xslt attribute node
436  *
437  * Process the xslt attribute node on the source node
438  */
439 static void
440 xsltAttributeComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
441     xsltStylePreCompPtr comp;
442
443     if ((ctxt == NULL) || (inst == NULL))
444         return;
445     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_ATTRIBUTE);
446     if (comp == NULL)
447         return;
448     inst->_private = comp;
449     comp->inst = inst;
450
451     /*
452      * TODO: more computation can be done there, especially namespace lookup
453      */
454     comp->name = xsltEvalStaticAttrValueTemplate(ctxt, inst,
455                                  (const xmlChar *)"name",
456                                  XSLT_NAMESPACE, &comp->has_name);
457     comp->ns = xsltEvalStaticAttrValueTemplate(ctxt, inst,
458                          (const xmlChar *)"namespace",
459                          XSLT_NAMESPACE, &comp->has_ns);
460
461 }
462
463 /**
464  * xsltCommentComp:
465  * @ctxt:  a XSLT process context
466  * @inst:  the xslt comment node
467  *
468  * Process the xslt comment node on the source node
469  */
470 static void
471 xsltCommentComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
472     xsltStylePreCompPtr comp;
473
474     if ((ctxt == NULL) || (inst == NULL))
475         return;
476     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_COMMENT);
477     if (comp == NULL)
478         return;
479     inst->_private = comp;
480     comp->inst = inst;
481 }
482
483 /**
484  * xsltProcessingInstructionComp:
485  * @ctxt:  a XSLT process context
486  * @inst:  the xslt processing-instruction node
487  *
488  * Process the xslt processing-instruction node on the source node
489  */
490 static void
491 xsltProcessingInstructionComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
492     xsltStylePreCompPtr comp;
493
494     if ((ctxt == NULL) || (inst == NULL))
495         return;
496     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_PI);
497     if (comp == NULL)
498         return;
499     inst->_private = comp;
500     comp->inst = inst;
501
502     comp->name = xsltEvalStaticAttrValueTemplate(ctxt, inst,
503                                  (const xmlChar *)"name",
504                                  XSLT_NAMESPACE, &comp->has_name);
505 }
506
507 /**
508  * xsltCopyOfComp:
509  * @ctxt:  a XSLT process context
510  * @inst:  the xslt copy-of node
511  *
512  * Process the xslt copy-of node on the source node
513  */
514 static void
515 xsltCopyOfComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
516     xsltStylePreCompPtr comp;
517
518     if ((ctxt == NULL) || (inst == NULL))
519         return;
520     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_COPYOF);
521     if (comp == NULL)
522         return;
523     inst->_private = comp;
524     comp->inst = inst;
525
526     comp->select = xmlGetNsProp(inst, (const xmlChar *)"select",
527                                 XSLT_NAMESPACE);
528     if (comp->select == NULL) {
529         xsltGenericError(xsltGenericErrorContext,
530              "xslt:copy-of : select is missing\n");
531     }
532 }
533
534 /**
535  * xsltValueOfComp:
536  * @ctxt:  a XSLT process context
537  * @inst:  the xslt value-of node
538  *
539  * Process the xslt value-of node on the source node
540  */
541 static void
542 xsltValueOfComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
543     xsltStylePreCompPtr comp;
544     xmlChar *prop;
545
546     if ((ctxt == NULL) || (inst == NULL))
547         return;
548     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_VALUEOF);
549     if (comp == NULL)
550         return;
551     inst->_private = comp;
552     comp->inst = inst;
553
554     prop = xmlGetNsProp(inst,
555             (const xmlChar *)"disable-output-escaping",
556                         XSLT_NAMESPACE);
557     if (prop != NULL) {
558         if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
559             comp->noescape = 1;
560         } else if (!xmlStrEqual(prop,
561                                 (const xmlChar *)"no")){
562             xsltGenericError(xsltGenericErrorContext,
563 "value-of: disable-output-escaping allow only yes or no\n");
564         }
565         xmlFree(prop);
566     }
567     comp->select = xmlGetNsProp(inst, (const xmlChar *)"select",
568                                 XSLT_NAMESPACE);
569     if (comp->select == NULL) {
570         xsltGenericError(xsltGenericErrorContext,
571              "xslt:value-of : select is missing\n");
572     }
573 }
574
575 /**
576  * xsltNumberComp:
577  * @ctxt:  a XSLT process context
578  * @cur:   the xslt number node
579  *
580  * Process the xslt number node on the source node
581  */
582 static void
583 xsltNumberComp(xsltTransformContextPtr ctxt, xmlNodePtr cur) {
584     xsltStylePreCompPtr comp;
585     xmlChar *prop;
586
587     if ((ctxt == NULL) || (cur == NULL))
588         return;
589     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_NUMBER);
590     if (comp == NULL)
591         return;
592     cur->_private = comp;
593
594     if ((ctxt == NULL) || (cur == NULL))
595         return;
596
597     comp->numdata.doc = cur->doc;
598     comp->numdata.node = cur;
599     comp->numdata.value = xmlGetNsProp(cur, (const xmlChar *)"value",
600                                         XSLT_NAMESPACE);
601     
602     prop = xmlGetNsProp(cur, (const xmlChar *)"format", XSLT_NAMESPACE);
603     if (prop != NULL) {
604         comp->numdata.format = prop;
605     } else {
606         comp->numdata.format = xmlStrdup(BAD_CAST("1"));
607     }
608     
609     comp->numdata.count = xmlGetNsProp(cur, (const xmlChar *)"count",
610                                         XSLT_NAMESPACE);
611     comp->numdata.from = xmlGetNsProp(cur, (const xmlChar *)"from",
612                                         XSLT_NAMESPACE);
613     
614     prop = xmlGetNsProp(cur, (const xmlChar *)"level", XSLT_NAMESPACE);
615     if (prop != NULL) {
616         if (xmlStrEqual(prop, BAD_CAST("single")) ||
617             xmlStrEqual(prop, BAD_CAST("multiple")) ||
618             xmlStrEqual(prop, BAD_CAST("any"))) {
619             comp->numdata.level = prop;
620         } else {
621             xsltGenericError(xsltGenericErrorContext,
622                          "xsl:number : invalid value %s for level\n", prop);
623             xmlFree(prop);
624         }
625     }
626     
627     prop = xmlGetNsProp(cur, (const xmlChar *)"lang", XSLT_NAMESPACE);
628     if (prop != NULL) {
629         TODO; /* xsl:number lang attribute */
630         xmlFree(prop);
631     }
632     
633     prop = xmlGetNsProp(cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE);
634     if (prop != NULL) {
635         if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) {
636             TODO; /* xsl:number letter-value attribute alphabetic */
637         } else if (xmlStrEqual(prop, BAD_CAST("traditional"))) {
638             TODO; /* xsl:number letter-value attribute traditional */
639         } else {
640             xsltGenericError(xsltGenericErrorContext,
641                      "xsl:number : invalid value %s for letter-value\n", prop);
642         }
643         xmlFree(prop);
644     }
645     
646     prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", XSLT_NAMESPACE);
647     if (prop != NULL) {
648         comp->numdata.groupingCharacter = prop[0];
649         xmlFree(prop);
650     }
651     
652     prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE);
653     if (prop != NULL) {
654         sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup);
655         xmlFree(prop);
656     } else {
657         comp->numdata.groupingCharacter = 0;
658     }
659
660     /* Set default values */
661     if (comp->numdata.value == NULL) {
662         if (comp->numdata.level == NULL) {
663             comp->numdata.level = xmlStrdup(BAD_CAST("single"));
664         }
665     }
666     
667 }
668
669 /**
670  * xsltApplyImportsComp:
671  * @ctxt:  a XSLT process context
672  * @inst:  the xslt apply-imports node
673  *
674  * Process the xslt apply-imports node on the source node
675  */
676 static void
677 xsltApplyImportsComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
678     xsltStylePreCompPtr comp;
679
680     if ((ctxt == NULL) || (inst == NULL))
681         return;
682     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_APPLYIMPORTS);
683     if (comp == NULL)
684         return;
685     inst->_private = comp;
686     comp->inst = inst;
687 }
688
689 /**
690  * xsltCallTemplateComp:
691  * @ctxt:  a XSLT process context
692  * @inst:  the xslt call-template node
693  *
694  * Process the xslt call-template node on the source node
695  */
696 static void
697 xsltCallTemplateComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
698     xsltStylePreCompPtr comp;
699     xmlChar *prop;
700     xmlChar *ncname = NULL;
701     xmlChar *prefix = NULL;
702     xmlNsPtr ns = NULL;
703
704     if ((ctxt == NULL) || (inst == NULL))
705         return;
706     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_CALLTEMPLATE);
707     if (comp == NULL)
708         return;
709     inst->_private = comp;
710     comp->inst = inst;
711
712     /*
713      * The full template resolution can be done statically
714      */
715     prop = xmlGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE);
716     if (prop == NULL) {
717         xsltGenericError(xsltGenericErrorContext,
718              "xslt:call-template : name is missing\n");
719     } else {
720
721         ncname = xmlSplitQName2(prop, &prefix);
722         if (ncname == NULL) {
723             ncname = prop;
724             prop = NULL;
725             prefix = NULL;
726         }
727         if (prefix != NULL) {
728             ns = xmlSearchNs(ctxt->insert->doc, ctxt->insert, prefix);
729             if (ns == NULL) {
730                 xsltGenericError(xsltGenericErrorContext,
731                     "no namespace bound to prefix %s\n", prefix);
732             }
733         }
734         if (ns != NULL)
735             comp->templ = xsltFindTemplate(ctxt, ncname, ns->href);
736         else
737             comp->templ = xsltFindTemplate(ctxt, ncname, NULL);
738
739         if (comp->templ == NULL) {
740             xsltGenericError(xsltGenericErrorContext,
741                  "xslt:call-template : template %s not found\n", ncname);
742         }
743     }
744
745     /* TODO: with-param could be optimized too */
746
747     if (prop != NULL)
748         xmlFree(prop);
749     if (ncname != NULL)
750         xmlFree(ncname);
751     if (prefix != NULL)
752         xmlFree(prefix);
753 }
754
755 /**
756  * xsltApplyTemplatesComp:
757  * @ctxt:  a XSLT process context
758  * @inst:  the apply-templates node
759  *
760  * Process the apply-templates node on the source node
761  */
762 static void
763 xsltApplyTemplatesComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
764     xsltStylePreCompPtr comp;
765     xmlChar *prop;
766
767     if ((ctxt == NULL) || (inst == NULL))
768         return;
769     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_APPLYTEMPLATES);
770     if (comp == NULL)
771         return;
772     inst->_private = comp;
773     comp->inst = inst;
774
775     /*
776      * Get mode if any
777      */
778     prop = xmlGetNsProp(inst, (const xmlChar *)"mode", XSLT_NAMESPACE);
779     if (prop != NULL) {
780         xmlChar *prefix = NULL;
781
782         comp->mode = xmlSplitQName2(prop, &prefix);
783         if (comp->mode != NULL) {
784             if (prefix != NULL) {
785                 xmlNsPtr ns;
786
787                 ns = xmlSearchNs(inst->doc, inst, prefix);
788                 if (ns == NULL) {
789                     xsltGenericError(xsltGenericErrorContext,
790                         "no namespace bound to prefix %s\n", prefix);
791                     xmlFree(prefix);
792                     xmlFree(comp->mode);
793                     comp->mode = prop;
794                     comp->modeURI = NULL;
795                 } else {
796                     comp->modeURI = xmlStrdup(ns->href);
797                     xmlFree(prefix);
798                     xmlFree(prop);
799                 }
800             } else {
801                 xmlFree(prop);
802                 comp->modeURI = NULL;
803             }
804         } else {
805             comp->mode = prop;
806             comp->modeURI = NULL;
807         }
808     }
809     comp->select = xmlGetNsProp(inst, (const xmlChar *)"select",
810                                 XSLT_NAMESPACE);
811
812     /* TODO: handle (or skip) the xsl:sort and xsl:with-param */
813 }
814
815 /**
816  * xsltChooseComp:
817  * @ctxt:  a XSLT process context
818  * @inst:  the xslt choose node
819  *
820  * Process the xslt choose node on the source node
821  */
822 static void
823 xsltChooseComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
824     xsltStylePreCompPtr comp;
825
826     if ((ctxt == NULL) || (inst == NULL))
827         return;
828     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_CHOOSE);
829     if (comp == NULL)
830         return;
831     inst->_private = comp;
832     comp->inst = inst;
833 }
834
835 /**
836  * xsltIfComp:
837  * @ctxt:  a XSLT process context
838  * @inst:  the xslt if node
839  *
840  * Process the xslt if node on the source node
841  */
842 static void
843 xsltIfComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
844     xsltStylePreCompPtr comp;
845
846     if ((ctxt == NULL) || (inst == NULL))
847         return;
848     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_IF);
849     if (comp == NULL)
850         return;
851     inst->_private = comp;
852     comp->inst = inst;
853
854     comp->test = xmlGetNsProp(inst, (const xmlChar *)"test", XSLT_NAMESPACE);
855     if (comp->test == NULL) {
856         xsltGenericError(xsltGenericErrorContext,
857              "xsltIf: test is not defined\n");
858         return;
859     }
860 }
861
862 /**
863  * xsltForEachComp:
864  * @ctxt:  a XSLT process context
865  * @inst:  the xslt for-each node
866  *
867  * Process the xslt for-each node on the source node
868  */
869 static void
870 xsltForEachComp(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
871     xsltStylePreCompPtr comp;
872
873     if ((ctxt == NULL) || (inst == NULL))
874         return;
875     comp = xsltNewStylePreComp(ctxt, XSLT_FUNC_FOREACH);
876     if (comp == NULL)
877         return;
878     inst->_private = comp;
879     comp->inst = inst;
880
881     comp->select = xmlGetNsProp(inst, (const xmlChar *)"select",
882                                 XSLT_NAMESPACE);
883
884     /* TODO: handle and skip the xsl:sort */
885 }
886
887
888 /************************************************************************
889  *                                                                      *
890  *                  Generic interface                                   *
891  *                                                                      *
892  ************************************************************************/
893
894 /**
895  * xsltFreeStylePreComps:
896  * @ctxt:  an XSLT transformation context
897  *
898  * Free up the memory allocated by all precomputed blocks
899  */
900 void
901 xsltFreeStylePreComps(xsltTransformContextPtr ctxt) {
902     xsltStylePreCompPtr cur, next;
903
904     if (ctxt == NULL)
905         return;
906     cur = ctxt->preComps;
907     while (cur != NULL) {
908         next = cur->next;
909         xsltFreeStylePreComp(cur);
910         cur = next;
911     }
912 }
913
914 /**
915  * xsltDocumentCompute:
916  * @ctxt:  an XSLT processing context
917  * @inst:  the instruction in the stylesheet
918  *
919  * Precompute an XSLT stylesheet element
920  */
921 void
922 xsltStylePreCompute(xsltTransformContextPtr ctxt, xmlNodePtr inst) {
923     if (inst->_private != NULL) 
924         return;
925     if (IS_XSLT_ELEM(inst)) {
926         xsltStylePreCompPtr cur;
927
928         if (IS_XSLT_NAME(inst, "apply-templates")) {
929             xsltApplyTemplatesComp(ctxt, inst);
930         } else if (IS_XSLT_NAME(inst, "value-of")) {
931             xsltValueOfComp(ctxt, inst);
932         } else if (IS_XSLT_NAME(inst, "copy")) {
933             xsltCopyComp(ctxt, inst);
934         } else if (IS_XSLT_NAME(inst, "copy-of")) {
935             xsltCopyOfComp(ctxt, inst);
936         } else if (IS_XSLT_NAME(inst, "if")) {
937             xsltIfComp(ctxt, inst);
938         } else if (IS_XSLT_NAME(inst, "choose")) {
939             xsltChooseComp(ctxt, inst);
940         } else if (IS_XSLT_NAME(inst, "for-each")) {
941             xsltForEachComp(ctxt, inst);
942         } else if (IS_XSLT_NAME(inst, "apply-imports")) {
943             xsltApplyImportsComp(ctxt, inst);
944         } else if (IS_XSLT_NAME(inst, "attribute")) {
945             xsltAttributeComp(ctxt, inst);
946         } else if (IS_XSLT_NAME(inst, "element")) {
947             xsltElementComp(ctxt, inst);
948         } else if (IS_XSLT_NAME(inst, "text")) {
949             xsltTextComp(ctxt, inst);
950         } else if (IS_XSLT_NAME(inst, "sort")) {
951             xsltSortComp(ctxt, inst);
952         } else if (IS_XSLT_NAME(inst, "comment")) {
953             xsltCommentComp(ctxt, inst);
954         } else if (IS_XSLT_NAME(inst, "number")) {
955             xsltNumberComp(ctxt, inst);
956         } else if (IS_XSLT_NAME(inst, "processing-instruction")) {
957             xsltProcessingInstructionComp(ctxt, inst);
958         } else if (IS_XSLT_NAME(inst, "call-template")) {
959             xsltCallTemplateComp(ctxt, inst);
960         } else if (IS_XSLT_NAME(inst, "param")) {
961             /* TODO: is there any use optimizing param too ? */
962             return;
963         } else if (IS_XSLT_NAME(inst, "variable")) {
964             /* TODO: is there any use optimizing variable too ? */
965             return;
966         } else if (IS_XSLT_NAME(inst, "message")) {
967             /* no optimization needed */
968             return;
969         } else if (IS_XSLT_NAME(inst, "document")) {
970             xsltDocumentComp(ctxt, inst);
971         } else {
972             xsltGenericError(xsltGenericDebugContext,
973                  "xsltStylePreCompute: unknown xslt:%s\n", inst->name);
974         }
975         /*
976          * Add the namespace lookup here, this code can be shared by
977          * all precomputations.
978          */
979         cur = inst->_private;
980         if (cur != NULL) {
981             int i = 0;
982
983             cur->nsList = xmlGetNsList(inst->doc, inst);
984             if (cur->nsList != NULL) {
985                 while (cur->nsList[i] != NULL)
986                     i++;
987             }
988             cur->nsNr = i;
989         }
990     } else {
991         if (IS_XSLT_NAME(inst, "document")) {
992             xsltDocumentComp(ctxt, inst);
993         }
994     }
995 }