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"
45 #ifdef WITH_XSLT_DEBUG
46 #define WITH_XSLT_DEBUG_PARSING
47 /* #define WITH_XSLT_DEBUG_BLANKS */
50 const char *xsltEngineVersion = LIBXSLT_VERSION_STRING;
51 const int xsltLibxsltVersion = LIBXSLT_VERSION;
52 const int xsltLibxmlVersion = LIBXML_VERSION;
55 * Harmless but avoiding a problem when compiling against a
56 * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
58 #ifndef LIBXML_DEBUG_ENABLED
59 double xmlXPathStringEvalNumber(const xmlChar *str);
65 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
68 #define IS_BLANK_NODE(n) \
69 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
73 * @style: the transformation stylesheet
74 * @value: the excluded prefix to push on the stack
76 * Push an excluded prefix on the stack
78 * Returns the new index in the stack or 0 in case of error
81 exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)
83 if (style->exclPrefixMax == 0) {
84 style->exclPrefixMax = 4;
85 style->exclPrefixTab =
86 (xmlChar * *)xmlMalloc(style->exclPrefixMax *
87 sizeof(style->exclPrefixTab[0]));
88 if (style->exclPrefixTab == NULL) {
89 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
93 if (style->exclPrefixNr >= style->exclPrefixMax) {
94 style->exclPrefixMax *= 2;
95 style->exclPrefixTab =
96 (xmlChar * *)xmlRealloc(style->exclPrefixTab,
97 style->exclPrefixMax *
98 sizeof(style->exclPrefixTab[0]));
99 if (style->exclPrefixTab == NULL) {
100 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
104 style->exclPrefixTab[style->exclPrefixNr] = value;
105 style->exclPrefix = value;
106 return (style->exclPrefixNr++);
110 * @style: the transformation stylesheet
112 * Pop an excluded prefix value from the stack
114 * Returns the stored excluded prefix value
117 exclPrefixPop(xsltStylesheetPtr style)
121 if (style->exclPrefixNr <= 0)
123 style->exclPrefixNr--;
124 if (style->exclPrefixNr > 0)
125 style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
127 style->exclPrefix = NULL;
128 ret = style->exclPrefixTab[style->exclPrefixNr];
129 style->exclPrefixTab[style->exclPrefixNr] = 0;
133 /************************************************************************
137 ************************************************************************/
142 * Initializes the processor (e.g. registers built-in extensions,
147 static int initialized = 0;
149 if (initialized == 0) {
151 xsltRegisterAllExtras();
159 * Check if a string is ignorable
161 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
164 xsltIsBlank(xmlChar *str) {
168 if (!(IS_BLANK(*str))) return(0);
174 /************************************************************************
176 * Routines to handle XSLT data structures *
178 ************************************************************************/
179 static xsltDecimalFormatPtr
180 xsltNewDecimalFormat(xmlChar *name)
182 xsltDecimalFormatPtr self;
184 self = xmlMalloc(sizeof(xsltDecimalFormat));
190 self->digit = xmlStrdup(BAD_CAST("#"));
191 self->patternSeparator = xmlStrdup(BAD_CAST(";"));
192 self->decimalPoint = xmlStrdup(BAD_CAST("."));
193 self->grouping = xmlStrdup(BAD_CAST(","));
194 self->percent = xmlStrdup(BAD_CAST("%"));
195 self->permille = xmlStrdup(BAD_CAST("?"));
196 self->zeroDigit = xmlStrdup(BAD_CAST("0"));
197 self->minusSign = xmlStrdup(BAD_CAST("-"));
198 self->infinity = xmlStrdup(BAD_CAST("Infinity"));
199 self->noNumber = xmlStrdup(BAD_CAST("NaN"));
205 xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
209 xmlFree(self->digit);
210 if (self->patternSeparator)
211 xmlFree(self->patternSeparator);
212 if (self->decimalPoint)
213 xmlFree(self->decimalPoint);
215 xmlFree(self->grouping);
217 xmlFree(self->percent);
219 xmlFree(self->permille);
221 xmlFree(self->zeroDigit);
223 xmlFree(self->minusSign);
225 xmlFree(self->infinity);
227 xmlFree(self->noNumber);
235 xsltFreeDecimalFormatList(xsltStylesheetPtr self)
237 xsltDecimalFormatPtr iter;
238 xsltDecimalFormatPtr tmp;
243 iter = self->decimalFormat;
244 while (iter != NULL) {
246 xsltFreeDecimalFormat(iter);
252 * xsltDecimalFormatGetByName:
253 * @sheet: the XSLT stylesheet
254 * @name: the decimal-format name to find
256 * Find decimal-format by name
258 * Returns the xsltDecimalFormatPtr
261 xsltDecimalFormatGetByName(xsltStylesheetPtr sheet, xmlChar *name)
263 xsltDecimalFormatPtr result = NULL;
266 return sheet->decimalFormat;
268 while (sheet != NULL) {
269 for (result = sheet->decimalFormat->next;
271 result = result->next) {
272 if (xmlStrEqual(name, result->name))
275 sheet = xsltNextImport(sheet);
284 * Create a new XSLT Template
286 * Returns the newly allocated xsltTemplatePtr or NULL in case of error
288 static xsltTemplatePtr
289 xsltNewTemplate(void) {
292 cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
294 xsltTransformError(NULL, NULL, NULL,
295 "xsltNewTemplate : malloc failed\n");
298 memset(cur, 0, sizeof(xsltTemplate));
299 cur->priority = XSLT_PAT_NO_PRIORITY;
305 * @template: an XSLT template
307 * Free up the memory allocated by @template
310 xsltFreeTemplate(xsltTemplatePtr template) {
311 if (template == NULL)
313 if (template->match) xmlFree(template->match);
314 if (template->name) xmlFree(template->name);
315 if (template->nameURI) xmlFree(template->nameURI);
316 if (template->mode) xmlFree(template->mode);
317 if (template->modeURI) xmlFree(template->modeURI);
318 if (template->inheritedNs) xmlFree(template->inheritedNs);
319 memset(template, -1, sizeof(xsltTemplate));
324 * xsltFreeTemplateList:
325 * @template: an XSLT template list
327 * Free up the memory allocated by all the elements of @template
330 xsltFreeTemplateList(xsltTemplatePtr template) {
333 while (template != NULL) {
335 template = template->next;
336 xsltFreeTemplate(cur);
343 * Create a new XSLT Stylesheet
345 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
348 xsltNewStylesheet(void) {
349 xsltStylesheetPtr cur;
351 cur = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
353 xsltTransformError(NULL, NULL, NULL,
354 "xsltNewStylesheet : malloc failed\n");
357 memset(cur, 0, sizeof(xsltStylesheet));
358 cur->omitXmlDeclaration = -1;
359 cur->standalone = -1;
360 cur->decimalFormat = xsltNewDecimalFormat(NULL);
364 cur->exclPrefixNr = 0;
365 cur->exclPrefixMax = 0;
366 cur->exclPrefixTab = NULL;
367 cur->extInfos = NULL;
377 * @style: an XSLT stylesheet
379 * Allocate an extra runtime information slot statically while compiling
380 * the stylesheet and return its number
382 * Returns the number of the slot
385 xsltAllocateExtra(xsltStylesheetPtr style)
387 return(style->extrasNr++);
391 * xsltAllocateExtraCtxt:
392 * @ctxt: an XSLT transformation context
394 * Allocate an extra runtime information slot at run-time
395 * and return its number
396 * This make sure there is a slot ready in the transformation context
398 * Returns the number of the slot
401 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
403 if (ctxt->extrasNr >= ctxt->extrasMax) {
405 if (ctxt->extrasNr == 0) {
406 ctxt->extrasMax = 20;
407 ctxt->extras = (xsltRuntimeExtraPtr)
408 xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
409 if (ctxt->extras == NULL) {
410 xmlGenericError(xmlGenericErrorContext,
411 "xsltAllocateExtraCtxt: out of memory\n");
412 ctxt->state = XSLT_STATE_ERROR;
415 for (i = 0;i < ctxt->extrasMax;i++) {
416 ctxt->extras[i].info = NULL;
417 ctxt->extras[i].deallocate = NULL;
418 ctxt->extras[i].val = NULL;
422 xsltRuntimeExtraPtr tmp;
424 ctxt->extrasMax += 100;
425 tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
426 ctxt->extrasMax * sizeof(xsltRuntimeExtra));
428 xmlGenericError(xmlGenericErrorContext,
429 "xsltAllocateExtraCtxt: out of memory\n");
430 ctxt->state = XSLT_STATE_ERROR;
434 for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
435 ctxt->extras[i].info = NULL;
436 ctxt->extras[i].deallocate = NULL;
437 ctxt->extras[i].val = NULL;
441 return(ctxt->extrasNr++);
445 * xsltFreeStylesheetList:
446 * @sheet: an XSLT stylesheet list
448 * Free up the memory allocated by the list @sheet
451 xsltFreeStylesheetList(xsltStylesheetPtr sheet) {
452 xsltStylesheetPtr next;
454 while (sheet != NULL) {
456 xsltFreeStylesheet(sheet);
462 * xsltFreeStylesheet:
463 * @sheet: an XSLT stylesheet
465 * Free up the memory allocated by @sheet
468 xsltFreeStylesheet(xsltStylesheetPtr sheet)
475 xsltFreeTemplateHashes(sheet);
476 xsltFreeDecimalFormatList(sheet);
477 xsltFreeTemplateList(sheet->templates);
478 xsltFreeAttributeSetsHashes(sheet);
479 xsltFreeNamespaceAliasHashes(sheet);
480 xsltFreeStyleDocuments(sheet);
481 xsltFreeStylePreComps(sheet);
482 xsltShutdownExts(sheet);
483 if (sheet->doc != NULL)
484 xmlFreeDoc(sheet->doc);
485 if (sheet->variables != NULL)
486 xsltFreeStackElemList(sheet->variables);
487 if (sheet->cdataSection != NULL)
488 xmlHashFree(sheet->cdataSection, NULL);
489 if (sheet->stripSpaces != NULL)
490 xmlHashFree(sheet->stripSpaces, NULL);
491 if (sheet->nsHash != NULL)
492 xmlHashFree(sheet->nsHash, NULL);
494 if (sheet->exclPrefixTab != NULL)
495 xmlFree(sheet->exclPrefixTab);
496 if (sheet->method != NULL)
497 xmlFree(sheet->method);
498 if (sheet->methodURI != NULL)
499 xmlFree(sheet->methodURI);
500 if (sheet->version != NULL)
501 xmlFree(sheet->version);
502 if (sheet->encoding != NULL)
503 xmlFree(sheet->encoding);
504 if (sheet->doctypePublic != NULL)
505 xmlFree(sheet->doctypePublic);
506 if (sheet->doctypeSystem != NULL)
507 xmlFree(sheet->doctypeSystem);
508 if (sheet->mediaType != NULL)
509 xmlFree(sheet->mediaType);
511 if (sheet->imports != NULL)
512 xsltFreeStylesheetList(sheet->imports);
514 memset(sheet, -1, sizeof(xsltStylesheet));
518 /************************************************************************
520 * Parsing of an XSLT Stylesheet *
522 ************************************************************************/
525 * xsltGetInheritedNsList:
526 * @style: the stylesheet
527 * @template: the template
528 * @node: the current node
530 * Search all the namespace applying to a given element except the ones
531 * from excluded output prefixes currently in scope. Initialize the
532 * template inheritedNs list with it.
534 * Returns the number of entries found
537 xsltGetInheritedNsList(xsltStylesheetPtr style,
538 xsltTemplatePtr template,
542 xmlNsPtr *ret = NULL;
547 if ((style == NULL) || (template == NULL) || (node == NULL) ||
548 (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
550 while (node != NULL) {
551 if (node->type == XML_ELEMENT_NODE) {
553 while (cur != NULL) {
554 if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
556 if ((cur->prefix != NULL) &&
557 (xsltCheckExtPrefix(style, cur->prefix)))
559 for (i = 0;i < style->exclPrefixNr;i++) {
560 if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
565 (xmlNsPtr *) xmlMalloc((maxns + 1) *
568 xmlGenericError(xmlGenericErrorContext,
569 "xmlGetNsList : out of memory!\n");
574 for (i = 0; i < nbns; i++) {
575 if ((cur->prefix == ret[i]->prefix) ||
576 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
582 ret = (xmlNsPtr *) xmlRealloc(ret,
587 xmlGenericError(xmlGenericErrorContext,
588 "xmlGetNsList : realloc failed!\n");
602 #ifdef WITH_XSLT_DEBUG_PARSING
603 xsltGenericDebug(xsltGenericDebugContext,
604 "template has %d inherited namespaces\n", nbns);
606 template->inheritedNsNr = nbns;
607 template->inheritedNs = ret;
613 * xsltParseStylesheetOutput:
614 * @style: the XSLT stylesheet
615 * @cur: the "output" element
617 * parse an XSLT stylesheet output element and record
618 * information related to the stylesheet output
622 xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
629 if ((cur == NULL) || (style == NULL))
632 prop = xsltGetNsProp(cur, (const xmlChar *) "version", XSLT_NAMESPACE);
634 if (style->version != NULL)
635 xmlFree(style->version);
636 style->version = prop;
640 xsltGetNsProp(cur, (const xmlChar *) "encoding", XSLT_NAMESPACE);
642 if (style->encoding != NULL)
643 xmlFree(style->encoding);
644 style->encoding = prop;
647 /* relaxed to support xt:document */
648 prop = xmlGetProp(cur, (const xmlChar *) "method");
652 if (style->method != NULL)
653 xmlFree(style->method);
654 style->method = NULL;
655 if (style->methodURI != NULL)
656 xmlFree(style->methodURI);
657 style->methodURI = NULL;
659 URI = xsltGetQNameURI(cur, &prop);
661 if (style != NULL) style->errors++;
662 } else if (URI == NULL) {
663 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
664 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
665 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
666 style->method = prop;
668 xsltTransformError(NULL, style, cur,
669 "invalid value for method: %s\n", prop);
670 if (style != NULL) style->warnings++;
673 style->method = prop;
674 style->methodURI = xmlStrdup(URI);
679 xsltGetNsProp(cur, (const xmlChar *) "doctype-system",
682 if (style->doctypeSystem != NULL)
683 xmlFree(style->doctypeSystem);
684 style->doctypeSystem = prop;
688 xsltGetNsProp(cur, (const xmlChar *) "doctype-public",
691 if (style->doctypePublic != NULL)
692 xmlFree(style->doctypePublic);
693 style->doctypePublic = prop;
696 prop = xsltGetNsProp(cur, (const xmlChar *) "standalone",
699 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
700 style->standalone = 1;
701 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
702 style->standalone = 0;
704 xsltTransformError(NULL, style, cur,
705 "invalid value for standalone: %s\n", prop);
706 if (style != NULL) style->warnings++;
711 prop = xsltGetNsProp(cur, (const xmlChar *) "indent", XSLT_NAMESPACE);
713 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
715 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
718 xsltTransformError(NULL, style, cur,
719 "invalid value for indent: %s\n", prop);
720 if (style != NULL) style->warnings++;
725 prop = xsltGetNsProp(cur, (const xmlChar *) "omit-xml-declaration",
728 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
729 style->omitXmlDeclaration = 1;
730 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
731 style->omitXmlDeclaration = 0;
733 xsltTransformError(NULL, style, cur,
734 "invalid value for omit-xml-declaration: %s\n",
736 if (style != NULL) style->warnings++;
742 xsltGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
744 if (elements != NULL) {
745 if (style->cdataSection == NULL)
746 style->cdataSection = xmlHashCreate(10);
747 if (style->cdataSection == NULL)
751 while (*element != 0) {
752 while (IS_BLANK(*element))
757 while ((*end != 0) && (!IS_BLANK(*end)))
759 element = xmlStrndup(element, end - element);
762 #ifdef WITH_XSLT_DEBUG_PARSING
763 xsltGenericDebug(xsltGenericDebugContext,
764 "add cdata section output element %s\n",
768 URI = xsltGetQNameURI(cur, &element);
769 if (element == NULL) {
770 if (style != NULL) style->errors++;
772 xmlHashAddEntry2(style->cdataSection, element, URI,
782 prop = xsltGetNsProp(cur, (const xmlChar *) "media-type", XSLT_NAMESPACE);
784 if (style->mediaType)
785 xmlFree(style->mediaType);
786 style->mediaType = prop;
791 * xsltParseStylesheetDecimalFormat:
792 * @style: the XSLT stylesheet
793 * @cur: the "decimal-format" element
795 * parse an XSLT stylesheet decimal-format element and
796 * and record the formatting characteristics
799 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
802 xsltDecimalFormatPtr format;
803 xsltDecimalFormatPtr iter;
805 if ((cur == NULL) || (style == NULL))
808 format = style->decimalFormat;
810 prop = xsltGetNsProp(cur, BAD_CAST("name"), XSLT_NAMESPACE);
812 format = xsltDecimalFormatGetByName(style, prop);
813 if (format != NULL) {
814 xsltTransformError(NULL, style, cur,
815 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
816 if (style != NULL) style->warnings++;
819 format = xsltNewDecimalFormat(prop);
820 if (format == NULL) {
821 xsltTransformError(NULL, style, cur,
822 "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
823 if (style != NULL) style->errors++;
826 /* Append new decimal-format structure */
827 for (iter = style->decimalFormat; iter->next; iter = iter->next)
833 prop = xsltGetNsProp(cur, (const xmlChar *)"decimal-separator",
836 if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
837 format->decimalPoint = prop;
840 prop = xsltGetNsProp(cur, (const xmlChar *)"grouping-separator",
843 if (format->grouping != NULL) xmlFree(format->grouping);
844 format->grouping = prop;
847 prop = xsltGetNsProp(cur, (const xmlChar *)"infinity", XSLT_NAMESPACE);
849 if (format->infinity != NULL) xmlFree(format->infinity);
850 format->infinity = prop;
853 prop = xsltGetNsProp(cur, (const xmlChar *)"minus-sign", XSLT_NAMESPACE);
855 if (format->minusSign != NULL) xmlFree(format->minusSign);
856 format->minusSign = prop;
859 prop = xsltGetNsProp(cur, (const xmlChar *)"NaN", XSLT_NAMESPACE);
861 if (format->noNumber != NULL) xmlFree(format->noNumber);
862 format->noNumber = prop;
865 prop = xsltGetNsProp(cur, (const xmlChar *)"percent", XSLT_NAMESPACE);
867 if (format->percent != NULL) xmlFree(format->percent);
868 format->percent = prop;
871 prop = xsltGetNsProp(cur, (const xmlChar *)"per-mille", XSLT_NAMESPACE);
873 if (format->permille != NULL) xmlFree(format->permille);
874 format->permille = prop;
877 prop = xsltGetNsProp(cur, (const xmlChar *)"zero-digit", XSLT_NAMESPACE);
879 if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
880 format->zeroDigit = prop;
883 prop = xsltGetNsProp(cur, (const xmlChar *)"digit", XSLT_NAMESPACE);
885 if (format->digit != NULL) xmlFree(format->digit);
886 format->digit = prop;
889 prop = xsltGetNsProp(cur, (const xmlChar *)"pattern-separator",
892 if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
893 format->patternSeparator = prop;
898 * xsltParseStylesheetPreserveSpace:
899 * @style: the XSLT stylesheet
900 * @cur: the "preserve-space" element
902 * parse an XSLT stylesheet preserve-space element and record
903 * elements needing preserving
907 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
909 xmlChar *element, *end;
911 if ((cur == NULL) || (style == NULL))
914 elements = xsltGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
915 if (elements == NULL) {
916 xsltTransformError(NULL, style, cur,
917 "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
918 if (style != NULL) style->warnings++;
922 if (style->stripSpaces == NULL)
923 style->stripSpaces = xmlHashCreate(10);
924 if (style->stripSpaces == NULL)
928 while (*element != 0) {
929 while (IS_BLANK(*element)) element++;
933 while ((*end != 0) && (!IS_BLANK(*end))) end++;
934 element = xmlStrndup(element, end - element);
936 #ifdef WITH_XSLT_DEBUG_PARSING
937 xsltGenericDebug(xsltGenericDebugContext,
938 "add preserved space element %s\n", element);
940 if (xmlStrEqual(element, (const xmlChar *)"*")) {
941 style->stripAll = -1;
945 URI = xsltGetQNameURI(cur, &element);
947 xmlHashAddEntry2(style->stripSpaces, element, URI,
948 (xmlChar *) "preserve");
958 * xsltParseStylesheetExtPrefix:
959 * @style: the XSLT stylesheet
960 * @template: the "extension-element-prefixes" prefix
962 * parse an XSLT stylesheet extension prefix and record
963 * prefixes needing stripping
967 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur) {
969 xmlChar *prefix, *end;
971 if ((cur == NULL) || (style == NULL))
974 prefixes = xsltGetNsProp(cur, (const xmlChar *)"extension-element-prefixes",
976 if (prefixes == NULL) {
981 while (*prefix != 0) {
982 while (IS_BLANK(*prefix)) prefix++;
986 while ((*end != 0) && (!IS_BLANK(*end))) end++;
987 prefix = xmlStrndup(prefix, end - prefix);
991 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
992 ns = xmlSearchNs(style->doc, cur, NULL);
994 ns = xmlSearchNs(style->doc, cur, prefix);
996 xsltTransformError(NULL, style, cur,
997 "xsl:extension-element-prefix : undefined namespace %s\n",
999 if (style != NULL) style->warnings++;
1001 #ifdef WITH_XSLT_DEBUG_PARSING
1002 xsltGenericDebug(xsltGenericDebugContext,
1003 "add extension prefix %s\n", prefix);
1005 xsltRegisterExtPrefix(style, prefix, ns->href);
1015 * xsltParseStylesheetStripSpace:
1016 * @style: the XSLT stylesheet
1017 * @cur: the "strip-space" element
1019 * parse an XSLT stylesheet strip-space element and record
1020 * elements needing stripping
1024 xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1026 xmlChar *element, *end;
1028 if ((cur == NULL) || (style == NULL))
1031 elements = xsltGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
1032 if (elements == NULL) {
1033 xsltTransformError(NULL, style, cur,
1034 "xsltParseStylesheetStripSpace: missing elements attribute\n");
1035 if (style != NULL) style->warnings++;
1039 if (style->stripSpaces == NULL)
1040 style->stripSpaces = xmlHashCreate(10);
1041 if (style->stripSpaces == NULL)
1045 while (*element != 0) {
1046 while (IS_BLANK(*element)) element++;
1050 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1051 element = xmlStrndup(element, end - element);
1053 #ifdef WITH_XSLT_DEBUG_PARSING
1054 xsltGenericDebug(xsltGenericDebugContext,
1055 "add stripped space element %s\n", element);
1057 if (xmlStrEqual(element, (const xmlChar *)"*")) {
1058 style->stripAll = 1;
1062 URI = xsltGetQNameURI(cur, &element);
1064 xmlHashAddEntry2(style->stripSpaces, element, URI,
1065 (xmlChar *) "strip");
1075 * xsltParseStylesheetExcludePrefix:
1076 * @style: the XSLT stylesheet
1077 * @cur: the current point in the stylesheet
1079 * parse an XSLT stylesheet exclude prefix and record
1080 * namespaces needing stripping
1082 * Returns the number of Excluded prefixes added at that level
1086 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur) {
1089 xmlChar *prefix, *end;
1091 if ((cur == NULL) || (style == NULL))
1094 prefixes = xsltGetNsProp(cur, (const xmlChar *)"exclude-result-prefixes",
1096 if (prefixes == NULL) {
1101 while (*prefix != 0) {
1102 while (IS_BLANK(*prefix)) prefix++;
1106 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1107 prefix = xmlStrndup(prefix, end - prefix);
1111 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1112 ns = xmlSearchNs(style->doc, cur, NULL);
1114 ns = xmlSearchNs(style->doc, cur, prefix);
1116 xsltTransformError(NULL, style, cur,
1117 "xsl:exclude-result-prefixes : undefined namespace %s\n",
1119 if (style != NULL) style->warnings++;
1121 #ifdef WITH_XSLT_DEBUG_PARSING
1122 xsltGenericDebug(xsltGenericDebugContext,
1123 "exclude result prefix %s\n", prefix);
1125 exclPrefixPush(style, (xmlChar *) ns->href);
1137 * xsltPrecomputeStylesheet:
1138 * @style: the XSLT stylesheet
1139 * @cur: the current child list
1141 * Clean-up the stylesheet content from unwanted ignorable blank nodes
1142 * and run the preprocessing of all XSLT constructs.
1144 * and process xslt:text
1147 xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) {
1151 * This content comes from the stylesheet
1152 * For stylesheets, the set of whitespace-preserving
1153 * element names consists of just xsl:text.
1156 while (cur != NULL) {
1157 if (delete != NULL) {
1158 #ifdef WITH_XSLT_DEBUG_BLANKS
1159 xsltGenericDebug(xsltGenericDebugContext,
1160 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
1162 xmlUnlinkNode(delete);
1163 xmlFreeNode(delete);
1166 if (cur->type == XML_ELEMENT_NODE) {
1169 exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur);
1170 if (IS_XSLT_ELEM(cur)) {
1171 xsltStylePreCompute(style, cur);
1172 if (IS_XSLT_NAME(cur, "text")) {
1173 for (;exclPrefixes > 0;exclPrefixes--)
1174 exclPrefixPop(style);
1179 * Remove excluded prefixes
1181 if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
1182 xmlNsPtr ns = cur->nsDef, prev = NULL, next;
1183 xmlNodePtr root = NULL;
1186 root = xmlDocGetRootElement(cur->doc);
1187 if ((root != NULL) && (root != cur)) {
1188 while (ns != NULL) {
1191 for (i = 0;i < style->exclPrefixNr;i++) {
1192 if (xmlStrEqual(ns->href,
1193 style->exclPrefixTab[i])) {
1195 * Move the namespace definition on the root
1196 * element to avoid duplicating it without
1200 cur->nsDef = ns->next;
1202 prev->next = ns->next;
1204 ns->next = root->nsDef;
1218 * If we have prefixes locally, recurse and pop them up when
1221 if (exclPrefixes > 0) {
1222 xsltPrecomputeStylesheet(style, cur->children);
1223 for (;exclPrefixes > 0;exclPrefixes--)
1224 exclPrefixPop(style);
1227 } else if (cur->type == XML_TEXT_NODE) {
1228 if (IS_BLANK_NODE(cur)) {
1229 if (xmlNodeGetSpacePreserve(cur) != 1) {
1233 } else if ((cur->type != XML_ELEMENT_NODE) &&
1234 (cur->type != XML_CDATA_SECTION_NODE)) {
1242 if (cur->children != NULL) {
1243 if ((cur->children->type != XML_ENTITY_DECL) &&
1244 (cur->children->type != XML_ENTITY_REF_NODE) &&
1245 (cur->children->type != XML_ENTITY_NODE)) {
1246 cur = cur->children;
1251 if (cur->next != NULL) {
1260 if (cur == (xmlNodePtr) style->doc) {
1264 if (cur->next != NULL) {
1268 } while (cur != NULL);
1270 if (delete != NULL) {
1271 #ifdef WITH_XSLT_DEBUG_PARSING
1272 xsltGenericDebug(xsltGenericDebugContext,
1273 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
1275 xmlUnlinkNode(delete);
1276 xmlFreeNode(delete);
1282 * xsltGatherNamespaces:
1283 * @style: the XSLT stylesheet
1285 * Browse the stylesheet and build the namspace hash table which
1286 * will be used for XPath interpretation. If needed do a bit of normalization
1290 xsltGatherNamespaces(xsltStylesheetPtr style) {
1295 * TODO: basically if the stylesheet uses the same prefix for different
1296 * patterns, well they may be in problem, hopefully they will get
1299 cur = xmlDocGetRootElement(style->doc);
1300 while (cur != NULL) {
1301 if (cur->type == XML_ELEMENT_NODE) {
1302 xmlNsPtr ns = cur->nsDef;
1303 while (ns != NULL) {
1304 if (ns->prefix != NULL) {
1305 if (style->nsHash == NULL) {
1306 style->nsHash = xmlHashCreate(10);
1307 if (style->nsHash == NULL) {
1308 xsltTransformError(NULL, style, cur,
1309 "xsltGatherNamespaces: failed to create hash table\n");
1310 if (style != NULL) style->errors++;
1314 URI = xmlHashLookup(style->nsHash, ns->prefix);
1315 if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
1316 xsltTransformError(NULL, style, cur,
1317 "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
1318 if (style != NULL) style->warnings++;
1319 } else if (URI == NULL) {
1320 xmlHashUpdateEntry(style->nsHash, ns->prefix,
1321 (void *) ns->href, (xmlHashDeallocator)xmlFree);
1323 #ifdef WITH_XSLT_DEBUG_PARSING
1324 xsltGenericDebug(xsltGenericDebugContext,
1325 "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
1336 if (cur->children != NULL) {
1337 if (cur->children->type != XML_ENTITY_DECL) {
1338 cur = cur->children;
1342 if (cur->next != NULL) {
1351 if (cur == (xmlNodePtr) style->doc) {
1355 if (cur->next != NULL) {
1359 } while (cur != NULL);
1364 * xsltParseTemplateContent:
1365 * @style: the XSLT stylesheet
1366 * @templ: the container node (can be a document for literal results)
1368 * parse a template content-model
1369 * Clean-up the template content from unwanted ignorable blank nodes
1370 * and process xslt:text
1374 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
1375 xmlNodePtr cur, delete;
1377 * This content comes from the stylesheet
1378 * For stylesheets, the set of whitespace-preserving
1379 * element names consists of just xsl:text.
1381 cur = templ->children;
1383 while (cur != NULL) {
1384 if (delete != NULL) {
1385 #ifdef WITH_XSLT_DEBUG_BLANKS
1386 xsltGenericDebug(xsltGenericDebugContext,
1387 "xsltParseTemplateContent: removing text\n");
1389 xmlUnlinkNode(delete);
1390 xmlFreeNode(delete);
1393 if (IS_XSLT_ELEM(cur)) {
1394 if (IS_XSLT_NAME(cur, "text")) {
1395 if (cur->children != NULL) {
1397 xmlNodePtr text = cur->children, next;
1400 prop = xsltGetNsProp(cur,
1401 (const xmlChar *)"disable-output-escaping",
1404 #ifdef WITH_XSLT_DEBUG_PARSING
1405 xsltGenericDebug(xsltGenericDebugContext,
1406 "Disable escaping: %s\n", text->content);
1408 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
1410 } else if (!xmlStrEqual(prop,
1411 (const xmlChar *)"no")){
1412 xsltTransformError(NULL, style, cur,
1413 "xsl:text: disable-output-escaping allows only yes or no\n");
1414 if (style != NULL) style->warnings++;
1420 while (text != NULL) {
1421 if (text->type == XML_COMMENT_NODE) {
1425 if ((text->type != XML_TEXT_NODE) &&
1426 (text->type != XML_CDATA_SECTION_NODE)) {
1427 xsltTransformError(NULL, style, cur,
1428 "xsltParseTemplateContent: xslt:text content problem\n");
1429 if (style != NULL) style->errors++;
1433 text->name = xmlStringTextNoenc;
1438 * replace xsl:text by the list of childs
1441 text = cur->children;
1442 while (text != NULL) {
1444 xmlUnlinkNode(text);
1445 xmlAddPrevSibling(cur, text);
1453 } else if ((cur->ns != NULL) && (style->nsDefs != NULL)) {
1454 if (xsltCheckExtPrefix(style, cur->ns->prefix)) {
1456 * okay this is an extension element compile it too
1458 xsltStylePreCompute(style, cur);
1465 if (cur->children != NULL) {
1466 if (cur->children->type != XML_ENTITY_DECL) {
1467 cur = cur->children;
1472 if (cur->next != NULL) {
1485 if (cur->next != NULL) {
1489 } while (cur != NULL);
1491 if (delete != NULL) {
1492 #ifdef WITH_XSLT_DEBUG_PARSING
1493 xsltGenericDebug(xsltGenericDebugContext,
1494 "xsltParseTemplateContent: removing text\n");
1496 xmlUnlinkNode(delete);
1497 xmlFreeNode(delete);
1502 * Skip the first params
1504 cur = templ->children;
1505 while (cur != NULL) {
1506 if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
1512 * Browse the remainder of the template
1514 while (cur != NULL) {
1515 if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
1516 xmlNodePtr param = cur;
1518 xsltTransformError(NULL, style, cur,
1519 "xsltParseTemplateContent: ignoring misplaced param element\n");
1520 if (style != NULL) style->warnings++;
1522 xmlUnlinkNode(param);
1530 * xsltParseStylesheetKey:
1531 * @style: the XSLT stylesheet
1532 * @key: the "key" element
1534 * parse an XSLT stylesheet key definition and register it
1538 xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
1539 xmlChar *prop = NULL;
1540 xmlChar *use = NULL;
1541 xmlChar *match = NULL;
1542 xmlChar *name = NULL;
1543 xmlChar *nameURI = NULL;
1551 prop = xsltGetNsProp(key, (const xmlChar *)"name", XSLT_NAMESPACE);
1555 URI = xsltGetQNameURI(key, &prop);
1557 if (style != NULL) style->errors++;
1562 nameURI = xmlStrdup(URI);
1564 #ifdef WITH_XSLT_DEBUG_PARSING
1565 xsltGenericDebug(xsltGenericDebugContext,
1566 "xsltParseStylesheetKey: name %s\n", name);
1569 xsltTransformError(NULL, style, key,
1570 "xsl:key : error missing name\n");
1571 if (style != NULL) style->errors++;
1575 match = xsltGetNsProp(key, (const xmlChar *)"match", XSLT_NAMESPACE);
1576 if (match == NULL) {
1577 xsltTransformError(NULL, style, key,
1578 "xsl:key : error missing match\n");
1579 if (style != NULL) style->errors++;
1583 use = xsltGetNsProp(key, (const xmlChar *)"use", XSLT_NAMESPACE);
1585 xsltTransformError(NULL, style, key,
1586 "xsl:key : error missing use\n");
1587 if (style != NULL) style->errors++;
1594 xsltAddKey(style, name, nameURI, match, use, key);
1604 if (nameURI != NULL)
1609 * xsltParseStylesheetTemplate:
1610 * @style: the XSLT stylesheet
1611 * @template: the "template" element
1613 * parse an XSLT stylesheet template building the associated structures
1617 xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
1618 xsltTemplatePtr ret;
1620 xmlChar *mode = NULL;
1621 xmlChar *modeURI = NULL;
1625 if (template == NULL)
1629 * Create and link the structure
1631 ret = xsltNewTemplate();
1634 ret->next = style->templates;
1635 style->templates = ret;
1639 * Check excluded prefixes
1641 exclPrefixes = xsltParseStylesheetExcludePrefix(style, template);
1644 * Get inherited namespaces
1646 xsltGetInheritedNsList(style, ret, template);
1651 prop = xsltGetNsProp(template, (const xmlChar *)"mode", XSLT_NAMESPACE);
1655 URI = xsltGetQNameURI(template, &prop);
1657 if (style != NULL) style->errors++;
1662 modeURI = xmlStrdup(URI);
1665 ret->modeURI = modeURI;
1666 #ifdef WITH_XSLT_DEBUG_PARSING
1667 xsltGenericDebug(xsltGenericDebugContext,
1668 "xsltParseStylesheetTemplate: mode %s\n", mode);
1674 prop = xsltGetNsProp(template, (const xmlChar *)"match", XSLT_NAMESPACE);
1676 if (ret->match != NULL) xmlFree(ret->match);
1680 prop = xsltGetNsProp(template, (const xmlChar *)"priority", XSLT_NAMESPACE);
1682 priority = xmlXPathStringEvalNumber(prop);
1683 ret->priority = (float) priority;
1687 prop = xsltGetNsProp(template, (const xmlChar *)"name", XSLT_NAMESPACE);
1691 if (ret->name != NULL) xmlFree(ret->name);
1693 if (ret->nameURI != NULL) xmlFree(ret->nameURI);
1694 ret->nameURI = NULL;
1696 URI = xsltGetQNameURI(template, &prop);
1698 if (style != NULL) style->errors++;
1703 ret->nameURI = xmlStrdup(URI);
1705 ret->nameURI = NULL;
1710 * parse the content and register the pattern
1712 xsltParseTemplateContent(style, template);
1713 ret->elem = template;
1714 ret->content = template->children;
1715 xsltAddTemplate(style, ret, mode, modeURI);
1718 for (;exclPrefixes > 0;exclPrefixes--)
1719 exclPrefixPop(style);
1723 * xsltParseStylesheetTop:
1724 * @style: the XSLT stylesheet
1725 * @top: the top level "stylesheet" element
1727 * scan the top level elements of an XSL stylesheet
1731 xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
1734 #ifdef WITH_XSLT_DEBUG_PARSING
1741 prop = xsltGetNsProp(top, (const xmlChar *)"version", XSLT_NAMESPACE);
1743 xsltTransformError(NULL, style, top,
1744 "xsl:version is missing: document may not be a stylesheet\n");
1745 if (style != NULL) style->warnings++;
1747 if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
1748 (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
1749 xsltTransformError(NULL, style, top,
1750 "xsl:version: only 1.0 features are supported\n");
1751 /* TODO set up compatibility when not XSLT 1.0 */
1752 if (style != NULL) style->warnings++;
1757 xsltParseStylesheetExtPrefix(style, top);
1759 cur = top->children;
1762 * process xsl:import elements
1764 while (cur != NULL) {
1765 if (IS_BLANK_NODE(cur)) {
1769 if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
1770 if (xsltParseStylesheetImport(style, cur) != 0)
1771 if (style != NULL) style->errors++;
1778 * process other top-level elements
1780 while (cur != NULL) {
1781 if (IS_BLANK_NODE(cur)) {
1785 if (cur->type == XML_TEXT_NODE) {
1786 if (cur->content != NULL) {
1787 xsltTransformError(NULL, style, cur,
1788 "misplaced text element: '%s'\n", cur->content);
1790 if (style != NULL) style->errors++;
1794 if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
1795 xsltGenericError(xsltGenericErrorContext,
1796 "Found a top-level element %s with null namespace URI\n",
1798 if (style != NULL) style->errors++;
1802 if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
1803 xsltTopLevelFunction function;
1805 function = xsltExtModuleTopLevelLookup(cur->name,
1807 if (function != NULL)
1808 function(style, cur);
1810 #ifdef WITH_XSLT_DEBUG_PARSING
1811 xsltGenericDebug(xsltGenericDebugContext,
1812 "xsltParseStylesheetTop : found foreign element %s\n",
1818 if (IS_XSLT_NAME(cur, "import")) {
1819 xsltTransformError(NULL, style, cur,
1820 "xsltParseStylesheetTop: ignoring misplaced import element\n");
1821 if (style != NULL) style->errors++;
1822 } else if (IS_XSLT_NAME(cur, "include")) {
1823 if (xsltParseStylesheetInclude(style, cur) != 0)
1824 if (style != NULL) style->errors++;
1825 } else if (IS_XSLT_NAME(cur, "strip-space")) {
1826 xsltParseStylesheetStripSpace(style, cur);
1827 } else if (IS_XSLT_NAME(cur, "preserve-space")) {
1828 xsltParseStylesheetPreserveSpace(style, cur);
1829 } else if (IS_XSLT_NAME(cur, "output")) {
1830 xsltParseStylesheetOutput(style, cur);
1831 } else if (IS_XSLT_NAME(cur, "key")) {
1832 xsltParseStylesheetKey(style, cur);
1833 } else if (IS_XSLT_NAME(cur, "decimal-format")) {
1834 xsltParseStylesheetDecimalFormat(style, cur);
1835 } else if (IS_XSLT_NAME(cur, "attribute-set")) {
1836 xsltParseStylesheetAttributeSet(style, cur);
1837 } else if (IS_XSLT_NAME(cur, "variable")) {
1838 xsltParseGlobalVariable(style, cur);
1839 } else if (IS_XSLT_NAME(cur, "param")) {
1840 xsltParseGlobalParam(style, cur);
1841 } else if (IS_XSLT_NAME(cur, "template")) {
1842 #ifdef WITH_XSLT_DEBUG_PARSING
1845 xsltParseStylesheetTemplate(style, cur);
1846 } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
1847 xsltNamespaceAlias(style, cur);
1849 xsltTransformError(NULL, style, cur,
1850 "xsltParseStylesheetTop: ignoring unknown %s element\n",
1852 if (style != NULL) style->warnings++;
1856 #ifdef WITH_XSLT_DEBUG_PARSING
1857 xsltGenericDebug(xsltGenericDebugContext,
1858 "parsed %d templates\n", templates);
1863 * xsltParseStylesheetProcess:
1864 * @ret: the XSLT stylesheet
1865 * @doc: and xmlDoc parsed XML
1867 * parse an XSLT stylesheet adding the associated structures
1869 * Returns the value of the 'ret' parameter if everything
1870 * went right, NULL if something went amiss.
1874 xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
1883 * First steps, remove blank nodes,
1884 * locate the xsl:stylesheet element and the
1885 * namespace declaration.
1887 cur = xmlDocGetRootElement(doc);
1889 xsltTransformError(NULL, ret, (xmlNodePtr) doc,
1890 "xsltParseStylesheetProcess : empty stylesheet\n");
1893 xsltParseStylesheetExcludePrefix(ret, cur);
1894 xsltPrecomputeStylesheet(ret, cur);
1896 if ((IS_XSLT_ELEM(cur)) &&
1897 ((IS_XSLT_NAME(cur, "stylesheet")) ||
1898 (IS_XSLT_NAME(cur, "transform")))) {
1899 #ifdef WITH_XSLT_DEBUG_PARSING
1900 xsltGenericDebug(xsltGenericDebugContext,
1901 "xsltParseStylesheetProcess : found stylesheet\n");
1904 xsltParseStylesheetTop(ret, cur);
1907 xsltTemplatePtr template;
1910 * the document itself might be the template, check xsl:version
1912 prop = xsltGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
1914 xsltTransformError(NULL, ret, cur,
1915 "xsltParseStylesheetProcess : document is not a stylesheet\n");
1919 #ifdef WITH_XSLT_DEBUG_PARSING
1920 xsltGenericDebug(xsltGenericDebugContext,
1921 "xsltParseStylesheetProcess : document is stylesheet\n");
1924 if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) {
1925 xsltTransformError(NULL, ret, cur,
1926 "xsl:version: only 1.0 features are supported\n");
1927 /* TODO set up compatibility when not XSLT 1.0 */
1933 * Create and link the template
1935 template = xsltNewTemplate();
1936 if (template == NULL) {
1939 template->next = ret->templates;
1940 ret->templates = template;
1941 template->match = xmlStrdup((const xmlChar *)"/");
1944 * parse the content and register the pattern
1946 xsltParseTemplateContent(ret, (xmlNodePtr) doc);
1947 template->elem = (xmlNodePtr) doc;
1948 template->content = doc->children;
1949 xsltAddTemplate(ret, template, NULL, NULL);
1956 * xsltParseStylesheetImportedDoc:
1957 * @doc: and xmlDoc parsed XML
1959 * parse an XSLT stylesheet building the associated structures
1960 * except the processing not needed for imported documents.
1962 * Returns a new XSLT stylesheet structure.
1966 xsltParseStylesheetImportedDoc(xmlDocPtr doc) {
1967 xsltStylesheetPtr ret;
1972 ret = xsltNewStylesheet();
1977 xsltGatherNamespaces(ret);
1978 if (xsltParseStylesheetProcess(ret, doc) == NULL) {
1980 xsltFreeStylesheet(ret);
1984 if (ret->errors != 0) {
1986 xsltFreeStylesheet(ret);
1995 * xsltParseStylesheetDoc:
1996 * @doc: and xmlDoc parsed XML
1998 * parse an XSLT stylesheet building the associated structures
2000 * Returns a new XSLT stylesheet structure.
2004 xsltParseStylesheetDoc(xmlDocPtr doc) {
2005 xsltStylesheetPtr ret;
2007 ret = xsltParseStylesheetImportedDoc(doc);
2011 xsltResolveStylesheetAttributeSet(ret);
2017 * xsltParseStylesheetFile:
2018 * @filename: the filename/URL to the stylesheet
2020 * Load and parse an XSLT stylesheet
2022 * Returns a new XSLT stylesheet structure.
2026 xsltParseStylesheetFile(const xmlChar* filename) {
2027 xsltSecurityPrefsPtr sec;
2028 xsltStylesheetPtr ret;
2032 if (filename == NULL)
2035 #ifdef WITH_XSLT_DEBUG_PARSING
2036 xsltGenericDebug(xsltGenericDebugContext,
2037 "xsltParseStylesheetFile : parse %s\n", filename);
2041 * Security framework check
2043 sec = xsltGetDefaultSecurityPrefs();
2047 res = xsltCheckRead(sec, NULL, filename);
2049 xsltTransformError(NULL, NULL, NULL,
2050 "xsltParseStylesheetFile: read rights for %s denied\n",
2056 doc = xmlParseFile((const char *) filename);
2058 xsltTransformError(NULL, NULL, NULL,
2059 "xsltParseStylesheetFile : cannot parse %s\n", filename);
2062 ret = xsltParseStylesheetDoc(doc);
2071 /************************************************************************
2073 * Handling of Stylesheet PI *
2075 ************************************************************************/
2078 #define SKIP(val) cur += (val)
2079 #define NXT(val) cur[(val)]
2080 #define SKIP_BLANKS \
2081 while (IS_BLANK(CUR)) NEXT
2082 #define NEXT ((*cur) ? cur++ : cur)
2085 * xsltParseStylesheetPI:
2086 * @value: the value of the PI
2088 * This function checks that the type is text/xml and extracts
2089 * the URI-Reference for the stylesheet
2091 * Returns the URI-Reference for the stylesheet or NULL (it need to
2092 * be freed by the caller)
2095 xsltParseStylesheetPI(const xmlChar *value) {
2097 const xmlChar *start;
2100 xmlChar *href = NULL;
2109 if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
2116 if ((CUR != '\'') && (CUR != '"'))
2121 while ((CUR != 0) && (CUR != tmp))
2125 val = xmlStrndup(start, cur - start);
2129 if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
2130 (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
2136 } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
2143 if ((CUR != '\'') && (CUR != '"'))
2148 while ((CUR != 0) && (CUR != tmp))
2153 href = xmlStrndup(start, cur - start);
2156 while ((CUR != 0) && (!IS_BLANK(CUR)))
2171 * xsltLoadStylesheetPI:
2172 * @doc: a document to process
2174 * This function tries to locate the stylesheet PI in the given document
2175 * If found, and if contained within the document, it will extract
2176 * that subtree to build the stylesheet to process @doc (doc itself will
2177 * be modified). If found but referencing an external document it will
2178 * attempt to load it and generate a stylesheet from it. In both cases,
2179 * the resulting stylesheet and the document need to be freed once the
2180 * transformation is done.
2182 * Returns a new XSLT stylesheet structure or NULL if not found.
2185 xsltLoadStylesheetPI(xmlDocPtr doc) {
2187 xsltStylesheetPtr ret = NULL;
2188 xmlChar *href = NULL;
2195 * Find the text/xml stylesheet PI id any before the root
2197 child = doc->children;
2198 while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
2199 if ((child->type == XML_PI_NODE) &&
2200 (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
2201 href = xsltParseStylesheetPI(child->content);
2205 child = child->next;
2209 * If found check the href to select processing
2212 #ifdef WITH_XSLT_DEBUG_PARSING
2213 xsltGenericDebug(xsltGenericDebugContext,
2214 "xsltLoadStylesheetPI : found PI href=%s\n", href);
2216 URI = xmlParseURI((const char *) href);
2218 xsltTransformError(NULL, NULL, child,
2219 "xml-stylesheet : href %s is not valid\n", href);
2223 if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
2224 (URI->opaque == NULL) && (URI->authority == NULL) &&
2225 (URI->server == NULL) && (URI->user == NULL) &&
2226 (URI->path == NULL) && (URI->query == NULL)) {
2229 #ifdef WITH_XSLT_DEBUG_PARSING
2230 xsltGenericDebug(xsltGenericDebugContext,
2231 "xsltLoadStylesheetPI : Reference to ID %s\n", href);
2233 if (URI->fragment[0] == '#')
2234 ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
2236 ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
2238 xsltTransformError(NULL, NULL, child,
2239 "xml-stylesheet : no ID %s found\n", URI->fragment);
2245 * move the subtree in a new document passed to
2246 * the stylesheet analyzer
2248 subtree = ID->parent;
2249 fake = xmlNewDoc(NULL);
2251 xmlUnlinkNode(subtree);
2252 xmlAddChild((xmlNodePtr) fake, subtree);
2253 ret = xsltParseStylesheetDoc(fake);
2259 xmlChar *URL, *base;
2262 * Reference to an external stylesheet
2265 base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
2266 URL = xmlBuildURI(href, base);
2268 #ifdef WITH_XSLT_DEBUG_PARSING
2269 xsltGenericDebug(xsltGenericDebugContext,
2270 "xsltLoadStylesheetPI : fetching %s\n", URL);
2272 ret = xsltParseStylesheetFile(URL);
2275 #ifdef WITH_XSLT_DEBUG_PARSING
2276 xsltGenericDebug(xsltGenericDebugContext,
2277 "xsltLoadStylesheetPI : fetching %s\n", href);
2279 ret = xsltParseStylesheetFile(href);