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