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);
68 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
74 #define IS_BLANK_NODE(n) \
75 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
79 * @style: the transformation stylesheet
80 * @value: the excluded prefix to push on the stack
82 * Push an excluded prefix on the stack
84 * Returns the new index in the stack or 0 in case of error
87 exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)
89 if (style->exclPrefixMax == 0) {
90 style->exclPrefixMax = 4;
91 style->exclPrefixTab =
92 (xmlChar * *)xmlMalloc(style->exclPrefixMax *
93 sizeof(style->exclPrefixTab[0]));
94 if (style->exclPrefixTab == NULL) {
95 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
99 if (style->exclPrefixNr >= style->exclPrefixMax) {
100 style->exclPrefixMax *= 2;
101 style->exclPrefixTab =
102 (xmlChar * *)xmlRealloc(style->exclPrefixTab,
103 style->exclPrefixMax *
104 sizeof(style->exclPrefixTab[0]));
105 if (style->exclPrefixTab == NULL) {
106 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
110 style->exclPrefixTab[style->exclPrefixNr] = value;
111 style->exclPrefix = value;
112 return (style->exclPrefixNr++);
116 * @style: the transformation stylesheet
118 * Pop an excluded prefix value from the stack
120 * Returns the stored excluded prefix value
123 exclPrefixPop(xsltStylesheetPtr style)
127 if (style->exclPrefixNr <= 0)
129 style->exclPrefixNr--;
130 if (style->exclPrefixNr > 0)
131 style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
133 style->exclPrefix = NULL;
134 ret = style->exclPrefixTab[style->exclPrefixNr];
135 style->exclPrefixTab[style->exclPrefixNr] = 0;
139 /************************************************************************
143 ************************************************************************/
148 * Initializes the processor (e.g. registers built-in extensions,
153 static int initialized = 0;
155 if (initialized == 0) {
157 xsltRegisterAllExtras();
165 * Check if a string is ignorable
167 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
170 xsltIsBlank(xmlChar *str) {
174 if (!(IS_BLANK(*str))) return(0);
180 /************************************************************************
182 * Routines to handle XSLT data structures *
184 ************************************************************************/
185 static xsltDecimalFormatPtr
186 xsltNewDecimalFormat(xmlChar *name)
188 xsltDecimalFormatPtr self;
190 self = xmlMalloc(sizeof(xsltDecimalFormat));
196 self->digit = xmlStrdup(BAD_CAST("#"));
197 self->patternSeparator = xmlStrdup(BAD_CAST(";"));
198 self->decimalPoint = xmlStrdup(BAD_CAST("."));
199 self->grouping = xmlStrdup(BAD_CAST(","));
200 self->percent = xmlStrdup(BAD_CAST("%"));
201 self->permille = xmlStrdup(BAD_CAST("?"));
202 self->zeroDigit = xmlStrdup(BAD_CAST("0"));
203 self->minusSign = xmlStrdup(BAD_CAST("-"));
204 self->infinity = xmlStrdup(BAD_CAST("Infinity"));
205 self->noNumber = xmlStrdup(BAD_CAST("NaN"));
211 xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
215 xmlFree(self->digit);
216 if (self->patternSeparator)
217 xmlFree(self->patternSeparator);
218 if (self->decimalPoint)
219 xmlFree(self->decimalPoint);
221 xmlFree(self->grouping);
223 xmlFree(self->percent);
225 xmlFree(self->permille);
227 xmlFree(self->zeroDigit);
229 xmlFree(self->minusSign);
231 xmlFree(self->infinity);
233 xmlFree(self->noNumber);
241 xsltFreeDecimalFormatList(xsltStylesheetPtr self)
243 xsltDecimalFormatPtr iter;
244 xsltDecimalFormatPtr tmp;
249 iter = self->decimalFormat;
250 while (iter != NULL) {
252 xsltFreeDecimalFormat(iter);
258 * xsltDecimalFormatGetByName:
259 * @sheet: the XSLT stylesheet
260 * @name: the decimal-format name to find
262 * Find decimal-format by name
264 * Returns the xsltDecimalFormatPtr
267 xsltDecimalFormatGetByName(xsltStylesheetPtr sheet, xmlChar *name)
269 xsltDecimalFormatPtr result = NULL;
272 return sheet->decimalFormat;
274 while (sheet != NULL) {
275 for (result = sheet->decimalFormat->next;
277 result = result->next) {
278 if (xmlStrEqual(name, result->name))
281 sheet = xsltNextImport(sheet);
290 * Create a new XSLT Template
292 * Returns the newly allocated xsltTemplatePtr or NULL in case of error
294 static xsltTemplatePtr
295 xsltNewTemplate(void) {
298 cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
300 xsltTransformError(NULL, NULL, NULL,
301 "xsltNewTemplate : malloc failed\n");
304 memset(cur, 0, sizeof(xsltTemplate));
305 cur->priority = XSLT_PAT_NO_PRIORITY;
311 * @template: an XSLT template
313 * Free up the memory allocated by @template
316 xsltFreeTemplate(xsltTemplatePtr template) {
317 if (template == NULL)
319 if (template->match) xmlFree(template->match);
320 if (template->name) xmlFree(template->name);
321 if (template->nameURI) xmlFree(template->nameURI);
322 if (template->mode) xmlFree(template->mode);
323 if (template->modeURI) xmlFree(template->modeURI);
324 if (template->inheritedNs) xmlFree(template->inheritedNs);
325 memset(template, -1, sizeof(xsltTemplate));
330 * xsltFreeTemplateList:
331 * @template: an XSLT template list
333 * Free up the memory allocated by all the elements of @template
336 xsltFreeTemplateList(xsltTemplatePtr template) {
339 while (template != NULL) {
341 template = template->next;
342 xsltFreeTemplate(cur);
349 * Create a new XSLT Stylesheet
351 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
354 xsltNewStylesheet(void) {
355 xsltStylesheetPtr cur;
357 cur = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
359 xsltTransformError(NULL, NULL, NULL,
360 "xsltNewStylesheet : malloc failed\n");
363 memset(cur, 0, sizeof(xsltStylesheet));
364 cur->omitXmlDeclaration = -1;
365 cur->standalone = -1;
366 cur->decimalFormat = xsltNewDecimalFormat(NULL);
370 cur->exclPrefixNr = 0;
371 cur->exclPrefixMax = 0;
372 cur->exclPrefixTab = NULL;
373 cur->extInfos = NULL;
383 * @style: an XSLT stylesheet
385 * Allocate an extra runtime information slot statically while compiling
386 * the stylesheet and return its number
388 * Returns the number of the slot
391 xsltAllocateExtra(xsltStylesheetPtr style)
393 return(style->extrasNr++);
397 * xsltAllocateExtraCtxt:
398 * @ctxt: an XSLT transformation context
400 * Allocate an extra runtime information slot at run-time
401 * and return its number
402 * This make sure there is a slot ready in the transformation context
404 * Returns the number of the slot
407 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
409 if (ctxt->extrasNr >= ctxt->extrasMax) {
411 if (ctxt->extrasNr == 0) {
412 ctxt->extrasMax = 20;
413 ctxt->extras = (xsltRuntimeExtraPtr)
414 xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
415 if (ctxt->extras == NULL) {
416 xmlGenericError(xmlGenericErrorContext,
417 "xsltAllocateExtraCtxt: out of memory\n");
418 ctxt->state = XSLT_STATE_ERROR;
421 for (i = 0;i < ctxt->extrasMax;i++) {
422 ctxt->extras[i].info = NULL;
423 ctxt->extras[i].deallocate = NULL;
424 ctxt->extras[i].val = NULL;
428 xsltRuntimeExtraPtr tmp;
430 ctxt->extrasMax += 100;
431 tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
432 ctxt->extrasMax * sizeof(xsltRuntimeExtra));
434 xmlGenericError(xmlGenericErrorContext,
435 "xsltAllocateExtraCtxt: out of memory\n");
436 ctxt->state = XSLT_STATE_ERROR;
440 for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
441 ctxt->extras[i].info = NULL;
442 ctxt->extras[i].deallocate = NULL;
443 ctxt->extras[i].val = NULL;
447 return(ctxt->extrasNr++);
451 * xsltFreeStylesheetList:
452 * @sheet: an XSLT stylesheet list
454 * Free up the memory allocated by the list @sheet
457 xsltFreeStylesheetList(xsltStylesheetPtr sheet) {
458 xsltStylesheetPtr next;
460 while (sheet != NULL) {
462 xsltFreeStylesheet(sheet);
468 * xsltFreeStylesheet:
469 * @sheet: an XSLT stylesheet
471 * Free up the memory allocated by @sheet
474 xsltFreeStylesheet(xsltStylesheetPtr sheet)
481 xsltFreeTemplateHashes(sheet);
482 xsltFreeDecimalFormatList(sheet);
483 xsltFreeTemplateList(sheet->templates);
484 xsltFreeAttributeSetsHashes(sheet);
485 xsltFreeNamespaceAliasHashes(sheet);
486 xsltFreeStyleDocuments(sheet);
487 xsltFreeStylePreComps(sheet);
488 xsltShutdownExts(sheet);
489 if (sheet->doc != NULL)
490 xmlFreeDoc(sheet->doc);
491 if (sheet->variables != NULL)
492 xsltFreeStackElemList(sheet->variables);
493 if (sheet->cdataSection != NULL)
494 xmlHashFree(sheet->cdataSection, NULL);
495 if (sheet->stripSpaces != NULL)
496 xmlHashFree(sheet->stripSpaces, NULL);
497 if (sheet->nsHash != NULL)
498 xmlHashFree(sheet->nsHash, NULL);
500 if (sheet->exclPrefixTab != NULL)
501 xmlFree(sheet->exclPrefixTab);
502 if (sheet->method != NULL)
503 xmlFree(sheet->method);
504 if (sheet->methodURI != NULL)
505 xmlFree(sheet->methodURI);
506 if (sheet->version != NULL)
507 xmlFree(sheet->version);
508 if (sheet->encoding != NULL)
509 xmlFree(sheet->encoding);
510 if (sheet->doctypePublic != NULL)
511 xmlFree(sheet->doctypePublic);
512 if (sheet->doctypeSystem != NULL)
513 xmlFree(sheet->doctypeSystem);
514 if (sheet->mediaType != NULL)
515 xmlFree(sheet->mediaType);
517 if (sheet->imports != NULL)
518 xsltFreeStylesheetList(sheet->imports);
520 memset(sheet, -1, sizeof(xsltStylesheet));
524 /************************************************************************
526 * Parsing of an XSLT Stylesheet *
528 ************************************************************************/
531 * xsltGetInheritedNsList:
532 * @style: the stylesheet
533 * @template: the template
534 * @node: the current node
536 * Search all the namespace applying to a given element except the ones
537 * from excluded output prefixes currently in scope. Initialize the
538 * template inheritedNs list with it.
540 * Returns the number of entries found
543 xsltGetInheritedNsList(xsltStylesheetPtr style,
544 xsltTemplatePtr template,
548 xmlNsPtr *ret = NULL;
553 if ((style == NULL) || (template == NULL) || (node == NULL) ||
554 (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
556 while (node != NULL) {
557 if (node->type == XML_ELEMENT_NODE) {
559 while (cur != NULL) {
560 if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
562 if ((cur->prefix != NULL) &&
563 (xsltCheckExtPrefix(style, cur->prefix)))
565 for (i = 0;i < style->exclPrefixNr;i++) {
566 if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
571 (xmlNsPtr *) xmlMalloc((maxns + 1) *
574 xmlGenericError(xmlGenericErrorContext,
575 "xmlGetNsList : out of memory!\n");
580 for (i = 0; i < nbns; i++) {
581 if ((cur->prefix == ret[i]->prefix) ||
582 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
588 ret = (xmlNsPtr *) xmlRealloc(ret,
593 xmlGenericError(xmlGenericErrorContext,
594 "xmlGetNsList : realloc failed!\n");
608 #ifdef WITH_XSLT_DEBUG_PARSING
609 xsltGenericDebug(xsltGenericDebugContext,
610 "template has %d inherited namespaces\n", nbns);
612 template->inheritedNsNr = nbns;
613 template->inheritedNs = ret;
619 * xsltParseStylesheetOutput:
620 * @style: the XSLT stylesheet
621 * @cur: the "output" element
623 * parse an XSLT stylesheet output element and record
624 * information related to the stylesheet output
628 xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
635 if ((cur == NULL) || (style == NULL))
638 prop = xsltGetNsProp(cur, (const xmlChar *) "version", XSLT_NAMESPACE);
640 if (style->version != NULL)
641 xmlFree(style->version);
642 style->version = prop;
646 xsltGetNsProp(cur, (const xmlChar *) "encoding", XSLT_NAMESPACE);
648 if (style->encoding != NULL)
649 xmlFree(style->encoding);
650 style->encoding = prop;
653 /* relaxed to support xt:document */
654 prop = xmlGetProp(cur, (const xmlChar *) "method");
658 if (style->method != NULL)
659 xmlFree(style->method);
660 style->method = NULL;
661 if (style->methodURI != NULL)
662 xmlFree(style->methodURI);
663 style->methodURI = NULL;
665 URI = xsltGetQNameURI(cur, &prop);
667 if (style != NULL) style->errors++;
668 } else if (URI == NULL) {
669 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
670 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
671 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
672 style->method = prop;
674 xsltTransformError(NULL, style, cur,
675 "invalid value for method: %s\n", prop);
676 if (style != NULL) style->warnings++;
679 style->method = prop;
680 style->methodURI = xmlStrdup(URI);
685 xsltGetNsProp(cur, (const xmlChar *) "doctype-system",
688 if (style->doctypeSystem != NULL)
689 xmlFree(style->doctypeSystem);
690 style->doctypeSystem = prop;
694 xsltGetNsProp(cur, (const xmlChar *) "doctype-public",
697 if (style->doctypePublic != NULL)
698 xmlFree(style->doctypePublic);
699 style->doctypePublic = prop;
702 prop = xsltGetNsProp(cur, (const xmlChar *) "standalone",
705 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
706 style->standalone = 1;
707 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
708 style->standalone = 0;
710 xsltTransformError(NULL, style, cur,
711 "invalid value for standalone: %s\n", prop);
712 if (style != NULL) style->warnings++;
717 prop = xsltGetNsProp(cur, (const xmlChar *) "indent", XSLT_NAMESPACE);
719 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
721 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
724 xsltTransformError(NULL, style, cur,
725 "invalid value for indent: %s\n", prop);
726 if (style != NULL) style->warnings++;
731 prop = xsltGetNsProp(cur, (const xmlChar *) "omit-xml-declaration",
734 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
735 style->omitXmlDeclaration = 1;
736 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
737 style->omitXmlDeclaration = 0;
739 xsltTransformError(NULL, style, cur,
740 "invalid value for omit-xml-declaration: %s\n",
742 if (style != NULL) style->warnings++;
748 xsltGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
750 if (elements != NULL) {
751 if (style->cdataSection == NULL)
752 style->cdataSection = xmlHashCreate(10);
753 if (style->cdataSection == NULL)
757 while (*element != 0) {
758 while (IS_BLANK(*element))
763 while ((*end != 0) && (!IS_BLANK(*end)))
765 element = xmlStrndup(element, end - element);
768 #ifdef WITH_XSLT_DEBUG_PARSING
769 xsltGenericDebug(xsltGenericDebugContext,
770 "add cdata section output element %s\n",
774 URI = xsltGetQNameURI(cur, &element);
775 if (element == NULL) {
776 if (style != NULL) style->errors++;
778 xmlHashAddEntry2(style->cdataSection, element, URI,
788 prop = xsltGetNsProp(cur, (const xmlChar *) "media-type", XSLT_NAMESPACE);
790 if (style->mediaType)
791 xmlFree(style->mediaType);
792 style->mediaType = prop;
797 * xsltParseStylesheetDecimalFormat:
798 * @style: the XSLT stylesheet
799 * @cur: the "decimal-format" element
801 * parse an XSLT stylesheet decimal-format element and
802 * and record the formatting characteristics
805 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
808 xsltDecimalFormatPtr format;
809 xsltDecimalFormatPtr iter;
811 if ((cur == NULL) || (style == NULL))
814 format = style->decimalFormat;
816 prop = xsltGetNsProp(cur, BAD_CAST("name"), XSLT_NAMESPACE);
818 format = xsltDecimalFormatGetByName(style, prop);
819 if (format != NULL) {
820 xsltTransformError(NULL, style, cur,
821 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
822 if (style != NULL) style->warnings++;
825 format = xsltNewDecimalFormat(prop);
826 if (format == NULL) {
827 xsltTransformError(NULL, style, cur,
828 "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
829 if (style != NULL) style->errors++;
832 /* Append new decimal-format structure */
833 for (iter = style->decimalFormat; iter->next; iter = iter->next)
839 prop = xsltGetNsProp(cur, (const xmlChar *)"decimal-separator",
842 if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
843 format->decimalPoint = prop;
846 prop = xsltGetNsProp(cur, (const xmlChar *)"grouping-separator",
849 if (format->grouping != NULL) xmlFree(format->grouping);
850 format->grouping = prop;
853 prop = xsltGetNsProp(cur, (const xmlChar *)"infinity", XSLT_NAMESPACE);
855 if (format->infinity != NULL) xmlFree(format->infinity);
856 format->infinity = prop;
859 prop = xsltGetNsProp(cur, (const xmlChar *)"minus-sign", XSLT_NAMESPACE);
861 if (format->minusSign != NULL) xmlFree(format->minusSign);
862 format->minusSign = prop;
865 prop = xsltGetNsProp(cur, (const xmlChar *)"NaN", XSLT_NAMESPACE);
867 if (format->noNumber != NULL) xmlFree(format->noNumber);
868 format->noNumber = prop;
871 prop = xsltGetNsProp(cur, (const xmlChar *)"percent", XSLT_NAMESPACE);
873 if (format->percent != NULL) xmlFree(format->percent);
874 format->percent = prop;
877 prop = xsltGetNsProp(cur, (const xmlChar *)"per-mille", XSLT_NAMESPACE);
879 if (format->permille != NULL) xmlFree(format->permille);
880 format->permille = prop;
883 prop = xsltGetNsProp(cur, (const xmlChar *)"zero-digit", XSLT_NAMESPACE);
885 if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
886 format->zeroDigit = prop;
889 prop = xsltGetNsProp(cur, (const xmlChar *)"digit", XSLT_NAMESPACE);
891 if (format->digit != NULL) xmlFree(format->digit);
892 format->digit = prop;
895 prop = xsltGetNsProp(cur, (const xmlChar *)"pattern-separator",
898 if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
899 format->patternSeparator = prop;
904 * xsltParseStylesheetPreserveSpace:
905 * @style: the XSLT stylesheet
906 * @cur: the "preserve-space" element
908 * parse an XSLT stylesheet preserve-space element and record
909 * elements needing preserving
913 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
915 xmlChar *element, *end;
917 if ((cur == NULL) || (style == NULL))
920 elements = xsltGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
921 if (elements == NULL) {
922 xsltTransformError(NULL, style, cur,
923 "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
924 if (style != NULL) style->warnings++;
928 if (style->stripSpaces == NULL)
929 style->stripSpaces = xmlHashCreate(10);
930 if (style->stripSpaces == NULL)
934 while (*element != 0) {
935 while (IS_BLANK(*element)) element++;
939 while ((*end != 0) && (!IS_BLANK(*end))) end++;
940 element = xmlStrndup(element, end - element);
942 #ifdef WITH_XSLT_DEBUG_PARSING
943 xsltGenericDebug(xsltGenericDebugContext,
944 "add preserved space element %s\n", element);
946 if (xmlStrEqual(element, (const xmlChar *)"*")) {
947 style->stripAll = -1;
951 URI = xsltGetQNameURI(cur, &element);
953 xmlHashAddEntry2(style->stripSpaces, element, URI,
954 (xmlChar *) "preserve");
964 * xsltParseStylesheetExtPrefix:
965 * @style: the XSLT stylesheet
966 * @template: the "extension-element-prefixes" prefix
968 * parse an XSLT stylesheet extension prefix and record
969 * prefixes needing stripping
973 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur) {
975 xmlChar *prefix, *end;
977 if ((cur == NULL) || (style == NULL))
980 prefixes = xsltGetNsProp(cur, (const xmlChar *)"extension-element-prefixes",
982 if (prefixes == NULL) {
987 while (*prefix != 0) {
988 while (IS_BLANK(*prefix)) prefix++;
992 while ((*end != 0) && (!IS_BLANK(*end))) end++;
993 prefix = xmlStrndup(prefix, end - prefix);
997 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
998 ns = xmlSearchNs(style->doc, cur, NULL);
1000 ns = xmlSearchNs(style->doc, cur, prefix);
1002 xsltTransformError(NULL, style, cur,
1003 "xsl:extension-element-prefix : undefined namespace %s\n",
1005 if (style != NULL) style->warnings++;
1007 #ifdef WITH_XSLT_DEBUG_PARSING
1008 xsltGenericDebug(xsltGenericDebugContext,
1009 "add extension prefix %s\n", prefix);
1011 xsltRegisterExtPrefix(style, prefix, ns->href);
1021 * xsltParseStylesheetStripSpace:
1022 * @style: the XSLT stylesheet
1023 * @cur: the "strip-space" element
1025 * parse an XSLT stylesheet strip-space element and record
1026 * elements needing stripping
1030 xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1032 xmlChar *element, *end;
1034 if ((cur == NULL) || (style == NULL))
1037 elements = xsltGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
1038 if (elements == NULL) {
1039 xsltTransformError(NULL, style, cur,
1040 "xsltParseStylesheetStripSpace: missing elements attribute\n");
1041 if (style != NULL) style->warnings++;
1045 if (style->stripSpaces == NULL)
1046 style->stripSpaces = xmlHashCreate(10);
1047 if (style->stripSpaces == NULL)
1051 while (*element != 0) {
1052 while (IS_BLANK(*element)) element++;
1056 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1057 element = xmlStrndup(element, end - element);
1059 #ifdef WITH_XSLT_DEBUG_PARSING
1060 xsltGenericDebug(xsltGenericDebugContext,
1061 "add stripped space element %s\n", element);
1063 if (xmlStrEqual(element, (const xmlChar *)"*")) {
1064 style->stripAll = 1;
1068 URI = xsltGetQNameURI(cur, &element);
1070 xmlHashAddEntry2(style->stripSpaces, element, URI,
1071 (xmlChar *) "strip");
1081 * xsltParseStylesheetExcludePrefix:
1082 * @style: the XSLT stylesheet
1083 * @cur: the current point in the stylesheet
1085 * parse an XSLT stylesheet exclude prefix and record
1086 * namespaces needing stripping
1088 * Returns the number of Excluded prefixes added at that level
1092 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur) {
1095 xmlChar *prefix, *end;
1097 if ((cur == NULL) || (style == NULL))
1100 prefixes = xsltGetNsProp(cur, (const xmlChar *)"exclude-result-prefixes",
1102 if (prefixes == NULL) {
1107 while (*prefix != 0) {
1108 while (IS_BLANK(*prefix)) prefix++;
1112 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1113 prefix = xmlStrndup(prefix, end - prefix);
1117 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1118 ns = xmlSearchNs(style->doc, cur, NULL);
1120 ns = xmlSearchNs(style->doc, cur, prefix);
1122 xsltTransformError(NULL, style, cur,
1123 "xsl:exclude-result-prefixes : undefined namespace %s\n",
1125 if (style != NULL) style->warnings++;
1127 #ifdef WITH_XSLT_DEBUG_PARSING
1128 xsltGenericDebug(xsltGenericDebugContext,
1129 "exclude result prefix %s\n", prefix);
1131 exclPrefixPush(style, (xmlChar *) ns->href);
1143 * xsltPrecomputeStylesheet:
1144 * @style: the XSLT stylesheet
1145 * @cur: the current child list
1147 * Clean-up the stylesheet content from unwanted ignorable blank nodes
1148 * and run the preprocessing of all XSLT constructs.
1150 * and process xslt:text
1153 xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) {
1157 * This content comes from the stylesheet
1158 * For stylesheets, the set of whitespace-preserving
1159 * element names consists of just xsl:text.
1162 while (cur != NULL) {
1163 if (delete != NULL) {
1164 #ifdef WITH_XSLT_DEBUG_BLANKS
1165 xsltGenericDebug(xsltGenericDebugContext,
1166 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
1168 xmlUnlinkNode(delete);
1169 xmlFreeNode(delete);
1172 if (cur->type == XML_ELEMENT_NODE) {
1175 exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur);
1176 if (IS_XSLT_ELEM(cur)) {
1177 xsltStylePreCompute(style, cur);
1178 if (IS_XSLT_NAME(cur, "text")) {
1179 for (;exclPrefixes > 0;exclPrefixes--)
1180 exclPrefixPop(style);
1185 * Remove excluded prefixes
1187 if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
1188 xmlNsPtr ns = cur->nsDef, prev = NULL, next;
1189 xmlNodePtr root = NULL;
1192 root = xmlDocGetRootElement(cur->doc);
1193 if ((root != NULL) && (root != cur)) {
1194 while (ns != NULL) {
1197 for (i = 0;i < style->exclPrefixNr;i++) {
1198 if (xmlStrEqual(ns->href,
1199 style->exclPrefixTab[i])) {
1201 * Move the namespace definition on the root
1202 * element to avoid duplicating it without
1206 cur->nsDef = ns->next;
1208 prev->next = ns->next;
1210 ns->next = root->nsDef;
1224 * If we have prefixes locally, recurse and pop them up when
1227 if (exclPrefixes > 0) {
1228 xsltPrecomputeStylesheet(style, cur->children);
1229 for (;exclPrefixes > 0;exclPrefixes--)
1230 exclPrefixPop(style);
1233 } else if (cur->type == XML_TEXT_NODE) {
1234 if (IS_BLANK_NODE(cur)) {
1235 if (xmlNodeGetSpacePreserve(cur) != 1) {
1239 } else if ((cur->type != XML_ELEMENT_NODE) &&
1240 (cur->type != XML_CDATA_SECTION_NODE)) {
1248 if (cur->children != NULL) {
1249 if ((cur->children->type != XML_ENTITY_DECL) &&
1250 (cur->children->type != XML_ENTITY_REF_NODE) &&
1251 (cur->children->type != XML_ENTITY_NODE)) {
1252 cur = cur->children;
1257 if (cur->next != NULL) {
1266 if (cur == (xmlNodePtr) style->doc) {
1270 if (cur->next != NULL) {
1274 } while (cur != NULL);
1276 if (delete != NULL) {
1277 #ifdef WITH_XSLT_DEBUG_PARSING
1278 xsltGenericDebug(xsltGenericDebugContext,
1279 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
1281 xmlUnlinkNode(delete);
1282 xmlFreeNode(delete);
1288 * xsltGatherNamespaces:
1289 * @style: the XSLT stylesheet
1291 * Browse the stylesheet and build the namspace hash table which
1292 * will be used for XPath interpretation. If needed do a bit of normalization
1296 xsltGatherNamespaces(xsltStylesheetPtr style) {
1301 * TODO: basically if the stylesheet uses the same prefix for different
1302 * patterns, well they may be in problem, hopefully they will get
1305 cur = xmlDocGetRootElement(style->doc);
1306 while (cur != NULL) {
1307 if (cur->type == XML_ELEMENT_NODE) {
1308 xmlNsPtr ns = cur->nsDef;
1309 while (ns != NULL) {
1310 if (ns->prefix != NULL) {
1311 if (style->nsHash == NULL) {
1312 style->nsHash = xmlHashCreate(10);
1313 if (style->nsHash == NULL) {
1314 xsltTransformError(NULL, style, cur,
1315 "xsltGatherNamespaces: failed to create hash table\n");
1316 if (style != NULL) style->errors++;
1320 URI = xmlHashLookup(style->nsHash, ns->prefix);
1321 if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
1322 xsltTransformError(NULL, style, cur,
1323 "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
1324 if (style != NULL) style->warnings++;
1325 } else if (URI == NULL) {
1326 xmlHashUpdateEntry(style->nsHash, ns->prefix,
1327 (void *) ns->href, (xmlHashDeallocator)xmlFree);
1329 #ifdef WITH_XSLT_DEBUG_PARSING
1330 xsltGenericDebug(xsltGenericDebugContext,
1331 "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
1342 if (cur->children != NULL) {
1343 if (cur->children->type != XML_ENTITY_DECL) {
1344 cur = cur->children;
1348 if (cur->next != NULL) {
1357 if (cur == (xmlNodePtr) style->doc) {
1361 if (cur->next != NULL) {
1365 } while (cur != NULL);
1370 * xsltParseTemplateContent:
1371 * @style: the XSLT stylesheet
1372 * @templ: the container node (can be a document for literal results)
1374 * parse a template content-model
1375 * Clean-up the template content from unwanted ignorable blank nodes
1376 * and process xslt:text
1380 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
1381 xmlNodePtr cur, delete;
1383 * This content comes from the stylesheet
1384 * For stylesheets, the set of whitespace-preserving
1385 * element names consists of just xsl:text.
1387 cur = templ->children;
1389 while (cur != NULL) {
1390 if (delete != NULL) {
1391 #ifdef WITH_XSLT_DEBUG_BLANKS
1392 xsltGenericDebug(xsltGenericDebugContext,
1393 "xsltParseTemplateContent: removing text\n");
1395 xmlUnlinkNode(delete);
1396 xmlFreeNode(delete);
1399 if (IS_XSLT_ELEM(cur)) {
1400 if (IS_XSLT_NAME(cur, "text")) {
1401 if (cur->children != NULL) {
1403 xmlNodePtr text = cur->children, next;
1406 prop = xsltGetNsProp(cur,
1407 (const xmlChar *)"disable-output-escaping",
1410 #ifdef WITH_XSLT_DEBUG_PARSING
1411 xsltGenericDebug(xsltGenericDebugContext,
1412 "Disable escaping: %s\n", text->content);
1414 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
1416 } else if (!xmlStrEqual(prop,
1417 (const xmlChar *)"no")){
1418 xsltTransformError(NULL, style, cur,
1419 "xsl:text: disable-output-escaping allows only yes or no\n");
1420 if (style != NULL) style->warnings++;
1426 while (text != NULL) {
1427 if (text->type == XML_COMMENT_NODE) {
1431 if ((text->type != XML_TEXT_NODE) &&
1432 (text->type != XML_CDATA_SECTION_NODE)) {
1433 xsltTransformError(NULL, style, cur,
1434 "xsltParseTemplateContent: xslt:text content problem\n");
1435 if (style != NULL) style->errors++;
1439 text->name = xmlStringTextNoenc;
1444 * replace xsl:text by the list of childs
1447 text = cur->children;
1448 while (text != NULL) {
1450 xmlUnlinkNode(text);
1451 xmlAddPrevSibling(cur, text);
1459 } else if ((cur->ns != NULL) && (style->nsDefs != NULL)) {
1460 if (xsltCheckExtPrefix(style, cur->ns->prefix)) {
1462 * okay this is an extension element compile it too
1464 xsltStylePreCompute(style, cur);
1471 if (cur->children != NULL) {
1472 if (cur->children->type != XML_ENTITY_DECL) {
1473 cur = cur->children;
1478 if (cur->next != NULL) {
1491 if (cur->next != NULL) {
1495 } while (cur != NULL);
1497 if (delete != NULL) {
1498 #ifdef WITH_XSLT_DEBUG_PARSING
1499 xsltGenericDebug(xsltGenericDebugContext,
1500 "xsltParseTemplateContent: removing text\n");
1502 xmlUnlinkNode(delete);
1503 xmlFreeNode(delete);
1508 * Skip the first params
1510 cur = templ->children;
1511 while (cur != NULL) {
1512 if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
1518 * Browse the remainder of the template
1520 while (cur != NULL) {
1521 if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
1522 xmlNodePtr param = cur;
1524 xsltTransformError(NULL, style, cur,
1525 "xsltParseTemplateContent: ignoring misplaced param element\n");
1526 if (style != NULL) style->warnings++;
1528 xmlUnlinkNode(param);
1536 * xsltParseStylesheetKey:
1537 * @style: the XSLT stylesheet
1538 * @key: the "key" element
1540 * parse an XSLT stylesheet key definition and register it
1544 xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
1545 xmlChar *prop = NULL;
1546 xmlChar *use = NULL;
1547 xmlChar *match = NULL;
1548 xmlChar *name = NULL;
1549 xmlChar *nameURI = NULL;
1557 prop = xsltGetNsProp(key, (const xmlChar *)"name", XSLT_NAMESPACE);
1561 URI = xsltGetQNameURI(key, &prop);
1563 if (style != NULL) style->errors++;
1568 nameURI = xmlStrdup(URI);
1570 #ifdef WITH_XSLT_DEBUG_PARSING
1571 xsltGenericDebug(xsltGenericDebugContext,
1572 "xsltParseStylesheetKey: name %s\n", name);
1575 xsltTransformError(NULL, style, key,
1576 "xsl:key : error missing name\n");
1577 if (style != NULL) style->errors++;
1581 match = xsltGetNsProp(key, (const xmlChar *)"match", XSLT_NAMESPACE);
1582 if (match == NULL) {
1583 xsltTransformError(NULL, style, key,
1584 "xsl:key : error missing match\n");
1585 if (style != NULL) style->errors++;
1589 use = xsltGetNsProp(key, (const xmlChar *)"use", XSLT_NAMESPACE);
1591 xsltTransformError(NULL, style, key,
1592 "xsl:key : error missing use\n");
1593 if (style != NULL) style->errors++;
1600 xsltAddKey(style, name, nameURI, match, use, key);
1610 if (nameURI != NULL)
1615 * xsltParseStylesheetTemplate:
1616 * @style: the XSLT stylesheet
1617 * @template: the "template" element
1619 * parse an XSLT stylesheet template building the associated structures
1623 xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
1624 xsltTemplatePtr ret;
1626 xmlChar *mode = NULL;
1627 xmlChar *modeURI = NULL;
1631 if (template == NULL)
1635 * Create and link the structure
1637 ret = xsltNewTemplate();
1640 ret->next = style->templates;
1641 style->templates = ret;
1645 * Check excluded prefixes
1647 exclPrefixes = xsltParseStylesheetExcludePrefix(style, template);
1650 * Get inherited namespaces
1652 xsltGetInheritedNsList(style, ret, template);
1657 prop = xsltGetNsProp(template, (const xmlChar *)"mode", XSLT_NAMESPACE);
1661 URI = xsltGetQNameURI(template, &prop);
1663 if (style != NULL) style->errors++;
1668 modeURI = xmlStrdup(URI);
1671 ret->modeURI = modeURI;
1672 #ifdef WITH_XSLT_DEBUG_PARSING
1673 xsltGenericDebug(xsltGenericDebugContext,
1674 "xsltParseStylesheetTemplate: mode %s\n", mode);
1680 prop = xsltGetNsProp(template, (const xmlChar *)"match", XSLT_NAMESPACE);
1682 if (ret->match != NULL) xmlFree(ret->match);
1686 prop = xsltGetNsProp(template, (const xmlChar *)"priority", XSLT_NAMESPACE);
1688 priority = xmlXPathStringEvalNumber(prop);
1689 ret->priority = (float) priority;
1693 prop = xsltGetNsProp(template, (const xmlChar *)"name", XSLT_NAMESPACE);
1697 if (ret->name != NULL) xmlFree(ret->name);
1699 if (ret->nameURI != NULL) xmlFree(ret->nameURI);
1700 ret->nameURI = NULL;
1702 URI = xsltGetQNameURI(template, &prop);
1704 if (style != NULL) style->errors++;
1709 ret->nameURI = xmlStrdup(URI);
1711 ret->nameURI = NULL;
1716 * parse the content and register the pattern
1718 xsltParseTemplateContent(style, template);
1719 ret->elem = template;
1720 ret->content = template->children;
1721 xsltAddTemplate(style, ret, mode, modeURI);
1724 for (;exclPrefixes > 0;exclPrefixes--)
1725 exclPrefixPop(style);
1729 * xsltParseStylesheetTop:
1730 * @style: the XSLT stylesheet
1731 * @top: the top level "stylesheet" element
1733 * scan the top level elements of an XSL stylesheet
1737 xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
1740 #ifdef WITH_XSLT_DEBUG_PARSING
1747 prop = xsltGetNsProp(top, (const xmlChar *)"version", XSLT_NAMESPACE);
1749 xsltTransformError(NULL, style, top,
1750 "xsl:version is missing: document may not be a stylesheet\n");
1751 if (style != NULL) style->warnings++;
1753 if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
1754 (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
1755 xsltTransformError(NULL, style, top,
1756 "xsl:version: only 1.0 features are supported\n");
1757 /* TODO set up compatibility when not XSLT 1.0 */
1758 if (style != NULL) style->warnings++;
1763 xsltParseStylesheetExtPrefix(style, top);
1765 cur = top->children;
1768 * process xsl:import elements
1770 while (cur != NULL) {
1771 if (IS_BLANK_NODE(cur)) {
1775 if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
1776 if (xsltParseStylesheetImport(style, cur) != 0)
1777 if (style != NULL) style->errors++;
1784 * process other top-level elements
1786 while (cur != NULL) {
1787 if (IS_BLANK_NODE(cur)) {
1791 if (cur->type == XML_TEXT_NODE) {
1792 if (cur->content != NULL) {
1793 xsltTransformError(NULL, style, cur,
1794 "misplaced text element: '%s'\n", cur->content);
1796 if (style != NULL) style->errors++;
1800 if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
1801 xsltGenericError(xsltGenericErrorContext,
1802 "Found a top-level element %s with null namespace URI\n",
1804 if (style != NULL) style->errors++;
1808 if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
1809 xsltTopLevelFunction function;
1811 function = xsltExtModuleTopLevelLookup(cur->name,
1813 if (function != NULL)
1814 function(style, cur);
1816 #ifdef WITH_XSLT_DEBUG_PARSING
1817 xsltGenericDebug(xsltGenericDebugContext,
1818 "xsltParseStylesheetTop : found foreign element %s\n",
1824 if (IS_XSLT_NAME(cur, "import")) {
1825 xsltTransformError(NULL, style, cur,
1826 "xsltParseStylesheetTop: ignoring misplaced import element\n");
1827 if (style != NULL) style->errors++;
1828 } else if (IS_XSLT_NAME(cur, "include")) {
1829 if (xsltParseStylesheetInclude(style, cur) != 0)
1830 if (style != NULL) style->errors++;
1831 } else if (IS_XSLT_NAME(cur, "strip-space")) {
1832 xsltParseStylesheetStripSpace(style, cur);
1833 } else if (IS_XSLT_NAME(cur, "preserve-space")) {
1834 xsltParseStylesheetPreserveSpace(style, cur);
1835 } else if (IS_XSLT_NAME(cur, "output")) {
1836 xsltParseStylesheetOutput(style, cur);
1837 } else if (IS_XSLT_NAME(cur, "key")) {
1838 xsltParseStylesheetKey(style, cur);
1839 } else if (IS_XSLT_NAME(cur, "decimal-format")) {
1840 xsltParseStylesheetDecimalFormat(style, cur);
1841 } else if (IS_XSLT_NAME(cur, "attribute-set")) {
1842 xsltParseStylesheetAttributeSet(style, cur);
1843 } else if (IS_XSLT_NAME(cur, "variable")) {
1844 xsltParseGlobalVariable(style, cur);
1845 } else if (IS_XSLT_NAME(cur, "param")) {
1846 xsltParseGlobalParam(style, cur);
1847 } else if (IS_XSLT_NAME(cur, "template")) {
1848 #ifdef WITH_XSLT_DEBUG_PARSING
1851 xsltParseStylesheetTemplate(style, cur);
1852 } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
1853 xsltNamespaceAlias(style, cur);
1855 xsltTransformError(NULL, style, cur,
1856 "xsltParseStylesheetTop: ignoring unknown %s element\n",
1858 if (style != NULL) style->warnings++;
1862 #ifdef WITH_XSLT_DEBUG_PARSING
1863 xsltGenericDebug(xsltGenericDebugContext,
1864 "parsed %d templates\n", templates);
1869 * xsltParseStylesheetProcess:
1870 * @ret: the XSLT stylesheet
1871 * @doc: and xmlDoc parsed XML
1873 * parse an XSLT stylesheet adding the associated structures
1875 * Returns the value of the 'ret' parameter if everything
1876 * went right, NULL if something went amiss.
1880 xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
1889 * First steps, remove blank nodes,
1890 * locate the xsl:stylesheet element and the
1891 * namespace declaration.
1893 cur = xmlDocGetRootElement(doc);
1895 xsltTransformError(NULL, ret, (xmlNodePtr) doc,
1896 "xsltParseStylesheetProcess : empty stylesheet\n");
1899 xsltParseStylesheetExcludePrefix(ret, cur);
1900 xsltPrecomputeStylesheet(ret, cur);
1902 if ((IS_XSLT_ELEM(cur)) &&
1903 ((IS_XSLT_NAME(cur, "stylesheet")) ||
1904 (IS_XSLT_NAME(cur, "transform")))) {
1905 #ifdef WITH_XSLT_DEBUG_PARSING
1906 xsltGenericDebug(xsltGenericDebugContext,
1907 "xsltParseStylesheetProcess : found stylesheet\n");
1910 xsltParseStylesheetTop(ret, cur);
1913 xsltTemplatePtr template;
1916 * the document itself might be the template, check xsl:version
1918 prop = xsltGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
1920 xsltTransformError(NULL, ret, cur,
1921 "xsltParseStylesheetProcess : document is not a stylesheet\n");
1925 #ifdef WITH_XSLT_DEBUG_PARSING
1926 xsltGenericDebug(xsltGenericDebugContext,
1927 "xsltParseStylesheetProcess : document is stylesheet\n");
1930 if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) {
1931 xsltTransformError(NULL, ret, cur,
1932 "xsl:version: only 1.0 features are supported\n");
1933 /* TODO set up compatibility when not XSLT 1.0 */
1939 * Create and link the template
1941 template = xsltNewTemplate();
1942 if (template == NULL) {
1945 template->next = ret->templates;
1946 ret->templates = template;
1947 template->match = xmlStrdup((const xmlChar *)"/");
1950 * parse the content and register the pattern
1952 xsltParseTemplateContent(ret, (xmlNodePtr) doc);
1953 template->elem = (xmlNodePtr) doc;
1954 template->content = doc->children;
1955 xsltAddTemplate(ret, template, NULL, NULL);
1962 * xsltParseStylesheetImportedDoc:
1963 * @doc: and xmlDoc parsed XML
1965 * parse an XSLT stylesheet building the associated structures
1966 * except the processing not needed for imported documents.
1968 * Returns a new XSLT stylesheet structure.
1972 xsltParseStylesheetImportedDoc(xmlDocPtr doc) {
1973 xsltStylesheetPtr ret;
1978 ret = xsltNewStylesheet();
1983 xsltGatherNamespaces(ret);
1984 if (xsltParseStylesheetProcess(ret, doc) == NULL) {
1986 xsltFreeStylesheet(ret);
1990 if (ret->errors != 0) {
1992 xsltFreeStylesheet(ret);
2001 * xsltParseStylesheetDoc:
2002 * @doc: and xmlDoc parsed XML
2004 * parse an XSLT stylesheet building the associated structures
2006 * Returns a new XSLT stylesheet structure.
2010 xsltParseStylesheetDoc(xmlDocPtr doc) {
2011 xsltStylesheetPtr ret;
2013 ret = xsltParseStylesheetImportedDoc(doc);
2017 xsltResolveStylesheetAttributeSet(ret);
2023 * xsltParseStylesheetFile:
2024 * @filename: the filename/URL to the stylesheet
2026 * Load and parse an XSLT stylesheet
2028 * Returns a new XSLT stylesheet structure.
2032 xsltParseStylesheetFile(const xmlChar* filename) {
2033 xsltSecurityPrefsPtr sec;
2034 xsltStylesheetPtr ret;
2038 if (filename == NULL)
2041 #ifdef WITH_XSLT_DEBUG_PARSING
2042 xsltGenericDebug(xsltGenericDebugContext,
2043 "xsltParseStylesheetFile : parse %s\n", filename);
2047 * Security framework check
2049 sec = xsltGetDefaultSecurityPrefs();
2053 res = xsltCheckRead(sec, NULL, filename);
2055 xsltTransformError(NULL, NULL, NULL,
2056 "xsltParseStylesheetFile: read rights for %s denied\n",
2062 doc = xmlParseFile((const char *) filename);
2064 xsltTransformError(NULL, NULL, NULL,
2065 "xsltParseStylesheetFile : cannot parse %s\n", filename);
2068 ret = xsltParseStylesheetDoc(doc);
2077 /************************************************************************
2079 * Handling of Stylesheet PI *
2081 ************************************************************************/
2084 #define SKIP(val) cur += (val)
2085 #define NXT(val) cur[(val)]
2086 #define SKIP_BLANKS \
2087 while (IS_BLANK(CUR)) NEXT
2088 #define NEXT ((*cur) ? cur++ : cur)
2091 * xsltParseStylesheetPI:
2092 * @value: the value of the PI
2094 * This function checks that the type is text/xml and extracts
2095 * the URI-Reference for the stylesheet
2097 * Returns the URI-Reference for the stylesheet or NULL (it need to
2098 * be freed by the caller)
2101 xsltParseStylesheetPI(const xmlChar *value) {
2103 const xmlChar *start;
2106 xmlChar *href = NULL;
2115 if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
2122 if ((CUR != '\'') && (CUR != '"'))
2127 while ((CUR != 0) && (CUR != tmp))
2131 val = xmlStrndup(start, cur - start);
2135 if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
2136 (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
2142 } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
2149 if ((CUR != '\'') && (CUR != '"'))
2154 while ((CUR != 0) && (CUR != tmp))
2159 href = xmlStrndup(start, cur - start);
2162 while ((CUR != 0) && (!IS_BLANK(CUR)))
2177 * xsltLoadStylesheetPI:
2178 * @doc: a document to process
2180 * This function tries to locate the stylesheet PI in the given document
2181 * If found, and if contained within the document, it will extract
2182 * that subtree to build the stylesheet to process @doc (doc itself will
2183 * be modified). If found but referencing an external document it will
2184 * attempt to load it and generate a stylesheet from it. In both cases,
2185 * the resulting stylesheet and the document need to be freed once the
2186 * transformation is done.
2188 * Returns a new XSLT stylesheet structure or NULL if not found.
2191 xsltLoadStylesheetPI(xmlDocPtr doc) {
2193 xsltStylesheetPtr ret = NULL;
2194 xmlChar *href = NULL;
2201 * Find the text/xml stylesheet PI id any before the root
2203 child = doc->children;
2204 while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
2205 if ((child->type == XML_PI_NODE) &&
2206 (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
2207 href = xsltParseStylesheetPI(child->content);
2211 child = child->next;
2215 * If found check the href to select processing
2218 #ifdef WITH_XSLT_DEBUG_PARSING
2219 xsltGenericDebug(xsltGenericDebugContext,
2220 "xsltLoadStylesheetPI : found PI href=%s\n", href);
2222 URI = xmlParseURI((const char *) href);
2224 xsltTransformError(NULL, NULL, child,
2225 "xml-stylesheet : href %s is not valid\n", href);
2229 if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
2230 (URI->opaque == NULL) && (URI->authority == NULL) &&
2231 (URI->server == NULL) && (URI->user == NULL) &&
2232 (URI->path == NULL) && (URI->query == NULL)) {
2235 #ifdef WITH_XSLT_DEBUG_PARSING
2236 xsltGenericDebug(xsltGenericDebugContext,
2237 "xsltLoadStylesheetPI : Reference to ID %s\n", href);
2239 if (URI->fragment[0] == '#')
2240 ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
2242 ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
2244 xsltTransformError(NULL, NULL, child,
2245 "xml-stylesheet : no ID %s found\n", URI->fragment);
2251 * move the subtree in a new document passed to
2252 * the stylesheet analyzer
2254 subtree = ID->parent;
2255 fake = xmlNewDoc(NULL);
2257 xmlUnlinkNode(subtree);
2258 xmlAddChild((xmlNodePtr) fake, subtree);
2259 ret = xsltParseStylesheetDoc(fake);
2265 xmlChar *URL, *base;
2268 * Reference to an external stylesheet
2271 base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
2272 URL = xmlBuildURI(href, base);
2274 #ifdef WITH_XSLT_DEBUG_PARSING
2275 xsltGenericDebug(xsltGenericDebugContext,
2276 "xsltLoadStylesheetPI : fetching %s\n", URL);
2278 ret = xsltParseStylesheetFile(URL);
2281 #ifdef WITH_XSLT_DEBUG_PARSING
2282 xsltGenericDebug(xsltGenericDebugContext,
2283 "xsltLoadStylesheetPI : fetching %s\n", href);
2285 ret = xsltParseStylesheetFile(href);