xref: /reactos/dll/3rdparty/libxslt/xslt.c (revision c7bba39a)
1 /*
2  * xslt.c: Implemetation of an XSL Transformation 1.0 engine
3  *
4  * Reference:
5  *   XSLT specification
6  *   http://www.w3.org/TR/1999/REC-xslt-19991116
7  *
8  *   Associating Style Sheets with XML documents
9  *   http://www.w3.org/1999/06/REC-xml-stylesheet-19990629
10  *
11  * See Copyright for the status of this software.
12  *
13  * daniel@veillard.com
14  */
15 
16 #include "precomp.h"
17 
18 #ifdef WITH_XSLT_DEBUG
19 #define WITH_XSLT_DEBUG_PARSING
20 /* #define WITH_XSLT_DEBUG_BLANKS */
21 #endif
22 
23 const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA;
24 const int xsltLibxsltVersion = LIBXSLT_VERSION;
25 const int xsltLibxmlVersion = LIBXML_VERSION;
26 
27 #ifdef XSLT_REFACTORED
28 
29 const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE;
30 
31 #define XSLT_ELEMENT_CATEGORY_XSLT 0
32 #define XSLT_ELEMENT_CATEGORY_EXTENSION 1
33 #define XSLT_ELEMENT_CATEGORY_LRE 2
34 
35 /*
36 * xsltLiteralResultMarker:
37 * Marker for Literal result elements, in order to avoid multiple attempts
38 * to recognize such elements in the stylesheet's tree.
39 * This marker is set on node->psvi during the initial traversal
40 * of a stylesheet's node tree.
41 *
42 const xmlChar *xsltLiteralResultMarker =
43     (const xmlChar *) "Literal Result Element";
44 */
45 
46 /*
47 * xsltXSLTTextMarker:
48 * Marker for xsl:text elements. Used to recognize xsl:text elements
49 * for post-processing of the stylesheet's tree, where those
50 * elements are removed from the tree.
51 */
52 const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
53 
54 /*
55 * xsltXSLTAttrMarker:
56 * Marker for XSLT attribute on Literal Result Elements.
57 */
58 const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
59 
60 #endif
61 
62 #ifdef XSLT_LOCALE_WINAPI
63 extern xmlRMutexPtr xsltLocaleMutex;
64 #endif
65 /*
66  * Harmless but avoiding a problem when compiling against a
67  * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
68  */
69 #ifndef LIBXML_DEBUG_ENABLED
70 double xmlXPathStringEvalNumber(const xmlChar *str);
71 #endif
72 /*
73  * Useful macros
74  */
75 
76 #ifdef  IS_BLANK
77 #undef	IS_BLANK
78 #endif
79 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||	\
80                      ((c) == 0x0D))
81 
82 #ifdef	IS_BLANK_NODE
83 #undef	IS_BLANK_NODE
84 #endif
85 #define IS_BLANK_NODE(n)						\
86     (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
87 
88 /**
89  * xsltParseContentError:
90  *
91  * @style: the stylesheet
92  * @node: the node where the error occured
93  *
94  * Compile-time error function.
95  */
96 static void
97 xsltParseContentError(xsltStylesheetPtr style,
98 		       xmlNodePtr node)
99 {
100     if ((style == NULL) || (node == NULL))
101 	return;
102 
103     if (IS_XSLT_ELEM(node))
104 	xsltTransformError(NULL, style, node,
105 	    "The XSLT-element '%s' is not allowed at this position.\n",
106 	    node->name);
107     else
108 	xsltTransformError(NULL, style, node,
109 	    "The element '%s' is not allowed at this position.\n",
110 	    node->name);
111     style->errors++;
112 }
113 
114 #ifdef XSLT_REFACTORED
115 #else
116 /**
117  * exclPrefixPush:
118  * @style: the transformation stylesheet
119  * @value:  the excluded namespace name to push on the stack
120  *
121  * Push an excluded namespace name on the stack
122  *
123  * Returns the new index in the stack or -1 if already present or
124  * in case of error
125  */
126 static int
127 exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)
128 {
129     int i;
130 
131     if (style->exclPrefixMax == 0) {
132         style->exclPrefixMax = 4;
133         style->exclPrefixTab =
134             (xmlChar * *)xmlMalloc(style->exclPrefixMax *
135                                    sizeof(style->exclPrefixTab[0]));
136         if (style->exclPrefixTab == NULL) {
137             xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
138             return (-1);
139         }
140     }
141     /* do not push duplicates */
142     for (i = 0;i < style->exclPrefixNr;i++) {
143         if (xmlStrEqual(style->exclPrefixTab[i], value))
144 	    return(-1);
145     }
146     if (style->exclPrefixNr >= style->exclPrefixMax) {
147         style->exclPrefixMax *= 2;
148         style->exclPrefixTab =
149             (xmlChar * *)xmlRealloc(style->exclPrefixTab,
150                                     style->exclPrefixMax *
151                                     sizeof(style->exclPrefixTab[0]));
152         if (style->exclPrefixTab == NULL) {
153             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
154             return (-1);
155         }
156     }
157     style->exclPrefixTab[style->exclPrefixNr] = value;
158     style->exclPrefix = value;
159     return (style->exclPrefixNr++);
160 }
161 /**
162  * exclPrefixPop:
163  * @style: the transformation stylesheet
164  *
165  * Pop an excluded prefix value from the stack
166  *
167  * Returns the stored excluded prefix value
168  */
169 static xmlChar *
170 exclPrefixPop(xsltStylesheetPtr style)
171 {
172     xmlChar *ret;
173 
174     if (style->exclPrefixNr <= 0)
175         return (0);
176     style->exclPrefixNr--;
177     if (style->exclPrefixNr > 0)
178         style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
179     else
180         style->exclPrefix = NULL;
181     ret = style->exclPrefixTab[style->exclPrefixNr];
182     style->exclPrefixTab[style->exclPrefixNr] = 0;
183     return (ret);
184 }
185 #endif
186 
187 /************************************************************************
188  *									*
189  *			Helper functions				*
190  *									*
191  ************************************************************************/
192 
193 static int initialized = 0;
194 /**
195  * xsltInit:
196  *
197  * Initializes the processor (e.g. registers built-in extensions,
198  * etc.)
199  */
200 void
201 xsltInit (void) {
202     if (initialized == 0) {
203 	initialized = 1;
204 #ifdef XSLT_LOCALE_WINAPI
205 	xsltLocaleMutex = xmlNewRMutex();
206 #endif
207         xsltRegisterAllExtras();
208     }
209 }
210 
211 /**
212  * xsltUninit:
213  *
214  * Uninitializes the processor.
215  */
216 void
217 xsltUninit (void) {
218 #ifdef XSLT_LOCALE_WINAPI
219     xmlFreeRMutex(xsltLocaleMutex);
220     xsltLocaleMutex = NULL;
221 #endif
222     initialized = 0;
223 }
224 
225 /**
226  * xsltIsBlank:
227  * @str:  a string
228  *
229  * Check if a string is ignorable
230  *
231  * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
232  */
233 int
234 xsltIsBlank(xmlChar *str) {
235     if (str == NULL)
236 	return(1);
237     while (*str != 0) {
238 	if (!(IS_BLANK(*str))) return(0);
239 	str++;
240     }
241     return(1);
242 }
243 
244 /************************************************************************
245  *									*
246  *		Routines to handle XSLT data structures			*
247  *									*
248  ************************************************************************/
249 static xsltDecimalFormatPtr
250 xsltNewDecimalFormat(const xmlChar *nsUri, xmlChar *name)
251 {
252     xsltDecimalFormatPtr self;
253     /* UTF-8 for 0x2030 */
254     static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};
255 
256     self = xmlMalloc(sizeof(xsltDecimalFormat));
257     if (self != NULL) {
258 	self->next = NULL;
259         self->nsUri = nsUri;
260 	self->name = name;
261 
262 	/* Default values */
263 	self->digit = xmlStrdup(BAD_CAST("#"));
264 	self->patternSeparator = xmlStrdup(BAD_CAST(";"));
265 	self->decimalPoint = xmlStrdup(BAD_CAST("."));
266 	self->grouping = xmlStrdup(BAD_CAST(","));
267 	self->percent = xmlStrdup(BAD_CAST("%"));
268 	self->permille = xmlStrdup(BAD_CAST(permille));
269 	self->zeroDigit = xmlStrdup(BAD_CAST("0"));
270 	self->minusSign = xmlStrdup(BAD_CAST("-"));
271 	self->infinity = xmlStrdup(BAD_CAST("Infinity"));
272 	self->noNumber = xmlStrdup(BAD_CAST("NaN"));
273     }
274     return self;
275 }
276 
277 static void
278 xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
279 {
280     if (self != NULL) {
281 	if (self->digit)
282 	    xmlFree(self->digit);
283 	if (self->patternSeparator)
284 	    xmlFree(self->patternSeparator);
285 	if (self->decimalPoint)
286 	    xmlFree(self->decimalPoint);
287 	if (self->grouping)
288 	    xmlFree(self->grouping);
289 	if (self->percent)
290 	    xmlFree(self->percent);
291 	if (self->permille)
292 	    xmlFree(self->permille);
293 	if (self->zeroDigit)
294 	    xmlFree(self->zeroDigit);
295 	if (self->minusSign)
296 	    xmlFree(self->minusSign);
297 	if (self->infinity)
298 	    xmlFree(self->infinity);
299 	if (self->noNumber)
300 	    xmlFree(self->noNumber);
301 	if (self->name)
302 	    xmlFree(self->name);
303 	xmlFree(self);
304     }
305 }
306 
307 static void
308 xsltFreeDecimalFormatList(xsltStylesheetPtr self)
309 {
310     xsltDecimalFormatPtr iter;
311     xsltDecimalFormatPtr tmp;
312 
313     if (self == NULL)
314 	return;
315 
316     iter = self->decimalFormat;
317     while (iter != NULL) {
318 	tmp = iter->next;
319 	xsltFreeDecimalFormat(iter);
320 	iter = tmp;
321     }
322 }
323 
324 /**
325  * xsltDecimalFormatGetByName:
326  * @style: the XSLT stylesheet
327  * @name: the decimal-format name to find
328  *
329  * Find decimal-format by name
330  *
331  * Returns the xsltDecimalFormatPtr
332  */
333 xsltDecimalFormatPtr
334 xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
335 {
336     xsltDecimalFormatPtr result = NULL;
337 
338     if (name == NULL)
339 	return style->decimalFormat;
340 
341     while (style != NULL) {
342 	for (result = style->decimalFormat->next;
343 	     result != NULL;
344 	     result = result->next) {
345 	    if ((result->nsUri == NULL) && xmlStrEqual(name, result->name))
346 		return result;
347 	}
348 	style = xsltNextImport(style);
349     }
350     return result;
351 }
352 
353 /**
354  * xsltDecimalFormatGetByQName:
355  * @style: the XSLT stylesheet
356  * @nsUri: the namespace URI of the QName
357  * @name: the local part of the QName
358  *
359  * Find decimal-format by QName
360  *
361  * Returns the xsltDecimalFormatPtr
362  */
363 xsltDecimalFormatPtr
364 xsltDecimalFormatGetByQName(xsltStylesheetPtr style, const xmlChar *nsUri,
365                             const xmlChar *name)
366 {
367     xsltDecimalFormatPtr result = NULL;
368 
369     if (name == NULL)
370 	return style->decimalFormat;
371 
372     while (style != NULL) {
373 	for (result = style->decimalFormat->next;
374 	     result != NULL;
375 	     result = result->next) {
376 	    if (xmlStrEqual(nsUri, result->nsUri) &&
377                 xmlStrEqual(name, result->name))
378 		return result;
379 	}
380 	style = xsltNextImport(style);
381     }
382     return result;
383 }
384 
385 
386 /**
387  * xsltNewTemplate:
388  *
389  * Create a new XSLT Template
390  *
391  * Returns the newly allocated xsltTemplatePtr or NULL in case of error
392  */
393 static xsltTemplatePtr
394 xsltNewTemplate(void) {
395     xsltTemplatePtr cur;
396 
397     cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
398     if (cur == NULL) {
399 	xsltTransformError(NULL, NULL, NULL,
400 		"xsltNewTemplate : malloc failed\n");
401 	return(NULL);
402     }
403     memset(cur, 0, sizeof(xsltTemplate));
404     cur->priority = XSLT_PAT_NO_PRIORITY;
405     return(cur);
406 }
407 
408 /**
409  * xsltFreeTemplate:
410  * @template:  an XSLT template
411  *
412  * Free up the memory allocated by @template
413  */
414 static void
415 xsltFreeTemplate(xsltTemplatePtr template) {
416     if (template == NULL)
417 	return;
418     if (template->match) xmlFree(template->match);
419 /*
420 *   NOTE: @name and @nameURI are put into the string dict now.
421 *   if (template->name) xmlFree(template->name);
422 *   if (template->nameURI) xmlFree(template->nameURI);
423 */
424 /*
425     if (template->mode) xmlFree(template->mode);
426     if (template->modeURI) xmlFree(template->modeURI);
427  */
428     if (template->inheritedNs) xmlFree(template->inheritedNs);
429 
430     /* free profiling data */
431     if (template->templCalledTab) xmlFree(template->templCalledTab);
432     if (template->templCountTab) xmlFree(template->templCountTab);
433 
434     memset(template, -1, sizeof(xsltTemplate));
435     xmlFree(template);
436 }
437 
438 /**
439  * xsltFreeTemplateList:
440  * @template:  an XSLT template list
441  *
442  * Free up the memory allocated by all the elements of @template
443  */
444 static void
445 xsltFreeTemplateList(xsltTemplatePtr template) {
446     xsltTemplatePtr cur;
447 
448     while (template != NULL) {
449 	cur = template;
450 	template = template->next;
451 	xsltFreeTemplate(cur);
452     }
453 }
454 
455 #ifdef XSLT_REFACTORED
456 
457 static void
458 xsltFreeNsAliasList(xsltNsAliasPtr item)
459 {
460     xsltNsAliasPtr tmp;
461 
462     while (item) {
463 	tmp = item;
464 	item = item->next;
465 	xmlFree(tmp);
466     }
467     return;
468 }
469 
470 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
471 static void
472 xsltFreeNamespaceMap(xsltNsMapPtr item)
473 {
474     xsltNsMapPtr tmp;
475 
476     while (item) {
477 	tmp = item;
478 	item = item->next;
479 	xmlFree(tmp);
480     }
481     return;
482 }
483 
484 static xsltNsMapPtr
485 xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
486 			xmlDocPtr doc,
487 			xmlNsPtr ns,
488 			xmlNodePtr elem)
489 {
490     xsltNsMapPtr ret;
491 
492     if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
493 	return(NULL);
494 
495     ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
496     if (ret == NULL) {
497 	xsltTransformError(NULL, cctxt->style, elem,
498 	    "Internal error: (xsltNewNamespaceMapItem) "
499 	    "memory allocation failed.\n");
500 	return(NULL);
501     }
502     memset(ret, 0, sizeof(xsltNsMap));
503     ret->doc = doc;
504     ret->ns = ns;
505     ret->origNsName = ns->href;
506     /*
507     * Store the item at current stylesheet-level.
508     */
509     if (cctxt->psData->nsMap != NULL)
510 	ret->next = cctxt->psData->nsMap;
511     cctxt->psData->nsMap = ret;
512 
513     return(ret);
514 }
515 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
516 
517 /**
518  * xsltCompilerVarInfoFree:
519  * @cctxt: the compilation context
520  *
521  * Frees the list of information for vars/params.
522  */
523 static void
524 xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)
525 {
526     xsltVarInfoPtr ivar = cctxt->ivars, ivartmp;
527 
528     while (ivar) {
529 	ivartmp = ivar;
530 	ivar = ivar->next;
531 	xmlFree(ivartmp);
532     }
533 }
534 
535 /**
536  * xsltCompilerCtxtFree:
537  *
538  * Free an XSLT compiler context.
539  */
540 static void
541 xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
542 {
543     if (cctxt == NULL)
544 	return;
545 #ifdef WITH_XSLT_DEBUG_PARSING
546     xsltGenericDebug(xsltGenericDebugContext,
547 	"Freeing compilation context\n");
548     xsltGenericDebug(xsltGenericDebugContext,
549 	"### Max inodes: %d\n", cctxt->maxNodeInfos);
550     xsltGenericDebug(xsltGenericDebugContext,
551 	"### Max LREs  : %d\n", cctxt->maxLREs);
552 #endif
553     /*
554     * Free node-infos.
555     */
556     if (cctxt->inodeList != NULL) {
557 	xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
558 	while (cur != NULL) {
559 	    tmp = cur;
560 	    cur = cur->next;
561 	    xmlFree(tmp);
562 	}
563     }
564     if (cctxt->tmpList != NULL)
565 	xsltPointerListFree(cctxt->tmpList);
566 #ifdef XSLT_REFACTORED_XPATHCOMP
567     if (cctxt->xpathCtxt != NULL)
568 	xmlXPathFreeContext(cctxt->xpathCtxt);
569 #endif
570     if (cctxt->nsAliases != NULL)
571 	xsltFreeNsAliasList(cctxt->nsAliases);
572 
573     if (cctxt->ivars)
574 	xsltCompilerVarInfoFree(cctxt);
575 
576     xmlFree(cctxt);
577 }
578 
579 /**
580  * xsltCompilerCreate:
581  *
582  * Creates an XSLT compiler context.
583  *
584  * Returns the pointer to the created xsltCompilerCtxt or
585  *         NULL in case of an internal error.
586  */
587 static xsltCompilerCtxtPtr
588 xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
589     xsltCompilerCtxtPtr ret;
590 
591     ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
592     if (ret == NULL) {
593 	xsltTransformError(NULL, style, NULL,
594 	    "xsltCompilerCreate: allocation of compiler "
595 	    "context failed.\n");
596 	return(NULL);
597     }
598     memset(ret, 0, sizeof(xsltCompilerCtxt));
599 
600     ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
601     ret->tmpList = xsltPointerListCreate(20);
602     if (ret->tmpList == NULL) {
603 	goto internal_err;
604     }
605 #ifdef XSLT_REFACTORED_XPATHCOMP
606     /*
607     * Create the XPath compilation context in order
608     * to speed up precompilation of XPath expressions.
609     */
610     ret->xpathCtxt = xmlXPathNewContext(NULL);
611     if (ret->xpathCtxt == NULL)
612 	goto internal_err;
613 #endif
614 
615     return(ret);
616 
617 internal_err:
618     xsltCompilationCtxtFree(ret);
619     return(NULL);
620 }
621 
622 static void
623 xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
624 {
625     xsltEffectiveNsPtr tmp;
626 
627     while (first != NULL) {
628 	tmp = first;
629 	first = first->nextInStore;
630 	xmlFree(tmp);
631     }
632 }
633 
634 static void
635 xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
636 {
637     if (data == NULL)
638 	return;
639 
640     if (data->inScopeNamespaces != NULL) {
641 	int i;
642 	xsltNsListContainerPtr nsi;
643 	xsltPointerListPtr list =
644 	    (xsltPointerListPtr) data->inScopeNamespaces;
645 
646 	for (i = 0; i < list->number; i++) {
647 	    /*
648 	    * REVISIT TODO: Free info of in-scope namespaces.
649 	    */
650 	    nsi = (xsltNsListContainerPtr) list->items[i];
651 	    if (nsi->list != NULL)
652 		xmlFree(nsi->list);
653 	    xmlFree(nsi);
654 	}
655 	xsltPointerListFree(list);
656 	data->inScopeNamespaces = NULL;
657     }
658 
659     if (data->exclResultNamespaces != NULL) {
660 	int i;
661 	xsltPointerListPtr list = (xsltPointerListPtr)
662 	    data->exclResultNamespaces;
663 
664 	for (i = 0; i < list->number; i++)
665 	    xsltPointerListFree((xsltPointerListPtr) list->items[i]);
666 
667 	xsltPointerListFree(list);
668 	data->exclResultNamespaces = NULL;
669     }
670 
671     if (data->extElemNamespaces != NULL) {
672 	xsltPointerListPtr list = (xsltPointerListPtr)
673 	    data->extElemNamespaces;
674 	int i;
675 
676 	for (i = 0; i < list->number; i++)
677 	    xsltPointerListFree((xsltPointerListPtr) list->items[i]);
678 
679 	xsltPointerListFree(list);
680 	data->extElemNamespaces = NULL;
681     }
682     if (data->effectiveNs) {
683 	xsltLREEffectiveNsNodesFree(data->effectiveNs);
684 	data->effectiveNs = NULL;
685     }
686 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
687     xsltFreeNamespaceMap(data->nsMap);
688 #endif
689     xmlFree(data);
690 }
691 
692 static xsltPrincipalStylesheetDataPtr
693 xsltNewPrincipalStylesheetData(void)
694 {
695     xsltPrincipalStylesheetDataPtr ret;
696 
697     ret = (xsltPrincipalStylesheetDataPtr)
698 	xmlMalloc(sizeof(xsltPrincipalStylesheetData));
699     if (ret == NULL) {
700 	xsltTransformError(NULL, NULL, NULL,
701 	    "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
702 	return(NULL);
703     }
704     memset(ret, 0, sizeof(xsltPrincipalStylesheetData));
705 
706     /*
707     * Global list of in-scope namespaces.
708     */
709     ret->inScopeNamespaces = xsltPointerListCreate(-1);
710     if (ret->inScopeNamespaces == NULL)
711 	goto internal_err;
712     /*
713     * Global list of excluded result ns-decls.
714     */
715     ret->exclResultNamespaces = xsltPointerListCreate(-1);
716     if (ret->exclResultNamespaces == NULL)
717 	goto internal_err;
718     /*
719     * Global list of extension instruction namespace names.
720     */
721     ret->extElemNamespaces = xsltPointerListCreate(-1);
722     if (ret->extElemNamespaces == NULL)
723 	goto internal_err;
724 
725     return(ret);
726 
727 internal_err:
728 
729     return(NULL);
730 }
731 
732 #endif
733 
734 /**
735  * xsltNewStylesheet:
736  *
737  * Create a new XSLT Stylesheet
738  *
739  * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
740  */
741 xsltStylesheetPtr
742 xsltNewStylesheet(void) {
743     xsltStylesheetPtr ret = NULL;
744 
745     ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
746     if (ret == NULL) {
747 	xsltTransformError(NULL, NULL, NULL,
748 		"xsltNewStylesheet : malloc failed\n");
749 	goto internal_err;
750     }
751     memset(ret, 0, sizeof(xsltStylesheet));
752 
753     ret->omitXmlDeclaration = -1;
754     ret->standalone = -1;
755     ret->decimalFormat = xsltNewDecimalFormat(NULL, NULL);
756     ret->indent = -1;
757     ret->errors = 0;
758     ret->warnings = 0;
759     ret->exclPrefixNr = 0;
760     ret->exclPrefixMax = 0;
761     ret->exclPrefixTab = NULL;
762     ret->extInfos = NULL;
763     ret->extrasNr = 0;
764     ret->internalized = 1;
765     ret->literal_result = 0;
766     ret->forwards_compatible = 0;
767     ret->dict = xmlDictCreate();
768 #ifdef WITH_XSLT_DEBUG
769     xsltGenericDebug(xsltGenericDebugContext,
770 	"creating dictionary for stylesheet\n");
771 #endif
772 
773     xsltInit();
774 
775     return(ret);
776 
777 internal_err:
778     if (ret != NULL)
779 	xsltFreeStylesheet(ret);
780     return(NULL);
781 }
782 
783 /**
784  * xsltAllocateExtra:
785  * @style:  an XSLT stylesheet
786  *
787  * Allocate an extra runtime information slot statically while compiling
788  * the stylesheet and return its number
789  *
790  * Returns the number of the slot
791  */
792 int
793 xsltAllocateExtra(xsltStylesheetPtr style)
794 {
795     return(style->extrasNr++);
796 }
797 
798 /**
799  * xsltAllocateExtraCtxt:
800  * @ctxt:  an XSLT transformation context
801  *
802  * Allocate an extra runtime information slot at run-time
803  * and return its number
804  * This make sure there is a slot ready in the transformation context
805  *
806  * Returns the number of the slot
807  */
808 int
809 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
810 {
811     if (ctxt->extrasNr >= ctxt->extrasMax) {
812 	int i;
813 	if (ctxt->extrasNr == 0) {
814 	    ctxt->extrasMax = 20;
815 	    ctxt->extras = (xsltRuntimeExtraPtr)
816 		xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
817 	    if (ctxt->extras == NULL) {
818 		xsltTransformError(ctxt, NULL, NULL,
819 			"xsltAllocateExtraCtxt: out of memory\n");
820 		return(0);
821 	    }
822 	    for (i = 0;i < ctxt->extrasMax;i++) {
823 		ctxt->extras[i].info = NULL;
824 		ctxt->extras[i].deallocate = NULL;
825 		ctxt->extras[i].val.ptr = NULL;
826 	    }
827 
828 	} else {
829 	    xsltRuntimeExtraPtr tmp;
830 
831 	    ctxt->extrasMax += 100;
832 	    tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
833 		            ctxt->extrasMax * sizeof(xsltRuntimeExtra));
834 	    if (tmp == NULL) {
835 		xsltTransformError(ctxt, NULL, NULL,
836 			"xsltAllocateExtraCtxt: out of memory\n");
837 		return(0);
838 	    }
839 	    ctxt->extras = tmp;
840 	    for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
841 		ctxt->extras[i].info = NULL;
842 		ctxt->extras[i].deallocate = NULL;
843 		ctxt->extras[i].val.ptr = NULL;
844 	    }
845 	}
846     }
847     return(ctxt->extrasNr++);
848 }
849 
850 /**
851  * xsltFreeStylesheetList:
852  * @style:  an XSLT stylesheet list
853  *
854  * Free up the memory allocated by the list @style
855  */
856 static void
857 xsltFreeStylesheetList(xsltStylesheetPtr style) {
858     xsltStylesheetPtr next;
859 
860     while (style != NULL) {
861 	next = style->next;
862 	xsltFreeStylesheet(style);
863 	style = next;
864     }
865 }
866 
867 /**
868  * xsltCleanupStylesheetTree:
869  *
870  * @doc: the document-node
871  * @node: the element where the stylesheet is rooted at
872  *
873  * Actually @node need not be the document-element, but
874  * currently Libxslt does not support embedded stylesheets.
875  *
876  * Returns 0 if OK, -1 on API or internal errors.
877  */
878 static int
879 xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED,
880 			  xmlNodePtr rootElem ATTRIBUTE_UNUSED)
881 {
882 #if 0 /* TODO: Currently disabled, since probably not needed. */
883     xmlNodePtr cur;
884 
885     if ((doc == NULL) || (rootElem == NULL) ||
886 	(rootElem->type != XML_ELEMENT_NODE) ||
887 	(doc != rootElem->doc))
888 	return(-1);
889 
890     /*
891     * Cleanup was suggested by Aleksey Sanin:
892     * Clear the PSVI field to avoid problems if the
893     * node-tree of the stylesheet is intended to be used for
894     * further processing by the user (e.g. for compiling it
895     * once again - although not recommended).
896     */
897 
898     cur = rootElem;
899     while (cur != NULL) {
900 	if (cur->type == XML_ELEMENT_NODE) {
901 	    /*
902 	    * Clear the PSVI field.
903 	    */
904 	    cur->psvi = NULL;
905 	    if (cur->children) {
906 		cur = cur->children;
907 		continue;
908 	    }
909 	}
910 
911 leave_node:
912 	if (cur == rootElem)
913 	    break;
914 	if (cur->next != NULL)
915 	    cur = cur->next;
916 	else {
917 	    cur = cur->parent;
918 	    if (cur == NULL)
919 		break;
920 	    goto leave_node;
921 	}
922     }
923 #endif /* #if 0 */
924     return(0);
925 }
926 
927 /**
928  * xsltFreeStylesheet:
929  * @style:  an XSLT stylesheet
930  *
931  * Free up the memory allocated by @style
932  */
933 void
934 xsltFreeStylesheet(xsltStylesheetPtr style)
935 {
936     if (style == NULL)
937         return;
938 
939 #ifdef XSLT_REFACTORED
940     /*
941     * Start with a cleanup of the main stylesheet's doc.
942     */
943     if ((style->principal == style) && (style->doc))
944 	xsltCleanupStylesheetTree(style->doc,
945 	    xmlDocGetRootElement(style->doc));
946 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
947     /*
948     * Restore changed ns-decls before freeing the document.
949     */
950     if ((style->doc != NULL) &&
951 	XSLT_HAS_INTERNAL_NSMAP(style))
952     {
953 	xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
954 	    style->doc);
955     }
956 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
957 #else
958     /*
959     * Start with a cleanup of the main stylesheet's doc.
960     */
961     if ((style->parent == NULL) && (style->doc))
962 	xsltCleanupStylesheetTree(style->doc,
963 	    xmlDocGetRootElement(style->doc));
964 #endif /* XSLT_REFACTORED */
965 
966     xsltFreeKeys(style);
967     xsltFreeExts(style);
968     xsltFreeTemplateHashes(style);
969     xsltFreeDecimalFormatList(style);
970     xsltFreeTemplateList(style->templates);
971     xsltFreeAttributeSetsHashes(style);
972     xsltFreeNamespaceAliasHashes(style);
973     xsltFreeStylePreComps(style);
974     /*
975     * Free documents of all included stylsheet modules of this
976     * stylesheet level.
977     */
978     xsltFreeStyleDocuments(style);
979     /*
980     * TODO: Best time to shutdown extension stuff?
981     */
982     xsltShutdownExts(style);
983 
984     if (style->variables != NULL)
985         xsltFreeStackElemList(style->variables);
986     if (style->cdataSection != NULL)
987         xmlHashFree(style->cdataSection, NULL);
988     if (style->stripSpaces != NULL)
989         xmlHashFree(style->stripSpaces, NULL);
990     if (style->nsHash != NULL)
991         xmlHashFree(style->nsHash, NULL);
992     if (style->exclPrefixTab != NULL)
993         xmlFree(style->exclPrefixTab);
994     if (style->method != NULL)
995         xmlFree(style->method);
996     if (style->methodURI != NULL)
997         xmlFree(style->methodURI);
998     if (style->version != NULL)
999         xmlFree(style->version);
1000     if (style->encoding != NULL)
1001         xmlFree(style->encoding);
1002     if (style->doctypePublic != NULL)
1003         xmlFree(style->doctypePublic);
1004     if (style->doctypeSystem != NULL)
1005         xmlFree(style->doctypeSystem);
1006     if (style->mediaType != NULL)
1007         xmlFree(style->mediaType);
1008     if (style->attVTs)
1009         xsltFreeAVTList(style->attVTs);
1010     if (style->imports != NULL)
1011         xsltFreeStylesheetList(style->imports);
1012 
1013 #ifdef XSLT_REFACTORED
1014     /*
1015     * If this is the principal stylesheet, then
1016     * free its internal data.
1017     */
1018     if (style->principal == style) {
1019 	if (style->principalData) {
1020 	    xsltFreePrincipalStylesheetData(style->principalData);
1021 	    style->principalData = NULL;
1022 	}
1023     }
1024 #endif
1025     /*
1026     * Better to free the main document of this stylesheet level
1027     * at the end - so here.
1028     */
1029     if (style->doc != NULL) {
1030         xmlFreeDoc(style->doc);
1031     }
1032 
1033 #ifdef WITH_XSLT_DEBUG
1034     xsltGenericDebug(xsltGenericDebugContext,
1035                      "freeing dictionary from stylesheet\n");
1036 #endif
1037     xmlDictFree(style->dict);
1038 
1039     memset(style, -1, sizeof(xsltStylesheet));
1040     xmlFree(style);
1041 }
1042 
1043 /************************************************************************
1044  *									*
1045  *		Parsing of an XSLT Stylesheet				*
1046  *									*
1047  ************************************************************************/
1048 
1049 #ifdef XSLT_REFACTORED
1050     /*
1051     * This is now performed in an optimized way in xsltParseXSLTTemplate.
1052     */
1053 #else
1054 /**
1055  * xsltGetInheritedNsList:
1056  * @style:  the stylesheet
1057  * @template: the template
1058  * @node:  the current node
1059  *
1060  * Search all the namespace applying to a given element except the ones
1061  * from excluded output prefixes currently in scope. Initialize the
1062  * template inheritedNs list with it.
1063  *
1064  * Returns the number of entries found
1065  */
1066 static int
1067 xsltGetInheritedNsList(xsltStylesheetPtr style,
1068 	               xsltTemplatePtr template,
1069 	               xmlNodePtr node)
1070 {
1071     xmlNsPtr cur;
1072     xmlNsPtr *ret = NULL;
1073     int nbns = 0;
1074     int maxns = 10;
1075     int i;
1076 
1077     if ((style == NULL) || (template == NULL) || (node == NULL) ||
1078 	(template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
1079 	return(0);
1080     while (node != NULL) {
1081         if (node->type == XML_ELEMENT_NODE) {
1082             cur = node->nsDef;
1083             while (cur != NULL) {
1084 		if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
1085 		    goto skip_ns;
1086 
1087 		if ((cur->prefix != NULL) &&
1088 		    (xsltCheckExtPrefix(style, cur->prefix)))
1089 		    goto skip_ns;
1090 		/*
1091 		* Check if this namespace was excluded.
1092 		* Note that at this point only the exclusions defined
1093 		* on the topmost stylesheet element are in the exclusion-list.
1094 		*/
1095 		for (i = 0;i < style->exclPrefixNr;i++) {
1096 		    if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
1097 			goto skip_ns;
1098 		}
1099                 if (ret == NULL) {
1100                     ret =
1101                         (xmlNsPtr *) xmlMalloc((maxns + 1) *
1102                                                sizeof(xmlNsPtr));
1103                     if (ret == NULL) {
1104                         xmlGenericError(xmlGenericErrorContext,
1105                                         "xsltGetInheritedNsList : out of memory!\n");
1106                         return(0);
1107                     }
1108                     ret[nbns] = NULL;
1109                 }
1110 		/*
1111 		* Skip shadowed namespace bindings.
1112 		*/
1113                 for (i = 0; i < nbns; i++) {
1114                     if ((cur->prefix == ret[i]->prefix) ||
1115                         (xmlStrEqual(cur->prefix, ret[i]->prefix)))
1116                         break;
1117                 }
1118                 if (i >= nbns) {
1119                     if (nbns >= maxns) {
1120                         maxns *= 2;
1121                         ret = (xmlNsPtr *) xmlRealloc(ret,
1122                                                       (maxns +
1123                                                        1) *
1124                                                       sizeof(xmlNsPtr));
1125                         if (ret == NULL) {
1126                             xmlGenericError(xmlGenericErrorContext,
1127                                             "xsltGetInheritedNsList : realloc failed!\n");
1128                             return(0);
1129                         }
1130                     }
1131                     ret[nbns++] = cur;
1132                     ret[nbns] = NULL;
1133                 }
1134 skip_ns:
1135                 cur = cur->next;
1136             }
1137         }
1138         node = node->parent;
1139     }
1140     if (nbns != 0) {
1141 #ifdef WITH_XSLT_DEBUG_PARSING
1142         xsltGenericDebug(xsltGenericDebugContext,
1143                          "template has %d inherited namespaces\n", nbns);
1144 #endif
1145 	template->inheritedNsNr = nbns;
1146 	template->inheritedNs = ret;
1147     }
1148     return (nbns);
1149 }
1150 #endif /* else of XSLT_REFACTORED */
1151 
1152 /**
1153  * xsltParseStylesheetOutput:
1154  * @style:  the XSLT stylesheet
1155  * @cur:  the "output" element
1156  *
1157  * parse an XSLT stylesheet output element and record
1158  * information related to the stylesheet output
1159  */
1160 
1161 void
1162 xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
1163 {
1164     xmlChar *elements,
1165      *prop;
1166     xmlChar *element,
1167      *end;
1168 
1169     if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1170         return;
1171 
1172     prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
1173     if (prop != NULL) {
1174         if (style->version != NULL)
1175             xmlFree(style->version);
1176         style->version = prop;
1177     }
1178 
1179     prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
1180     if (prop != NULL) {
1181         if (style->encoding != NULL)
1182             xmlFree(style->encoding);
1183         style->encoding = prop;
1184     }
1185 
1186     /* relaxed to support xt:document
1187     * TODO KB: What does "relaxed to support xt:document" mean?
1188     */
1189     prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL);
1190     if (prop != NULL) {
1191         const xmlChar *URI;
1192 
1193         if (style->method != NULL)
1194             xmlFree(style->method);
1195         style->method = NULL;
1196         if (style->methodURI != NULL)
1197             xmlFree(style->methodURI);
1198         style->methodURI = NULL;
1199 
1200 	/*
1201 	* TODO: Don't use xsltGetQNameURI().
1202 	*/
1203 	URI = xsltGetQNameURI(cur, &prop);
1204 	if (prop == NULL) {
1205 	    if (style != NULL) style->errors++;
1206 	} else if (URI == NULL) {
1207             if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
1208                 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
1209                 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
1210                 style->method = prop;
1211             } else {
1212 		xsltTransformError(NULL, style, cur,
1213                                  "invalid value for method: %s\n", prop);
1214                 if (style != NULL) style->warnings++;
1215                 xmlFree(prop);
1216             }
1217 	} else {
1218 	    style->method = prop;
1219 	    style->methodURI = xmlStrdup(URI);
1220 	}
1221     }
1222 
1223     prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
1224     if (prop != NULL) {
1225         if (style->doctypeSystem != NULL)
1226             xmlFree(style->doctypeSystem);
1227         style->doctypeSystem = prop;
1228     }
1229 
1230     prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
1231     if (prop != NULL) {
1232         if (style->doctypePublic != NULL)
1233             xmlFree(style->doctypePublic);
1234         style->doctypePublic = prop;
1235     }
1236 
1237     prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL);
1238     if (prop != NULL) {
1239         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1240             style->standalone = 1;
1241         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1242             style->standalone = 0;
1243         } else {
1244 	    xsltTransformError(NULL, style, cur,
1245                              "invalid value for standalone: %s\n", prop);
1246             style->errors++;
1247         }
1248         xmlFree(prop);
1249     }
1250 
1251     prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL);
1252     if (prop != NULL) {
1253         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1254             style->indent = 1;
1255         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1256             style->indent = 0;
1257         } else {
1258 	    xsltTransformError(NULL, style, cur,
1259                              "invalid value for indent: %s\n", prop);
1260             style->errors++;
1261         }
1262         xmlFree(prop);
1263     }
1264 
1265     prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL);
1266     if (prop != NULL) {
1267         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1268             style->omitXmlDeclaration = 1;
1269         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1270             style->omitXmlDeclaration = 0;
1271         } else {
1272 	    xsltTransformError(NULL, style, cur,
1273                              "invalid value for omit-xml-declaration: %s\n",
1274                              prop);
1275             style->errors++;
1276         }
1277         xmlFree(prop);
1278     }
1279 
1280     elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
1281 	NULL);
1282     if (elements != NULL) {
1283         if (style->cdataSection == NULL)
1284             style->cdataSection = xmlHashCreate(10);
1285         if (style->cdataSection == NULL)
1286             return;
1287 
1288         element = elements;
1289         while (*element != 0) {
1290             while (IS_BLANK(*element))
1291                 element++;
1292             if (*element == 0)
1293                 break;
1294             end = element;
1295             while ((*end != 0) && (!IS_BLANK(*end)))
1296                 end++;
1297             element = xmlStrndup(element, end - element);
1298             if (element) {
1299 #ifdef WITH_XSLT_DEBUG_PARSING
1300                 xsltGenericDebug(xsltGenericDebugContext,
1301                                  "add cdata section output element %s\n",
1302                                  element);
1303 #endif
1304 		if (xmlValidateQName(BAD_CAST element, 0) != 0) {
1305 		    xsltTransformError(NULL, style, cur,
1306 			"Attribute 'cdata-section-elements': The value "
1307 			"'%s' is not a valid QName.\n", element);
1308 		    xmlFree(element);
1309 		    style->errors++;
1310 		} else {
1311 		    const xmlChar *URI;
1312 
1313 		    /*
1314 		    * TODO: Don't use xsltGetQNameURI().
1315 		    */
1316 		    URI = xsltGetQNameURI(cur, &element);
1317 		    if (element == NULL) {
1318 			/*
1319 			* TODO: We'll report additionally an error
1320 			*  via the stylesheet's error handling.
1321 			*/
1322 			xsltTransformError(NULL, style, cur,
1323 			    "Attribute 'cdata-section-elements': The value "
1324 			    "'%s' is not a valid QName.\n", element);
1325 			style->errors++;
1326 		    } else {
1327 			xmlNsPtr ns;
1328 
1329 			/*
1330 			* XSLT-1.0 "Each QName is expanded into an
1331 			*  expanded-name using the namespace declarations in
1332 			*  effect on the xsl:output element in which the QName
1333 			*  occurs; if there is a default namespace, it is used
1334 			*  for QNames that do not have a prefix"
1335 			* NOTE: Fix of bug #339570.
1336 			*/
1337 			if (URI == NULL) {
1338 			    ns = xmlSearchNs(style->doc, cur, NULL);
1339 			    if (ns != NULL)
1340 				URI = ns->href;
1341 			}
1342 			xmlHashAddEntry2(style->cdataSection, element, URI,
1343 			    (void *) "cdata");
1344 			xmlFree(element);
1345 		    }
1346 		}
1347             }
1348             element = end;
1349         }
1350         xmlFree(elements);
1351     }
1352 
1353     prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
1354     if (prop != NULL) {
1355 	if (style->mediaType)
1356 	    xmlFree(style->mediaType);
1357 	style->mediaType = prop;
1358     }
1359     if (cur->children != NULL) {
1360 	xsltParseContentError(style, cur->children);
1361     }
1362 }
1363 
1364 /**
1365  * xsltParseStylesheetDecimalFormat:
1366  * @style:  the XSLT stylesheet
1367  * @cur:  the "decimal-format" element
1368  *
1369  * <!-- Category: top-level-element -->
1370  * <xsl:decimal-format
1371  *   name = qname, decimal-separator = char, grouping-separator = char,
1372  *   infinity = string, minus-sign = char, NaN = string, percent = char
1373  *   per-mille = char, zero-digit = char, digit = char,
1374  * pattern-separator = char />
1375  *
1376  * parse an XSLT stylesheet decimal-format element and
1377  * and record the formatting characteristics
1378  */
1379 static void
1380 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
1381 {
1382     xmlChar *prop;
1383     xsltDecimalFormatPtr format;
1384     xsltDecimalFormatPtr iter;
1385 
1386     if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1387 	return;
1388 
1389     format = style->decimalFormat;
1390 
1391     prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
1392     if (prop != NULL) {
1393         const xmlChar *nsUri;
1394 
1395         if (xmlValidateQName(prop, 0) != 0) {
1396             xsltTransformError(NULL, style, cur,
1397                 "xsl:decimal-format: Invalid QName '%s'.\n", prop);
1398 	    style->warnings++;
1399             xmlFree(prop);
1400             return;
1401         }
1402         /*
1403         * TODO: Don't use xsltGetQNameURI().
1404         */
1405         nsUri = xsltGetQNameURI(cur, &prop);
1406         if (prop == NULL) {
1407 	    style->warnings++;
1408             return;
1409         }
1410 	format = xsltDecimalFormatGetByQName(style, nsUri, prop);
1411 	if (format != NULL) {
1412 	    xsltTransformError(NULL, style, cur,
1413 	 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
1414 	    style->warnings++;
1415             xmlFree(prop);
1416 	    return;
1417 	}
1418 	format = xsltNewDecimalFormat(nsUri, prop);
1419 	if (format == NULL) {
1420 	    xsltTransformError(NULL, style, cur,
1421      "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
1422 	    style->errors++;
1423             xmlFree(prop);
1424 	    return;
1425 	}
1426 	/* Append new decimal-format structure */
1427 	for (iter = style->decimalFormat; iter->next; iter = iter->next)
1428 	    ;
1429 	if (iter)
1430 	    iter->next = format;
1431     }
1432 
1433     prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
1434     if (prop != NULL) {
1435 	if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
1436 	format->decimalPoint  = prop;
1437     }
1438 
1439     prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
1440     if (prop != NULL) {
1441 	if (format->grouping != NULL) xmlFree(format->grouping);
1442 	format->grouping  = prop;
1443     }
1444 
1445     prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
1446     if (prop != NULL) {
1447 	if (format->infinity != NULL) xmlFree(format->infinity);
1448 	format->infinity  = prop;
1449     }
1450 
1451     prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
1452     if (prop != NULL) {
1453 	if (format->minusSign != NULL) xmlFree(format->minusSign);
1454 	format->minusSign  = prop;
1455     }
1456 
1457     prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
1458     if (prop != NULL) {
1459 	if (format->noNumber != NULL) xmlFree(format->noNumber);
1460 	format->noNumber  = prop;
1461     }
1462 
1463     prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
1464     if (prop != NULL) {
1465 	if (format->percent != NULL) xmlFree(format->percent);
1466 	format->percent  = prop;
1467     }
1468 
1469     prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
1470     if (prop != NULL) {
1471 	if (format->permille != NULL) xmlFree(format->permille);
1472 	format->permille  = prop;
1473     }
1474 
1475     prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
1476     if (prop != NULL) {
1477 	if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
1478 	format->zeroDigit  = prop;
1479     }
1480 
1481     prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
1482     if (prop != NULL) {
1483 	if (format->digit != NULL) xmlFree(format->digit);
1484 	format->digit  = prop;
1485     }
1486 
1487     prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
1488     if (prop != NULL) {
1489 	if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
1490 	format->patternSeparator  = prop;
1491     }
1492     if (cur->children != NULL) {
1493 	xsltParseContentError(style, cur->children);
1494     }
1495 }
1496 
1497 /**
1498  * xsltParseStylesheetPreserveSpace:
1499  * @style:  the XSLT stylesheet
1500  * @cur:  the "preserve-space" element
1501  *
1502  * parse an XSLT stylesheet preserve-space element and record
1503  * elements needing preserving
1504  */
1505 
1506 static void
1507 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1508     xmlChar *elements;
1509     xmlChar *element, *end;
1510 
1511     if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1512 	return;
1513 
1514     elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1515     if (elements == NULL) {
1516 	xsltTransformError(NULL, style, cur,
1517 	    "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
1518 	if (style != NULL) style->warnings++;
1519 	return;
1520     }
1521 
1522     if (style->stripSpaces == NULL)
1523 	style->stripSpaces = xmlHashCreate(10);
1524     if (style->stripSpaces == NULL)
1525 	return;
1526 
1527     element = elements;
1528     while (*element != 0) {
1529 	while (IS_BLANK(*element)) element++;
1530 	if (*element == 0)
1531 	    break;
1532         end = element;
1533 	while ((*end != 0) && (!IS_BLANK(*end))) end++;
1534 	element = xmlStrndup(element, end - element);
1535 	if (element) {
1536 #ifdef WITH_XSLT_DEBUG_PARSING
1537 	    xsltGenericDebug(xsltGenericDebugContext,
1538 		"add preserved space element %s\n", element);
1539 #endif
1540 	    if (xmlStrEqual(element, (const xmlChar *)"*")) {
1541 		style->stripAll = -1;
1542 	    } else {
1543 		const xmlChar *URI;
1544 
1545 		/*
1546 		* TODO: Don't use xsltGetQNameURI().
1547 		*/
1548                 URI = xsltGetQNameURI(cur, &element);
1549 
1550 		xmlHashAddEntry2(style->stripSpaces, element, URI,
1551 				(xmlChar *) "preserve");
1552 	    }
1553 	    xmlFree(element);
1554 	}
1555 	element = end;
1556     }
1557     xmlFree(elements);
1558     if (cur->children != NULL) {
1559 	xsltParseContentError(style, cur->children);
1560     }
1561 }
1562 
1563 #ifdef XSLT_REFACTORED
1564 #else
1565 /**
1566  * xsltParseStylesheetExtPrefix:
1567  * @style:  the XSLT stylesheet
1568  * @template:  the "extension-element-prefixes" prefix
1569  *
1570  * parse an XSLT stylesheet's "extension-element-prefix" attribute value
1571  * and register the namespaces of extension instruction.
1572  * SPEC "A namespace is designated as an extension namespace by using
1573  *   an extension-element-prefixes attribute on:
1574  *   1) an xsl:stylesheet element
1575  *   2) an xsl:extension-element-prefixes attribute on a
1576  *      literal result element
1577  *   3) an extension instruction."
1578  */
1579 static void
1580 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,
1581 			     int isXsltElem) {
1582     xmlChar *prefixes;
1583     xmlChar *prefix, *end;
1584 
1585     if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1586 	return;
1587 
1588     if (isXsltElem) {
1589 	/* For xsl:stylesheet/xsl:transform. */
1590 	prefixes = xmlGetNsProp(cur,
1591 	    (const xmlChar *)"extension-element-prefixes", NULL);
1592     } else {
1593 	/* For literal result elements and extension instructions. */
1594 	prefixes = xmlGetNsProp(cur,
1595 	    (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
1596     }
1597     if (prefixes == NULL) {
1598 	return;
1599     }
1600 
1601     prefix = prefixes;
1602     while (*prefix != 0) {
1603 	while (IS_BLANK(*prefix)) prefix++;
1604 	if (*prefix == 0)
1605 	    break;
1606         end = prefix;
1607 	while ((*end != 0) && (!IS_BLANK(*end))) end++;
1608 	prefix = xmlStrndup(prefix, end - prefix);
1609 	if (prefix) {
1610 	    xmlNsPtr ns;
1611 
1612 	    if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1613 		ns = xmlSearchNs(style->doc, cur, NULL);
1614 	    else
1615 		ns = xmlSearchNs(style->doc, cur, prefix);
1616 	    if (ns == NULL) {
1617 		xsltTransformError(NULL, style, cur,
1618 	    "xsl:extension-element-prefix : undefined namespace %s\n",
1619 	                         prefix);
1620 		if (style != NULL) style->warnings++;
1621 	    } else {
1622 #ifdef WITH_XSLT_DEBUG_PARSING
1623 		xsltGenericDebug(xsltGenericDebugContext,
1624 		    "add extension prefix %s\n", prefix);
1625 #endif
1626 		xsltRegisterExtPrefix(style, prefix, ns->href);
1627 	    }
1628 	    xmlFree(prefix);
1629 	}
1630 	prefix = end;
1631     }
1632     xmlFree(prefixes);
1633 }
1634 #endif /* else of XSLT_REFACTORED */
1635 
1636 /**
1637  * xsltParseStylesheetStripSpace:
1638  * @style:  the XSLT stylesheet
1639  * @cur:  the "strip-space" element
1640  *
1641  * parse an XSLT stylesheet's strip-space element and record
1642  * the elements needing stripping
1643  */
1644 
1645 static void
1646 xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1647     xmlChar *elements;
1648     xmlChar *element, *end;
1649 
1650     if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1651 	return;
1652 
1653     elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1654     if (elements == NULL) {
1655 	xsltTransformError(NULL, style, cur,
1656 	    "xsltParseStylesheetStripSpace: missing elements attribute\n");
1657 	if (style != NULL) style->warnings++;
1658 	return;
1659     }
1660 
1661     if (style->stripSpaces == NULL)
1662 	style->stripSpaces = xmlHashCreate(10);
1663     if (style->stripSpaces == NULL)
1664 	return;
1665 
1666     element = elements;
1667     while (*element != 0) {
1668 	while (IS_BLANK(*element)) element++;
1669 	if (*element == 0)
1670 	    break;
1671         end = element;
1672 	while ((*end != 0) && (!IS_BLANK(*end))) end++;
1673 	element = xmlStrndup(element, end - element);
1674 	if (element) {
1675 #ifdef WITH_XSLT_DEBUG_PARSING
1676 	    xsltGenericDebug(xsltGenericDebugContext,
1677 		"add stripped space element %s\n", element);
1678 #endif
1679 	    if (xmlStrEqual(element, (const xmlChar *)"*")) {
1680 		style->stripAll = 1;
1681 	    } else {
1682 		const xmlChar *URI;
1683 
1684 		/*
1685 		* TODO: Don't use xsltGetQNameURI().
1686 		*/
1687                 URI = xsltGetQNameURI(cur, &element);
1688 
1689 		xmlHashAddEntry2(style->stripSpaces, element, URI,
1690 			        (xmlChar *) "strip");
1691 	    }
1692 	    xmlFree(element);
1693 	}
1694 	element = end;
1695     }
1696     xmlFree(elements);
1697     if (cur->children != NULL) {
1698 	xsltParseContentError(style, cur->children);
1699     }
1700 }
1701 
1702 #ifdef XSLT_REFACTORED
1703 #else
1704 /**
1705  * xsltParseStylesheetExcludePrefix:
1706  * @style:  the XSLT stylesheet
1707  * @cur:  the current point in the stylesheet
1708  *
1709  * parse an XSLT stylesheet exclude prefix and record
1710  * namespaces needing stripping
1711  *
1712  * Returns the number of Excluded prefixes added at that level
1713  */
1714 
1715 static int
1716 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur,
1717 				 int isXsltElem)
1718 {
1719     int nb = 0;
1720     xmlChar *prefixes;
1721     xmlChar *prefix, *end;
1722 
1723     if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1724 	return(0);
1725 
1726     if (isXsltElem)
1727 	prefixes = xmlGetNsProp(cur,
1728 	    (const xmlChar *)"exclude-result-prefixes", NULL);
1729     else
1730 	prefixes = xmlGetNsProp(cur,
1731 	    (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);
1732 
1733     if (prefixes == NULL) {
1734 	return(0);
1735     }
1736 
1737     prefix = prefixes;
1738     while (*prefix != 0) {
1739 	while (IS_BLANK(*prefix)) prefix++;
1740 	if (*prefix == 0)
1741 	    break;
1742         end = prefix;
1743 	while ((*end != 0) && (!IS_BLANK(*end))) end++;
1744 	prefix = xmlStrndup(prefix, end - prefix);
1745 	if (prefix) {
1746 	    xmlNsPtr ns;
1747 
1748 	    if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1749 		ns = xmlSearchNs(style->doc, cur, NULL);
1750 	    else
1751 		ns = xmlSearchNs(style->doc, cur, prefix);
1752 	    if (ns == NULL) {
1753 		xsltTransformError(NULL, style, cur,
1754 	    "xsl:exclude-result-prefixes : undefined namespace %s\n",
1755 	                         prefix);
1756 		if (style != NULL) style->warnings++;
1757 	    } else {
1758 		if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) {
1759 #ifdef WITH_XSLT_DEBUG_PARSING
1760 		    xsltGenericDebug(xsltGenericDebugContext,
1761 			"exclude result prefix %s\n", prefix);
1762 #endif
1763 		    nb++;
1764 		}
1765 	    }
1766 	    xmlFree(prefix);
1767 	}
1768 	prefix = end;
1769     }
1770     xmlFree(prefixes);
1771     return(nb);
1772 }
1773 #endif /* else of XSLT_REFACTORED */
1774 
1775 #ifdef XSLT_REFACTORED
1776 
1777 /*
1778 * xsltTreeEnsureXMLDecl:
1779 * @doc: the doc
1780 *
1781 * BIG NOTE:
1782 *  This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
1783 * Ensures that there is an XML namespace declaration on the doc.
1784 *
1785 * Returns the XML ns-struct or NULL on API and internal errors.
1786 */
1787 static xmlNsPtr
1788 xsltTreeEnsureXMLDecl(xmlDocPtr doc)
1789 {
1790     if (doc == NULL)
1791 	return (NULL);
1792     if (doc->oldNs != NULL)
1793 	return (doc->oldNs);
1794     {
1795 	xmlNsPtr ns;
1796 	ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1797 	if (ns == NULL) {
1798 	    xmlGenericError(xmlGenericErrorContext,
1799 		"xsltTreeEnsureXMLDecl: Failed to allocate "
1800 		"the XML namespace.\n");
1801 	    return (NULL);
1802 	}
1803 	memset(ns, 0, sizeof(xmlNs));
1804 	ns->type = XML_LOCAL_NAMESPACE;
1805 	/*
1806 	* URGENT TODO: revisit this.
1807 	*/
1808 #ifdef LIBXML_NAMESPACE_DICT
1809 	if (doc->dict)
1810 	    ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
1811 	else
1812 	    ns->href = xmlStrdup(XML_XML_NAMESPACE);
1813 #else
1814 	ns->href = xmlStrdup(XML_XML_NAMESPACE);
1815 #endif
1816 	ns->prefix = xmlStrdup((const xmlChar *)"xml");
1817 	doc->oldNs = ns;
1818 	return (ns);
1819     }
1820 }
1821 
1822 /*
1823 * xsltTreeAcquireStoredNs:
1824 * @doc: the doc
1825 * @nsName: the namespace name
1826 * @prefix: the prefix
1827 *
1828 * BIG NOTE:
1829 *  This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
1830 * Creates or reuses an xmlNs struct on doc->oldNs with
1831 * the given prefix and namespace name.
1832 *
1833 * Returns the aquired ns struct or NULL in case of an API
1834 *         or internal error.
1835 */
1836 static xmlNsPtr
1837 xsltTreeAcquireStoredNs(xmlDocPtr doc,
1838 			const xmlChar *nsName,
1839 			const xmlChar *prefix)
1840 {
1841     xmlNsPtr ns;
1842 
1843     if (doc == NULL)
1844 	return (NULL);
1845     if (doc->oldNs != NULL)
1846 	ns = doc->oldNs;
1847     else
1848 	ns = xsltTreeEnsureXMLDecl(doc);
1849     if (ns == NULL)
1850 	return (NULL);
1851     if (ns->next != NULL) {
1852 	/* Reuse. */
1853 	ns = ns->next;
1854 	while (ns != NULL) {
1855 	    if ((ns->prefix == NULL) != (prefix == NULL)) {
1856 		/* NOP */
1857 	    } else if (prefix == NULL) {
1858 		if (xmlStrEqual(ns->href, nsName))
1859 		    return (ns);
1860 	    } else {
1861 		if ((ns->prefix[0] == prefix[0]) &&
1862 		     xmlStrEqual(ns->prefix, prefix) &&
1863 		     xmlStrEqual(ns->href, nsName))
1864 		    return (ns);
1865 
1866 	    }
1867 	    if (ns->next == NULL)
1868 		break;
1869 	    ns = ns->next;
1870 	}
1871     }
1872     /* Create. */
1873     ns->next = xmlNewNs(NULL, nsName, prefix);
1874     return (ns->next);
1875 }
1876 
1877 /**
1878  * xsltLREBuildEffectiveNs:
1879  *
1880  * Apply ns-aliasing on the namespace of the given @elem and
1881  * its attributes.
1882  */
1883 static int
1884 xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
1885 			xmlNodePtr elem)
1886 {
1887     xmlNsPtr ns;
1888     xsltNsAliasPtr alias;
1889 
1890     if ((cctxt == NULL) || (elem == NULL))
1891 	return(-1);
1892     if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
1893 	return(0);
1894 
1895     alias = cctxt->nsAliases;
1896     while (alias != NULL) {
1897 	if ( /* If both namespaces are NULL... */
1898 	    ( (elem->ns == NULL) &&
1899 	    ((alias->literalNs == NULL) ||
1900 	    (alias->literalNs->href == NULL)) ) ||
1901 	    /* ... or both namespace are equal */
1902 	    ( (elem->ns != NULL) &&
1903 	    (alias->literalNs != NULL) &&
1904 	    xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
1905 	{
1906 	    if ((alias->targetNs != NULL) &&
1907 		(alias->targetNs->href != NULL))
1908 	    {
1909 		/*
1910 		* Convert namespace.
1911 		*/
1912 		if (elem->doc == alias->docOfTargetNs) {
1913 		    /*
1914 		    * This is the nice case: same docs.
1915 		    * This will eventually assign a ns-decl which
1916 		    * is shadowed, but this has no negative effect on
1917 		    * the generation of the result tree.
1918 		    */
1919 		    elem->ns = alias->targetNs;
1920 		} else {
1921 		    /*
1922 		    * This target xmlNs originates from a different
1923 		    * stylesheet tree. Try to locate it in the
1924 		    * in-scope namespaces.
1925 		    * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
1926 		    */
1927 		    ns = xmlSearchNs(elem->doc, elem,
1928 			alias->targetNs->prefix);
1929 		    /*
1930 		    * If no matching ns-decl found, then assign a
1931 		    * ns-decl stored in xmlDoc.
1932 		    */
1933 		    if ((ns == NULL) ||
1934 			(! xmlStrEqual(ns->href, alias->targetNs->href)))
1935 		    {
1936 			/*
1937 			* BIG NOTE: The use of xsltTreeAcquireStoredNs()
1938 			*  is not very efficient, but currently I don't
1939 			*  see an other way of *safely* changing a node's
1940 			*  namespace, since the xmlNs struct in
1941 			*  alias->targetNs might come from an other
1942 			*  stylesheet tree. So we need to anchor it in the
1943 			*  current document, without adding it to the tree,
1944 			*  which would otherwise change the in-scope-ns
1945 			*  semantic of the tree.
1946 			*/
1947 			ns = xsltTreeAcquireStoredNs(elem->doc,
1948 			    alias->targetNs->href,
1949 			    alias->targetNs->prefix);
1950 
1951 			if (ns == NULL) {
1952 			    xsltTransformError(NULL, cctxt->style, elem,
1953 				"Internal error in "
1954 				"xsltLREBuildEffectiveNs(): "
1955 				"failed to acquire a stored "
1956 				"ns-declaration.\n");
1957 			    cctxt->style->errors++;
1958 			    return(-1);
1959 
1960 			}
1961 		    }
1962 		    elem->ns = ns;
1963 		}
1964 	    } else {
1965 		/*
1966 		* Move into or leave in the NULL namespace.
1967 		*/
1968 		elem->ns = NULL;
1969 	    }
1970 	    break;
1971 	}
1972 	alias = alias->next;
1973     }
1974     /*
1975     * Same with attributes of literal result elements.
1976     */
1977     if (elem->properties != NULL) {
1978 	xmlAttrPtr attr = elem->properties;
1979 
1980 	while (attr != NULL) {
1981 	    if (attr->ns == NULL) {
1982 		attr = attr->next;
1983 		continue;
1984 	    }
1985 	    alias = cctxt->nsAliases;
1986 	    while (alias != NULL) {
1987 		if ( /* If both namespaces are NULL... */
1988 		    ( (elem->ns == NULL) &&
1989 		    ((alias->literalNs == NULL) ||
1990 		    (alias->literalNs->href == NULL)) ) ||
1991 		    /* ... or both namespace are equal */
1992 		    ( (elem->ns != NULL) &&
1993 		    (alias->literalNs != NULL) &&
1994 		    xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
1995 		{
1996 		    if ((alias->targetNs != NULL) &&
1997 			(alias->targetNs->href != NULL))
1998 		    {
1999 			if (elem->doc == alias->docOfTargetNs) {
2000 			    elem->ns = alias->targetNs;
2001 			} else {
2002 			    ns = xmlSearchNs(elem->doc, elem,
2003 				alias->targetNs->prefix);
2004 			    if ((ns == NULL) ||
2005 				(! xmlStrEqual(ns->href, alias->targetNs->href)))
2006 			    {
2007 				ns = xsltTreeAcquireStoredNs(elem->doc,
2008 				    alias->targetNs->href,
2009 				    alias->targetNs->prefix);
2010 
2011 				if (ns == NULL) {
2012 				    xsltTransformError(NULL, cctxt->style, elem,
2013 					"Internal error in "
2014 					"xsltLREBuildEffectiveNs(): "
2015 					"failed to acquire a stored "
2016 					"ns-declaration.\n");
2017 				    cctxt->style->errors++;
2018 				    return(-1);
2019 
2020 				}
2021 			    }
2022 			    elem->ns = ns;
2023 			}
2024 		    } else {
2025 		    /*
2026 		    * Move into or leave in the NULL namespace.
2027 			*/
2028 			elem->ns = NULL;
2029 		    }
2030 		    break;
2031 		}
2032 		alias = alias->next;
2033 	    }
2034 
2035 	    attr = attr->next;
2036 	}
2037     }
2038     return(0);
2039 }
2040 
2041 /**
2042  * xsltLREBuildEffectiveNsNodes:
2043  *
2044  * Computes the effective namespaces nodes for a literal result
2045  * element.
2046  * @effectiveNs is the set of effective ns-nodes
2047  *  on the literal result element, which will be added to the result
2048  *  element if not already existing in the result tree.
2049  *  This means that excluded namespaces (via exclude-result-prefixes,
2050  *  extension-element-prefixes and the XSLT namespace) not added
2051  *  to the set.
2052  *  Namespace-aliasing was applied on the @effectiveNs.
2053  */
2054 static int
2055 xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
2056 			     xsltStyleItemLRElementInfoPtr item,
2057 			     xmlNodePtr elem,
2058 			     int isLRE)
2059 {
2060     xmlNsPtr ns, tmpns;
2061     xsltEffectiveNsPtr effNs, lastEffNs = NULL;
2062     int i, j, holdByElem;
2063     xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
2064     xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
2065 
2066     if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
2067 	(item == NULL) || (item->effectiveNs != NULL))
2068 	return(-1);
2069 
2070     if (item->inScopeNs == NULL)
2071 	return(0);
2072 
2073     extElemNs = cctxt->inode->extElemNs;
2074     exclResultNs = cctxt->inode->exclResultNs;
2075 
2076     for (i = 0; i < item->inScopeNs->totalNumber; i++) {
2077 	ns = item->inScopeNs->list[i];
2078 	/*
2079 	* Skip namespaces designated as excluded namespaces
2080 	* -------------------------------------------------
2081 	*
2082 	* XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
2083 	*  which are target namespaces of namespace-aliases
2084 	*  regardless if designated as excluded.
2085 	*
2086 	* Exclude the XSLT namespace.
2087 	*/
2088 	if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2089 	    goto skip_ns;
2090 
2091 	/*
2092 	* Apply namespace aliasing
2093 	* ------------------------
2094 	*
2095 	* SPEC XSLT 2.0
2096 	*  "- A namespace node whose string value is a literal namespace
2097 	*     URI is not copied to the result tree.
2098 	*   - A namespace node whose string value is a target namespace URI
2099 	*     is copied to the result tree, whether or not the URI
2100 	*     identifies an excluded namespace."
2101 	*
2102 	* NOTE: The ns-aliasing machanism is non-cascading.
2103 	*  (checked with Saxon, Xalan and MSXML .NET).
2104 	* URGENT TODO: is style->nsAliases the effective list of
2105 	*  ns-aliases, or do we need to lookup the whole
2106 	*  import-tree?
2107 	* TODO: Get rid of import-tree lookup.
2108 	*/
2109 	if (cctxt->hasNsAliases) {
2110 	    xsltNsAliasPtr alias;
2111 	    /*
2112 	    * First check for being a target namespace.
2113 	    */
2114 	    alias = cctxt->nsAliases;
2115 	    do {
2116 		/*
2117 		* TODO: Is xmlns="" handled already?
2118 		*/
2119 		if ((alias->targetNs != NULL) &&
2120 		    (xmlStrEqual(alias->targetNs->href, ns->href)))
2121 		{
2122 		    /*
2123 		    * Recognized as a target namespace; use it regardless
2124 		    * if excluded otherwise.
2125 		    */
2126 		    goto add_effective_ns;
2127 		}
2128 		alias = alias->next;
2129 	    } while (alias != NULL);
2130 
2131 	    alias = cctxt->nsAliases;
2132 	    do {
2133 		/*
2134 		* TODO: Is xmlns="" handled already?
2135 		*/
2136 		if ((alias->literalNs != NULL) &&
2137 		    (xmlStrEqual(alias->literalNs->href, ns->href)))
2138 		{
2139 		    /*
2140 		    * Recognized as an namespace alias; do not use it.
2141 		    */
2142 		    goto skip_ns;
2143 		}
2144 		alias = alias->next;
2145 	    } while (alias != NULL);
2146 	}
2147 
2148 	/*
2149 	* Exclude excluded result namespaces.
2150 	*/
2151 	if (exclResultNs) {
2152 	    for (j = 0; j < exclResultNs->number; j++)
2153 		if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
2154 		    goto skip_ns;
2155 	}
2156 	/*
2157 	* Exclude extension-element namespaces.
2158 	*/
2159 	if (extElemNs) {
2160 	    for (j = 0; j < extElemNs->number; j++)
2161 		if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
2162 		    goto skip_ns;
2163 	}
2164 
2165 add_effective_ns:
2166 	/*
2167 	* OPTIMIZE TODO: This information may not be needed.
2168 	*/
2169 	if (isLRE && (elem->nsDef != NULL)) {
2170 	    holdByElem = 0;
2171 	    tmpns = elem->nsDef;
2172 	    do {
2173 		if (tmpns == ns) {
2174 		    holdByElem = 1;
2175 		    break;
2176 		}
2177 		tmpns = tmpns->next;
2178 	    } while (tmpns != NULL);
2179 	} else
2180 	    holdByElem = 0;
2181 
2182 
2183 	/*
2184 	* Add the effective namespace declaration.
2185 	*/
2186 	effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
2187 	if (effNs == NULL) {
2188 	    xsltTransformError(NULL, cctxt->style, elem,
2189 		"Internal error in xsltLREBuildEffectiveNs(): "
2190 		"failed to allocate memory.\n");
2191 	    cctxt->style->errors++;
2192 	    return(-1);
2193 	}
2194 	if (cctxt->psData->effectiveNs == NULL) {
2195 	    cctxt->psData->effectiveNs = effNs;
2196 	    effNs->nextInStore = NULL;
2197 	} else {
2198 	    effNs->nextInStore = cctxt->psData->effectiveNs;
2199 	    cctxt->psData->effectiveNs = effNs;
2200 	}
2201 
2202 	effNs->next = NULL;
2203 	effNs->prefix = ns->prefix;
2204 	effNs->nsName = ns->href;
2205 	effNs->holdByElem = holdByElem;
2206 
2207 	if (lastEffNs == NULL)
2208 	    item->effectiveNs = effNs;
2209 	else
2210 	    lastEffNs->next = effNs;
2211 	lastEffNs = effNs;
2212 
2213 skip_ns:
2214 	{}
2215     }
2216     return(0);
2217 }
2218 
2219 
2220 /**
2221  * xsltLREInfoCreate:
2222  *
2223  * @isLRE: indicates if the given @elem is a literal result element
2224  *
2225  * Creates a new info for a literal result element.
2226  */
2227 static int
2228 xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
2229 		  xmlNodePtr elem,
2230 		  int isLRE)
2231 {
2232     xsltStyleItemLRElementInfoPtr item;
2233 
2234     if ((cctxt == NULL) || (cctxt->inode == NULL))
2235 	return(-1);
2236 
2237     item = (xsltStyleItemLRElementInfoPtr)
2238 	xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
2239     if (item == NULL) {
2240 	xsltTransformError(NULL, cctxt->style, NULL,
2241 	    "Internal error in xsltLREInfoCreate(): "
2242 	    "memory allocation failed.\n");
2243 	cctxt->style->errors++;
2244 	return(-1);
2245     }
2246     memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
2247     item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
2248     /*
2249     * Store it in the stylesheet.
2250     */
2251     item->next = cctxt->style->preComps;
2252     cctxt->style->preComps = (xsltElemPreCompPtr) item;
2253     /*
2254     * @inScopeNs are used for execution of XPath expressions
2255     *  in AVTs.
2256     */
2257     item->inScopeNs = cctxt->inode->inScopeNs;
2258 
2259     if (elem)
2260 	xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);
2261 
2262     cctxt->inode->litResElemInfo = item;
2263     cctxt->inode->nsChanged = 0;
2264     cctxt->maxLREs++;
2265     return(0);
2266 }
2267 
2268 /**
2269  * xsltCompilerVarInfoPush:
2270  * @cctxt: the compilation context
2271  *
2272  * Pushes a new var/param info onto the stack.
2273  *
2274  * Returns the acquired variable info.
2275  */
2276 static xsltVarInfoPtr
2277 xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,
2278 				  xmlNodePtr inst,
2279 				  const xmlChar *name,
2280 				  const xmlChar *nsName)
2281 {
2282     xsltVarInfoPtr ivar;
2283 
2284     if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) {
2285 	ivar = cctxt->ivar->next;
2286     } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) {
2287 	ivar = cctxt->ivars;
2288     } else {
2289 	ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo));
2290 	if (ivar == NULL) {
2291 	    xsltTransformError(NULL, cctxt->style, inst,
2292 		"xsltParseInScopeVarPush: xmlMalloc() failed!\n");
2293 	    cctxt->style->errors++;
2294 	    return(NULL);
2295 	}
2296 	/* memset(retVar, 0, sizeof(xsltInScopeVar)); */
2297 	if (cctxt->ivars == NULL) {
2298 	    cctxt->ivars = ivar;
2299 	    ivar->prev = NULL;
2300 	} else {
2301 	    cctxt->ivar->next = ivar;
2302 	    ivar->prev = cctxt->ivar;
2303 	}
2304 	cctxt->ivar = ivar;
2305 	ivar->next = NULL;
2306     }
2307     ivar->depth = cctxt->depth;
2308     ivar->name = name;
2309     ivar->nsName = nsName;
2310     return(ivar);
2311 }
2312 
2313 /**
2314  * xsltCompilerVarInfoPop:
2315  * @cctxt: the compilation context
2316  *
2317  * Pops all var/param infos from the stack, which
2318  * have the current depth.
2319  */
2320 static void
2321 xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)
2322 {
2323 
2324     while ((cctxt->ivar != NULL) &&
2325 	(cctxt->ivar->depth > cctxt->depth))
2326     {
2327 	cctxt->ivar = cctxt->ivar->prev;
2328     }
2329 }
2330 
2331 /*
2332 * xsltCompilerNodePush:
2333 *
2334 * @cctxt: the compilation context
2335 * @node: the node to be pushed (this can also be the doc-node)
2336 *
2337 *
2338 *
2339 * Returns the current node info structure or
2340 *         NULL in case of an internal error.
2341 */
2342 static xsltCompilerNodeInfoPtr
2343 xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2344 {
2345     xsltCompilerNodeInfoPtr inode, iprev;
2346 
2347     if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {
2348 	inode = cctxt->inode->next;
2349     } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {
2350 	inode = cctxt->inodeList;
2351     } else {
2352 	/*
2353 	* Create a new node-info.
2354 	*/
2355 	inode = (xsltCompilerNodeInfoPtr)
2356 	    xmlMalloc(sizeof(xsltCompilerNodeInfo));
2357 	if (inode == NULL) {
2358 	    xsltTransformError(NULL, cctxt->style, NULL,
2359 		"xsltCompilerNodePush: malloc failed.\n");
2360 	    return(NULL);
2361 	}
2362 	memset(inode, 0, sizeof(xsltCompilerNodeInfo));
2363 	if (cctxt->inodeList == NULL)
2364 	    cctxt->inodeList = inode;
2365 	else {
2366 	    cctxt->inodeLast->next = inode;
2367 	    inode->prev = cctxt->inodeLast;
2368 	}
2369 	cctxt->inodeLast = inode;
2370 	cctxt->maxNodeInfos++;
2371 	if (cctxt->inode == NULL) {
2372 	    cctxt->inode = inode;
2373 	    /*
2374 	    * Create an initial literal result element info for
2375 	    * the root of the stylesheet.
2376 	    */
2377 	    xsltLREInfoCreate(cctxt, NULL, 0);
2378 	}
2379     }
2380     cctxt->depth++;
2381     cctxt->inode = inode;
2382     /*
2383     * REVISIT TODO: Keep the reset always complete.
2384     * NOTE: Be carefull with the @node, since it might be
2385     *  a doc-node.
2386     */
2387     inode->node = node;
2388     inode->depth = cctxt->depth;
2389     inode->templ = NULL;
2390     inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
2391     inode->type = 0;
2392     inode->item = NULL;
2393     inode->curChildType = 0;
2394     inode->extContentHandled = 0;
2395     inode->isRoot = 0;
2396 
2397     if (inode->prev != NULL) {
2398 	iprev = inode->prev;
2399 	/*
2400 	* Inherit the following information:
2401 	* ---------------------------------
2402 	*
2403 	* In-scope namespaces
2404 	*/
2405 	inode->inScopeNs = iprev->inScopeNs;
2406 	/*
2407 	* Info for literal result elements
2408 	*/
2409 	inode->litResElemInfo = iprev->litResElemInfo;
2410 	inode->nsChanged = iprev->nsChanged;
2411 	/*
2412 	* Excluded result namespaces
2413 	*/
2414 	inode->exclResultNs = iprev->exclResultNs;
2415 	/*
2416 	* Extension instruction namespaces
2417 	*/
2418 	inode->extElemNs = iprev->extElemNs;
2419 	/*
2420 	* Whitespace preservation
2421 	*/
2422 	inode->preserveWhitespace = iprev->preserveWhitespace;
2423 	/*
2424 	* Forwards-compatible mode
2425 	*/
2426 	inode->forwardsCompat = iprev->forwardsCompat;
2427     } else {
2428 	inode->inScopeNs = NULL;
2429 	inode->exclResultNs = NULL;
2430 	inode->extElemNs = NULL;
2431 	inode->preserveWhitespace = 0;
2432 	inode->forwardsCompat = 0;
2433     }
2434 
2435     return(inode);
2436 }
2437 
2438 /*
2439 * xsltCompilerNodePop:
2440 *
2441 * @cctxt: the compilation context
2442 * @node: the node to be pushed (this can also be the doc-node)
2443 *
2444 * Pops the current node info.
2445 */
2446 static void
2447 xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2448 {
2449     if (cctxt->inode == NULL) {
2450 	xmlGenericError(xmlGenericErrorContext,
2451 	    "xsltCompilerNodePop: Top-node mismatch.\n");
2452 	return;
2453     }
2454     /*
2455     * NOTE: Be carefull with the @node, since it might be
2456     *  a doc-node.
2457     */
2458     if (cctxt->inode->node != node) {
2459 	xmlGenericError(xmlGenericErrorContext,
2460 	"xsltCompilerNodePop: Node mismatch.\n");
2461 	goto mismatch;
2462     }
2463     if (cctxt->inode->depth != cctxt->depth) {
2464 	xmlGenericError(xmlGenericErrorContext,
2465 	"xsltCompilerNodePop: Depth mismatch.\n");
2466 	goto mismatch;
2467     }
2468     cctxt->depth--;
2469     /*
2470     * Pop information of variables.
2471     */
2472     if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))
2473 	xsltCompilerVarInfoPop(cctxt);
2474 
2475     cctxt->inode = cctxt->inode->prev;
2476     if (cctxt->inode != NULL)
2477 	cctxt->inode->curChildType = 0;
2478     return;
2479 
2480 mismatch:
2481     {
2482 	const xmlChar *nsName = NULL, *name = NULL;
2483 	const xmlChar *infnsName = NULL, *infname = NULL;
2484 
2485 	if (node) {
2486 	    if (node->type == XML_ELEMENT_NODE) {
2487 		name = node->name;
2488 		if (node->ns != NULL)
2489 		    nsName = node->ns->href;
2490 		else
2491 		    nsName = BAD_CAST "";
2492 	    } else {
2493 		name = BAD_CAST "#document";
2494 		nsName = BAD_CAST "";
2495 	    }
2496 	} else
2497 	    name = BAD_CAST "Not given";
2498 
2499 	if (cctxt->inode->node) {
2500 	    if (node->type == XML_ELEMENT_NODE) {
2501 		infname = cctxt->inode->node->name;
2502 		if (cctxt->inode->node->ns != NULL)
2503 		    infnsName = cctxt->inode->node->ns->href;
2504 		else
2505 		    infnsName = BAD_CAST "";
2506 	    } else {
2507 		infname = BAD_CAST "#document";
2508 		infnsName = BAD_CAST "";
2509 	    }
2510 	} else
2511 	    infname = BAD_CAST "Not given";
2512 
2513 
2514 	xmlGenericError(xmlGenericErrorContext,
2515 	    "xsltCompilerNodePop: Given   : '%s' URI '%s'\n",
2516 	    name, nsName);
2517 	xmlGenericError(xmlGenericErrorContext,
2518 	    "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
2519 	    infname, infnsName);
2520     }
2521 }
2522 
2523 /*
2524 * xsltCompilerBuildInScopeNsList:
2525 *
2526 * Create and store the list of in-scope namespaces for the given
2527 * node in the stylesheet. If there are no changes in the in-scope
2528 * namespaces then the last ns-info of the ancestor axis will be returned.
2529 * Compilation-time only.
2530 *
2531 * Returns the ns-info or NULL if there are no namespaces in scope.
2532 */
2533 static xsltNsListContainerPtr
2534 xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2535 {
2536     xsltNsListContainerPtr nsi = NULL;
2537     xmlNsPtr *list = NULL, ns;
2538     int i, maxns = 5;
2539     /*
2540     * Create a new ns-list for this position in the node-tree.
2541     * xmlGetNsList() will return NULL, if there are no ns-decls in the
2542     * tree. Note that the ns-decl for the XML namespace is not added
2543     * to the resulting list; the XPath module handles the XML namespace
2544     * internally.
2545     */
2546     while (node != NULL) {
2547         if (node->type == XML_ELEMENT_NODE) {
2548             ns = node->nsDef;
2549             while (ns != NULL) {
2550                 if (nsi == NULL) {
2551 		    nsi = (xsltNsListContainerPtr)
2552 			xmlMalloc(sizeof(xsltNsListContainer));
2553 		    if (nsi == NULL) {
2554 			xsltTransformError(NULL, cctxt->style, NULL,
2555 			    "xsltCompilerBuildInScopeNsList: "
2556 			    "malloc failed!\n");
2557 			goto internal_err;
2558 		    }
2559 		    memset(nsi, 0, sizeof(xsltNsListContainer));
2560                     nsi->list =
2561                         (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
2562                     if (nsi->list == NULL) {
2563 			xsltTransformError(NULL, cctxt->style, NULL,
2564 			    "xsltCompilerBuildInScopeNsList: "
2565 			    "malloc failed!\n");
2566 			goto internal_err;
2567                     }
2568                     nsi->list[0] = NULL;
2569                 }
2570 		/*
2571 		* Skip shadowed namespace bindings.
2572 		*/
2573                 for (i = 0; i < nsi->totalNumber; i++) {
2574                     if ((ns->prefix == nsi->list[i]->prefix) ||
2575                         (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
2576 		    break;
2577                 }
2578                 if (i >= nsi->totalNumber) {
2579                     if (nsi->totalNumber +1 >= maxns) {
2580                         maxns *= 2;
2581 			nsi->list =
2582 			    (xmlNsPtr *) xmlRealloc(nsi->list,
2583 				maxns * sizeof(xmlNsPtr));
2584                         if (nsi->list == NULL) {
2585                             xsltTransformError(NULL, cctxt->style, NULL,
2586 				"xsltCompilerBuildInScopeNsList: "
2587 				"realloc failed!\n");
2588 				goto internal_err;
2589                         }
2590                     }
2591                     nsi->list[nsi->totalNumber++] = ns;
2592                     nsi->list[nsi->totalNumber] = NULL;
2593                 }
2594 
2595                 ns = ns->next;
2596             }
2597         }
2598         node = node->parent;
2599     }
2600     if (nsi == NULL)
2601 	return(NULL);
2602     /*
2603     * Move the default namespace to last position.
2604     */
2605     nsi->xpathNumber = nsi->totalNumber;
2606     for (i = 0; i < nsi->totalNumber; i++) {
2607 	if (nsi->list[i]->prefix == NULL) {
2608 	    ns = nsi->list[i];
2609 	    nsi->list[i] = nsi->list[nsi->totalNumber-1];
2610 	    nsi->list[nsi->totalNumber-1] = ns;
2611 	    nsi->xpathNumber--;
2612 	    break;
2613 	}
2614     }
2615     /*
2616     * Store the ns-list in the stylesheet.
2617     */
2618     if (xsltPointerListAddSize(
2619 	(xsltPointerListPtr)cctxt->psData->inScopeNamespaces,
2620 	(void *) nsi, 5) == -1)
2621     {
2622 	xmlFree(nsi);
2623 	nsi = NULL;
2624 	xsltTransformError(NULL, cctxt->style, NULL,
2625 	    "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
2626 	goto internal_err;
2627     }
2628     /*
2629     * Notify of change in status wrt namespaces.
2630     */
2631     if (cctxt->inode != NULL)
2632 	cctxt->inode->nsChanged = 1;
2633 
2634     return(nsi);
2635 
2636 internal_err:
2637     if (list != NULL)
2638 	xmlFree(list);
2639     cctxt->style->errors++;
2640     return(NULL);
2641 }
2642 
2643 static int
2644 xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
2645 		      xsltPointerListPtr list,
2646 		      xmlNodePtr node,
2647 		      const xmlChar *value)
2648 {
2649     xmlChar *cur, *end;
2650     xmlNsPtr ns;
2651 
2652     if ((cctxt == NULL) || (value == NULL) || (list == NULL))
2653 	return(-1);
2654 
2655     list->number = 0;
2656 
2657     cur = (xmlChar *) value;
2658     while (*cur != 0) {
2659 	while (IS_BLANK(*cur)) cur++;
2660 	if (*cur == 0)
2661 	    break;
2662 	end = cur;
2663 	while ((*end != 0) && (!IS_BLANK(*end))) end++;
2664 	cur = xmlStrndup(cur, end - cur);
2665 	if (cur == NULL) {
2666 	    cur = end;
2667 	    continue;
2668 	}
2669 	/*
2670 	* TODO: Export and use xmlSearchNsByPrefixStrict()
2671 	*   in Libxml2, tree.c, since xmlSearchNs() is in most
2672 	*   cases not efficient and in some cases not correct.
2673 	*
2674 	* XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
2675 	*/
2676 	if ((cur[0] == '#') &&
2677 	    xmlStrEqual(cur, (const xmlChar *)"#default"))
2678 	    ns = xmlSearchNs(cctxt->style->doc, node, NULL);
2679 	else
2680 	    ns = xmlSearchNs(cctxt->style->doc, node, cur);
2681 
2682 	if (ns == NULL) {
2683 	    /*
2684 	    * TODO: Better to report the attr-node, otherwise
2685 	    *  the user won't know which attribute was invalid.
2686 	    */
2687 	    xsltTransformError(NULL, cctxt->style, node,
2688 		"No namespace binding in scope for prefix '%s'.\n", cur);
2689 	    /*
2690 	    * XSLT-1.0: "It is an error if there is no namespace
2691 	    *  bound to the prefix on the element bearing the
2692 	    *  exclude-result-prefixes or xsl:exclude-result-prefixes
2693 	    *  attribute."
2694 	    */
2695 	    cctxt->style->errors++;
2696 	} else {
2697 #ifdef WITH_XSLT_DEBUG_PARSING
2698 	    xsltGenericDebug(xsltGenericDebugContext,
2699 		"resolved prefix '%s'\n", cur);
2700 #endif
2701 	    /*
2702 	    * Note that we put the namespace name into the dict.
2703 	    */
2704 	    if (xsltPointerListAddSize(list,
2705 		(void *) xmlDictLookup(cctxt->style->dict,
2706 		ns->href, -1), 5) == -1)
2707 	    {
2708 		xmlFree(cur);
2709 		goto internal_err;
2710 	    }
2711 	}
2712 	xmlFree(cur);
2713 
2714 	cur = end;
2715     }
2716     return(0);
2717 
2718 internal_err:
2719     cctxt->style->errors++;
2720     return(-1);
2721 }
2722 
2723 /**
2724  * xsltCompilerUtilsCreateMergedList:
2725  * @dest: the destination list (optional)
2726  * @first: the first list
2727  * @second: the second list (optional)
2728  *
2729  * Appends the content of @second to @first into @destination.
2730  * If @destination is NULL a new list will be created.
2731  *
2732  * Returns the merged list of items or NULL if there's nothing to merge.
2733  */
2734 static xsltPointerListPtr
2735 xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,
2736 			    xsltPointerListPtr second)
2737 {
2738     xsltPointerListPtr ret;
2739     size_t num;
2740 
2741     if (first)
2742 	num = first->number;
2743     else
2744 	num = 0;
2745     if (second)
2746 	num += second->number;
2747     if (num == 0)
2748 	return(NULL);
2749     ret = xsltPointerListCreate(num);
2750     if (ret == NULL)
2751 	return(NULL);
2752     /*
2753     * Copy contents.
2754     */
2755     if ((first != NULL) &&  (first->number != 0)) {
2756 	memcpy(ret->items, first->items,
2757 	    first->number * sizeof(void *));
2758 	if ((second != NULL) && (second->number != 0))
2759 	    memcpy(ret->items + first->number, second->items,
2760 		second->number * sizeof(void *));
2761     } else if ((second != NULL) && (second->number != 0))
2762 	memcpy(ret->items, (void *) second->items,
2763 	    second->number * sizeof(void *));
2764     ret->number = num;
2765     return(ret);
2766 }
2767 
2768 /*
2769 * xsltParseExclResultPrefixes:
2770 *
2771 * Create and store the list of in-scope namespaces for the given
2772 * node in the stylesheet. If there are no changes in the in-scope
2773 * namespaces then the last ns-info of the ancestor axis will be returned.
2774 * Compilation-time only.
2775 *
2776 * Returns the ns-info or NULL if there are no namespaces in scope.
2777 */
2778 static xsltPointerListPtr
2779 xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2780 			    xsltPointerListPtr def,
2781 			    int instrCategory)
2782 {
2783     xsltPointerListPtr list = NULL;
2784     xmlChar *value;
2785     xmlAttrPtr attr;
2786 
2787     if ((cctxt == NULL) || (node == NULL))
2788 	return(NULL);
2789 
2790     if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2791 	attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
2792     else
2793 	attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
2794 	    XSLT_NAMESPACE);
2795     if (attr == NULL)
2796 	return(def);
2797 
2798     if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2799 	/*
2800 	* Mark the XSLT attr.
2801 	*/
2802 	attr->psvi = (void *) xsltXSLTAttrMarker;
2803     }
2804 
2805     if ((attr->children != NULL) &&
2806 	(attr->children->content != NULL))
2807 	value = attr->children->content;
2808     else {
2809 	xsltTransformError(NULL, cctxt->style, node,
2810 	    "Attribute 'exclude-result-prefixes': Invalid value.\n");
2811 	cctxt->style->errors++;
2812 	return(def);
2813     }
2814 
2815     if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2816 	BAD_CAST value) != 0)
2817 	goto exit;
2818     if (cctxt->tmpList->number == 0)
2819 	goto exit;
2820     /*
2821     * Merge the list with the inherited list.
2822     */
2823     list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2824     if (list == NULL)
2825 	goto exit;
2826     /*
2827     * Store the list in the stylesheet/compiler context.
2828     */
2829     if (xsltPointerListAddSize(
2830 	cctxt->psData->exclResultNamespaces, list, 5) == -1)
2831     {
2832 	xsltPointerListFree(list);
2833 	list = NULL;
2834 	goto exit;
2835     }
2836     /*
2837     * Notify of change in status wrt namespaces.
2838     */
2839     if (cctxt->inode != NULL)
2840 	cctxt->inode->nsChanged = 1;
2841 
2842 exit:
2843     if (list != NULL)
2844 	return(list);
2845     else
2846 	return(def);
2847 }
2848 
2849 /*
2850 * xsltParseExtElemPrefixes:
2851 *
2852 * Create and store the list of in-scope namespaces for the given
2853 * node in the stylesheet. If there are no changes in the in-scope
2854 * namespaces then the last ns-info of the ancestor axis will be returned.
2855 * Compilation-time only.
2856 *
2857 * Returns the ns-info or NULL if there are no namespaces in scope.
2858 */
2859 static xsltPointerListPtr
2860 xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2861 			 xsltPointerListPtr def,
2862 			 int instrCategory)
2863 {
2864     xsltPointerListPtr list = NULL;
2865     xmlAttrPtr attr;
2866     xmlChar *value;
2867     int i;
2868 
2869     if ((cctxt == NULL) || (node == NULL))
2870 	return(NULL);
2871 
2872     if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2873 	attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
2874     else
2875 	attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
2876 	    XSLT_NAMESPACE);
2877     if (attr == NULL)
2878 	return(def);
2879 
2880     if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2881 	/*
2882 	* Mark the XSLT attr.
2883 	*/
2884 	attr->psvi = (void *) xsltXSLTAttrMarker;
2885     }
2886 
2887     if ((attr->children != NULL) &&
2888 	(attr->children->content != NULL))
2889 	value = attr->children->content;
2890     else {
2891 	xsltTransformError(NULL, cctxt->style, node,
2892 	    "Attribute 'extension-element-prefixes': Invalid value.\n");
2893 	cctxt->style->errors++;
2894 	return(def);
2895     }
2896 
2897 
2898     if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2899 	BAD_CAST value) != 0)
2900 	goto exit;
2901 
2902     if (cctxt->tmpList->number == 0)
2903 	goto exit;
2904     /*
2905     * REVISIT: Register the extension namespaces.
2906     */
2907     for (i = 0; i < cctxt->tmpList->number; i++)
2908 	xsltRegisterExtPrefix(cctxt->style, NULL,
2909 	BAD_CAST cctxt->tmpList->items[i]);
2910     /*
2911     * Merge the list with the inherited list.
2912     */
2913     list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2914     if (list == NULL)
2915 	goto exit;
2916     /*
2917     * Store the list in the stylesheet.
2918     */
2919     if (xsltPointerListAddSize(
2920 	cctxt->psData->extElemNamespaces, list, 5) == -1)
2921     {
2922 	xsltPointerListFree(list);
2923 	list = NULL;
2924 	goto exit;
2925     }
2926     /*
2927     * Notify of change in status wrt namespaces.
2928     */
2929     if (cctxt->inode != NULL)
2930 	cctxt->inode->nsChanged = 1;
2931 
2932 exit:
2933     if (list != NULL)
2934 	return(list);
2935     else
2936 	return(def);
2937 }
2938 
2939 /*
2940 * xsltParseAttrXSLTVersion:
2941 *
2942 * @cctxt: the compilation context
2943 * @node: the element-node
2944 * @isXsltElem: whether this is an XSLT element
2945 *
2946 * Parses the attribute xsl:version.
2947 *
2948 * Returns 1 if there was such an attribute, 0 if not and
2949 *         -1 if an internal or API error occured.
2950 */
2951 static int
2952 xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2953 			 int instrCategory)
2954 {
2955     xmlChar *value;
2956     xmlAttrPtr attr;
2957 
2958     if ((cctxt == NULL) || (node == NULL))
2959 	return(-1);
2960 
2961     if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2962 	attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
2963     else
2964 	attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
2965 
2966     if (attr == NULL)
2967 	return(0);
2968 
2969     attr->psvi = (void *) xsltXSLTAttrMarker;
2970 
2971     if ((attr->children != NULL) &&
2972 	(attr->children->content != NULL))
2973 	value = attr->children->content;
2974     else {
2975 	xsltTransformError(NULL, cctxt->style, node,
2976 	    "Attribute 'version': Invalid value.\n");
2977 	cctxt->style->errors++;
2978 	return(1);
2979     }
2980 
2981     if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
2982 	cctxt->inode->forwardsCompat = 1;
2983 	/*
2984 	* TODO: To what extent do we support the
2985 	*  forwards-compatible mode?
2986 	*/
2987 	/*
2988 	* Report this only once per compilation episode.
2989 	*/
2990 	if (! cctxt->hasForwardsCompat) {
2991 	    cctxt->hasForwardsCompat = 1;
2992 	    cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;
2993 	    xsltTransformError(NULL, cctxt->style, node,
2994 		"Warning: the attribute xsl:version specifies a value "
2995 		"different from '1.0'. Switching to forwards-compatible "
2996 		"mode. Only features of XSLT 1.0 are supported by this "
2997 		"processor.\n");
2998 	    cctxt->style->warnings++;
2999 	    cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
3000 	}
3001     } else {
3002 	cctxt->inode->forwardsCompat = 0;
3003     }
3004 
3005     if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
3006 	/*
3007 	* Set a marker on XSLT attributes.
3008 	*/
3009 	attr->psvi = (void *) xsltXSLTAttrMarker;
3010     }
3011     return(1);
3012 }
3013 
3014 static int
3015 xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
3016 {
3017     xmlNodePtr deleteNode, cur, txt, textNode = NULL;
3018     xmlDocPtr doc;
3019     xsltStylesheetPtr style;
3020     int internalize = 0, findSpaceAttr;
3021     int xsltStylesheetElemDepth;
3022     xmlAttrPtr attr;
3023     xmlChar *value;
3024     const xmlChar *name, *nsNameXSLT = NULL;
3025     int strictWhitespace, inXSLText = 0;
3026 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3027     xsltNsMapPtr nsMapItem;
3028 #endif
3029 
3030     if ((cctxt == NULL) || (cctxt->style == NULL) ||
3031 	(node == NULL) || (node->type != XML_ELEMENT_NODE))
3032         return(-1);
3033 
3034     doc = node->doc;
3035     if (doc == NULL)
3036 	goto internal_err;
3037 
3038     style = cctxt->style;
3039     if ((style->dict != NULL) && (doc->dict == style->dict))
3040 	internalize = 1;
3041     else
3042         style->internalized = 0;
3043 
3044     /*
3045     * Init value of xml:space. Since this might be an embedded
3046     * stylesheet, this is needed to be performed on the element
3047     * where the stylesheet is rooted at, taking xml:space of
3048     * ancestors into account.
3049     */
3050     if (! cctxt->simplified)
3051 	xsltStylesheetElemDepth = cctxt->depth +1;
3052     else
3053 	xsltStylesheetElemDepth = 0;
3054 
3055     if (xmlNodeGetSpacePreserve(node) != 1)
3056 	cctxt->inode->preserveWhitespace = 0;
3057     else
3058 	cctxt->inode->preserveWhitespace = 1;
3059 
3060     /*
3061     * Eval if we should keep the old incorrect behaviour.
3062     */
3063     strictWhitespace = (cctxt->strict != 0) ? 1 : 0;
3064 
3065     nsNameXSLT = xsltConstNamespaceNameXSLT;
3066 
3067     deleteNode = NULL;
3068     cur = node;
3069     while (cur != NULL) {
3070 	if (deleteNode != NULL)	{
3071 
3072 #ifdef WITH_XSLT_DEBUG_BLANKS
3073 	    xsltGenericDebug(xsltGenericDebugContext,
3074 	     "xsltParsePreprocessStylesheetTree: removing node\n");
3075 #endif
3076 	    xmlUnlinkNode(deleteNode);
3077 	    xmlFreeNode(deleteNode);
3078 	    deleteNode = NULL;
3079 	}
3080 	if (cur->type == XML_ELEMENT_NODE) {
3081 
3082 	    /*
3083 	    * Clear the PSVI field.
3084 	    */
3085 	    cur->psvi = NULL;
3086 
3087 	    xsltCompilerNodePush(cctxt, cur);
3088 
3089 	    inXSLText = 0;
3090 	    textNode = NULL;
3091 	    findSpaceAttr = 1;
3092 	    cctxt->inode->stripWhitespace = 0;
3093 	    /*
3094 	    * TODO: I'd love to use a string pointer comparison here :-/
3095 	    */
3096 	    if (IS_XSLT_ELEM(cur)) {
3097 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3098 		if (cur->ns->href != nsNameXSLT) {
3099 		    nsMapItem = xsltNewNamespaceMapItem(cctxt,
3100 			doc, cur->ns, cur);
3101 		    if (nsMapItem == NULL)
3102 			goto internal_err;
3103 		    cur->ns->href = nsNameXSLT;
3104 		}
3105 #endif
3106 
3107 		if (cur->name == NULL)
3108 		    goto process_attributes;
3109 		/*
3110 		* Mark the XSLT element for later recognition.
3111 		* TODO: Using the marker is still too dangerous, since if
3112 		*   the parsing mechanism leaves out an XSLT element, then
3113 		*   this might hit the transformation-mechanism, which
3114 		*   will break if it doesn't expect such a marker.
3115 		*/
3116 		/* cur->psvi = (void *) xsltXSLTElemMarker; */
3117 
3118 		/*
3119 		* XSLT 2.0: "Any whitespace text node whose parent is
3120 		* one of the following elements is removed from the "
3121 		* tree, regardless of any xml:space attributes:..."
3122 		* xsl:apply-imports,
3123 		* xsl:apply-templates,
3124 		* xsl:attribute-set,
3125 		* xsl:call-template,
3126 		* xsl:choose,
3127 		* xsl:stylesheet, xsl:transform.
3128 		* XSLT 2.0: xsl:analyze-string,
3129 		*           xsl:character-map,
3130 		*           xsl:next-match
3131 		*
3132 		* TODO: I'd love to use a string pointer comparison here :-/
3133 		*/
3134 		name = cur->name;
3135 		switch (*name) {
3136 		    case 't':
3137 			if ((name[0] == 't') && (name[1] == 'e') &&
3138 			    (name[2] == 'x') && (name[3] == 't') &&
3139 			    (name[4] == 0))
3140 			{
3141 			    /*
3142 			    * Process the xsl:text element.
3143 			    * ----------------------------
3144 			    * Mark it for later recognition.
3145 			    */
3146 			    cur->psvi = (void *) xsltXSLTTextMarker;
3147 			    /*
3148 			    * For stylesheets, the set of
3149 			    * whitespace-preserving element names
3150 			    * consists of just xsl:text.
3151 			    */
3152 			    findSpaceAttr = 0;
3153 			    cctxt->inode->preserveWhitespace = 1;
3154 			    inXSLText = 1;
3155 			}
3156 			break;
3157 		    case 'c':
3158 			if (xmlStrEqual(name, BAD_CAST "choose") ||
3159 			    xmlStrEqual(name, BAD_CAST "call-template"))
3160 			    cctxt->inode->stripWhitespace = 1;
3161 			break;
3162 		    case 'a':
3163 			if (xmlStrEqual(name, BAD_CAST "apply-templates") ||
3164 			    xmlStrEqual(name, BAD_CAST "apply-imports") ||
3165 			    xmlStrEqual(name, BAD_CAST "attribute-set"))
3166 
3167 			    cctxt->inode->stripWhitespace = 1;
3168 			break;
3169 		    default:
3170 			if (xsltStylesheetElemDepth == cctxt->depth) {
3171 			    /*
3172 			    * This is a xsl:stylesheet/xsl:transform.
3173 			    */
3174 			    cctxt->inode->stripWhitespace = 1;
3175 			    break;
3176 			}
3177 
3178 			if ((cur->prev != NULL) &&
3179 			    (cur->prev->type == XML_TEXT_NODE))
3180 			{
3181 			    /*
3182 			    * XSLT 2.0 : "Any whitespace text node whose
3183 			    *  following-sibling node is an xsl:param or
3184 			    *  xsl:sort element is removed from the tree,
3185 			    *  regardless of any xml:space attributes."
3186 			    */
3187 			    if (((*name == 'p') || (*name == 's')) &&
3188 				(xmlStrEqual(name, BAD_CAST "param") ||
3189 				 xmlStrEqual(name, BAD_CAST "sort")))
3190 			    {
3191 				do {
3192 				    if (IS_BLANK_NODE(cur->prev)) {
3193 					txt = cur->prev;
3194 					xmlUnlinkNode(txt);
3195 					xmlFreeNode(txt);
3196 				    } else {
3197 					/*
3198 					* This will result in a content
3199 					* error, when hitting the parsing
3200 					* functions.
3201 					*/
3202 					break;
3203 				    }
3204 				} while (cur->prev);
3205 			    }
3206 			}
3207 			break;
3208 		}
3209 	    }
3210 
3211 process_attributes:
3212 	    /*
3213 	    * Process attributes.
3214 	    * ------------------
3215 	    */
3216 	    if (cur->properties != NULL) {
3217 		if (cur->children == NULL)
3218 		    findSpaceAttr = 0;
3219 		attr = cur->properties;
3220 		do {
3221 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3222 		    if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
3223 			xmlStrEqual(attr->ns->href, nsNameXSLT))
3224 		    {
3225 			nsMapItem = xsltNewNamespaceMapItem(cctxt,
3226 			    doc, attr->ns, cur);
3227 			if (nsMapItem == NULL)
3228 			    goto internal_err;
3229 			attr->ns->href = nsNameXSLT;
3230 		    }
3231 #endif
3232 		    if (internalize) {
3233 			/*
3234 			* Internalize the attribute's value; the goal is to
3235 			* speed up operations and minimize used space by
3236 			* compiled stylesheets.
3237 			*/
3238 			txt = attr->children;
3239 			/*
3240 			* NOTE that this assumes only one
3241 			*  text-node in the attribute's content.
3242 			*/
3243 			if ((txt != NULL) && (txt->content != NULL) &&
3244 			    (!xmlDictOwns(style->dict, txt->content)))
3245 			{
3246 			    value = (xmlChar *) xmlDictLookup(style->dict,
3247 				txt->content, -1);
3248 			    xmlNodeSetContent(txt, NULL);
3249 			    txt->content = value;
3250 			}
3251 		    }
3252 		    /*
3253 		    * Process xml:space attributes.
3254 		    * ----------------------------
3255 		    */
3256 		    if ((findSpaceAttr != 0) &&
3257 			(attr->ns != NULL) &&
3258 			(attr->name != NULL) &&
3259 			(attr->name[0] == 's') &&
3260 			(attr->ns->prefix != NULL) &&
3261 			(attr->ns->prefix[0] == 'x') &&
3262 			(attr->ns->prefix[1] == 'm') &&
3263 			(attr->ns->prefix[2] == 'l') &&
3264 			(attr->ns->prefix[3] == 0))
3265 		    {
3266 			value = xmlGetNsProp(cur, BAD_CAST "space",
3267 			    XML_XML_NAMESPACE);
3268 			if (value != NULL) {
3269 			    if (xmlStrEqual(value, BAD_CAST "preserve")) {
3270 				cctxt->inode->preserveWhitespace = 1;
3271 			    } else if (xmlStrEqual(value, BAD_CAST "default")) {
3272 				cctxt->inode->preserveWhitespace = 0;
3273 			    } else {
3274 				/* Invalid value for xml:space. */
3275 				xsltTransformError(NULL, style, cur,
3276 				    "Attribute xml:space: Invalid value.\n");
3277 				cctxt->style->warnings++;
3278 			    }
3279 			    findSpaceAttr = 0;
3280 			    xmlFree(value);
3281 			}
3282 
3283 		    }
3284 		    attr = attr->next;
3285 		} while (attr != NULL);
3286 	    }
3287 	    /*
3288 	    * We'll descend into the children of element nodes only.
3289 	    */
3290 	    if (cur->children != NULL) {
3291 		cur = cur->children;
3292 		continue;
3293 	    }
3294 	} else if ((cur->type == XML_TEXT_NODE) ||
3295 		(cur->type == XML_CDATA_SECTION_NODE))
3296 	{
3297 	    /*
3298 	    * Merge adjacent text/CDATA-section-nodes
3299 	    * ---------------------------------------
3300 	    * In order to avoid breaking of existing stylesheets,
3301 	    * if the old behaviour is wanted (strictWhitespace == 0),
3302 	    * then we *won't* merge adjacent text-nodes
3303 	    * (except in xsl:text); this will ensure that whitespace-only
3304 	    * text nodes are (incorrectly) not stripped in some cases.
3305 	    *
3306 	    * Example:               : <foo>  <!-- bar -->zoo</foo>
3307 	    * Corrent (strict) result: <foo>  zoo</foo>
3308 	    * Incorrect (old) result : <foo>zoo</foo>
3309 	    *
3310 	    * NOTE that we *will* merge adjacent text-nodes if
3311 	    * they are in xsl:text.
3312 	    * Example, the following:
3313 	    * <xsl:text>  <!-- bar -->zoo<xsl:text>
3314 	    * will result in both cases in:
3315 	    * <xsl:text>  zoo<xsl:text>
3316 	    */
3317 	    cur->type = XML_TEXT_NODE;
3318 	    if ((strictWhitespace != 0) || (inXSLText != 0)) {
3319 		/*
3320 		* New behaviour; merge nodes.
3321 		*/
3322 		if (textNode == NULL)
3323 		    textNode = cur;
3324 		else {
3325 		    if (cur->content != NULL)
3326 			xmlNodeAddContent(textNode, cur->content);
3327 		    deleteNode = cur;
3328 		}
3329 		if ((cur->next == NULL) ||
3330 		    (cur->next->type == XML_ELEMENT_NODE))
3331 		    goto end_of_text;
3332 		else
3333 		    goto next_sibling;
3334 	    } else {
3335 		/*
3336 		* Old behaviour.
3337 		*/
3338 		if (textNode == NULL)
3339 		    textNode = cur;
3340 		goto end_of_text;
3341 	    }
3342 	} else if ((cur->type == XML_COMMENT_NODE) ||
3343 	    (cur->type == XML_PI_NODE))
3344 	{
3345 	    /*
3346 	    * Remove processing instructions and comments.
3347 	    */
3348 	    deleteNode = cur;
3349 	    if ((cur->next == NULL) ||
3350 		(cur->next->type == XML_ELEMENT_NODE))
3351 		goto end_of_text;
3352 	    else
3353 		goto next_sibling;
3354 	} else {
3355 	    textNode = NULL;
3356 	    /*
3357 	    * Invalid node-type for this data-model.
3358 	    */
3359 	    xsltTransformError(NULL, style, cur,
3360 		"Invalid type of node for the XSLT data model.\n");
3361 	    cctxt->style->errors++;
3362 	    goto next_sibling;
3363 	}
3364 
3365 end_of_text:
3366 	if (textNode) {
3367 	    value = textNode->content;
3368 	    /*
3369 	    * At this point all adjacent text/CDATA-section nodes
3370 	    * have been merged.
3371 	    *
3372 	    * Strip whitespace-only text-nodes.
3373 	    * (cctxt->inode->stripWhitespace)
3374 	    */
3375 	    if ((value == NULL) || (*value == 0) ||
3376 		(((cctxt->inode->stripWhitespace) ||
3377 		  (! cctxt->inode->preserveWhitespace)) &&
3378 		 IS_BLANK(*value) &&
3379 		 xsltIsBlank(value)))
3380 	    {
3381 		if (textNode != cur) {
3382 		    xmlUnlinkNode(textNode);
3383 		    xmlFreeNode(textNode);
3384 		} else
3385 		    deleteNode = textNode;
3386 		textNode = NULL;
3387 		goto next_sibling;
3388 	    }
3389 	    /*
3390 	    * Convert CDATA-section nodes to text-nodes.
3391 	    * TODO: Can this produce problems?
3392 	    */
3393 	    if (textNode->type != XML_TEXT_NODE) {
3394 		textNode->type = XML_TEXT_NODE;
3395 		textNode->name = xmlStringText;
3396 	    }
3397 	    if (internalize &&
3398 		(textNode->content != NULL) &&
3399 		(!xmlDictOwns(style->dict, textNode->content)))
3400 	    {
3401 		/*
3402 		* Internalize the string.
3403 		*/
3404 		value = (xmlChar *) xmlDictLookup(style->dict,
3405 		    textNode->content, -1);
3406 		xmlNodeSetContent(textNode, NULL);
3407 		textNode->content = value;
3408 	    }
3409 	    textNode = NULL;
3410 	    /*
3411 	    * Note that "disable-output-escaping" of the xsl:text
3412 	    * element will be applied at a later level, when
3413 	    * XSLT elements are processed.
3414 	    */
3415 	}
3416 
3417 next_sibling:
3418 	if (cur->type == XML_ELEMENT_NODE) {
3419 	    xsltCompilerNodePop(cctxt, cur);
3420 	}
3421 	if (cur == node)
3422 	    break;
3423 	if (cur->next != NULL) {
3424 	    cur = cur->next;
3425 	} else {
3426 	    cur = cur->parent;
3427 	    inXSLText = 0;
3428 	    goto next_sibling;
3429 	};
3430     }
3431     if (deleteNode != NULL) {
3432 #ifdef WITH_XSLT_DEBUG_PARSING
3433 	xsltGenericDebug(xsltGenericDebugContext,
3434 	 "xsltParsePreprocessStylesheetTree: removing node\n");
3435 #endif
3436 	xmlUnlinkNode(deleteNode);
3437 	xmlFreeNode(deleteNode);
3438     }
3439     return(0);
3440 
3441 internal_err:
3442     return(-1);
3443 }
3444 
3445 #endif /* XSLT_REFACTORED */
3446 
3447 #ifdef XSLT_REFACTORED
3448 #else
3449 static void
3450 xsltPreprocessStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
3451 {
3452     xmlNodePtr deleteNode, styleelem;
3453     int internalize = 0;
3454 
3455     if ((style == NULL) || (cur == NULL))
3456         return;
3457 
3458     if ((cur->doc != NULL) && (style->dict != NULL) &&
3459         (cur->doc->dict == style->dict))
3460 	internalize = 1;
3461     else
3462         style->internalized = 0;
3463 
3464     if ((cur != NULL) && (IS_XSLT_ELEM(cur)) &&
3465         (IS_XSLT_NAME(cur, "stylesheet"))) {
3466 	styleelem = cur;
3467     } else {
3468         styleelem = NULL;
3469     }
3470 
3471     /*
3472      * This content comes from the stylesheet
3473      * For stylesheets, the set of whitespace-preserving
3474      * element names consists of just xsl:text.
3475      */
3476     deleteNode = NULL;
3477     while (cur != NULL) {
3478 	if (deleteNode != NULL) {
3479 #ifdef WITH_XSLT_DEBUG_BLANKS
3480 	    xsltGenericDebug(xsltGenericDebugContext,
3481 	     "xsltPreprocessStylesheet: removing ignorable blank node\n");
3482 #endif
3483 	    xmlUnlinkNode(deleteNode);
3484 	    xmlFreeNode(deleteNode);
3485 	    deleteNode = NULL;
3486 	}
3487 	if (cur->type == XML_ELEMENT_NODE) {
3488 	    int exclPrefixes;
3489 	    /*
3490 	     * Internalize attributes values.
3491 	     */
3492 	    if ((internalize) && (cur->properties != NULL)) {
3493 	        xmlAttrPtr attr = cur->properties;
3494 		xmlNodePtr txt;
3495 
3496 		while (attr != NULL) {
3497 		    txt = attr->children;
3498 		    if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
3499 		        (txt->content != NULL) &&
3500 			(!xmlDictOwns(style->dict, txt->content)))
3501 		    {
3502 			xmlChar *tmp;
3503 
3504 			/*
3505 			 * internalize the text string, goal is to speed
3506 			 * up operations and minimize used space by compiled
3507 			 * stylesheets.
3508 			 */
3509 			tmp = (xmlChar *) xmlDictLookup(style->dict,
3510 			                                txt->content, -1);
3511 			if (tmp != txt->content) {
3512 			    xmlNodeSetContent(txt, NULL);
3513 			    txt->content = tmp;
3514 			}
3515 		    }
3516 		    attr = attr->next;
3517 		}
3518 	    }
3519 	    if (IS_XSLT_ELEM(cur)) {
3520 		exclPrefixes = 0;
3521 		if (IS_XSLT_NAME(cur, "text")) {
3522 		    for (;exclPrefixes > 0;exclPrefixes--)
3523 			exclPrefixPop(style);
3524 		    goto skip_children;
3525 		}
3526 	    } else {
3527 		exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
3528 	    }
3529 
3530 	    if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
3531 		xmlNsPtr ns = cur->nsDef, prev = NULL, next;
3532 		xmlNodePtr root = NULL;
3533 		int i, moved;
3534 
3535 		root = xmlDocGetRootElement(cur->doc);
3536 		if ((root != NULL) && (root != cur)) {
3537 		    while (ns != NULL) {
3538 			moved = 0;
3539 			next = ns->next;
3540 			for (i = 0;i < style->exclPrefixNr;i++) {
3541 			    if ((ns->prefix != NULL) &&
3542 			        (xmlStrEqual(ns->href,
3543 					     style->exclPrefixTab[i]))) {
3544 				/*
3545 				 * Move the namespace definition on the root
3546 				 * element to avoid duplicating it without
3547 				 * loosing it.
3548 				 */
3549 				if (prev == NULL) {
3550 				    cur->nsDef = ns->next;
3551 				} else {
3552 				    prev->next = ns->next;
3553 				}
3554 				ns->next = root->nsDef;
3555 				root->nsDef = ns;
3556 				moved = 1;
3557 				break;
3558 			    }
3559 			}
3560 			if (moved == 0)
3561 			    prev = ns;
3562 			ns = next;
3563 		    }
3564 		}
3565 	    }
3566 	    /*
3567 	     * If we have prefixes locally, recurse and pop them up when
3568 	     * going back
3569 	     */
3570 	    if (exclPrefixes > 0) {
3571 		xsltPreprocessStylesheet(style, cur->children);
3572 		for (;exclPrefixes > 0;exclPrefixes--)
3573 		    exclPrefixPop(style);
3574 		goto skip_children;
3575 	    }
3576 	} else if (cur->type == XML_TEXT_NODE) {
3577 	    if (IS_BLANK_NODE(cur)) {
3578 		if (xmlNodeGetSpacePreserve(cur->parent) != 1) {
3579 		    deleteNode = cur;
3580 		}
3581 	    } else if ((cur->content != NULL) && (internalize) &&
3582 	               (!xmlDictOwns(style->dict, cur->content))) {
3583 		xmlChar *tmp;
3584 
3585 		/*
3586 		 * internalize the text string, goal is to speed
3587 		 * up operations and minimize used space by compiled
3588 		 * stylesheets.
3589 		 */
3590 		tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
3591 		xmlNodeSetContent(cur, NULL);
3592 		cur->content = tmp;
3593 	    }
3594 	} else if ((cur->type != XML_ELEMENT_NODE) &&
3595 		   (cur->type != XML_CDATA_SECTION_NODE)) {
3596 	    deleteNode = cur;
3597 	    goto skip_children;
3598 	}
3599 
3600 	/*
3601 	 * Skip to next node. In case of a namespaced element children of
3602 	 * the stylesheet and not in the XSLT namespace and not an extension
3603 	 * element, ignore its content.
3604 	 */
3605 	if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) &&
3606 	    (styleelem != NULL) && (cur->parent == styleelem) &&
3607 	    (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) &&
3608 	    (!xsltCheckExtURI(style, cur->ns->href))) {
3609 	    goto skip_children;
3610 	} else if (cur->children != NULL) {
3611 	    if ((cur->children->type != XML_ENTITY_DECL) &&
3612 		(cur->children->type != XML_ENTITY_REF_NODE) &&
3613 		(cur->children->type != XML_ENTITY_NODE)) {
3614 		cur = cur->children;
3615 		continue;
3616 	    }
3617 	}
3618 
3619 skip_children:
3620 	if (cur->next != NULL) {
3621 	    cur = cur->next;
3622 	    continue;
3623 	}
3624 	do {
3625 
3626 	    cur = cur->parent;
3627 	    if (cur == NULL)
3628 		break;
3629 	    if (cur == (xmlNodePtr) style->doc) {
3630 		cur = NULL;
3631 		break;
3632 	    }
3633 	    if (cur->next != NULL) {
3634 		cur = cur->next;
3635 		break;
3636 	    }
3637 	} while (cur != NULL);
3638     }
3639     if (deleteNode != NULL) {
3640 #ifdef WITH_XSLT_DEBUG_PARSING
3641 	xsltGenericDebug(xsltGenericDebugContext,
3642 	 "xsltPreprocessStylesheet: removing ignorable blank node\n");
3643 #endif
3644 	xmlUnlinkNode(deleteNode);
3645 	xmlFreeNode(deleteNode);
3646     }
3647 }
3648 #endif /* end of else XSLT_REFACTORED */
3649 
3650 /**
3651  * xsltGatherNamespaces:
3652  * @style:  the XSLT stylesheet
3653  *
3654  * Browse the stylesheet and build the namspace hash table which
3655  * will be used for XPath interpretation. If needed do a bit of normalization
3656  */
3657 
3658 static void
3659 xsltGatherNamespaces(xsltStylesheetPtr style) {
3660     xmlNodePtr cur;
3661     const xmlChar *URI;
3662 
3663     if (style == NULL)
3664         return;
3665     /*
3666      * TODO: basically if the stylesheet uses the same prefix for different
3667      *       patterns, well they may be in problem, hopefully they will get
3668      *       a warning first.
3669      */
3670     /*
3671     * TODO: Eliminate the use of the hash for XPath expressions.
3672     *   An expression should be evaluated in the context of the in-scope
3673     *   namespaces; eliminate the restriction of an XML document to contain
3674     *   no duplicate prefixes for different namespace names.
3675     *
3676     */
3677     cur = xmlDocGetRootElement(style->doc);
3678     while (cur != NULL) {
3679 	if (cur->type == XML_ELEMENT_NODE) {
3680 	    xmlNsPtr ns = cur->nsDef;
3681 	    while (ns != NULL) {
3682 		if (ns->prefix != NULL) {
3683 		    if (style->nsHash == NULL) {
3684 			style->nsHash = xmlHashCreate(10);
3685 			if (style->nsHash == NULL) {
3686 			    xsltTransformError(NULL, style, cur,
3687 		 "xsltGatherNamespaces: failed to create hash table\n");
3688 			    style->errors++;
3689 			    return;
3690 			}
3691 		    }
3692 		    URI = xmlHashLookup(style->nsHash, ns->prefix);
3693 		    if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
3694 			xsltTransformError(NULL, style, cur,
3695 	     "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
3696 			style->warnings++;
3697 		    } else if (URI == NULL) {
3698 			xmlHashUpdateEntry(style->nsHash, ns->prefix,
3699 			    (void *) ns->href, (xmlHashDeallocator)xmlFree);
3700 
3701 #ifdef WITH_XSLT_DEBUG_PARSING
3702 			xsltGenericDebug(xsltGenericDebugContext,
3703 		 "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
3704 #endif
3705 		    }
3706 		}
3707 		ns = ns->next;
3708 	    }
3709 	}
3710 
3711 	/*
3712 	 * Skip to next node
3713 	 */
3714 	if (cur->children != NULL) {
3715 	    if (cur->children->type != XML_ENTITY_DECL) {
3716 		cur = cur->children;
3717 		continue;
3718 	    }
3719 	}
3720 	if (cur->next != NULL) {
3721 	    cur = cur->next;
3722 	    continue;
3723 	}
3724 
3725 	do {
3726 	    cur = cur->parent;
3727 	    if (cur == NULL)
3728 		break;
3729 	    if (cur == (xmlNodePtr) style->doc) {
3730 		cur = NULL;
3731 		break;
3732 	    }
3733 	    if (cur->next != NULL) {
3734 		cur = cur->next;
3735 		break;
3736 	    }
3737 	} while (cur != NULL);
3738     }
3739 }
3740 
3741 #ifdef XSLT_REFACTORED
3742 
3743 static xsltStyleType
3744 xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
3745 			     xmlNodePtr node)
3746 {
3747     if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
3748 	(node->name == NULL))
3749 	return(0);
3750 
3751     if (node->name[0] == 'a') {
3752 	if (IS_XSLT_NAME(node, "apply-templates"))
3753 	    return(XSLT_FUNC_APPLYTEMPLATES);
3754 	else if (IS_XSLT_NAME(node, "attribute"))
3755 	    return(XSLT_FUNC_ATTRIBUTE);
3756 	else if (IS_XSLT_NAME(node, "apply-imports"))
3757 	    return(XSLT_FUNC_APPLYIMPORTS);
3758 	else if (IS_XSLT_NAME(node, "attribute-set"))
3759 	    return(0);
3760 
3761     } else if (node->name[0] == 'c') {
3762 	if (IS_XSLT_NAME(node, "choose"))
3763 	    return(XSLT_FUNC_CHOOSE);
3764 	else if (IS_XSLT_NAME(node, "copy"))
3765 	    return(XSLT_FUNC_COPY);
3766 	else if (IS_XSLT_NAME(node, "copy-of"))
3767 	    return(XSLT_FUNC_COPYOF);
3768 	else if (IS_XSLT_NAME(node, "call-template"))
3769 	    return(XSLT_FUNC_CALLTEMPLATE);
3770 	else if (IS_XSLT_NAME(node, "comment"))
3771 	    return(XSLT_FUNC_COMMENT);
3772 
3773     } else if (node->name[0] == 'd') {
3774 	if (IS_XSLT_NAME(node, "document"))
3775 	    return(XSLT_FUNC_DOCUMENT);
3776 	else if (IS_XSLT_NAME(node, "decimal-format"))
3777 	    return(0);
3778 
3779     } else if (node->name[0] == 'e') {
3780 	if (IS_XSLT_NAME(node, "element"))
3781 	    return(XSLT_FUNC_ELEMENT);
3782 
3783     } else if (node->name[0] == 'f') {
3784 	if (IS_XSLT_NAME(node, "for-each"))
3785 	    return(XSLT_FUNC_FOREACH);
3786 	else if (IS_XSLT_NAME(node, "fallback"))
3787 	    return(XSLT_FUNC_FALLBACK);
3788 
3789     } else if (*(node->name) == 'i') {
3790 	if (IS_XSLT_NAME(node, "if"))
3791 	    return(XSLT_FUNC_IF);
3792 	else if (IS_XSLT_NAME(node, "include"))
3793 	    return(0);
3794 	else if (IS_XSLT_NAME(node, "import"))
3795 	    return(0);
3796 
3797     } else if (*(node->name) == 'k') {
3798 	if (IS_XSLT_NAME(node, "key"))
3799 	    return(0);
3800 
3801     } else if (*(node->name) == 'm') {
3802 	if (IS_XSLT_NAME(node, "message"))
3803 	    return(XSLT_FUNC_MESSAGE);
3804 
3805     } else if (*(node->name) == 'n') {
3806 	if (IS_XSLT_NAME(node, "number"))
3807 	    return(XSLT_FUNC_NUMBER);
3808 	else if (IS_XSLT_NAME(node, "namespace-alias"))
3809 	    return(0);
3810 
3811     } else if (*(node->name) == 'o') {
3812 	if (IS_XSLT_NAME(node, "otherwise"))
3813 	    return(XSLT_FUNC_OTHERWISE);
3814 	else if (IS_XSLT_NAME(node, "output"))
3815 	    return(0);
3816 
3817     } else if (*(node->name) == 'p') {
3818 	if (IS_XSLT_NAME(node, "param"))
3819 	    return(XSLT_FUNC_PARAM);
3820 	else if (IS_XSLT_NAME(node, "processing-instruction"))
3821 	    return(XSLT_FUNC_PI);
3822 	else if (IS_XSLT_NAME(node, "preserve-space"))
3823 	    return(0);
3824 
3825     } else if (*(node->name) == 's') {
3826 	if (IS_XSLT_NAME(node, "sort"))
3827 	    return(XSLT_FUNC_SORT);
3828 	else if (IS_XSLT_NAME(node, "strip-space"))
3829 	    return(0);
3830 	else if (IS_XSLT_NAME(node, "stylesheet"))
3831 	    return(0);
3832 
3833     } else if (node->name[0] == 't') {
3834 	if (IS_XSLT_NAME(node, "text"))
3835 	    return(XSLT_FUNC_TEXT);
3836 	else if (IS_XSLT_NAME(node, "template"))
3837 	    return(0);
3838 	else if (IS_XSLT_NAME(node, "transform"))
3839 	    return(0);
3840 
3841     } else if (*(node->name) == 'v') {
3842 	if (IS_XSLT_NAME(node, "value-of"))
3843 	    return(XSLT_FUNC_VALUEOF);
3844 	else if (IS_XSLT_NAME(node, "variable"))
3845 	    return(XSLT_FUNC_VARIABLE);
3846 
3847     } else if (*(node->name) == 'w') {
3848 	if (IS_XSLT_NAME(node, "when"))
3849 	    return(XSLT_FUNC_WHEN);
3850 	if (IS_XSLT_NAME(node, "with-param"))
3851 	    return(XSLT_FUNC_WITHPARAM);
3852     }
3853     return(0);
3854 }
3855 
3856 /**
3857  * xsltParseAnyXSLTElem:
3858  *
3859  * @cctxt: the compilation context
3860  * @elem: the element node of the XSLT instruction
3861  *
3862  * Parses, validates the content models and compiles XSLT instructions.
3863  *
3864  * Returns 0 if everything's fine;
3865  *         -1 on API or internal errors.
3866  */
3867 int
3868 xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
3869 {
3870     if ((cctxt == NULL) || (elem == NULL) ||
3871 	(elem->type != XML_ELEMENT_NODE))
3872 	return(-1);
3873 
3874     elem->psvi = NULL;
3875 
3876     if (! (IS_XSLT_ELEM_FAST(elem)))
3877 	return(-1);
3878     /*
3879     * Detection of handled content of extension instructions.
3880     */
3881     if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
3882 	cctxt->inode->extContentHandled = 1;
3883     }
3884 
3885     xsltCompilerNodePush(cctxt, elem);
3886     /*
3887     * URGENT TODO: Find a way to speed up this annoying redundant
3888     *  textual node-name and namespace comparison.
3889     */
3890     if (cctxt->inode->prev->curChildType != 0)
3891 	cctxt->inode->type = cctxt->inode->prev->curChildType;
3892     else
3893 	cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem);
3894     /*
3895     * Update the in-scope namespaces if needed.
3896     */
3897     if (elem->nsDef != NULL)
3898 	cctxt->inode->inScopeNs =
3899 	    xsltCompilerBuildInScopeNsList(cctxt, elem);
3900     /*
3901     * xsltStylePreCompute():
3902     *  This will compile the information found on the current
3903     *  element's attributes. NOTE that this won't process the
3904     *  children of the instruction.
3905     */
3906     xsltStylePreCompute(cctxt->style, elem);
3907     /*
3908     * TODO: How to react on errors in xsltStylePreCompute() ?
3909     */
3910 
3911     /*
3912     * Validate the content model of the XSLT-element.
3913     */
3914     switch (cctxt->inode->type) {
3915 	case XSLT_FUNC_APPLYIMPORTS:
3916 	    /* EMPTY */
3917 	    goto empty_content;
3918 	case XSLT_FUNC_APPLYTEMPLATES:
3919 	    /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
3920 	    goto apply_templates;
3921 	case XSLT_FUNC_ATTRIBUTE:
3922 	    /* <!-- Content: template --> */
3923 	    goto sequence_constructor;
3924 	case XSLT_FUNC_CALLTEMPLATE:
3925 	    /* <!-- Content: xsl:with-param* --> */
3926 	    goto call_template;
3927 	case XSLT_FUNC_CHOOSE:
3928 	    /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
3929 	    goto choose;
3930 	case XSLT_FUNC_COMMENT:
3931 	    /* <!-- Content: template --> */
3932 	    goto sequence_constructor;
3933 	case XSLT_FUNC_COPY:
3934 	    /* <!-- Content: template --> */
3935 	    goto sequence_constructor;
3936 	case XSLT_FUNC_COPYOF:
3937 	    /* EMPTY */
3938 	    goto empty_content;
3939 	case XSLT_FUNC_DOCUMENT: /* Extra one */
3940 	    /* ?? template ?? */
3941 	    goto sequence_constructor;
3942 	case XSLT_FUNC_ELEMENT:
3943 	    /* <!-- Content: template --> */
3944 	    goto sequence_constructor;
3945 	case XSLT_FUNC_FALLBACK:
3946 	    /* <!-- Content: template --> */
3947 	    goto sequence_constructor;
3948 	case XSLT_FUNC_FOREACH:
3949 	    /* <!-- Content: (xsl:sort*, template) --> */
3950 	    goto for_each;
3951 	case XSLT_FUNC_IF:
3952 	    /* <!-- Content: template --> */
3953 	    goto sequence_constructor;
3954 	case XSLT_FUNC_OTHERWISE:
3955 	    /* <!-- Content: template --> */
3956 	    goto sequence_constructor;
3957 	case XSLT_FUNC_MESSAGE:
3958 	    /* <!-- Content: template --> */
3959 	    goto sequence_constructor;
3960 	case XSLT_FUNC_NUMBER:
3961 	    /* EMPTY */
3962 	    goto empty_content;
3963 	case XSLT_FUNC_PARAM:
3964 	    /*
3965 	    * Check for redefinition.
3966 	    */
3967 	    if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
3968 		xsltVarInfoPtr ivar = cctxt->ivar;
3969 
3970 		do {
3971 		    if ((ivar->name ==
3972 			 ((xsltStyleItemParamPtr) elem->psvi)->name) &&
3973 			(ivar->nsName ==
3974 			 ((xsltStyleItemParamPtr) elem->psvi)->ns))
3975 		    {
3976 			elem->psvi = NULL;
3977 			xsltTransformError(NULL, cctxt->style, elem,
3978 			    "Redefinition of variable or parameter '%s'.\n",
3979 			    ivar->name);
3980 			cctxt->style->errors++;
3981 			goto error;
3982 		    }
3983 		    ivar = ivar->prev;
3984 		} while (ivar != NULL);
3985 	    }
3986 	    /*  <!-- Content: template --> */
3987 	    goto sequence_constructor;
3988 	case XSLT_FUNC_PI:
3989 	    /*  <!-- Content: template --> */
3990 	    goto sequence_constructor;
3991 	case XSLT_FUNC_SORT:
3992 	    /* EMPTY */
3993 	    goto empty_content;
3994 	case XSLT_FUNC_TEXT:
3995 	    /* <!-- Content: #PCDATA --> */
3996 	    goto text;
3997 	case XSLT_FUNC_VALUEOF:
3998 	    /* EMPTY */
3999 	    goto empty_content;
4000 	case XSLT_FUNC_VARIABLE:
4001 	    /*
4002 	    * Check for redefinition.
4003 	    */
4004 	    if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
4005 		xsltVarInfoPtr ivar = cctxt->ivar;
4006 
4007 		do {
4008 		    if ((ivar->name ==
4009 			 ((xsltStyleItemVariablePtr) elem->psvi)->name) &&
4010 			(ivar->nsName ==
4011 			 ((xsltStyleItemVariablePtr) elem->psvi)->ns))
4012 		    {
4013 			elem->psvi = NULL;
4014 			xsltTransformError(NULL, cctxt->style, elem,
4015 			    "Redefinition of variable or parameter '%s'.\n",
4016 			    ivar->name);
4017 			cctxt->style->errors++;
4018 			goto error;
4019 		    }
4020 		    ivar = ivar->prev;
4021 		} while (ivar != NULL);
4022 	    }
4023 	    /* <!-- Content: template --> */
4024 	    goto sequence_constructor;
4025 	case XSLT_FUNC_WHEN:
4026 	    /* <!-- Content: template --> */
4027 	    goto sequence_constructor;
4028 	case XSLT_FUNC_WITHPARAM:
4029 	    /* <!-- Content: template --> */
4030 	    goto sequence_constructor;
4031 	default:
4032 #ifdef WITH_XSLT_DEBUG_PARSING
4033 	    xsltGenericDebug(xsltGenericDebugContext,
4034 		"xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
4035 		elem->name);
4036 #endif
4037 	    xsltTransformError(NULL, cctxt->style, elem,
4038 		"xsltParseXSLTNode: Internal error; "
4039 		"unhandled XSLT element '%s'.\n", elem->name);
4040 	    cctxt->style->errors++;
4041 	    goto internal_err;
4042     }
4043 
4044 apply_templates:
4045     /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
4046     if (elem->children != NULL) {
4047 	xmlNodePtr child = elem->children;
4048 	do {
4049 	    if (child->type == XML_ELEMENT_NODE) {
4050 		if (IS_XSLT_ELEM_FAST(child)) {
4051 		    if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
4052 			cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4053 			xsltParseAnyXSLTElem(cctxt, child);
4054 		    } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
4055 			cctxt->inode->curChildType = XSLT_FUNC_SORT;
4056 			xsltParseAnyXSLTElem(cctxt, child);
4057 		    } else
4058 			xsltParseContentError(cctxt->style, child);
4059 		} else
4060 		    xsltParseContentError(cctxt->style, child);
4061 	    }
4062 	    child = child->next;
4063 	} while (child != NULL);
4064     }
4065     goto exit;
4066 
4067 call_template:
4068     /* <!-- Content: xsl:with-param* --> */
4069     if (elem->children != NULL) {
4070 	xmlNodePtr child = elem->children;
4071 	do {
4072 	    if (child->type == XML_ELEMENT_NODE) {
4073 		if (IS_XSLT_ELEM_FAST(child)) {
4074 		    xsltStyleType type;
4075 
4076 		    type = xsltGetXSLTElementTypeByNode(cctxt, child);
4077 		    if (type == XSLT_FUNC_WITHPARAM) {
4078 			cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4079 			xsltParseAnyXSLTElem(cctxt, child);
4080 		    } else {
4081 			xsltParseContentError(cctxt->style, child);
4082 		    }
4083 		} else
4084 		    xsltParseContentError(cctxt->style, child);
4085 	    }
4086 	    child = child->next;
4087 	} while (child != NULL);
4088     }
4089     goto exit;
4090 
4091 text:
4092     if (elem->children != NULL) {
4093 	xmlNodePtr child = elem->children;
4094 	do {
4095 	    if ((child->type != XML_TEXT_NODE) &&
4096 		(child->type != XML_CDATA_SECTION_NODE))
4097 	    {
4098 		xsltTransformError(NULL, cctxt->style, elem,
4099 		    "The XSLT 'text' element must have only character "
4100 		    "data as content.\n");
4101 	    }
4102 	    child = child->next;
4103 	} while (child != NULL);
4104     }
4105     goto exit;
4106 
4107 empty_content:
4108     if (elem->children != NULL) {
4109 	xmlNodePtr child = elem->children;
4110 	/*
4111 	* Relaxed behaviour: we will allow whitespace-only text-nodes.
4112 	*/
4113 	do {
4114 	    if (((child->type != XML_TEXT_NODE) &&
4115 		 (child->type != XML_CDATA_SECTION_NODE)) ||
4116 		(! IS_BLANK_NODE(child)))
4117 	    {
4118 		xsltTransformError(NULL, cctxt->style, elem,
4119 		    "This XSLT element must have no content.\n");
4120 		cctxt->style->errors++;
4121 		break;
4122 	    }
4123 	    child = child->next;
4124 	} while (child != NULL);
4125     }
4126     goto exit;
4127 
4128 choose:
4129     /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
4130     /*
4131     * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
4132     *   The old behaviour did not check this.
4133     * NOTE: In XSLT 2.0 they are stripped beforehand
4134     *  if whitespace-only (regardless of xml:space).
4135     */
4136     if (elem->children != NULL) {
4137 	xmlNodePtr child = elem->children;
4138 	int nbWhen = 0, nbOtherwise = 0, err = 0;
4139 	do {
4140 	    if (child->type == XML_ELEMENT_NODE) {
4141 		if (IS_XSLT_ELEM_FAST(child)) {
4142 		    xsltStyleType type;
4143 
4144 		    type = xsltGetXSLTElementTypeByNode(cctxt, child);
4145 		    if (type == XSLT_FUNC_WHEN) {
4146 			nbWhen++;
4147 			if (nbOtherwise) {
4148 			    xsltParseContentError(cctxt->style, child);
4149 			    err = 1;
4150 			    break;
4151 			}
4152 			cctxt->inode->curChildType = XSLT_FUNC_WHEN;
4153 			xsltParseAnyXSLTElem(cctxt, child);
4154 		    } else if (type == XSLT_FUNC_OTHERWISE) {
4155 			if (! nbWhen) {
4156 			    xsltParseContentError(cctxt->style, child);
4157 			    err = 1;
4158 			    break;
4159 			}
4160 			if (nbOtherwise) {
4161 			    xsltTransformError(NULL, cctxt->style, elem,
4162 				"The XSLT 'choose' element must not contain "
4163 				"more than one XSLT 'otherwise' element.\n");
4164 			    cctxt->style->errors++;
4165 			    err = 1;
4166 			    break;
4167 			}
4168 			nbOtherwise++;
4169 			cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;
4170 			xsltParseAnyXSLTElem(cctxt, child);
4171 		    } else
4172 			xsltParseContentError(cctxt->style, child);
4173 		} else
4174 		    xsltParseContentError(cctxt->style, child);
4175 	    }
4176 	    /*
4177 		else
4178 		    xsltParseContentError(cctxt, child);
4179 	    */
4180 	    child = child->next;
4181 	} while (child != NULL);
4182 	if ((! err) && (! nbWhen)) {
4183 	    xsltTransformError(NULL, cctxt->style, elem,
4184 		"The XSLT element 'choose' must contain at least one "
4185 		"XSLT element 'when'.\n");
4186 		cctxt->style->errors++;
4187 	}
4188     }
4189     goto exit;
4190 
4191 for_each:
4192     /* <!-- Content: (xsl:sort*, template) --> */
4193     /*
4194     * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
4195     *   The old behaviour did not allow this, but it catched this
4196     *   only at transformation-time.
4197     *   In XSLT 2.0 they are stripped beforehand if whitespace-only
4198     *   (regardless of xml:space).
4199     */
4200     if (elem->children != NULL) {
4201 	xmlNodePtr child = elem->children;
4202 	/*
4203 	* Parse xsl:sort first.
4204 	*/
4205 	do {
4206 	    if ((child->type == XML_ELEMENT_NODE) &&
4207 		IS_XSLT_ELEM_FAST(child))
4208 	    {
4209 		if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
4210 		    XSLT_FUNC_SORT)
4211 		{
4212 		    cctxt->inode->curChildType = XSLT_FUNC_SORT;
4213 		    xsltParseAnyXSLTElem(cctxt, child);
4214 		} else
4215 		    break;
4216 	    } else
4217 		break;
4218 	    child = child->next;
4219 	} while (child != NULL);
4220 	/*
4221 	* Parse the sequece constructor.
4222 	*/
4223 	if (child != NULL)
4224 	    xsltParseSequenceConstructor(cctxt, child);
4225     }
4226     goto exit;
4227 
4228 sequence_constructor:
4229     /*
4230     * Parse the sequence constructor.
4231     */
4232     if (elem->children != NULL)
4233 	xsltParseSequenceConstructor(cctxt, elem->children);
4234 
4235     /*
4236     * Register information for vars/params. Only needed if there
4237     * are any following siblings.
4238     */
4239     if ((elem->next != NULL) &&
4240 	((cctxt->inode->type == XSLT_FUNC_VARIABLE) ||
4241 	 (cctxt->inode->type == XSLT_FUNC_PARAM)))
4242     {
4243 	if ((elem->psvi != NULL) &&
4244 	    (((xsltStyleBasicItemVariablePtr) elem->psvi)->name))
4245 	{
4246 	    xsltCompilerVarInfoPush(cctxt, elem,
4247 		((xsltStyleBasicItemVariablePtr) elem->psvi)->name,
4248 		((xsltStyleBasicItemVariablePtr) elem->psvi)->ns);
4249 	}
4250     }
4251 
4252 error:
4253 exit:
4254     xsltCompilerNodePop(cctxt, elem);
4255     return(0);
4256 
4257 internal_err:
4258     xsltCompilerNodePop(cctxt, elem);
4259     return(-1);
4260 }
4261 
4262 /**
4263  * xsltForwardsCompatUnkownItemCreate:
4264  *
4265  * @cctxt: the compilation context
4266  *
4267  * Creates a compiled representation of the unknown
4268  * XSLT instruction.
4269  *
4270  * Returns the compiled representation.
4271  */
4272 static xsltStyleItemUknownPtr
4273 xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
4274 {
4275     xsltStyleItemUknownPtr item;
4276 
4277     item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
4278     if (item == NULL) {
4279 	xsltTransformError(NULL, cctxt->style, NULL,
4280 	    "Internal error in xsltForwardsCompatUnkownItemCreate(): "
4281 	    "Failed to allocate memory.\n");
4282 	cctxt->style->errors++;
4283 	return(NULL);
4284     }
4285     memset(item, 0, sizeof(xsltStyleItemUknown));
4286     item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
4287     /*
4288     * Store it in the stylesheet.
4289     */
4290     item->next = cctxt->style->preComps;
4291     cctxt->style->preComps = (xsltElemPreCompPtr) item;
4292     return(item);
4293 }
4294 
4295 /**
4296  * xsltParseUnknownXSLTElem:
4297  *
4298  * @cctxt: the compilation context
4299  * @node: the element of the unknown XSLT instruction
4300  *
4301  * Parses an unknown XSLT element.
4302  * If forwards compatible mode is enabled this will allow
4303  * such an unknown XSLT and; otherwise it is rejected.
4304  *
4305  * Returns 1 in the unknown XSLT instruction is rejected,
4306  *         0 if everything's fine and
4307  *         -1 on API or internal errors.
4308  */
4309 static int
4310 xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
4311 			    xmlNodePtr node)
4312 {
4313     if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
4314 	return(-1);
4315 
4316     /*
4317     * Detection of handled content of extension instructions.
4318     */
4319     if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4320 	cctxt->inode->extContentHandled = 1;
4321     }
4322     if (cctxt->inode->forwardsCompat == 0) {
4323 	/*
4324 	* We are not in forwards-compatible mode, so raise an error.
4325 	*/
4326 	xsltTransformError(NULL, cctxt->style, node,
4327 	    "Unknown XSLT element '%s'.\n", node->name);
4328 	cctxt->style->errors++;
4329 	return(1);
4330     }
4331     /*
4332     * Forwards-compatible mode.
4333     * ------------------------
4334     *
4335     * Parse/compile xsl:fallback elements.
4336     *
4337     * QUESTION: Do we have to raise an error if there's no xsl:fallback?
4338     * ANSWER: No, since in the stylesheet the fallback behaviour might
4339     *  also be provided by using the XSLT function "element-available".
4340     */
4341     if (cctxt->unknownItem == NULL) {
4342 	/*
4343 	* Create a singleton for all unknown XSLT instructions.
4344 	*/
4345 	cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
4346 	if (cctxt->unknownItem == NULL) {
4347 	    node->psvi = NULL;
4348 	    return(-1);
4349 	}
4350     }
4351     node->psvi = cctxt->unknownItem;
4352     if (node->children == NULL)
4353 	return(0);
4354     else {
4355 	xmlNodePtr child = node->children;
4356 
4357 	xsltCompilerNodePush(cctxt, node);
4358 	/*
4359 	* Update the in-scope namespaces if needed.
4360 	*/
4361 	if (node->nsDef != NULL)
4362 	    cctxt->inode->inScopeNs =
4363 		xsltCompilerBuildInScopeNsList(cctxt, node);
4364 	/*
4365 	* Parse all xsl:fallback children.
4366 	*/
4367 	do {
4368 	    if ((child->type == XML_ELEMENT_NODE) &&
4369 		IS_XSLT_ELEM_FAST(child) &&
4370 		IS_XSLT_NAME(child, "fallback"))
4371 	    {
4372 		cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
4373 		xsltParseAnyXSLTElem(cctxt, child);
4374 	    }
4375 	    child = child->next;
4376 	} while (child != NULL);
4377 
4378 	xsltCompilerNodePop(cctxt, node);
4379     }
4380     return(0);
4381 }
4382 
4383 /**
4384  * xsltParseSequenceConstructor:
4385  *
4386  * @cctxt: the compilation context
4387  * @cur: the start-node of the content to be parsed
4388  *
4389  * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
4390  * This will additionally remove xsl:text elements from the tree.
4391  */
4392 void
4393 xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
4394 {
4395     xsltStyleType type;
4396     xmlNodePtr deleteNode = NULL;
4397 
4398     if (cctxt == NULL) {
4399 	xmlGenericError(xmlGenericErrorContext,
4400 	    "xsltParseSequenceConstructor: Bad arguments\n");
4401 	cctxt->style->errors++;
4402 	return;
4403     }
4404     /*
4405     * Detection of handled content of extension instructions.
4406     */
4407     if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4408 	cctxt->inode->extContentHandled = 1;
4409     }
4410     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
4411 	return;
4412     /*
4413     * This is the content reffered to as a "template".
4414     * E.g. an xsl:element has such content model:
4415     * <xsl:element
4416     *   name = { qname }
4417     *   namespace = { uri-reference }
4418     *   use-attribute-sets = qnames>
4419     * <!-- Content: template -->
4420     *
4421     * NOTE that in XSLT-2 the term "template" was abandoned due to
4422     *  confusion with xsl:template and the term "sequence constructor"
4423     *  was introduced instead.
4424     *
4425     * The following XSLT-instructions are allowed to appear:
4426     *  xsl:apply-templates, xsl:call-template, xsl:apply-imports,
4427     *  xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
4428     *  xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
4429     *  xsl:message, xsl:fallback,
4430     *  xsl:processing-instruction, xsl:comment, xsl:element
4431     *  xsl:attribute.
4432     * Additional allowed content:
4433     * 1) extension instructions
4434     * 2) literal result elements
4435     * 3) PCDATA
4436     *
4437     * NOTE that this content model does *not* allow xsl:param.
4438     */
4439     while (cur != NULL) {
4440 	if (deleteNode != NULL)	{
4441 #ifdef WITH_XSLT_DEBUG_BLANKS
4442 	    xsltGenericDebug(xsltGenericDebugContext,
4443 	     "xsltParseSequenceConstructor: removing xsl:text element\n");
4444 #endif
4445 	    xmlUnlinkNode(deleteNode);
4446 	    xmlFreeNode(deleteNode);
4447 	    deleteNode = NULL;
4448 	}
4449 	if (cur->type == XML_ELEMENT_NODE) {
4450 
4451 	    if (cur->psvi == xsltXSLTTextMarker) {
4452 		/*
4453 		* xsl:text elements
4454 		* --------------------------------------------------------
4455 		*/
4456 		xmlNodePtr tmp;
4457 
4458 		cur->psvi = NULL;
4459 		/*
4460 		* Mark the xsl:text element for later deletion.
4461 		*/
4462 		deleteNode = cur;
4463 		/*
4464 		* Validate content.
4465 		*/
4466 		tmp = cur->children;
4467 		if (tmp) {
4468 		    /*
4469 		    * We don't expect more than one text-node in the
4470 		    * content, since we already merged adjacent
4471 		    * text/CDATA-nodes and eliminated PI/comment-nodes.
4472 		    */
4473 		    if ((tmp->type == XML_TEXT_NODE) ||
4474 			(tmp->next == NULL))
4475 		    {
4476 			/*
4477 			* Leave the contained text-node in the tree.
4478 			*/
4479 			xmlUnlinkNode(tmp);
4480 			xmlAddPrevSibling(cur, tmp);
4481 		    } else {
4482 			tmp = NULL;
4483 			xsltTransformError(NULL, cctxt->style, cur,
4484 			    "Element 'xsl:text': Invalid type "
4485 			    "of node found in content.\n");
4486 			cctxt->style->errors++;
4487 		    }
4488 		}
4489 		if (cur->properties) {
4490 		    xmlAttrPtr attr;
4491 		    /*
4492 		    * TODO: We need to report errors for
4493 		    *  invalid attrs.
4494 		    */
4495 		    attr = cur->properties;
4496 		    do {
4497 			if ((attr->ns == NULL) &&
4498 			    (attr->name != NULL) &&
4499 			    (attr->name[0] == 'd') &&
4500 			    xmlStrEqual(attr->name,
4501 			    BAD_CAST "disable-output-escaping"))
4502 			{
4503 			    /*
4504 			    * Attr "disable-output-escaping".
4505 			    * XSLT-2: This attribute is deprecated.
4506 			    */
4507 			    if ((attr->children != NULL) &&
4508 				xmlStrEqual(attr->children->content,
4509 				BAD_CAST "yes"))
4510 			    {
4511 				/*
4512 				* Disable output escaping for this
4513 				* text node.
4514 				*/
4515 				if (tmp)
4516 				    tmp->name = xmlStringTextNoenc;
4517 			    } else if ((attr->children == NULL) ||
4518 				(attr->children->content == NULL) ||
4519 				(!xmlStrEqual(attr->children->content,
4520 				BAD_CAST "no")))
4521 			    {
4522 				xsltTransformError(NULL, cctxt->style,
4523 				    cur,
4524 				    "Attribute 'disable-output-escaping': "
4525 				    "Invalid value. Expected is "
4526 				    "'yes' or 'no'.\n");
4527 				cctxt->style->errors++;
4528 			    }
4529 			    break;
4530 			}
4531 			attr = attr->next;
4532 		    } while (attr != NULL);
4533 		}
4534 	    } else if (IS_XSLT_ELEM_FAST(cur)) {
4535 		/*
4536 		* TODO: Using the XSLT-marker is still not stable yet.
4537 		*/
4538 		/* if (cur->psvi == xsltXSLTElemMarker) { */
4539 		/*
4540 		* XSLT instructions
4541 		* --------------------------------------------------------
4542 		*/
4543 		cur->psvi = NULL;
4544 		type = xsltGetXSLTElementTypeByNode(cctxt, cur);
4545 		switch (type) {
4546 		    case XSLT_FUNC_APPLYIMPORTS:
4547 		    case XSLT_FUNC_APPLYTEMPLATES:
4548 		    case XSLT_FUNC_ATTRIBUTE:
4549 		    case XSLT_FUNC_CALLTEMPLATE:
4550 		    case XSLT_FUNC_CHOOSE:
4551 		    case XSLT_FUNC_COMMENT:
4552 		    case XSLT_FUNC_COPY:
4553 		    case XSLT_FUNC_COPYOF:
4554 		    case XSLT_FUNC_DOCUMENT: /* Extra one */
4555 		    case XSLT_FUNC_ELEMENT:
4556 		    case XSLT_FUNC_FALLBACK:
4557 		    case XSLT_FUNC_FOREACH:
4558 		    case XSLT_FUNC_IF:
4559 		    case XSLT_FUNC_MESSAGE:
4560 		    case XSLT_FUNC_NUMBER:
4561 		    case XSLT_FUNC_PI:
4562 		    case XSLT_FUNC_TEXT:
4563 		    case XSLT_FUNC_VALUEOF:
4564 		    case XSLT_FUNC_VARIABLE:
4565 			/*
4566 			* Parse the XSLT element.
4567 			*/
4568 			cctxt->inode->curChildType = type;
4569 			xsltParseAnyXSLTElem(cctxt, cur);
4570 			break;
4571 		    default:
4572 			xsltParseUnknownXSLTElem(cctxt, cur);
4573 			cur = cur->next;
4574 			continue;
4575 		}
4576 	    } else {
4577 		/*
4578 		* Non-XSLT elements
4579 		* -----------------
4580 		*/
4581 		xsltCompilerNodePush(cctxt, cur);
4582 		/*
4583 		* Update the in-scope namespaces if needed.
4584 		*/
4585 		if (cur->nsDef != NULL)
4586 		    cctxt->inode->inScopeNs =
4587 			xsltCompilerBuildInScopeNsList(cctxt, cur);
4588 		/*
4589 		* The current element is either a literal result element
4590 		* or an extension instruction.
4591 		*
4592 		* Process attr "xsl:extension-element-prefixes".
4593 		* FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
4594 		* processed by the implementor of the extension function;
4595 		* i.e., it won't be handled by the XSLT processor.
4596 		*/
4597 		/* SPEC 1.0:
4598 		*   "exclude-result-prefixes" is only allowed on literal
4599 		*   result elements and "xsl:exclude-result-prefixes"
4600 		*   on xsl:stylesheet/xsl:transform.
4601 		* SPEC 2.0:
4602 		*   "There are a number of standard attributes
4603 		*   that may appear on any XSLT element: specifically
4604 		*   version, exclude-result-prefixes,
4605 		*   extension-element-prefixes, xpath-default-namespace,
4606 		*   default-collation, and use-when."
4607 		*
4608 		* SPEC 2.0:
4609 		*   For literal result elements:
4610 		*   "xsl:version, xsl:exclude-result-prefixes,
4611 		*    xsl:extension-element-prefixes,
4612 		*    xsl:xpath-default-namespace,
4613 		*    xsl:default-collation, or xsl:use-when."
4614 		*/
4615 		if (cur->properties)
4616 		    cctxt->inode->extElemNs =
4617 			xsltParseExtElemPrefixes(cctxt,
4618 			    cur, cctxt->inode->extElemNs,
4619 			    XSLT_ELEMENT_CATEGORY_LRE);
4620 		/*
4621 		* Eval if we have an extension instruction here.
4622 		*/
4623 		if ((cur->ns != NULL) &&
4624 		    (cctxt->inode->extElemNs != NULL) &&
4625 		    (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
4626 		{
4627 		    /*
4628 		    * Extension instructions
4629 		    * ----------------------------------------------------
4630 		    * Mark the node information.
4631 		    */
4632 		    cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
4633 		    cctxt->inode->extContentHandled = 0;
4634 		    if (cur->psvi != NULL) {
4635 			cur->psvi = NULL;
4636 			/*
4637 			* TODO: Temporary sanity check.
4638 			*/
4639 			xsltTransformError(NULL, cctxt->style, cur,
4640 			    "Internal error in xsltParseSequenceConstructor(): "
4641 			    "Occupied PSVI field.\n");
4642 			cctxt->style->errors++;
4643 			cur = cur->next;
4644 			continue;
4645 		    }
4646 		    cur->psvi = (void *)
4647 			xsltPreComputeExtModuleElement(cctxt->style, cur);
4648 
4649 		    if (cur->psvi == NULL) {
4650 			/*
4651 			* OLD COMMENT: "Unknown element, maybe registered
4652 			*  at the context level. Mark it for later
4653 			*  recognition."
4654 			* QUESTION: What does the xsltExtMarker mean?
4655 			*  ANSWER: It is used in
4656 			*   xsltApplySequenceConstructor() at
4657 			*   transformation-time to look out for extension
4658 			*   registered in the transformation context.
4659 			*/
4660 			cur->psvi = (void *) xsltExtMarker;
4661 		    }
4662 		    /*
4663 		    * BIG NOTE: Now the ugly part. In previous versions
4664 		    *  of Libxslt (until 1.1.16), all the content of an
4665 		    *  extension instruction was processed and compiled without
4666 		    *  the need of the extension-author to explicitely call
4667 		    *  such a processing;.We now need to mimic this old
4668 		    *  behaviour in order to avoid breaking old code
4669 		    *  on the extension-author's side.
4670 		    * The mechanism:
4671 		    *  1) If the author does *not* set the
4672 		    *    compile-time-flag @extContentHandled, then we'll
4673 		    *    parse the content assuming that it's a "template"
4674 		    *    (or "sequence constructor in XSLT 2.0 terms).
4675 		    *    NOTE: If the extension is registered at
4676 		    *    transformation-time only, then there's no way of
4677 		    *    knowing that content shall be valid, and we'll
4678 		    *    process the content the same way.
4679 		    *  2) If the author *does* set the flag, then we'll assume
4680 		    *   that the author has handled the parsing him/herself
4681 		    *   (e.g. called xsltParseSequenceConstructor(), etc.
4682 		    *   explicitely in his/her code).
4683 		    */
4684 		    if ((cur->children != NULL) &&
4685 			(cctxt->inode->extContentHandled == 0))
4686 		    {
4687 			/*
4688 			* Default parsing of the content using the
4689 			* sequence-constructor model.
4690 			*/
4691 			xsltParseSequenceConstructor(cctxt, cur->children);
4692 		    }
4693 		} else {
4694 		    /*
4695 		    * Literal result element
4696 		    * ----------------------------------------------------
4697 		    * Allowed XSLT attributes:
4698 		    *  xsl:extension-element-prefixes CDATA #IMPLIED
4699 		    *  xsl:exclude-result-prefixes CDATA #IMPLIED
4700 		    *  TODO: xsl:use-attribute-sets %qnames; #IMPLIED
4701 		    *  xsl:version NMTOKEN #IMPLIED
4702 		    */
4703 		    cur->psvi = NULL;
4704 		    cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
4705 		    if (cur->properties != NULL) {
4706 			xmlAttrPtr attr = cur->properties;
4707 			/*
4708 			* Attribute "xsl:exclude-result-prefixes".
4709 			*/
4710 			cctxt->inode->exclResultNs =
4711 			    xsltParseExclResultPrefixes(cctxt, cur,
4712 				cctxt->inode->exclResultNs,
4713 				XSLT_ELEMENT_CATEGORY_LRE);
4714 			/*
4715 			* Attribute "xsl:version".
4716 			*/
4717 			xsltParseAttrXSLTVersion(cctxt, cur,
4718 			    XSLT_ELEMENT_CATEGORY_LRE);
4719 			/*
4720 			* Report invalid XSLT attributes.
4721 			* For XSLT 1.0 only xsl:use-attribute-sets is allowed
4722 			* next to xsl:version, xsl:exclude-result-prefixes and
4723 			* xsl:extension-element-prefixes.
4724 			*
4725 			* Mark all XSLT attributes, in order to skip such
4726 			* attributes when instantiating the LRE.
4727 			*/
4728 			do {
4729 			    if ((attr->psvi != xsltXSLTAttrMarker) &&
4730 				IS_XSLT_ATTR_FAST(attr))
4731 			    {
4732 				if (! xmlStrEqual(attr->name,
4733 				    BAD_CAST "use-attribute-sets"))
4734 				{
4735 				    xsltTransformError(NULL, cctxt->style,
4736 					cur,
4737 					"Unknown XSLT attribute '%s'.\n",
4738 					attr->name);
4739 				    cctxt->style->errors++;
4740 				} else {
4741 				    /*
4742 				    * XSLT attr marker.
4743 				    */
4744 				    attr->psvi = (void *) xsltXSLTAttrMarker;
4745 				}
4746 			    }
4747 			    attr = attr->next;
4748 			} while (attr != NULL);
4749 		    }
4750 		    /*
4751 		    * Create/reuse info for the literal result element.
4752 		    */
4753 		    if (cctxt->inode->nsChanged)
4754 			xsltLREInfoCreate(cctxt, cur, 1);
4755 		    cur->psvi = cctxt->inode->litResElemInfo;
4756 		    /*
4757 		    * Apply ns-aliasing on the element and on its attributes.
4758 		    */
4759 		    if (cctxt->hasNsAliases)
4760 			xsltLREBuildEffectiveNs(cctxt, cur);
4761 		    /*
4762 		    * Compile attribute value templates (AVT).
4763 		    */
4764 		    if (cur->properties) {
4765 			xmlAttrPtr attr = cur->properties;
4766 
4767 			while (attr != NULL) {
4768 			    xsltCompileAttr(cctxt->style, attr);
4769 			    attr = attr->next;
4770 			}
4771 		    }
4772 		    /*
4773 		    * Parse the content, which is defined to be a "template"
4774 		    * (or "sequence constructor" in XSLT 2.0 terms).
4775 		    */
4776 		    if (cur->children != NULL) {
4777 			xsltParseSequenceConstructor(cctxt, cur->children);
4778 		    }
4779 		}
4780 		/*
4781 		* Leave the non-XSLT element.
4782 		*/
4783 		xsltCompilerNodePop(cctxt, cur);
4784 	    }
4785 	}
4786 	cur = cur->next;
4787     }
4788     if (deleteNode != NULL) {
4789 #ifdef WITH_XSLT_DEBUG_BLANKS
4790 	xsltGenericDebug(xsltGenericDebugContext,
4791 	    "xsltParseSequenceConstructor: removing xsl:text element\n");
4792 #endif
4793 	xmlUnlinkNode(deleteNode);
4794 	xmlFreeNode(deleteNode);
4795 	deleteNode = NULL;
4796     }
4797 }
4798 
4799 /**
4800  * xsltParseTemplateContent:
4801  * @style:  the XSLT stylesheet
4802  * @templ:  the node containing the content to be parsed
4803  *
4804  * Parses and compiles the content-model of an xsl:template element.
4805  * Note that this is *not* the "template" content model (or "sequence
4806  *  constructor" in XSLT 2.0); it it allows addional xsl:param
4807  *  elements as immediate children of @templ.
4808  *
4809  * Called by:
4810  *   exsltFuncFunctionComp() (EXSLT, functions.c)
4811  *   So this is intended to be called from extension functions.
4812  */
4813 void
4814 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
4815     if ((style == NULL) || (templ == NULL) ||
4816         (templ->type == XML_NAMESPACE_DECL))
4817 	return;
4818 
4819     /*
4820     * Detection of handled content of extension instructions.
4821     */
4822     if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4823 	XSLT_CCTXT(style)->inode->extContentHandled = 1;
4824     }
4825 
4826     if (templ->children != NULL) {
4827 	xmlNodePtr child = templ->children;
4828 	/*
4829 	* Process xsl:param elements, which can only occur as the
4830 	* immediate children of xsl:template (well, and of any
4831 	* user-defined extension instruction if needed).
4832 	*/
4833 	do {
4834 	    if ((child->type == XML_ELEMENT_NODE) &&
4835 		IS_XSLT_ELEM_FAST(child) &&
4836 		IS_XSLT_NAME(child, "param"))
4837 	    {
4838 		XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
4839 		xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
4840 	    } else
4841 		break;
4842 	    child = child->next;
4843 	} while (child != NULL);
4844 	/*
4845 	* Parse the content and register the pattern.
4846 	*/
4847 	xsltParseSequenceConstructor(XSLT_CCTXT(style), child);
4848     }
4849 }
4850 
4851 #else /* XSLT_REFACTORED */
4852 
4853 /**
4854  * xsltParseTemplateContent:
4855  * @style:  the XSLT stylesheet
4856  * @templ:  the container node (can be a document for literal results)
4857  *
4858  * parse a template content-model
4859  * Clean-up the template content from unwanted ignorable blank nodes
4860  * and process xslt:text
4861  */
4862 void
4863 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
4864     xmlNodePtr cur, delete;
4865 
4866     if ((style == NULL) || (templ == NULL) ||
4867         (templ->type == XML_NAMESPACE_DECL)) return;
4868 
4869     /*
4870      * This content comes from the stylesheet
4871      * For stylesheets, the set of whitespace-preserving
4872      * element names consists of just xsl:text.
4873      */
4874     cur = templ->children;
4875     delete = NULL;
4876     while (cur != NULL) {
4877 	if (delete != NULL) {
4878 #ifdef WITH_XSLT_DEBUG_BLANKS
4879 	    xsltGenericDebug(xsltGenericDebugContext,
4880 	     "xsltParseTemplateContent: removing text\n");
4881 #endif
4882 	    xmlUnlinkNode(delete);
4883 	    xmlFreeNode(delete);
4884 	    delete = NULL;
4885 	}
4886 	if (IS_XSLT_ELEM(cur)) {
4887             xsltStylePreCompute(style, cur);
4888 
4889 	    if (IS_XSLT_NAME(cur, "text")) {
4890 		/*
4891 		* TODO: Processing of xsl:text should be moved to
4892 		*   xsltPreprocessStylesheet(), since otherwise this
4893 		*   will be performed for every multiply included
4894 		*   stylesheet; i.e. this here is not skipped with
4895 		*   the use of the style->nopreproc flag.
4896 		*/
4897 		if (cur->children != NULL) {
4898 		    xmlChar *prop;
4899 		    xmlNodePtr text = cur->children, next;
4900 		    int noesc = 0;
4901 
4902 		    prop = xmlGetNsProp(cur,
4903 			(const xmlChar *)"disable-output-escaping",
4904 			NULL);
4905 		    if (prop != NULL) {
4906 #ifdef WITH_XSLT_DEBUG_PARSING
4907 			xsltGenericDebug(xsltGenericDebugContext,
4908 			     "Disable escaping: %s\n", text->content);
4909 #endif
4910 			if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
4911 			    noesc = 1;
4912 			} else if (!xmlStrEqual(prop,
4913 						(const xmlChar *)"no")){
4914 			    xsltTransformError(NULL, style, cur,
4915 	     "xsl:text: disable-output-escaping allows only yes or no\n");
4916 			    style->warnings++;
4917 
4918 			}
4919 			xmlFree(prop);
4920 		    }
4921 
4922 		    while (text != NULL) {
4923 			if (text->type == XML_COMMENT_NODE) {
4924 			    text = text->next;
4925 			    continue;
4926 			}
4927 			if ((text->type != XML_TEXT_NODE) &&
4928 			     (text->type != XML_CDATA_SECTION_NODE)) {
4929 			    xsltTransformError(NULL, style, cur,
4930 		 "xsltParseTemplateContent: xslt:text content problem\n");
4931 			    style->errors++;
4932 			    break;
4933 			}
4934 			if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
4935 			    text->name = xmlStringTextNoenc;
4936 			text = text->next;
4937 		    }
4938 
4939 		    /*
4940 		     * replace xsl:text by the list of childs
4941 		     */
4942 		    if (text == NULL) {
4943 			text = cur->children;
4944 			while (text != NULL) {
4945 			    if ((style->internalized) &&
4946 			        (text->content != NULL) &&
4947 			        (!xmlDictOwns(style->dict, text->content))) {
4948 
4949 				/*
4950 				 * internalize the text string
4951 				 */
4952 				if (text->doc->dict != NULL) {
4953 				    const xmlChar *tmp;
4954 
4955 				    tmp = xmlDictLookup(text->doc->dict,
4956 				                        text->content, -1);
4957 				    if (tmp != text->content) {
4958 				        xmlNodeSetContent(text, NULL);
4959 					text->content = (xmlChar *) tmp;
4960 				    }
4961 				}
4962 			    }
4963 
4964 			    next = text->next;
4965 			    xmlUnlinkNode(text);
4966 			    xmlAddPrevSibling(cur, text);
4967 			    text = next;
4968 			}
4969 		    }
4970 		}
4971 		delete = cur;
4972 		goto skip_children;
4973 	    }
4974 	}
4975 	else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
4976 	    (xsltCheckExtPrefix(style, cur->ns->prefix)))
4977 	{
4978 	    /*
4979 	     * okay this is an extension element compile it too
4980 	     */
4981 	    xsltStylePreCompute(style, cur);
4982 	}
4983 	else if (cur->type == XML_ELEMENT_NODE)
4984 	{
4985 	    /*
4986 	     * This is an element which will be output as part of the
4987 	     * template exectution, precompile AVT if found.
4988 	     */
4989 	    if ((cur->ns == NULL) && (style->defaultAlias != NULL)) {
4990 		cur->ns = xmlSearchNsByHref(cur->doc, cur,
4991 			style->defaultAlias);
4992 	    }
4993 	    if (cur->properties != NULL) {
4994 	        xmlAttrPtr attr = cur->properties;
4995 
4996 		while (attr != NULL) {
4997 		    xsltCompileAttr(style, attr);
4998 		    attr = attr->next;
4999 		}
5000 	    }
5001 	}
5002 	/*
5003 	 * Skip to next node
5004 	 */
5005 	if (cur->children != NULL) {
5006 	    if (cur->children->type != XML_ENTITY_DECL) {
5007 		cur = cur->children;
5008 		continue;
5009 	    }
5010 	}
5011 skip_children:
5012 	if (cur->next != NULL) {
5013 	    cur = cur->next;
5014 	    continue;
5015 	}
5016 
5017 	do {
5018 	    cur = cur->parent;
5019 	    if (cur == NULL)
5020 		break;
5021 	    if (cur == templ) {
5022 		cur = NULL;
5023 		break;
5024 	    }
5025 	    if (cur->next != NULL) {
5026 		cur = cur->next;
5027 		break;
5028 	    }
5029 	} while (cur != NULL);
5030     }
5031     if (delete != NULL) {
5032 #ifdef WITH_XSLT_DEBUG_PARSING
5033 	xsltGenericDebug(xsltGenericDebugContext,
5034 	 "xsltParseTemplateContent: removing text\n");
5035 #endif
5036 	xmlUnlinkNode(delete);
5037 	xmlFreeNode(delete);
5038 	delete = NULL;
5039     }
5040 
5041     /*
5042      * Skip the first params
5043      */
5044     cur = templ->children;
5045     while (cur != NULL) {
5046 	if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
5047 	    break;
5048 	cur = cur->next;
5049     }
5050 
5051     /*
5052      * Browse the remainder of the template
5053      */
5054     while (cur != NULL) {
5055 	if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
5056 	    xmlNodePtr param = cur;
5057 
5058 	    xsltTransformError(NULL, style, cur,
5059 		"xsltParseTemplateContent: ignoring misplaced param element\n");
5060 	    if (style != NULL) style->warnings++;
5061             cur = cur->next;
5062 	    xmlUnlinkNode(param);
5063 	    xmlFreeNode(param);
5064 	} else
5065 	    break;
5066     }
5067 }
5068 
5069 #endif /* else XSLT_REFACTORED */
5070 
5071 /**
5072  * xsltParseStylesheetKey:
5073  * @style:  the XSLT stylesheet
5074  * @key:  the "key" element
5075  *
5076  * <!-- Category: top-level-element -->
5077  * <xsl:key name = qname, match = pattern, use = expression />
5078  *
5079  * parse an XSLT stylesheet key definition and register it
5080  */
5081 
5082 static void
5083 xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
5084     xmlChar *prop = NULL;
5085     xmlChar *use = NULL;
5086     xmlChar *match = NULL;
5087     xmlChar *name = NULL;
5088     xmlChar *nameURI = NULL;
5089 
5090     if ((style == NULL) || (key == NULL) || (key->type != XML_ELEMENT_NODE))
5091 	return;
5092 
5093     /*
5094      * Get arguments
5095      */
5096     prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
5097     if (prop != NULL) {
5098         const xmlChar *URI;
5099 
5100 	/*
5101 	* TODO: Don't use xsltGetQNameURI().
5102 	*/
5103 	URI = xsltGetQNameURI(key, &prop);
5104 	if (prop == NULL) {
5105 	    if (style != NULL) style->errors++;
5106 	    goto error;
5107 	} else {
5108 	    name = prop;
5109 	    if (URI != NULL)
5110 		nameURI = xmlStrdup(URI);
5111 	}
5112 #ifdef WITH_XSLT_DEBUG_PARSING
5113 	xsltGenericDebug(xsltGenericDebugContext,
5114 	     "xsltParseStylesheetKey: name %s\n", name);
5115 #endif
5116     } else {
5117 	xsltTransformError(NULL, style, key,
5118 	    "xsl:key : error missing name\n");
5119 	if (style != NULL) style->errors++;
5120 	goto error;
5121     }
5122 
5123     match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
5124     if (match == NULL) {
5125 	xsltTransformError(NULL, style, key,
5126 	    "xsl:key : error missing match\n");
5127 	if (style != NULL) style->errors++;
5128 	goto error;
5129     }
5130 
5131     use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
5132     if (use == NULL) {
5133 	xsltTransformError(NULL, style, key,
5134 	    "xsl:key : error missing use\n");
5135 	if (style != NULL) style->errors++;
5136 	goto error;
5137     }
5138 
5139     /*
5140      * register the keys
5141      */
5142     xsltAddKey(style, name, nameURI, match, use, key);
5143 
5144 
5145 error:
5146     if (use != NULL)
5147 	xmlFree(use);
5148     if (match != NULL)
5149 	xmlFree(match);
5150     if (name != NULL)
5151 	xmlFree(name);
5152     if (nameURI != NULL)
5153 	xmlFree(nameURI);
5154 
5155     if (key->children != NULL) {
5156 	xsltParseContentError(style, key->children);
5157     }
5158 }
5159 
5160 #ifdef XSLT_REFACTORED
5161 /**
5162  * xsltParseXSLTTemplate:
5163  * @style:  the XSLT stylesheet
5164  * @template:  the "template" element
5165  *
5166  * parse an XSLT stylesheet template building the associated structures
5167  * TODO: Is @style ever expected to be NULL?
5168  *
5169  * Called from:
5170  *   xsltParseXSLTStylesheet()
5171  *   xsltParseStylesheetTop()
5172  */
5173 
5174 static void
5175 xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
5176     xsltTemplatePtr templ;
5177     xmlChar *prop;
5178     double  priority;
5179 
5180     if ((cctxt == NULL) || (templNode == NULL) ||
5181         (templNode->type != XML_ELEMENT_NODE))
5182 	return;
5183 
5184     /*
5185      * Create and link the structure
5186      */
5187     templ = xsltNewTemplate();
5188     if (templ == NULL)
5189 	return;
5190 
5191     xsltCompilerNodePush(cctxt, templNode);
5192     if (templNode->nsDef != NULL)
5193 	cctxt->inode->inScopeNs =
5194 	    xsltCompilerBuildInScopeNsList(cctxt, templNode);
5195 
5196     templ->next = cctxt->style->templates;
5197     cctxt->style->templates = templ;
5198     templ->style = cctxt->style;
5199 
5200     /*
5201     * Attribute "mode".
5202     */
5203     prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);
5204     if (prop != NULL) {
5205         const xmlChar *modeURI;
5206 
5207 	/*
5208 	* TODO: We need a standardized function for extraction
5209 	*  of namespace names and local names from QNames.
5210 	*  Don't use xsltGetQNameURI() as it cannot channe�
5211 	*  reports through the context.
5212 	*/
5213 	modeURI = xsltGetQNameURI(templNode, &prop);
5214 	if (prop == NULL) {
5215 	    cctxt->style->errors++;
5216 	    goto error;
5217 	}
5218 	templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);
5219 	xmlFree(prop);
5220 	prop = NULL;
5221 	if (xmlValidateNCName(templ->mode, 0)) {
5222 	    xsltTransformError(NULL, cctxt->style, templNode,
5223 		"xsl:template: Attribute 'mode': The local part '%s' "
5224 		"of the value is not a valid NCName.\n", templ->name);
5225 	    cctxt->style->errors++;
5226 	    goto error;
5227 	}
5228 	if (modeURI != NULL)
5229 	    templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);
5230 #ifdef WITH_XSLT_DEBUG_PARSING
5231 	xsltGenericDebug(xsltGenericDebugContext,
5232 	     "xsltParseXSLTTemplate: mode %s\n", templ->mode);
5233 #endif
5234     }
5235     /*
5236     * Attribute "match".
5237     */
5238     prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);
5239     if (prop != NULL) {
5240 	templ->match  = prop;
5241 	prop = NULL;
5242     }
5243     /*
5244     * Attribute "priority".
5245     */
5246     prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);
5247     if (prop != NULL) {
5248 	priority = xmlXPathStringEvalNumber(prop);
5249 	templ->priority = (float) priority;
5250 	xmlFree(prop);
5251 	prop = NULL;
5252     }
5253     /*
5254     * Attribute "name".
5255     */
5256     prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);
5257     if (prop != NULL) {
5258         const xmlChar *nameURI;
5259 	xsltTemplatePtr curTempl;
5260 
5261 	/*
5262 	* TODO: Don't use xsltGetQNameURI().
5263 	*/
5264 	nameURI = xsltGetQNameURI(templNode, &prop);
5265 	if (prop == NULL) {
5266 	    cctxt->style->errors++;
5267 	    goto error;
5268 	}
5269 	templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);
5270 	xmlFree(prop);
5271 	prop = NULL;
5272 	if (xmlValidateNCName(templ->name, 0)) {
5273 	    xsltTransformError(NULL, cctxt->style, templNode,
5274 		"xsl:template: Attribute 'name': The local part '%s' of "
5275 		"the value is not a valid NCName.\n", templ->name);
5276 	    cctxt->style->errors++;
5277 	    goto error;
5278 	}
5279 	if (nameURI != NULL)
5280 	    templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);
5281 	curTempl = templ->next;
5282 	while (curTempl != NULL) {
5283 	    if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&
5284 		xmlStrEqual(curTempl->nameURI, nameURI) ) ||
5285 		(nameURI == NULL && curTempl->nameURI == NULL &&
5286 		xmlStrEqual(curTempl->name, templ->name)))
5287 	    {
5288 		xsltTransformError(NULL, cctxt->style, templNode,
5289 		    "xsl:template: error duplicate name '%s'\n", templ->name);
5290 		cctxt->style->errors++;
5291 		goto error;
5292 	    }
5293 	    curTempl = curTempl->next;
5294 	}
5295     }
5296     if (templNode->children != NULL) {
5297 	xsltParseTemplateContent(cctxt->style, templNode);
5298 	/*
5299 	* MAYBE TODO: Custom behaviour: In order to stay compatible with
5300 	* Xalan and MSXML(.NET), we could allow whitespace
5301 	* to appear before an xml:param element; this whitespace
5302 	* will additionally become part of the "template".
5303 	* NOTE that this is totally deviates from the spec, but
5304 	* is the de facto behaviour of Xalan and MSXML(.NET).
5305 	* Personally I wouldn't allow this, since if we have:
5306 	* <xsl:template ...xml:space="preserve">
5307 	*   <xsl:param name="foo"/>
5308 	*   <xsl:param name="bar"/>
5309 	*   <xsl:param name="zoo"/>
5310 	* ... the whitespace between every xsl:param would be
5311 	* added to the result tree.
5312 	*/
5313     }
5314 
5315     templ->elem = templNode;
5316     templ->content = templNode->children;
5317     xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI);
5318 
5319 error:
5320     xsltCompilerNodePop(cctxt, templNode);
5321     return;
5322 }
5323 
5324 #else /* XSLT_REFACTORED */
5325 
5326 /**
5327  * xsltParseStylesheetTemplate:
5328  * @style:  the XSLT stylesheet
5329  * @template:  the "template" element
5330  *
5331  * parse an XSLT stylesheet template building the associated structures
5332  */
5333 
5334 static void
5335 xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
5336     xsltTemplatePtr ret;
5337     xmlChar *prop;
5338     xmlChar *mode = NULL;
5339     xmlChar *modeURI = NULL;
5340     double  priority;
5341 
5342     if ((style == NULL) || (template == NULL) ||
5343         (template->type != XML_ELEMENT_NODE))
5344 	return;
5345 
5346     /*
5347      * Create and link the structure
5348      */
5349     ret = xsltNewTemplate();
5350     if (ret == NULL)
5351 	return;
5352     ret->next = style->templates;
5353     style->templates = ret;
5354     ret->style = style;
5355 
5356     /*
5357      * Get inherited namespaces
5358      */
5359     /*
5360     * TODO: Apply the optimized in-scope-namespace mechanism
5361     *   as for the other XSLT instructions.
5362     */
5363     xsltGetInheritedNsList(style, ret, template);
5364 
5365     /*
5366      * Get arguments
5367      */
5368     prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);
5369     if (prop != NULL) {
5370         const xmlChar *URI;
5371 
5372 	/*
5373 	* TODO: Don't use xsltGetQNameURI().
5374 	*/
5375 	URI = xsltGetQNameURI(template, &prop);
5376 	if (prop == NULL) {
5377 	    if (style != NULL) style->errors++;
5378 	    goto error;
5379 	} else {
5380 	    mode = prop;
5381 	    if (URI != NULL)
5382 		modeURI = xmlStrdup(URI);
5383 	}
5384 	ret->mode = xmlDictLookup(style->dict, mode, -1);
5385 	ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);
5386 #ifdef WITH_XSLT_DEBUG_PARSING
5387 	xsltGenericDebug(xsltGenericDebugContext,
5388 	     "xsltParseStylesheetTemplate: mode %s\n", mode);
5389 #endif
5390         if (mode != NULL) xmlFree(mode);
5391 	if (modeURI != NULL) xmlFree(modeURI);
5392     }
5393     prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);
5394     if (prop != NULL) {
5395 	if (ret->match != NULL) xmlFree(ret->match);
5396 	ret->match  = prop;
5397     }
5398 
5399     prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);
5400     if (prop != NULL) {
5401 	priority = xmlXPathStringEvalNumber(prop);
5402 	ret->priority = (float) priority;
5403 	xmlFree(prop);
5404     }
5405 
5406     prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);
5407     if (prop != NULL) {
5408         const xmlChar *URI;
5409 
5410 	/*
5411 	* TODO: Don't use xsltGetQNameURI().
5412 	*/
5413 	URI = xsltGetQNameURI(template, &prop);
5414 	if (prop == NULL) {
5415 	    if (style != NULL) style->errors++;
5416 	    goto error;
5417 	} else {
5418 	    if (xmlValidateNCName(prop,0)) {
5419 	        xsltTransformError(NULL, style, template,
5420 	            "xsl:template : error invalid name '%s'\n", prop);
5421 		if (style != NULL) style->errors++;
5422                 xmlFree(prop);
5423 		goto error;
5424 	    }
5425 	    ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
5426 	    xmlFree(prop);
5427 	    prop = NULL;
5428 	    if (URI != NULL)
5429 		ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);
5430 	    else
5431 		ret->nameURI = NULL;
5432 	}
5433     }
5434 
5435     /*
5436      * parse the content and register the pattern
5437      */
5438     xsltParseTemplateContent(style, template);
5439     ret->elem = template;
5440     ret->content = template->children;
5441     xsltAddTemplate(style, ret, ret->mode, ret->modeURI);
5442 
5443 error:
5444     return;
5445 }
5446 
5447 #endif /* else XSLT_REFACTORED */
5448 
5449 #ifdef XSLT_REFACTORED
5450 
5451 /**
5452  * xsltIncludeComp:
5453  * @cctxt: the compilation contenxt
5454  * @node:  the xsl:include node
5455  *
5456  * Process the xslt include node on the source node
5457  */
5458 static xsltStyleItemIncludePtr
5459 xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) {
5460     xsltStyleItemIncludePtr item;
5461 
5462     if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
5463 	return(NULL);
5464 
5465     node->psvi = NULL;
5466     item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude));
5467     if (item == NULL) {
5468 	xsltTransformError(NULL, cctxt->style, node,
5469 		"xsltIncludeComp : malloc failed\n");
5470 	cctxt->style->errors++;
5471 	return(NULL);
5472     }
5473     memset(item, 0, sizeof(xsltStyleItemInclude));
5474 
5475     node->psvi = item;
5476     item->inst = node;
5477     item->type = XSLT_FUNC_INCLUDE;
5478 
5479     item->next = cctxt->style->preComps;
5480     cctxt->style->preComps = (xsltElemPreCompPtr) item;
5481 
5482     return(item);
5483 }
5484 
5485 /**
5486  * xsltParseFindTopLevelElem:
5487  */
5488 static int
5489 xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,
5490 			      xmlNodePtr cur,
5491 			      const xmlChar *name,
5492 			      const xmlChar *namespaceURI,
5493 			      int breakOnOtherElem,
5494 			      xmlNodePtr *resultNode)
5495 {
5496     if (name == NULL)
5497 	return(-1);
5498 
5499     *resultNode = NULL;
5500     while (cur != NULL) {
5501 	if (cur->type == XML_ELEMENT_NODE) {
5502 	    if ((cur->ns != NULL) && (cur->name != NULL)) {
5503 		if ((*(cur->name) == *name) &&
5504 		    xmlStrEqual(cur->name, name) &&
5505 		    xmlStrEqual(cur->ns->href, namespaceURI))
5506 		{
5507 		    *resultNode = cur;
5508 		    return(1);
5509 		}
5510 	    }
5511 	    if (breakOnOtherElem)
5512 		break;
5513 	}
5514 	cur = cur->next;
5515     }
5516     *resultNode = cur;
5517     return(0);
5518 }
5519 
5520 static int
5521 xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,
5522 			  xmlNodePtr node,
5523 			  xsltStyleType type)
5524 {
5525     int ret = 0;
5526 
5527     /*
5528     * TODO: The reason why this function exists:
5529     *  due to historical reasons some of the
5530     *  top-level declarations are processed by functions
5531     *  in other files. Since we need still to set
5532     *  up the node-info and generate information like
5533     *  in-scope namespaces, this is a wrapper around
5534     *  those old parsing functions.
5535     */
5536     xsltCompilerNodePush(cctxt, node);
5537     if (node->nsDef != NULL)
5538 	cctxt->inode->inScopeNs =
5539 	    xsltCompilerBuildInScopeNsList(cctxt, node);
5540     cctxt->inode->type = type;
5541 
5542     switch (type) {
5543 	case XSLT_FUNC_INCLUDE:
5544 	    {
5545 		int oldIsInclude;
5546 
5547 		if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL)
5548 		    goto exit;
5549 		/*
5550 		* Mark this stylesheet tree as being currently included.
5551 		*/
5552 		oldIsInclude = cctxt->isInclude;
5553 		cctxt->isInclude = 1;
5554 
5555 		if (xsltParseStylesheetInclude(cctxt->style, node) != 0) {
5556 		    cctxt->style->errors++;
5557 		}
5558 		cctxt->isInclude = oldIsInclude;
5559 	    }
5560 	    break;
5561 	case XSLT_FUNC_PARAM:
5562 	    xsltStylePreCompute(cctxt->style, node);
5563 	    xsltParseGlobalParam(cctxt->style, node);
5564 	    break;
5565 	case XSLT_FUNC_VARIABLE:
5566 	    xsltStylePreCompute(cctxt->style, node);
5567 	    xsltParseGlobalVariable(cctxt->style, node);
5568 	    break;
5569 	case XSLT_FUNC_ATTRSET:
5570 	    xsltParseStylesheetAttributeSet(cctxt->style, node);
5571 	    break;
5572 	default:
5573 	    xsltTransformError(NULL, cctxt->style, node,
5574 		"Internal error: (xsltParseTopLevelXSLTElem) "
5575 		"Cannot handle this top-level declaration.\n");
5576 	    cctxt->style->errors++;
5577 	    ret = -1;
5578     }
5579 
5580 exit:
5581     xsltCompilerNodePop(cctxt, node);
5582 
5583     return(ret);
5584 }
5585 
5586 #if 0
5587 static int
5588 xsltParseRemoveWhitespace(xmlNodePtr node)
5589 {
5590     if ((node == NULL) || (node->children == NULL))
5591 	return(0);
5592     else {
5593 	xmlNodePtr delNode = NULL, child = node->children;
5594 
5595 	do {
5596 	    if (delNode) {
5597 		xmlUnlinkNode(delNode);
5598 		xmlFreeNode(delNode);
5599 		delNode = NULL;
5600 	    }
5601 	    if (((child->type == XML_TEXT_NODE) ||
5602 		 (child->type == XML_CDATA_SECTION_NODE)) &&
5603 		(IS_BLANK_NODE(child)))
5604 		delNode = child;
5605 	    child = child->next;
5606 	} while (child != NULL);
5607 	if (delNode) {
5608 	    xmlUnlinkNode(delNode);
5609 	    xmlFreeNode(delNode);
5610 	    delNode = NULL;
5611 	}
5612     }
5613     return(0);
5614 }
5615 #endif
5616 
5617 static int
5618 xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
5619 {
5620 #ifdef WITH_XSLT_DEBUG_PARSING
5621     int templates = 0;
5622 #endif
5623     xmlNodePtr cur, start = NULL;
5624     xsltStylesheetPtr style;
5625 
5626     if ((cctxt == NULL) || (node == NULL) ||
5627 	(node->type != XML_ELEMENT_NODE))
5628 	return(-1);
5629 
5630     style = cctxt->style;
5631     /*
5632     * At this stage all import declarations of all stylesheet modules
5633     * with the same stylesheet level have been processed.
5634     * Now we can safely parse the rest of the declarations.
5635     */
5636     if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include"))
5637     {
5638 	xsltDocumentPtr include;
5639 	/*
5640 	* URGENT TODO: Make this work with simplified stylesheets!
5641 	*   I.e., when we won't find an xsl:stylesheet element.
5642 	*/
5643 	/*
5644 	* This is as include declaration.
5645 	*/
5646 	include = ((xsltStyleItemIncludePtr) node->psvi)->include;
5647 	if (include == NULL) {
5648 	    /* TODO: raise error? */
5649 	    return(-1);
5650 	}
5651 	/*
5652 	* TODO: Actually an xsl:include should locate an embedded
5653 	*  stylesheet as well; so the document-element won't always
5654 	*  be the element where the actual stylesheet is rooted at.
5655 	*  But such embedded stylesheets are not supported by Libxslt yet.
5656 	*/
5657 	node = xmlDocGetRootElement(include->doc);
5658 	if (node == NULL) {
5659 	    return(-1);
5660 	}
5661     }
5662 
5663     if (node->children == NULL)
5664 	return(0);
5665     /*
5666     * Push the xsl:stylesheet/xsl:transform element.
5667     */
5668     xsltCompilerNodePush(cctxt, node);
5669     cctxt->inode->isRoot = 1;
5670     cctxt->inode->nsChanged = 0;
5671     /*
5672     * Start with the naked dummy info for literal result elements.
5673     */
5674     cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;
5675 
5676     /*
5677     * In every case, we need to have
5678     * the in-scope namespaces of the element, where the
5679     * stylesheet is rooted at, regardless if it's an XSLT
5680     * instruction or a literal result instruction (or if
5681     * this is an embedded stylesheet).
5682     */
5683     cctxt->inode->inScopeNs =
5684 	xsltCompilerBuildInScopeNsList(cctxt, node);
5685 
5686     /*
5687     * Process attributes of xsl:stylesheet/xsl:transform.
5688     * --------------------------------------------------
5689     * Allowed are:
5690     *  id = id
5691     *  extension-element-prefixes = tokens
5692     *  exclude-result-prefixes = tokens
5693     *  version = number (mandatory)
5694     */
5695     if (xsltParseAttrXSLTVersion(cctxt, node,
5696 	XSLT_ELEMENT_CATEGORY_XSLT) == 0)
5697     {
5698 	/*
5699 	* Attribute "version".
5700 	* XSLT 1.0: "An xsl:stylesheet element *must* have a version
5701 	*  attribute, indicating the version of XSLT that the
5702 	*  stylesheet requires".
5703 	* The root element of a simplified stylesheet must also have
5704 	* this attribute.
5705 	*/
5706 #ifdef XSLT_REFACTORED_MANDATORY_VERSION
5707 	if (isXsltElem)
5708 	    xsltTransformError(NULL, cctxt->style, node,
5709 		"The attribute 'version' is missing.\n");
5710 	cctxt->style->errors++;
5711 #else
5712 	/* OLD behaviour. */
5713 	xsltTransformError(NULL, cctxt->style, node,
5714 	    "xsl:version is missing: document may not be a stylesheet\n");
5715 	cctxt->style->warnings++;
5716 #endif
5717     }
5718     /*
5719     * The namespaces declared by the attributes
5720     *  "extension-element-prefixes" and
5721     *  "exclude-result-prefixes" are local to *this*
5722     *  stylesheet tree; i.e., they are *not* visible to
5723     *  other stylesheet-modules, whether imported or included.
5724     *
5725     * Attribute "extension-element-prefixes".
5726     */
5727     cctxt->inode->extElemNs =
5728 	xsltParseExtElemPrefixes(cctxt, node, NULL,
5729 	    XSLT_ELEMENT_CATEGORY_XSLT);
5730     /*
5731     * Attribute "exclude-result-prefixes".
5732     */
5733     cctxt->inode->exclResultNs =
5734 	xsltParseExclResultPrefixes(cctxt, node, NULL,
5735 	    XSLT_ELEMENT_CATEGORY_XSLT);
5736     /*
5737     * Create/reuse info for the literal result element.
5738     */
5739     if (cctxt->inode->nsChanged)
5740 	xsltLREInfoCreate(cctxt, node, 0);
5741     /*
5742     * Processed top-level elements:
5743     * ----------------------------
5744     *  xsl:variable, xsl:param (QName, in-scope ns,
5745     *    expression (vars allowed))
5746     *  xsl:attribute-set (QName, in-scope ns)
5747     *  xsl:strip-space, xsl:preserve-space (XPath NameTests,
5748     *    in-scope ns)
5749     *    I *think* global scope, merge with includes
5750     *  xsl:output (QName, in-scope ns)
5751     *  xsl:key (QName, in-scope ns, pattern,
5752     *    expression (vars *not* allowed))
5753     *  xsl:decimal-format (QName, needs in-scope ns)
5754     *  xsl:namespace-alias (in-scope ns)
5755     *    global scope, merge with includes
5756     *  xsl:template (last, QName, pattern)
5757     *
5758     * (whitespace-only text-nodes have *not* been removed
5759     *  yet; this will be done in xsltParseSequenceConstructor)
5760     *
5761     * Report misplaced child-nodes first.
5762     */
5763     cur = node->children;
5764     while (cur != NULL) {
5765 	if (cur->type == XML_TEXT_NODE) {
5766 	    xsltTransformError(NULL, style, cur,
5767 		"Misplaced text node (content: '%s').\n",
5768 		(cur->content != NULL) ? cur->content : BAD_CAST "");
5769 	    style->errors++;
5770 	} else if (cur->type != XML_ELEMENT_NODE) {
5771 	    xsltTransformError(NULL, style, cur, "Misplaced node.\n");
5772 	    style->errors++;
5773 	}
5774 	cur = cur->next;
5775     }
5776     /*
5777     * Skip xsl:import elements; they have been processed
5778     * already.
5779     */
5780     cur = node->children;
5781     while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur,
5782 	    BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
5783 	cur = cur->next;
5784     if (cur == NULL)
5785 	goto exit;
5786 
5787     start = cur;
5788     /*
5789     * Process all top-level xsl:param elements.
5790     */
5791     while ((cur != NULL) &&
5792 	xsltParseFindTopLevelElem(cctxt, cur,
5793 	BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1)
5794     {
5795 	xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM);
5796 	cur = cur->next;
5797     }
5798     /*
5799     * Process all top-level xsl:variable elements.
5800     */
5801     cur = start;
5802     while ((cur != NULL) &&
5803 	xsltParseFindTopLevelElem(cctxt, cur,
5804 	BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1)
5805     {
5806 	xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE);
5807 	cur = cur->next;
5808     }
5809     /*
5810     * Process all the rest of top-level elements.
5811     */
5812     cur = start;
5813     while (cur != NULL) {
5814 	/*
5815 	* Process element nodes.
5816 	*/
5817 	if (cur->type == XML_ELEMENT_NODE) {
5818 	    if (cur->ns == NULL) {
5819 		xsltTransformError(NULL, style, cur,
5820 		    "Unexpected top-level element in no namespace.\n");
5821 		style->errors++;
5822 		cur = cur->next;
5823 		continue;
5824 	    }
5825 	    /*
5826 	    * Process all XSLT elements.
5827 	    */
5828 	    if (IS_XSLT_ELEM_FAST(cur)) {
5829 		/*
5830 		* xsl:import is only allowed at the beginning.
5831 		*/
5832 		if (IS_XSLT_NAME(cur, "import")) {
5833 		    xsltTransformError(NULL, style, cur,
5834 			"Misplaced xsl:import element.\n");
5835 		    style->errors++;
5836 		    cur = cur->next;
5837 		    continue;
5838 		}
5839 		/*
5840 		* TODO: Change the return type of the parsing functions
5841 		*  to int.
5842 		*/
5843 		if (IS_XSLT_NAME(cur, "template")) {
5844 #ifdef WITH_XSLT_DEBUG_PARSING
5845 		    templates++;
5846 #endif
5847 		    /*
5848 		    * TODO: Is the position of xsl:template in the
5849 		    *  tree significant? If not it would be easier to
5850 		    *  parse them at a later stage.
5851 		    */
5852 		    xsltParseXSLTTemplate(cctxt, cur);
5853 		} else if (IS_XSLT_NAME(cur, "variable")) {
5854 		    /* NOP; done already */
5855 		} else if (IS_XSLT_NAME(cur, "param")) {
5856 		    /* NOP; done already */
5857 		} else if (IS_XSLT_NAME(cur, "include")) {
5858 		    if (cur->psvi != NULL)
5859 			xsltParseXSLTStylesheetElemCore(cctxt, cur);
5860 		    else {
5861 			xsltTransformError(NULL, style, cur,
5862 			    "Internal error: "
5863 			    "(xsltParseXSLTStylesheetElemCore) "
5864 			    "The xsl:include element was not compiled.\n");
5865 			style->errors++;
5866 		    }
5867 		} else if (IS_XSLT_NAME(cur, "strip-space")) {
5868 		    /* No node info needed. */
5869 		    xsltParseStylesheetStripSpace(style, cur);
5870 		} else if (IS_XSLT_NAME(cur, "preserve-space")) {
5871 		    /* No node info needed. */
5872 		    xsltParseStylesheetPreserveSpace(style, cur);
5873 		} else if (IS_XSLT_NAME(cur, "output")) {
5874 		    /* No node-info needed. */
5875 		    xsltParseStylesheetOutput(style, cur);
5876 		} else if (IS_XSLT_NAME(cur, "key")) {
5877 		    /* TODO: node-info needed for expressions ? */
5878 		    xsltParseStylesheetKey(style, cur);
5879 		} else if (IS_XSLT_NAME(cur, "decimal-format")) {
5880 		    /* No node-info needed. */
5881 		    xsltParseStylesheetDecimalFormat(style, cur);
5882 		} else if (IS_XSLT_NAME(cur, "attribute-set")) {
5883 		    xsltParseTopLevelXSLTElem(cctxt, cur,
5884 			XSLT_FUNC_ATTRSET);
5885 		} else if (IS_XSLT_NAME(cur, "namespace-alias")) {
5886 		    /* NOP; done already */
5887 		} else {
5888 		    if (cctxt->inode->forwardsCompat) {
5889 			/*
5890 			* Forwards-compatible mode:
5891 			*
5892 			* XSLT-1: "if it is a top-level element and
5893 			*  XSLT 1.0 does not allow such elements as top-level
5894 			*  elements, then the element must be ignored along
5895 			*  with its content;"
5896 			*/
5897 			/*
5898 			* TODO: I don't think we should generate a warning.
5899 			*/
5900 			xsltTransformError(NULL, style, cur,
5901 			    "Forwards-compatible mode: Ignoring unknown XSLT "
5902 			    "element '%s'.\n", cur->name);
5903 			style->warnings++;
5904 		    } else {
5905 			xsltTransformError(NULL, style, cur,
5906 			    "Unknown XSLT element '%s'.\n", cur->name);
5907 			style->errors++;
5908 		    }
5909 		}
5910 	    } else {
5911 		xsltTopLevelFunction function;
5912 
5913 		/*
5914 		* Process non-XSLT elements, which are in a
5915 		*  non-NULL namespace.
5916 		*/
5917 		/*
5918 		* QUESTION: What does xsltExtModuleTopLevelLookup()
5919 		*  do exactly?
5920 		*/
5921 		function = xsltExtModuleTopLevelLookup(cur->name,
5922 		    cur->ns->href);
5923 		if (function != NULL)
5924 		    function(style, cur);
5925 #ifdef WITH_XSLT_DEBUG_PARSING
5926 		xsltGenericDebug(xsltGenericDebugContext,
5927 		    "xsltParseXSLTStylesheetElemCore : User-defined "
5928 		    "data element '%s'.\n", cur->name);
5929 #endif
5930 	    }
5931 	}
5932 	cur = cur->next;
5933     }
5934 
5935 exit:
5936 
5937 #ifdef WITH_XSLT_DEBUG_PARSING
5938     xsltGenericDebug(xsltGenericDebugContext,
5939 	"### END of parsing top-level elements of doc '%s'.\n",
5940 	node->doc->URL);
5941     xsltGenericDebug(xsltGenericDebugContext,
5942 	"### Templates: %d\n", templates);
5943 #ifdef XSLT_REFACTORED
5944     xsltGenericDebug(xsltGenericDebugContext,
5945 	"### Max inodes: %d\n", cctxt->maxNodeInfos);
5946     xsltGenericDebug(xsltGenericDebugContext,
5947 	"### Max LREs  : %d\n", cctxt->maxLREs);
5948 #endif /* XSLT_REFACTORED */
5949 #endif /* WITH_XSLT_DEBUG_PARSING */
5950 
5951     xsltCompilerNodePop(cctxt, node);
5952     return(0);
5953 }
5954 
5955 /**
5956  * xsltParseXSLTStylesheet:
5957  * @cctxt: the compiler context
5958  * @node: the xsl:stylesheet/xsl:transform element-node
5959  *
5960  * Parses the xsl:stylesheet and xsl:transform element.
5961  *
5962  * <xsl:stylesheet
5963  *  id = id
5964  *  extension-element-prefixes = tokens
5965  *  exclude-result-prefixes = tokens
5966  *  version = number>
5967  *  <!-- Content: (xsl:import*, top-level-elements) -->
5968  * </xsl:stylesheet>
5969  *
5970  * BIG TODO: The xsl:include stuff.
5971  *
5972  * Called by xsltParseStylesheetTree()
5973  *
5974  * Returns 0 on success, a positive result on errors and
5975  *         -1 on API or internal errors.
5976  */
5977 static int
5978 xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
5979 {
5980     xmlNodePtr cur, start;
5981 
5982     if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
5983 	return(-1);
5984 
5985     if (node->children == NULL)
5986 	goto exit;
5987 
5988     /*
5989     * Process top-level elements:
5990     *  xsl:import (must be first)
5991     *  xsl:include (this is just a pre-processing)
5992     */
5993     cur = node->children;
5994     /*
5995     * Process xsl:import elements.
5996     * XSLT 1.0: "The xsl:import element children must precede all
5997     *  other element children of an xsl:stylesheet element,
5998     *  including any xsl:include element children."
5999     */
6000     while ((cur != NULL) &&
6001 	xsltParseFindTopLevelElem(cctxt, cur,
6002 	    BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
6003     {
6004 	if (xsltParseStylesheetImport(cctxt->style, cur) != 0) {
6005 	    cctxt->style->errors++;
6006 	}
6007 	cur = cur->next;
6008     }
6009     if (cur == NULL)
6010 	goto exit;
6011     start = cur;
6012     /*
6013     * Pre-process all xsl:include elements.
6014     */
6015     cur = start;
6016     while ((cur != NULL) &&
6017 	xsltParseFindTopLevelElem(cctxt, cur,
6018 	    BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1)
6019     {
6020 	xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE);
6021 	cur = cur->next;
6022     }
6023     /*
6024     * Pre-process all xsl:namespace-alias elements.
6025     * URGENT TODO: This won't work correctly: the order of included
6026     *  aliases and aliases defined here is significant.
6027     */
6028     cur = start;
6029     while ((cur != NULL) &&
6030 	xsltParseFindTopLevelElem(cctxt, cur,
6031 	    BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1)
6032     {
6033 	xsltNamespaceAlias(cctxt->style, cur);
6034 	cur = cur->next;
6035     }
6036 
6037     if (cctxt->isInclude) {
6038 	/*
6039 	* If this stylesheet is intended for inclusion, then
6040 	* we will process only imports and includes.
6041 	*/
6042 	goto exit;
6043     }
6044     /*
6045     * Now parse the rest of the top-level elements.
6046     */
6047     xsltParseXSLTStylesheetElemCore(cctxt, node);
6048 exit:
6049 
6050     return(0);
6051 }
6052 
6053 #else /* XSLT_REFACTORED */
6054 
6055 /**
6056  * xsltParseStylesheetTop:
6057  * @style:  the XSLT stylesheet
6058  * @top:  the top level "stylesheet" or "transform" element
6059  *
6060  * scan the top level elements of an XSL stylesheet
6061  */
6062 static void
6063 xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
6064     xmlNodePtr cur;
6065     xmlChar *prop;
6066 #ifdef WITH_XSLT_DEBUG_PARSING
6067     int templates = 0;
6068 #endif
6069 
6070     if ((top == NULL) || (top->type != XML_ELEMENT_NODE))
6071 	return;
6072 
6073     prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL);
6074     if (prop == NULL) {
6075 	xsltTransformError(NULL, style, top,
6076 	    "xsl:version is missing: document may not be a stylesheet\n");
6077 	if (style != NULL) style->warnings++;
6078     } else {
6079 	if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
6080             (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
6081 	    xsltTransformError(NULL, style, top,
6082 		"xsl:version: only 1.1 features are supported\n");
6083 	    if (style != NULL) {
6084                 style->forwards_compatible = 1;
6085                 style->warnings++;
6086             }
6087 	}
6088 	xmlFree(prop);
6089     }
6090 
6091     /*
6092      * process xsl:import elements
6093      */
6094     cur = top->children;
6095     while (cur != NULL) {
6096 	    if (IS_BLANK_NODE(cur)) {
6097 		    cur = cur->next;
6098 		    continue;
6099 	    }
6100 	    if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
6101 		    if (xsltParseStylesheetImport(style, cur) != 0)
6102 			    if (style != NULL) style->errors++;
6103 	    } else
6104 		    break;
6105 	    cur = cur->next;
6106     }
6107 
6108     /*
6109      * process other top-level elements
6110      */
6111     while (cur != NULL) {
6112 	if (IS_BLANK_NODE(cur)) {
6113 	    cur = cur->next;
6114 	    continue;
6115 	}
6116 	if (cur->type == XML_TEXT_NODE) {
6117 	    if (cur->content != NULL) {
6118 		xsltTransformError(NULL, style, cur,
6119 		    "misplaced text node: '%s'\n", cur->content);
6120 	    }
6121 	    if (style != NULL) style->errors++;
6122             cur = cur->next;
6123 	    continue;
6124 	}
6125 	if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
6126 	    xsltGenericError(xsltGenericErrorContext,
6127 		     "Found a top-level element %s with null namespace URI\n",
6128 		     cur->name);
6129 	    if (style != NULL) style->errors++;
6130 	    cur = cur->next;
6131 	    continue;
6132 	}
6133 	if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
6134 	    xsltTopLevelFunction function;
6135 
6136 	    function = xsltExtModuleTopLevelLookup(cur->name,
6137 						   cur->ns->href);
6138 	    if (function != NULL)
6139 		function(style, cur);
6140 
6141 #ifdef WITH_XSLT_DEBUG_PARSING
6142 	    xsltGenericDebug(xsltGenericDebugContext,
6143 		    "xsltParseStylesheetTop : found foreign element %s\n",
6144 		    cur->name);
6145 #endif
6146             cur = cur->next;
6147 	    continue;
6148 	}
6149 	if (IS_XSLT_NAME(cur, "import")) {
6150 	    xsltTransformError(NULL, style, cur,
6151 			"xsltParseStylesheetTop: ignoring misplaced import element\n");
6152 	    if (style != NULL) style->errors++;
6153         } else if (IS_XSLT_NAME(cur, "include")) {
6154 	    if (xsltParseStylesheetInclude(style, cur) != 0)
6155 		if (style != NULL) style->errors++;
6156         } else if (IS_XSLT_NAME(cur, "strip-space")) {
6157 	    xsltParseStylesheetStripSpace(style, cur);
6158         } else if (IS_XSLT_NAME(cur, "preserve-space")) {
6159 	    xsltParseStylesheetPreserveSpace(style, cur);
6160         } else if (IS_XSLT_NAME(cur, "output")) {
6161 	    xsltParseStylesheetOutput(style, cur);
6162         } else if (IS_XSLT_NAME(cur, "key")) {
6163 	    xsltParseStylesheetKey(style, cur);
6164         } else if (IS_XSLT_NAME(cur, "decimal-format")) {
6165 	    xsltParseStylesheetDecimalFormat(style, cur);
6166         } else if (IS_XSLT_NAME(cur, "attribute-set")) {
6167 	    xsltParseStylesheetAttributeSet(style, cur);
6168         } else if (IS_XSLT_NAME(cur, "variable")) {
6169 	    xsltParseGlobalVariable(style, cur);
6170         } else if (IS_XSLT_NAME(cur, "param")) {
6171 	    xsltParseGlobalParam(style, cur);
6172         } else if (IS_XSLT_NAME(cur, "template")) {
6173 #ifdef WITH_XSLT_DEBUG_PARSING
6174 	    templates++;
6175 #endif
6176 	    xsltParseStylesheetTemplate(style, cur);
6177         } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
6178 	    xsltNamespaceAlias(style, cur);
6179 	} else {
6180             if ((style != NULL) && (style->forwards_compatible == 0)) {
6181 	        xsltTransformError(NULL, style, cur,
6182 			"xsltParseStylesheetTop: unknown %s element\n",
6183 			cur->name);
6184 	        if (style != NULL) style->errors++;
6185 	    }
6186 	}
6187 	cur = cur->next;
6188     }
6189 #ifdef WITH_XSLT_DEBUG_PARSING
6190     xsltGenericDebug(xsltGenericDebugContext,
6191 		    "parsed %d templates\n", templates);
6192 #endif
6193 }
6194 
6195 #endif /* else of XSLT_REFACTORED */
6196 
6197 #ifdef XSLT_REFACTORED
6198 /**
6199  * xsltParseSimplifiedStylesheetTree:
6200  *
6201  * @style: the stylesheet (TODO: Change this to the compiler context)
6202  * @doc: the document containing the stylesheet.
6203  * @node: the node where the stylesheet is rooted at
6204  *
6205  * Returns 0 in case of success, a positive result if an error occurred
6206  *         and -1 on API and internal errors.
6207  */
6208 static int
6209 xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt,
6210 				  xmlDocPtr doc,
6211 				  xmlNodePtr node)
6212 {
6213     xsltTemplatePtr templ;
6214 
6215     if ((cctxt == NULL) || (node == NULL))
6216 	return(-1);
6217 
6218     if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE)
6219     {
6220 	/*
6221 	* TODO: Adjust report, since this might be an
6222 	* embedded stylesheet.
6223 	*/
6224 	xsltTransformError(NULL, cctxt->style, node,
6225 	    "The attribute 'xsl:version' is missing; cannot identify "
6226 	    "this document as an XSLT stylesheet document.\n");
6227 	cctxt->style->errors++;
6228 	return(1);
6229     }
6230 
6231 #ifdef WITH_XSLT_DEBUG_PARSING
6232     xsltGenericDebug(xsltGenericDebugContext,
6233 	"xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
6234 #endif
6235 
6236     /*
6237     * Create and link the template
6238     */
6239     templ = xsltNewTemplate();
6240     if (templ == NULL) {
6241 	return(-1);
6242     }
6243     templ->next = cctxt->style->templates;
6244     cctxt->style->templates = templ;
6245     templ->match = xmlStrdup(BAD_CAST "/");
6246 
6247     /*
6248     * Note that we push the document-node in this special case.
6249     */
6250     xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
6251     /*
6252     * In every case, we need to have
6253     * the in-scope namespaces of the element, where the
6254     * stylesheet is rooted at, regardless if it's an XSLT
6255     * instruction or a literal result instruction (or if
6256     * this is an embedded stylesheet).
6257     */
6258     cctxt->inode->inScopeNs =
6259 	xsltCompilerBuildInScopeNsList(cctxt, node);
6260     /*
6261     * Parse the content and register the match-pattern.
6262     */
6263     xsltParseSequenceConstructor(cctxt, node);
6264     xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
6265 
6266     templ->elem = (xmlNodePtr) doc;
6267     templ->content = node;
6268     xsltAddTemplate(cctxt->style, templ, NULL, NULL);
6269     cctxt->style->literal_result = 1;
6270     return(0);
6271 }
6272 
6273 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6274 /**
6275  * xsltRestoreDocumentNamespaces:
6276  * @ns: map of namespaces
6277  * @doc: the document
6278  *
6279  * Restore the namespaces for the document
6280  *
6281  * Returns 0 in case of success, -1 in case of failure
6282  */
6283 int
6284 xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc)
6285 {
6286     if (doc == NULL)
6287 	return(-1);
6288     /*
6289     * Revert the changes we have applied to the namespace-URIs of
6290     * ns-decls.
6291     */
6292     while (ns != NULL) {
6293 	if ((ns->doc == doc) && (ns->ns != NULL)) {
6294 	    ns->ns->href = ns->origNsName;
6295 	    ns->origNsName = NULL;
6296 	    ns->ns = NULL;
6297 	}
6298 	ns = ns->next;
6299     }
6300     return(0);
6301 }
6302 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
6303 
6304 /**
6305  * xsltParseStylesheetProcess:
6306  * @style:  the XSLT stylesheet (the current stylesheet-level)
6307  * @doc:  and xmlDoc parsed XML
6308  *
6309  * Parses an XSLT stylesheet, adding the associated structures.
6310  * Called by:
6311  *  xsltParseStylesheetImportedDoc() (xslt.c)
6312  *  xsltParseStylesheetInclude() (imports.c)
6313  *
6314  * Returns the value of the @style parameter if everything
6315  * went right, NULL if something went amiss.
6316  */
6317 xsltStylesheetPtr
6318 xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc)
6319 {
6320     xsltCompilerCtxtPtr cctxt;
6321     xmlNodePtr cur;
6322     int oldIsSimplifiedStylesheet;
6323 
6324     xsltInitGlobals();
6325 
6326     if ((style == NULL) || (doc == NULL))
6327 	return(NULL);
6328 
6329     cctxt = XSLT_CCTXT(style);
6330 
6331     cur = xmlDocGetRootElement(doc);
6332     if (cur == NULL) {
6333 	xsltTransformError(NULL, style, (xmlNodePtr) doc,
6334 		"xsltParseStylesheetProcess : empty stylesheet\n");
6335 	return(NULL);
6336     }
6337     oldIsSimplifiedStylesheet = cctxt->simplified;
6338 
6339     if ((IS_XSLT_ELEM(cur)) &&
6340 	((IS_XSLT_NAME(cur, "stylesheet")) ||
6341 	 (IS_XSLT_NAME(cur, "transform")))) {
6342 #ifdef WITH_XSLT_DEBUG_PARSING
6343 	xsltGenericDebug(xsltGenericDebugContext,
6344 		"xsltParseStylesheetProcess : found stylesheet\n");
6345 #endif
6346 	cctxt->simplified = 0;
6347 	style->literal_result = 0;
6348     } else {
6349 	cctxt->simplified = 1;
6350 	style->literal_result = 1;
6351     }
6352     /*
6353     * Pre-process the stylesheet if not already done before.
6354     *  This will remove PIs and comments, merge adjacent
6355     *  text nodes, internalize strings, etc.
6356     */
6357     if (! style->nopreproc)
6358 	xsltParsePreprocessStylesheetTree(cctxt, cur);
6359     /*
6360     * Parse and compile the stylesheet.
6361     */
6362     if (style->literal_result == 0) {
6363 	if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0)
6364 	    return(NULL);
6365     } else {
6366 	if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0)
6367 	    return(NULL);
6368     }
6369 
6370     cctxt->simplified = oldIsSimplifiedStylesheet;
6371 
6372     return(style);
6373 }
6374 
6375 #else /* XSLT_REFACTORED */
6376 
6377 /**
6378  * xsltParseStylesheetProcess:
6379  * @ret:  the XSLT stylesheet (the current stylesheet-level)
6380  * @doc:  and xmlDoc parsed XML
6381  *
6382  * Parses an XSLT stylesheet, adding the associated structures.
6383  * Called by:
6384  *  xsltParseStylesheetImportedDoc() (xslt.c)
6385  *  xsltParseStylesheetInclude() (imports.c)
6386  *
6387  * Returns the value of the @style parameter if everything
6388  * went right, NULL if something went amiss.
6389  */
6390 xsltStylesheetPtr
6391 xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
6392     xmlNodePtr cur;
6393 
6394     xsltInitGlobals();
6395 
6396     if (doc == NULL)
6397 	return(NULL);
6398     if (ret == NULL)
6399 	return(ret);
6400 
6401     /*
6402      * First steps, remove blank nodes,
6403      * locate the xsl:stylesheet element and the
6404      * namespace declaration.
6405      */
6406     cur = xmlDocGetRootElement(doc);
6407     if (cur == NULL) {
6408 	xsltTransformError(NULL, ret, (xmlNodePtr) doc,
6409 		"xsltParseStylesheetProcess : empty stylesheet\n");
6410 	return(NULL);
6411     }
6412 
6413     if ((IS_XSLT_ELEM(cur)) &&
6414 	((IS_XSLT_NAME(cur, "stylesheet")) ||
6415 	 (IS_XSLT_NAME(cur, "transform")))) {
6416 #ifdef WITH_XSLT_DEBUG_PARSING
6417 	xsltGenericDebug(xsltGenericDebugContext,
6418 		"xsltParseStylesheetProcess : found stylesheet\n");
6419 #endif
6420 	ret->literal_result = 0;
6421 	xsltParseStylesheetExcludePrefix(ret, cur, 1);
6422 	xsltParseStylesheetExtPrefix(ret, cur, 1);
6423     } else {
6424 	xsltParseStylesheetExcludePrefix(ret, cur, 0);
6425 	xsltParseStylesheetExtPrefix(ret, cur, 0);
6426 	ret->literal_result = 1;
6427     }
6428     if (!ret->nopreproc) {
6429 	xsltPreprocessStylesheet(ret, cur);
6430     }
6431     if (ret->literal_result == 0) {
6432 	xsltParseStylesheetTop(ret, cur);
6433     } else {
6434 	xmlChar *prop;
6435 	xsltTemplatePtr template;
6436 
6437 	/*
6438 	 * the document itself might be the template, check xsl:version
6439 	 */
6440 	prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
6441 	if (prop == NULL) {
6442 	    xsltTransformError(NULL, ret, cur,
6443 		"xsltParseStylesheetProcess : document is not a stylesheet\n");
6444 	    return(NULL);
6445 	}
6446 
6447 #ifdef WITH_XSLT_DEBUG_PARSING
6448         xsltGenericDebug(xsltGenericDebugContext,
6449 		"xsltParseStylesheetProcess : document is stylesheet\n");
6450 #endif
6451 
6452 	if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
6453             (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
6454 	    xsltTransformError(NULL, ret, cur,
6455 		"xsl:version: only 1.1 features are supported\n");
6456             ret->forwards_compatible = 1;
6457 	    ret->warnings++;
6458 	}
6459 	xmlFree(prop);
6460 
6461 	/*
6462 	 * Create and link the template
6463 	 */
6464 	template = xsltNewTemplate();
6465 	if (template == NULL) {
6466 	    return(NULL);
6467 	}
6468 	template->next = ret->templates;
6469 	ret->templates = template;
6470 	template->match = xmlStrdup((const xmlChar *)"/");
6471 
6472 	/*
6473 	 * parse the content and register the pattern
6474 	 */
6475 	xsltParseTemplateContent(ret, (xmlNodePtr) doc);
6476 	template->elem = (xmlNodePtr) doc;
6477 	template->content = doc->children;
6478 	xsltAddTemplate(ret, template, NULL, NULL);
6479 	ret->literal_result = 1;
6480     }
6481 
6482     return(ret);
6483 }
6484 
6485 #endif /* else of XSLT_REFACTORED */
6486 
6487 /**
6488  * xsltParseStylesheetImportedDoc:
6489  * @doc:  an xmlDoc parsed XML
6490  * @parentStyle: pointer to the parent stylesheet (if it exists)
6491  *
6492  * parse an XSLT stylesheet building the associated structures
6493  * except the processing not needed for imported documents.
6494  *
6495  * Returns a new XSLT stylesheet structure.
6496  */
6497 
6498 xsltStylesheetPtr
6499 xsltParseStylesheetImportedDoc(xmlDocPtr doc,
6500 			       xsltStylesheetPtr parentStyle) {
6501     xsltStylesheetPtr retStyle;
6502 
6503     if (doc == NULL)
6504 	return(NULL);
6505 
6506     retStyle = xsltNewStylesheet();
6507     if (retStyle == NULL)
6508 	return(NULL);
6509     /*
6510     * Set the importing stylesheet module; also used to detect recursion.
6511     */
6512     retStyle->parent = parentStyle;
6513     /*
6514     * Adjust the string dict.
6515     */
6516     if (doc->dict != NULL) {
6517         xmlDictFree(retStyle->dict);
6518 	retStyle->dict = doc->dict;
6519 #ifdef WITH_XSLT_DEBUG
6520         xsltGenericDebug(xsltGenericDebugContext,
6521 	    "reusing dictionary from %s for stylesheet\n",
6522 	    doc->URL);
6523 #endif
6524 	xmlDictReference(retStyle->dict);
6525     }
6526 
6527     /*
6528     * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
6529     *  the stylesheet to containt distinct namespace prefixes.
6530     */
6531     xsltGatherNamespaces(retStyle);
6532 
6533 #ifdef XSLT_REFACTORED
6534     {
6535 	xsltCompilerCtxtPtr cctxt;
6536 	xsltStylesheetPtr oldCurSheet;
6537 
6538 	if (parentStyle == NULL) {
6539 	    xsltPrincipalStylesheetDataPtr principalData;
6540 	    /*
6541 	    * Principal stylesheet
6542 	    * --------------------
6543 	    */
6544 	    retStyle->principal = retStyle;
6545 	    /*
6546 	    * Create extra data for the principal stylesheet.
6547 	    */
6548 	    principalData = xsltNewPrincipalStylesheetData();
6549 	    if (principalData == NULL) {
6550 		xsltFreeStylesheet(retStyle);
6551 		return(NULL);
6552 	    }
6553 	    retStyle->principalData = principalData;
6554 	    /*
6555 	    * Create the compilation context
6556 	    * ------------------------------
6557 	    * (only once; for the principal stylesheet).
6558 	    * This is currently the only function where the
6559 	    * compilation context is created.
6560 	    */
6561 	    cctxt = xsltCompilationCtxtCreate(retStyle);
6562 	    if (cctxt == NULL) {
6563 		xsltFreeStylesheet(retStyle);
6564 		return(NULL);
6565 	    }
6566 	    retStyle->compCtxt = (void *) cctxt;
6567 	    cctxt->style = retStyle;
6568 	    cctxt->dict = retStyle->dict;
6569 	    cctxt->psData = principalData;
6570 	    /*
6571 	    * Push initial dummy node info.
6572 	    */
6573 	    cctxt->depth = -1;
6574 	    xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
6575 	} else {
6576 	    /*
6577 	    * Imported stylesheet.
6578 	    */
6579 	    retStyle->principal = parentStyle->principal;
6580 	    cctxt = parentStyle->compCtxt;
6581 	    retStyle->compCtxt = cctxt;
6582 	}
6583 	/*
6584 	* Save the old and set the current stylesheet structure in the
6585 	* compilation context.
6586 	*/
6587 	oldCurSheet = cctxt->style;
6588 	cctxt->style = retStyle;
6589 
6590 	retStyle->doc = doc;
6591 	xsltParseStylesheetProcess(retStyle, doc);
6592 
6593 	cctxt->style = oldCurSheet;
6594 	if (parentStyle == NULL) {
6595 	    /*
6596 	    * Pop the initial dummy node info.
6597 	    */
6598 	    xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
6599 	} else {
6600 	    /*
6601 	    * Clear the compilation context of imported
6602 	    * stylesheets.
6603 	    * TODO: really?
6604 	    */
6605 	    /* retStyle->compCtxt = NULL; */
6606 	}
6607 	/*
6608 	* Free the stylesheet if there were errors.
6609 	*/
6610 	if (retStyle != NULL) {
6611 	    if (retStyle->errors != 0) {
6612 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6613 		/*
6614 		* Restore all changes made to namespace URIs of ns-decls.
6615 		*/
6616 		if (cctxt->psData->nsMap)
6617 		    xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
6618 #endif
6619 		/*
6620 		* Detach the doc from the stylesheet; otherwise the doc
6621 		* will be freed in xsltFreeStylesheet().
6622 		*/
6623 		retStyle->doc = NULL;
6624 		/*
6625 		* Cleanup the doc if its the main stylesheet.
6626 		*/
6627 		if (parentStyle == NULL) {
6628 		    xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
6629 		    if (retStyle->compCtxt != NULL) {
6630 			xsltCompilationCtxtFree(retStyle->compCtxt);
6631 			retStyle->compCtxt = NULL;
6632 		    }
6633 		}
6634 
6635 		xsltFreeStylesheet(retStyle);
6636 		retStyle = NULL;
6637 	    }
6638 	}
6639     }
6640 
6641 #else /* XSLT_REFACTORED */
6642     /*
6643     * Old behaviour.
6644     */
6645     retStyle->doc = doc;
6646     if (xsltParseStylesheetProcess(retStyle, doc) == NULL) {
6647 		retStyle->doc = NULL;
6648 		xsltFreeStylesheet(retStyle);
6649 		retStyle = NULL;
6650     }
6651     if (retStyle != NULL) {
6652 	if (retStyle->errors != 0) {
6653 	    retStyle->doc = NULL;
6654 	    if (parentStyle == NULL)
6655 		xsltCleanupStylesheetTree(doc,
6656 		    xmlDocGetRootElement(doc));
6657 	    xsltFreeStylesheet(retStyle);
6658 	    retStyle = NULL;
6659 	}
6660     }
6661 #endif /* else of XSLT_REFACTORED */
6662 
6663     return(retStyle);
6664 }
6665 
6666 /**
6667  * xsltParseStylesheetDoc:
6668  * @doc:  and xmlDoc parsed XML
6669  *
6670  * parse an XSLT stylesheet, building the associated structures.  doc
6671  * is kept as a reference within the returned stylesheet, so changes
6672  * to doc after the parsing will be reflected when the stylesheet
6673  * is applied, and the doc is automatically freed when the
6674  * stylesheet is closed.
6675  *
6676  * Returns a new XSLT stylesheet structure.
6677  */
6678 
6679 xsltStylesheetPtr
6680 xsltParseStylesheetDoc(xmlDocPtr doc) {
6681     xsltStylesheetPtr ret;
6682 
6683     xsltInitGlobals();
6684 
6685     ret = xsltParseStylesheetImportedDoc(doc, NULL);
6686     if (ret == NULL)
6687 	return(NULL);
6688 
6689     xsltResolveStylesheetAttributeSet(ret);
6690 #ifdef XSLT_REFACTORED
6691     /*
6692     * Free the compilation context.
6693     * TODO: Check if it's better to move this cleanup to
6694     *   xsltParseStylesheetImportedDoc().
6695     */
6696     if (ret->compCtxt != NULL) {
6697 	xsltCompilationCtxtFree(XSLT_CCTXT(ret));
6698 	ret->compCtxt = NULL;
6699     }
6700 #endif
6701     return(ret);
6702 }
6703 
6704 /**
6705  * xsltParseStylesheetFile:
6706  * @filename:  the filename/URL to the stylesheet
6707  *
6708  * Load and parse an XSLT stylesheet
6709  *
6710  * Returns a new XSLT stylesheet structure.
6711  */
6712 
6713 xsltStylesheetPtr
6714 xsltParseStylesheetFile(const xmlChar* filename) {
6715     xsltSecurityPrefsPtr sec;
6716     xsltStylesheetPtr ret;
6717     xmlDocPtr doc;
6718 
6719     xsltInitGlobals();
6720 
6721     if (filename == NULL)
6722 	return(NULL);
6723 
6724 #ifdef WITH_XSLT_DEBUG_PARSING
6725     xsltGenericDebug(xsltGenericDebugContext,
6726 	    "xsltParseStylesheetFile : parse %s\n", filename);
6727 #endif
6728 
6729     /*
6730      * Security framework check
6731      */
6732     sec = xsltGetDefaultSecurityPrefs();
6733     if (sec != NULL) {
6734 	int res;
6735 
6736 	res = xsltCheckRead(sec, NULL, filename);
6737 	if (res == 0) {
6738 	    xsltTransformError(NULL, NULL, NULL,
6739 		 "xsltParseStylesheetFile: read rights for %s denied\n",
6740 			     filename);
6741 	    return(NULL);
6742 	}
6743     }
6744 
6745     doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,
6746                                NULL, XSLT_LOAD_START);
6747     if (doc == NULL) {
6748 	xsltTransformError(NULL, NULL, NULL,
6749 		"xsltParseStylesheetFile : cannot parse %s\n", filename);
6750 	return(NULL);
6751     }
6752     ret = xsltParseStylesheetDoc(doc);
6753     if (ret == NULL) {
6754 	xmlFreeDoc(doc);
6755 	return(NULL);
6756     }
6757 
6758     return(ret);
6759 }
6760 
6761 /************************************************************************
6762  *									*
6763  *			Handling of Stylesheet PI			*
6764  *									*
6765  ************************************************************************/
6766 
6767 #define CUR (*cur)
6768 #define SKIP(val) cur += (val)
6769 #define NXT(val) cur[(val)]
6770 #define SKIP_BLANKS						\
6771     while (IS_BLANK(CUR)) NEXT
6772 #define NEXT ((*cur) ?  cur++ : cur)
6773 
6774 /**
6775  * xsltParseStylesheetPI:
6776  * @value: the value of the PI
6777  *
6778  * This function checks that the type is text/xml and extracts
6779  * the URI-Reference for the stylesheet
6780  *
6781  * Returns the URI-Reference for the stylesheet or NULL (it need to
6782  *         be freed by the caller)
6783  */
6784 static xmlChar *
6785 xsltParseStylesheetPI(const xmlChar *value) {
6786     const xmlChar *cur;
6787     const xmlChar *start;
6788     xmlChar *val;
6789     xmlChar tmp;
6790     xmlChar *href = NULL;
6791     int isXml = 0;
6792 
6793     if (value == NULL)
6794 	return(NULL);
6795 
6796     cur = value;
6797     while (CUR != 0) {
6798 	SKIP_BLANKS;
6799 	if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
6800 	    (NXT(3) == 'e')) {
6801 	    SKIP(4);
6802 	    SKIP_BLANKS;
6803 	    if (CUR != '=')
6804 		continue;
6805 	    NEXT;
6806 	    if ((CUR != '\'') && (CUR != '"'))
6807 		continue;
6808 	    tmp = CUR;
6809 	    NEXT;
6810 	    start = cur;
6811 	    while ((CUR != 0) && (CUR != tmp))
6812 		NEXT;
6813 	    if (CUR != tmp)
6814 		continue;
6815 	    val = xmlStrndup(start, cur - start);
6816 	    NEXT;
6817 	    if (val == NULL)
6818 		return(NULL);
6819 	    if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
6820 		(xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
6821                 xmlFree(val);
6822 		break;
6823 	    }
6824 	    isXml = 1;
6825 	    xmlFree(val);
6826 	} else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
6827 	    (NXT(3) == 'f')) {
6828 	    SKIP(4);
6829 	    SKIP_BLANKS;
6830 	    if (CUR != '=')
6831 		continue;
6832 	    NEXT;
6833 	    if ((CUR != '\'') && (CUR != '"'))
6834 		continue;
6835 	    tmp = CUR;
6836 	    NEXT;
6837 	    start = cur;
6838 	    while ((CUR != 0) && (CUR != tmp))
6839 		NEXT;
6840 	    if (CUR != tmp)
6841 		continue;
6842 	    if (href == NULL)
6843 		href = xmlStrndup(start, cur - start);
6844 	    NEXT;
6845 	} else {
6846 	    while ((CUR != 0) && (!IS_BLANK(CUR)))
6847 		NEXT;
6848 	}
6849 
6850     }
6851 
6852     if (!isXml) {
6853 	if (href != NULL)
6854 	    xmlFree(href);
6855 	href = NULL;
6856     }
6857     return(href);
6858 }
6859 
6860 /**
6861  * xsltLoadStylesheetPI:
6862  * @doc:  a document to process
6863  *
6864  * This function tries to locate the stylesheet PI in the given document
6865  * If found, and if contained within the document, it will extract
6866  * that subtree to build the stylesheet to process @doc (doc itself will
6867  * be modified). If found but referencing an external document it will
6868  * attempt to load it and generate a stylesheet from it. In both cases,
6869  * the resulting stylesheet and the document need to be freed once the
6870  * transformation is done.
6871  *
6872  * Returns a new XSLT stylesheet structure or NULL if not found.
6873  */
6874 xsltStylesheetPtr
6875 xsltLoadStylesheetPI(xmlDocPtr doc) {
6876     xmlNodePtr child;
6877     xsltStylesheetPtr ret = NULL;
6878     xmlChar *href = NULL;
6879     xmlURIPtr URI;
6880 
6881     xsltInitGlobals();
6882 
6883     if (doc == NULL)
6884 	return(NULL);
6885 
6886     /*
6887      * Find the text/xml stylesheet PI id any before the root
6888      */
6889     child = doc->children;
6890     while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
6891 	if ((child->type == XML_PI_NODE) &&
6892 	    (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
6893 	    href = xsltParseStylesheetPI(child->content);
6894 	    if (href != NULL)
6895 		break;
6896 	}
6897 	child = child->next;
6898     }
6899 
6900     /*
6901      * If found check the href to select processing
6902      */
6903     if (href != NULL) {
6904 #ifdef WITH_XSLT_DEBUG_PARSING
6905 	xsltGenericDebug(xsltGenericDebugContext,
6906 		"xsltLoadStylesheetPI : found PI href=%s\n", href);
6907 #endif
6908 	URI = xmlParseURI((const char *) href);
6909 	if (URI == NULL) {
6910 	    xsltTransformError(NULL, NULL, child,
6911 		    "xml-stylesheet : href %s is not valid\n", href);
6912 	    xmlFree(href);
6913 	    return(NULL);
6914 	}
6915 	if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
6916             (URI->opaque == NULL) && (URI->authority == NULL) &&
6917             (URI->server == NULL) && (URI->user == NULL) &&
6918             (URI->path == NULL) && (URI->query == NULL)) {
6919 	    xmlAttrPtr ID;
6920 
6921 #ifdef WITH_XSLT_DEBUG_PARSING
6922 	    xsltGenericDebug(xsltGenericDebugContext,
6923 		    "xsltLoadStylesheetPI : Reference to ID %s\n", href);
6924 #endif
6925 	    if (URI->fragment[0] == '#')
6926 		ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
6927 	    else
6928 		ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
6929 	    if (ID == NULL) {
6930 		xsltTransformError(NULL, NULL, child,
6931 		    "xml-stylesheet : no ID %s found\n", URI->fragment);
6932 	    } else {
6933 		xmlDocPtr fake;
6934 		xmlNodePtr subtree, newtree;
6935 		xmlNsPtr ns;
6936 
6937 #ifdef WITH_XSLT_DEBUG
6938 		xsltGenericDebug(xsltGenericDebugContext,
6939 		    "creating new document from %s for embedded stylesheet\n",
6940 		    doc->URL);
6941 #endif
6942 		/*
6943 		 * move the subtree in a new document passed to
6944 		 * the stylesheet analyzer
6945 		 */
6946 		subtree = ID->parent;
6947 		fake = xmlNewDoc(NULL);
6948 		if (fake != NULL) {
6949 		    /*
6950 		    * Should the dictionary still be shared even though
6951 		    * the nodes are being copied rather than moved?
6952 		    */
6953 		    fake->dict = doc->dict;
6954 		    xmlDictReference(doc->dict);
6955 #ifdef WITH_XSLT_DEBUG
6956 		    xsltGenericDebug(xsltGenericDebugContext,
6957 			"reusing dictionary from %s for embedded stylesheet\n",
6958 			doc->URL);
6959 #endif
6960 
6961 		    newtree = xmlDocCopyNode(subtree, fake, 1);
6962 
6963 		    fake->URL = xmlNodeGetBase(doc, subtree->parent);
6964 #ifdef WITH_XSLT_DEBUG
6965 		    xsltGenericDebug(xsltGenericDebugContext,
6966 			"set base URI for embedded stylesheet as %s\n",
6967 			fake->URL);
6968 #endif
6969 
6970 		    /*
6971 		    * Add all namespaces in scope of embedded stylesheet to
6972 		    * root element of newly created stylesheet document
6973 		    */
6974 		    while ((subtree = subtree->parent) != (xmlNodePtr)doc) {
6975 			for (ns = subtree->ns; ns; ns = ns->next) {
6976 			    xmlNewNs(newtree,  ns->href, ns->prefix);
6977 			}
6978 		    }
6979 
6980 		    xmlAddChild((xmlNodePtr)fake, newtree);
6981 		    ret = xsltParseStylesheetDoc(fake);
6982 		    if (ret == NULL)
6983 			xmlFreeDoc(fake);
6984 		}
6985 	    }
6986 	} else {
6987 	    xmlChar *URL, *base;
6988 
6989 	    /*
6990 	     * Reference to an external stylesheet
6991 	     */
6992 
6993 	    base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
6994 	    URL = xmlBuildURI(href, base);
6995 	    if (URL != NULL) {
6996 #ifdef WITH_XSLT_DEBUG_PARSING
6997 		xsltGenericDebug(xsltGenericDebugContext,
6998 			"xsltLoadStylesheetPI : fetching %s\n", URL);
6999 #endif
7000 		ret = xsltParseStylesheetFile(URL);
7001 		xmlFree(URL);
7002 	    } else {
7003 #ifdef WITH_XSLT_DEBUG_PARSING
7004 		xsltGenericDebug(xsltGenericDebugContext,
7005 			"xsltLoadStylesheetPI : fetching %s\n", href);
7006 #endif
7007 		ret = xsltParseStylesheetFile(href);
7008 	    }
7009 	    if (base != NULL)
7010 		xmlFree(base);
7011 	}
7012 	xmlFreeURI(URI);
7013 	xmlFree(href);
7014     }
7015     return(ret);
7016 }
7017