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