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