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