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.
20 #include <libxml/xmlmemory.h>
21 #include <libxml/parser.h>
22 #include <libxml/tree.h>
23 #include <libxml/valid.h>
24 #include <libxml/hash.h>
25 #include <libxml/uri.h>
26 #include <libxml/xmlerror.h>
27 #include <libxml/parserInternals.h>
28 #include <libxml/xpathInternals.h>
30 #include "xsltInternals.h"
32 #include "variables.h"
33 #include "namespaces.h"
34 #include "attributes.h"
35 #include "xsltutils.h"
38 #include "documents.h"
39 #include "extensions.h"
43 #ifdef WITH_XSLT_DEBUG
44 #define WITH_XSLT_DEBUG_PARSING
45 /* #define WITH_XSLT_DEBUG_BLANKS */
48 const char *xsltEngineVersion = LIBXSLT_VERSION_STRING;
49 const int xsltLibxsltVersion = LIBXSLT_VERSION;
50 const int xsltLibxmlVersion = LIBXML_VERSION;
53 * Harmless but avoiding a problem when compiling against a
54 * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
56 #ifndef LIBXML_DEBUG_ENABLED
57 double xmlXPathStringEvalNumber(const xmlChar *str);
63 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
66 #define IS_BLANK_NODE(n) \
67 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
70 * Generic function for accessing stacks in the stylesheet
73 #define PUSH_AND_POP(scope, type, name) \
74 scope int name##Push(xsltStylesheetPtr style, type value) { \
75 if (style->name##Max == 0) { \
76 style->name##Max = 4; \
77 style->name##Tab = (type *) xmlMalloc(style->name##Max * \
78 sizeof(style->name##Tab[0])); \
79 if (style->name##Tab == NULL) { \
80 xmlGenericError(xmlGenericErrorContext, \
81 "malloc failed !\n"); \
85 if (style->name##Nr >= style->name##Max) { \
86 style->name##Max *= 2; \
87 style->name##Tab = (type *) xmlRealloc(style->name##Tab, \
88 style->name##Max * sizeof(style->name##Tab[0])); \
89 if (style->name##Tab == NULL) { \
90 xmlGenericError(xmlGenericErrorContext, \
91 "realloc failed !\n"); \
95 style->name##Tab[style->name##Nr] = value; \
96 style->name = value; \
97 return(style->name##Nr++); \
99 scope type name##Pop(xsltStylesheetPtr style) { \
101 if (style->name##Nr <= 0) return(0); \
103 if (style->name##Nr > 0) \
104 style->name = style->name##Tab[style->name##Nr - 1]; \
106 style->name = NULL; \
107 ret = style->name##Tab[style->name##Nr]; \
108 style->name##Tab[style->name##Nr] = 0; \
113 * Those macros actually generate the functions
115 PUSH_AND_POP(static, xmlChar *, exclPrefix)
117 /************************************************************************
121 ************************************************************************/
126 * Initializes the processor (e.g. registers built-in extensions,
131 static int initialized = 0;
133 if (initialized == 0) {
135 xsltRegisterAllExtras();
143 * Check if a string is ignorable
145 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
148 xsltIsBlank(xmlChar *str) {
152 if (!(IS_BLANK(*str))) return(0);
158 /************************************************************************
160 * Routines to handle XSLT data structures *
162 ************************************************************************/
163 static xsltDecimalFormatPtr
164 xsltNewDecimalFormat(xmlChar *name)
166 xsltDecimalFormatPtr self;
168 self = xmlMalloc(sizeof(xsltDecimalFormat));
174 self->digit = xmlStrdup(BAD_CAST("#"));
175 self->patternSeparator = xmlStrdup(BAD_CAST(";"));
176 self->decimalPoint = xmlStrdup(BAD_CAST("."));
177 self->grouping = xmlStrdup(BAD_CAST(","));
178 self->percent = xmlStrdup(BAD_CAST("%"));
179 self->permille = xmlStrdup(BAD_CAST("?"));
180 self->zeroDigit = xmlStrdup(BAD_CAST("0"));
181 self->minusSign = xmlStrdup(BAD_CAST("-"));
182 self->infinity = xmlStrdup(BAD_CAST("Infinity"));
183 self->noNumber = xmlStrdup(BAD_CAST("NaN"));
189 xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
193 xmlFree(self->digit);
194 if (self->patternSeparator)
195 xmlFree(self->patternSeparator);
196 if (self->decimalPoint)
197 xmlFree(self->decimalPoint);
199 xmlFree(self->grouping);
201 xmlFree(self->percent);
203 xmlFree(self->permille);
205 xmlFree(self->zeroDigit);
207 xmlFree(self->minusSign);
209 xmlFree(self->infinity);
211 xmlFree(self->noNumber);
219 xsltFreeDecimalFormatList(xsltStylesheetPtr self)
221 xsltDecimalFormatPtr iter;
222 xsltDecimalFormatPtr tmp;
227 iter = self->decimalFormat;
228 while (iter != NULL) {
230 xsltFreeDecimalFormat(iter);
236 * xsltDecimalFormatGetByName:
237 * @sheet: the XSLT stylesheet
238 * @name: the decimal-format name to find
240 * Find decimal-format by name
243 xsltDecimalFormatGetByName(xsltStylesheetPtr sheet, xmlChar *name)
245 xsltDecimalFormatPtr result;
248 return sheet->decimalFormat;
250 for (result = sheet->decimalFormat->next;
252 result = result->next) {
253 if (xmlStrEqual(name, result->name))
263 * Create a new XSLT Template
265 * Returns the newly allocated xsltTemplatePtr or NULL in case of error
267 static xsltTemplatePtr
268 xsltNewTemplate(void) {
271 cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
273 xsltPrintErrorContext(NULL, NULL, NULL);
274 xsltGenericError(xsltGenericErrorContext,
275 "xsltNewTemplate : malloc failed\n");
278 memset(cur, 0, sizeof(xsltTemplate));
279 cur->priority = XSLT_PAT_NO_PRIORITY;
285 * @template: an XSLT template
287 * Free up the memory allocated by @template
290 xsltFreeTemplate(xsltTemplatePtr template) {
291 if (template == NULL)
293 if (template->match) xmlFree(template->match);
294 if (template->name) xmlFree(template->name);
295 if (template->nameURI) xmlFree(template->nameURI);
296 if (template->mode) xmlFree(template->mode);
297 if (template->modeURI) xmlFree(template->modeURI);
298 if (template->inheritedNs) xmlFree(template->inheritedNs);
299 memset(template, -1, sizeof(xsltTemplate));
304 * xsltFreeTemplateList:
305 * @template: an XSLT template list
307 * Free up the memory allocated by all the elements of @template
310 xsltFreeTemplateList(xsltTemplatePtr template) {
313 while (template != NULL) {
315 template = template->next;
316 xsltFreeTemplate(cur);
323 * Create a new XSLT Stylesheet
325 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
328 xsltNewStylesheet(void) {
329 xsltStylesheetPtr cur;
331 cur = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
333 xsltPrintErrorContext(NULL, NULL, NULL);
334 xsltGenericError(xsltGenericErrorContext,
335 "xsltNewStylesheet : malloc failed\n");
338 memset(cur, 0, sizeof(xsltStylesheet));
339 cur->omitXmlDeclaration = -1;
340 cur->standalone = -1;
341 cur->decimalFormat = xsltNewDecimalFormat(NULL);
345 cur->exclPrefixNr = 0;
346 cur->exclPrefixMax = 0;
347 cur->exclPrefixTab = NULL;
348 cur->extInfos = NULL;
358 * @style: an XSLT stylesheet
360 * Allocate an extra runtime information slot statically while compiling
361 * the stylesheet and return its number
363 * Returns the number of the slot
366 xsltAllocateExtra(xsltStylesheetPtr style)
368 return(style->extrasNr++);
372 * xsltAllocateExtraCtxt:
373 * @ctxt: an XSLT transformation context
375 * Allocate an extra runtime information slot at run-time
376 * and return its number
377 * This make sure there is a slot ready in the transformation context
379 * Returns the number of the slot
382 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
384 if (ctxt->extrasNr >= ctxt->extrasMax) {
386 if (ctxt->extrasNr == 0) {
387 ctxt->extrasMax = 20;
388 ctxt->extras = (xsltRuntimeExtraPtr)
389 xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
390 if (ctxt->extras == NULL) {
391 xmlGenericError(xmlGenericErrorContext,
392 "xsltAllocateExtraCtxt: out of memory\n");
393 ctxt->state = XSLT_STATE_ERROR;
396 for (i = 0;i < ctxt->extrasMax;i++) {
397 ctxt->extras[i].info = NULL;
398 ctxt->extras[i].deallocate = NULL;
402 xsltRuntimeExtraPtr tmp;
404 ctxt->extrasMax += 100;
405 tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
406 ctxt->extrasMax * sizeof(xsltRuntimeExtra));
408 xmlGenericError(xmlGenericErrorContext,
409 "xsltAllocateExtraCtxt: out of memory\n");
410 ctxt->state = XSLT_STATE_ERROR;
414 for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
415 ctxt->extras[i].info = NULL;
416 ctxt->extras[i].deallocate = NULL;
420 return(ctxt->extrasNr++);
424 * xsltFreeStylesheetList:
425 * @sheet: an XSLT stylesheet list
427 * Free up the memory allocated by the list @sheet
430 xsltFreeStylesheetList(xsltStylesheetPtr sheet) {
431 xsltStylesheetPtr next;
433 while (sheet != NULL) {
435 xsltFreeStylesheet(sheet);
441 * xsltFreeStylesheet:
442 * @sheet: an XSLT stylesheet
444 * Free up the memory allocated by @sheet
447 xsltFreeStylesheet(xsltStylesheetPtr sheet)
454 xsltFreeTemplateHashes(sheet);
455 xsltFreeDecimalFormatList(sheet);
456 xsltFreeTemplateList(sheet->templates);
457 xsltFreeAttributeSetsHashes(sheet);
458 xsltFreeNamespaceAliasHashes(sheet);
459 xsltFreeStyleDocuments(sheet);
460 xsltFreeStylePreComps(sheet);
461 xsltShutdownExts(sheet);
462 if (sheet->doc != NULL)
463 xmlFreeDoc(sheet->doc);
464 if (sheet->variables != NULL)
465 xsltFreeStackElemList(sheet->variables);
466 if (sheet->cdataSection != NULL)
467 xmlHashFree(sheet->cdataSection, NULL);
468 if (sheet->stripSpaces != NULL)
469 xmlHashFree(sheet->stripSpaces, NULL);
470 if (sheet->nsHash != NULL)
471 xmlHashFree(sheet->nsHash, NULL);
473 if (sheet->exclPrefixTab != NULL)
474 xmlFree(sheet->exclPrefixTab);
475 if (sheet->method != NULL)
476 xmlFree(sheet->method);
477 if (sheet->methodURI != NULL)
478 xmlFree(sheet->methodURI);
479 if (sheet->version != NULL)
480 xmlFree(sheet->version);
481 if (sheet->encoding != NULL)
482 xmlFree(sheet->encoding);
483 if (sheet->doctypePublic != NULL)
484 xmlFree(sheet->doctypePublic);
485 if (sheet->doctypeSystem != NULL)
486 xmlFree(sheet->doctypeSystem);
487 if (sheet->mediaType != NULL)
488 xmlFree(sheet->mediaType);
490 if (sheet->imports != NULL)
491 xsltFreeStylesheetList(sheet->imports);
493 memset(sheet, -1, sizeof(xsltStylesheet));
497 /************************************************************************
499 * Parsing of an XSLT Stylesheet *
501 ************************************************************************/
504 * xsltGetInheritedNsList:
505 * @style: the stylesheet
506 * @template: the template
507 * @node: the current node
509 * Search all the namespace applying to a given element except the ones
510 * from excluded output prefixes currently in scope. Initialize the
511 * template inheritedNs list with it.
513 * Returns the number of entries found
516 xsltGetInheritedNsList(xsltStylesheetPtr style,
517 xsltTemplatePtr template,
521 xmlNsPtr *ret = NULL;
526 if ((style == NULL) || (template == NULL) || (node == NULL) ||
527 (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
529 while (node != NULL) {
530 if (node->type == XML_ELEMENT_NODE) {
532 while (cur != NULL) {
533 if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
535 for (i = 0;i < style->exclPrefixNr;i++) {
536 if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
541 (xmlNsPtr *) xmlMalloc((maxns + 1) *
544 xmlGenericError(xmlGenericErrorContext,
545 "xmlGetNsList : out of memory!\n");
550 for (i = 0; i < nbns; i++) {
551 if ((cur->prefix == ret[i]->prefix) ||
552 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
558 ret = (xmlNsPtr *) xmlRealloc(ret,
563 xmlGenericError(xmlGenericErrorContext,
564 "xmlGetNsList : realloc failed!\n");
578 #ifdef WITH_XSLT_DEBUG_PARSING
579 xsltGenericDebug(xsltGenericDebugContext,
580 "template has %d inherited namespaces\n", nbns);
582 template->inheritedNsNr = nbns;
583 template->inheritedNs = ret;
589 * xsltParseStylesheetOutput:
590 * @style: the XSLT stylesheet
591 * @cur: the "output" element
593 * parse an XSLT stylesheet output element and record
594 * information related to the stylesheet output
598 xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
605 if ((cur == NULL) || (style == NULL))
608 prop = xsltGetNsProp(cur, (const xmlChar *) "version", XSLT_NAMESPACE);
610 if (style->version != NULL)
611 xmlFree(style->version);
612 style->version = prop;
616 xsltGetNsProp(cur, (const xmlChar *) "encoding", XSLT_NAMESPACE);
618 if (style->encoding != NULL)
619 xmlFree(style->encoding);
620 style->encoding = prop;
623 /* relaxed to support xt:document */
624 prop = xmlGetProp(cur, (const xmlChar *) "method");
628 if (style->method != NULL)
629 xmlFree(style->method);
630 style->method = NULL;
631 if (style->methodURI != NULL)
632 xmlFree(style->methodURI);
633 style->methodURI = NULL;
635 URI = xsltGetQNameURI(cur, &prop);
638 } else if (URI == NULL) {
639 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
640 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
641 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
642 style->method = prop;
644 xsltPrintErrorContext(NULL, style, cur);
645 xsltGenericError(xsltGenericErrorContext,
646 "invalid value for method: %s\n", prop);
650 style->method = prop;
651 style->methodURI = xmlStrdup(URI);
656 xsltGetNsProp(cur, (const xmlChar *) "doctype-system",
659 if (style->doctypeSystem != NULL)
660 xmlFree(style->doctypeSystem);
661 style->doctypeSystem = prop;
665 xsltGetNsProp(cur, (const xmlChar *) "doctype-public",
668 if (style->doctypePublic != NULL)
669 xmlFree(style->doctypePublic);
670 style->doctypePublic = prop;
673 prop = xsltGetNsProp(cur, (const xmlChar *) "standalone",
676 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
677 style->standalone = 1;
678 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
679 style->standalone = 0;
681 xsltPrintErrorContext(NULL, style, cur);
682 xsltGenericError(xsltGenericErrorContext,
683 "invalid value for standalone: %s\n", prop);
689 prop = xsltGetNsProp(cur, (const xmlChar *) "indent", XSLT_NAMESPACE);
691 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
693 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
696 xsltPrintErrorContext(NULL, style, cur);
697 xsltGenericError(xsltGenericErrorContext,
698 "invalid value for indent: %s\n", prop);
704 prop = xsltGetNsProp(cur, (const xmlChar *) "omit-xml-declaration",
707 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
708 style->omitXmlDeclaration = 1;
709 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
710 style->omitXmlDeclaration = 0;
712 xsltPrintErrorContext(NULL, style, cur);
713 xsltGenericError(xsltGenericErrorContext,
714 "invalid value for omit-xml-declaration: %s\n",
722 xsltGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
724 if (elements != NULL) {
725 if (style->cdataSection == NULL)
726 style->cdataSection = xmlHashCreate(10);
727 if (style->cdataSection == NULL)
731 while (*element != 0) {
732 while (IS_BLANK(*element))
737 while ((*end != 0) && (!IS_BLANK(*end)))
739 element = xmlStrndup(element, end - element);
742 #ifdef WITH_XSLT_DEBUG_PARSING
743 xsltGenericDebug(xsltGenericDebugContext,
744 "add cdata section output element %s\n",
748 URI = xsltGetQNameURI(cur, &element);
749 if (element == NULL) {
752 xmlHashAddEntry2(style->cdataSection, element, URI,
764 * xsltParseStylesheetDecimalFormat:
765 * @style: the XSLT stylesheet
766 * @cur: the "decimal-format" element
768 * parse an XSLT stylesheet decimal-format element and
769 * and record the formatting characteristics
772 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
775 xsltDecimalFormatPtr format;
776 xsltDecimalFormatPtr iter;
778 if ((cur == NULL) || (style == NULL))
781 format = style->decimalFormat;
783 prop = xsltGetNsProp(cur, BAD_CAST("name"), XSLT_NAMESPACE);
785 format = xsltDecimalFormatGetByName(style, prop);
786 if (format != NULL) {
787 xsltPrintErrorContext(NULL, style, cur);
788 xsltGenericError(xsltGenericErrorContext,
789 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
793 format = xsltNewDecimalFormat(prop);
794 if (format == NULL) {
795 xsltPrintErrorContext(NULL, style, cur);
796 xsltGenericError(xsltGenericErrorContext,
797 "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
801 /* Append new decimal-format structure */
802 for (iter = style->decimalFormat; iter->next; iter = iter->next)
808 prop = xsltGetNsProp(cur, (const xmlChar *)"decimal-separator",
811 if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
812 format->decimalPoint = prop;
815 prop = xsltGetNsProp(cur, (const xmlChar *)"grouping-separator",
818 if (format->grouping != NULL) xmlFree(format->grouping);
819 format->grouping = prop;
822 prop = xsltGetNsProp(cur, (const xmlChar *)"infinity", XSLT_NAMESPACE);
824 if (format->infinity != NULL) xmlFree(format->infinity);
825 format->infinity = prop;
828 prop = xsltGetNsProp(cur, (const xmlChar *)"minus-sign", XSLT_NAMESPACE);
830 if (format->minusSign != NULL) xmlFree(format->minusSign);
831 format->minusSign = prop;
834 prop = xsltGetNsProp(cur, (const xmlChar *)"NaN", XSLT_NAMESPACE);
836 if (format->noNumber != NULL) xmlFree(format->noNumber);
837 format->noNumber = prop;
840 prop = xsltGetNsProp(cur, (const xmlChar *)"percent", XSLT_NAMESPACE);
842 if (format->percent != NULL) xmlFree(format->percent);
843 format->percent = prop;
846 prop = xsltGetNsProp(cur, (const xmlChar *)"per-mille", XSLT_NAMESPACE);
848 if (format->permille != NULL) xmlFree(format->permille);
849 format->permille = prop;
852 prop = xsltGetNsProp(cur, (const xmlChar *)"zero-digit", XSLT_NAMESPACE);
854 if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
855 format->zeroDigit = prop;
858 prop = xsltGetNsProp(cur, (const xmlChar *)"digit", XSLT_NAMESPACE);
860 if (format->digit != NULL) xmlFree(format->digit);
861 format->digit = prop;
864 prop = xsltGetNsProp(cur, (const xmlChar *)"pattern-separator",
867 if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
868 format->patternSeparator = prop;
873 * xsltParseStylesheetPreserveSpace:
874 * @style: the XSLT stylesheet
875 * @cur: the "preserve-space" element
877 * parse an XSLT stylesheet preserve-space element and record
878 * elements needing preserving
882 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
884 xmlChar *element, *end;
886 if ((cur == NULL) || (style == NULL))
889 elements = xsltGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
890 if (elements == NULL) {
891 xsltPrintErrorContext(NULL, style, cur);
892 xsltGenericError(xsltGenericErrorContext,
893 "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
898 if (style->stripSpaces == NULL)
899 style->stripSpaces = xmlHashCreate(10);
900 if (style->stripSpaces == NULL)
904 while (*element != 0) {
905 while (IS_BLANK(*element)) element++;
909 while ((*end != 0) && (!IS_BLANK(*end))) end++;
910 element = xmlStrndup(element, end - element);
912 #ifdef WITH_XSLT_DEBUG_PARSING
913 xsltGenericDebug(xsltGenericDebugContext,
914 "add preserved space element %s\n", element);
916 if (xmlStrEqual(element, (const xmlChar *)"*")) {
917 style->stripAll = -1;
919 xmlHashAddEntry(style->stripSpaces, element,
920 (xmlChar *) "preserve");
930 * xsltParseStylesheetExtPrefix:
931 * @style: the XSLT stylesheet
932 * @template: the "extension-element-prefixes" prefix
934 * parse an XSLT stylesheet extension prefix and record
935 * prefixes needing stripping
939 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur) {
941 xmlChar *prefix, *end;
943 if ((cur == NULL) || (style == NULL))
946 prefixes = xsltGetNsProp(cur, (const xmlChar *)"extension-element-prefixes",
948 if (prefixes == NULL) {
953 while (*prefix != 0) {
954 while (IS_BLANK(*prefix)) prefix++;
958 while ((*end != 0) && (!IS_BLANK(*end))) end++;
959 prefix = xmlStrndup(prefix, end - prefix);
963 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
964 ns = xmlSearchNs(style->doc, cur, NULL);
966 ns = xmlSearchNs(style->doc, cur, prefix);
968 xsltPrintErrorContext(NULL, style, cur);
969 xsltGenericError(xsltGenericErrorContext,
970 "xsl:extension-element-prefix : undefined namespace %s\n",
974 #ifdef WITH_XSLT_DEBUG_PARSING
975 xsltGenericDebug(xsltGenericDebugContext,
976 "add extension prefix %s\n", prefix);
978 xsltRegisterExtPrefix(style, prefix, ns->href);
988 * xsltParseStylesheetStripSpace:
989 * @style: the XSLT stylesheet
990 * @cur: the "strip-space" element
992 * parse an XSLT stylesheet strip-space element and record
993 * elements needing stripping
997 xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
999 xmlChar *element, *end;
1001 if ((cur == NULL) || (style == NULL))
1004 elements = xsltGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
1005 if (elements == NULL) {
1006 xsltPrintErrorContext(NULL, style, cur);
1007 xsltGenericError(xsltGenericErrorContext,
1008 "xsltParseStylesheetStripSpace: missing elements attribute\n");
1013 if (style->stripSpaces == NULL)
1014 style->stripSpaces = xmlHashCreate(10);
1015 if (style->stripSpaces == NULL)
1019 while (*element != 0) {
1020 while (IS_BLANK(*element)) element++;
1024 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1025 element = xmlStrndup(element, end - element);
1027 #ifdef WITH_XSLT_DEBUG_PARSING
1028 xsltGenericDebug(xsltGenericDebugContext,
1029 "add stripped space element %s\n", element);
1031 if (xmlStrEqual(element, (const xmlChar *)"*")) {
1032 style->stripAll = 1;
1034 xmlHashAddEntry(style->stripSpaces, element,
1035 (xmlChar *) "strip");
1045 * xsltParseStylesheetExcludePrefix:
1046 * @style: the XSLT stylesheet
1047 * @cur: the current point in the stylesheet
1049 * parse an XSLT stylesheet exclude prefix and record
1050 * namespaces needing stripping
1052 * Returns the number of Excluded prefixes added at that level
1056 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur) {
1059 xmlChar *prefix, *end;
1061 if ((cur == NULL) || (style == NULL))
1064 prefixes = xsltGetNsProp(cur, (const xmlChar *)"exclude-result-prefixes",
1066 if (prefixes == NULL) {
1071 while (*prefix != 0) {
1072 while (IS_BLANK(*prefix)) prefix++;
1076 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1077 prefix = xmlStrndup(prefix, end - prefix);
1081 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1082 ns = xmlSearchNs(style->doc, cur, NULL);
1084 ns = xmlSearchNs(style->doc, cur, prefix);
1086 xsltPrintErrorContext(NULL, style, cur);
1087 xsltGenericError(xsltGenericErrorContext,
1088 "xsl:exclude-result-prefixes : undefined namespace %s\n",
1092 #ifdef WITH_XSLT_DEBUG_PARSING
1093 xsltGenericDebug(xsltGenericDebugContext,
1094 "exclude result prefix %s\n", prefix);
1096 exclPrefixPush(style, (xmlChar *) ns->href);
1108 * xsltPrecomputeStylesheet:
1109 * @style: the XSLT stylesheet
1110 * @cur: the current child list
1112 * Clean-up the stylesheet content from unwanted ignorable blank nodes
1113 * and run the preprocessing of all XSLT constructs.
1115 * and process xslt:text
1118 xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) {
1122 * This content comes from the stylesheet
1123 * For stylesheets, the set of whitespace-preserving
1124 * element names consists of just xsl:text.
1127 while (cur != NULL) {
1128 if (delete != NULL) {
1129 #ifdef WITH_XSLT_DEBUG_BLANKS
1130 xsltGenericDebug(xsltGenericDebugContext,
1131 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
1133 xmlUnlinkNode(delete);
1134 xmlFreeNode(delete);
1137 if (cur->type == XML_ELEMENT_NODE) {
1141 exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur);
1142 if (IS_XSLT_ELEM(cur)) {
1143 xsltStylePreCompute(style, cur);
1144 if (IS_XSLT_NAME(cur, "text")) {
1145 for (;exclPrefixes > 0;exclPrefixes--)
1146 prefix = exclPrefixPop(style);
1151 * Remove excluded prefixes
1153 if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
1154 xmlNsPtr ns = cur->nsDef, prev = NULL, next;
1155 xmlNodePtr root = NULL;
1158 root = xmlDocGetRootElement(cur->doc);
1159 if ((root != NULL) && (root != cur)) {
1160 while (ns != NULL) {
1163 for (i = 0;i < style->exclPrefixNr;i++) {
1164 if (xmlStrEqual(ns->href,
1165 style->exclPrefixTab[i])) {
1167 * Move the namespace definition on the root
1168 * element to avoid duplicating it without
1172 cur->nsDef = ns->next;
1174 prev->next = ns->next;
1176 ns->next = root->nsDef;
1190 * If we have prefixes locally, recurse and pop them up when
1193 if (exclPrefixes > 0) {
1194 xsltPrecomputeStylesheet(style, cur->children);
1195 for (;exclPrefixes > 0;exclPrefixes--)
1196 prefix = exclPrefixPop(style);
1199 } else if (cur->type == XML_TEXT_NODE) {
1200 if (IS_BLANK_NODE(cur)) {
1201 if (xmlNodeGetSpacePreserve(cur) != 1) {
1205 } else if ((cur->type != XML_ELEMENT_NODE) &&
1206 (cur->type != XML_CDATA_SECTION_NODE)) {
1214 if (cur->children != NULL) {
1215 if ((cur->children->type != XML_ENTITY_DECL) &&
1216 (cur->children->type != XML_ENTITY_REF_NODE) &&
1217 (cur->children->type != XML_ENTITY_NODE)) {
1218 cur = cur->children;
1223 if (cur->next != NULL) {
1232 if (cur == (xmlNodePtr) style->doc) {
1236 if (cur->next != NULL) {
1240 } while (cur != NULL);
1242 if (delete != NULL) {
1243 #ifdef WITH_XSLT_DEBUG_PARSING
1244 xsltGenericDebug(xsltGenericDebugContext,
1245 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
1247 xmlUnlinkNode(delete);
1248 xmlFreeNode(delete);
1254 * xsltGatherNamespaces:
1255 * @style: the XSLT stylesheet
1257 * Browse the stylesheet and build the namspace hash table which
1258 * will be used for XPath interpretation. If needed do a bit of normalization
1262 xsltGatherNamespaces(xsltStylesheetPtr style) {
1267 * TODO: basically if the stylesheet uses the same prefix for different
1268 * patterns, well they may be in problem, hopefully they will get
1271 cur = xmlDocGetRootElement(style->doc);
1272 while (cur != NULL) {
1273 if (cur->type == XML_ELEMENT_NODE) {
1274 xmlNsPtr ns = cur->nsDef;
1275 while (ns != NULL) {
1276 if (ns->prefix != NULL) {
1277 if (style->nsHash == NULL) {
1278 style->nsHash = xmlHashCreate(10);
1279 if (style->nsHash == NULL) {
1280 xsltPrintErrorContext(NULL, style, cur);
1281 xsltGenericError(xsltGenericErrorContext,
1282 "xsltGatherNamespaces: failed to create hash table\n");
1287 URI = xmlHashLookup(style->nsHash, ns->prefix);
1288 if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
1289 xsltPrintErrorContext(NULL, style, cur);
1290 xsltGenericError(xsltGenericErrorContext,
1291 "Namespaces prefix %s used for multiple namespaces\n");
1293 } else if (URI == NULL) {
1294 xmlHashUpdateEntry(style->nsHash, ns->prefix,
1295 (void *) ns->href, (xmlHashDeallocator)xmlFree);
1297 #ifdef WITH_XSLT_DEBUG_PARSING
1298 xsltGenericDebug(xsltGenericDebugContext,
1299 "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
1310 if (cur->children != NULL) {
1311 if (cur->children->type != XML_ENTITY_DECL) {
1312 cur = cur->children;
1316 if (cur->next != NULL) {
1325 if (cur == (xmlNodePtr) style->doc) {
1329 if (cur->next != NULL) {
1333 } while (cur != NULL);
1338 * xsltParseTemplateContent:
1339 * @style: the XSLT stylesheet
1340 * @templ: the container node (can be a document for literal results)
1342 * parse a template content-model
1343 * Clean-up the template content from unwanted ignorable blank nodes
1344 * and process xslt:text
1348 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
1349 xmlNodePtr cur, delete;
1351 * This content comes from the stylesheet
1352 * For stylesheets, the set of whitespace-preserving
1353 * element names consists of just xsl:text.
1355 cur = templ->children;
1357 while (cur != NULL) {
1358 if (delete != NULL) {
1359 #ifdef WITH_XSLT_DEBUG_BLANKS
1360 xsltGenericDebug(xsltGenericDebugContext,
1361 "xsltParseTemplateContent: removing text\n");
1363 xmlUnlinkNode(delete);
1364 xmlFreeNode(delete);
1367 if (IS_XSLT_ELEM(cur)) {
1368 if (IS_XSLT_NAME(cur, "text")) {
1369 if (cur->children != NULL) {
1371 xmlNodePtr text = cur->children, next;
1374 prop = xsltGetNsProp(cur,
1375 (const xmlChar *)"disable-output-escaping",
1378 #ifdef WITH_XSLT_DEBUG_PARSING
1379 xsltGenericDebug(xsltGenericDebugContext,
1380 "Disable escaping: %s\n", text->content);
1382 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
1384 } else if (!xmlStrEqual(prop,
1385 (const xmlChar *)"no")){
1386 xsltPrintErrorContext(NULL, style, cur);
1387 xsltGenericError(xsltGenericErrorContext,
1388 "xsl:text: disable-output-escaping allows only yes or no\n");
1395 while (text != NULL) {
1396 if ((text->type != XML_TEXT_NODE) &&
1397 (text->type != XML_CDATA_SECTION_NODE)) {
1398 xsltPrintErrorContext(NULL, style, cur);
1399 xsltGenericError(xsltGenericErrorContext,
1400 "xsltParseTemplateContent: xslt:text content problem\n");
1405 text->name = xmlStringTextNoenc;
1410 * replace xsl:text by the list of childs
1413 text = cur->children;
1414 while (text != NULL) {
1416 xmlUnlinkNode(text);
1417 xmlAddPrevSibling(cur, text);
1425 } else if ((cur->ns != NULL) && (style->nsDefs != NULL)) {
1426 if (xsltCheckExtPrefix(style, cur->ns->prefix)) {
1428 * okay this is an extension element compile it too
1430 xsltStylePreCompute(style, cur);
1437 if (cur->children != NULL) {
1438 if (cur->children->type != XML_ENTITY_DECL) {
1439 cur = cur->children;
1444 if (cur->next != NULL) {
1457 if (cur->next != NULL) {
1461 } while (cur != NULL);
1463 if (delete != NULL) {
1464 #ifdef WITH_XSLT_DEBUG_PARSING
1465 xsltGenericDebug(xsltGenericDebugContext,
1466 "xsltParseTemplateContent: removing text\n");
1468 xmlUnlinkNode(delete);
1469 xmlFreeNode(delete);
1474 * Skip the first params
1476 cur = templ->children;
1477 while (cur != NULL) {
1478 if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
1484 * Browse the remainder of the template
1486 while (cur != NULL) {
1487 if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
1488 xmlNodePtr param = cur;
1491 xsltPrintErrorContext(NULL, style, cur);
1492 xsltGenericError(xsltGenericErrorContext,
1493 "xsltParseTemplateContent: ignoring misplaced param element\n");
1495 xmlUnlinkNode(param);
1505 * xsltParseStylesheetKey:
1506 * @style: the XSLT stylesheet
1507 * @key: the "key" element
1509 * parse an XSLT stylesheet key definition and register it
1513 xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
1514 xmlChar *prop = NULL;
1515 xmlChar *use = NULL;
1516 xmlChar *match = NULL;
1517 xmlChar *name = NULL;
1518 xmlChar *nameURI = NULL;
1526 prop = xsltGetNsProp(key, (const xmlChar *)"name", XSLT_NAMESPACE);
1530 URI = xsltGetQNameURI(key, &prop);
1537 nameURI = xmlStrdup(URI);
1539 #ifdef WITH_XSLT_DEBUG_PARSING
1540 xsltGenericDebug(xsltGenericDebugContext,
1541 "xsltParseStylesheetKey: name %s\n", name);
1544 xsltPrintErrorContext(NULL, style, key);
1545 xsltGenericError(xsltGenericErrorContext,
1546 "xsl:key : error missing name\n");
1551 match = xsltGetNsProp(key, (const xmlChar *)"match", XSLT_NAMESPACE);
1552 if (match == NULL) {
1553 xsltPrintErrorContext(NULL, style, key);
1554 xsltGenericError(xsltGenericErrorContext,
1555 "xsl:key : error missing match\n");
1560 use = xsltGetNsProp(key, (const xmlChar *)"use", XSLT_NAMESPACE);
1562 xsltPrintErrorContext(NULL, style, key);
1563 xsltGenericError(xsltGenericErrorContext,
1564 "xsl:key : error missing use\n");
1572 xsltAddKey(style, name, nameURI, match, use, key);
1582 if (nameURI != NULL)
1587 * xsltParseStylesheetTemplate:
1588 * @style: the XSLT stylesheet
1589 * @template: the "template" element
1591 * parse an XSLT stylesheet template building the associated structures
1595 xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
1596 xsltTemplatePtr ret;
1598 xmlChar *mode = NULL;
1599 xmlChar *modeURI = NULL;
1603 if (template == NULL)
1607 * Create and link the structure
1609 ret = xsltNewTemplate();
1612 ret->next = style->templates;
1613 style->templates = ret;
1617 * Check excluded prefixes
1619 exclPrefixes = xsltParseStylesheetExcludePrefix(style, template);
1622 * Get inherited namespaces
1624 xsltGetInheritedNsList(style, ret, template);
1629 prop = xsltGetNsProp(template, (const xmlChar *)"mode", XSLT_NAMESPACE);
1633 URI = xsltGetQNameURI(template, &prop);
1640 modeURI = xmlStrdup(URI);
1643 ret->modeURI = modeURI;
1644 #ifdef WITH_XSLT_DEBUG_PARSING
1645 xsltGenericDebug(xsltGenericDebugContext,
1646 "xsltParseStylesheetTemplate: mode %s\n", mode);
1652 prop = xsltGetNsProp(template, (const xmlChar *)"match", XSLT_NAMESPACE);
1654 if (ret->match != NULL) xmlFree(ret->match);
1658 prop = xsltGetNsProp(template, (const xmlChar *)"priority", XSLT_NAMESPACE);
1660 priority = xmlXPathStringEvalNumber(prop);
1661 ret->priority = (float) priority;
1665 prop = xsltGetNsProp(template, (const xmlChar *)"name", XSLT_NAMESPACE);
1669 if (ret->name != NULL) xmlFree(ret->name);
1671 if (ret->nameURI != NULL) xmlFree(ret->nameURI);
1672 ret->nameURI = NULL;
1674 URI = xsltGetQNameURI(template, &prop);
1681 ret->nameURI = xmlStrdup(URI);
1683 ret->nameURI = NULL;
1688 * parse the content and register the pattern
1690 xsltParseTemplateContent(style, template);
1691 ret->elem = template;
1692 ret->content = template->children;
1693 xsltAddTemplate(style, ret, mode, modeURI);
1696 for (;exclPrefixes > 0;exclPrefixes--)
1697 exclPrefixPop(style);
1701 * xsltParseStylesheetTop:
1702 * @style: the XSLT stylesheet
1703 * @top: the top level "stylesheet" element
1705 * scan the top level elements of an XSL stylesheet
1709 xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
1712 #ifdef WITH_XSLT_DEBUG_PARSING
1719 prop = xsltGetNsProp(top, (const xmlChar *)"version", XSLT_NAMESPACE);
1721 xsltPrintErrorContext(NULL, style, top);
1722 xsltGenericError(xsltGenericErrorContext,
1723 "xsl:version is missing: document may not be a stylesheet\n");
1726 if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
1727 (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
1728 xsltPrintErrorContext(NULL, style, top);
1729 xsltGenericError(xsltGenericErrorContext,
1730 "xsl:version: only 1.0 features are supported\n");
1731 /* TODO set up compatibility when not XSLT 1.0 */
1737 xsltParseStylesheetExtPrefix(style, top);
1739 cur = top->children;
1742 * process xsl:import elements
1744 while (cur != NULL) {
1745 if (IS_BLANK_NODE(cur)) {
1749 if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
1750 xsltParseStylesheetImport(style, cur);
1756 * process other top-level elements
1758 while (cur != NULL) {
1759 if (IS_BLANK_NODE(cur)) {
1763 if (cur->type == XML_TEXT_NODE) {
1764 if (cur->content != NULL) {
1765 xsltPrintErrorContext(NULL, style, cur);
1766 xsltGenericError(xsltGenericErrorContext,
1767 "misplaced text element: '%s'\n", cur->content);
1773 if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
1774 xsltGenericError(xsltGenericErrorContext,
1775 "Found a top-level element %s with null namespace URI\n",
1781 if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
1782 xsltTopLevelFunction function;
1784 function = xsltExtModuleTopLevelLookup(cur->name,
1786 if (function != NULL)
1787 function(style, cur);
1789 #ifdef WITH_XSLT_DEBUG_PARSING
1790 xsltGenericDebug(xsltGenericDebugContext,
1791 "xsltParseStylesheetTop : found foreign element %s\n",
1797 if (IS_XSLT_NAME(cur, "import")) {
1798 xsltPrintErrorContext(NULL, style, cur);
1799 xsltGenericError(xsltGenericErrorContext,
1800 "xsltParseStylesheetTop: ignoring misplaced import element\n");
1802 } else if (IS_XSLT_NAME(cur, "include")) {
1803 xsltParseStylesheetInclude(style, cur);
1804 } else if (IS_XSLT_NAME(cur, "strip-space")) {
1805 xsltParseStylesheetStripSpace(style, cur);
1806 } else if (IS_XSLT_NAME(cur, "preserve-space")) {
1807 xsltParseStylesheetPreserveSpace(style, cur);
1808 } else if (IS_XSLT_NAME(cur, "output")) {
1809 xsltParseStylesheetOutput(style, cur);
1810 } else if (IS_XSLT_NAME(cur, "key")) {
1811 xsltParseStylesheetKey(style, cur);
1812 } else if (IS_XSLT_NAME(cur, "decimal-format")) {
1813 xsltParseStylesheetDecimalFormat(style, cur);
1814 } else if (IS_XSLT_NAME(cur, "attribute-set")) {
1815 xsltParseStylesheetAttributeSet(style, cur);
1816 } else if (IS_XSLT_NAME(cur, "variable")) {
1817 xsltParseGlobalVariable(style, cur);
1818 } else if (IS_XSLT_NAME(cur, "param")) {
1819 xsltParseGlobalParam(style, cur);
1820 } else if (IS_XSLT_NAME(cur, "template")) {
1821 #ifdef WITH_XSLT_DEBUG_PARSING
1824 xsltParseStylesheetTemplate(style, cur);
1825 } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
1826 xsltNamespaceAlias(style, cur);
1828 xsltPrintErrorContext(NULL, style, cur);
1829 xsltGenericError(xsltGenericErrorContext,
1830 "xsltParseStylesheetTop: ignoring unknown %s element\n",
1836 #ifdef WITH_XSLT_DEBUG_PARSING
1837 xsltGenericDebug(xsltGenericDebugContext,
1838 "parsed %d templates\n", templates);
1843 * xsltParseStylesheetProcess:
1844 * @ret: the XSLT stylesheet
1845 * @doc: and xmlDoc parsed XML
1847 * parse an XSLT stylesheet adding the associated structures
1849 * Returns a new XSLT stylesheet structure.
1853 xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
1862 * First steps, remove blank nodes,
1863 * locate the xsl:stylesheet element and the
1864 * namespace declaration.
1866 cur = xmlDocGetRootElement(doc);
1868 xsltPrintErrorContext(NULL, ret, (xmlNodePtr) doc);
1869 xsltGenericError(xsltGenericErrorContext,
1870 "xsltParseStylesheetProcess : empty stylesheet\n");
1872 xsltFreeStylesheet(ret);
1875 xsltParseStylesheetExcludePrefix(ret, cur);
1876 xsltPrecomputeStylesheet(ret, cur);
1878 if ((IS_XSLT_ELEM(cur)) &&
1879 ((IS_XSLT_NAME(cur, "stylesheet")) ||
1880 (IS_XSLT_NAME(cur, "transform")))) {
1881 #ifdef WITH_XSLT_DEBUG_PARSING
1882 xsltGenericDebug(xsltGenericDebugContext,
1883 "xsltParseStylesheetProcess : found stylesheet\n");
1886 xsltParseStylesheetTop(ret, cur);
1889 xsltTemplatePtr template;
1892 * the document itself might be the template, check xsl:version
1894 prop = xsltGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
1896 xsltPrintErrorContext(NULL, ret, cur);
1897 xsltGenericError(xsltGenericErrorContext,
1898 "xsltParseStylesheetProcess : document is not a stylesheet\n");
1900 xsltFreeStylesheet(ret);
1904 #ifdef WITH_XSLT_DEBUG_PARSING
1905 xsltGenericDebug(xsltGenericDebugContext,
1906 "xsltParseStylesheetProcess : document is stylesheet\n");
1909 if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) {
1910 xsltPrintErrorContext(NULL, ret, cur);
1911 xsltGenericError(xsltGenericErrorContext,
1912 "xsl:version: only 1.0 features are supported\n");
1913 /* TODO set up compatibility when not XSLT 1.0 */
1919 * Create and link the template
1921 template = xsltNewTemplate();
1922 if (template == NULL) {
1924 xsltFreeStylesheet(ret);
1927 template->next = ret->templates;
1928 ret->templates = template;
1929 template->match = xmlStrdup((const xmlChar *)"/");
1932 * parse the content and register the pattern
1934 xsltParseTemplateContent(ret, (xmlNodePtr) doc);
1935 template->elem = (xmlNodePtr) doc;
1936 template->content = doc->children;
1937 xsltAddTemplate(ret, template, NULL, NULL);
1944 * xsltParseStylesheetDoc:
1945 * @doc: and xmlDoc parsed XML
1947 * parse an XSLT stylesheet building the associated structures
1949 * Returns a new XSLT stylesheet structure.
1953 xsltParseStylesheetDoc(xmlDocPtr doc) {
1954 xsltStylesheetPtr ret;
1959 ret = xsltNewStylesheet();
1964 xsltGatherNamespaces(ret);
1965 ret = xsltParseStylesheetProcess(ret, doc);
1971 * xsltParseStylesheetFile:
1972 * @filename: the filename/URL to the stylesheet
1974 * Load and parse an XSLT stylesheet
1976 * Returns a new XSLT stylesheet structure.
1980 xsltParseStylesheetFile(const xmlChar* filename) {
1981 xsltStylesheetPtr ret;
1985 if (filename == NULL)
1988 #ifdef WITH_XSLT_DEBUG_PARSING
1989 xsltGenericDebug(xsltGenericDebugContext,
1990 "xsltParseStylesheetFile : parse %s\n", filename);
1993 doc = xmlParseFile((const char *) filename);
1995 xsltPrintErrorContext(NULL, NULL, NULL);
1996 xsltGenericError(xsltGenericErrorContext,
1997 "xsltParseStylesheetFile : cannot parse %s\n", filename);
2000 ret = xsltParseStylesheetDoc(doc);
2009 /************************************************************************
2011 * Handling of Stylesheet PI *
2013 ************************************************************************/
2016 #define SKIP(val) cur += (val)
2017 #define NXT(val) cur[(val)]
2018 #define SKIP_BLANKS \
2019 while (IS_BLANK(CUR)) NEXT
2020 #define NEXT ((*cur) ? cur++ : cur)
2023 * xsltParseStylesheetPI:
2024 * @value: the value of the PI
2026 * This function checks that the type is text/xml and extracts
2027 * the URI-Reference for the stylesheet
2029 * Returns the URI-Reference for the stylesheet or NULL (it need to
2030 * be freed by the caller)
2033 xsltParseStylesheetPI(const xmlChar *value) {
2035 const xmlChar *start;
2038 xmlChar *href = NULL;
2047 if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
2054 if ((CUR != '\'') && (CUR != '"'))
2059 while ((CUR != 0) && (CUR != tmp))
2063 val = xmlStrndup(start, cur - start);
2067 if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
2068 (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
2074 } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
2081 if ((CUR != '\'') && (CUR != '"'))
2086 while ((CUR != 0) && (CUR != tmp))
2091 href = xmlStrndup(start, cur - start);
2094 while ((CUR != 0) && (!IS_BLANK(CUR)))
2109 * xsltLoadStylesheetPI:
2110 * @doc: a document to process
2112 * This function tries to locate the stylesheet PI in the given document
2113 * If found, and if contained within the document, it will extract
2114 * that subtree to build the stylesheet to process @doc (doc itself will
2115 * be modified). If found but referencing an external document it will
2116 * attempt to load it and generate a stylesheet from it. In both cases,
2117 * the resulting stylesheet and the document need to be freed once the
2118 * transformation is done.
2120 * Returns a new XSLT stylesheet structure or NULL if not found.
2123 xsltLoadStylesheetPI(xmlDocPtr doc) {
2125 xsltStylesheetPtr ret = NULL;
2126 xmlChar *href = NULL;
2133 * Find the text/xml stylesheet PI id any before the root
2135 child = doc->children;
2136 while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
2137 if ((child->type == XML_PI_NODE) &&
2138 (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
2139 href = xsltParseStylesheetPI(child->content);
2143 child = child->next;
2147 * If found check the href to select processing
2150 #ifdef WITH_XSLT_DEBUG_PARSING
2151 xsltGenericDebug(xsltGenericDebugContext,
2152 "xsltLoadStylesheetPI : found PI href=%s\n", href);
2154 URI = xmlParseURI((const char *) href);
2156 xsltPrintErrorContext(NULL, NULL, child);
2157 xsltGenericError(xsltGenericErrorContext,
2158 "xml-stylesheet : href %s is not valid\n", href);
2162 if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
2163 (URI->opaque == NULL) && (URI->authority == NULL) &&
2164 (URI->server == NULL) && (URI->user == NULL) &&
2165 (URI->path == NULL) && (URI->query == NULL)) {
2168 #ifdef WITH_XSLT_DEBUG_PARSING
2169 xsltGenericDebug(xsltGenericDebugContext,
2170 "xsltLoadStylesheetPI : Reference to ID %s\n", href);
2172 if (URI->fragment[0] == '#')
2173 ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
2175 ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
2177 xsltPrintErrorContext(NULL, NULL, child);
2178 xsltGenericError(xsltGenericErrorContext,
2179 "xml-stylesheet : no ID %s found\n", URI->fragment);
2185 * move the subtree in a new document passed to
2186 * the stylesheet analyzer
2188 subtree = ID->parent;
2189 fake = xmlNewDoc(NULL);
2191 xmlUnlinkNode(subtree);
2192 xmlAddChild((xmlNodePtr) fake, subtree);
2193 ret = xsltParseStylesheetDoc(fake);
2199 xmlChar *URL, *base;
2202 * Reference to an external stylesheet
2205 base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
2206 URL = xmlBuildURI(href, base);
2208 #ifdef WITH_XSLT_DEBUG_PARSING
2209 xsltGenericDebug(xsltGenericDebugContext,
2210 "xsltLoadStylesheetPI : fetching %s\n", URL);
2212 ret = xsltParseStylesheetFile(URL);
2215 #ifdef WITH_XSLT_DEBUG_PARSING
2216 xsltGenericDebug(xsltGenericDebugContext,
2217 "xsltLoadStylesheetPI : fetching %s\n", href);
2219 ret = xsltParseStylesheetFile(href);