preparing 1.0.14 updated rebuilt implemented the IN_LIBXSLT and
[platform/upstream/libxslt.git] / 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 "xslt.h"
31 #include "xsltInternals.h"
32 #include "pattern.h"
33 #include "variables.h"
34 #include "namespaces.h"
35 #include "attributes.h"
36 #include "xsltutils.h"
37 #include "imports.h"
38 #include "keys.h"
39 #include "documents.h"
40 #include "extensions.h"
41 #include "preproc.h"
42 #include "extra.h"
43
44 #ifdef WITH_XSLT_DEBUG
45 #define WITH_XSLT_DEBUG_PARSING
46 /* #define WITH_XSLT_DEBUG_BLANKS */
47 #endif
48
49 const char *xsltEngineVersion = LIBXSLT_VERSION_STRING;
50 const int xsltLibxsltVersion = LIBXSLT_VERSION;
51 const int xsltLibxmlVersion = LIBXML_VERSION;
52
53 /*
54  * Harmless but avoiding a problem when compiling against a
55  * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
56  */
57 #ifndef LIBXML_DEBUG_ENABLED
58 double xmlXPathStringEvalNumber(const xmlChar *str);
59 #endif
60 /*
61  * Useful macros
62  */
63
64 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||  \
65                      ((c) == 0x0D))
66
67 #define IS_BLANK_NODE(n)                                                \
68     (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
69
70 /*
71  * Generic function for accessing stacks in the stylesheet
72  */
73
74 #define PUSH_AND_POP(scope, type, name)                                 \
75 scope int name##Push(xsltStylesheetPtr style, type value)        {      \
76     if (style->name##Max == 0) {                                        \
77         style->name##Max = 4;                                           \
78         style->name##Tab = (type *) xmlMalloc(style->name##Max *        \
79                       sizeof(style->name##Tab[0]));                     \
80         if (style->name##Tab == NULL) {                                 \
81             xmlGenericError(xmlGenericErrorContext,                     \
82                     "malloc failed !\n");                               \
83             return(0);                                                  \
84         }                                                               \
85     }                                                                   \
86     if (style->name##Nr >= style->name##Max) {                          \
87         style->name##Max *= 2;                                          \
88         style->name##Tab = (type *) xmlRealloc(style->name##Tab,        \
89                      style->name##Max * sizeof(style->name##Tab[0]));   \
90         if (style->name##Tab == NULL) {                                 \
91             xmlGenericError(xmlGenericErrorContext,                     \
92                     "realloc failed !\n");                              \
93             return(0);                                                  \
94         }                                                               \
95     }                                                                   \
96     style->name##Tab[style->name##Nr] = value;                          \
97     style->name = value;                                                \
98     return(style->name##Nr++);                                          \
99 }                                                                       \
100 scope type name##Pop(xsltStylesheetPtr style)    {                      \
101     type ret;                                                           \
102     if (style->name##Nr <= 0) return(0);                                \
103     style->name##Nr--;                                                  \
104     if (style->name##Nr > 0)                                            \
105         style->name = style->name##Tab[style->name##Nr - 1];            \
106     else                                                                \
107         style->name = NULL;                                             \
108     ret = style->name##Tab[style->name##Nr];                            \
109     style->name##Tab[style->name##Nr] = 0;                              \
110     return(ret);                                                        \
111 }                                                                       \
112
113 /*
114  * Those macros actually generate the functions
115  */
116 PUSH_AND_POP(static, xmlChar *, exclPrefix)
117
118 /************************************************************************
119  *                                                                      *
120  *                      Helper functions                                *
121  *                                                                      *
122  ************************************************************************/
123
124 /**
125  * xsltInit:
126  *
127  * Initializes the processor (e.g. registers built-in extensions,
128  * etc.)
129  */
130 static void
131 xsltInit (void) {
132     static int initialized = 0;
133
134     if (initialized == 0) {
135         initialized = 1;
136         xsltRegisterAllExtras();
137     }
138 }
139
140 /**
141  * xsltIsBlank:
142  * @str:  a string
143  *
144  * Check if a string is ignorable
145  *
146  * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
147  */
148 int
149 xsltIsBlank(xmlChar *str) {
150     if (str == NULL)
151         return(1);
152     while (*str != 0) {
153         if (!(IS_BLANK(*str))) return(0);
154         str++;
155     }
156     return(1);
157 }
158
159 /************************************************************************
160  *                                                                      *
161  *              Routines to handle XSLT data structures                 *
162  *                                                                      *
163  ************************************************************************/
164 static xsltDecimalFormatPtr
165 xsltNewDecimalFormat(xmlChar *name)
166 {
167     xsltDecimalFormatPtr self;
168
169     self = xmlMalloc(sizeof(xsltDecimalFormat));
170     if (self != NULL) {
171         self->next = NULL;
172         self->name = name;
173         
174         /* Default values */
175         self->digit = xmlStrdup(BAD_CAST("#"));
176         self->patternSeparator = xmlStrdup(BAD_CAST(";"));
177         self->decimalPoint = xmlStrdup(BAD_CAST("."));
178         self->grouping = xmlStrdup(BAD_CAST(","));
179         self->percent = xmlStrdup(BAD_CAST("%"));
180         self->permille = xmlStrdup(BAD_CAST("?"));
181         self->zeroDigit = xmlStrdup(BAD_CAST("0"));
182         self->minusSign = xmlStrdup(BAD_CAST("-"));
183         self->infinity = xmlStrdup(BAD_CAST("Infinity"));
184         self->noNumber = xmlStrdup(BAD_CAST("NaN"));
185     }
186     return self;
187 }
188
189 static void
190 xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
191 {
192     if (self != NULL) {
193         if (self->digit)
194             xmlFree(self->digit);
195         if (self->patternSeparator)
196             xmlFree(self->patternSeparator);
197         if (self->decimalPoint)
198             xmlFree(self->decimalPoint);
199         if (self->grouping)
200             xmlFree(self->grouping);
201         if (self->percent)
202             xmlFree(self->percent);
203         if (self->permille)
204             xmlFree(self->permille);
205         if (self->zeroDigit)
206             xmlFree(self->zeroDigit);
207         if (self->minusSign)
208             xmlFree(self->minusSign);
209         if (self->infinity)
210             xmlFree(self->infinity);
211         if (self->noNumber)
212             xmlFree(self->noNumber);
213         if (self->name)
214             xmlFree(self->name);
215         xmlFree(self);
216     }
217 }
218
219 static void
220 xsltFreeDecimalFormatList(xsltStylesheetPtr self)
221 {
222     xsltDecimalFormatPtr iter;
223     xsltDecimalFormatPtr tmp;
224
225     if (self == NULL)
226         return;
227     
228     iter = self->decimalFormat;
229     while (iter != NULL) {
230         tmp = iter->next;
231         xsltFreeDecimalFormat(iter);
232         iter = tmp;
233     }
234 }
235
236 /**
237  * xsltDecimalFormatGetByName:
238  * @sheet: the XSLT stylesheet
239  * @name: the decimal-format name to find
240  *
241  * Find decimal-format by name
242  */
243 xsltDecimalFormatPtr
244 xsltDecimalFormatGetByName(xsltStylesheetPtr sheet, xmlChar *name)
245 {
246     xsltDecimalFormatPtr result;
247
248     if (name == NULL)
249         return sheet->decimalFormat;
250     
251     for (result = sheet->decimalFormat->next;
252          result != NULL;
253          result = result->next) {
254         if (xmlStrEqual(name, result->name))
255             break; /* for */
256     }
257     return result;
258 }
259
260
261 /**
262  * xsltNewTemplate:
263  *
264  * Create a new XSLT Template
265  *
266  * Returns the newly allocated xsltTemplatePtr or NULL in case of error
267  */
268 static xsltTemplatePtr
269 xsltNewTemplate(void) {
270     xsltTemplatePtr cur;
271
272     cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
273     if (cur == NULL) {
274         xsltPrintErrorContext(NULL, NULL, NULL);
275         xsltGenericError(xsltGenericErrorContext,
276                 "xsltNewTemplate : malloc failed\n");
277         return(NULL);
278     }
279     memset(cur, 0, sizeof(xsltTemplate));
280     cur->priority = XSLT_PAT_NO_PRIORITY;
281     return(cur);
282 }
283
284 /**
285  * xsltFreeTemplate:
286  * @template:  an XSLT template
287  *
288  * Free up the memory allocated by @template
289  */
290 static void
291 xsltFreeTemplate(xsltTemplatePtr template) {
292     if (template == NULL)
293         return;
294     if (template->match) xmlFree(template->match);
295     if (template->name) xmlFree(template->name);
296     if (template->nameURI) xmlFree(template->nameURI);
297     if (template->mode) xmlFree(template->mode);
298     if (template->modeURI) xmlFree(template->modeURI);
299     if (template->inheritedNs) xmlFree(template->inheritedNs);
300     memset(template, -1, sizeof(xsltTemplate));
301     xmlFree(template);
302 }
303
304 /**
305  * xsltFreeTemplateList:
306  * @template:  an XSLT template list
307  *
308  * Free up the memory allocated by all the elements of @template
309  */
310 static void
311 xsltFreeTemplateList(xsltTemplatePtr template) {
312     xsltTemplatePtr cur;
313
314     while (template != NULL) {
315         cur = template;
316         template = template->next;
317         xsltFreeTemplate(cur);
318     }
319 }
320
321 /**
322  * xsltNewStylesheet:
323  *
324  * Create a new XSLT Stylesheet
325  *
326  * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
327  */
328 xsltStylesheetPtr
329 xsltNewStylesheet(void) {
330     xsltStylesheetPtr cur;
331
332     cur = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
333     if (cur == NULL) {
334         xsltPrintErrorContext(NULL, NULL, NULL);
335         xsltGenericError(xsltGenericErrorContext,
336                 "xsltNewStylesheet : malloc failed\n");
337         return(NULL);
338     }
339     memset(cur, 0, sizeof(xsltStylesheet));
340     cur->omitXmlDeclaration = -1;
341     cur->standalone = -1;
342     cur->decimalFormat = xsltNewDecimalFormat(NULL);
343     cur->indent = -1;
344     cur->errors = 0;
345     cur->warnings = 0;
346     cur->exclPrefixNr = 0;
347     cur->exclPrefixMax = 0;
348     cur->exclPrefixTab = NULL;
349     cur->extInfos = NULL;
350     cur->extrasNr = 0;
351
352     xsltInit();
353
354     return(cur);
355 }
356
357 /**
358  * xsltAllocateExtra:
359  * @style:  an XSLT stylesheet
360  *
361  * Allocate an extra runtime information slot statically while compiling
362  * the stylesheet and return its number
363  *
364  * Returns the number of the slot
365  */
366 int
367 xsltAllocateExtra(xsltStylesheetPtr style)
368 {
369     return(style->extrasNr++);
370 }
371
372 /**
373  * xsltAllocateExtraCtxt:
374  * @ctxt:  an XSLT transformation context
375  *
376  * Allocate an extra runtime information slot at run-time
377  * and return its number
378  * This make sure there is a slot ready in the transformation context
379  *
380  * Returns the number of the slot
381  */
382 int
383 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
384 {
385     if (ctxt->extrasNr >= ctxt->extrasMax) {
386         int i;
387         if (ctxt->extrasNr == 0) {
388             ctxt->extrasMax = 20;
389             ctxt->extras = (xsltRuntimeExtraPtr)
390                 xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
391             if (ctxt->extras == NULL) {
392                 xmlGenericError(xmlGenericErrorContext,
393                         "xsltAllocateExtraCtxt: out of memory\n");
394                 ctxt->state = XSLT_STATE_ERROR;
395                 return(0);
396             }
397             for (i = 0;i < ctxt->extrasMax;i++) {
398                 ctxt->extras[i].info = NULL;
399                 ctxt->extras[i].deallocate = NULL;
400             }
401
402         } else {
403             xsltRuntimeExtraPtr tmp;
404
405             ctxt->extrasMax += 100;
406             tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
407                             ctxt->extrasMax * sizeof(xsltRuntimeExtra));
408             if (tmp == NULL) {
409                 xmlGenericError(xmlGenericErrorContext,
410                         "xsltAllocateExtraCtxt: out of memory\n");
411                 ctxt->state = XSLT_STATE_ERROR;
412                 return(0);
413             }
414             ctxt->extras = tmp;
415             for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
416                 ctxt->extras[i].info = NULL;
417                 ctxt->extras[i].deallocate = NULL;
418             }
419         }
420     }
421     return(ctxt->extrasNr++);
422 }
423
424 /**
425  * xsltFreeStylesheetList:
426  * @sheet:  an XSLT stylesheet list
427  *
428  * Free up the memory allocated by the list @sheet
429  */
430 static void
431 xsltFreeStylesheetList(xsltStylesheetPtr sheet) {
432     xsltStylesheetPtr next;
433
434     while (sheet != NULL) {
435         next = sheet->next;
436         xsltFreeStylesheet(sheet);
437         sheet = next;
438     }
439 }
440
441 /**
442  * xsltFreeStylesheet:
443  * @sheet:  an XSLT stylesheet
444  *
445  * Free up the memory allocated by @sheet
446  */
447 void
448 xsltFreeStylesheet(xsltStylesheetPtr sheet)
449 {
450     if (sheet == NULL)
451         return;
452
453     xsltFreeKeys(sheet);
454     xsltFreeExts(sheet);
455     xsltFreeTemplateHashes(sheet);
456     xsltFreeDecimalFormatList(sheet);
457     xsltFreeTemplateList(sheet->templates);
458     xsltFreeAttributeSetsHashes(sheet);
459     xsltFreeNamespaceAliasHashes(sheet);
460     xsltFreeStyleDocuments(sheet);
461     xsltFreeStylePreComps(sheet);
462     xsltShutdownExts(sheet);
463     if (sheet->doc != NULL)
464         xmlFreeDoc(sheet->doc);
465     if (sheet->variables != NULL)
466         xsltFreeStackElemList(sheet->variables);
467     if (sheet->cdataSection != NULL)
468         xmlHashFree(sheet->cdataSection, NULL);
469     if (sheet->stripSpaces != NULL)
470         xmlHashFree(sheet->stripSpaces, NULL);
471     if (sheet->nsHash != NULL)
472         xmlHashFree(sheet->nsHash, NULL);
473
474     if (sheet->exclPrefixTab != NULL)
475         xmlFree(sheet->exclPrefixTab);
476     if (sheet->method != NULL)
477         xmlFree(sheet->method);
478     if (sheet->methodURI != NULL)
479         xmlFree(sheet->methodURI);
480     if (sheet->version != NULL)
481         xmlFree(sheet->version);
482     if (sheet->encoding != NULL)
483         xmlFree(sheet->encoding);
484     if (sheet->doctypePublic != NULL)
485         xmlFree(sheet->doctypePublic);
486     if (sheet->doctypeSystem != NULL)
487         xmlFree(sheet->doctypeSystem);
488     if (sheet->mediaType != NULL)
489         xmlFree(sheet->mediaType);
490
491     if (sheet->imports != NULL)
492         xsltFreeStylesheetList(sheet->imports);
493
494     memset(sheet, -1, sizeof(xsltStylesheet));
495     xmlFree(sheet);
496 }
497
498 /************************************************************************
499  *                                                                      *
500  *              Parsing of an XSLT Stylesheet                           *
501  *                                                                      *
502  ************************************************************************/
503
504 /**
505  * xsltGetInheritedNsList:
506  * @style:  the stylesheet
507  * @template: the template
508  * @node:  the current node
509  *
510  * Search all the namespace applying to a given element except the ones 
511  * from excluded output prefixes currently in scope. Initialize the
512  * template inheritedNs list with it.
513  *
514  * Returns the number of entries found
515  */
516 static int
517 xsltGetInheritedNsList(xsltStylesheetPtr style,
518                        xsltTemplatePtr template,
519                        xmlNodePtr node)
520 {
521     xmlNsPtr cur;
522     xmlNsPtr *ret = NULL;
523     int nbns = 0;
524     int maxns = 10;
525     int i;
526
527     if ((style == NULL) || (template == NULL) || (node == NULL) ||
528         (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
529         return(0);
530     while (node != NULL) {
531         if (node->type == XML_ELEMENT_NODE) {
532             cur = node->nsDef;
533             while (cur != NULL) {
534                 if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
535                     goto skip_ns;
536                 for (i = 0;i < style->exclPrefixNr;i++) {
537                     if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
538                         goto skip_ns;
539                 }
540                 if (ret == NULL) {
541                     ret =
542                         (xmlNsPtr *) xmlMalloc((maxns + 1) *
543                                                sizeof(xmlNsPtr));
544                     if (ret == NULL) {
545                         xmlGenericError(xmlGenericErrorContext,
546                                         "xmlGetNsList : out of memory!\n");
547                         return(0);
548                     }
549                     ret[nbns] = NULL;
550                 }
551                 for (i = 0; i < nbns; i++) {
552                     if ((cur->prefix == ret[i]->prefix) ||
553                         (xmlStrEqual(cur->prefix, ret[i]->prefix)))
554                         break;
555                 }
556                 if (i >= nbns) {
557                     if (nbns >= maxns) {
558                         maxns *= 2;
559                         ret = (xmlNsPtr *) xmlRealloc(ret,
560                                                       (maxns +
561                                                        1) *
562                                                       sizeof(xmlNsPtr));
563                         if (ret == NULL) {
564                             xmlGenericError(xmlGenericErrorContext,
565                                             "xmlGetNsList : realloc failed!\n");
566                             return(0);
567                         }
568                     }
569                     ret[nbns++] = cur;
570                     ret[nbns] = NULL;
571                 }
572 skip_ns:
573                 cur = cur->next;
574             }
575         }
576         node = node->parent;
577     }
578     if (nbns != 0) {
579 #ifdef WITH_XSLT_DEBUG_PARSING
580         xsltGenericDebug(xsltGenericDebugContext,
581                          "template has %d inherited namespaces\n", nbns);
582 #endif
583         template->inheritedNsNr = nbns;
584         template->inheritedNs = ret;
585     }
586     return (nbns);
587 }
588
589 /**
590  * xsltParseStylesheetOutput:
591  * @style:  the XSLT stylesheet
592  * @cur:  the "output" element
593  *
594  * parse an XSLT stylesheet output element and record
595  * information related to the stylesheet output
596  */
597
598 void
599 xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
600 {
601     xmlChar *elements,
602      *prop;
603     xmlChar *element,
604      *end;
605
606     if ((cur == NULL) || (style == NULL))
607         return;
608
609     prop = xsltGetNsProp(cur, (const xmlChar *) "version", XSLT_NAMESPACE);
610     if (prop != NULL) {
611         if (style->version != NULL)
612             xmlFree(style->version);
613         style->version = prop;
614     }
615
616     prop =
617         xsltGetNsProp(cur, (const xmlChar *) "encoding", XSLT_NAMESPACE);
618     if (prop != NULL) {
619         if (style->encoding != NULL)
620             xmlFree(style->encoding);
621         style->encoding = prop;
622     }
623
624     /* relaxed to support xt:document */
625     prop = xmlGetProp(cur, (const xmlChar *) "method");
626     if (prop != NULL) {
627         const xmlChar *URI;
628
629         if (style->method != NULL)
630             xmlFree(style->method);
631         style->method = NULL;
632         if (style->methodURI != NULL)
633             xmlFree(style->methodURI);
634         style->methodURI = NULL;
635
636         URI = xsltGetQNameURI(cur, &prop);
637         if (prop == NULL) {
638             style->errors++;
639         } else if (URI == NULL) {
640             if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
641                 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
642                 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
643                 style->method = prop;
644             } else {
645                 xsltPrintErrorContext(NULL, style, cur);
646                 xsltGenericError(xsltGenericErrorContext,
647                                  "invalid value for method: %s\n", prop);
648                 style->warnings++;
649             }
650         } else {
651             style->method = prop;
652             style->methodURI = xmlStrdup(URI);
653         }
654     }
655
656     prop =
657         xsltGetNsProp(cur, (const xmlChar *) "doctype-system",
658                       XSLT_NAMESPACE);
659     if (prop != NULL) {
660         if (style->doctypeSystem != NULL)
661             xmlFree(style->doctypeSystem);
662         style->doctypeSystem = prop;
663     }
664
665     prop =
666         xsltGetNsProp(cur, (const xmlChar *) "doctype-public",
667                       XSLT_NAMESPACE);
668     if (prop != NULL) {
669         if (style->doctypePublic != NULL)
670             xmlFree(style->doctypePublic);
671         style->doctypePublic = prop;
672     }
673
674     prop = xsltGetNsProp(cur, (const xmlChar *) "standalone",
675                          XSLT_NAMESPACE);
676     if (prop != NULL) {
677         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
678             style->standalone = 1;
679         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
680             style->standalone = 0;
681         } else {
682             xsltPrintErrorContext(NULL, style, cur);
683             xsltGenericError(xsltGenericErrorContext,
684                              "invalid value for standalone: %s\n", prop);
685             style->warnings++;
686         }
687         xmlFree(prop);
688     }
689
690     prop = xsltGetNsProp(cur, (const xmlChar *) "indent", XSLT_NAMESPACE);
691     if (prop != NULL) {
692         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
693             style->indent = 1;
694         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
695             style->indent = 0;
696         } else {
697             xsltPrintErrorContext(NULL, style, cur);
698             xsltGenericError(xsltGenericErrorContext,
699                              "invalid value for indent: %s\n", prop);
700             style->warnings++;
701         }
702         xmlFree(prop);
703     }
704
705     prop = xsltGetNsProp(cur, (const xmlChar *) "omit-xml-declaration",
706                          XSLT_NAMESPACE);
707     if (prop != NULL) {
708         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
709             style->omitXmlDeclaration = 1;
710         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
711             style->omitXmlDeclaration = 0;
712         } else {
713             xsltPrintErrorContext(NULL, style, cur);
714             xsltGenericError(xsltGenericErrorContext,
715                              "invalid value for omit-xml-declaration: %s\n",
716                              prop);
717             style->warnings++;
718         }
719         xmlFree(prop);
720     }
721
722     elements =
723         xsltGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
724                       XSLT_NAMESPACE);
725     if (elements != NULL) {
726         if (style->cdataSection == NULL)
727             style->cdataSection = xmlHashCreate(10);
728         if (style->cdataSection == NULL)
729             return;
730
731         element = elements;
732         while (*element != 0) {
733             while (IS_BLANK(*element))
734                 element++;
735             if (*element == 0)
736                 break;
737             end = element;
738             while ((*end != 0) && (!IS_BLANK(*end)))
739                 end++;
740             element = xmlStrndup(element, end - element);
741             if (element) {
742                 const xmlChar *URI;
743 #ifdef WITH_XSLT_DEBUG_PARSING
744                 xsltGenericDebug(xsltGenericDebugContext,
745                                  "add cdata section output element %s\n",
746                                  element);
747 #endif
748
749                 URI = xsltGetQNameURI(cur, &element);
750                 if (element == NULL) {
751                     style->errors++;
752                 } else {
753                     xmlHashAddEntry2(style->cdataSection, element, URI,
754                                      (void *) "cdata");
755                     xmlFree(element);
756                 }
757             }
758             element = end;
759         }
760         xmlFree(elements);
761     }
762 }
763
764 /**
765  * xsltParseStylesheetDecimalFormat:
766  * @style:  the XSLT stylesheet
767  * @cur:  the "decimal-format" element
768  *
769  * parse an XSLT stylesheet decimal-format element and
770  * and record the formatting characteristics
771  */
772 static void
773 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
774 {
775     xmlChar *prop;
776     xsltDecimalFormatPtr format;
777     xsltDecimalFormatPtr iter;
778     
779     if ((cur == NULL) || (style == NULL))
780         return;
781
782     format = style->decimalFormat;
783     
784     prop = xsltGetNsProp(cur, BAD_CAST("name"), XSLT_NAMESPACE);
785     if (prop != NULL) {
786         format = xsltDecimalFormatGetByName(style, prop);
787         if (format != NULL) {
788             xsltPrintErrorContext(NULL, style, cur);
789             xsltGenericError(xsltGenericErrorContext,
790          "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
791             style->warnings++;
792             return;
793         }
794         format = xsltNewDecimalFormat(prop);
795         if (format == NULL) {
796             xsltPrintErrorContext(NULL, style, cur);
797             xsltGenericError(xsltGenericErrorContext,
798      "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
799             style->errors++;
800             return;
801         }
802         /* Append new decimal-format structure */
803         for (iter = style->decimalFormat; iter->next; iter = iter->next)
804             ;
805         if (iter)
806             iter->next = format;
807     }
808
809     prop = xsltGetNsProp(cur, (const xmlChar *)"decimal-separator",
810                         XSLT_NAMESPACE);
811     if (prop != NULL) {
812         if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
813         format->decimalPoint  = prop;
814     }
815     
816     prop = xsltGetNsProp(cur, (const xmlChar *)"grouping-separator",
817                         XSLT_NAMESPACE);
818     if (prop != NULL) {
819         if (format->grouping != NULL) xmlFree(format->grouping);
820         format->grouping  = prop;
821     }
822
823     prop = xsltGetNsProp(cur, (const xmlChar *)"infinity", XSLT_NAMESPACE);
824     if (prop != NULL) {
825         if (format->infinity != NULL) xmlFree(format->infinity);
826         format->infinity  = prop;
827     }
828     
829     prop = xsltGetNsProp(cur, (const xmlChar *)"minus-sign", XSLT_NAMESPACE);
830     if (prop != NULL) {
831         if (format->minusSign != NULL) xmlFree(format->minusSign);
832         format->minusSign  = prop;
833     }
834     
835     prop = xsltGetNsProp(cur, (const xmlChar *)"NaN", XSLT_NAMESPACE);
836     if (prop != NULL) {
837         if (format->noNumber != NULL) xmlFree(format->noNumber);
838         format->noNumber  = prop;
839     }
840     
841     prop = xsltGetNsProp(cur, (const xmlChar *)"percent", XSLT_NAMESPACE);
842     if (prop != NULL) {
843         if (format->percent != NULL) xmlFree(format->percent);
844         format->percent  = prop;
845     }
846     
847     prop = xsltGetNsProp(cur, (const xmlChar *)"per-mille", XSLT_NAMESPACE);
848     if (prop != NULL) {
849         if (format->permille != NULL) xmlFree(format->permille);
850         format->permille  = prop;
851     }
852     
853     prop = xsltGetNsProp(cur, (const xmlChar *)"zero-digit", XSLT_NAMESPACE);
854     if (prop != NULL) {
855         if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
856         format->zeroDigit  = prop;
857     }
858     
859     prop = xsltGetNsProp(cur, (const xmlChar *)"digit", XSLT_NAMESPACE);
860     if (prop != NULL) {
861         if (format->digit != NULL) xmlFree(format->digit);
862         format->digit  = prop;
863     }
864     
865     prop = xsltGetNsProp(cur, (const xmlChar *)"pattern-separator",
866                         XSLT_NAMESPACE);
867     if (prop != NULL) {
868         if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
869         format->patternSeparator  = prop;
870     }
871 }
872
873 /**
874  * xsltParseStylesheetPreserveSpace:
875  * @style:  the XSLT stylesheet
876  * @cur:  the "preserve-space" element
877  *
878  * parse an XSLT stylesheet preserve-space element and record
879  * elements needing preserving
880  */
881
882 static void
883 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
884     xmlChar *elements;
885     xmlChar *element, *end;
886
887     if ((cur == NULL) || (style == NULL))
888         return;
889
890     elements = xsltGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
891     if (elements == NULL) {
892         xsltPrintErrorContext(NULL, style, cur);
893         xsltGenericError(xsltGenericErrorContext,
894             "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
895         style->warnings++;
896         return;
897     }
898
899     if (style->stripSpaces == NULL)
900         style->stripSpaces = xmlHashCreate(10);
901     if (style->stripSpaces == NULL)
902         return;
903
904     element = elements;
905     while (*element != 0) {
906         while (IS_BLANK(*element)) element++;
907         if (*element == 0)
908             break;
909         end = element;
910         while ((*end != 0) && (!IS_BLANK(*end))) end++;
911         element = xmlStrndup(element, end - element);
912         if (element) {
913 #ifdef WITH_XSLT_DEBUG_PARSING
914             xsltGenericDebug(xsltGenericDebugContext,
915                 "add preserved space element %s\n", element);
916 #endif
917             if (xmlStrEqual(element, (const xmlChar *)"*")) {
918                 style->stripAll = -1;
919             } else {
920                 xmlHashAddEntry(style->stripSpaces, element,
921                                 (xmlChar *) "preserve");
922             }
923             xmlFree(element);
924         }
925         element = end;
926     }
927     xmlFree(elements);
928 }
929
930 /**
931  * xsltParseStylesheetExtPrefix:
932  * @style:  the XSLT stylesheet
933  * @template:  the "extension-element-prefixes" prefix
934  *
935  * parse an XSLT stylesheet extension prefix and record
936  * prefixes needing stripping
937  */
938
939 static void
940 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur) {
941     xmlChar *prefixes;
942     xmlChar *prefix, *end;
943
944     if ((cur == NULL) || (style == NULL))
945         return;
946
947     prefixes = xsltGetNsProp(cur, (const xmlChar *)"extension-element-prefixes",
948                             XSLT_NAMESPACE);
949     if (prefixes == NULL) {
950         return;
951     }
952
953     prefix = prefixes;
954     while (*prefix != 0) {
955         while (IS_BLANK(*prefix)) prefix++;
956         if (*prefix == 0)
957             break;
958         end = prefix;
959         while ((*end != 0) && (!IS_BLANK(*end))) end++;
960         prefix = xmlStrndup(prefix, end - prefix);
961         if (prefix) {
962             xmlNsPtr ns;
963
964             if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
965                 ns = xmlSearchNs(style->doc, cur, NULL);
966             else
967                 ns = xmlSearchNs(style->doc, cur, prefix);
968             if (ns == NULL) {
969                 xsltPrintErrorContext(NULL, style, cur);
970                 xsltGenericError(xsltGenericErrorContext,
971             "xsl:extension-element-prefix : undefined namespace %s\n",
972                                  prefix);
973                 style->warnings++;
974             } else {
975 #ifdef WITH_XSLT_DEBUG_PARSING
976                 xsltGenericDebug(xsltGenericDebugContext,
977                     "add extension prefix %s\n", prefix);
978 #endif
979                 xsltRegisterExtPrefix(style, prefix, ns->href);
980             }
981             xmlFree(prefix);
982         }
983         prefix = end;
984     }
985     xmlFree(prefixes);
986 }
987
988 /**
989  * xsltParseStylesheetStripSpace:
990  * @style:  the XSLT stylesheet
991  * @cur:  the "strip-space" element
992  *
993  * parse an XSLT stylesheet strip-space element and record
994  * elements needing stripping
995  */
996
997 static void
998 xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
999     xmlChar *elements;
1000     xmlChar *element, *end;
1001
1002     if ((cur == NULL) || (style == NULL))
1003         return;
1004
1005     elements = xsltGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
1006     if (elements == NULL) {
1007         xsltPrintErrorContext(NULL, style, cur);
1008         xsltGenericError(xsltGenericErrorContext,
1009             "xsltParseStylesheetStripSpace: missing elements attribute\n");
1010         style->warnings++;
1011         return;
1012     }
1013
1014     if (style->stripSpaces == NULL)
1015         style->stripSpaces = xmlHashCreate(10);
1016     if (style->stripSpaces == NULL)
1017         return;
1018
1019     element = elements;
1020     while (*element != 0) {
1021         while (IS_BLANK(*element)) element++;
1022         if (*element == 0)
1023             break;
1024         end = element;
1025         while ((*end != 0) && (!IS_BLANK(*end))) end++;
1026         element = xmlStrndup(element, end - element);
1027         if (element) {
1028 #ifdef WITH_XSLT_DEBUG_PARSING
1029             xsltGenericDebug(xsltGenericDebugContext,
1030                 "add stripped space element %s\n", element);
1031 #endif
1032             if (xmlStrEqual(element, (const xmlChar *)"*")) {
1033                 style->stripAll = 1;
1034             } else {
1035                 xmlHashAddEntry(style->stripSpaces, element,
1036                                 (xmlChar *) "strip");
1037             }
1038             xmlFree(element);
1039         }
1040         element = end;
1041     }
1042     xmlFree(elements);
1043 }
1044
1045 /**
1046  * xsltParseStylesheetExcludePrefix:
1047  * @style:  the XSLT stylesheet
1048  * @cur:  the current point in the stylesheet
1049  *
1050  * parse an XSLT stylesheet exclude prefix and record
1051  * namespaces needing stripping
1052  *
1053  * Returns the number of Excluded prefixes added at that level
1054  */
1055
1056 static int
1057 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur) {
1058     int nb = 0;
1059     xmlChar *prefixes;
1060     xmlChar *prefix, *end;
1061
1062     if ((cur == NULL) || (style == NULL))
1063         return(0);
1064
1065     prefixes = xsltGetNsProp(cur, (const xmlChar *)"exclude-result-prefixes",
1066                             XSLT_NAMESPACE);
1067     if (prefixes == NULL) {
1068         return(0);
1069     }
1070
1071     prefix = prefixes;
1072     while (*prefix != 0) {
1073         while (IS_BLANK(*prefix)) prefix++;
1074         if (*prefix == 0)
1075             break;
1076         end = prefix;
1077         while ((*end != 0) && (!IS_BLANK(*end))) end++;
1078         prefix = xmlStrndup(prefix, end - prefix);
1079         if (prefix) {
1080             xmlNsPtr ns;
1081
1082             if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1083                 ns = xmlSearchNs(style->doc, cur, NULL);
1084             else
1085                 ns = xmlSearchNs(style->doc, cur, prefix);
1086             if (ns == NULL) {
1087                 xsltPrintErrorContext(NULL, style, cur);
1088                 xsltGenericError(xsltGenericErrorContext,
1089             "xsl:exclude-result-prefixes : undefined namespace %s\n",
1090                                  prefix);
1091                 style->warnings++;
1092             } else {
1093 #ifdef WITH_XSLT_DEBUG_PARSING
1094                 xsltGenericDebug(xsltGenericDebugContext,
1095                     "exclude result prefix %s\n", prefix);
1096 #endif
1097                 exclPrefixPush(style, (xmlChar *) ns->href);
1098                 nb++;
1099             }
1100             xmlFree(prefix);
1101         }
1102         prefix = end;
1103     }
1104     xmlFree(prefixes);
1105     return(nb);
1106 }
1107
1108 /**
1109  * xsltPrecomputeStylesheet:
1110  * @style:  the XSLT stylesheet
1111  * @cur:  the current child list
1112  *
1113  * Clean-up the stylesheet content from unwanted ignorable blank nodes
1114  * and run the preprocessing of all XSLT constructs.
1115  *
1116  * and process xslt:text
1117  */
1118 static void
1119 xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) {
1120     xmlNodePtr delete;
1121
1122     /*
1123      * This content comes from the stylesheet
1124      * For stylesheets, the set of whitespace-preserving
1125      * element names consists of just xsl:text.
1126      */
1127     delete = NULL;
1128     while (cur != NULL) {
1129         if (delete != NULL) {
1130 #ifdef WITH_XSLT_DEBUG_BLANKS
1131             xsltGenericDebug(xsltGenericDebugContext,
1132              "xsltPrecomputeStylesheet: removing ignorable blank node\n");
1133 #endif
1134             xmlUnlinkNode(delete);
1135             xmlFreeNode(delete);
1136             delete = NULL;
1137         }
1138         if (cur->type == XML_ELEMENT_NODE) {
1139             int exclPrefixes;
1140             xmlChar *prefix;
1141
1142             exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur);
1143             if (IS_XSLT_ELEM(cur)) {
1144                 xsltStylePreCompute(style, cur);
1145                 if (IS_XSLT_NAME(cur, "text")) {
1146                     for (;exclPrefixes > 0;exclPrefixes--)
1147                         prefix = exclPrefixPop(style);
1148                     goto skip_children;
1149                 }
1150             }
1151             /*
1152              * Remove excluded prefixes
1153              */
1154             if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
1155                 xmlNsPtr ns = cur->nsDef, prev = NULL, next;
1156                 xmlNodePtr root = NULL;
1157                 int i, moved;
1158
1159                 root = xmlDocGetRootElement(cur->doc);
1160                 if ((root != NULL) && (root != cur)) {
1161                     while (ns != NULL) {
1162                         moved = 0;
1163                         next = ns->next;
1164                         for (i = 0;i < style->exclPrefixNr;i++) {
1165                             if (xmlStrEqual(ns->href,
1166                                             style->exclPrefixTab[i])) {
1167                                 /*
1168                                  * Move the namespace definition on the root
1169                                  * element to avoid duplicating it without
1170                                  * loosing it.
1171                                  */
1172                                 if (prev == NULL) {
1173                                     cur->nsDef = ns->next;
1174                                 } else {
1175                                     prev->next = ns->next;
1176                                 }
1177                                 ns->next = root->nsDef;
1178                                 root->nsDef = ns;
1179                                 moved = 1;
1180                                 break;
1181                             }
1182                         }
1183                         if (moved == 0)
1184                             prev = ns;
1185                         ns = next;
1186                     }
1187                 }
1188             }
1189
1190             /*
1191              * If we have prefixes locally, recurse and pop them up when
1192              * going back
1193              */
1194             if (exclPrefixes > 0) {
1195                 xsltPrecomputeStylesheet(style, cur->children);
1196                 for (;exclPrefixes > 0;exclPrefixes--)
1197                     prefix = exclPrefixPop(style);
1198                 goto skip_children;
1199             }
1200         } else if (cur->type == XML_TEXT_NODE) {
1201             if (IS_BLANK_NODE(cur)) {
1202                 if (xmlNodeGetSpacePreserve(cur) != 1) {
1203                     delete = cur;
1204                 }
1205             }
1206         } else if ((cur->type != XML_ELEMENT_NODE) &&
1207                    (cur->type != XML_CDATA_SECTION_NODE)) {
1208             delete = cur;
1209             goto skip_children;
1210         }
1211
1212         /*
1213          * Skip to next node
1214          */
1215         if (cur->children != NULL) {
1216             if ((cur->children->type != XML_ENTITY_DECL) &&
1217                 (cur->children->type != XML_ENTITY_REF_NODE) &&
1218                 (cur->children->type != XML_ENTITY_NODE)) {
1219                 cur = cur->children;
1220                 continue;
1221             }
1222         }
1223 skip_children:
1224         if (cur->next != NULL) {
1225             cur = cur->next;
1226             continue;
1227         }
1228         
1229         do {
1230             cur = cur->parent;
1231             if (cur == NULL)
1232                 break;
1233             if (cur == (xmlNodePtr) style->doc) {
1234                 cur = NULL;
1235                 break;
1236             }
1237             if (cur->next != NULL) {
1238                 cur = cur->next;
1239                 break;
1240             }
1241         } while (cur != NULL);
1242     }
1243     if (delete != NULL) {
1244 #ifdef WITH_XSLT_DEBUG_PARSING
1245         xsltGenericDebug(xsltGenericDebugContext,
1246          "xsltPrecomputeStylesheet: removing ignorable blank node\n");
1247 #endif
1248         xmlUnlinkNode(delete);
1249         xmlFreeNode(delete);
1250         delete = NULL;
1251     }
1252 }
1253
1254 /**
1255  * xsltGatherNamespaces:
1256  * @style:  the XSLT stylesheet
1257  *
1258  * Browse the stylesheet and build the namspace hash table which
1259  * will be used for XPath interpretation. If needed do a bit of normalization
1260  */
1261
1262 static void
1263 xsltGatherNamespaces(xsltStylesheetPtr style) {
1264     xmlNodePtr cur;
1265     const xmlChar *URI;
1266
1267     /* 
1268      * TODO: basically if the stylesheet uses the same prefix for different
1269      *       patterns, well they may be in problem, hopefully they will get
1270      *       a warning first.
1271      */
1272     cur = xmlDocGetRootElement(style->doc);
1273     while (cur != NULL) {
1274         if (cur->type == XML_ELEMENT_NODE) {
1275             xmlNsPtr ns = cur->nsDef;
1276             while (ns != NULL) {
1277                 if (ns->prefix != NULL) {
1278                     if (style->nsHash == NULL) {
1279                         style->nsHash = xmlHashCreate(10);
1280                         if (style->nsHash == NULL) {
1281                             xsltPrintErrorContext(NULL, style, cur);
1282                             xsltGenericError(xsltGenericErrorContext,
1283                  "xsltGatherNamespaces: failed to create hash table\n");
1284                             style->errors++;
1285                             return;
1286                         }
1287                     }
1288                     URI = xmlHashLookup(style->nsHash, ns->prefix);
1289                     if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
1290                         xsltPrintErrorContext(NULL, style, cur);
1291                         xsltGenericError(xsltGenericErrorContext,
1292              "Namespaces prefix %s used for multiple namespaces\n");
1293                         style->warnings++;
1294                     } else if (URI == NULL) {
1295                         xmlHashUpdateEntry(style->nsHash, ns->prefix,
1296                             (void *) ns->href, (xmlHashDeallocator)xmlFree);
1297
1298 #ifdef WITH_XSLT_DEBUG_PARSING
1299                         xsltGenericDebug(xsltGenericDebugContext,
1300                  "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
1301 #endif
1302                     }
1303                 }
1304                 ns = ns->next;
1305             }
1306         }
1307
1308         /*
1309          * Skip to next node
1310          */
1311         if (cur->children != NULL) {
1312             if (cur->children->type != XML_ENTITY_DECL) {
1313                 cur = cur->children;
1314                 continue;
1315             }
1316         }
1317         if (cur->next != NULL) {
1318             cur = cur->next;
1319             continue;
1320         }
1321         
1322         do {
1323             cur = cur->parent;
1324             if (cur == NULL)
1325                 break;
1326             if (cur == (xmlNodePtr) style->doc) {
1327                 cur = NULL;
1328                 break;
1329             }
1330             if (cur->next != NULL) {
1331                 cur = cur->next;
1332                 break;
1333             }
1334         } while (cur != NULL);
1335     }
1336 }
1337
1338 /**
1339  * xsltParseTemplateContent:
1340  * @style:  the XSLT stylesheet
1341  * @templ:  the container node (can be a document for literal results)
1342  *
1343  * parse a template content-model
1344  * Clean-up the template content from unwanted ignorable blank nodes
1345  * and process xslt:text
1346  */
1347
1348 void
1349 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
1350     xmlNodePtr cur, delete;
1351     /*
1352      * This content comes from the stylesheet
1353      * For stylesheets, the set of whitespace-preserving
1354      * element names consists of just xsl:text.
1355      */
1356     cur = templ->children;
1357     delete = NULL;
1358     while (cur != NULL) {
1359         if (delete != NULL) {
1360 #ifdef WITH_XSLT_DEBUG_BLANKS
1361             xsltGenericDebug(xsltGenericDebugContext,
1362              "xsltParseTemplateContent: removing text\n");
1363 #endif
1364             xmlUnlinkNode(delete);
1365             xmlFreeNode(delete);
1366             delete = NULL;
1367         }
1368         if (IS_XSLT_ELEM(cur)) {
1369             if (IS_XSLT_NAME(cur, "text")) {
1370                 if (cur->children != NULL) {
1371                     xmlChar *prop;
1372                     xmlNodePtr text = cur->children, next;
1373                     int noesc = 0;
1374                         
1375                     prop = xsltGetNsProp(cur,
1376                             (const xmlChar *)"disable-output-escaping",
1377                                         XSLT_NAMESPACE);
1378                     if (prop != NULL) {
1379 #ifdef WITH_XSLT_DEBUG_PARSING
1380                         xsltGenericDebug(xsltGenericDebugContext,
1381                              "Disable escaping: %s\n", text->content);
1382 #endif
1383                         if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
1384                             noesc = 1;
1385                         } else if (!xmlStrEqual(prop,
1386                                                 (const xmlChar *)"no")){
1387                             xsltPrintErrorContext(NULL, style, cur);
1388                             xsltGenericError(xsltGenericErrorContext,
1389              "xsl:text: disable-output-escaping allows only yes or no\n");
1390                             style->warnings++;
1391
1392                         }
1393                         xmlFree(prop);
1394                     }
1395
1396                     while (text != NULL) {
1397                         if ((text->type != XML_TEXT_NODE) &&
1398                              (text->type != XML_CDATA_SECTION_NODE)) {
1399                             xsltPrintErrorContext(NULL, style, cur);
1400                             xsltGenericError(xsltGenericErrorContext,
1401                  "xsltParseTemplateContent: xslt:text content problem\n");
1402                             style->errors++;
1403                             break;
1404                         }
1405                         if (noesc)
1406                             text->name = xmlStringTextNoenc;
1407                         text = text->next;
1408                     }
1409
1410                     /*
1411                      * replace xsl:text by the list of childs
1412                      */
1413                     if (text == NULL) {
1414                         text = cur->children;
1415                         while (text != NULL) {
1416                             next = text->next;
1417                             xmlUnlinkNode(text);
1418                             xmlAddPrevSibling(cur, text);
1419                             text = next;
1420                         }
1421                     }
1422                 }
1423                 delete = cur;
1424                 goto skip_children;
1425             }
1426         } else if ((cur->ns != NULL) && (style->nsDefs != NULL)) {
1427             if (xsltCheckExtPrefix(style, cur->ns->prefix)) {
1428                 /*
1429                  * okay this is an extension element compile it too
1430                  */
1431                 xsltStylePreCompute(style, cur);
1432             }
1433         }
1434
1435         /*
1436          * Skip to next node
1437          */
1438         if (cur->children != NULL) {
1439             if (cur->children->type != XML_ENTITY_DECL) {
1440                 cur = cur->children;
1441                 continue;
1442             }
1443         }
1444 skip_children:
1445         if (cur->next != NULL) {
1446             cur = cur->next;
1447             continue;
1448         }
1449         
1450         do {
1451             cur = cur->parent;
1452             if (cur == NULL)
1453                 break;
1454             if (cur == templ) {
1455                 cur = NULL;
1456                 break;
1457             }
1458             if (cur->next != NULL) {
1459                 cur = cur->next;
1460                 break;
1461             }
1462         } while (cur != NULL);
1463     }
1464     if (delete != NULL) {
1465 #ifdef WITH_XSLT_DEBUG_PARSING
1466         xsltGenericDebug(xsltGenericDebugContext,
1467          "xsltParseTemplateContent: removing text\n");
1468 #endif
1469         xmlUnlinkNode(delete);
1470         xmlFreeNode(delete);
1471         delete = NULL;
1472     }
1473
1474     /*
1475      * Skip the first params
1476      */
1477     cur = templ->children;
1478     while (cur != NULL) {
1479         if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
1480             break;
1481         cur = cur->next;
1482     }
1483
1484     /*
1485      * Browse the remainder of the template
1486      */
1487     while (cur != NULL) {
1488         if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
1489             xmlNodePtr param = cur;
1490
1491             cur = cur->next;
1492             xsltPrintErrorContext(NULL, style, cur);
1493             xsltGenericError(xsltGenericErrorContext,
1494                 "xsltParseTemplateContent: ignoring misplaced param element\n");
1495             style->warnings++;
1496             xmlUnlinkNode(param);
1497             xmlFreeNode(param);
1498             continue;
1499         } else
1500             break;
1501         cur = cur->next;
1502     }
1503 }
1504
1505 /**
1506  * xsltParseStylesheetKey:
1507  * @style:  the XSLT stylesheet
1508  * @key:  the "key" element
1509  *
1510  * parse an XSLT stylesheet key definition and register it
1511  */
1512
1513 static void
1514 xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
1515     xmlChar *prop = NULL;
1516     xmlChar *use = NULL;
1517     xmlChar *match = NULL;
1518     xmlChar *name = NULL;
1519     xmlChar *nameURI = NULL;
1520
1521     if (key == NULL)
1522         return;
1523
1524     /*
1525      * Get arguments
1526      */
1527     prop = xsltGetNsProp(key, (const xmlChar *)"name", XSLT_NAMESPACE);
1528     if (prop != NULL) {
1529         const xmlChar *URI;
1530
1531         URI = xsltGetQNameURI(key, &prop);
1532         if (prop == NULL) {
1533             style->errors++;
1534             goto error;
1535         } else {
1536             name = prop;
1537             if (URI != NULL)
1538                 nameURI = xmlStrdup(URI);
1539         }
1540 #ifdef WITH_XSLT_DEBUG_PARSING
1541         xsltGenericDebug(xsltGenericDebugContext,
1542              "xsltParseStylesheetKey: name %s\n", name);
1543 #endif
1544     } else {
1545         xsltPrintErrorContext(NULL, style, key);
1546         xsltGenericError(xsltGenericErrorContext,
1547             "xsl:key : error missing name\n");
1548         style->errors++;
1549         goto error;
1550     }
1551
1552     match = xsltGetNsProp(key, (const xmlChar *)"match", XSLT_NAMESPACE);
1553     if (match == NULL) {
1554         xsltPrintErrorContext(NULL, style, key);
1555         xsltGenericError(xsltGenericErrorContext,
1556             "xsl:key : error missing match\n");
1557         style->errors++;
1558         goto error;
1559     }
1560
1561     use = xsltGetNsProp(key, (const xmlChar *)"use", XSLT_NAMESPACE);
1562     if (use == NULL) {
1563         xsltPrintErrorContext(NULL, style, key);
1564         xsltGenericError(xsltGenericErrorContext,
1565             "xsl:key : error missing use\n");
1566         style->errors++;
1567         goto error;
1568     }
1569
1570     /*
1571      * register the keys
1572      */
1573     xsltAddKey(style, name, nameURI, match, use, key);
1574
1575
1576 error:
1577     if (use != NULL)
1578         xmlFree(use);
1579     if (match != NULL)
1580         xmlFree(match);
1581     if (name != NULL)
1582         xmlFree(name);
1583     if (nameURI != NULL)
1584         xmlFree(nameURI);
1585 }
1586
1587 /**
1588  * xsltParseStylesheetTemplate:
1589  * @style:  the XSLT stylesheet
1590  * @template:  the "template" element
1591  *
1592  * parse an XSLT stylesheet template building the associated structures
1593  */
1594
1595 static void
1596 xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
1597     xsltTemplatePtr ret;
1598     xmlChar *prop;
1599     xmlChar *mode = NULL;
1600     xmlChar *modeURI = NULL;
1601     double  priority;
1602     int exclPrefixes;
1603
1604     if (template == NULL)
1605         return;
1606
1607     /*
1608      * Create and link the structure
1609      */
1610     ret = xsltNewTemplate();
1611     if (ret == NULL)
1612         return;
1613     ret->next = style->templates;
1614     style->templates = ret;
1615     ret->style = style;
1616
1617     /*
1618      * Check excluded prefixes
1619      */
1620     exclPrefixes = xsltParseStylesheetExcludePrefix(style, template);
1621
1622     /*
1623      * Get inherited namespaces
1624      */
1625     xsltGetInheritedNsList(style, ret, template);
1626
1627     /*
1628      * Get arguments
1629      */
1630     prop = xsltGetNsProp(template, (const xmlChar *)"mode", XSLT_NAMESPACE);
1631     if (prop != NULL) {
1632         const xmlChar *URI;
1633
1634         URI = xsltGetQNameURI(template, &prop);
1635         if (prop == NULL) {
1636             style->errors++;
1637             goto error;
1638         } else {
1639             mode = prop;
1640             if (URI != NULL)
1641                 modeURI = xmlStrdup(URI);
1642         }
1643         ret->mode = mode;
1644         ret->modeURI = modeURI;
1645 #ifdef WITH_XSLT_DEBUG_PARSING
1646         xsltGenericDebug(xsltGenericDebugContext,
1647              "xsltParseStylesheetTemplate: mode %s\n", mode);
1648 #endif
1649     } else {
1650         mode = NULL;
1651         modeURI = NULL;
1652     }
1653     prop = xsltGetNsProp(template, (const xmlChar *)"match", XSLT_NAMESPACE);
1654     if (prop != NULL) {
1655         if (ret->match != NULL) xmlFree(ret->match);
1656         ret->match  = prop;
1657     }
1658
1659     prop = xsltGetNsProp(template, (const xmlChar *)"priority", XSLT_NAMESPACE);
1660     if (prop != NULL) {
1661         priority = xmlXPathStringEvalNumber(prop);
1662         ret->priority = (float) priority;
1663         xmlFree(prop);
1664     }
1665
1666     prop = xsltGetNsProp(template, (const xmlChar *)"name", XSLT_NAMESPACE);
1667     if (prop != NULL) {
1668         const xmlChar *URI;
1669
1670         if (ret->name != NULL) xmlFree(ret->name);
1671         ret->name = NULL;
1672         if (ret->nameURI != NULL) xmlFree(ret->nameURI);
1673         ret->nameURI = NULL;
1674
1675         URI = xsltGetQNameURI(template, &prop);
1676         if (prop == NULL) {
1677             style->errors++;
1678             goto error;
1679         } else {
1680             ret->name = prop;
1681             if (URI != NULL)
1682                 ret->nameURI = xmlStrdup(URI);
1683             else
1684                 ret->nameURI = NULL;
1685         }
1686     }
1687
1688     /*
1689      * parse the content and register the pattern
1690      */
1691     xsltParseTemplateContent(style, template);
1692     ret->elem = template;
1693     ret->content = template->children;
1694     xsltAddTemplate(style, ret, mode, modeURI);
1695
1696 error:
1697     for (;exclPrefixes > 0;exclPrefixes--)
1698         exclPrefixPop(style);
1699 }
1700
1701 /**
1702  * xsltParseStylesheetTop:
1703  * @style:  the XSLT stylesheet
1704  * @top:  the top level "stylesheet" element
1705  *
1706  * scan the top level elements of an XSL stylesheet
1707  */
1708
1709 static void
1710 xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
1711     xmlNodePtr cur;
1712     xmlChar *prop;
1713 #ifdef WITH_XSLT_DEBUG_PARSING
1714     int templates = 0;
1715 #endif
1716
1717     if (top == NULL)
1718         return;
1719
1720     prop = xsltGetNsProp(top, (const xmlChar *)"version", XSLT_NAMESPACE);
1721     if (prop == NULL) {
1722         xsltPrintErrorContext(NULL, style, top);
1723         xsltGenericError(xsltGenericErrorContext,
1724             "xsl:version is missing: document may not be a stylesheet\n");
1725         style->warnings++;
1726     } else {
1727         if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
1728             (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
1729             xsltPrintErrorContext(NULL, style, top);
1730             xsltGenericError(xsltGenericErrorContext,
1731                 "xsl:version: only 1.0 features are supported\n");
1732              /* TODO set up compatibility when not XSLT 1.0 */
1733             style->warnings++;
1734         }
1735         xmlFree(prop);
1736     }
1737
1738     xsltParseStylesheetExtPrefix(style, top);
1739
1740     cur = top->children;
1741
1742     /*
1743      * process xsl:import elements
1744      */
1745     while (cur != NULL) {
1746         if (IS_BLANK_NODE(cur)) {
1747             cur = cur->next;
1748             continue;
1749         }
1750         if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
1751             xsltParseStylesheetImport(style, cur);
1752         } else
1753             break;
1754         cur = cur->next;
1755     }
1756     /*
1757      * process other top-level elements
1758      */
1759     while (cur != NULL) {
1760         if (IS_BLANK_NODE(cur)) {
1761             cur = cur->next;
1762             continue;
1763         }
1764         if (cur->type == XML_TEXT_NODE) {
1765             if (cur->content != NULL) {
1766                 xsltPrintErrorContext(NULL, style, cur);
1767                 xsltGenericError(xsltGenericErrorContext,
1768                     "misplaced text element: '%s'\n", cur->content);
1769             }
1770             style->errors++;
1771             cur = cur->next;
1772             continue;
1773         }
1774         if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
1775             xsltGenericError(xsltGenericErrorContext,
1776                      "Found a top-level element %s with null namespace URI\n",
1777                      cur->name);
1778             style->errors++;
1779             cur = cur->next;
1780             continue;
1781         }
1782         if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
1783             xsltTopLevelFunction function;
1784
1785             function = xsltExtModuleTopLevelLookup(cur->name,
1786                                                    cur->ns->href);
1787             if (function != NULL)
1788                 function(style, cur);
1789
1790 #ifdef WITH_XSLT_DEBUG_PARSING
1791             xsltGenericDebug(xsltGenericDebugContext,
1792                     "xsltParseStylesheetTop : found foreign element %s\n",
1793                     cur->name);
1794 #endif
1795             cur = cur->next;
1796             continue;
1797         }
1798         if (IS_XSLT_NAME(cur, "import")) {
1799             xsltPrintErrorContext(NULL, style, cur);
1800             xsltGenericError(xsltGenericErrorContext,
1801                 "xsltParseStylesheetTop: ignoring misplaced import element\n");
1802             style->errors++;
1803         } else if (IS_XSLT_NAME(cur, "include")) {
1804             xsltParseStylesheetInclude(style, cur);
1805         } else if (IS_XSLT_NAME(cur, "strip-space")) {
1806             xsltParseStylesheetStripSpace(style, cur);
1807         } else if (IS_XSLT_NAME(cur, "preserve-space")) {
1808             xsltParseStylesheetPreserveSpace(style, cur);
1809         } else if (IS_XSLT_NAME(cur, "output")) {
1810             xsltParseStylesheetOutput(style, cur);
1811         } else if (IS_XSLT_NAME(cur, "key")) {
1812             xsltParseStylesheetKey(style, cur);
1813         } else if (IS_XSLT_NAME(cur, "decimal-format")) {
1814             xsltParseStylesheetDecimalFormat(style, cur);
1815         } else if (IS_XSLT_NAME(cur, "attribute-set")) {
1816             xsltParseStylesheetAttributeSet(style, cur);
1817         } else if (IS_XSLT_NAME(cur, "variable")) {
1818             xsltParseGlobalVariable(style, cur);
1819         } else if (IS_XSLT_NAME(cur, "param")) {
1820             xsltParseGlobalParam(style, cur);
1821         } else if (IS_XSLT_NAME(cur, "template")) {
1822 #ifdef WITH_XSLT_DEBUG_PARSING
1823             templates++;
1824 #endif
1825             xsltParseStylesheetTemplate(style, cur);
1826         } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
1827             xsltNamespaceAlias(style, cur);
1828         } else {
1829             xsltPrintErrorContext(NULL, style, cur);
1830             xsltGenericError(xsltGenericErrorContext,
1831                 "xsltParseStylesheetTop: ignoring unknown %s element\n",
1832                              cur->name);
1833             style->warnings++;
1834         }
1835         cur = cur->next;
1836     }
1837 #ifdef WITH_XSLT_DEBUG_PARSING
1838     xsltGenericDebug(xsltGenericDebugContext,
1839                     "parsed %d templates\n", templates);
1840 #endif
1841 }
1842
1843 /**
1844  * xsltParseStylesheetProcess:
1845  * @ret:  the XSLT stylesheet
1846  * @doc:  and xmlDoc parsed XML
1847  *
1848  * parse an XSLT stylesheet adding the associated structures
1849  *
1850  * Returns a new XSLT stylesheet structure.
1851  */
1852
1853 xsltStylesheetPtr
1854 xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
1855     xmlNodePtr cur;
1856
1857     if (doc == NULL)
1858         return(NULL);
1859     if (ret == NULL)
1860         return(ret);
1861     
1862     /*
1863      * First steps, remove blank nodes,
1864      * locate the xsl:stylesheet element and the
1865      * namespace declaration.
1866      */
1867     cur = xmlDocGetRootElement(doc);
1868     if (cur == NULL) {
1869         xsltPrintErrorContext(NULL, ret, (xmlNodePtr) doc);
1870         xsltGenericError(xsltGenericErrorContext,
1871                 "xsltParseStylesheetProcess : empty stylesheet\n");
1872         ret->doc = NULL;
1873         xsltFreeStylesheet(ret);
1874         return(NULL);
1875     }
1876     xsltParseStylesheetExcludePrefix(ret, cur);
1877     xsltPrecomputeStylesheet(ret, cur);
1878
1879     if ((IS_XSLT_ELEM(cur)) && 
1880         ((IS_XSLT_NAME(cur, "stylesheet")) ||
1881          (IS_XSLT_NAME(cur, "transform")))) {
1882 #ifdef WITH_XSLT_DEBUG_PARSING
1883         xsltGenericDebug(xsltGenericDebugContext,
1884                 "xsltParseStylesheetProcess : found stylesheet\n");
1885 #endif
1886
1887         xsltParseStylesheetTop(ret, cur);
1888     } else {
1889         xmlChar *prop;
1890         xsltTemplatePtr template;
1891
1892         /*
1893          * the document itself might be the template, check xsl:version
1894          */
1895         prop = xsltGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
1896         if (prop == NULL) {
1897             xsltPrintErrorContext(NULL, ret, cur);
1898             xsltGenericError(xsltGenericErrorContext,
1899                 "xsltParseStylesheetProcess : document is not a stylesheet\n");
1900             ret->doc = NULL;
1901             xsltFreeStylesheet(ret);
1902             return(NULL);
1903         }
1904
1905 #ifdef WITH_XSLT_DEBUG_PARSING
1906         xsltGenericDebug(xsltGenericDebugContext,
1907                 "xsltParseStylesheetProcess : document is stylesheet\n");
1908 #endif
1909         
1910         if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) {
1911             xsltPrintErrorContext(NULL, ret, cur);
1912             xsltGenericError(xsltGenericErrorContext,
1913                 "xsl:version: only 1.0 features are supported\n");
1914              /* TODO set up compatibility when not XSLT 1.0 */
1915             ret->warnings++;
1916         }
1917         xmlFree(prop);
1918
1919         /*
1920          * Create and link the template
1921          */
1922         template = xsltNewTemplate();
1923         if (template == NULL) {
1924             ret->doc = NULL;
1925             xsltFreeStylesheet(ret);
1926             return(NULL);
1927         }
1928         template->next = ret->templates;
1929         ret->templates = template;
1930         template->match = xmlStrdup((const xmlChar *)"/");
1931
1932         /*
1933          * parse the content and register the pattern
1934          */
1935         xsltParseTemplateContent(ret, (xmlNodePtr) doc);
1936         template->elem = (xmlNodePtr) doc;
1937         template->content = doc->children;
1938         xsltAddTemplate(ret, template, NULL, NULL);
1939     }
1940
1941     return(ret);
1942 }
1943
1944 /**
1945  * xsltParseStylesheetDoc:
1946  * @doc:  and xmlDoc parsed XML
1947  *
1948  * parse an XSLT stylesheet building the associated structures
1949  *
1950  * Returns a new XSLT stylesheet structure.
1951  */
1952
1953 xsltStylesheetPtr
1954 xsltParseStylesheetDoc(xmlDocPtr doc) {
1955     xsltStylesheetPtr ret;
1956
1957     if (doc == NULL)
1958         return(NULL);
1959
1960     ret = xsltNewStylesheet();
1961     if (ret == NULL)
1962         return(NULL);
1963     
1964     ret->doc = doc;
1965     xsltGatherNamespaces(ret);
1966     ret = xsltParseStylesheetProcess(ret, doc);
1967
1968     return(ret);
1969 }
1970
1971 /**
1972  * xsltParseStylesheetFile:
1973  * @filename:  the filename/URL to the stylesheet
1974  *
1975  * Load and parse an XSLT stylesheet
1976  *
1977  * Returns a new XSLT stylesheet structure.
1978  */
1979
1980 xsltStylesheetPtr
1981 xsltParseStylesheetFile(const xmlChar* filename) {
1982     xsltStylesheetPtr ret;
1983     xmlDocPtr doc;
1984     
1985
1986     if (filename == NULL)
1987         return(NULL);
1988
1989 #ifdef WITH_XSLT_DEBUG_PARSING
1990     xsltGenericDebug(xsltGenericDebugContext,
1991             "xsltParseStylesheetFile : parse %s\n", filename);
1992 #endif
1993
1994     doc = xmlParseFile((const char *) filename);
1995     if (doc == NULL) {
1996         xsltPrintErrorContext(NULL, NULL, NULL);
1997         xsltGenericError(xsltGenericErrorContext,
1998                 "xsltParseStylesheetFile : cannot parse %s\n", filename);
1999         return(NULL);
2000     }
2001     ret = xsltParseStylesheetDoc(doc);
2002     if (ret == NULL) {
2003         xmlFreeDoc(doc);
2004         return(NULL);
2005     }
2006
2007     return(ret);
2008 }
2009
2010 /************************************************************************
2011  *                                                                      *
2012  *                      Handling of Stylesheet PI                       *
2013  *                                                                      *
2014  ************************************************************************/
2015
2016 #define CUR (*cur)
2017 #define SKIP(val) cur += (val)
2018 #define NXT(val) cur[(val)]
2019 #define SKIP_BLANKS                                             \
2020     while (IS_BLANK(CUR)) NEXT
2021 #define NEXT ((*cur) ?  cur++ : cur)
2022
2023 /**
2024  * xsltParseStylesheetPI:
2025  * @value: the value of the PI
2026  *
2027  * This function checks that the type is text/xml and extracts
2028  * the URI-Reference for the stylesheet
2029  *
2030  * Returns the URI-Reference for the stylesheet or NULL (it need to
2031  *         be freed by the caller)
2032  */
2033 static xmlChar *
2034 xsltParseStylesheetPI(const xmlChar *value) {
2035     const xmlChar *cur;
2036     const xmlChar *start;
2037     xmlChar *val;
2038     xmlChar tmp;
2039     xmlChar *href = NULL;
2040     int isXml = 0;
2041
2042     if (value == NULL)
2043         return(NULL);
2044
2045     cur = value;
2046     while (CUR != 0) {
2047         SKIP_BLANKS;
2048         if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
2049             (NXT(3) == 'e')) {
2050             SKIP(4);
2051             SKIP_BLANKS;
2052             if (CUR != '=')
2053                 continue;
2054             NEXT;
2055             if ((CUR != '\'') && (CUR != '"'))
2056                 continue;
2057             tmp = CUR;
2058             NEXT;
2059             start = cur;
2060             while ((CUR != 0) && (CUR != tmp))
2061                 NEXT;
2062             if (CUR != tmp)
2063                 continue;
2064             val = xmlStrndup(start, cur - start);
2065             NEXT;
2066             if (val == NULL) 
2067                 return(NULL);
2068             if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
2069                 (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
2070                 xmlFree(val);
2071                 break;
2072             }
2073             isXml = 1;
2074             xmlFree(val);
2075         } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
2076             (NXT(3) == 'f')) {
2077             SKIP(4);
2078             SKIP_BLANKS;
2079             if (CUR != '=')
2080                 continue;
2081             NEXT;
2082             if ((CUR != '\'') && (CUR != '"'))
2083                 continue;
2084             tmp = CUR;
2085             NEXT;
2086             start = cur;
2087             while ((CUR != 0) && (CUR != tmp))
2088                 NEXT;
2089             if (CUR != tmp)
2090                 continue;
2091             if (href == NULL)
2092                 href = xmlStrndup(start, cur - start);
2093             NEXT;
2094         } else {
2095             while ((CUR != 0) && (!IS_BLANK(CUR)))
2096                 NEXT;
2097         }
2098             
2099     }
2100
2101     if (!isXml) {
2102         if (href != NULL)
2103             xmlFree(href);
2104         href = NULL;
2105     }
2106     return(href);
2107 }
2108
2109 /**
2110  * xsltLoadStylesheetPI:
2111  * @doc:  a document to process
2112  *
2113  * This function tries to locate the stylesheet PI in the given document
2114  * If found, and if contained within the document, it will extract 
2115  * that subtree to build the stylesheet to process @doc (doc itself will
2116  * be modified). If found but referencing an external document it will
2117  * attempt to load it and generate a stylesheet from it. In both cases,
2118  * the resulting stylesheet and the document need to be freed once the
2119  * transformation is done.
2120  *
2121  * Returns a new XSLT stylesheet structure or NULL if not found.
2122  */
2123 xsltStylesheetPtr
2124 xsltLoadStylesheetPI(xmlDocPtr doc) {
2125     xmlNodePtr child;
2126     xsltStylesheetPtr ret = NULL;
2127     xmlChar *href = NULL;
2128     xmlURIPtr URI;
2129
2130     if (doc == NULL)
2131         return(NULL);
2132
2133     /*
2134      * Find the text/xml stylesheet PI id any before the root
2135      */
2136     child = doc->children;
2137     while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
2138         if ((child->type == XML_PI_NODE) &&
2139             (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
2140             href = xsltParseStylesheetPI(child->content);
2141             if (href != NULL)
2142                 break;
2143         }
2144         child = child->next;
2145     }
2146
2147     /*
2148      * If found check the href to select processing
2149      */
2150     if (href != NULL) {
2151 #ifdef WITH_XSLT_DEBUG_PARSING
2152         xsltGenericDebug(xsltGenericDebugContext,
2153                 "xsltLoadStylesheetPI : found PI href=%s\n", href);
2154 #endif
2155         URI = xmlParseURI((const char *) href);
2156         if (URI == NULL) {
2157             xsltPrintErrorContext(NULL, NULL, child);
2158             xsltGenericError(xsltGenericErrorContext,
2159                     "xml-stylesheet : href %s is not valid\n", href);
2160             xmlFree(href);
2161             return(NULL);
2162         }
2163         if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
2164             (URI->opaque == NULL) && (URI->authority == NULL) &&
2165             (URI->server == NULL) && (URI->user == NULL) &&
2166             (URI->path == NULL) && (URI->query == NULL)) {
2167             xmlAttrPtr ID;
2168
2169 #ifdef WITH_XSLT_DEBUG_PARSING
2170             xsltGenericDebug(xsltGenericDebugContext,
2171                     "xsltLoadStylesheetPI : Reference to ID %s\n", href);
2172 #endif
2173             if (URI->fragment[0] == '#')
2174                 ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
2175             else
2176                 ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
2177             if (ID == NULL) {
2178                 xsltPrintErrorContext(NULL, NULL, child);
2179                 xsltGenericError(xsltGenericErrorContext,
2180                     "xml-stylesheet : no ID %s found\n", URI->fragment);
2181             } else {
2182                 xmlDocPtr fake;
2183                 xmlNodePtr subtree;
2184
2185                 /*
2186                  * move the subtree in a new document passed to
2187                  * the stylesheet analyzer
2188                  */
2189                 subtree = ID->parent;
2190                 fake = xmlNewDoc(NULL);
2191                 if (fake != NULL) {
2192                     xmlUnlinkNode(subtree);
2193                     xmlAddChild((xmlNodePtr) fake, subtree);
2194                     ret = xsltParseStylesheetDoc(fake);
2195                     if (ret == NULL)
2196                         xmlFreeDoc(fake);
2197                 }
2198             }
2199         } else {
2200             xmlChar *URL, *base;
2201
2202             /*
2203              * Reference to an external stylesheet
2204              */
2205
2206             base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
2207             URL = xmlBuildURI(href, base);
2208             if (URL != NULL) {
2209 #ifdef WITH_XSLT_DEBUG_PARSING
2210                 xsltGenericDebug(xsltGenericDebugContext,
2211                         "xsltLoadStylesheetPI : fetching %s\n", URL);
2212 #endif
2213                 ret = xsltParseStylesheetFile(URL);
2214                 xmlFree(URL);
2215             } else {
2216 #ifdef WITH_XSLT_DEBUG_PARSING
2217                 xsltGenericDebug(xsltGenericDebugContext,
2218                         "xsltLoadStylesheetPI : fetching %s\n", href);
2219 #endif
2220                 ret = xsltParseStylesheetFile(href);
2221             }
2222             if (base != NULL)
2223                 xmlFree(base);
2224         }
2225         xmlFreeURI(URI);
2226         xmlFree(href);
2227     }
2228     return(ret);
2229 }