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