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 /************************************************************************
53 ************************************************************************/
56 * xsltCheckTopLevelElement:
57 * @style: the XSLT stylesheet
58 * @inst: the XSLT instruction
59 * @err: raise an error or not
61 * Check that the instruction is instanciated as a top level element.
63 * Returns -1 in case of error, 0 if failed and 1 in case of success
66 xsltCheckTopLevelElement(xsltStylesheetPtr style, xmlNodePtr inst, int err) {
68 if ((style == NULL) || (inst == NULL) || (inst->ns == NULL))
71 parent = inst->parent;
74 xsltTransformError(NULL, style, inst,
75 "internal problem: element has no parent\n");
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")))) {
86 xsltTransformError(NULL, style, inst,
87 "element %s only allowed as child of stylesheet\n",
97 * xsltCheckInstructionElement:
98 * @style: the XSLT stylesheet
99 * @inst: the XSLT instruction
101 * Check that the instruction is instanciated as an instruction element.
104 xsltCheckInstructionElement(xsltStylesheetPtr style, xmlNodePtr inst) {
108 if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||
109 (style->literal_result))
112 has_ext = (style->extInfos != NULL);
114 parent = inst->parent;
115 if (parent == NULL) {
116 xsltTransformError(NULL, style, inst,
117 "internal problem: element has no parent\n");
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")))) {
133 * if we are within an extension element all bets are off
134 * about the semantic there e.g. xsl:param within func:function
136 if ((has_ext) && (parent->ns != NULL) &&
137 (xmlHashLookup(style->extInfos, parent->ns->href) != NULL))
140 parent = parent->parent;
142 xsltTransformError(NULL, style, inst,
143 "element %s only allowed within a template, variable or param\n",
149 * xsltCheckParentElement:
150 * @style: the XSLT stylesheet
151 * @inst: the XSLT instruction
152 * @allow1: allowed parent1
153 * @allow2: allowed parent2
155 * Check that the instruction is instanciated as the childre of one of the
159 xsltCheckParentElement(xsltStylesheetPtr style, xmlNodePtr inst,
160 const xmlChar *allow1, const xmlChar *allow2) {
163 if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||
164 (style->literal_result))
167 parent = inst->parent;
168 if (parent == NULL) {
169 xsltTransformError(NULL, style, inst,
170 "internal problem: element has no parent\n");
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)))) {
182 if (style->extInfos != NULL) {
183 while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) {
185 * if we are within an extension element all bets are off
186 * about the semantic there e.g. xsl:param within func:function
188 if ((parent->ns != NULL) &&
189 (xmlHashLookup(style->extInfos, parent->ns->href) != NULL))
192 parent = parent->parent;
195 xsltTransformError(NULL, style, inst,
196 "element %s is not allowed within that context\n",
201 /************************************************************************
203 * handling of precomputed data *
205 ************************************************************************/
208 * xsltNewStylePreComp:
209 * @style: the XSLT stylesheet
210 * @type: the construct type
212 * Create a new XSLT Style precomputed block
214 * Returns the newly allocated xsltStylePreCompPtr or NULL in case of error
216 static xsltStylePreCompPtr
217 xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) {
218 xsltStylePreCompPtr cur;
220 cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp));
222 xsltTransformError(NULL, style, NULL,
223 "xsltNewStylePreComp : malloc failed\n");
224 if (style != NULL) style->errors++;
227 memset(cur, 0, sizeof(xsltStylePreComp));
232 cur->func = (xsltTransformFunction) xsltCopy;break;
234 cur->func = (xsltTransformFunction) xsltSort;break;
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;
244 cur->func = (xsltTransformFunction) xsltProcessingInstruction;
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;
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;
273 cur->func = NULL;break;
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++;
281 cur->next = style->preComps;
282 style->preComps = (xsltElemPreCompPtr) cur;
288 * xsltFreeStylePreComp:
289 * @comp: an XSLT Style precomputed block
291 * Free up the memory allocated by @comp
294 xsltFreeStylePreComp(xsltStylePreCompPtr comp) {
298 if (comp->comp != NULL)
299 xmlXPathFreeCompExpr(comp->comp);
300 if (comp->nsList != NULL)
301 xmlFree(comp->nsList);
307 /************************************************************************
309 * XSLT-1.1 extensions *
311 ************************************************************************/
315 * @style: the XSLT stylesheet
316 * @inst: the instruction in the stylesheet
319 * Pre process an XSLT-1.1 document element
321 * Returns a precompiled data structure for the element
324 xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst,
325 xsltTransformFunction function ATTRIBUTE_UNUSED) {
326 xsltStylePreCompPtr comp;
327 const xmlChar *filename = NULL;
329 comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);
335 if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
336 #ifdef WITH_XSLT_DEBUG_EXTRA
337 xsltGenericDebug(xsltGenericDebugContext,
338 "Found saxon:output extension\n");
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");
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");
358 filename = xsltEvalStaticAttrValueTemplate(style, inst,
359 (const xmlChar *)"href",
360 XSLT_NAMESPACE, &comp->has_filename);
363 #ifdef WITH_XSLT_DEBUG_EXTRA
364 xsltGenericDebug(xsltGenericDebugContext,
365 "Found xt:document extension\n");
370 if (!comp->has_filename) {
373 comp->filename = filename;
376 return ((xsltElemPreCompPtr) comp);
379 /************************************************************************
381 * Most of the XSLT-1.0 transformations *
383 ************************************************************************/
387 * @style: the XSLT stylesheet
388 * @inst: the xslt sort node
390 * Process the xslt sort node on the source node
393 xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) {
394 xsltStylePreCompPtr comp;
396 if ((style == NULL) || (inst == NULL))
398 comp = xsltNewStylePreComp(style, XSLT_FUNC_SORT);
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"))
410 else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
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++;
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;
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++;
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;
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++;
450 comp->lang = xsltEvalStaticAttrValueTemplate(style, inst,
451 (const xmlChar *)"lang",
452 XSLT_NAMESPACE, &comp->has_lang);
454 comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE);
455 if (comp->select == NULL) {
457 * The default value of the select attribute is ., which will
458 * cause the string-value of the current node to be used as
461 comp->select = xmlDictLookup(style->dict, BAD_CAST ".", 1);
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",
468 if (style != NULL) style->errors++;
470 if (inst->children != NULL) {
471 xsltTransformError(NULL, style, inst,
472 "xsl:sort : is not empty\n");
473 if (style != NULL) style->errors++;
479 * @style: the XSLT stylesheet
480 * @inst: the xslt copy node
482 * Process the xslt copy node on the source node
485 xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) {
486 xsltStylePreCompPtr comp;
489 if ((style == NULL) || (inst == NULL))
491 comp = xsltNewStylePreComp(style, XSLT_FUNC_COPY);
498 comp->use = xsltGetCNsProp(style, inst, (const xmlChar *)"use-attribute-sets",
500 if (comp->use == NULL)
508 * @style: an XSLT compiled stylesheet
509 * @inst: the xslt text node
511 * Process the xslt text node on the source node
514 xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) {
515 xsltStylePreCompPtr comp;
518 if ((style == NULL) || (inst == NULL))
520 comp = xsltNewStylePreComp(style, XSLT_FUNC_TEXT);
527 prop = xsltGetCNsProp(style, inst,
528 (const xmlChar *)"disable-output-escaping",
531 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
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++;
544 * @style: an XSLT compiled stylesheet
545 * @inst: the xslt element node
547 * Process the xslt element node on the source node
550 xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) {
551 xsltStylePreCompPtr comp;
553 if ((style == NULL) || (inst == NULL))
555 comp = xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);
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++;
571 comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
572 (const xmlChar *)"namespace",
573 XSLT_NAMESPACE, &comp->has_ns);
574 if (comp->has_ns == 0) {
577 defaultNs = xmlSearchNs(inst->doc, inst, NULL);
578 if (defaultNs != NULL) {
579 comp->ns = xmlDictLookup(style->dict, defaultNs->href, -1);
583 comp->use = xsltEvalStaticAttrValueTemplate(style, inst,
584 (const xmlChar *)"use-attribute-sets",
585 XSLT_NAMESPACE, &comp->has_use);
590 * @style: an XSLT compiled stylesheet
591 * @inst: the xslt attribute node
593 * Process the xslt attribute node on the source node
596 xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) {
597 xsltStylePreCompPtr comp;
599 if ((style == NULL) || (inst == NULL))
601 comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE);
608 * TODO: more computation can be done there, especially namespace lookup
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++;
620 comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
621 (const xmlChar *)"namespace",
622 XSLT_NAMESPACE, &comp->has_ns);
628 * @style: an XSLT compiled stylesheet
629 * @inst: the xslt comment node
631 * Process the xslt comment node on the source node
634 xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) {
635 xsltStylePreCompPtr comp;
637 if ((style == NULL) || (inst == NULL))
639 comp = xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);
647 * xsltProcessingInstructionComp:
648 * @style: an XSLT compiled stylesheet
649 * @inst: the xslt processing-instruction node
651 * Process the xslt processing-instruction node on the source node
654 xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) {
655 xsltStylePreCompPtr comp;
657 if ((style == NULL) || (inst == NULL))
659 comp = xsltNewStylePreComp(style, XSLT_FUNC_PI);
665 comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
666 (const xmlChar *)"name",
667 XSLT_NAMESPACE, &comp->has_name);
672 * @style: an XSLT compiled stylesheet
673 * @inst: the xslt copy-of node
675 * Process the xslt copy-of node on the source node
678 xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
679 xsltStylePreCompPtr comp;
681 if ((style == NULL) || (inst == NULL))
683 comp = xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);
689 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
691 if (comp->select == NULL) {
692 xsltTransformError(NULL, style, inst,
693 "xsl:copy-of : select is missing\n");
694 if (style != NULL) style->errors++;
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",
702 if (style != NULL) style->errors++;
708 * @style: an XSLT compiled stylesheet
709 * @inst: the xslt value-of node
711 * Process the xslt value-of node on the source node
714 xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
715 xsltStylePreCompPtr comp;
718 if ((style == NULL) || (inst == NULL))
720 comp = xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);
726 prop = xsltGetCNsProp(style, inst,
727 (const xmlChar *)"disable-output-escaping",
730 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
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++;
739 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
741 if (comp->select == NULL) {
742 xsltTransformError(NULL, style, inst,
743 "xsl:value-of : select is missing\n");
744 if (style != NULL) style->errors++;
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",
752 if (style != NULL) style->errors++;
758 * @style: an XSLT compiled stylesheet
759 * @inst: the xslt with-param node
761 * Process the xslt with-param node on the source node
764 xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
765 xsltStylePreCompPtr comp;
768 if ((style == NULL) || (inst == NULL))
770 comp = xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);
777 * The full namespace resolution can be done statically
779 prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);
781 xsltTransformError(NULL, style, inst,
782 "xsl:with-param : name is missing\n");
783 if (style != NULL) style->errors++;
787 URI = xsltGetQNameURI2(style, inst, &prop);
789 if (style != NULL) style->errors++;
794 comp->ns = xmlStrdup(URI);
802 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
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",
810 if (style != NULL) style->errors++;
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++;
822 * @style: an XSLT compiled stylesheet
823 * @cur: the xslt number node
825 * Process the xslt number node on the source node
828 xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) {
829 xsltStylePreCompPtr comp;
832 if ((style == NULL) || (cur == NULL))
834 comp = xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);
839 if ((style == NULL) || (cur == NULL))
842 comp->numdata.doc = cur->doc;
843 comp->numdata.node = cur;
844 comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value",
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);
853 comp->numdata.format = prop;
856 comp->numdata.count = xsltGetCNsProp(style, cur, (const xmlChar *)"count",
858 comp->numdata.from = xsltGetCNsProp(style, cur, (const xmlChar *)"from",
861 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"level", XSLT_NAMESPACE);
863 if (xmlStrEqual(prop, BAD_CAST("single")) ||
864 xmlStrEqual(prop, BAD_CAST("multiple")) ||
865 xmlStrEqual(prop, BAD_CAST("any"))) {
866 comp->numdata.level = prop;
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));
875 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"lang", XSLT_NAMESPACE);
877 XSLT_TODO; /* xsl:number lang attribute */
878 xmlFree((void *)prop);
881 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE);
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 */
894 xsltTransformError(NULL, style, cur,
895 "xsl:number : invalid value %s for letter-value\n", prop);
896 if (style != NULL) style->warnings++;
900 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-separator",
903 comp->numdata.groupingCharacterLen = xmlStrlen(prop);
904 comp->numdata.groupingCharacter =
905 xsltGetUTF8Char(prop, &(comp->numdata.groupingCharacterLen));
908 prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE);
910 sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup);
912 comp->numdata.groupingCharacter = 0;
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);
926 * xsltApplyImportsComp:
927 * @style: an XSLT compiled stylesheet
928 * @inst: the xslt apply-imports node
930 * Process the xslt apply-imports node on the source node
933 xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) {
934 xsltStylePreCompPtr comp;
936 if ((style == NULL) || (inst == NULL))
938 comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);
946 * xsltCallTemplateComp:
947 * @style: an XSLT compiled stylesheet
948 * @inst: the xslt call-template node
950 * Process the xslt call-template node on the source node
953 xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) {
954 xsltStylePreCompPtr comp;
957 if ((style == NULL) || (inst == NULL))
959 comp = xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);
966 * The full template resolution can be done statically
968 prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);
970 xsltTransformError(NULL, style, inst,
971 "xsl:call-template : name is missing\n");
972 if (style != NULL) style->errors++;
976 URI = xsltGetQNameURI2(style, inst, &prop);
978 if (style != NULL) style->errors++;
994 * xsltApplyTemplatesComp:
995 * @style: an XSLT compiled stylesheet
996 * @inst: the apply-templates node
998 * Process the apply-templates node on the source node
1001 xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1002 xsltStylePreCompPtr comp;
1003 const xmlChar *prop;
1005 if ((style == NULL) || (inst == NULL))
1007 comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);
1016 prop = xsltGetCNsProp(style, inst, (const xmlChar *)"mode", XSLT_NAMESPACE);
1020 URI = xsltGetQNameURI2(style, inst, &prop);
1022 if (style != NULL) style->errors++;
1024 comp->mode = xmlDictLookup(style->dict, prop, -1);
1026 comp->modeURI = xmlDictLookup(style->dict, URI, -1);
1028 comp->modeURI = NULL;
1032 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
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",
1040 if (style != NULL) style->errors++;
1044 /* TODO: handle (or skip) the xsl:sort and xsl:with-param */
1049 * @style: an XSLT compiled stylesheet
1050 * @inst: the xslt choose node
1052 * Process the xslt choose node on the source node
1055 xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1056 xsltStylePreCompPtr comp;
1058 if ((style == NULL) || (inst == NULL))
1060 comp = xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);
1069 * @style: an XSLT compiled stylesheet
1070 * @inst: the xslt if node
1072 * Process the xslt if node on the source node
1075 xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1076 xsltStylePreCompPtr comp;
1078 if ((style == NULL) || (inst == NULL))
1080 comp = xsltNewStylePreComp(style, XSLT_FUNC_IF);
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++;
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",
1098 if (style != NULL) style->errors++;
1104 * @style: an XSLT compiled stylesheet
1105 * @inst: the xslt if node
1107 * Process the xslt if node on the source node
1110 xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1111 xsltStylePreCompPtr comp;
1113 if ((style == NULL) || (inst == NULL))
1115 comp = xsltNewStylePreComp(style, XSLT_FUNC_WHEN);
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++;
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",
1133 if (style != NULL) style->errors++;
1139 * @style: an XSLT compiled stylesheet
1140 * @inst: the xslt for-each node
1142 * Process the xslt for-each node on the source node
1145 xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1146 xsltStylePreCompPtr comp;
1148 if ((style == NULL) || (inst == NULL))
1150 comp = xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);
1156 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1158 if (comp->select == NULL) {
1159 xsltTransformError(NULL, style, inst,
1160 "xsl:for-each : select is missing\n");
1161 if (style != NULL) style->errors++;
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",
1168 if (style != NULL) style->errors++;
1171 /* TODO: handle and skip the xsl:sort */
1176 * @style: an XSLT compiled stylesheet
1177 * @inst: the xslt variable node
1179 * Process the xslt variable node on the source node
1182 xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1183 xsltStylePreCompPtr comp;
1184 const xmlChar *prop;
1186 if ((style == NULL) || (inst == NULL))
1188 comp = xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);
1195 * The full template resolution can be done statically
1197 prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);
1199 xsltTransformError(NULL, style, inst,
1200 "xsl:variable : name is missing\n");
1201 if (style != NULL) style->errors++;
1205 URI = xsltGetQNameURI2(style, inst, &prop);
1207 if (style != NULL) style->errors++;
1212 comp->ns = xmlDictLookup(style->dict, URI, -1);
1220 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
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",
1228 if (style != NULL) style->errors++;
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++;
1240 * @style: an XSLT compiled stylesheet
1241 * @inst: the xslt param node
1243 * Process the xslt param node on the source node
1246 xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1247 xsltStylePreCompPtr comp;
1248 const xmlChar *prop;
1250 if ((style == NULL) || (inst == NULL))
1252 comp = xsltNewStylePreComp(style, XSLT_FUNC_PARAM);
1259 * The full template resolution can be done statically
1261 prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);
1263 xsltTransformError(NULL, style, inst,
1264 "xsl:param : name is missing\n");
1265 if (style != NULL) style->errors++;
1269 URI = xsltGetQNameURI2(style, inst, &prop);
1271 if (style != NULL) style->errors++;
1276 comp->ns = xmlStrdup(URI);
1284 comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
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",
1292 if (style != NULL) style->errors++;
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++;
1303 /************************************************************************
1305 * Generic interface *
1307 ************************************************************************/
1310 * xsltFreeStylePreComps:
1311 * @style: an XSLT transformation context
1313 * Free up the memory allocated by all precomputed blocks
1316 xsltFreeStylePreComps(xsltStylesheetPtr style) {
1317 xsltElemPreCompPtr cur, next;
1321 cur = style->preComps;
1322 while (cur != NULL) {
1324 if (cur->type == XSLT_FUNC_EXTENSION)
1327 xsltFreeStylePreComp((xsltStylePreCompPtr) cur);
1333 * xsltStylePreCompute:
1334 * @style: the XSLT stylesheet
1335 * @inst: the instruction in the stylesheet
1337 * Precompute an XSLT stylesheet element
1340 xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) {
1341 if (inst->psvi != NULL)
1343 if (IS_XSLT_ELEM(inst)) {
1344 xsltStylePreCompPtr cur;
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;
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);
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);
1421 } else if (IS_XSLT_NAME(inst, "template")) {
1422 xsltCheckTopLevelElement(style, inst, 1);
1424 } else if (IS_XSLT_NAME(inst, "output")) {
1425 xsltCheckTopLevelElement(style, inst, 1);
1427 } else if (IS_XSLT_NAME(inst, "preserve-space")) {
1428 xsltCheckTopLevelElement(style, inst, 1);
1430 } else if (IS_XSLT_NAME(inst, "strip-space")) {
1431 xsltCheckTopLevelElement(style, inst, 1);
1433 } else if ((IS_XSLT_NAME(inst, "stylesheet")) ||
1434 (IS_XSLT_NAME(inst, "transform"))) {
1435 xmlNodePtr parent = inst->parent;
1437 if ((parent == NULL) || (parent->type != XML_DOCUMENT_NODE)) {
1438 xsltTransformError(NULL, style, inst,
1439 "element %s only allowed only as root element\n",
1444 } else if (IS_XSLT_NAME(inst, "key")) {
1445 xsltCheckTopLevelElement(style, inst, 1);
1447 } else if (IS_XSLT_NAME(inst, "message")) {
1448 xsltCheckInstructionElement(style, inst);
1450 } else if (IS_XSLT_NAME(inst, "attribute-set")) {
1451 xsltCheckTopLevelElement(style, inst, 1);
1453 } else if (IS_XSLT_NAME(inst, "namespace-alias")) {
1454 xsltCheckTopLevelElement(style, inst, 1);
1456 } else if (IS_XSLT_NAME(inst, "include")) {
1457 xsltCheckTopLevelElement(style, inst, 1);
1459 } else if (IS_XSLT_NAME(inst, "import")) {
1460 xsltCheckTopLevelElement(style, inst, 1);
1462 } else if (IS_XSLT_NAME(inst, "decimal-format")) {
1463 xsltCheckTopLevelElement(style, inst, 1);
1465 } else if (IS_XSLT_NAME(inst, "fallback")) {
1466 xsltCheckInstructionElement(style, inst);
1468 } else if (IS_XSLT_NAME(inst, "document")) {
1469 xsltCheckInstructionElement(style, inst);
1470 inst->psvi = (void *) xsltDocumentComp(style, inst,
1471 (xsltTransformFunction) xsltDocumentElem);
1473 xsltTransformError(NULL, style, inst,
1474 "xsltStylePreCompute: unknown xsl:%s\n", inst->name);
1475 if (style != NULL) style->warnings++;
1478 * Add the namespace lookup here, this code can be shared by
1479 * all precomputations.
1481 cur = (xsltStylePreCompPtr) inst->psvi;
1485 cur->nsList = xmlGetNsList(inst->doc, inst);
1486 if (cur->nsList != NULL) {
1487 while (cur->nsList[i] != NULL)
1494 (void *) xsltPreComputeExtModuleElement(style, inst);
1497 * Unknown element, maybe registered at the context
1498 * level. Mark it for later recognition.
1500 if (inst->psvi == NULL)
1501 inst->psvi = (void *) xsltExtMarker;