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 LIBXSLT_VERSION_EXTRA;
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);
323 if (template->mode) xmlFree(template->mode);
324 if (template->modeURI) xmlFree(template->modeURI);
326 if (template->inheritedNs) xmlFree(template->inheritedNs);
327 memset(template, -1, sizeof(xsltTemplate));
332 * xsltFreeTemplateList:
333 * @template: an XSLT template list
335 * Free up the memory allocated by all the elements of @template
338 xsltFreeTemplateList(xsltTemplatePtr template) {
341 while (template != NULL) {
343 template = template->next;
344 xsltFreeTemplate(cur);
351 * Create a new XSLT Stylesheet
353 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
356 xsltNewStylesheet(void) {
357 xsltStylesheetPtr cur;
359 cur = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
361 xsltTransformError(NULL, NULL, NULL,
362 "xsltNewStylesheet : malloc failed\n");
365 memset(cur, 0, sizeof(xsltStylesheet));
366 cur->omitXmlDeclaration = -1;
367 cur->standalone = -1;
368 cur->decimalFormat = xsltNewDecimalFormat(NULL);
372 cur->exclPrefixNr = 0;
373 cur->exclPrefixMax = 0;
374 cur->exclPrefixTab = NULL;
375 cur->extInfos = NULL;
377 cur->internalized = 1;
378 cur->literal_result = 0;
379 cur->dict = xmlDictCreate();
380 #ifdef WITH_XSLT_DEBUG
381 xsltGenericDebug(xsltGenericDebugContext,
382 "creating dictionary for stylesheet\n");
392 * @style: an XSLT stylesheet
394 * Allocate an extra runtime information slot statically while compiling
395 * the stylesheet and return its number
397 * Returns the number of the slot
400 xsltAllocateExtra(xsltStylesheetPtr style)
402 return(style->extrasNr++);
406 * xsltAllocateExtraCtxt:
407 * @ctxt: an XSLT transformation context
409 * Allocate an extra runtime information slot at run-time
410 * and return its number
411 * This make sure there is a slot ready in the transformation context
413 * Returns the number of the slot
416 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
418 if (ctxt->extrasNr >= ctxt->extrasMax) {
420 if (ctxt->extrasNr == 0) {
421 ctxt->extrasMax = 20;
422 ctxt->extras = (xsltRuntimeExtraPtr)
423 xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
424 if (ctxt->extras == NULL) {
425 xmlGenericError(xmlGenericErrorContext,
426 "xsltAllocateExtraCtxt: out of memory\n");
427 ctxt->state = XSLT_STATE_ERROR;
430 for (i = 0;i < ctxt->extrasMax;i++) {
431 ctxt->extras[i].info = NULL;
432 ctxt->extras[i].deallocate = NULL;
433 ctxt->extras[i].val.ptr = NULL;
437 xsltRuntimeExtraPtr tmp;
439 ctxt->extrasMax += 100;
440 tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
441 ctxt->extrasMax * sizeof(xsltRuntimeExtra));
443 xmlGenericError(xmlGenericErrorContext,
444 "xsltAllocateExtraCtxt: out of memory\n");
445 ctxt->state = XSLT_STATE_ERROR;
449 for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
450 ctxt->extras[i].info = NULL;
451 ctxt->extras[i].deallocate = NULL;
452 ctxt->extras[i].val.ptr = NULL;
456 return(ctxt->extrasNr++);
460 * xsltFreeStylesheetList:
461 * @sheet: an XSLT stylesheet list
463 * Free up the memory allocated by the list @sheet
466 xsltFreeStylesheetList(xsltStylesheetPtr sheet) {
467 xsltStylesheetPtr next;
469 while (sheet != NULL) {
471 xsltFreeStylesheet(sheet);
477 * xsltFreeStylesheet:
478 * @sheet: an XSLT stylesheet
480 * Free up the memory allocated by @sheet
483 xsltFreeStylesheet(xsltStylesheetPtr sheet)
490 xsltFreeTemplateHashes(sheet);
491 xsltFreeDecimalFormatList(sheet);
492 xsltFreeTemplateList(sheet->templates);
493 xsltFreeAttributeSetsHashes(sheet);
494 xsltFreeNamespaceAliasHashes(sheet);
495 xsltFreeStyleDocuments(sheet);
496 xsltFreeStylePreComps(sheet);
497 xsltShutdownExts(sheet);
498 if (sheet->doc != NULL)
499 xmlFreeDoc(sheet->doc);
500 if (sheet->variables != NULL)
501 xsltFreeStackElemList(sheet->variables);
502 if (sheet->cdataSection != NULL)
503 xmlHashFree(sheet->cdataSection, NULL);
504 if (sheet->stripSpaces != NULL)
505 xmlHashFree(sheet->stripSpaces, NULL);
506 if (sheet->nsHash != NULL)
507 xmlHashFree(sheet->nsHash, NULL);
509 if (sheet->exclPrefixTab != NULL)
510 xmlFree(sheet->exclPrefixTab);
511 if (sheet->method != NULL)
512 xmlFree(sheet->method);
513 if (sheet->methodURI != NULL)
514 xmlFree(sheet->methodURI);
515 if (sheet->version != NULL)
516 xmlFree(sheet->version);
517 if (sheet->encoding != NULL)
518 xmlFree(sheet->encoding);
519 if (sheet->doctypePublic != NULL)
520 xmlFree(sheet->doctypePublic);
521 if (sheet->doctypeSystem != NULL)
522 xmlFree(sheet->doctypeSystem);
523 if (sheet->mediaType != NULL)
524 xmlFree(sheet->mediaType);
526 xsltFreeAVTList(sheet->attVTs);
528 if (sheet->imports != NULL)
529 xsltFreeStylesheetList(sheet->imports);
531 #ifdef WITH_XSLT_DEBUG
532 xsltGenericDebug(xsltGenericDebugContext,
533 "freeing dictionary from stylesheet\n");
535 xmlDictFree(sheet->dict);
537 memset(sheet, -1, sizeof(xsltStylesheet));
541 /************************************************************************
543 * Parsing of an XSLT Stylesheet *
545 ************************************************************************/
548 * xsltGetInheritedNsList:
549 * @style: the stylesheet
550 * @template: the template
551 * @node: the current node
553 * Search all the namespace applying to a given element except the ones
554 * from excluded output prefixes currently in scope. Initialize the
555 * template inheritedNs list with it.
557 * Returns the number of entries found
560 xsltGetInheritedNsList(xsltStylesheetPtr style,
561 xsltTemplatePtr template,
565 xmlNsPtr *ret = NULL;
570 if ((style == NULL) || (template == NULL) || (node == NULL) ||
571 (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
573 while (node != NULL) {
574 if (node->type == XML_ELEMENT_NODE) {
576 while (cur != NULL) {
577 if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
579 if ((cur->prefix != NULL) &&
580 (xsltCheckExtPrefix(style, cur->prefix)))
582 for (i = 0;i < style->exclPrefixNr;i++) {
583 if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
588 (xmlNsPtr *) xmlMalloc((maxns + 1) *
591 xmlGenericError(xmlGenericErrorContext,
592 "xsltGetInheritedNsList : out of memory!\n");
597 for (i = 0; i < nbns; i++) {
598 if ((cur->prefix == ret[i]->prefix) ||
599 (xmlStrEqual(cur->prefix, ret[i]->prefix)))
605 ret = (xmlNsPtr *) xmlRealloc(ret,
610 xmlGenericError(xmlGenericErrorContext,
611 "xsltGetInheritedNsList : realloc failed!\n");
625 #ifdef WITH_XSLT_DEBUG_PARSING
626 xsltGenericDebug(xsltGenericDebugContext,
627 "template has %d inherited namespaces\n", nbns);
629 template->inheritedNsNr = nbns;
630 template->inheritedNs = ret;
636 * xsltParseStylesheetOutput:
637 * @style: the XSLT stylesheet
638 * @cur: the "output" element
640 * parse an XSLT stylesheet output element and record
641 * information related to the stylesheet output
645 xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
652 if ((cur == NULL) || (style == NULL))
655 prop = xsltGetNsProp(cur, (const xmlChar *) "version", XSLT_NAMESPACE);
657 if (style->version != NULL)
658 xmlFree(style->version);
659 style->version = prop;
663 xsltGetNsProp(cur, (const xmlChar *) "encoding", XSLT_NAMESPACE);
665 if (style->encoding != NULL)
666 xmlFree(style->encoding);
667 style->encoding = prop;
670 /* relaxed to support xt:document */
671 prop = xmlGetProp(cur, (const xmlChar *) "method");
675 if (style->method != NULL)
676 xmlFree(style->method);
677 style->method = NULL;
678 if (style->methodURI != NULL)
679 xmlFree(style->methodURI);
680 style->methodURI = NULL;
682 URI = xsltGetQNameURI(cur, &prop);
684 if (style != NULL) style->errors++;
685 } else if (URI == NULL) {
686 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
687 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
688 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
689 style->method = prop;
691 xsltTransformError(NULL, style, cur,
692 "invalid value for method: %s\n", prop);
693 if (style != NULL) style->warnings++;
696 style->method = prop;
697 style->methodURI = xmlStrdup(URI);
702 xsltGetNsProp(cur, (const xmlChar *) "doctype-system",
705 if (style->doctypeSystem != NULL)
706 xmlFree(style->doctypeSystem);
707 style->doctypeSystem = prop;
711 xsltGetNsProp(cur, (const xmlChar *) "doctype-public",
714 if (style->doctypePublic != NULL)
715 xmlFree(style->doctypePublic);
716 style->doctypePublic = prop;
719 prop = xsltGetNsProp(cur, (const xmlChar *) "standalone",
722 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
723 style->standalone = 1;
724 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
725 style->standalone = 0;
727 xsltTransformError(NULL, style, cur,
728 "invalid value for standalone: %s\n", prop);
729 if (style != NULL) style->warnings++;
734 prop = xsltGetNsProp(cur, (const xmlChar *) "indent", XSLT_NAMESPACE);
736 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
738 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
741 xsltTransformError(NULL, style, cur,
742 "invalid value for indent: %s\n", prop);
743 if (style != NULL) style->warnings++;
748 prop = xsltGetNsProp(cur, (const xmlChar *) "omit-xml-declaration",
751 if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
752 style->omitXmlDeclaration = 1;
753 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
754 style->omitXmlDeclaration = 0;
756 xsltTransformError(NULL, style, cur,
757 "invalid value for omit-xml-declaration: %s\n",
759 if (style != NULL) style->warnings++;
765 xsltGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
767 if (elements != NULL) {
768 if (style->cdataSection == NULL)
769 style->cdataSection = xmlHashCreate(10);
770 if (style->cdataSection == NULL)
774 while (*element != 0) {
775 while (IS_BLANK(*element))
780 while ((*end != 0) && (!IS_BLANK(*end)))
782 element = xmlStrndup(element, end - element);
785 #ifdef WITH_XSLT_DEBUG_PARSING
786 xsltGenericDebug(xsltGenericDebugContext,
787 "add cdata section output element %s\n",
791 URI = xsltGetQNameURI(cur, &element);
792 if (element == NULL) {
793 if (style != NULL) style->errors++;
797 xmlHashAddEntry2(style->cdataSection, element, URI,
800 * if prefix is NULL, we must check whether it's
801 * necessary to also put in the name of the default
805 ns = xmlSearchNs(style->doc, cur, NULL);
807 xmlHashAddEntry2(style->cdataSection, element,
808 ns->href, (void *) "cdata");
818 prop = xsltGetNsProp(cur, (const xmlChar *) "media-type", XSLT_NAMESPACE);
820 if (style->mediaType)
821 xmlFree(style->mediaType);
822 style->mediaType = prop;
827 * xsltParseStylesheetDecimalFormat:
828 * @style: the XSLT stylesheet
829 * @cur: the "decimal-format" element
831 * parse an XSLT stylesheet decimal-format element and
832 * and record the formatting characteristics
835 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
838 xsltDecimalFormatPtr format;
839 xsltDecimalFormatPtr iter;
841 if ((cur == NULL) || (style == NULL))
844 format = style->decimalFormat;
846 prop = xsltGetNsProp(cur, BAD_CAST("name"), XSLT_NAMESPACE);
848 format = xsltDecimalFormatGetByName(style, prop);
849 if (format != NULL) {
850 xsltTransformError(NULL, style, cur,
851 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
852 if (style != NULL) style->warnings++;
855 format = xsltNewDecimalFormat(prop);
856 if (format == NULL) {
857 xsltTransformError(NULL, style, cur,
858 "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
859 if (style != NULL) style->errors++;
862 /* Append new decimal-format structure */
863 for (iter = style->decimalFormat; iter->next; iter = iter->next)
869 prop = xsltGetNsProp(cur, (const xmlChar *)"decimal-separator",
872 if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
873 format->decimalPoint = prop;
876 prop = xsltGetNsProp(cur, (const xmlChar *)"grouping-separator",
879 if (format->grouping != NULL) xmlFree(format->grouping);
880 format->grouping = prop;
883 prop = xsltGetNsProp(cur, (const xmlChar *)"infinity", XSLT_NAMESPACE);
885 if (format->infinity != NULL) xmlFree(format->infinity);
886 format->infinity = prop;
889 prop = xsltGetNsProp(cur, (const xmlChar *)"minus-sign", XSLT_NAMESPACE);
891 if (format->minusSign != NULL) xmlFree(format->minusSign);
892 format->minusSign = prop;
895 prop = xsltGetNsProp(cur, (const xmlChar *)"NaN", XSLT_NAMESPACE);
897 if (format->noNumber != NULL) xmlFree(format->noNumber);
898 format->noNumber = prop;
901 prop = xsltGetNsProp(cur, (const xmlChar *)"percent", XSLT_NAMESPACE);
903 if (format->percent != NULL) xmlFree(format->percent);
904 format->percent = prop;
907 prop = xsltGetNsProp(cur, (const xmlChar *)"per-mille", XSLT_NAMESPACE);
909 if (format->permille != NULL) xmlFree(format->permille);
910 format->permille = prop;
913 prop = xsltGetNsProp(cur, (const xmlChar *)"zero-digit", XSLT_NAMESPACE);
915 if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
916 format->zeroDigit = prop;
919 prop = xsltGetNsProp(cur, (const xmlChar *)"digit", XSLT_NAMESPACE);
921 if (format->digit != NULL) xmlFree(format->digit);
922 format->digit = prop;
925 prop = xsltGetNsProp(cur, (const xmlChar *)"pattern-separator",
928 if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
929 format->patternSeparator = prop;
934 * xsltParseStylesheetPreserveSpace:
935 * @style: the XSLT stylesheet
936 * @cur: the "preserve-space" element
938 * parse an XSLT stylesheet preserve-space element and record
939 * elements needing preserving
943 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
945 xmlChar *element, *end;
947 if ((cur == NULL) || (style == NULL))
950 elements = xsltGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
951 if (elements == NULL) {
952 xsltTransformError(NULL, style, cur,
953 "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
954 if (style != NULL) style->warnings++;
958 if (style->stripSpaces == NULL)
959 style->stripSpaces = xmlHashCreate(10);
960 if (style->stripSpaces == NULL)
964 while (*element != 0) {
965 while (IS_BLANK(*element)) element++;
969 while ((*end != 0) && (!IS_BLANK(*end))) end++;
970 element = xmlStrndup(element, end - element);
972 #ifdef WITH_XSLT_DEBUG_PARSING
973 xsltGenericDebug(xsltGenericDebugContext,
974 "add preserved space element %s\n", element);
976 if (xmlStrEqual(element, (const xmlChar *)"*")) {
977 style->stripAll = -1;
981 URI = xsltGetQNameURI(cur, &element);
983 xmlHashAddEntry2(style->stripSpaces, element, URI,
984 (xmlChar *) "preserve");
994 * xsltParseStylesheetExtPrefix:
995 * @style: the XSLT stylesheet
996 * @template: the "extension-element-prefixes" prefix
998 * parse an XSLT stylesheet extension prefix and record
999 * prefixes needing stripping
1003 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur) {
1005 xmlChar *prefix, *end;
1007 if ((cur == NULL) || (style == NULL))
1010 prefixes = xsltGetNsProp(cur, (const xmlChar *)"extension-element-prefixes",
1012 if (prefixes == NULL) {
1017 while (*prefix != 0) {
1018 while (IS_BLANK(*prefix)) prefix++;
1022 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1023 prefix = xmlStrndup(prefix, end - prefix);
1027 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1028 ns = xmlSearchNs(style->doc, cur, NULL);
1030 ns = xmlSearchNs(style->doc, cur, prefix);
1032 xsltTransformError(NULL, style, cur,
1033 "xsl:extension-element-prefix : undefined namespace %s\n",
1035 if (style != NULL) style->warnings++;
1037 #ifdef WITH_XSLT_DEBUG_PARSING
1038 xsltGenericDebug(xsltGenericDebugContext,
1039 "add extension prefix %s\n", prefix);
1041 xsltRegisterExtPrefix(style, prefix, ns->href);
1051 * xsltParseStylesheetStripSpace:
1052 * @style: the XSLT stylesheet
1053 * @cur: the "strip-space" element
1055 * parse an XSLT stylesheet strip-space element and record
1056 * elements needing stripping
1060 xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1062 xmlChar *element, *end;
1064 if ((cur == NULL) || (style == NULL))
1067 elements = xsltGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
1068 if (elements == NULL) {
1069 xsltTransformError(NULL, style, cur,
1070 "xsltParseStylesheetStripSpace: missing elements attribute\n");
1071 if (style != NULL) style->warnings++;
1075 if (style->stripSpaces == NULL)
1076 style->stripSpaces = xmlHashCreate(10);
1077 if (style->stripSpaces == NULL)
1081 while (*element != 0) {
1082 while (IS_BLANK(*element)) element++;
1086 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1087 element = xmlStrndup(element, end - element);
1089 #ifdef WITH_XSLT_DEBUG_PARSING
1090 xsltGenericDebug(xsltGenericDebugContext,
1091 "add stripped space element %s\n", element);
1093 if (xmlStrEqual(element, (const xmlChar *)"*")) {
1094 style->stripAll = 1;
1098 URI = xsltGetQNameURI(cur, &element);
1100 xmlHashAddEntry2(style->stripSpaces, element, URI,
1101 (xmlChar *) "strip");
1111 * xsltParseStylesheetExcludePrefix:
1112 * @style: the XSLT stylesheet
1113 * @cur: the current point in the stylesheet
1115 * parse an XSLT stylesheet exclude prefix and record
1116 * namespaces needing stripping
1118 * Returns the number of Excluded prefixes added at that level
1122 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur) {
1125 xmlChar *prefix, *end;
1127 if ((cur == NULL) || (style == NULL))
1130 prefixes = xsltGetNsProp(cur, (const xmlChar *)"exclude-result-prefixes",
1132 if (prefixes == NULL) {
1137 while (*prefix != 0) {
1138 while (IS_BLANK(*prefix)) prefix++;
1142 while ((*end != 0) && (!IS_BLANK(*end))) end++;
1143 prefix = xmlStrndup(prefix, end - prefix);
1147 if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1148 ns = xmlSearchNs(style->doc, cur, NULL);
1150 ns = xmlSearchNs(style->doc, cur, prefix);
1152 xsltTransformError(NULL, style, cur,
1153 "xsl:exclude-result-prefixes : undefined namespace %s\n",
1155 if (style != NULL) style->warnings++;
1157 #ifdef WITH_XSLT_DEBUG_PARSING
1158 xsltGenericDebug(xsltGenericDebugContext,
1159 "exclude result prefix %s\n", prefix);
1161 exclPrefixPush(style, (xmlChar *) ns->href);
1173 * xsltPrecomputeStylesheet:
1174 * @style: the XSLT stylesheet
1175 * @cur: the current child list
1177 * Clean-up the stylesheet content from unwanted ignorable blank nodes
1178 * and run the preprocessing of all XSLT constructs.
1180 * and process xslt:text
1183 xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) {
1185 int internalize = 0;
1187 if ((style != NULL) && (cur != NULL) && (cur->doc != NULL) &&
1188 (style->dict != NULL) && (cur->doc->dict == style->dict))
1191 style->internalized = 0;
1194 * This content comes from the stylesheet
1195 * For stylesheets, the set of whitespace-preserving
1196 * element names consists of just xsl:text.
1199 while (cur != NULL) {
1200 if (delete != NULL) {
1201 #ifdef WITH_XSLT_DEBUG_BLANKS
1202 xsltGenericDebug(xsltGenericDebugContext,
1203 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
1205 xmlUnlinkNode(delete);
1206 xmlFreeNode(delete);
1209 if (cur->type == XML_ELEMENT_NODE) {
1213 * Internalize attributes values.
1215 if ((internalize) && (cur->properties != NULL)) {
1216 xmlAttrPtr prop = cur->properties;
1219 while (prop != NULL) {
1220 txt = prop->children;
1221 if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
1222 (txt->content != NULL) &&
1223 (!xmlDictOwns(style->dict, txt->content))) {
1224 xmlChar *old = (xmlChar *) txt->content;
1227 * internalize the text string, goal is to speed
1228 * up operations and minimize used space by compiled
1231 txt->content = (xmlChar *)
1232 xmlDictLookup(style->dict, old, -1);
1233 if (old != txt->content)
1240 exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur);
1241 if (IS_XSLT_ELEM(cur)) {
1242 xsltStylePreCompute(style, cur);
1243 if (IS_XSLT_NAME(cur, "text")) {
1244 for (;exclPrefixes > 0;exclPrefixes--)
1245 exclPrefixPop(style);
1251 * Remove excluded prefixes
1253 if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
1254 xmlNsPtr ns = cur->nsDef, prev = NULL, next;
1255 xmlNodePtr root = NULL;
1258 root = xmlDocGetRootElement(cur->doc);
1259 if ((root != NULL) && (root != cur)) {
1260 while (ns != NULL) {
1263 for (i = 0;i < style->exclPrefixNr;i++) {
1264 if ((ns->prefix != NULL) &&
1265 (xmlStrEqual(ns->href,
1266 style->exclPrefixTab[i]))) {
1268 * Move the namespace definition on the root
1269 * element to avoid duplicating it without
1273 cur->nsDef = ns->next;
1275 prev->next = ns->next;
1277 ns->next = root->nsDef;
1291 * If we have prefixes locally, recurse and pop them up when
1294 if (exclPrefixes > 0) {
1295 xsltPrecomputeStylesheet(style, cur->children);
1296 for (;exclPrefixes > 0;exclPrefixes--)
1297 exclPrefixPop(style);
1301 } else if (cur->type == XML_TEXT_NODE) {
1302 if (IS_BLANK_NODE(cur)) {
1303 if (xmlNodeGetSpacePreserve(cur) != 1) {
1306 } else if ((cur->content != NULL) && (internalize) &&
1307 (!xmlDictOwns(style->dict, cur->content))) {
1308 xmlChar *old = (xmlChar *) cur->content;
1311 * internalize the text string, goal is to speed
1312 * up operations and minimize used space by compiled
1315 cur->content = (xmlChar *) xmlDictLookup(style->dict, old, -1);
1318 } else if ((cur->type != XML_ELEMENT_NODE) &&
1319 (cur->type != XML_CDATA_SECTION_NODE)) {
1327 if (cur->children != NULL) {
1328 if ((cur->children->type != XML_ENTITY_DECL) &&
1329 (cur->children->type != XML_ENTITY_REF_NODE) &&
1330 (cur->children->type != XML_ENTITY_NODE)) {
1331 cur = cur->children;
1336 if (cur->next != NULL) {
1345 if (cur == (xmlNodePtr) style->doc) {
1349 if (cur->next != NULL) {
1353 } while (cur != NULL);
1355 if (delete != NULL) {
1356 #ifdef WITH_XSLT_DEBUG_PARSING
1357 xsltGenericDebug(xsltGenericDebugContext,
1358 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
1360 xmlUnlinkNode(delete);
1361 xmlFreeNode(delete);
1367 * xsltGatherNamespaces:
1368 * @style: the XSLT stylesheet
1370 * Browse the stylesheet and build the namspace hash table which
1371 * will be used for XPath interpretation. If needed do a bit of normalization
1375 xsltGatherNamespaces(xsltStylesheetPtr style) {
1380 * TODO: basically if the stylesheet uses the same prefix for different
1381 * patterns, well they may be in problem, hopefully they will get
1384 cur = xmlDocGetRootElement(style->doc);
1385 while (cur != NULL) {
1386 if (cur->type == XML_ELEMENT_NODE) {
1387 xmlNsPtr ns = cur->nsDef;
1388 while (ns != NULL) {
1389 if (ns->prefix != NULL) {
1390 if (style->nsHash == NULL) {
1391 style->nsHash = xmlHashCreate(10);
1392 if (style->nsHash == NULL) {
1393 xsltTransformError(NULL, style, cur,
1394 "xsltGatherNamespaces: failed to create hash table\n");
1395 if (style != NULL) style->errors++;
1399 URI = xmlHashLookup(style->nsHash, ns->prefix);
1400 if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
1401 xsltTransformError(NULL, style, cur,
1402 "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
1403 if (style != NULL) style->warnings++;
1404 } else if (URI == NULL) {
1405 xmlHashUpdateEntry(style->nsHash, ns->prefix,
1406 (void *) ns->href, (xmlHashDeallocator)xmlFree);
1408 #ifdef WITH_XSLT_DEBUG_PARSING
1409 xsltGenericDebug(xsltGenericDebugContext,
1410 "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
1421 if (cur->children != NULL) {
1422 if (cur->children->type != XML_ENTITY_DECL) {
1423 cur = cur->children;
1427 if (cur->next != NULL) {
1436 if (cur == (xmlNodePtr) style->doc) {
1440 if (cur->next != NULL) {
1444 } while (cur != NULL);
1449 * xsltParseTemplateContent:
1450 * @style: the XSLT stylesheet
1451 * @templ: the container node (can be a document for literal results)
1453 * parse a template content-model
1454 * Clean-up the template content from unwanted ignorable blank nodes
1455 * and process xslt:text
1459 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
1460 xmlNodePtr cur, delete;
1462 * This content comes from the stylesheet
1463 * For stylesheets, the set of whitespace-preserving
1464 * element names consists of just xsl:text.
1466 cur = templ->children;
1468 while (cur != NULL) {
1469 if (delete != NULL) {
1470 #ifdef WITH_XSLT_DEBUG_BLANKS
1471 xsltGenericDebug(xsltGenericDebugContext,
1472 "xsltParseTemplateContent: removing text\n");
1474 xmlUnlinkNode(delete);
1475 xmlFreeNode(delete);
1478 if (IS_XSLT_ELEM(cur)) {
1479 if (IS_XSLT_NAME(cur, "text")) {
1480 if (cur->children != NULL) {
1482 xmlNodePtr text = cur->children, next;
1485 prop = xsltGetNsProp(cur,
1486 (const xmlChar *)"disable-output-escaping",
1489 #ifdef WITH_XSLT_DEBUG_PARSING
1490 xsltGenericDebug(xsltGenericDebugContext,
1491 "Disable escaping: %s\n", text->content);
1493 if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
1495 } else if (!xmlStrEqual(prop,
1496 (const xmlChar *)"no")){
1497 xsltTransformError(NULL, style, cur,
1498 "xsl:text: disable-output-escaping allows only yes or no\n");
1499 if (style != NULL) style->warnings++;
1505 while (text != NULL) {
1506 if (text->type == XML_COMMENT_NODE) {
1510 if ((text->type != XML_TEXT_NODE) &&
1511 (text->type != XML_CDATA_SECTION_NODE)) {
1512 xsltTransformError(NULL, style, cur,
1513 "xsltParseTemplateContent: xslt:text content problem\n");
1514 if (style != NULL) style->errors++;
1517 if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
1518 text->name = xmlStringTextNoenc;
1523 * replace xsl:text by the list of childs
1526 int internalize = 0;
1527 if ((style != NULL) && (text != NULL) &&
1528 (text->doc != NULL) && (style->dict != NULL) &&
1529 (text->doc->dict == style->dict))
1532 style->internalized = 0;
1534 text = cur->children;
1535 while (text != NULL) {
1536 if ((text->content != NULL) &&
1537 (!xmlDictOwns(style->dict, text->content))) {
1540 * internalize the text string
1542 if (text->doc->dict != NULL) {
1543 xmlChar *old = (xmlChar *) text->content;
1545 (xmlChar *) xmlDictLookup(
1546 text->doc->dict, old, -1);
1552 xmlUnlinkNode(text);
1553 xmlAddPrevSibling(cur, text);
1561 } else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
1562 (xsltCheckExtPrefix(style, cur->ns->prefix))) {
1564 * okay this is an extension element compile it too
1566 xsltStylePreCompute(style, cur);
1569 * This is an element which will be output as part of the
1570 * template exectution, precompile AVT if found.
1572 if ((cur->ns == NULL) && (style->defaultAlias != NULL) &&
1573 (cur->type == XML_ELEMENT_NODE)) {
1574 cur->ns = xmlSearchNsByHref(cur->doc, cur,
1575 style->defaultAlias);
1577 if (cur->properties != NULL) {
1578 xmlAttrPtr attr = cur->properties;
1580 while (attr != NULL) {
1581 xsltCompileAttr(style, attr);
1590 if (cur->children != NULL) {
1591 if (cur->children->type != XML_ENTITY_DECL) {
1592 cur = cur->children;
1597 if (cur->next != NULL) {
1610 if (cur->next != NULL) {
1614 } while (cur != NULL);
1616 if (delete != NULL) {
1617 #ifdef WITH_XSLT_DEBUG_PARSING
1618 xsltGenericDebug(xsltGenericDebugContext,
1619 "xsltParseTemplateContent: removing text\n");
1621 xmlUnlinkNode(delete);
1622 xmlFreeNode(delete);
1627 * Skip the first params
1629 cur = templ->children;
1630 while (cur != NULL) {
1631 if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
1637 * Browse the remainder of the template
1639 while (cur != NULL) {
1640 if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
1641 xmlNodePtr param = cur;
1643 xsltTransformError(NULL, style, cur,
1644 "xsltParseTemplateContent: ignoring misplaced param element\n");
1645 if (style != NULL) style->warnings++;
1647 xmlUnlinkNode(param);
1655 * xsltParseStylesheetKey:
1656 * @style: the XSLT stylesheet
1657 * @key: the "key" element
1659 * parse an XSLT stylesheet key definition and register it
1663 xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
1664 xmlChar *prop = NULL;
1665 xmlChar *use = NULL;
1666 xmlChar *match = NULL;
1667 xmlChar *name = NULL;
1668 xmlChar *nameURI = NULL;
1676 prop = xsltGetNsProp(key, (const xmlChar *)"name", XSLT_NAMESPACE);
1680 URI = xsltGetQNameURI(key, &prop);
1682 if (style != NULL) style->errors++;
1687 nameURI = xmlStrdup(URI);
1689 #ifdef WITH_XSLT_DEBUG_PARSING
1690 xsltGenericDebug(xsltGenericDebugContext,
1691 "xsltParseStylesheetKey: name %s\n", name);
1694 xsltTransformError(NULL, style, key,
1695 "xsl:key : error missing name\n");
1696 if (style != NULL) style->errors++;
1700 match = xsltGetNsProp(key, (const xmlChar *)"match", XSLT_NAMESPACE);
1701 if (match == NULL) {
1702 xsltTransformError(NULL, style, key,
1703 "xsl:key : error missing match\n");
1704 if (style != NULL) style->errors++;
1708 use = xsltGetNsProp(key, (const xmlChar *)"use", XSLT_NAMESPACE);
1710 xsltTransformError(NULL, style, key,
1711 "xsl:key : error missing use\n");
1712 if (style != NULL) style->errors++;
1719 xsltAddKey(style, name, nameURI, match, use, key);
1729 if (nameURI != NULL)
1734 * xsltParseStylesheetTemplate:
1735 * @style: the XSLT stylesheet
1736 * @template: the "template" element
1738 * parse an XSLT stylesheet template building the associated structures
1742 xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
1743 xsltTemplatePtr ret;
1745 xmlChar *mode = NULL;
1746 xmlChar *modeURI = NULL;
1750 if (template == NULL)
1754 * Create and link the structure
1756 ret = xsltNewTemplate();
1759 ret->next = style->templates;
1760 style->templates = ret;
1764 * Check excluded prefixes
1766 exclPrefixes = xsltParseStylesheetExcludePrefix(style, template);
1769 * Get inherited namespaces
1771 xsltGetInheritedNsList(style, ret, template);
1776 prop = xsltGetNsProp(template, (const xmlChar *)"mode", XSLT_NAMESPACE);
1780 URI = xsltGetQNameURI(template, &prop);
1782 if (style != NULL) style->errors++;
1787 modeURI = xmlStrdup(URI);
1789 ret->mode = xmlDictLookup(style->dict, mode, -1);
1790 ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);
1791 #ifdef WITH_XSLT_DEBUG_PARSING
1792 xsltGenericDebug(xsltGenericDebugContext,
1793 "xsltParseStylesheetTemplate: mode %s\n", mode);
1795 if (mode != NULL) xmlFree(mode);
1796 if (modeURI != NULL) xmlFree(modeURI);
1798 prop = xsltGetNsProp(template, (const xmlChar *)"match", XSLT_NAMESPACE);
1800 if (ret->match != NULL) xmlFree(ret->match);
1804 prop = xsltGetNsProp(template, (const xmlChar *)"priority", XSLT_NAMESPACE);
1806 priority = xmlXPathStringEvalNumber(prop);
1807 ret->priority = (float) priority;
1811 prop = xsltGetNsProp(template, (const xmlChar *)"name", XSLT_NAMESPACE);
1814 xsltTemplatePtr cur;
1816 if (ret->name != NULL) {
1820 if (ret->nameURI != NULL) {
1821 xmlFree(ret->nameURI);
1822 ret->nameURI = NULL;
1825 URI = xsltGetQNameURI(template, &prop);
1827 if (style != NULL) style->errors++;
1830 if (xmlValidateNCName(prop,0)) {
1831 xsltTransformError(NULL, style, template,
1832 "xsl:template : error invalid name '%s'\n", prop);
1833 if (style != NULL) style->errors++;
1838 ret->nameURI = xmlStrdup(URI);
1840 ret->nameURI = NULL;
1842 while (cur != NULL) {
1843 if ((URI != NULL && xmlStrEqual(cur->name, prop) &&
1844 xmlStrEqual(cur->nameURI, URI) ) ||
1845 (URI == NULL && cur->nameURI == NULL &&
1846 xmlStrEqual(cur->name, prop))) {
1847 xsltTransformError(NULL, style, template,
1848 "xsl:template: error duplicate name '%s'\n", prop);
1858 * parse the content and register the pattern
1860 xsltParseTemplateContent(style, template);
1861 ret->elem = template;
1862 ret->content = template->children;
1863 xsltAddTemplate(style, ret, ret->mode, ret->modeURI);
1866 for (;exclPrefixes > 0;exclPrefixes--)
1867 exclPrefixPop(style);
1871 * xsltParseStylesheetTop:
1872 * @style: the XSLT stylesheet
1873 * @top: the top level "stylesheet" element
1875 * scan the top level elements of an XSL stylesheet
1879 xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
1882 #ifdef WITH_XSLT_DEBUG_PARSING
1889 prop = xsltGetNsProp(top, (const xmlChar *)"version", XSLT_NAMESPACE);
1891 xsltTransformError(NULL, style, top,
1892 "xsl:version is missing: document may not be a stylesheet\n");
1893 if (style != NULL) style->warnings++;
1895 if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
1896 (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
1897 xsltTransformError(NULL, style, top,
1898 "xsl:version: only 1.0 features are supported\n");
1899 /* TODO set up compatibility when not XSLT 1.0 */
1900 if (style != NULL) style->warnings++;
1905 cur = top->children;
1908 * process xsl:import elements
1910 while (cur != NULL) {
1911 if (IS_BLANK_NODE(cur)) {
1915 if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
1916 if (xsltParseStylesheetImport(style, cur) != 0)
1917 if (style != NULL) style->errors++;
1924 * process other top-level elements
1926 while (cur != NULL) {
1927 if (IS_BLANK_NODE(cur)) {
1931 if (cur->type == XML_TEXT_NODE) {
1932 if (cur->content != NULL) {
1933 xsltTransformError(NULL, style, cur,
1934 "misplaced text element: '%s'\n", cur->content);
1936 if (style != NULL) style->errors++;
1940 if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
1941 xsltGenericError(xsltGenericErrorContext,
1942 "Found a top-level element %s with null namespace URI\n",
1944 if (style != NULL) style->errors++;
1948 if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
1949 xsltTopLevelFunction function;
1951 function = xsltExtModuleTopLevelLookup(cur->name,
1953 if (function != NULL)
1954 function(style, cur);
1956 #ifdef WITH_XSLT_DEBUG_PARSING
1957 xsltGenericDebug(xsltGenericDebugContext,
1958 "xsltParseStylesheetTop : found foreign element %s\n",
1964 if (IS_XSLT_NAME(cur, "import")) {
1965 xsltTransformError(NULL, style, cur,
1966 "xsltParseStylesheetTop: ignoring misplaced import element\n");
1967 if (style != NULL) style->errors++;
1968 } else if (IS_XSLT_NAME(cur, "include")) {
1969 if (xsltParseStylesheetInclude(style, cur) != 0)
1970 if (style != NULL) style->errors++;
1971 } else if (IS_XSLT_NAME(cur, "strip-space")) {
1972 xsltParseStylesheetStripSpace(style, cur);
1973 } else if (IS_XSLT_NAME(cur, "preserve-space")) {
1974 xsltParseStylesheetPreserveSpace(style, cur);
1975 } else if (IS_XSLT_NAME(cur, "output")) {
1976 xsltParseStylesheetOutput(style, cur);
1977 } else if (IS_XSLT_NAME(cur, "key")) {
1978 xsltParseStylesheetKey(style, cur);
1979 } else if (IS_XSLT_NAME(cur, "decimal-format")) {
1980 xsltParseStylesheetDecimalFormat(style, cur);
1981 } else if (IS_XSLT_NAME(cur, "attribute-set")) {
1982 xsltParseStylesheetAttributeSet(style, cur);
1983 } else if (IS_XSLT_NAME(cur, "variable")) {
1984 xsltParseGlobalVariable(style, cur);
1985 } else if (IS_XSLT_NAME(cur, "param")) {
1986 xsltParseGlobalParam(style, cur);
1987 } else if (IS_XSLT_NAME(cur, "template")) {
1988 #ifdef WITH_XSLT_DEBUG_PARSING
1991 xsltParseStylesheetTemplate(style, cur);
1992 } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
1993 xsltNamespaceAlias(style, cur);
1995 if ((style != NULL) && (style->doc->version != NULL) &&
1996 (!strncmp((const char *) style->doc->version, "1.0", 3))) {
1997 xsltTransformError(NULL, style, cur,
1998 "xsltParseStylesheetTop: unknown %s element\n",
2000 if (style != NULL) style->errors++;
2003 /* do Forwards-Compatible Processing */
2004 xsltTransformError(NULL, style, cur,
2005 "xsltParseStylesheetTop: ignoring unknown %s element\n",
2007 if (style != NULL) style->warnings++;
2012 #ifdef WITH_XSLT_DEBUG_PARSING
2013 xsltGenericDebug(xsltGenericDebugContext,
2014 "parsed %d templates\n", templates);
2019 * xsltParseStylesheetProcess:
2020 * @ret: the XSLT stylesheet
2021 * @doc: and xmlDoc parsed XML
2023 * parse an XSLT stylesheet adding the associated structures
2025 * Returns the value of the 'ret' parameter if everything
2026 * went right, NULL if something went amiss.
2030 xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
2039 * First steps, remove blank nodes,
2040 * locate the xsl:stylesheet element and the
2041 * namespace declaration.
2043 cur = xmlDocGetRootElement(doc);
2045 xsltTransformError(NULL, ret, (xmlNodePtr) doc,
2046 "xsltParseStylesheetProcess : empty stylesheet\n");
2049 xsltParseStylesheetExcludePrefix(ret, cur);
2050 if ((IS_XSLT_ELEM(cur)) &&
2051 ((IS_XSLT_NAME(cur, "stylesheet")) ||
2052 (IS_XSLT_NAME(cur, "transform")))) {
2053 #ifdef WITH_XSLT_DEBUG_PARSING
2054 xsltGenericDebug(xsltGenericDebugContext,
2055 "xsltParseStylesheetProcess : found stylesheet\n");
2057 ret->literal_result = 0;
2059 xsltParseStylesheetExtPrefix(ret, cur);
2061 ret->literal_result = 1;
2063 if (!ret->nopreproc)
2064 xsltPrecomputeStylesheet(ret, cur);
2066 if (ret->literal_result == 0) {
2068 xsltParseStylesheetTop(ret, cur);
2071 xsltTemplatePtr template;
2074 * the document itself might be the template, check xsl:version
2076 prop = xsltGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
2078 xsltTransformError(NULL, ret, cur,
2079 "xsltParseStylesheetProcess : document is not a stylesheet\n");
2083 #ifdef WITH_XSLT_DEBUG_PARSING
2084 xsltGenericDebug(xsltGenericDebugContext,
2085 "xsltParseStylesheetProcess : document is stylesheet\n");
2088 if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) {
2089 xsltTransformError(NULL, ret, cur,
2090 "xsl:version: only 1.0 features are supported\n");
2091 /* TODO set up compatibility when not XSLT 1.0 */
2097 * Create and link the template
2099 template = xsltNewTemplate();
2100 if (template == NULL) {
2103 template->next = ret->templates;
2104 ret->templates = template;
2105 template->match = xmlStrdup((const xmlChar *)"/");
2108 * parse the content and register the pattern
2110 xsltParseTemplateContent(ret, (xmlNodePtr) doc);
2111 template->elem = (xmlNodePtr) doc;
2112 template->content = doc->children;
2113 xsltAddTemplate(ret, template, NULL, NULL);
2114 ret->literal_result = 1;
2121 * xsltParseStylesheetImportedDoc:
2122 * @doc: an xmlDoc parsed XML
2123 * @style: pointer to parent stylesheet
2125 * parse an XSLT stylesheet building the associated structures
2126 * except the processing not needed for imported documents.
2128 * Returns a new XSLT stylesheet structure.
2132 xsltParseStylesheetImportedDoc(xmlDocPtr doc, xsltStylesheetPtr style) {
2133 xsltStylesheetPtr ret;
2138 ret = xsltNewStylesheet();
2141 if (doc->dict != NULL) {
2142 xmlDictFree(ret->dict);
2143 ret->dict = doc->dict;
2144 #ifdef WITH_XSLT_DEBUG
2145 xsltGenericDebug(xsltGenericDebugContext,
2146 "reusing dictionary from %s for stylesheet\n",
2149 xmlDictReference(ret->dict);
2153 ret->parent = style; /* needed to prevent loops */
2154 xsltGatherNamespaces(ret);
2155 if (xsltParseStylesheetProcess(ret, doc) == NULL) {
2157 xsltFreeStylesheet(ret);
2161 if (ret->errors != 0) {
2163 xsltFreeStylesheet(ret);
2172 * xsltParseStylesheetDoc:
2173 * @doc: and xmlDoc parsed XML
2175 * parse an XSLT stylesheet building the associated structures
2177 * Returns a new XSLT stylesheet structure.
2181 xsltParseStylesheetDoc(xmlDocPtr doc) {
2182 xsltStylesheetPtr ret;
2184 ret = xsltParseStylesheetImportedDoc(doc, NULL);
2188 xsltResolveStylesheetAttributeSet(ret);
2194 * xsltParseStylesheetFile:
2195 * @filename: the filename/URL to the stylesheet
2197 * Load and parse an XSLT stylesheet
2199 * Returns a new XSLT stylesheet structure.
2203 xsltParseStylesheetFile(const xmlChar* filename) {
2204 xsltSecurityPrefsPtr sec;
2205 xsltStylesheetPtr ret;
2209 if (filename == NULL)
2212 #ifdef WITH_XSLT_DEBUG_PARSING
2213 xsltGenericDebug(xsltGenericDebugContext,
2214 "xsltParseStylesheetFile : parse %s\n", filename);
2218 * Security framework check
2220 sec = xsltGetDefaultSecurityPrefs();
2224 res = xsltCheckRead(sec, NULL, filename);
2226 xsltTransformError(NULL, NULL, NULL,
2227 "xsltParseStylesheetFile: read rights for %s denied\n",
2233 doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,
2234 NULL, XSLT_LOAD_START);
2236 xsltTransformError(NULL, NULL, NULL,
2237 "xsltParseStylesheetFile : cannot parse %s\n", filename);
2240 ret = xsltParseStylesheetDoc(doc);
2249 /************************************************************************
2251 * Handling of Stylesheet PI *
2253 ************************************************************************/
2256 #define SKIP(val) cur += (val)
2257 #define NXT(val) cur[(val)]
2258 #define SKIP_BLANKS \
2259 while (IS_BLANK(CUR)) NEXT
2260 #define NEXT ((*cur) ? cur++ : cur)
2263 * xsltParseStylesheetPI:
2264 * @value: the value of the PI
2266 * This function checks that the type is text/xml and extracts
2267 * the URI-Reference for the stylesheet
2269 * Returns the URI-Reference for the stylesheet or NULL (it need to
2270 * be freed by the caller)
2273 xsltParseStylesheetPI(const xmlChar *value) {
2275 const xmlChar *start;
2278 xmlChar *href = NULL;
2287 if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
2294 if ((CUR != '\'') && (CUR != '"'))
2299 while ((CUR != 0) && (CUR != tmp))
2303 val = xmlStrndup(start, cur - start);
2307 if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
2308 (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
2314 } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
2321 if ((CUR != '\'') && (CUR != '"'))
2326 while ((CUR != 0) && (CUR != tmp))
2331 href = xmlStrndup(start, cur - start);
2334 while ((CUR != 0) && (!IS_BLANK(CUR)))
2349 * xsltLoadStylesheetPI:
2350 * @doc: a document to process
2352 * This function tries to locate the stylesheet PI in the given document
2353 * If found, and if contained within the document, it will extract
2354 * that subtree to build the stylesheet to process @doc (doc itself will
2355 * be modified). If found but referencing an external document it will
2356 * attempt to load it and generate a stylesheet from it. In both cases,
2357 * the resulting stylesheet and the document need to be freed once the
2358 * transformation is done.
2360 * Returns a new XSLT stylesheet structure or NULL if not found.
2363 xsltLoadStylesheetPI(xmlDocPtr doc) {
2365 xsltStylesheetPtr ret = NULL;
2366 xmlChar *href = NULL;
2373 * Find the text/xml stylesheet PI id any before the root
2375 child = doc->children;
2376 while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
2377 if ((child->type == XML_PI_NODE) &&
2378 (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
2379 href = xsltParseStylesheetPI(child->content);
2383 child = child->next;
2387 * If found check the href to select processing
2390 #ifdef WITH_XSLT_DEBUG_PARSING
2391 xsltGenericDebug(xsltGenericDebugContext,
2392 "xsltLoadStylesheetPI : found PI href=%s\n", href);
2394 URI = xmlParseURI((const char *) href);
2396 xsltTransformError(NULL, NULL, child,
2397 "xml-stylesheet : href %s is not valid\n", href);
2401 if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
2402 (URI->opaque == NULL) && (URI->authority == NULL) &&
2403 (URI->server == NULL) && (URI->user == NULL) &&
2404 (URI->path == NULL) && (URI->query == NULL)) {
2407 #ifdef WITH_XSLT_DEBUG_PARSING
2408 xsltGenericDebug(xsltGenericDebugContext,
2409 "xsltLoadStylesheetPI : Reference to ID %s\n", href);
2411 if (URI->fragment[0] == '#')
2412 ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
2414 ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
2416 xsltTransformError(NULL, NULL, child,
2417 "xml-stylesheet : no ID %s found\n", URI->fragment);
2423 * move the subtree in a new document passed to
2424 * the stylesheet analyzer
2426 subtree = ID->parent;
2427 fake = xmlNewDoc(NULL);
2430 * the dictionnary should be shared since nodes are
2433 fake->dict = doc->dict;
2434 xmlDictReference(doc->dict);
2435 #ifdef WITH_XSLT_DEBUG
2436 xsltGenericDebug(xsltGenericDebugContext,
2437 "reusing dictionary from %s for stylesheet\n",
2441 xmlUnlinkNode(subtree);
2442 xmlAddChild((xmlNodePtr) fake, subtree);
2443 ret = xsltParseStylesheetDoc(fake);
2449 xmlChar *URL, *base;
2452 * Reference to an external stylesheet
2455 base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
2456 URL = xmlBuildURI(href, base);
2458 #ifdef WITH_XSLT_DEBUG_PARSING
2459 xsltGenericDebug(xsltGenericDebugContext,
2460 "xsltLoadStylesheetPI : fetching %s\n", URL);
2462 ret = xsltParseStylesheetFile(URL);
2465 #ifdef WITH_XSLT_DEBUG_PARSING
2466 xsltGenericDebug(xsltGenericDebugContext,
2467 "xsltLoadStylesheetPI : fetching %s\n", href);
2469 ret = xsltParseStylesheetFile(href);