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