2 * preproc.c: Preprocessing of style operations
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 * Michael Kay "XSLT Programmer's Reference" pp 637-643
8 * Writing Multiple Output Files
10 * XSLT-1.1 Working Draft
11 * http://www.w3.org/TR/xslt11#multiple-output
13 * See Copyright for the status of this software.
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>
32 #include "xsltutils.h"
33 #include "xsltInternals.h"
34 #include "transform.h"
35 #include "templates.h"
36 #include "variables.h"
37 #include "numbersInternals.h"
41 #include "extensions.h"
43 #ifdef WITH_XSLT_DEBUG
44 #define WITH_XSLT_DEBUG_PREPROC
47 const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element";
49 /************************************************************************
51 * handling of precomputed data *
53 ************************************************************************/
56 * xsltNewStylePreComp:
57 * @style: the XSLT stylesheet
58 * @type: the construct type
60 * Create a new XSLT Style precomputed block
62 * Returns the newly allocated xsltStylePreCompPtr or NULL in case of error
64 static xsltStylePreCompPtr
65 xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) {
66 xsltStylePreCompPtr cur;
68 cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp));
70 xsltTransformError(NULL, style, NULL,
71 "xsltNewStylePreComp : malloc failed\n");
72 if (style != NULL) style->errors++;
75 memset(cur, 0, sizeof(xsltStylePreComp));
80 cur->func = (xsltTransformFunction) xsltCopy;break;
82 cur->func = (xsltTransformFunction) xsltSort;break;
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;
92 cur->func = (xsltTransformFunction) xsltProcessingInstruction;
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;
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;
121 cur->func = NULL;break;
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++;
129 cur->next = style->preComps;
130 style->preComps = (xsltElemPreCompPtr) cur;
136 * xsltFreeStylePreComp:
137 * @comp: an XSLT Style precomputed block
139 * Free up the memory allocated by @comp
142 xsltFreeStylePreComp(xsltStylePreCompPtr comp) {
146 if (comp->comp != NULL)
147 xmlXPathFreeCompExpr(comp->comp);
148 if (comp->nsList != NULL)
149 xmlFree(comp->nsList);
155 /************************************************************************
157 * XSLT-1.1 extensions *
159 ************************************************************************/
163 * @style: the XSLT stylesheet
164 * @inst: the instruction in the stylesheet
167 * Pre process an XSLT-1.1 document element
169 * Returns a precompiled data structure for the element
172 xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst,
173 xsltTransformFunction function ATTRIBUTE_UNUSED) {
174 xsltStylePreCompPtr comp;
175 const xmlChar *filename = NULL;
177 comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);
183 if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
184 #ifdef WITH_XSLT_DEBUG_EXTRA
185 xsltGenericDebug(xsltGenericDebugContext,
186 "Found saxon:output extension\n");
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");
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");
206 filename = xsltEvalStaticAttrValueTemplate(style, inst,
207 (const xmlChar *)"href",
208 XSLT_NAMESPACE, &comp->has_filename);
211 #ifdef WITH_XSLT_DEBUG_EXTRA
212 xsltGenericDebug(xsltGenericDebugContext,
213 "Found xt:document extension\n");
218 if (!comp->has_filename) {
221 comp->filename = filename;
224 return ((xsltElemPreCompPtr) comp);
227 /************************************************************************
229 * Most of the XSLT-1.0 transformations *
231 ************************************************************************/
235 * @style: the XSLT stylesheet
236 * @inst: the xslt sort node
238 * Process the xslt sort node on the source node
241 xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) {
242 xsltStylePreCompPtr comp;
244 if ((style == NULL) || (inst == NULL))
246 comp = xsltNewStylePreComp(style, XSLT_FUNC_SORT);
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"))
258 else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
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++;
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;
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++;
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;
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++;
298 comp->lang = xsltEvalStaticAttrValueTemplate(style, inst,
299 (const xmlChar *)"lang",
300 XSLT_NAMESPACE, &comp->has_lang);
302 comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE);
303 if (comp->select == NULL) {
305 * The default value of the select attribute is ., which will
306 * cause the string-value of the current node to be used as
309 comp->select = xmlDictLookup(style->dict, BAD_CAST ".", 1);
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",
316 if (style != NULL) style->errors++;
318 if (inst->children != NULL) {
319 xsltTransformError(NULL, style, inst,
320 "xsl:sort : is not empty\n");
321 if (style != NULL) style->errors++;
327 * @style: the XSLT stylesheet
328 * @inst: the xslt copy node
330 * Process the xslt copy node on the source node
333 xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) {
334 xsltStylePreCompPtr comp;
337 if ((style == NULL) || (inst == NULL))
339 comp = xsltNewStylePreComp(style, XSLT_FUNC_COPY);
346 comp->use = xsltGetCNsProp(style, inst, (const xmlChar *)"use-attribute-sets",
348 if (comp->use == NULL)
356 * @style: an XSLT compiled stylesheet
357 * @inst: the xslt text node
359 * Process the xslt text node on the source node
362 xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) {
363 xsltStylePreCompPtr comp;
366 if ((style == NULL) || (inst == NULL))
368 comp = xsltNewStylePreComp(style, XSLT_FUNC_TEXT);
375 prop = xsltGetCNsProp(style, inst,
376 (const xmlChar *)"disable-output-escaping",
379 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
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++;
392 * @style: an XSLT compiled stylesheet
393 * @inst: the xslt element node
395 * Process the xslt element node on the source node
398 xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) {
399 xsltStylePreCompPtr comp;
401 if ((style == NULL) || (inst == NULL))
403 comp = xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);
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++;
419 comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
420 (const xmlChar *)"namespace",
421 XSLT_NAMESPACE, &comp->has_ns);
422 if (comp->has_ns == 0) {
425 defaultNs = xmlSearchNs(inst->doc, inst, NULL);
426 if (defaultNs != NULL) {
427 comp->ns = xmlDictLookup(style->dict, defaultNs->href, -1);
431 comp->use = xsltEvalStaticAttrValueTemplate(style, inst,
432 (const xmlChar *)"use-attribute-sets",
433 XSLT_NAMESPACE, &comp->has_use);
438 * @style: an XSLT compiled stylesheet
439 * @inst: the xslt attribute node
441 * Process the xslt attribute node on the source node
444 xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) {
445 xsltStylePreCompPtr comp;
447 if ((style == NULL) || (inst == NULL))
449 comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE);
456 * TODO: more computation can be done there, especially namespace lookup
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++;
468 comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
469 (const xmlChar *)"namespace",
470 XSLT_NAMESPACE, &comp->has_ns);
476 * @style: an XSLT compiled stylesheet
477 * @inst: the xslt comment node
479 * Process the xslt comment node on the source node
482 xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) {
483 xsltStylePreCompPtr comp;
485 if ((style == NULL) || (inst == NULL))
487 comp = xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);
495 * xsltProcessingInstructionComp:
496 * @style: an XSLT compiled stylesheet
497 * @inst: the xslt processing-instruction node
499 * Process the xslt processing-instruction node on the source node
502 xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) {
503 xsltStylePreCompPtr comp;
505 if ((style == NULL) || (inst == NULL))
507 comp = xsltNewStylePreComp(style, XSLT_FUNC_PI);
513 comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
514 (const xmlChar *)"name",
515 XSLT_NAMESPACE, &comp->has_name);
520 * @style: an XSLT compiled stylesheet
521 * @inst: the xslt copy-of node
523 * Process the xslt copy-of node on the source node
526 xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
527 xsltStylePreCompPtr comp;
529 if ((style == NULL) || (inst == NULL))
531 comp = xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);
537 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
539 if (comp->select == NULL) {
540 xsltTransformError(NULL, style, inst,
541 "xsl:copy-of : select is missing\n");
542 if (style != NULL) style->errors++;
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",
550 if (style != NULL) style->errors++;
556 * @style: an XSLT compiled stylesheet
557 * @inst: the xslt value-of node
559 * Process the xslt value-of node on the source node
562 xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
563 xsltStylePreCompPtr comp;
566 if ((style == NULL) || (inst == NULL))
568 comp = xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);
574 prop = xsltGetCNsProp(style, inst,
575 (const xmlChar *)"disable-output-escaping",
578 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
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++;
587 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
589 if (comp->select == NULL) {
590 xsltTransformError(NULL, style, inst,
591 "xsl:value-of : select is missing\n");
592 if (style != NULL) style->errors++;
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",
600 if (style != NULL) style->errors++;
606 * @style: an XSLT compiled stylesheet
607 * @inst: the xslt with-param node
609 * Process the xslt with-param node on the source node
612 xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
613 xsltStylePreCompPtr comp;
616 if ((style == NULL) || (inst == NULL))
618 comp = xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);
625 * The full namespace resolution can be done statically
627 prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);
629 xsltTransformError(NULL, style, inst,
630 "xsl:with-param : name is missing\n");
631 if (style != NULL) style->errors++;
635 URI = xsltGetQNameURI2(style, inst, &prop);
637 if (style != NULL) style->errors++;
642 comp->ns = xmlStrdup(URI);
650 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
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",
658 if (style != NULL) style->errors++;
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++;
670 * @style: an XSLT compiled stylesheet
671 * @cur: the xslt number node
673 * Process the xslt number node on the source node
676 xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) {
677 xsltStylePreCompPtr comp;
680 if ((style == NULL) || (cur == NULL))
682 comp = xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);
687 if ((style == NULL) || (cur == NULL))
690 comp->numdata.doc = cur->doc;
691 comp->numdata.node = cur;
692 comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value",
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);
701 comp->numdata.format = prop;
704 comp->numdata.count = xsltGetCNsProp(style, cur, (const xmlChar *)"count",
706 comp->numdata.from = xsltGetCNsProp(style, cur, (const xmlChar *)"from",
709 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"level", XSLT_NAMESPACE);
711 if (xmlStrEqual(prop, BAD_CAST("single")) ||
712 xmlStrEqual(prop, BAD_CAST("multiple")) ||
713 xmlStrEqual(prop, BAD_CAST("any"))) {
714 comp->numdata.level = prop;
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));
723 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"lang", XSLT_NAMESPACE);
725 XSLT_TODO; /* xsl:number lang attribute */
726 xmlFree((void *)prop);
729 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE);
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 */
742 xsltTransformError(NULL, style, cur,
743 "xsl:number : invalid value %s for letter-value\n", prop);
744 if (style != NULL) style->warnings++;
748 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-separator",
751 comp->numdata.groupingCharacterLen = xmlStrlen(prop);
752 comp->numdata.groupingCharacter =
753 xsltGetUTF8Char(prop, &(comp->numdata.groupingCharacterLen));
756 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE);
758 sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup);
760 comp->numdata.groupingCharacter = 0;
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);
774 * xsltApplyImportsComp:
775 * @style: an XSLT compiled stylesheet
776 * @inst: the xslt apply-imports node
778 * Process the xslt apply-imports node on the source node
781 xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) {
782 xsltStylePreCompPtr comp;
784 if ((style == NULL) || (inst == NULL))
786 comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);
794 * xsltCallTemplateComp:
795 * @style: an XSLT compiled stylesheet
796 * @inst: the xslt call-template node
798 * Process the xslt call-template node on the source node
801 xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) {
802 xsltStylePreCompPtr comp;
805 if ((style == NULL) || (inst == NULL))
807 comp = xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);
814 * The full template resolution can be done statically
816 prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);
818 xsltTransformError(NULL, style, inst,
819 "xsl:call-template : name is missing\n");
820 if (style != NULL) style->errors++;
824 URI = xsltGetQNameURI2(style, inst, &prop);
826 if (style != NULL) style->errors++;
842 * xsltApplyTemplatesComp:
843 * @style: an XSLT compiled stylesheet
844 * @inst: the apply-templates node
846 * Process the apply-templates node on the source node
849 xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) {
850 xsltStylePreCompPtr comp;
853 if ((style == NULL) || (inst == NULL))
855 comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);
864 prop = xsltGetCNsProp(style, inst, (const xmlChar *)"mode", XSLT_NAMESPACE);
868 URI = xsltGetQNameURI2(style, inst, &prop);
870 if (style != NULL) style->errors++;
872 comp->mode = xmlDictLookup(style->dict, prop, -1);
874 comp->modeURI = xmlDictLookup(style->dict, URI, -1);
876 comp->modeURI = NULL;
880 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
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",
888 if (style != NULL) style->errors++;
892 /* TODO: handle (or skip) the xsl:sort and xsl:with-param */
897 * @style: an XSLT compiled stylesheet
898 * @inst: the xslt choose node
900 * Process the xslt choose node on the source node
903 xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) {
904 xsltStylePreCompPtr comp;
906 if ((style == NULL) || (inst == NULL))
908 comp = xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);
917 * @style: an XSLT compiled stylesheet
918 * @inst: the xslt if node
920 * Process the xslt if node on the source node
923 xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
924 xsltStylePreCompPtr comp;
926 if ((style == NULL) || (inst == NULL))
928 comp = xsltNewStylePreComp(style, XSLT_FUNC_IF);
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++;
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",
946 if (style != NULL) style->errors++;
952 * @style: an XSLT compiled stylesheet
953 * @inst: the xslt if node
955 * Process the xslt if node on the source node
958 xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) {
959 xsltStylePreCompPtr comp;
961 if ((style == NULL) || (inst == NULL))
963 comp = xsltNewStylePreComp(style, XSLT_FUNC_WHEN);
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++;
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",
981 if (style != NULL) style->errors++;
987 * @style: an XSLT compiled stylesheet
988 * @inst: the xslt for-each node
990 * Process the xslt for-each node on the source node
993 xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) {
994 xsltStylePreCompPtr comp;
996 if ((style == NULL) || (inst == NULL))
998 comp = xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);
1004 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1006 if (comp->select == NULL) {
1007 xsltTransformError(NULL, style, inst,
1008 "xsl:for-each : select is missing\n");
1009 if (style != NULL) style->errors++;
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",
1016 if (style != NULL) style->errors++;
1019 /* TODO: handle and skip the xsl:sort */
1024 * @style: an XSLT compiled stylesheet
1025 * @inst: the xslt variable node
1027 * Process the xslt variable node on the source node
1030 xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1031 xsltStylePreCompPtr comp;
1032 const xmlChar *prop;
1034 if ((style == NULL) || (inst == NULL))
1036 comp = xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);
1043 * The full template resolution can be done statically
1045 prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);
1047 xsltTransformError(NULL, style, inst,
1048 "xsl:variable : name is missing\n");
1049 if (style != NULL) style->errors++;
1053 URI = xsltGetQNameURI2(style, inst, &prop);
1055 if (style != NULL) style->errors++;
1060 comp->ns = xmlDictLookup(style->dict, URI, -1);
1068 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
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",
1076 if (style != NULL) style->errors++;
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++;
1088 * @style: an XSLT compiled stylesheet
1089 * @inst: the xslt param node
1091 * Process the xslt param node on the source node
1094 xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1095 xsltStylePreCompPtr comp;
1096 const xmlChar *prop;
1098 if ((style == NULL) || (inst == NULL))
1100 comp = xsltNewStylePreComp(style, XSLT_FUNC_PARAM);
1107 * The full template resolution can be done statically
1109 prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);
1111 xsltTransformError(NULL, style, inst,
1112 "xsl:param : name is missing\n");
1113 if (style != NULL) style->errors++;
1117 URI = xsltGetQNameURI2(style, inst, &prop);
1119 if (style != NULL) style->errors++;
1124 comp->ns = xmlStrdup(URI);
1132 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
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",
1140 if (style != NULL) style->errors++;
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++;
1151 /************************************************************************
1153 * Generic interface *
1155 ************************************************************************/
1158 * xsltFreeStylePreComps:
1159 * @style: an XSLT transformation context
1161 * Free up the memory allocated by all precomputed blocks
1164 xsltFreeStylePreComps(xsltStylesheetPtr style) {
1165 xsltElemPreCompPtr cur, next;
1169 cur = style->preComps;
1170 while (cur != NULL) {
1172 if (cur->type == XSLT_FUNC_EXTENSION)
1175 xsltFreeStylePreComp((xsltStylePreCompPtr) cur);
1181 * xsltStylePreCompute:
1182 * @style: the XSLT stylesheet
1183 * @inst: the instruction in the stylesheet
1185 * Precompute an XSLT stylesheet element
1188 xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) {
1189 if (inst->psvi != NULL)
1191 if (IS_XSLT_ELEM(inst)) {
1192 xsltStylePreCompPtr cur;
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 */
1237 } else if (IS_XSLT_NAME(inst, "template")) {
1238 /* no computation needed */
1240 } else if (IS_XSLT_NAME(inst, "output")) {
1241 /* no computation needed */
1243 } else if (IS_XSLT_NAME(inst, "preserve-space")) {
1244 /* no computation needed */
1246 } else if (IS_XSLT_NAME(inst, "strip-space")) {
1247 /* no computation needed */
1249 } else if (IS_XSLT_NAME(inst, "stylesheet")) {
1250 /* no computation needed */
1252 } else if (IS_XSLT_NAME(inst, "transform")) {
1253 /* no computation needed */
1255 } else if (IS_XSLT_NAME(inst, "key")) {
1256 /* no computation needed */
1258 } else if (IS_XSLT_NAME(inst, "message")) {
1259 /* no computation needed */
1261 } else if (IS_XSLT_NAME(inst, "attribute-set")) {
1262 /* no computation needed */
1264 } else if (IS_XSLT_NAME(inst, "namespace-alias")) {
1265 /* no computation needed */
1267 } else if (IS_XSLT_NAME(inst, "include")) {
1268 /* no computation needed */
1270 } else if (IS_XSLT_NAME(inst, "import")) {
1271 /* no computation needed */
1273 } else if (IS_XSLT_NAME(inst, "decimal-format")) {
1274 /* no computation needed */
1276 } else if (IS_XSLT_NAME(inst, "fallback")) {
1277 /* no computation needed */
1279 } else if (IS_XSLT_NAME(inst, "document")) {
1280 inst->psvi = (void *) xsltDocumentComp(style, inst,
1281 (xsltTransformFunction) xsltDocumentElem);
1283 xsltTransformError(NULL, style, inst,
1284 "xsltStylePreCompute: unknown xsl:%s\n", inst->name);
1285 if (style != NULL) style->warnings++;
1288 * Add the namespace lookup here, this code can be shared by
1289 * all precomputations.
1291 cur = (xsltStylePreCompPtr) inst->psvi;
1295 cur->nsList = xmlGetNsList(inst->doc, inst);
1296 if (cur->nsList != NULL) {
1297 while (cur->nsList[i] != NULL)
1304 (void *) xsltPreComputeExtModuleElement(style, inst);
1307 * Unknown element, maybe registered at the context
1308 * level. Mark it for later recognition.
1310 if (inst->psvi == NULL)
1311 inst->psvi = (void *) xsltExtMarker;