2 * xslt.c: Implemetation of an XSL Transformation 1.0 engine
6 * http://www.w3.org/TR/1999/REC-xslt-19991116
8 * Associating Style Sheets with XML documents
9 * http://www.w3.org/1999/06/REC-xml-stylesheet-19990629
11 * See Copyright for the status of this software.
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>
31 #include "xsltInternals.h"
33 #include "variables.h"
34 #include "namespaces.h"
35 #include "attributes.h"
36 #include "xsltutils.h"
39 #include "documents.h"
40 #include "extensions.h"
44 #ifdef WITH_XSLT_DEBUG
45 #define WITH_XSLT_DEBUG_PARSING
46 /* #define WITH_XSLT_DEBUG_BLANKS */
49 const char *xsltEngineVersion = LIBXSLT_VERSION_STRING;
50 const int xsltLibxsltVersion = LIBXSLT_VERSION;
51 const int xsltLibxmlVersion = LIBXML_VERSION;
54 * Harmless but avoiding a problem when compiling against a
55 * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
57 #ifndef LIBXML_DEBUG_ENABLED
58 double xmlXPathStringEvalNumber(const xmlChar *str);
64 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
67 #define IS_BLANK_NODE(n) \
68 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
71 * Generic function for accessing stacks in the stylesheet
74 #define PUSH_AND_POP(scope, type, name) \
75 scope int name##Push(xsltStylesheetPtr style, type value) { \
76 if (style->name##Max == 0) { \
77 style->name##Max = 4; \
78 style->name##Tab = (type *) xmlMalloc(style->name##Max * \
79 sizeof(style->name##Tab[0])); \
80 if (style->name##Tab == NULL) { \
81 xmlGenericError(xmlGenericErrorContext, \
82 "malloc failed !\n"); \
86 if (style->name##Nr >= style->name##Max) { \
87 style->name##Max *= 2; \
88 style->name##Tab = (type *) xmlRealloc(style->name##Tab, \
89 style->name##Max * sizeof(style->name##Tab[0])); \
90 if (style->name##Tab == NULL) { \
91 xmlGenericError(xmlGenericErrorContext, \
92 "realloc failed !\n"); \
96 style->name##Tab[style->name##Nr] = value; \
97 style->name = value; \
98 return(style->name##Nr++); \
100 scope type name##Pop(xsltStylesheetPtr style) { \
102 if (style->name##Nr <= 0) return(0); \
104 if (style->name##Nr > 0) \
105 style->name = style->name##Tab[style->name##Nr - 1]; \
107 style->name = NULL; \
108 ret = style->name##Tab[style->name##Nr]; \
109 style->name##Tab[style->name##Nr] = 0; \
114 * Those macros actually generate the functions
116 PUSH_AND_POP(static, xmlChar *, exclPrefix)
118 /************************************************************************
122 ************************************************************************/
127 * Initializes the processor (e.g. registers built-in extensions,
132 static int initialized = 0;
134 if (initialized == 0) {
136 xsltRegisterAllExtras();
144 * Check if a string is ignorable
146 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
149 xsltIsBlank(xmlChar *str) {
153 if (!(IS_BLANK(*str))) return(0);
159 /************************************************************************
161 * Routines to handle XSLT data structures *
163 ************************************************************************/
164 static xsltDecimalFormatPtr
165 xsltNewDecimalFormat(xmlChar *name)
167 xsltDecimalFormatPtr self;
169 self = xmlMalloc(sizeof(xsltDecimalFormat));
175 self->digit = xmlStrdup(BAD_CAST("#"));
176 self->patternSeparator = xmlStrdup(BAD_CAST(";"));
177 self->decimalPoint = xmlStrdup(BAD_CAST("."));
178 self->grouping = xmlStrdup(BAD_CAST(","));
179 self->percent = xmlStrdup(BAD_CAST("%"));
180 self->permille = xmlStrdup(BAD_CAST("?"));
181 self->zeroDigit = xmlStrdup(BAD_CAST("0"));
182 self->minusSign = xmlStrdup(BAD_CAST("-"));
183 self->infinity = xmlStrdup(BAD_CAST("Infinity"));
184 self->noNumber = xmlStrdup(BAD_CAST("NaN"));
190 xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
194 xmlFree(self->digit);
195 if (self->patternSeparator)
196 xmlFree(self->patternSeparator);
197 if (self->decimalPoint)
198 xmlFree(self->decimalPoint);
200 xmlFree(self->grouping);
202 xmlFree(self->percent);
204 xmlFree(self->permille);
206 xmlFree(self->zeroDigit);
208 xmlFree(self->minusSign);
210 xmlFree(self->infinity);
212 xmlFree(self->noNumber);
220 xsltFreeDecimalFormatList(xsltStylesheetPtr self)
222 xsltDecimalFormatPtr iter;
223 xsltDecimalFormatPtr tmp;
228 iter = self->decimalFormat;
229 while (iter != NULL) {
231 xsltFreeDecimalFormat(iter);
237 * xsltDecimalFormatGetByName:
238 * @sheet: the XSLT stylesheet
239 * @name: the decimal-format name to find
241 * Find decimal-format by name
244 xsltDecimalFormatGetByName(xsltStylesheetPtr sheet, xmlChar *name)
246 xsltDecimalFormatPtr result;
249 return sheet->decimalFormat;
251 for (result = sheet->decimalFormat->next;
253 result = result->next) {
254 if (xmlStrEqual(name, result->name))
264 * Create a new XSLT Template
266 * Returns the newly allocated xsltTemplatePtr or NULL in case of error
268 static xsltTemplatePtr
269 xsltNewTemplate(void) {
272 cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
274 xsltPrintErrorContext(NULL, NULL, NULL);
275 xsltGenericError(xsltGenericErrorContext,
276 "xsltNewTemplate : malloc failed\n");
279 memset(cur, 0, sizeof(xsltTemplate));
280 cur->priority = XSLT_PAT_NO_PRIORITY;
286 * @template: an XSLT template
288 * Free up the memory allocated by @template
291 xsltFreeTemplate(xsltTemplatePtr template) {
292 if (template == NULL)
294 if (template->match) xmlFree(template->match);
295 if (template->name) xmlFree(template->name);
296 if (template->nameURI) xmlFree(template->nameURI);
297 if (template->mode) xmlFree(template->mode);
298 if (template->modeURI) xmlFree(template->modeURI);
299 if (template->inheritedNs) xmlFree(template->inheritedNs);
300 memset(template, -1, sizeof(xsltTemplate));
305 * xsltFreeTemplateList:
306 * @template: an XSLT template list
308 * Free up the memory allocated by all the elements of @template
311 xsltFreeTemplateList(xsltTemplatePtr template) {
314 while (template != NULL) {
316 template = template->next;
317 xsltFreeTemplate(cur);
324 * Create a new XSLT Stylesheet
326 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
329 xsltNewStylesheet(void) {
330 xsltStylesheetPtr cur;
332 cur = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
334 xsltPrintErrorContext(NULL, NULL, NULL);
335 xsltGenericError(xsltGenericErrorContext,
336 "xsltNewStylesheet : malloc failed\n");
339 memset(cur, 0, sizeof(xsltStylesheet));
340 cur->omitXmlDeclaration = -1;
341 cur->standalone = -1;
342 cur->decimalFormat = xsltNewDecimalFormat(NULL);
346 cur->exclPrefixNr = 0;
347 cur->exclPrefixMax = 0;
348 cur->exclPrefixTab = NULL;
349 cur->extInfos = NULL;
359 * @style: an XSLT stylesheet
361 * Allocate an extra runtime information slot statically while compiling
362 * the stylesheet and return its number
364 * Returns the number of the slot
367 xsltAllocateExtra(xsltStylesheetPtr style)
369 return(style->extrasNr++);
373 * xsltAllocateExtraCtxt:
374 * @ctxt: an XSLT transformation context
376 * Allocate an extra runtime information slot at run-time
377 * and return its number
378 * This make sure there is a slot ready in the transformation context
380 * Returns the number of the slot
383 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
385 if (ctxt->extrasNr >= ctxt->extrasMax) {
387 if (ctxt->extrasNr == 0) {
388 ctxt->extrasMax = 20;
389 ctxt->extras = (xsltRuntimeExtraPtr)
390 xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
391 if (ctxt->extras == NULL) {
392 xmlGenericError(xmlGenericErrorContext,
393 "xsltAllocateExtraCtxt: out of memory\n");
394 ctxt->state = XSLT_STATE_ERROR;
397 for (i = 0;i < ctxt->extrasMax;i++) {
398 ctxt->extras[i].info = NULL;
399 ctxt->extras[i].deallocate = NULL;
403 xsltRuntimeExtraPtr tmp;
405 ctxt->extrasMax += 100;
406 tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
407 ctxt->extrasMax * sizeof(xsltRuntimeExtra));
409 xmlGenericError(xmlGenericErrorContext,
410 "xsltAllocateExtraCtxt: out of memory\n");
411 ctxt->state = XSLT_STATE_ERROR;
415 for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
416 ctxt->extras[i].info = NULL;
417 ctxt->extras[i].deallocate = NULL;
421 return(ctxt->extrasNr++);
425 * xsltFreeStylesheetList:
426 * @sheet: an XSLT stylesheet list
428 * Free up the memory allocated by the list @sheet
431 xsltFreeStylesheetList(xsltStylesheetPtr sheet) {
432 xsltStylesheetPtr next;
434 while (sheet != NULL) {
436 xsltFreeStylesheet(sheet);
442 * xsltFreeStylesheet:
443 * @sheet: an XSLT stylesheet
445 * Free up the memory allocated by @sheet
448 xsltFreeStylesheet(xsltStylesheetPtr sheet)
455 xsltFreeTemplateHashes(sheet);
456 xsltFreeDecimalFormatList(sheet);
457 xsltFreeTemplateList(sheet->templates);
458 xsltFreeAttributeSetsHashes(sheet);
459 xsltFreeNamespaceAliasHashes(sheet);
460 xsltFreeStyleDocuments(sheet);
461 xsltFreeStylePreComps(sheet);
462 xsltShutdownExts(sheet);
463 if (sheet->doc != NULL)
464 xmlFreeDoc(sheet->doc);
465 if (sheet->variables != NULL)
466 xsltFreeStackElemList(sheet->variables);
467 if (sheet->cdataSection != NULL)
468 xmlHashFree(sheet->cdataSection, NULL);
469 if (sheet->stripSpaces != NULL)
470 xmlHashFree(sheet->stripSpaces, NULL);
471 if (sheet->nsHash != NULL)
472 xmlHashFree(sheet->nsHash, NULL);
474 if (sheet->exclPrefixTab != NULL)
475 xmlFree(sheet->exclPrefixTab);
476 if (sheet->method != NULL)
477 xmlFree(sheet->method);
478 if (sheet->methodURI != NULL)
479 xmlFree(sheet->methodURI);
480 if (sheet->version != NULL)
481 xmlFree(sheet->version);
482 if (sheet->encoding != NULL)
483 xmlFree(sheet->encoding);
484 if (sheet->doctypePublic != NULL)
485 xmlFree(sheet->doctypePublic);
486 if (sheet->doctypeSystem != NULL)
487 xmlFree(sheet->doctypeSystem);
488 if (sheet->mediaType != NULL)
489 xmlFree(sheet->mediaType);
491 if (sheet->imports != NULL)
492 xsltFreeStylesheetList(sheet->imports);
494 memset(sheet, -1, sizeof(xsltStylesheet));
498 /************************************************************************
500 * Parsing of an XSLT Stylesheet *
502 ************************************************************************/
505 * xsltGetInheritedNsList:
506 * @style: the stylesheet
507 * @template: the template
508 * @node: the current node
510 * Search all the namespace applying to a given element except the ones
511 * from excluded output prefixes currently in scope. Initialize the
512 * template inheritedNs list with it.
514 * Returns the number of entries found
517 xsltGetInheritedNsList(xsltStylesheetPtr style,
518 xsltTemplatePtr template,
522 xmlNsPtr *ret = NULL;
527 if ((style == NULL) || (template == NULL) || (node == NULL) ||
528 (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
530 while (node != NULL) {
531 if (node->type == XML_ELEMENT_NODE) {
533 while (cur != NULL) {
534 if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
536 for (i = 0;i < style->exclPrefixNr;i++) {
537 if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
542 (xmlNsPtr *) xmlMalloc((maxns + 1) *
545 xmlGenericError(xmlGenericErrorContext,
546 "xmlGetNsList : out of memory!\n");
551 for (i = 0; i < nbns; i++) {
552 if ((cur->prefix == ret[i]->prefix) ||
553 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
559 ret = (xmlNsPtr *) xmlRealloc(ret,
564 xmlGenericError(xmlGenericErrorContext,
565 "xmlGetNsList : realloc failed!\n");
579 #ifdef WITH_XSLT_DEBUG_PARSING
580 xsltGenericDebug(xsltGenericDebugContext,
581 "template has %d inherited namespaces\n", nbns);
583 template->inheritedNsNr = nbns;
584 template->inheritedNs = ret;
590 * xsltParseStylesheetOutput:
591 * @style: the XSLT stylesheet
592 * @cur: the "output" element
594 * parse an XSLT stylesheet output element and record
595 * information related to the stylesheet output
599 xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
606 if ((cur == NULL) || (style == NULL))
609 prop = xsltGetNsProp(cur, (const xmlChar *) "version", XSLT_NAMESPACE);
611 if (style->version != NULL)
612 xmlFree(style->version);
613 style->version = prop;
617 xsltGetNsProp(cur, (const xmlChar *) "encoding", XSLT_NAMESPACE);
619 if (style->encoding != NULL)
620 xmlFree(style->encoding);
621 style->encoding = prop;
624 /* relaxed to support xt:document */
625 prop = xmlGetProp(cur, (const xmlChar *) "method");
629 if (style->method != NULL)
630 xmlFree(style->method);
631 style->method = NULL;
632 if (style->methodURI != NULL)
633 xmlFree(style->methodURI);
634 style->methodURI = NULL;
636 URI = xsltGetQNameURI(cur, &prop);
639 } else if (URI == NULL) {
640 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
641 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
642 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
643 style->method = prop;
645 xsltPrintErrorContext(NULL, style, cur);
646 xsltGenericError(xsltGenericErrorContext,
647 "invalid value for method: %s\n", prop);
651 style->method = prop;
652 style->methodURI = xmlStrdup(URI);
657 xsltGetNsProp(cur, (const xmlChar *) "doctype-system",
660 if (style->doctypeSystem != NULL)
661 xmlFree(style->doctypeSystem);
662 style->doctypeSystem = prop;
666 xsltGetNsProp(cur, (const xmlChar *) "doctype-public",
669 if (style->doctypePublic != NULL)
670 xmlFree(style->doctypePublic);
671 style->doctypePublic = prop;
674 prop = xsltGetNsProp(cur, (const xmlChar *) "standalone",
677 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
678 style->standalone = 1;
679 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
680 style->standalone = 0;
682 xsltPrintErrorContext(NULL, style, cur);
683 xsltGenericError(xsltGenericErrorContext,
684 "invalid value for standalone: %s\n", prop);
690 prop = xsltGetNsProp(cur, (const xmlChar *) "indent", XSLT_NAMESPACE);
692 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
694 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
697 xsltPrintErrorContext(NULL, style, cur);
698 xsltGenericError(xsltGenericErrorContext,
699 "invalid value for indent: %s\n", prop);
705 prop = xsltGetNsProp(cur, (const xmlChar *) "omit-xml-declaration",
708 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
709 style->omitXmlDeclaration = 1;
710 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
711 style->omitXmlDeclaration = 0;
713 xsltPrintErrorContext(NULL, style, cur);
714 xsltGenericError(xsltGenericErrorContext,
715 "invalid value for omit-xml-declaration: %s\n",
723 xsltGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
725 if (elements != NULL) {
726 if (style->cdataSection == NULL)
727 style->cdataSection = xmlHashCreate(10);
728 if (style->cdataSection == NULL)
732 while (*element != 0) {
733 while (IS_BLANK(*element))
738 while ((*end != 0) && (!IS_BLANK(*end)))
740 element = xmlStrndup(element, end - element);
743 #ifdef WITH_XSLT_DEBUG_PARSING
744 xsltGenericDebug(xsltGenericDebugContext,
745 "add cdata section output element %s\n",
749 URI = xsltGetQNameURI(cur, &element);
750 if (element == NULL) {
753 xmlHashAddEntry2(style->cdataSection, element, URI,
765 * xsltParseStylesheetDecimalFormat:
766 * @style: the XSLT stylesheet
767 * @cur: the "decimal-format" element
769 * parse an XSLT stylesheet decimal-format element and
770 * and record the formatting characteristics
773 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
776 xsltDecimalFormatPtr format;
777 xsltDecimalFormatPtr iter;
779 if ((cur == NULL) || (style == NULL))
782 format = style->decimalFormat;
784 prop = xsltGetNsProp(cur, BAD_CAST("name"), XSLT_NAMESPACE);
786 format = xsltDecimalFormatGetByName(style, prop);
787 if (format != NULL) {
788 xsltPrintErrorContext(NULL, style, cur);
789 xsltGenericError(xsltGenericErrorContext,
790 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
794 format = xsltNewDecimalFormat(prop);
795 if (format == NULL) {
796 xsltPrintErrorContext(NULL, style, cur);
797 xsltGenericError(xsltGenericErrorContext,
798 "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
802 /* Append new decimal-format structure */
803 for (iter = style->decimalFormat; iter->next; iter = iter->next)
809 prop = xsltGetNsProp(cur, (const xmlChar *)"decimal-separator",
812 if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
813 format->decimalPoint = prop;
816 prop = xsltGetNsProp(cur, (const xmlChar *)"grouping-separator",
819 if (format->grouping != NULL) xmlFree(format->grouping);
820 format->grouping = prop;
823 prop = xsltGetNsProp(cur, (const xmlChar *)"infinity", XSLT_NAMESPACE);
825 if (format->infinity != NULL) xmlFree(format->infinity);
826 format->infinity = prop;
829 prop = xsltGetNsProp(cur, (const xmlChar *)"minus-sign", XSLT_NAMESPACE);
831 if (format->minusSign != NULL) xmlFree(format->minusSign);
832 format->minusSign = prop;
835 prop = xsltGetNsProp(cur, (const xmlChar *)"NaN", XSLT_NAMESPACE);
837 if (format->noNumber != NULL) xmlFree(format->noNumber);
838 format->noNumber = prop;
841 prop = xsltGetNsProp(cur, (const xmlChar *)"percent", XSLT_NAMESPACE);
843 if (format->percent != NULL) xmlFree(format->percent);
844 format->percent = prop;
847 prop = xsltGetNsProp(cur, (const xmlChar *)"per-mille", XSLT_NAMESPACE);
849 if (format->permille != NULL) xmlFree(format->permille);
850 format->permille = prop;
853 prop = xsltGetNsProp(cur, (const xmlChar *)"zero-digit", XSLT_NAMESPACE);
855 if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
856 format->zeroDigit = prop;
859 prop = xsltGetNsProp(cur, (const xmlChar *)"digit", XSLT_NAMESPACE);
861 if (format->digit != NULL) xmlFree(format->digit);
862 format->digit = prop;
865 prop = xsltGetNsProp(cur, (const xmlChar *)"pattern-separator",
868 if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
869 format->patternSeparator = prop;
874 * xsltParseStylesheetPreserveSpace:
875 * @style: the XSLT stylesheet
876 * @cur: the "preserve-space" element
878 * parse an XSLT stylesheet preserve-space element and record
879 * elements needing preserving
883 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
885 xmlChar *element, *end;
887 if ((cur == NULL) || (style == NULL))
890 elements = xsltGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
891 if (elements == NULL) {
892 xsltPrintErrorContext(NULL, style, cur);
893 xsltGenericError(xsltGenericErrorContext,
894 "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
899 if (style->stripSpaces == NULL)
900 style->stripSpaces = xmlHashCreate(10);
901 if (style->stripSpaces == NULL)
905 while (*element != 0) {
906 while (IS_BLANK(*element)) element++;
910 while ((*end != 0) && (!IS_BLANK(*end))) end++;
911 element = xmlStrndup(element, end - element);
913 #ifdef WITH_XSLT_DEBUG_PARSING
914 xsltGenericDebug(xsltGenericDebugContext,
915 "add preserved space element %s\n", element);
917 if (xmlStrEqual(element, (const xmlChar *)"*")) {
918 style->stripAll = -1;
920 xmlHashAddEntry(style->stripSpaces, element,
921 (xmlChar *) "preserve");
931 * xsltParseStylesheetExtPrefix:
932 * @style: the XSLT stylesheet
933 * @template: the "extension-element-prefixes" prefix
935 * parse an XSLT stylesheet extension prefix and record
936 * prefixes needing stripping
940 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur) {
942 xmlChar *prefix, *end;
944 if ((cur == NULL) || (style == NULL))
947 prefixes = xsltGetNsProp(cur, (const xmlChar *)"extension-element-prefixes",
949 if (prefixes == NULL) {
954 while (*prefix != 0) {
955 while (IS_BLANK(*prefix)) prefix++;
959 while ((*end != 0) && (!IS_BLANK(*end))) end++;
960 prefix = xmlStrndup(prefix, end - prefix);
964 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
965 ns = xmlSearchNs(style->doc, cur, NULL);
967 ns = xmlSearchNs(style->doc, cur, prefix);
969 xsltPrintErrorContext(NULL, style, cur);
970 xsltGenericError(xsltGenericErrorContext,
971 "xsl:extension-element-prefix : undefined namespace %s\n",
975 #ifdef WITH_XSLT_DEBUG_PARSING
976 xsltGenericDebug(xsltGenericDebugContext,
977 "add extension prefix %s\n", prefix);
979 xsltRegisterExtPrefix(style, prefix, ns->href);
989 * xsltParseStylesheetStripSpace:
990 * @style: the XSLT stylesheet
991 * @cur: the "strip-space" element
993 * parse an XSLT stylesheet strip-space element and record
994 * elements needing stripping
998 xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1000 xmlChar *element, *end;
1002 if ((cur == NULL) || (style == NULL))
1005 elements = xsltGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
1006 if (elements == NULL) {
1007 xsltPrintErrorContext(NULL, style, cur);
1008 xsltGenericError(xsltGenericErrorContext,
1009 "xsltParseStylesheetStripSpace: missing elements attribute\n");
1014 if (style->stripSpaces == NULL)
1015 style->stripSpaces = xmlHashCreate(10);
1016 if (style->stripSpaces == NULL)
1020 while (*element != 0) {
1021 while (IS_BLANK(*element)) element++;
1025 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1026 element = xmlStrndup(element, end - element);
1028 #ifdef WITH_XSLT_DEBUG_PARSING
1029 xsltGenericDebug(xsltGenericDebugContext,
1030 "add stripped space element %s\n", element);
1032 if (xmlStrEqual(element, (const xmlChar *)"*")) {
1033 style->stripAll = 1;
1035 xmlHashAddEntry(style->stripSpaces, element,
1036 (xmlChar *) "strip");
1046 * xsltParseStylesheetExcludePrefix:
1047 * @style: the XSLT stylesheet
1048 * @cur: the current point in the stylesheet
1050 * parse an XSLT stylesheet exclude prefix and record
1051 * namespaces needing stripping
1053 * Returns the number of Excluded prefixes added at that level
1057 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur) {
1060 xmlChar *prefix, *end;
1062 if ((cur == NULL) || (style == NULL))
1065 prefixes = xsltGetNsProp(cur, (const xmlChar *)"exclude-result-prefixes",
1067 if (prefixes == NULL) {
1072 while (*prefix != 0) {
1073 while (IS_BLANK(*prefix)) prefix++;
1077 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1078 prefix = xmlStrndup(prefix, end - prefix);
1082 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1083 ns = xmlSearchNs(style->doc, cur, NULL);
1085 ns = xmlSearchNs(style->doc, cur, prefix);
1087 xsltPrintErrorContext(NULL, style, cur);
1088 xsltGenericError(xsltGenericErrorContext,
1089 "xsl:exclude-result-prefixes : undefined namespace %s\n",
1093 #ifdef WITH_XSLT_DEBUG_PARSING
1094 xsltGenericDebug(xsltGenericDebugContext,
1095 "exclude result prefix %s\n", prefix);
1097 exclPrefixPush(style, (xmlChar *) ns->href);
1109 * xsltPrecomputeStylesheet:
1110 * @style: the XSLT stylesheet
1111 * @cur: the current child list
1113 * Clean-up the stylesheet content from unwanted ignorable blank nodes
1114 * and run the preprocessing of all XSLT constructs.
1116 * and process xslt:text
1119 xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) {
1123 * This content comes from the stylesheet
1124 * For stylesheets, the set of whitespace-preserving
1125 * element names consists of just xsl:text.
1128 while (cur != NULL) {
1129 if (delete != NULL) {
1130 #ifdef WITH_XSLT_DEBUG_BLANKS
1131 xsltGenericDebug(xsltGenericDebugContext,
1132 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
1134 xmlUnlinkNode(delete);
1135 xmlFreeNode(delete);
1138 if (cur->type == XML_ELEMENT_NODE) {
1142 exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur);
1143 if (IS_XSLT_ELEM(cur)) {
1144 xsltStylePreCompute(style, cur);
1145 if (IS_XSLT_NAME(cur, "text")) {
1146 for (;exclPrefixes > 0;exclPrefixes--)
1147 prefix = exclPrefixPop(style);
1152 * Remove excluded prefixes
1154 if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
1155 xmlNsPtr ns = cur->nsDef, prev = NULL, next;
1156 xmlNodePtr root = NULL;
1159 root = xmlDocGetRootElement(cur->doc);
1160 if ((root != NULL) && (root != cur)) {
1161 while (ns != NULL) {
1164 for (i = 0;i < style->exclPrefixNr;i++) {
1165 if (xmlStrEqual(ns->href,
1166 style->exclPrefixTab[i])) {
1168 * Move the namespace definition on the root
1169 * element to avoid duplicating it without
1173 cur->nsDef = ns->next;
1175 prev->next = ns->next;
1177 ns->next = root->nsDef;
1191 * If we have prefixes locally, recurse and pop them up when
1194 if (exclPrefixes > 0) {
1195 xsltPrecomputeStylesheet(style, cur->children);
1196 for (;exclPrefixes > 0;exclPrefixes--)
1197 prefix = exclPrefixPop(style);
1200 } else if (cur->type == XML_TEXT_NODE) {
1201 if (IS_BLANK_NODE(cur)) {
1202 if (xmlNodeGetSpacePreserve(cur) != 1) {
1206 } else if ((cur->type != XML_ELEMENT_NODE) &&
1207 (cur->type != XML_CDATA_SECTION_NODE)) {
1215 if (cur->children != NULL) {
1216 if ((cur->children->type != XML_ENTITY_DECL) &&
1217 (cur->children->type != XML_ENTITY_REF_NODE) &&
1218 (cur->children->type != XML_ENTITY_NODE)) {
1219 cur = cur->children;
1224 if (cur->next != NULL) {
1233 if (cur == (xmlNodePtr) style->doc) {
1237 if (cur->next != NULL) {
1241 } while (cur != NULL);
1243 if (delete != NULL) {
1244 #ifdef WITH_XSLT_DEBUG_PARSING
1245 xsltGenericDebug(xsltGenericDebugContext,
1246 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
1248 xmlUnlinkNode(delete);
1249 xmlFreeNode(delete);
1255 * xsltGatherNamespaces:
1256 * @style: the XSLT stylesheet
1258 * Browse the stylesheet and build the namspace hash table which
1259 * will be used for XPath interpretation. If needed do a bit of normalization
1263 xsltGatherNamespaces(xsltStylesheetPtr style) {
1268 * TODO: basically if the stylesheet uses the same prefix for different
1269 * patterns, well they may be in problem, hopefully they will get
1272 cur = xmlDocGetRootElement(style->doc);
1273 while (cur != NULL) {
1274 if (cur->type == XML_ELEMENT_NODE) {
1275 xmlNsPtr ns = cur->nsDef;
1276 while (ns != NULL) {
1277 if (ns->prefix != NULL) {
1278 if (style->nsHash == NULL) {
1279 style->nsHash = xmlHashCreate(10);
1280 if (style->nsHash == NULL) {
1281 xsltPrintErrorContext(NULL, style, cur);
1282 xsltGenericError(xsltGenericErrorContext,
1283 "xsltGatherNamespaces: failed to create hash table\n");
1288 URI = xmlHashLookup(style->nsHash, ns->prefix);
1289 if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
1290 xsltPrintErrorContext(NULL, style, cur);
1291 xsltGenericError(xsltGenericErrorContext,
1292 "Namespaces prefix %s used for multiple namespaces\n");
1294 } else if (URI == NULL) {
1295 xmlHashUpdateEntry(style->nsHash, ns->prefix,
1296 (void *) ns->href, (xmlHashDeallocator)xmlFree);
1298 #ifdef WITH_XSLT_DEBUG_PARSING
1299 xsltGenericDebug(xsltGenericDebugContext,
1300 "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
1311 if (cur->children != NULL) {
1312 if (cur->children->type != XML_ENTITY_DECL) {
1313 cur = cur->children;
1317 if (cur->next != NULL) {
1326 if (cur == (xmlNodePtr) style->doc) {
1330 if (cur->next != NULL) {
1334 } while (cur != NULL);
1339 * xsltParseTemplateContent:
1340 * @style: the XSLT stylesheet
1341 * @templ: the container node (can be a document for literal results)
1343 * parse a template content-model
1344 * Clean-up the template content from unwanted ignorable blank nodes
1345 * and process xslt:text
1349 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
1350 xmlNodePtr cur, delete;
1352 * This content comes from the stylesheet
1353 * For stylesheets, the set of whitespace-preserving
1354 * element names consists of just xsl:text.
1356 cur = templ->children;
1358 while (cur != NULL) {
1359 if (delete != NULL) {
1360 #ifdef WITH_XSLT_DEBUG_BLANKS
1361 xsltGenericDebug(xsltGenericDebugContext,
1362 "xsltParseTemplateContent: removing text\n");
1364 xmlUnlinkNode(delete);
1365 xmlFreeNode(delete);
1368 if (IS_XSLT_ELEM(cur)) {
1369 if (IS_XSLT_NAME(cur, "text")) {
1370 if (cur->children != NULL) {
1372 xmlNodePtr text = cur->children, next;
1375 prop = xsltGetNsProp(cur,
1376 (const xmlChar *)"disable-output-escaping",
1379 #ifdef WITH_XSLT_DEBUG_PARSING
1380 xsltGenericDebug(xsltGenericDebugContext,
1381 "Disable escaping: %s\n", text->content);
1383 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
1385 } else if (!xmlStrEqual(prop,
1386 (const xmlChar *)"no")){
1387 xsltPrintErrorContext(NULL, style, cur);
1388 xsltGenericError(xsltGenericErrorContext,
1389 "xsl:text: disable-output-escaping allows only yes or no\n");
1396 while (text != NULL) {
1397 if ((text->type != XML_TEXT_NODE) &&
1398 (text->type != XML_CDATA_SECTION_NODE)) {
1399 xsltPrintErrorContext(NULL, style, cur);
1400 xsltGenericError(xsltGenericErrorContext,
1401 "xsltParseTemplateContent: xslt:text content problem\n");
1406 text->name = xmlStringTextNoenc;
1411 * replace xsl:text by the list of childs
1414 text = cur->children;
1415 while (text != NULL) {
1417 xmlUnlinkNode(text);
1418 xmlAddPrevSibling(cur, text);
1426 } else if ((cur->ns != NULL) && (style->nsDefs != NULL)) {
1427 if (xsltCheckExtPrefix(style, cur->ns->prefix)) {
1429 * okay this is an extension element compile it too
1431 xsltStylePreCompute(style, cur);
1438 if (cur->children != NULL) {
1439 if (cur->children->type != XML_ENTITY_DECL) {
1440 cur = cur->children;
1445 if (cur->next != NULL) {
1458 if (cur->next != NULL) {
1462 } while (cur != NULL);
1464 if (delete != NULL) {
1465 #ifdef WITH_XSLT_DEBUG_PARSING
1466 xsltGenericDebug(xsltGenericDebugContext,
1467 "xsltParseTemplateContent: removing text\n");
1469 xmlUnlinkNode(delete);
1470 xmlFreeNode(delete);
1475 * Skip the first params
1477 cur = templ->children;
1478 while (cur != NULL) {
1479 if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
1485 * Browse the remainder of the template
1487 while (cur != NULL) {
1488 if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
1489 xmlNodePtr param = cur;
1492 xsltPrintErrorContext(NULL, style, cur);
1493 xsltGenericError(xsltGenericErrorContext,
1494 "xsltParseTemplateContent: ignoring misplaced param element\n");
1496 xmlUnlinkNode(param);
1506 * xsltParseStylesheetKey:
1507 * @style: the XSLT stylesheet
1508 * @key: the "key" element
1510 * parse an XSLT stylesheet key definition and register it
1514 xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
1515 xmlChar *prop = NULL;
1516 xmlChar *use = NULL;
1517 xmlChar *match = NULL;
1518 xmlChar *name = NULL;
1519 xmlChar *nameURI = NULL;
1527 prop = xsltGetNsProp(key, (const xmlChar *)"name", XSLT_NAMESPACE);
1531 URI = xsltGetQNameURI(key, &prop);
1538 nameURI = xmlStrdup(URI);
1540 #ifdef WITH_XSLT_DEBUG_PARSING
1541 xsltGenericDebug(xsltGenericDebugContext,
1542 "xsltParseStylesheetKey: name %s\n", name);
1545 xsltPrintErrorContext(NULL, style, key);
1546 xsltGenericError(xsltGenericErrorContext,
1547 "xsl:key : error missing name\n");
1552 match = xsltGetNsProp(key, (const xmlChar *)"match", XSLT_NAMESPACE);
1553 if (match == NULL) {
1554 xsltPrintErrorContext(NULL, style, key);
1555 xsltGenericError(xsltGenericErrorContext,
1556 "xsl:key : error missing match\n");
1561 use = xsltGetNsProp(key, (const xmlChar *)"use", XSLT_NAMESPACE);
1563 xsltPrintErrorContext(NULL, style, key);
1564 xsltGenericError(xsltGenericErrorContext,
1565 "xsl:key : error missing use\n");
1573 xsltAddKey(style, name, nameURI, match, use, key);
1583 if (nameURI != NULL)
1588 * xsltParseStylesheetTemplate:
1589 * @style: the XSLT stylesheet
1590 * @template: the "template" element
1592 * parse an XSLT stylesheet template building the associated structures
1596 xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
1597 xsltTemplatePtr ret;
1599 xmlChar *mode = NULL;
1600 xmlChar *modeURI = NULL;
1604 if (template == NULL)
1608 * Create and link the structure
1610 ret = xsltNewTemplate();
1613 ret->next = style->templates;
1614 style->templates = ret;
1618 * Check excluded prefixes
1620 exclPrefixes = xsltParseStylesheetExcludePrefix(style, template);
1623 * Get inherited namespaces
1625 xsltGetInheritedNsList(style, ret, template);
1630 prop = xsltGetNsProp(template, (const xmlChar *)"mode", XSLT_NAMESPACE);
1634 URI = xsltGetQNameURI(template, &prop);
1641 modeURI = xmlStrdup(URI);
1644 ret->modeURI = modeURI;
1645 #ifdef WITH_XSLT_DEBUG_PARSING
1646 xsltGenericDebug(xsltGenericDebugContext,
1647 "xsltParseStylesheetTemplate: mode %s\n", mode);
1653 prop = xsltGetNsProp(template, (const xmlChar *)"match", XSLT_NAMESPACE);
1655 if (ret->match != NULL) xmlFree(ret->match);
1659 prop = xsltGetNsProp(template, (const xmlChar *)"priority", XSLT_NAMESPACE);
1661 priority = xmlXPathStringEvalNumber(prop);
1662 ret->priority = (float) priority;
1666 prop = xsltGetNsProp(template, (const xmlChar *)"name", XSLT_NAMESPACE);
1670 if (ret->name != NULL) xmlFree(ret->name);
1672 if (ret->nameURI != NULL) xmlFree(ret->nameURI);
1673 ret->nameURI = NULL;
1675 URI = xsltGetQNameURI(template, &prop);
1682 ret->nameURI = xmlStrdup(URI);
1684 ret->nameURI = NULL;
1689 * parse the content and register the pattern
1691 xsltParseTemplateContent(style, template);
1692 ret->elem = template;
1693 ret->content = template->children;
1694 xsltAddTemplate(style, ret, mode, modeURI);
1697 for (;exclPrefixes > 0;exclPrefixes--)
1698 exclPrefixPop(style);
1702 * xsltParseStylesheetTop:
1703 * @style: the XSLT stylesheet
1704 * @top: the top level "stylesheet" element
1706 * scan the top level elements of an XSL stylesheet
1710 xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
1713 #ifdef WITH_XSLT_DEBUG_PARSING
1720 prop = xsltGetNsProp(top, (const xmlChar *)"version", XSLT_NAMESPACE);
1722 xsltPrintErrorContext(NULL, style, top);
1723 xsltGenericError(xsltGenericErrorContext,
1724 "xsl:version is missing: document may not be a stylesheet\n");
1727 if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
1728 (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
1729 xsltPrintErrorContext(NULL, style, top);
1730 xsltGenericError(xsltGenericErrorContext,
1731 "xsl:version: only 1.0 features are supported\n");
1732 /* TODO set up compatibility when not XSLT 1.0 */
1738 xsltParseStylesheetExtPrefix(style, top);
1740 cur = top->children;
1743 * process xsl:import elements
1745 while (cur != NULL) {
1746 if (IS_BLANK_NODE(cur)) {
1750 if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
1751 xsltParseStylesheetImport(style, cur);
1757 * process other top-level elements
1759 while (cur != NULL) {
1760 if (IS_BLANK_NODE(cur)) {
1764 if (cur->type == XML_TEXT_NODE) {
1765 if (cur->content != NULL) {
1766 xsltPrintErrorContext(NULL, style, cur);
1767 xsltGenericError(xsltGenericErrorContext,
1768 "misplaced text element: '%s'\n", cur->content);
1774 if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
1775 xsltGenericError(xsltGenericErrorContext,
1776 "Found a top-level element %s with null namespace URI\n",
1782 if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
1783 xsltTopLevelFunction function;
1785 function = xsltExtModuleTopLevelLookup(cur->name,
1787 if (function != NULL)
1788 function(style, cur);
1790 #ifdef WITH_XSLT_DEBUG_PARSING
1791 xsltGenericDebug(xsltGenericDebugContext,
1792 "xsltParseStylesheetTop : found foreign element %s\n",
1798 if (IS_XSLT_NAME(cur, "import")) {
1799 xsltPrintErrorContext(NULL, style, cur);
1800 xsltGenericError(xsltGenericErrorContext,
1801 "xsltParseStylesheetTop: ignoring misplaced import element\n");
1803 } else if (IS_XSLT_NAME(cur, "include")) {
1804 xsltParseStylesheetInclude(style, cur);
1805 } else if (IS_XSLT_NAME(cur, "strip-space")) {
1806 xsltParseStylesheetStripSpace(style, cur);
1807 } else if (IS_XSLT_NAME(cur, "preserve-space")) {
1808 xsltParseStylesheetPreserveSpace(style, cur);
1809 } else if (IS_XSLT_NAME(cur, "output")) {
1810 xsltParseStylesheetOutput(style, cur);
1811 } else if (IS_XSLT_NAME(cur, "key")) {
1812 xsltParseStylesheetKey(style, cur);
1813 } else if (IS_XSLT_NAME(cur, "decimal-format")) {
1814 xsltParseStylesheetDecimalFormat(style, cur);
1815 } else if (IS_XSLT_NAME(cur, "attribute-set")) {
1816 xsltParseStylesheetAttributeSet(style, cur);
1817 } else if (IS_XSLT_NAME(cur, "variable")) {
1818 xsltParseGlobalVariable(style, cur);
1819 } else if (IS_XSLT_NAME(cur, "param")) {
1820 xsltParseGlobalParam(style, cur);
1821 } else if (IS_XSLT_NAME(cur, "template")) {
1822 #ifdef WITH_XSLT_DEBUG_PARSING
1825 xsltParseStylesheetTemplate(style, cur);
1826 } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
1827 xsltNamespaceAlias(style, cur);
1829 xsltPrintErrorContext(NULL, style, cur);
1830 xsltGenericError(xsltGenericErrorContext,
1831 "xsltParseStylesheetTop: ignoring unknown %s element\n",
1837 #ifdef WITH_XSLT_DEBUG_PARSING
1838 xsltGenericDebug(xsltGenericDebugContext,
1839 "parsed %d templates\n", templates);
1844 * xsltParseStylesheetProcess:
1845 * @ret: the XSLT stylesheet
1846 * @doc: and xmlDoc parsed XML
1848 * parse an XSLT stylesheet adding the associated structures
1850 * Returns a new XSLT stylesheet structure.
1854 xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
1863 * First steps, remove blank nodes,
1864 * locate the xsl:stylesheet element and the
1865 * namespace declaration.
1867 cur = xmlDocGetRootElement(doc);
1869 xsltPrintErrorContext(NULL, ret, (xmlNodePtr) doc);
1870 xsltGenericError(xsltGenericErrorContext,
1871 "xsltParseStylesheetProcess : empty stylesheet\n");
1873 xsltFreeStylesheet(ret);
1876 xsltParseStylesheetExcludePrefix(ret, cur);
1877 xsltPrecomputeStylesheet(ret, cur);
1879 if ((IS_XSLT_ELEM(cur)) &&
1880 ((IS_XSLT_NAME(cur, "stylesheet")) ||
1881 (IS_XSLT_NAME(cur, "transform")))) {
1882 #ifdef WITH_XSLT_DEBUG_PARSING
1883 xsltGenericDebug(xsltGenericDebugContext,
1884 "xsltParseStylesheetProcess : found stylesheet\n");
1887 xsltParseStylesheetTop(ret, cur);
1890 xsltTemplatePtr template;
1893 * the document itself might be the template, check xsl:version
1895 prop = xsltGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
1897 xsltPrintErrorContext(NULL, ret, cur);
1898 xsltGenericError(xsltGenericErrorContext,
1899 "xsltParseStylesheetProcess : document is not a stylesheet\n");
1901 xsltFreeStylesheet(ret);
1905 #ifdef WITH_XSLT_DEBUG_PARSING
1906 xsltGenericDebug(xsltGenericDebugContext,
1907 "xsltParseStylesheetProcess : document is stylesheet\n");
1910 if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) {
1911 xsltPrintErrorContext(NULL, ret, cur);
1912 xsltGenericError(xsltGenericErrorContext,
1913 "xsl:version: only 1.0 features are supported\n");
1914 /* TODO set up compatibility when not XSLT 1.0 */
1920 * Create and link the template
1922 template = xsltNewTemplate();
1923 if (template == NULL) {
1925 xsltFreeStylesheet(ret);
1928 template->next = ret->templates;
1929 ret->templates = template;
1930 template->match = xmlStrdup((const xmlChar *)"/");
1933 * parse the content and register the pattern
1935 xsltParseTemplateContent(ret, (xmlNodePtr) doc);
1936 template->elem = (xmlNodePtr) doc;
1937 template->content = doc->children;
1938 xsltAddTemplate(ret, template, NULL, NULL);
1945 * xsltParseStylesheetDoc:
1946 * @doc: and xmlDoc parsed XML
1948 * parse an XSLT stylesheet building the associated structures
1950 * Returns a new XSLT stylesheet structure.
1954 xsltParseStylesheetDoc(xmlDocPtr doc) {
1955 xsltStylesheetPtr ret;
1960 ret = xsltNewStylesheet();
1965 xsltGatherNamespaces(ret);
1966 ret = xsltParseStylesheetProcess(ret, doc);
1972 * xsltParseStylesheetFile:
1973 * @filename: the filename/URL to the stylesheet
1975 * Load and parse an XSLT stylesheet
1977 * Returns a new XSLT stylesheet structure.
1981 xsltParseStylesheetFile(const xmlChar* filename) {
1982 xsltStylesheetPtr ret;
1986 if (filename == NULL)
1989 #ifdef WITH_XSLT_DEBUG_PARSING
1990 xsltGenericDebug(xsltGenericDebugContext,
1991 "xsltParseStylesheetFile : parse %s\n", filename);
1994 doc = xmlParseFile((const char *) filename);
1996 xsltPrintErrorContext(NULL, NULL, NULL);
1997 xsltGenericError(xsltGenericErrorContext,
1998 "xsltParseStylesheetFile : cannot parse %s\n", filename);
2001 ret = xsltParseStylesheetDoc(doc);
2010 /************************************************************************
2012 * Handling of Stylesheet PI *
2014 ************************************************************************/
2017 #define SKIP(val) cur += (val)
2018 #define NXT(val) cur[(val)]
2019 #define SKIP_BLANKS \
2020 while (IS_BLANK(CUR)) NEXT
2021 #define NEXT ((*cur) ? cur++ : cur)
2024 * xsltParseStylesheetPI:
2025 * @value: the value of the PI
2027 * This function checks that the type is text/xml and extracts
2028 * the URI-Reference for the stylesheet
2030 * Returns the URI-Reference for the stylesheet or NULL (it need to
2031 * be freed by the caller)
2034 xsltParseStylesheetPI(const xmlChar *value) {
2036 const xmlChar *start;
2039 xmlChar *href = NULL;
2048 if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
2055 if ((CUR != '\'') && (CUR != '"'))
2060 while ((CUR != 0) && (CUR != tmp))
2064 val = xmlStrndup(start, cur - start);
2068 if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
2069 (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
2075 } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
2082 if ((CUR != '\'') && (CUR != '"'))
2087 while ((CUR != 0) && (CUR != tmp))
2092 href = xmlStrndup(start, cur - start);
2095 while ((CUR != 0) && (!IS_BLANK(CUR)))
2110 * xsltLoadStylesheetPI:
2111 * @doc: a document to process
2113 * This function tries to locate the stylesheet PI in the given document
2114 * If found, and if contained within the document, it will extract
2115 * that subtree to build the stylesheet to process @doc (doc itself will
2116 * be modified). If found but referencing an external document it will
2117 * attempt to load it and generate a stylesheet from it. In both cases,
2118 * the resulting stylesheet and the document need to be freed once the
2119 * transformation is done.
2121 * Returns a new XSLT stylesheet structure or NULL if not found.
2124 xsltLoadStylesheetPI(xmlDocPtr doc) {
2126 xsltStylesheetPtr ret = NULL;
2127 xmlChar *href = NULL;
2134 * Find the text/xml stylesheet PI id any before the root
2136 child = doc->children;
2137 while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
2138 if ((child->type == XML_PI_NODE) &&
2139 (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
2140 href = xsltParseStylesheetPI(child->content);
2144 child = child->next;
2148 * If found check the href to select processing
2151 #ifdef WITH_XSLT_DEBUG_PARSING
2152 xsltGenericDebug(xsltGenericDebugContext,
2153 "xsltLoadStylesheetPI : found PI href=%s\n", href);
2155 URI = xmlParseURI((const char *) href);
2157 xsltPrintErrorContext(NULL, NULL, child);
2158 xsltGenericError(xsltGenericErrorContext,
2159 "xml-stylesheet : href %s is not valid\n", href);
2163 if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
2164 (URI->opaque == NULL) && (URI->authority == NULL) &&
2165 (URI->server == NULL) && (URI->user == NULL) &&
2166 (URI->path == NULL) && (URI->query == NULL)) {
2169 #ifdef WITH_XSLT_DEBUG_PARSING
2170 xsltGenericDebug(xsltGenericDebugContext,
2171 "xsltLoadStylesheetPI : Reference to ID %s\n", href);
2173 if (URI->fragment[0] == '#')
2174 ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
2176 ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
2178 xsltPrintErrorContext(NULL, NULL, child);
2179 xsltGenericError(xsltGenericErrorContext,
2180 "xml-stylesheet : no ID %s found\n", URI->fragment);
2186 * move the subtree in a new document passed to
2187 * the stylesheet analyzer
2189 subtree = ID->parent;
2190 fake = xmlNewDoc(NULL);
2192 xmlUnlinkNode(subtree);
2193 xmlAddChild((xmlNodePtr) fake, subtree);
2194 ret = xsltParseStylesheetDoc(fake);
2200 xmlChar *URL, *base;
2203 * Reference to an external stylesheet
2206 base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
2207 URL = xmlBuildURI(href, base);
2209 #ifdef WITH_XSLT_DEBUG_PARSING
2210 xsltGenericDebug(xsltGenericDebugContext,
2211 "xsltLoadStylesheetPI : fetching %s\n", URL);
2213 ret = xsltParseStylesheetFile(URL);
2216 #ifdef WITH_XSLT_DEBUG_PARSING
2217 xsltGenericDebug(xsltGenericDebugContext,
2218 "xsltLoadStylesheetPI : fetching %s\n", href);
2220 ret = xsltParseStylesheetFile(href);