1/*
2 * preproc.c: Preprocessing of style operations
3 *
4 * References:
5 *   http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 *   Michael Kay "XSLT Programmer's Reference" pp 637-643
8 *   Writing Multiple Output Files
9 *
10 *   XSLT-1.1 Working Draft
11 *   http://www.w3.org/TR/xslt11#multiple-output
12 *
13 * See Copyright for the status of this software.
14 *
15 * daniel@veillard.com
16 */
17
18#define IN_LIBXSLT
19#include "libxslt.h"
20
21#include <string.h>
22
23#include <libxml/xmlmemory.h>
24#include <libxml/parser.h>
25#include <libxml/tree.h>
26#include <libxml/valid.h>
27#include <libxml/hash.h>
28#include <libxml/uri.h>
29#include <libxml/encoding.h>
30#include <libxml/xmlerror.h>
31#include "xslt.h"
32#include "xsltutils.h"
33#include "xsltInternals.h"
34#include "transform.h"
35#include "templates.h"
36#include "variables.h"
37#include "numbersInternals.h"
38#include "preproc.h"
39#include "extra.h"
40#include "imports.h"
41#include "extensions.h"
42#include "pattern.h"
43
44#ifdef WITH_XSLT_DEBUG
45#define WITH_XSLT_DEBUG_PREPROC
46#endif
47
48const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element";
49
50/************************************************************************
51 *									*
52 *			Grammar checks					*
53 *									*
54 ************************************************************************/
55
56#ifdef XSLT_REFACTORED
57    /*
58    * Grammar checks are now performed in xslt.c.
59    */
60#else
61/**
62 * xsltCheckTopLevelElement:
63 * @style: the XSLT stylesheet
64 * @inst: the XSLT instruction
65 * @err: raise an error or not
66 *
67 * Check that the instruction is instanciated as a top level element.
68 *
69 * Returns -1 in case of error, 0 if failed and 1 in case of success
70 */
71static int
72xsltCheckTopLevelElement(xsltStylesheetPtr style, xmlNodePtr inst, int err) {
73    xmlNodePtr parent;
74    if ((style == NULL) || (inst == NULL) || (inst->ns == NULL))
75        return(-1);
76
77    parent = inst->parent;
78    if (parent == NULL) {
79        if (err) {
80	    xsltTransformError(NULL, style, inst,
81		    "internal problem: element has no parent\n");
82	    style->errors++;
83	}
84	return(0);
85    }
86    if ((parent->ns == NULL) || (parent->type != XML_ELEMENT_NODE) ||
87        ((parent->ns != inst->ns) &&
88	 (!xmlStrEqual(parent->ns->href, inst->ns->href))) ||
89	((!xmlStrEqual(parent->name, BAD_CAST "stylesheet")) &&
90	 (!xmlStrEqual(parent->name, BAD_CAST "transform")))) {
91	if (err) {
92	    xsltTransformError(NULL, style, inst,
93		    "element %s only allowed as child of stylesheet\n",
94			       inst->name);
95	    style->errors++;
96	}
97	return(0);
98    }
99    return(1);
100}
101
102/**
103 * xsltCheckInstructionElement:
104 * @style: the XSLT stylesheet
105 * @inst: the XSLT instruction
106 *
107 * Check that the instruction is instanciated as an instruction element.
108 */
109static void
110xsltCheckInstructionElement(xsltStylesheetPtr style, xmlNodePtr inst) {
111    xmlNodePtr parent;
112    int has_ext;
113
114    if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||
115        (style->literal_result))
116        return;
117
118    has_ext = (style->extInfos != NULL);
119
120    parent = inst->parent;
121    if (parent == NULL) {
122	xsltTransformError(NULL, style, inst,
123		"internal problem: element has no parent\n");
124	style->errors++;
125	return;
126    }
127    while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) {
128        if (((parent->ns == inst->ns) ||
129	     ((parent->ns != NULL) &&
130	      (xmlStrEqual(parent->ns->href, inst->ns->href)))) &&
131	    ((xmlStrEqual(parent->name, BAD_CAST "template")) ||
132	     (xmlStrEqual(parent->name, BAD_CAST "param")) ||
133	     (xmlStrEqual(parent->name, BAD_CAST "attribute")) ||
134	     (xmlStrEqual(parent->name, BAD_CAST "variable")))) {
135	    return;
136	}
137
138	/*
139	 * if we are within an extension element all bets are off
140	 * about the semantic there e.g. xsl:param within func:function
141	 */
142	if ((has_ext) && (parent->ns != NULL) &&
143	    (xmlHashLookup(style->extInfos, parent->ns->href) != NULL))
144	    return;
145
146        parent = parent->parent;
147    }
148    xsltTransformError(NULL, style, inst,
149	    "element %s only allowed within a template, variable or param\n",
150		           inst->name);
151    style->errors++;
152}
153
154/**
155 * xsltCheckParentElement:
156 * @style: the XSLT stylesheet
157 * @inst: the XSLT instruction
158 * @allow1: allowed parent1
159 * @allow2: allowed parent2
160 *
161 * Check that the instruction is instanciated as the childre of one of the
162 * possible parents.
163 */
164static void
165xsltCheckParentElement(xsltStylesheetPtr style, xmlNodePtr inst,
166                       const xmlChar *allow1, const xmlChar *allow2) {
167    xmlNodePtr parent;
168
169    if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||
170        (style->literal_result))
171        return;
172
173    parent = inst->parent;
174    if (parent == NULL) {
175	xsltTransformError(NULL, style, inst,
176		"internal problem: element has no parent\n");
177	style->errors++;
178	return;
179    }
180    if (((parent->ns == inst->ns) ||
181	 ((parent->ns != NULL) &&
182	  (xmlStrEqual(parent->ns->href, inst->ns->href)))) &&
183	((xmlStrEqual(parent->name, allow1)) ||
184	 (xmlStrEqual(parent->name, allow2)))) {
185	return;
186    }
187
188    if (style->extInfos != NULL) {
189	while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) {
190	    /*
191	     * if we are within an extension element all bets are off
192	     * about the semantic there e.g. xsl:param within func:function
193	     */
194	    if ((parent->ns != NULL) &&
195		(xmlHashLookup(style->extInfos, parent->ns->href) != NULL))
196		return;
197
198	    parent = parent->parent;
199	}
200    }
201    xsltTransformError(NULL, style, inst,
202		       "element %s is not allowed within that context\n",
203		       inst->name);
204    style->errors++;
205}
206#endif
207
208/************************************************************************
209 *									*
210 *			handling of precomputed data			*
211 *									*
212 ************************************************************************/
213
214/**
215 * xsltNewStylePreComp:
216 * @style:  the XSLT stylesheet
217 * @type:  the construct type
218 *
219 * Create a new XSLT Style precomputed block
220 *
221 * Returns the newly allocated specialized structure
222 *         or NULL in case of error
223 */
224static xsltStylePreCompPtr
225xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) {
226    xsltStylePreCompPtr cur;
227#ifdef XSLT_REFACTORED
228    size_t size;
229#endif
230
231    if (style == NULL)
232        return(NULL);
233
234#ifdef XSLT_REFACTORED
235    /*
236    * URGENT TODO: Use specialized factory functions in order
237    *   to avoid this ugliness.
238    */
239    switch (type) {
240        case XSLT_FUNC_COPY:
241            size = sizeof(xsltStyleItemCopy); break;
242        case XSLT_FUNC_SORT:
243            size = sizeof(xsltStyleItemSort); break;
244        case XSLT_FUNC_TEXT:
245            size = sizeof(xsltStyleItemText); break;
246        case XSLT_FUNC_ELEMENT:
247            size = sizeof(xsltStyleItemElement); break;
248        case XSLT_FUNC_ATTRIBUTE:
249            size = sizeof(xsltStyleItemAttribute); break;
250        case XSLT_FUNC_COMMENT:
251            size = sizeof(xsltStyleItemComment); break;
252        case XSLT_FUNC_PI:
253            size = sizeof(xsltStyleItemPI); break;
254        case XSLT_FUNC_COPYOF:
255            size = sizeof(xsltStyleItemCopyOf); break;
256        case XSLT_FUNC_VALUEOF:
257            size = sizeof(xsltStyleItemValueOf); break;;
258        case XSLT_FUNC_NUMBER:
259            size = sizeof(xsltStyleItemNumber); break;
260        case XSLT_FUNC_APPLYIMPORTS:
261            size = sizeof(xsltStyleItemApplyImports); break;
262        case XSLT_FUNC_CALLTEMPLATE:
263            size = sizeof(xsltStyleItemCallTemplate); break;
264        case XSLT_FUNC_APPLYTEMPLATES:
265            size = sizeof(xsltStyleItemApplyTemplates); break;
266        case XSLT_FUNC_CHOOSE:
267            size = sizeof(xsltStyleItemChoose); break;
268        case XSLT_FUNC_IF:
269            size = sizeof(xsltStyleItemIf); break;
270        case XSLT_FUNC_FOREACH:
271            size = sizeof(xsltStyleItemForEach); break;
272        case XSLT_FUNC_DOCUMENT:
273            size = sizeof(xsltStyleItemDocument); break;
274	case XSLT_FUNC_WITHPARAM:
275	    size = sizeof(xsltStyleItemWithParam); break;
276	case XSLT_FUNC_PARAM:
277	    size = sizeof(xsltStyleItemParam); break;
278	case XSLT_FUNC_VARIABLE:
279	    size = sizeof(xsltStyleItemVariable); break;
280	case XSLT_FUNC_WHEN:
281	    size = sizeof(xsltStyleItemWhen); break;
282	case XSLT_FUNC_OTHERWISE:
283	    size = sizeof(xsltStyleItemOtherwise); break;
284	default:
285	    xsltTransformError(NULL, style, NULL,
286		    "xsltNewStylePreComp : invalid type %d\n", type);
287	    style->errors++;
288	    return(NULL);
289    }
290    /*
291    * Create the structure.
292    */
293    cur = (xsltStylePreCompPtr) xmlMalloc(size);
294    if (cur == NULL) {
295	xsltTransformError(NULL, style, NULL,
296		"xsltNewStylePreComp : malloc failed\n");
297	style->errors++;
298	return(NULL);
299    }
300    memset(cur, 0, size);
301
302#else /* XSLT_REFACTORED */
303    /*
304    * Old behaviour.
305    */
306    cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp));
307    if (cur == NULL) {
308	xsltTransformError(NULL, style, NULL,
309		"xsltNewStylePreComp : malloc failed\n");
310	style->errors++;
311	return(NULL);
312    }
313    memset(cur, 0, sizeof(xsltStylePreComp));
314#endif /* XSLT_REFACTORED */
315
316    /*
317    * URGENT TODO: Better to move this to spezialized factory functions.
318    */
319    cur->type = type;
320    switch (cur->type) {
321        case XSLT_FUNC_COPY:
322            cur->func = (xsltTransformFunction) xsltCopy;break;
323        case XSLT_FUNC_SORT:
324            cur->func = (xsltTransformFunction) xsltSort;break;
325        case XSLT_FUNC_TEXT:
326            cur->func = (xsltTransformFunction) xsltText;break;
327        case XSLT_FUNC_ELEMENT:
328            cur->func = (xsltTransformFunction) xsltElement;break;
329        case XSLT_FUNC_ATTRIBUTE:
330            cur->func = (xsltTransformFunction) xsltAttribute;break;
331        case XSLT_FUNC_COMMENT:
332            cur->func = (xsltTransformFunction) xsltComment;break;
333        case XSLT_FUNC_PI:
334            cur->func = (xsltTransformFunction) xsltProcessingInstruction;
335	    break;
336        case XSLT_FUNC_COPYOF:
337            cur->func = (xsltTransformFunction) xsltCopyOf;break;
338        case XSLT_FUNC_VALUEOF:
339            cur->func = (xsltTransformFunction) xsltValueOf;break;
340        case XSLT_FUNC_NUMBER:
341            cur->func = (xsltTransformFunction) xsltNumber;break;
342        case XSLT_FUNC_APPLYIMPORTS:
343            cur->func = (xsltTransformFunction) xsltApplyImports;break;
344        case XSLT_FUNC_CALLTEMPLATE:
345            cur->func = (xsltTransformFunction) xsltCallTemplate;break;
346        case XSLT_FUNC_APPLYTEMPLATES:
347            cur->func = (xsltTransformFunction) xsltApplyTemplates;break;
348        case XSLT_FUNC_CHOOSE:
349            cur->func = (xsltTransformFunction) xsltChoose;break;
350        case XSLT_FUNC_IF:
351            cur->func = (xsltTransformFunction) xsltIf;break;
352        case XSLT_FUNC_FOREACH:
353            cur->func = (xsltTransformFunction) xsltForEach;break;
354        case XSLT_FUNC_DOCUMENT:
355            cur->func = (xsltTransformFunction) xsltDocumentElem;break;
356	case XSLT_FUNC_WITHPARAM:
357	case XSLT_FUNC_PARAM:
358	case XSLT_FUNC_VARIABLE:
359	case XSLT_FUNC_WHEN:
360	    break;
361	default:
362	if (cur->func == NULL) {
363	    xsltTransformError(NULL, style, NULL,
364		    "xsltNewStylePreComp : no function for type %d\n", type);
365	    style->errors++;
366	}
367    }
368    cur->next = style->preComps;
369    style->preComps = (xsltElemPreCompPtr) cur;
370
371    return(cur);
372}
373
374/**
375 * xsltFreeStylePreComp:
376 * @comp:  an XSLT Style precomputed block
377 *
378 * Free up the memory allocated by @comp
379 */
380static void
381xsltFreeStylePreComp(xsltStylePreCompPtr comp) {
382    if (comp == NULL)
383	return;
384#ifdef XSLT_REFACTORED
385    /*
386    * URGENT TODO: Implement destructors.
387    */
388    switch (comp->type) {
389	case XSLT_FUNC_LITERAL_RESULT_ELEMENT:
390	    break;
391	case XSLT_FUNC_COPY:
392            break;
393        case XSLT_FUNC_SORT: {
394		xsltStyleItemSortPtr item = (xsltStyleItemSortPtr) comp;
395		if (item->locale != (xsltLocale)0)
396		    xsltFreeLocale(item->locale);
397		if (item->comp != NULL)
398		    xmlXPathFreeCompExpr(item->comp);
399	    }
400            break;
401        case XSLT_FUNC_TEXT:
402            break;
403        case XSLT_FUNC_ELEMENT:
404            break;
405        case XSLT_FUNC_ATTRIBUTE:
406            break;
407        case XSLT_FUNC_COMMENT:
408            break;
409        case XSLT_FUNC_PI:
410	    break;
411        case XSLT_FUNC_COPYOF: {
412		xsltStyleItemCopyOfPtr item = (xsltStyleItemCopyOfPtr) comp;
413		if (item->comp != NULL)
414		    xmlXPathFreeCompExpr(item->comp);
415	    }
416            break;
417        case XSLT_FUNC_VALUEOF: {
418		xsltStyleItemValueOfPtr item = (xsltStyleItemValueOfPtr) comp;
419		if (item->comp != NULL)
420		    xmlXPathFreeCompExpr(item->comp);
421	    }
422            break;
423        case XSLT_FUNC_NUMBER: {
424                xsltStyleItemNumberPtr item = (xsltStyleItemNumberPtr) comp;
425                if (item->numdata.countPat != NULL)
426                    xsltFreeCompMatchList(item->numdata.countPat);
427                if (item->numdata.fromPat != NULL)
428                    xsltFreeCompMatchList(item->numdata.fromPat);
429            }
430            break;
431        case XSLT_FUNC_APPLYIMPORTS:
432            break;
433        case XSLT_FUNC_CALLTEMPLATE:
434            break;
435        case XSLT_FUNC_APPLYTEMPLATES: {
436		xsltStyleItemApplyTemplatesPtr item =
437		    (xsltStyleItemApplyTemplatesPtr) comp;
438		if (item->comp != NULL)
439		    xmlXPathFreeCompExpr(item->comp);
440	    }
441            break;
442        case XSLT_FUNC_CHOOSE:
443            break;
444        case XSLT_FUNC_IF: {
445		xsltStyleItemIfPtr item = (xsltStyleItemIfPtr) comp;
446		if (item->comp != NULL)
447		    xmlXPathFreeCompExpr(item->comp);
448	    }
449            break;
450        case XSLT_FUNC_FOREACH: {
451		xsltStyleItemForEachPtr item =
452		    (xsltStyleItemForEachPtr) comp;
453		if (item->comp != NULL)
454		    xmlXPathFreeCompExpr(item->comp);
455	    }
456            break;
457        case XSLT_FUNC_DOCUMENT:
458            break;
459	case XSLT_FUNC_WITHPARAM: {
460		xsltStyleItemWithParamPtr item =
461		    (xsltStyleItemWithParamPtr) comp;
462		if (item->comp != NULL)
463		    xmlXPathFreeCompExpr(item->comp);
464	    }
465	    break;
466	case XSLT_FUNC_PARAM: {
467		xsltStyleItemParamPtr item =
468		    (xsltStyleItemParamPtr) comp;
469		if (item->comp != NULL)
470		    xmlXPathFreeCompExpr(item->comp);
471	    }
472	    break;
473	case XSLT_FUNC_VARIABLE: {
474		xsltStyleItemVariablePtr item =
475		    (xsltStyleItemVariablePtr) comp;
476		if (item->comp != NULL)
477		    xmlXPathFreeCompExpr(item->comp);
478	    }
479	    break;
480	case XSLT_FUNC_WHEN: {
481		xsltStyleItemWhenPtr item =
482		    (xsltStyleItemWhenPtr) comp;
483		if (item->comp != NULL)
484		    xmlXPathFreeCompExpr(item->comp);
485	    }
486	    break;
487	case XSLT_FUNC_OTHERWISE:
488	case XSLT_FUNC_FALLBACK:
489	case XSLT_FUNC_MESSAGE:
490	case XSLT_FUNC_INCLUDE:
491	case XSLT_FUNC_ATTRSET:
492
493	    break;
494	default:
495	    /* TODO: Raise error. */
496	    break;
497    }
498#else
499    if (comp->locale != (xsltLocale)0)
500	xsltFreeLocale(comp->locale);
501    if (comp->comp != NULL)
502	xmlXPathFreeCompExpr(comp->comp);
503    if (comp->numdata.countPat != NULL)
504        xsltFreeCompMatchList(comp->numdata.countPat);
505    if (comp->numdata.fromPat != NULL)
506        xsltFreeCompMatchList(comp->numdata.fromPat);
507    if (comp->nsList != NULL)
508	xmlFree(comp->nsList);
509#endif
510
511    xmlFree(comp);
512}
513
514
515/************************************************************************
516 *									*
517 *		    XSLT-1.1 extensions					*
518 *									*
519 ************************************************************************/
520
521/**
522 * xsltDocumentComp:
523 * @style:  the XSLT stylesheet
524 * @inst:  the instruction in the stylesheet
525 * @function:  unused
526 *
527 * Pre process an XSLT-1.1 document element
528 *
529 * Returns a precompiled data structure for the element
530 */
531xsltElemPreCompPtr
532xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst,
533		 xsltTransformFunction function ATTRIBUTE_UNUSED) {
534#ifdef XSLT_REFACTORED
535    xsltStyleItemDocumentPtr comp;
536#else
537    xsltStylePreCompPtr comp;
538#endif
539    const xmlChar *filename = NULL;
540
541    /*
542    * As of 2006-03-30, this function is currently defined in Libxslt
543    * to be used for:
544    * (in libxslt/extra.c)
545    * "output" in XSLT_SAXON_NAMESPACE
546    * "write" XSLT_XALAN_NAMESPACE
547    * "document" XSLT_XT_NAMESPACE
548    * "document" XSLT_NAMESPACE (from the abandoned old working
549    *                            draft of XSLT 1.1)
550    * (in libexslt/common.c)
551    * "document" in EXSLT_COMMON_NAMESPACE
552    */
553#ifdef XSLT_REFACTORED
554    comp = (xsltStyleItemDocumentPtr)
555	xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);
556#else
557    comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);
558#endif
559
560    if (comp == NULL)
561	return (NULL);
562    comp->inst = inst;
563    comp->ver11 = 0;
564
565    if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
566#ifdef WITH_XSLT_DEBUG_EXTRA
567	xsltGenericDebug(xsltGenericDebugContext,
568	    "Found saxon:output extension\n");
569#endif
570	/*
571	* The element "output" is in the namespace XSLT_SAXON_NAMESPACE
572	*   (http://icl.com/saxon)
573	* The @file is in no namespace; it is an AVT.
574	*   (http://www.computerwizards.com/saxon/doc/extensions.html#saxon:output)
575	*
576	* TODO: Do we need not to check the namespace here?
577	*/
578	filename = xsltEvalStaticAttrValueTemplate(style, inst,
579			 (const xmlChar *)"file",
580			 NULL, &comp->has_filename);
581    } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
582#ifdef WITH_XSLT_DEBUG_EXTRA
583	xsltGenericDebug(xsltGenericDebugContext,
584	    "Found xalan:write extension\n");
585#endif
586	/* the filename need to be interpreted */
587	/*
588	* TODO: Is "filename need to be interpreted" meant to be a todo?
589	*   Where will be the filename of xalan:write be processed?
590	*
591	* TODO: Do we need not to check the namespace here?
592	*   The extension ns is "http://xml.apache.org/xalan/redirect".
593	*   See http://xml.apache.org/xalan-j/extensionslib.html.
594	*/
595    } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
596	if (inst->ns != NULL) {
597	    if (xmlStrEqual(inst->ns->href, XSLT_NAMESPACE)) {
598		/*
599		* Mark the instruction as being of
600		* XSLT version 1.1 (abandoned).
601		*/
602		comp->ver11 = 1;
603#ifdef WITH_XSLT_DEBUG_EXTRA
604		xsltGenericDebug(xsltGenericDebugContext,
605		    "Found xslt11:document construct\n");
606#endif
607	    } else {
608		if (xmlStrEqual(inst->ns->href,
609		    (const xmlChar *)"http://exslt.org/common")) {
610		    /* EXSLT. */
611#ifdef WITH_XSLT_DEBUG_EXTRA
612		    xsltGenericDebug(xsltGenericDebugContext,
613			"Found exslt:document extension\n");
614#endif
615		} else if (xmlStrEqual(inst->ns->href, XSLT_XT_NAMESPACE)) {
616		    /* James Clark's XT. */
617#ifdef WITH_XSLT_DEBUG_EXTRA
618		    xsltGenericDebug(xsltGenericDebugContext,
619			"Found xt:document extension\n");
620#endif
621		}
622	    }
623	}
624	/*
625	* The element "document" is used in conjunction with the
626	* following namespaces:
627	*
628	* 1) XSLT_NAMESPACE (http://www.w3.org/1999/XSL/Transform version 1.1)
629	*    <!ELEMENT xsl:document %template;>
630	*    <!ATTLIST xsl:document
631	*       href %avt; #REQUIRED
632	*    @href is an AVT
633	*    IMPORTANT: xsl:document was in the abandoned XSLT 1.1 draft,
634	*    it was removed and isn't available in XSLT 1.1 anymore.
635	*    In XSLT 2.0 it was renamed to xsl:result-document.
636	*
637	*   All other attributes are identical to the attributes
638	*   on xsl:output
639	*
640	* 2) EXSLT_COMMON_NAMESPACE (http://exslt.org/common)
641	*    <exsl:document
642	*       href = { uri-reference }
643	*    TODO: is @href is an AVT?
644	*
645	* 3) XSLT_XT_NAMESPACE (http://www.jclark.com/xt)
646	*     Example: <xt:document method="xml" href="myFile.xml">
647	*    TODO: is @href is an AVT?
648	*
649	* In all cases @href is in no namespace.
650	*/
651	filename = xsltEvalStaticAttrValueTemplate(style, inst,
652	    (const xmlChar *)"href", NULL, &comp->has_filename);
653    }
654    if (!comp->has_filename) {
655	goto error;
656    }
657    comp->filename = filename;
658
659error:
660    return ((xsltElemPreCompPtr) comp);
661}
662
663/************************************************************************
664 *									*
665 *		Most of the XSLT-1.0 transformations			*
666 *									*
667 ************************************************************************/
668
669/**
670 * xsltSortComp:
671 * @style:  the XSLT stylesheet
672 * @inst:  the xslt sort node
673 *
674 * Process the xslt sort node on the source node
675 */
676static void
677xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) {
678#ifdef XSLT_REFACTORED
679    xsltStyleItemSortPtr comp;
680#else
681    xsltStylePreCompPtr comp;
682#endif
683    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
684	return;
685
686#ifdef XSLT_REFACTORED
687    comp = (xsltStyleItemSortPtr) xsltNewStylePreComp(style, XSLT_FUNC_SORT);
688#else
689    comp = xsltNewStylePreComp(style, XSLT_FUNC_SORT);
690#endif
691
692    if (comp == NULL)
693	return;
694    inst->psvi = comp;
695    comp->inst = inst;
696
697    comp->stype = xsltEvalStaticAttrValueTemplate(style, inst,
698			 (const xmlChar *)"data-type",
699			 NULL, &comp->has_stype);
700    if (comp->stype != NULL) {
701	if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
702	    comp->number = 0;
703	else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
704	    comp->number = 1;
705	else {
706	    xsltTransformError(NULL, style, inst,
707		 "xsltSortComp: no support for data-type = %s\n", comp->stype);
708	    comp->number = 0; /* use default */
709	    if (style != NULL) style->warnings++;
710	}
711    }
712    comp->order = xsltEvalStaticAttrValueTemplate(style, inst,
713			      (const xmlChar *)"order",
714			      NULL, &comp->has_order);
715    if (comp->order != NULL) {
716	if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
717	    comp->descending = 0;
718	else if (xmlStrEqual(comp->order, (const xmlChar *) "descending"))
719	    comp->descending = 1;
720	else {
721	    xsltTransformError(NULL, style, inst,
722		 "xsltSortComp: invalid value %s for order\n", comp->order);
723	    comp->descending = 0; /* use default */
724	    if (style != NULL) style->warnings++;
725	}
726    }
727    comp->case_order = xsltEvalStaticAttrValueTemplate(style, inst,
728			      (const xmlChar *)"case-order",
729			      NULL, &comp->has_use);
730    if (comp->case_order != NULL) {
731	if (xmlStrEqual(comp->case_order, (const xmlChar *) "upper-first"))
732	    comp->lower_first = 0;
733	else if (xmlStrEqual(comp->case_order, (const xmlChar *) "lower-first"))
734	    comp->lower_first = 1;
735	else {
736	    xsltTransformError(NULL, style, inst,
737		 "xsltSortComp: invalid value %s for order\n", comp->order);
738	    comp->lower_first = 0; /* use default */
739	    if (style != NULL) style->warnings++;
740	}
741    }
742
743    comp->lang = xsltEvalStaticAttrValueTemplate(style, inst,
744				 (const xmlChar *)"lang",
745				 NULL, &comp->has_lang);
746    if (comp->lang != NULL) {
747	comp->locale = xsltNewLocale(comp->lang);
748    }
749    else {
750        comp->locale = (xsltLocale)0;
751    }
752
753    comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE);
754    if (comp->select == NULL) {
755	/*
756	 * The default value of the select attribute is ., which will
757	 * cause the string-value of the current node to be used as
758	 * the sort key.
759	 */
760	comp->select = xmlDictLookup(style->dict, BAD_CAST ".", 1);
761    }
762    comp->comp = xsltXPathCompile(style, comp->select);
763    if (comp->comp == NULL) {
764	xsltTransformError(NULL, style, inst,
765	     "xsltSortComp: could not compile select expression '%s'\n",
766	                 comp->select);
767	if (style != NULL) style->errors++;
768    }
769    if (inst->children != NULL) {
770	xsltTransformError(NULL, style, inst,
771	"xsl:sort : is not empty\n");
772	if (style != NULL) style->errors++;
773    }
774}
775
776/**
777 * xsltCopyComp:
778 * @style:  the XSLT stylesheet
779 * @inst:  the xslt copy node
780 *
781 * Process the xslt copy node on the source node
782 */
783static void
784xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) {
785#ifdef XSLT_REFACTORED
786    xsltStyleItemCopyPtr comp;
787#else
788    xsltStylePreCompPtr comp;
789#endif
790
791    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
792	return;
793#ifdef XSLT_REFACTORED
794    comp = (xsltStyleItemCopyPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPY);
795#else
796    comp = xsltNewStylePreComp(style, XSLT_FUNC_COPY);
797#endif
798
799    if (comp == NULL)
800	return;
801    inst->psvi = comp;
802    comp->inst = inst;
803
804
805    comp->use = xsltGetCNsProp(style, inst, (const xmlChar *)"use-attribute-sets",
806				    XSLT_NAMESPACE);
807    if (comp->use == NULL)
808	comp->has_use = 0;
809    else
810	comp->has_use = 1;
811}
812
813#ifdef XSLT_REFACTORED
814    /* Enable if ever needed for xsl:text. */
815#else
816/**
817 * xsltTextComp:
818 * @style: an XSLT compiled stylesheet
819 * @inst:  the xslt text node
820 *
821 * TODO: This function is obsolete, since xsl:text won't
822 *  be compiled, but removed from the tree.
823 *
824 * Process the xslt text node on the source node
825 */
826static void
827xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) {
828#ifdef XSLT_REFACTORED
829    xsltStyleItemTextPtr comp;
830#else
831    xsltStylePreCompPtr comp;
832#endif
833    const xmlChar *prop;
834
835    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
836	return;
837
838#ifdef XSLT_REFACTORED
839    comp = (xsltStyleItemTextPtr) xsltNewStylePreComp(style, XSLT_FUNC_TEXT);
840#else
841    comp = xsltNewStylePreComp(style, XSLT_FUNC_TEXT);
842#endif
843    if (comp == NULL)
844	return;
845    inst->psvi = comp;
846    comp->inst = inst;
847    comp->noescape = 0;
848
849    prop = xsltGetCNsProp(style, inst,
850	    (const xmlChar *)"disable-output-escaping",
851			XSLT_NAMESPACE);
852    if (prop != NULL) {
853	if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
854	    comp->noescape = 1;
855	} else if (!xmlStrEqual(prop,
856	    (const xmlChar *)"no")){
857	    xsltTransformError(NULL, style, inst,
858		"xsl:text: disable-output-escaping allows only yes or no\n");
859	    if (style != NULL) style->warnings++;
860	}
861    }
862}
863#endif /* else of XSLT_REFACTORED */
864
865/**
866 * xsltElementComp:
867 * @style: an XSLT compiled stylesheet
868 * @inst:  the xslt element node
869 *
870 * Process the xslt element node on the source node
871 */
872static void
873xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) {
874#ifdef XSLT_REFACTORED
875    xsltStyleItemElementPtr comp;
876#else
877    xsltStylePreCompPtr comp;
878#endif
879
880    /*
881    * <xsl:element
882    *   name = { qname }
883    *   namespace = { uri-reference }
884    *   use-attribute-sets = qnames>
885    *   <!-- Content: template -->
886    * </xsl:element>
887    */
888    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
889	return;
890
891#ifdef XSLT_REFACTORED
892    comp = (xsltStyleItemElementPtr) xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);
893#else
894    comp = xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);
895#endif
896
897    if (comp == NULL)
898	return;
899    inst->psvi = comp;
900    comp->inst = inst;
901
902    /*
903    * Attribute "name".
904    */
905    /*
906    * TODO: Precompile the AVT. See bug #344894.
907    */
908    comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
909	(const xmlChar *)"name", NULL, &comp->has_name);
910    if (! comp->has_name) {
911	xsltTransformError(NULL, style, inst,
912	    "xsl:element: The attribute 'name' is missing.\n");
913	style->errors++;
914	goto error;
915    }
916    /*
917    * Attribute "namespace".
918    */
919    /*
920    * TODO: Precompile the AVT. See bug #344894.
921    */
922    comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
923	(const xmlChar *)"namespace", NULL, &comp->has_ns);
924
925    if (comp->name != NULL) {
926	if (xmlValidateQName(comp->name, 0)) {
927	    xsltTransformError(NULL, style, inst,
928		"xsl:element: The value '%s' of the attribute 'name' is "
929		"not a valid QName.\n", comp->name);
930	    style->errors++;
931	} else {
932	    const xmlChar *prefix = NULL, *name;
933
934	    name = xsltSplitQName(style->dict, comp->name, &prefix);
935	    if (comp->has_ns == 0) {
936		xmlNsPtr ns;
937
938		/*
939		* SPEC XSLT 1.0:
940		*  "If the namespace attribute is not present, then the QName is
941		*  expanded into an expanded-name using the namespace declarations
942		*  in effect for the xsl:element element, including any default
943		*  namespace declaration.
944		*/
945		ns = xmlSearchNs(inst->doc, inst, prefix);
946		if (ns != NULL) {
947		    comp->ns = xmlDictLookup(style->dict, ns->href, -1);
948		    comp->has_ns = 1;
949#ifdef XSLT_REFACTORED
950		    comp->nsPrefix = prefix;
951		    comp->name = name;
952#endif
953		} else if (prefix != NULL) {
954		    xsltTransformError(NULL, style, inst,
955			"xsl:element: The prefixed QName '%s' "
956			"has no namespace binding in scope in the "
957			"stylesheet; this is an error, since the namespace was "
958			"not specified by the instruction itself.\n", comp->name);
959		    style->errors++;
960		}
961	    }
962	    if ((prefix != NULL) &&
963		(!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))
964	    {
965		/*
966		* Mark is to be skipped.
967		*/
968		comp->has_name = 0;
969	    }
970	}
971    }
972    /*
973    * Attribute "use-attribute-sets",
974    */
975    comp->use = xsltEvalStaticAttrValueTemplate(style, inst,
976		       (const xmlChar *)"use-attribute-sets",
977		       NULL, &comp->has_use);
978
979error:
980    return;
981}
982
983/**
984 * xsltAttributeComp:
985 * @style: an XSLT compiled stylesheet
986 * @inst:  the xslt attribute node
987 *
988 * Process the xslt attribute node on the source node
989 */
990static void
991xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) {
992#ifdef XSLT_REFACTORED
993    xsltStyleItemAttributePtr comp;
994#else
995    xsltStylePreCompPtr comp;
996#endif
997
998    /*
999    * <xsl:attribute
1000    *   name = { qname }
1001    *   namespace = { uri-reference }>
1002    *   <!-- Content: template -->
1003    * </xsl:attribute>
1004    */
1005    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1006	return;
1007
1008#ifdef XSLT_REFACTORED
1009    comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style,
1010	XSLT_FUNC_ATTRIBUTE);
1011#else
1012    comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE);
1013#endif
1014
1015    if (comp == NULL)
1016	return;
1017    inst->psvi = comp;
1018    comp->inst = inst;
1019
1020    /*
1021    * Attribute "name".
1022    */
1023    /*
1024    * TODO: Precompile the AVT. See bug #344894.
1025    */
1026    comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
1027				 (const xmlChar *)"name",
1028				 NULL, &comp->has_name);
1029    if (! comp->has_name) {
1030	xsltTransformError(NULL, style, inst,
1031	    "XSLT-attribute: The attribute 'name' is missing.\n");
1032	style->errors++;
1033	return;
1034    }
1035    /*
1036    * Attribute "namespace".
1037    */
1038    /*
1039    * TODO: Precompile the AVT. See bug #344894.
1040    */
1041    comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
1042	(const xmlChar *)"namespace",
1043	NULL, &comp->has_ns);
1044
1045    if (comp->name != NULL) {
1046	if (xmlValidateQName(comp->name, 0)) {
1047	    xsltTransformError(NULL, style, inst,
1048		"xsl:attribute: The value '%s' of the attribute 'name' is "
1049		"not a valid QName.\n", comp->name);
1050	    style->errors++;
1051        } else if (xmlStrEqual(comp->name, BAD_CAST "xmlns")) {
1052	    xsltTransformError(NULL, style, inst,
1053                "xsl:attribute: The attribute name 'xmlns' is not allowed.\n");
1054	    style->errors++;
1055	} else {
1056	    const xmlChar *prefix = NULL, *name;
1057
1058	    name = xsltSplitQName(style->dict, comp->name, &prefix);
1059	    if (prefix != NULL) {
1060		if (comp->has_ns == 0) {
1061		    xmlNsPtr ns;
1062
1063		    /*
1064		    * SPEC XSLT 1.0:
1065		    *  "If the namespace attribute is not present, then the
1066		    *  QName is expanded into an expanded-name using the
1067		    *  namespace declarations in effect for the xsl:element
1068		    *  element, including any default namespace declaration.
1069		    */
1070		    ns = xmlSearchNs(inst->doc, inst, prefix);
1071		    if (ns != NULL) {
1072			comp->ns = xmlDictLookup(style->dict, ns->href, -1);
1073			comp->has_ns = 1;
1074#ifdef XSLT_REFACTORED
1075			comp->nsPrefix = prefix;
1076			comp->name = name;
1077#endif
1078		    } else {
1079			xsltTransformError(NULL, style, inst,
1080			    "xsl:attribute: The prefixed QName '%s' "
1081			    "has no namespace binding in scope in the "
1082			    "stylesheet; this is an error, since the "
1083			    "namespace was not specified by the instruction "
1084			    "itself.\n", comp->name);
1085			style->errors++;
1086		    }
1087		}
1088	    }
1089	}
1090    }
1091}
1092
1093/**
1094 * xsltCommentComp:
1095 * @style: an XSLT compiled stylesheet
1096 * @inst:  the xslt comment node
1097 *
1098 * Process the xslt comment node on the source node
1099 */
1100static void
1101xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1102#ifdef XSLT_REFACTORED
1103    xsltStyleItemCommentPtr comp;
1104#else
1105    xsltStylePreCompPtr comp;
1106#endif
1107
1108    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1109	return;
1110
1111#ifdef XSLT_REFACTORED
1112    comp = (xsltStyleItemCommentPtr) xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);
1113#else
1114    comp = xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);
1115#endif
1116
1117    if (comp == NULL)
1118	return;
1119    inst->psvi = comp;
1120    comp->inst = inst;
1121}
1122
1123/**
1124 * xsltProcessingInstructionComp:
1125 * @style: an XSLT compiled stylesheet
1126 * @inst:  the xslt processing-instruction node
1127 *
1128 * Process the xslt processing-instruction node on the source node
1129 */
1130static void
1131xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1132#ifdef XSLT_REFACTORED
1133    xsltStyleItemPIPtr comp;
1134#else
1135    xsltStylePreCompPtr comp;
1136#endif
1137
1138    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1139	return;
1140
1141#ifdef XSLT_REFACTORED
1142    comp = (xsltStyleItemPIPtr) xsltNewStylePreComp(style, XSLT_FUNC_PI);
1143#else
1144    comp = xsltNewStylePreComp(style, XSLT_FUNC_PI);
1145#endif
1146
1147    if (comp == NULL)
1148	return;
1149    inst->psvi = comp;
1150    comp->inst = inst;
1151
1152    comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
1153				 (const xmlChar *)"name",
1154				 XSLT_NAMESPACE, &comp->has_name);
1155}
1156
1157/**
1158 * xsltCopyOfComp:
1159 * @style: an XSLT compiled stylesheet
1160 * @inst:  the xslt copy-of node
1161 *
1162 * Process the xslt copy-of node on the source node
1163 */
1164static void
1165xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1166#ifdef XSLT_REFACTORED
1167    xsltStyleItemCopyOfPtr comp;
1168#else
1169    xsltStylePreCompPtr comp;
1170#endif
1171
1172    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1173	return;
1174
1175#ifdef XSLT_REFACTORED
1176    comp = (xsltStyleItemCopyOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);
1177#else
1178    comp = xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);
1179#endif
1180
1181    if (comp == NULL)
1182	return;
1183    inst->psvi = comp;
1184    comp->inst = inst;
1185
1186    comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1187	                        XSLT_NAMESPACE);
1188    if (comp->select == NULL) {
1189	xsltTransformError(NULL, style, inst,
1190	     "xsl:copy-of : select is missing\n");
1191	if (style != NULL) style->errors++;
1192	return;
1193    }
1194    comp->comp = xsltXPathCompile(style, comp->select);
1195    if (comp->comp == NULL) {
1196	xsltTransformError(NULL, style, inst,
1197	     "xsl:copy-of : could not compile select expression '%s'\n",
1198	                 comp->select);
1199	if (style != NULL) style->errors++;
1200    }
1201}
1202
1203/**
1204 * xsltValueOfComp:
1205 * @style: an XSLT compiled stylesheet
1206 * @inst:  the xslt value-of node
1207 *
1208 * Process the xslt value-of node on the source node
1209 */
1210static void
1211xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1212#ifdef XSLT_REFACTORED
1213    xsltStyleItemValueOfPtr comp;
1214#else
1215    xsltStylePreCompPtr comp;
1216#endif
1217    const xmlChar *prop;
1218
1219    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1220	return;
1221
1222#ifdef XSLT_REFACTORED
1223    comp = (xsltStyleItemValueOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);
1224#else
1225    comp = xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);
1226#endif
1227
1228    if (comp == NULL)
1229	return;
1230    inst->psvi = comp;
1231    comp->inst = inst;
1232
1233    prop = xsltGetCNsProp(style, inst,
1234	    (const xmlChar *)"disable-output-escaping",
1235			XSLT_NAMESPACE);
1236    if (prop != NULL) {
1237	if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
1238	    comp->noescape = 1;
1239	} else if (!xmlStrEqual(prop,
1240				(const xmlChar *)"no")){
1241	    xsltTransformError(NULL, style, inst,
1242"xsl:value-of : disable-output-escaping allows only yes or no\n");
1243	    if (style != NULL) style->warnings++;
1244	}
1245    }
1246    comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1247	                        XSLT_NAMESPACE);
1248    if (comp->select == NULL) {
1249	xsltTransformError(NULL, style, inst,
1250	     "xsl:value-of : select is missing\n");
1251	if (style != NULL) style->errors++;
1252	return;
1253    }
1254    comp->comp = xsltXPathCompile(style, comp->select);
1255    if (comp->comp == NULL) {
1256	xsltTransformError(NULL, style, inst,
1257	     "xsl:value-of : could not compile select expression '%s'\n",
1258	                 comp->select);
1259	if (style != NULL) style->errors++;
1260    }
1261}
1262
1263static void
1264xsltGetQNameProperty(xsltStylesheetPtr style, xmlNodePtr inst,
1265		     const xmlChar *propName,
1266		     int mandatory,
1267		     int *hasProp, const xmlChar **nsName,
1268		     const xmlChar** localName)
1269{
1270    const xmlChar *prop;
1271
1272    if (nsName)
1273	*nsName = NULL;
1274    if (localName)
1275	*localName = NULL;
1276    if (hasProp)
1277	*hasProp = 0;
1278
1279    prop = xsltGetCNsProp(style, inst, propName, XSLT_NAMESPACE);
1280    if (prop == NULL) {
1281	if (mandatory) {
1282	    xsltTransformError(NULL, style, inst,
1283		"The attribute '%s' is missing.\n", propName);
1284	    style->errors++;
1285	    return;
1286	}
1287    } else {
1288        const xmlChar *URI;
1289
1290	if (xmlValidateQName(prop, 0)) {
1291	    xsltTransformError(NULL, style, inst,
1292		"The value '%s' of the attribute "
1293		"'%s' is not a valid QName.\n", prop, propName);
1294	    style->errors++;
1295	    return;
1296	} else {
1297	    /*
1298	    * @prop will be in the string dict afterwards, @URI not.
1299	    */
1300	    URI = xsltGetQNameURI2(style, inst, &prop);
1301	    if (prop == NULL) {
1302		style->errors++;
1303	    } else {
1304		*localName = prop;
1305		if (hasProp)
1306		    *hasProp = 1;
1307		if (URI != NULL) {
1308		    /*
1309		    * Fixes bug #308441: Put the ns-name in the dict
1310		    * in order to pointer compare names during XPath's
1311		    * variable lookup.
1312		    */
1313		    if (nsName)
1314			*nsName = xmlDictLookup(style->dict, URI, -1);
1315		    /* comp->has_ns = 1; */
1316		}
1317	    }
1318	}
1319    }
1320    return;
1321}
1322
1323/**
1324 * xsltWithParamComp:
1325 * @style: an XSLT compiled stylesheet
1326 * @inst:  the xslt with-param node
1327 *
1328 * Process the xslt with-param node on the source node
1329 * Allowed parents: xsl:call-template, xsl:apply-templates.
1330 * <xsl:with-param
1331 *  name = qname
1332 *  select = expression>
1333 *  <!-- Content: template -->
1334 * </xsl:with-param>
1335 */
1336static void
1337xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1338#ifdef XSLT_REFACTORED
1339    xsltStyleItemWithParamPtr comp;
1340#else
1341    xsltStylePreCompPtr comp;
1342#endif
1343
1344    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1345	return;
1346
1347#ifdef XSLT_REFACTORED
1348    comp = (xsltStyleItemWithParamPtr) xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);
1349#else
1350    comp = xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);
1351#endif
1352
1353    if (comp == NULL)
1354	return;
1355    inst->psvi = comp;
1356    comp->inst = inst;
1357
1358    /*
1359    * Attribute "name".
1360    */
1361    xsltGetQNameProperty(style, inst, BAD_CAST "name",
1362	1, &(comp->has_name), &(comp->ns), &(comp->name));
1363    if (comp->ns)
1364	comp->has_ns = 1;
1365    /*
1366    * Attribute "select".
1367    */
1368    comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1369	                        XSLT_NAMESPACE);
1370    if (comp->select != NULL) {
1371	comp->comp = xsltXPathCompile(style, comp->select);
1372	if (comp->comp == NULL) {
1373	    xsltTransformError(NULL, style, inst,
1374		 "XSLT-with-param: Failed to compile select "
1375		 "expression '%s'\n", comp->select);
1376	    style->errors++;
1377	}
1378	if (inst->children != NULL) {
1379	    xsltTransformError(NULL, style, inst,
1380		"XSLT-with-param: The content should be empty since "
1381		"the attribute select is present.\n");
1382	    style->warnings++;
1383	}
1384    }
1385}
1386
1387/**
1388 * xsltNumberComp:
1389 * @style: an XSLT compiled stylesheet
1390 * @cur:   the xslt number node
1391 *
1392 * Process the xslt number node on the source node
1393 */
1394static void
1395xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) {
1396#ifdef XSLT_REFACTORED
1397    xsltStyleItemNumberPtr comp;
1398#else
1399    xsltStylePreCompPtr comp;
1400#endif
1401    const xmlChar *prop;
1402
1403    if ((style == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE))
1404	return;
1405
1406#ifdef XSLT_REFACTORED
1407    comp = (xsltStyleItemNumberPtr) xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);
1408#else
1409    comp = xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);
1410#endif
1411
1412    if (comp == NULL)
1413	return;
1414    cur->psvi = comp;
1415
1416    if ((style == NULL) || (cur == NULL))
1417	return;
1418
1419    comp->numdata.doc = cur->doc;
1420    comp->numdata.node = cur;
1421    comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value",
1422	                                XSLT_NAMESPACE);
1423
1424    prop = xsltEvalStaticAttrValueTemplate(style, cur,
1425			 (const xmlChar *)"format",
1426			 XSLT_NAMESPACE, &comp->numdata.has_format);
1427    if (comp->numdata.has_format == 0) {
1428	comp->numdata.format = xmlDictLookup(style->dict, BAD_CAST "" , 0);
1429    } else {
1430	comp->numdata.format = prop;
1431    }
1432
1433    comp->numdata.count = xsltGetCNsProp(style, cur, (const xmlChar *)"count",
1434                                         XSLT_NAMESPACE);
1435    comp->numdata.from = xsltGetCNsProp(style, cur, (const xmlChar *)"from",
1436                                        XSLT_NAMESPACE);
1437
1438    prop = xsltGetCNsProp(style, cur, (const xmlChar *)"count", XSLT_NAMESPACE);
1439    if (prop != NULL) {
1440	comp->numdata.countPat = xsltCompilePattern(prop, cur->doc, cur, style,
1441                                                    NULL);
1442    }
1443
1444    prop = xsltGetCNsProp(style, cur, (const xmlChar *)"from", XSLT_NAMESPACE);
1445    if (prop != NULL) {
1446	comp->numdata.fromPat = xsltCompilePattern(prop, cur->doc, cur, style,
1447                                                   NULL);
1448    }
1449
1450    prop = xsltGetCNsProp(style, cur, (const xmlChar *)"level", XSLT_NAMESPACE);
1451    if (prop != NULL) {
1452	if (xmlStrEqual(prop, BAD_CAST("single")) ||
1453	    xmlStrEqual(prop, BAD_CAST("multiple")) ||
1454	    xmlStrEqual(prop, BAD_CAST("any"))) {
1455	    comp->numdata.level = prop;
1456	} else {
1457	    xsltTransformError(NULL, style, cur,
1458			 "xsl:number : invalid value %s for level\n", prop);
1459	    if (style != NULL) style->warnings++;
1460	}
1461    }
1462
1463    prop = xsltGetCNsProp(style, cur, (const xmlChar *)"lang", XSLT_NAMESPACE);
1464    if (prop != NULL) {
1465	    xsltTransformError(NULL, style, cur,
1466		 "xsl:number : lang attribute not implemented\n");
1467	XSLT_TODO; /* xsl:number lang attribute */
1468    }
1469
1470    prop = xsltGetCNsProp(style, cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE);
1471    if (prop != NULL) {
1472	if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) {
1473	    xsltTransformError(NULL, style, cur,
1474		 "xsl:number : letter-value 'alphabetic' not implemented\n");
1475	    if (style != NULL) style->warnings++;
1476	    XSLT_TODO; /* xsl:number letter-value attribute alphabetic */
1477	} else if (xmlStrEqual(prop, BAD_CAST("traditional"))) {
1478	    xsltTransformError(NULL, style, cur,
1479		 "xsl:number : letter-value 'traditional' not implemented\n");
1480	    if (style != NULL) style->warnings++;
1481	    XSLT_TODO; /* xsl:number letter-value attribute traditional */
1482	} else {
1483	    xsltTransformError(NULL, style, cur,
1484		     "xsl:number : invalid value %s for letter-value\n", prop);
1485	    if (style != NULL) style->warnings++;
1486	}
1487    }
1488
1489    prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-separator",
1490	                XSLT_NAMESPACE);
1491    if (prop != NULL) {
1492        comp->numdata.groupingCharacterLen = xmlStrlen(prop);
1493	comp->numdata.groupingCharacter =
1494	    xsltGetUTF8Char(prop, &(comp->numdata.groupingCharacterLen));
1495    }
1496
1497    prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE);
1498    if (prop != NULL) {
1499	sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup);
1500    } else {
1501	comp->numdata.groupingCharacter = 0;
1502    }
1503
1504    /* Set default values */
1505    if (comp->numdata.value == NULL) {
1506	if (comp->numdata.level == NULL) {
1507	    comp->numdata.level = xmlDictLookup(style->dict,
1508	                                        BAD_CAST"single", 6);
1509	}
1510    }
1511
1512}
1513
1514/**
1515 * xsltApplyImportsComp:
1516 * @style: an XSLT compiled stylesheet
1517 * @inst:  the xslt apply-imports node
1518 *
1519 * Process the xslt apply-imports node on the source node
1520 */
1521static void
1522xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1523#ifdef XSLT_REFACTORED
1524    xsltStyleItemApplyImportsPtr comp;
1525#else
1526    xsltStylePreCompPtr comp;
1527#endif
1528
1529    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1530	return;
1531
1532#ifdef XSLT_REFACTORED
1533    comp = (xsltStyleItemApplyImportsPtr) xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);
1534#else
1535    comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);
1536#endif
1537
1538    if (comp == NULL)
1539	return;
1540    inst->psvi = comp;
1541    comp->inst = inst;
1542}
1543
1544/**
1545 * xsltCallTemplateComp:
1546 * @style: an XSLT compiled stylesheet
1547 * @inst:  the xslt call-template node
1548 *
1549 * Process the xslt call-template node on the source node
1550 */
1551static void
1552xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1553#ifdef XSLT_REFACTORED
1554    xsltStyleItemCallTemplatePtr comp;
1555#else
1556    xsltStylePreCompPtr comp;
1557#endif
1558
1559    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1560	return;
1561
1562#ifdef XSLT_REFACTORED
1563    comp = (xsltStyleItemCallTemplatePtr)
1564	xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);
1565#else
1566    comp = xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);
1567#endif
1568
1569    if (comp == NULL)
1570	return;
1571    inst->psvi = comp;
1572    comp->inst = inst;
1573
1574    /*
1575     * Attribute "name".
1576     */
1577    xsltGetQNameProperty(style, inst, BAD_CAST "name",
1578	1, &(comp->has_name), &(comp->ns), &(comp->name));
1579    if (comp->ns)
1580	comp->has_ns = 1;
1581}
1582
1583/**
1584 * xsltApplyTemplatesComp:
1585 * @style: an XSLT compiled stylesheet
1586 * @inst:  the apply-templates node
1587 *
1588 * Process the apply-templates node on the source node
1589 */
1590static void
1591xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1592#ifdef XSLT_REFACTORED
1593    xsltStyleItemApplyTemplatesPtr comp;
1594#else
1595    xsltStylePreCompPtr comp;
1596#endif
1597
1598    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1599	return;
1600
1601#ifdef XSLT_REFACTORED
1602    comp = (xsltStyleItemApplyTemplatesPtr)
1603	xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);
1604#else
1605    comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);
1606#endif
1607
1608    if (comp == NULL)
1609	return;
1610    inst->psvi = comp;
1611    comp->inst = inst;
1612
1613    /*
1614     * Attribute "mode".
1615     */
1616    xsltGetQNameProperty(style, inst, BAD_CAST "mode",
1617	0, NULL, &(comp->modeURI), &(comp->mode));
1618    /*
1619    * Attribute "select".
1620    */
1621    comp->select = xsltGetCNsProp(style, inst, BAD_CAST "select",
1622	XSLT_NAMESPACE);
1623    if (comp->select != NULL) {
1624	comp->comp = xsltXPathCompile(style, comp->select);
1625	if (comp->comp == NULL) {
1626	    xsltTransformError(NULL, style, inst,
1627		"XSLT-apply-templates: could not compile select "
1628		"expression '%s'\n", comp->select);
1629	     style->errors++;
1630	}
1631    }
1632    /* TODO: handle (or skip) the xsl:sort and xsl:with-param */
1633}
1634
1635/**
1636 * xsltChooseComp:
1637 * @style: an XSLT compiled stylesheet
1638 * @inst:  the xslt choose node
1639 *
1640 * Process the xslt choose node on the source node
1641 */
1642static void
1643xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1644#ifdef XSLT_REFACTORED
1645    xsltStyleItemChoosePtr comp;
1646#else
1647    xsltStylePreCompPtr comp;
1648#endif
1649
1650    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1651	return;
1652
1653#ifdef XSLT_REFACTORED
1654    comp = (xsltStyleItemChoosePtr)
1655	xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);
1656#else
1657    comp = xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);
1658#endif
1659
1660    if (comp == NULL)
1661	return;
1662    inst->psvi = comp;
1663    comp->inst = inst;
1664}
1665
1666/**
1667 * xsltIfComp:
1668 * @style: an XSLT compiled stylesheet
1669 * @inst:  the xslt if node
1670 *
1671 * Process the xslt if node on the source node
1672 */
1673static void
1674xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1675#ifdef XSLT_REFACTORED
1676    xsltStyleItemIfPtr comp;
1677#else
1678    xsltStylePreCompPtr comp;
1679#endif
1680
1681    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1682	return;
1683
1684#ifdef XSLT_REFACTORED
1685    comp = (xsltStyleItemIfPtr)
1686	xsltNewStylePreComp(style, XSLT_FUNC_IF);
1687#else
1688    comp = xsltNewStylePreComp(style, XSLT_FUNC_IF);
1689#endif
1690
1691    if (comp == NULL)
1692	return;
1693    inst->psvi = comp;
1694    comp->inst = inst;
1695
1696    comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE);
1697    if (comp->test == NULL) {
1698	xsltTransformError(NULL, style, inst,
1699	     "xsl:if : test is not defined\n");
1700	if (style != NULL) style->errors++;
1701	return;
1702    }
1703    comp->comp = xsltXPathCompile(style, comp->test);
1704    if (comp->comp == NULL) {
1705	xsltTransformError(NULL, style, inst,
1706	     "xsl:if : could not compile test expression '%s'\n",
1707	                 comp->test);
1708	if (style != NULL) style->errors++;
1709    }
1710}
1711
1712/**
1713 * xsltWhenComp:
1714 * @style: an XSLT compiled stylesheet
1715 * @inst:  the xslt if node
1716 *
1717 * Process the xslt if node on the source node
1718 */
1719static void
1720xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1721#ifdef XSLT_REFACTORED
1722    xsltStyleItemWhenPtr comp;
1723#else
1724    xsltStylePreCompPtr comp;
1725#endif
1726
1727    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1728	return;
1729
1730#ifdef XSLT_REFACTORED
1731    comp = (xsltStyleItemWhenPtr)
1732	xsltNewStylePreComp(style, XSLT_FUNC_WHEN);
1733#else
1734    comp = xsltNewStylePreComp(style, XSLT_FUNC_WHEN);
1735#endif
1736
1737    if (comp == NULL)
1738	return;
1739    inst->psvi = comp;
1740    comp->inst = inst;
1741
1742    comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE);
1743    if (comp->test == NULL) {
1744	xsltTransformError(NULL, style, inst,
1745	     "xsl:when : test is not defined\n");
1746	if (style != NULL) style->errors++;
1747	return;
1748    }
1749    comp->comp = xsltXPathCompile(style, comp->test);
1750    if (comp->comp == NULL) {
1751	xsltTransformError(NULL, style, inst,
1752	     "xsl:when : could not compile test expression '%s'\n",
1753	                 comp->test);
1754	if (style != NULL) style->errors++;
1755    }
1756}
1757
1758/**
1759 * xsltForEachComp:
1760 * @style: an XSLT compiled stylesheet
1761 * @inst:  the xslt for-each node
1762 *
1763 * Process the xslt for-each node on the source node
1764 */
1765static void
1766xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1767#ifdef XSLT_REFACTORED
1768    xsltStyleItemForEachPtr comp;
1769#else
1770    xsltStylePreCompPtr comp;
1771#endif
1772
1773    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1774	return;
1775
1776#ifdef XSLT_REFACTORED
1777    comp = (xsltStyleItemForEachPtr)
1778	xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);
1779#else
1780    comp = xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);
1781#endif
1782
1783    if (comp == NULL)
1784	return;
1785    inst->psvi = comp;
1786    comp->inst = inst;
1787
1788    comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1789	                        XSLT_NAMESPACE);
1790    if (comp->select == NULL) {
1791	xsltTransformError(NULL, style, inst,
1792		"xsl:for-each : select is missing\n");
1793	if (style != NULL) style->errors++;
1794    } else {
1795	comp->comp = xsltXPathCompile(style, comp->select);
1796	if (comp->comp == NULL) {
1797	    xsltTransformError(NULL, style, inst,
1798     "xsl:for-each : could not compile select expression '%s'\n",
1799			     comp->select);
1800	    if (style != NULL) style->errors++;
1801	}
1802    }
1803    /* TODO: handle and skip the xsl:sort */
1804}
1805
1806/**
1807 * xsltVariableComp:
1808 * @style: an XSLT compiled stylesheet
1809 * @inst:  the xslt variable node
1810 *
1811 * Process the xslt variable node on the source node
1812 */
1813static void
1814xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1815#ifdef XSLT_REFACTORED
1816    xsltStyleItemVariablePtr comp;
1817#else
1818    xsltStylePreCompPtr comp;
1819#endif
1820
1821    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1822	return;
1823
1824#ifdef XSLT_REFACTORED
1825    comp = (xsltStyleItemVariablePtr)
1826	xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);
1827#else
1828    comp = xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);
1829#endif
1830
1831    if (comp == NULL)
1832	return;
1833
1834    inst->psvi = comp;
1835    comp->inst = inst;
1836    /*
1837     * The full template resolution can be done statically
1838     */
1839
1840    /*
1841    * Attribute "name".
1842    */
1843    xsltGetQNameProperty(style, inst, BAD_CAST "name",
1844	1, &(comp->has_name), &(comp->ns), &(comp->name));
1845    if (comp->ns)
1846	comp->has_ns = 1;
1847    /*
1848    * Attribute "select".
1849    */
1850    comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1851	                        XSLT_NAMESPACE);
1852    if (comp->select != NULL) {
1853#ifndef XSLT_REFACTORED
1854        xmlNodePtr cur;
1855#endif
1856	comp->comp = xsltXPathCompile(style, comp->select);
1857	if (comp->comp == NULL) {
1858	    xsltTransformError(NULL, style, inst,
1859		"XSLT-variable: Failed to compile the XPath expression '%s'.\n",
1860		comp->select);
1861	    style->errors++;
1862	}
1863#ifdef XSLT_REFACTORED
1864	if (inst->children != NULL) {
1865	    xsltTransformError(NULL, style, inst,
1866		"XSLT-variable: There must be no child nodes, since the "
1867		"attribute 'select' was specified.\n");
1868	    style->errors++;
1869	}
1870#else
1871        for (cur = inst->children; cur != NULL; cur = cur->next) {
1872            if (cur->type != XML_COMMENT_NODE &&
1873                (cur->type != XML_TEXT_NODE || !xsltIsBlank(cur->content)))
1874            {
1875                xsltTransformError(NULL, style, inst,
1876                    "XSLT-variable: There must be no child nodes, since the "
1877                    "attribute 'select' was specified.\n");
1878                style->errors++;
1879            }
1880        }
1881#endif
1882    }
1883}
1884
1885/**
1886 * xsltParamComp:
1887 * @style: an XSLT compiled stylesheet
1888 * @inst:  the xslt param node
1889 *
1890 * Process the xslt param node on the source node
1891 */
1892static void
1893xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
1894#ifdef XSLT_REFACTORED
1895    xsltStyleItemParamPtr comp;
1896#else
1897    xsltStylePreCompPtr comp;
1898#endif
1899
1900    if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE))
1901	return;
1902
1903#ifdef XSLT_REFACTORED
1904    comp = (xsltStyleItemParamPtr)
1905	xsltNewStylePreComp(style, XSLT_FUNC_PARAM);
1906#else
1907    comp = xsltNewStylePreComp(style, XSLT_FUNC_PARAM);
1908#endif
1909
1910    if (comp == NULL)
1911	return;
1912    inst->psvi = comp;
1913    comp->inst = inst;
1914
1915    /*
1916     * Attribute "name".
1917     */
1918    xsltGetQNameProperty(style, inst, BAD_CAST "name",
1919	1, &(comp->has_name), &(comp->ns), &(comp->name));
1920    if (comp->ns)
1921	comp->has_ns = 1;
1922    /*
1923    * Attribute "select".
1924    */
1925    comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
1926	                        XSLT_NAMESPACE);
1927    if (comp->select != NULL) {
1928	comp->comp = xsltXPathCompile(style, comp->select);
1929	if (comp->comp == NULL) {
1930	    xsltTransformError(NULL, style, inst,
1931		"XSLT-param: could not compile select expression '%s'.\n",
1932		comp->select);
1933	    style->errors++;
1934	}
1935	if (inst->children != NULL) {
1936	    xsltTransformError(NULL, style, inst,
1937		"XSLT-param: The content should be empty since the "
1938		"attribute 'select' is present.\n");
1939	    style->warnings++;
1940	}
1941    }
1942}
1943
1944/************************************************************************
1945 *									*
1946 *		    Generic interface					*
1947 *									*
1948 ************************************************************************/
1949
1950/**
1951 * xsltFreeStylePreComps:
1952 * @style:  an XSLT transformation context
1953 *
1954 * Free up the memory allocated by all precomputed blocks
1955 */
1956void
1957xsltFreeStylePreComps(xsltStylesheetPtr style) {
1958    xsltElemPreCompPtr cur, next;
1959
1960    if (style == NULL)
1961	return;
1962
1963    cur = style->preComps;
1964    while (cur != NULL) {
1965	next = cur->next;
1966	if (cur->type == XSLT_FUNC_EXTENSION)
1967	    cur->free(cur);
1968	else
1969	    xsltFreeStylePreComp((xsltStylePreCompPtr) cur);
1970	cur = next;
1971    }
1972}
1973
1974#ifdef XSLT_REFACTORED
1975
1976/**
1977 * xsltStylePreCompute:
1978 * @style:  the XSLT stylesheet
1979 * @node:  the element in the XSLT namespace
1980 *
1981 * Precompute an XSLT element.
1982 * This expects the type of the element to be already
1983 * set in style->compCtxt->inode->type;
1984 */
1985void
1986xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr node) {
1987    /*
1988    * The xsltXSLTElemMarker marker was set beforehand by
1989    *  the parsing mechanism for all elements in the XSLT namespace.
1990    */
1991    if (style == NULL) {
1992	if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
1993	    node->psvi = NULL;
1994	return;
1995    }
1996    if (node == NULL)
1997	return;
1998    if (! IS_XSLT_ELEM_FAST(node))
1999	return;
2000
2001    node->psvi = NULL;
2002    if (XSLT_CCTXT(style)->inode->type != 0) {
2003	switch (XSLT_CCTXT(style)->inode->type) {
2004	    case XSLT_FUNC_APPLYTEMPLATES:
2005		xsltApplyTemplatesComp(style, node);
2006		break;
2007	    case XSLT_FUNC_WITHPARAM:
2008		xsltWithParamComp(style, node);
2009		break;
2010	    case XSLT_FUNC_VALUEOF:
2011		xsltValueOfComp(style, node);
2012		break;
2013	    case XSLT_FUNC_COPY:
2014		xsltCopyComp(style, node);
2015		break;
2016	    case XSLT_FUNC_COPYOF:
2017		xsltCopyOfComp(style, node);
2018		break;
2019	    case XSLT_FUNC_IF:
2020		xsltIfComp(style, node);
2021		break;
2022	    case XSLT_FUNC_CHOOSE:
2023		xsltChooseComp(style, node);
2024		break;
2025	    case XSLT_FUNC_WHEN:
2026		xsltWhenComp(style, node);
2027		break;
2028	    case XSLT_FUNC_OTHERWISE:
2029		/* NOP yet */
2030		return;
2031	    case XSLT_FUNC_FOREACH:
2032		xsltForEachComp(style, node);
2033		break;
2034	    case XSLT_FUNC_APPLYIMPORTS:
2035		xsltApplyImportsComp(style, node);
2036		break;
2037	    case XSLT_FUNC_ATTRIBUTE:
2038		xsltAttributeComp(style, node);
2039		break;
2040	    case XSLT_FUNC_ELEMENT:
2041		xsltElementComp(style, node);
2042		break;
2043	    case XSLT_FUNC_SORT:
2044		xsltSortComp(style, node);
2045		break;
2046	    case XSLT_FUNC_COMMENT:
2047		xsltCommentComp(style, node);
2048		break;
2049	    case XSLT_FUNC_NUMBER:
2050		xsltNumberComp(style, node);
2051		break;
2052	    case XSLT_FUNC_PI:
2053		xsltProcessingInstructionComp(style, node);
2054		break;
2055	    case XSLT_FUNC_CALLTEMPLATE:
2056		xsltCallTemplateComp(style, node);
2057		break;
2058	    case XSLT_FUNC_PARAM:
2059		xsltParamComp(style, node);
2060		break;
2061	    case XSLT_FUNC_VARIABLE:
2062		xsltVariableComp(style, node);
2063		break;
2064	    case XSLT_FUNC_FALLBACK:
2065		/* NOP yet */
2066		return;
2067	    case XSLT_FUNC_DOCUMENT:
2068		/* The extra one */
2069		node->psvi = (void *) xsltDocumentComp(style, node,
2070		    (xsltTransformFunction) xsltDocumentElem);
2071		break;
2072	    case XSLT_FUNC_MESSAGE:
2073		/* NOP yet */
2074		return;
2075	    default:
2076		/*
2077		* NOTE that xsl:text, xsl:template, xsl:stylesheet,
2078		*  xsl:transform, xsl:import, xsl:include are not expected
2079		*  to be handed over to this function.
2080		*/
2081		xsltTransformError(NULL, style, node,
2082		    "Internal error: (xsltStylePreCompute) cannot handle "
2083		    "the XSLT element '%s'.\n", node->name);
2084		style->errors++;
2085		return;
2086	}
2087    } else {
2088	/*
2089	* Fallback to string comparison.
2090	*/
2091	if (IS_XSLT_NAME(node, "apply-templates")) {
2092	    xsltApplyTemplatesComp(style, node);
2093	} else if (IS_XSLT_NAME(node, "with-param")) {
2094	    xsltWithParamComp(style, node);
2095	} else if (IS_XSLT_NAME(node, "value-of")) {
2096	    xsltValueOfComp(style, node);
2097	} else if (IS_XSLT_NAME(node, "copy")) {
2098	    xsltCopyComp(style, node);
2099	} else if (IS_XSLT_NAME(node, "copy-of")) {
2100	    xsltCopyOfComp(style, node);
2101	} else if (IS_XSLT_NAME(node, "if")) {
2102	    xsltIfComp(style, node);
2103	} else if (IS_XSLT_NAME(node, "choose")) {
2104	    xsltChooseComp(style, node);
2105	} else if (IS_XSLT_NAME(node, "when")) {
2106	    xsltWhenComp(style, node);
2107	} else if (IS_XSLT_NAME(node, "otherwise")) {
2108	    /* NOP yet */
2109	    return;
2110	} else if (IS_XSLT_NAME(node, "for-each")) {
2111	    xsltForEachComp(style, node);
2112	} else if (IS_XSLT_NAME(node, "apply-imports")) {
2113	    xsltApplyImportsComp(style, node);
2114	} else if (IS_XSLT_NAME(node, "attribute")) {
2115	    xsltAttributeComp(style, node);
2116	} else if (IS_XSLT_NAME(node, "element")) {
2117	    xsltElementComp(style, node);
2118	} else if (IS_XSLT_NAME(node, "sort")) {
2119	    xsltSortComp(style, node);
2120	} else if (IS_XSLT_NAME(node, "comment")) {
2121	    xsltCommentComp(style, node);
2122	} else if (IS_XSLT_NAME(node, "number")) {
2123	    xsltNumberComp(style, node);
2124	} else if (IS_XSLT_NAME(node, "processing-instruction")) {
2125	    xsltProcessingInstructionComp(style, node);
2126	} else if (IS_XSLT_NAME(node, "call-template")) {
2127	    xsltCallTemplateComp(style, node);
2128	} else if (IS_XSLT_NAME(node, "param")) {
2129	    xsltParamComp(style, node);
2130	} else if (IS_XSLT_NAME(node, "variable")) {
2131	    xsltVariableComp(style, node);
2132	} else if (IS_XSLT_NAME(node, "fallback")) {
2133	    /* NOP yet */
2134	    return;
2135	} else if (IS_XSLT_NAME(node, "document")) {
2136	    /* The extra one */
2137	    node->psvi = (void *) xsltDocumentComp(style, node,
2138		(xsltTransformFunction) xsltDocumentElem);
2139	} else if (IS_XSLT_NAME(node, "output")) {
2140	    /* Top-level */
2141	    return;
2142	} else if (IS_XSLT_NAME(node, "preserve-space")) {
2143	    /* Top-level */
2144	    return;
2145	} else if (IS_XSLT_NAME(node, "strip-space")) {
2146	    /* Top-level */
2147	    return;
2148	} else if (IS_XSLT_NAME(node, "key")) {
2149	    /* Top-level */
2150	    return;
2151	} else if (IS_XSLT_NAME(node, "message")) {
2152	    return;
2153	} else if (IS_XSLT_NAME(node, "attribute-set")) {
2154	    /* Top-level */
2155	    return;
2156	} else if (IS_XSLT_NAME(node, "namespace-alias")) {
2157	    /* Top-level */
2158	    return;
2159	} else if (IS_XSLT_NAME(node, "decimal-format")) {
2160	    /* Top-level */
2161	    return;
2162	} else if (IS_XSLT_NAME(node, "include")) {
2163	    /* Top-level */
2164	} else {
2165	    /*
2166	    * NOTE that xsl:text, xsl:template, xsl:stylesheet,
2167	    *  xsl:transform, xsl:import, xsl:include are not expected
2168	    *  to be handed over to this function.
2169	    */
2170	    xsltTransformError(NULL, style, node,
2171		"Internal error: (xsltStylePreCompute) cannot handle "
2172		"the XSLT element '%s'.\n", node->name);
2173		style->errors++;
2174	    return;
2175	}
2176    }
2177    /*
2178    * Assign the current list of in-scope namespaces to the
2179    * item. This is needed for XPath expressions.
2180    */
2181    if (node->psvi != NULL) {
2182	((xsltStylePreCompPtr) node->psvi)->inScopeNs =
2183	    XSLT_CCTXT(style)->inode->inScopeNs;
2184    }
2185}
2186
2187#else
2188
2189/**
2190 * xsltStylePreCompute:
2191 * @style:  the XSLT stylesheet
2192 * @inst:  the instruction in the stylesheet
2193 *
2194 * Precompute an XSLT stylesheet element
2195 */
2196void
2197xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) {
2198    /*
2199    * URGENT TODO: Normally inst->psvi Should never be reserved here,
2200    *   BUT: since if we include the same stylesheet from
2201    *   multiple imports, then the stylesheet will be parsed
2202    *   again. We simply must not try to compute the stylesheet again.
2203    * TODO: Get to the point where we don't need to query the
2204    *   namespace- and local-name of the node, but can evaluate this
2205    *   using cctxt->style->inode->category;
2206    */
2207    if ((inst == NULL) || (inst->type != XML_ELEMENT_NODE) ||
2208        (inst->psvi != NULL))
2209	return;
2210
2211    if (IS_XSLT_ELEM(inst)) {
2212	xsltStylePreCompPtr cur;
2213
2214	if (IS_XSLT_NAME(inst, "apply-templates")) {
2215	    xsltCheckInstructionElement(style, inst);
2216	    xsltApplyTemplatesComp(style, inst);
2217	} else if (IS_XSLT_NAME(inst, "with-param")) {
2218	    xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",
2219	                           BAD_CAST "call-template");
2220	    xsltWithParamComp(style, inst);
2221	} else if (IS_XSLT_NAME(inst, "value-of")) {
2222	    xsltCheckInstructionElement(style, inst);
2223	    xsltValueOfComp(style, inst);
2224	} else if (IS_XSLT_NAME(inst, "copy")) {
2225	    xsltCheckInstructionElement(style, inst);
2226	    xsltCopyComp(style, inst);
2227	} else if (IS_XSLT_NAME(inst, "copy-of")) {
2228	    xsltCheckInstructionElement(style, inst);
2229	    xsltCopyOfComp(style, inst);
2230	} else if (IS_XSLT_NAME(inst, "if")) {
2231	    xsltCheckInstructionElement(style, inst);
2232	    xsltIfComp(style, inst);
2233	} else if (IS_XSLT_NAME(inst, "when")) {
2234	    xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);
2235	    xsltWhenComp(style, inst);
2236	} else if (IS_XSLT_NAME(inst, "choose")) {
2237	    xsltCheckInstructionElement(style, inst);
2238	    xsltChooseComp(style, inst);
2239	} else if (IS_XSLT_NAME(inst, "for-each")) {
2240	    xsltCheckInstructionElement(style, inst);
2241	    xsltForEachComp(style, inst);
2242	} else if (IS_XSLT_NAME(inst, "apply-imports")) {
2243	    xsltCheckInstructionElement(style, inst);
2244	    xsltApplyImportsComp(style, inst);
2245	} else if (IS_XSLT_NAME(inst, "attribute")) {
2246	    xmlNodePtr parent = inst->parent;
2247
2248	    if ((parent == NULL) || (parent->ns == NULL) ||
2249		((parent->ns != inst->ns) &&
2250		 (!xmlStrEqual(parent->ns->href, inst->ns->href))) ||
2251		(!xmlStrEqual(parent->name, BAD_CAST "attribute-set"))) {
2252		xsltCheckInstructionElement(style, inst);
2253	    }
2254	    xsltAttributeComp(style, inst);
2255	} else if (IS_XSLT_NAME(inst, "element")) {
2256	    xsltCheckInstructionElement(style, inst);
2257	    xsltElementComp(style, inst);
2258	} else if (IS_XSLT_NAME(inst, "text")) {
2259	    xsltCheckInstructionElement(style, inst);
2260	    xsltTextComp(style, inst);
2261	} else if (IS_XSLT_NAME(inst, "sort")) {
2262	    xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",
2263	                           BAD_CAST "for-each");
2264	    xsltSortComp(style, inst);
2265	} else if (IS_XSLT_NAME(inst, "comment")) {
2266	    xsltCheckInstructionElement(style, inst);
2267	    xsltCommentComp(style, inst);
2268	} else if (IS_XSLT_NAME(inst, "number")) {
2269	    xsltCheckInstructionElement(style, inst);
2270	    xsltNumberComp(style, inst);
2271	} else if (IS_XSLT_NAME(inst, "processing-instruction")) {
2272	    xsltCheckInstructionElement(style, inst);
2273	    xsltProcessingInstructionComp(style, inst);
2274	} else if (IS_XSLT_NAME(inst, "call-template")) {
2275	    xsltCheckInstructionElement(style, inst);
2276	    xsltCallTemplateComp(style, inst);
2277	} else if (IS_XSLT_NAME(inst, "param")) {
2278	    if (xsltCheckTopLevelElement(style, inst, 0) == 0)
2279	        xsltCheckInstructionElement(style, inst);
2280	    xsltParamComp(style, inst);
2281	} else if (IS_XSLT_NAME(inst, "variable")) {
2282	    if (xsltCheckTopLevelElement(style, inst, 0) == 0)
2283	        xsltCheckInstructionElement(style, inst);
2284	    xsltVariableComp(style, inst);
2285	} else if (IS_XSLT_NAME(inst, "otherwise")) {
2286	    xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);
2287	    xsltCheckInstructionElement(style, inst);
2288	    return;
2289	} else if (IS_XSLT_NAME(inst, "template")) {
2290	    xsltCheckTopLevelElement(style, inst, 1);
2291	    return;
2292	} else if (IS_XSLT_NAME(inst, "output")) {
2293	    xsltCheckTopLevelElement(style, inst, 1);
2294	    return;
2295	} else if (IS_XSLT_NAME(inst, "preserve-space")) {
2296	    xsltCheckTopLevelElement(style, inst, 1);
2297	    return;
2298	} else if (IS_XSLT_NAME(inst, "strip-space")) {
2299	    xsltCheckTopLevelElement(style, inst, 1);
2300	    return;
2301	} else if ((IS_XSLT_NAME(inst, "stylesheet")) ||
2302	           (IS_XSLT_NAME(inst, "transform"))) {
2303	    xmlNodePtr parent = inst->parent;
2304
2305	    if ((parent == NULL) || (parent->type != XML_DOCUMENT_NODE)) {
2306		xsltTransformError(NULL, style, inst,
2307		    "element %s only allowed only as root element\n",
2308				   inst->name);
2309		style->errors++;
2310	    }
2311	    return;
2312	} else if (IS_XSLT_NAME(inst, "key")) {
2313	    xsltCheckTopLevelElement(style, inst, 1);
2314	    return;
2315	} else if (IS_XSLT_NAME(inst, "message")) {
2316	    xsltCheckInstructionElement(style, inst);
2317	    return;
2318	} else if (IS_XSLT_NAME(inst, "attribute-set")) {
2319	    xsltCheckTopLevelElement(style, inst, 1);
2320	    return;
2321	} else if (IS_XSLT_NAME(inst, "namespace-alias")) {
2322	    xsltCheckTopLevelElement(style, inst, 1);
2323	    return;
2324	} else if (IS_XSLT_NAME(inst, "include")) {
2325	    xsltCheckTopLevelElement(style, inst, 1);
2326	    return;
2327	} else if (IS_XSLT_NAME(inst, "import")) {
2328	    xsltCheckTopLevelElement(style, inst, 1);
2329	    return;
2330	} else if (IS_XSLT_NAME(inst, "decimal-format")) {
2331	    xsltCheckTopLevelElement(style, inst, 1);
2332	    return;
2333	} else if (IS_XSLT_NAME(inst, "fallback")) {
2334	    xsltCheckInstructionElement(style, inst);
2335	    return;
2336	} else if (IS_XSLT_NAME(inst, "document")) {
2337	    xsltCheckInstructionElement(style, inst);
2338	    inst->psvi = (void *) xsltDocumentComp(style, inst,
2339				(xsltTransformFunction) xsltDocumentElem);
2340	} else {
2341	    xsltTransformError(NULL, style, inst,
2342		 "xsltStylePreCompute: unknown xsl:%s\n", inst->name);
2343	    if (style != NULL) style->warnings++;
2344	}
2345
2346	cur = (xsltStylePreCompPtr) inst->psvi;
2347	/*
2348	* A ns-list is build for every XSLT item in the
2349	* node-tree. This is needed for XPath expressions.
2350	*/
2351	if (cur != NULL) {
2352	    int i = 0;
2353
2354	    cur->nsList = xmlGetNsList(inst->doc, inst);
2355            if (cur->nsList != NULL) {
2356		while (cur->nsList[i] != NULL)
2357		    i++;
2358	    }
2359	    cur->nsNr = i;
2360	}
2361    } else {
2362	inst->psvi =
2363	    (void *) xsltPreComputeExtModuleElement(style, inst);
2364
2365	/*
2366	 * Unknown element, maybe registered at the context
2367	 * level. Mark it for later recognition.
2368	 */
2369	if (inst->psvi == NULL)
2370	    inst->psvi = (void *) xsltExtMarker;
2371    }
2372}
2373#endif /* XSLT_REFACTORED */
2374