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