• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
47 const 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  */
70 static int
xsltCheckTopLevelElement(xsltStylesheetPtr style,xmlNodePtr inst,int err)71 xsltCheckTopLevelElement(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  */
108 static void
xsltCheckInstructionElement(xsltStylesheetPtr style,xmlNodePtr inst)109 xsltCheckInstructionElement(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  */
163 static void
xsltCheckParentElement(xsltStylesheetPtr style,xmlNodePtr inst,const xmlChar * allow1,const xmlChar * allow2)164 xsltCheckParentElement(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  */
223 static xsltStylePreCompPtr
xsltNewStylePreComp(xsltStylesheetPtr style,xsltStyleType type)224 xsltNewStylePreComp(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  */
379 static void
xsltFreeStylePreComp(xsltStylePreCompPtr comp)380 xsltFreeStylePreComp(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  */
520 xsltElemPreCompPtr
xsltDocumentComp(xsltStylesheetPtr style,xmlNodePtr inst,xsltTransformFunction function ATTRIBUTE_UNUSED)521 xsltDocumentComp(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 
648 error:
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  */
665 static void
xsltSortComp(xsltStylesheetPtr style,xmlNodePtr inst)666 xsltSortComp(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  */
772 static void
xsltCopyComp(xsltStylesheetPtr style,xmlNodePtr inst)773 xsltCopyComp(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  */
815 static void
xsltTextComp(xsltStylesheetPtr style,xmlNodePtr inst)816 xsltTextComp(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  */
861 static void
xsltElementComp(xsltStylesheetPtr style,xmlNodePtr inst)862 xsltElementComp(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 
968 error:
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  */
979 static void
xsltAttributeComp(xsltStylesheetPtr style,xmlNodePtr inst)980 xsltAttributeComp(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  */
1106 static void
xsltCommentComp(xsltStylesheetPtr style,xmlNodePtr inst)1107 xsltCommentComp(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  */
1136 static void
xsltProcessingInstructionComp(xsltStylesheetPtr style,xmlNodePtr inst)1137 xsltProcessingInstructionComp(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  */
1170 static void
xsltCopyOfComp(xsltStylesheetPtr style,xmlNodePtr inst)1171 xsltCopyOfComp(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  */
1216 static void
xsltValueOfComp(xsltStylesheetPtr style,xmlNodePtr inst)1217 xsltValueOfComp(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 
1269 static void
xsltGetQNameProperty(xsltStylesheetPtr style,xmlNodePtr inst,const xmlChar * propName,int mandatory,int * hasProp,const xmlChar ** nsName,const xmlChar ** localName)1270 xsltGetQNameProperty(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  */
1342 static void
xsltWithParamComp(xsltStylesheetPtr style,xmlNodePtr inst)1343 xsltWithParamComp(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  */
1400 static void
xsltNumberComp(xsltStylesheetPtr style,xmlNodePtr cur)1401 xsltNumberComp(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  */
1515 static void
xsltApplyImportsComp(xsltStylesheetPtr style,xmlNodePtr inst)1516 xsltApplyImportsComp(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  */
1545 static void
xsltCallTemplateComp(xsltStylesheetPtr style,xmlNodePtr inst)1546 xsltCallTemplateComp(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  */
1584 static void
xsltApplyTemplatesComp(xsltStylesheetPtr style,xmlNodePtr inst)1585 xsltApplyTemplatesComp(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  */
1636 static void
xsltChooseComp(xsltStylesheetPtr style,xmlNodePtr inst)1637 xsltChooseComp(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  */
1667 static void
xsltIfComp(xsltStylesheetPtr style,xmlNodePtr inst)1668 xsltIfComp(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  */
1713 static void
xsltWhenComp(xsltStylesheetPtr style,xmlNodePtr inst)1714 xsltWhenComp(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  */
1759 static void
xsltForEachComp(xsltStylesheetPtr style,xmlNodePtr inst)1760 xsltForEachComp(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  */
1807 static void
xsltVariableComp(xsltStylesheetPtr style,xmlNodePtr inst)1808 xsltVariableComp(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  */
1870 static void
xsltParamComp(xsltStylesheetPtr style,xmlNodePtr inst)1871 xsltParamComp(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  */
1934 void
xsltFreeStylePreComps(xsltStylesheetPtr style)1935 xsltFreeStylePreComps(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  */
1963 void
xsltStylePreCompute(xsltStylesheetPtr style,xmlNodePtr node)1964 xsltStylePreCompute(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  */
2174 void
xsltStylePreCompute(xsltStylesheetPtr style,xmlNodePtr inst)2175 xsltStylePreCompute(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