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>
30 #include <libxml/xpath.h>
32 #include "xsltInternals.h"
34 #include "variables.h"
35 #include "namespaces.h"
36 #include "attributes.h"
37 #include "xsltutils.h"
40 #include "documents.h"
41 #include "extensions.h"
46 #ifdef WITH_XSLT_DEBUG
47 #define WITH_XSLT_DEBUG_PARSING
48 /* #define WITH_XSLT_DEBUG_BLANKS */
51 const char *xsltEngineVersion
= LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA
;
52 const int xsltLibxsltVersion
= LIBXSLT_VERSION
;
53 const int xsltLibxmlVersion
= LIBXML_VERSION
;
55 #ifdef XSLT_REFACTORED
57 const xmlChar
*xsltConstNamespaceNameXSLT
= (const xmlChar
*) XSLT_NAMESPACE
;
59 #define XSLT_ELEMENT_CATEGORY_XSLT 0
60 #define XSLT_ELEMENT_CATEGORY_EXTENSION 1
61 #define XSLT_ELEMENT_CATEGORY_LRE 2
64 * xsltLiteralResultMarker:
65 * Marker for Literal result elements, in order to avoid multiple attempts
66 * to recognize such elements in the stylesheet's tree.
67 * This marker is set on node->psvi during the initial traversal
68 * of a stylesheet's node tree.
70 const xmlChar *xsltLiteralResultMarker =
71 (const xmlChar *) "Literal Result Element";
76 * Marker for xsl:text elements. Used to recognize xsl:text elements
77 * for post-processing of the stylesheet's tree, where those
78 * elements are removed from the tree.
80 const xmlChar
*xsltXSLTTextMarker
= (const xmlChar
*) "XSLT Text Element";
84 * Marker for XSLT attribute on Literal Result Elements.
86 const xmlChar
*xsltXSLTAttrMarker
= (const xmlChar
*) "LRE XSLT Attr";
90 #ifdef XSLT_LOCALE_WINAPI
91 extern xmlRMutexPtr xsltLocaleMutex
;
94 * Harmless but avoiding a problem when compiling against a
95 * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
97 #ifndef LIBXML_DEBUG_ENABLED
98 double xmlXPathStringEvalNumber(const xmlChar
*str
);
107 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
113 #define IS_BLANK_NODE(n) \
114 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
117 * xsltParseContentError:
119 * @style: the stylesheet
120 * @node: the node where the error occured
122 * Compile-time error function.
125 xsltParseContentError(xsltStylesheetPtr style
,
128 if ((style
== NULL
) || (node
== NULL
))
131 if (IS_XSLT_ELEM(node
))
132 xsltTransformError(NULL
, style
, node
,
133 "The XSLT-element '%s' is not allowed at this position.\n",
136 xsltTransformError(NULL
, style
, node
,
137 "The element '%s' is not allowed at this position.\n",
142 #ifdef XSLT_REFACTORED
146 * @style: the transformation stylesheet
147 * @value: the excluded namespace name to push on the stack
149 * Push an excluded namespace name on the stack
151 * Returns the new index in the stack or -1 if already present or
155 exclPrefixPush(xsltStylesheetPtr style
, xmlChar
* value
)
159 if (style
->exclPrefixMax
== 0) {
160 style
->exclPrefixMax
= 4;
161 style
->exclPrefixTab
=
162 (xmlChar
* *)xmlMalloc(style
->exclPrefixMax
*
163 sizeof(style
->exclPrefixTab
[0]));
164 if (style
->exclPrefixTab
== NULL
) {
165 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
169 /* do not push duplicates */
170 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
171 if (xmlStrEqual(style
->exclPrefixTab
[i
], value
))
174 if (style
->exclPrefixNr
>= style
->exclPrefixMax
) {
175 style
->exclPrefixMax
*= 2;
176 style
->exclPrefixTab
=
177 (xmlChar
* *)xmlRealloc(style
->exclPrefixTab
,
178 style
->exclPrefixMax
*
179 sizeof(style
->exclPrefixTab
[0]));
180 if (style
->exclPrefixTab
== NULL
) {
181 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
185 style
->exclPrefixTab
[style
->exclPrefixNr
] = value
;
186 style
->exclPrefix
= value
;
187 return (style
->exclPrefixNr
++);
191 * @style: the transformation stylesheet
193 * Pop an excluded prefix value from the stack
195 * Returns the stored excluded prefix value
198 exclPrefixPop(xsltStylesheetPtr style
)
202 if (style
->exclPrefixNr
<= 0)
204 style
->exclPrefixNr
--;
205 if (style
->exclPrefixNr
> 0)
206 style
->exclPrefix
= style
->exclPrefixTab
[style
->exclPrefixNr
- 1];
208 style
->exclPrefix
= NULL
;
209 ret
= style
->exclPrefixTab
[style
->exclPrefixNr
];
210 style
->exclPrefixTab
[style
->exclPrefixNr
] = 0;
215 /************************************************************************
219 ************************************************************************/
221 static int initialized
= 0;
225 * Initializes the processor (e.g. registers built-in extensions,
230 if (initialized
== 0) {
232 #ifdef XSLT_LOCALE_WINAPI
233 xsltLocaleMutex
= xmlNewRMutex();
235 xsltRegisterAllExtras();
242 * Uninitializes the processor.
253 * Check if a string is ignorable
255 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
258 xsltIsBlank(xmlChar
*str
) {
262 if (!(IS_BLANK(*str
))) return(0);
268 /************************************************************************
270 * Routines to handle XSLT data structures *
272 ************************************************************************/
273 static xsltDecimalFormatPtr
274 xsltNewDecimalFormat(xmlChar
*name
)
276 xsltDecimalFormatPtr self
;
277 /* UTF-8 for 0x2030 */
278 static const xmlChar permille
[4] = {0xe2, 0x80, 0xb0, 0};
280 self
= xmlMalloc(sizeof(xsltDecimalFormat
));
286 self
->digit
= xmlStrdup(BAD_CAST("#"));
287 self
->patternSeparator
= xmlStrdup(BAD_CAST(";"));
288 self
->decimalPoint
= xmlStrdup(BAD_CAST("."));
289 self
->grouping
= xmlStrdup(BAD_CAST(","));
290 self
->percent
= xmlStrdup(BAD_CAST("%"));
291 self
->permille
= xmlStrdup(BAD_CAST(permille
));
292 self
->zeroDigit
= xmlStrdup(BAD_CAST("0"));
293 self
->minusSign
= xmlStrdup(BAD_CAST("-"));
294 self
->infinity
= xmlStrdup(BAD_CAST("Infinity"));
295 self
->noNumber
= xmlStrdup(BAD_CAST("NaN"));
301 xsltFreeDecimalFormat(xsltDecimalFormatPtr self
)
305 xmlFree(self
->digit
);
306 if (self
->patternSeparator
)
307 xmlFree(self
->patternSeparator
);
308 if (self
->decimalPoint
)
309 xmlFree(self
->decimalPoint
);
311 xmlFree(self
->grouping
);
313 xmlFree(self
->percent
);
315 xmlFree(self
->permille
);
317 xmlFree(self
->zeroDigit
);
319 xmlFree(self
->minusSign
);
321 xmlFree(self
->infinity
);
323 xmlFree(self
->noNumber
);
331 xsltFreeDecimalFormatList(xsltStylesheetPtr self
)
333 xsltDecimalFormatPtr iter
;
334 xsltDecimalFormatPtr tmp
;
339 iter
= self
->decimalFormat
;
340 while (iter
!= NULL
) {
342 xsltFreeDecimalFormat(iter
);
348 * xsltDecimalFormatGetByName:
349 * @style: the XSLT stylesheet
350 * @name: the decimal-format name to find
352 * Find decimal-format by name
354 * Returns the xsltDecimalFormatPtr
357 xsltDecimalFormatGetByName(xsltStylesheetPtr style
, xmlChar
*name
)
359 xsltDecimalFormatPtr result
= NULL
;
362 return style
->decimalFormat
;
364 while (style
!= NULL
) {
365 for (result
= style
->decimalFormat
->next
;
367 result
= result
->next
) {
368 if (xmlStrEqual(name
, result
->name
))
371 style
= xsltNextImport(style
);
380 * Create a new XSLT Template
382 * Returns the newly allocated xsltTemplatePtr or NULL in case of error
384 static xsltTemplatePtr
385 xsltNewTemplate(void) {
388 cur
= (xsltTemplatePtr
) xmlMalloc(sizeof(xsltTemplate
));
390 xsltTransformError(NULL
, NULL
, NULL
,
391 "xsltNewTemplate : malloc failed\n");
394 memset(cur
, 0, sizeof(xsltTemplate
));
395 cur
->priority
= XSLT_PAT_NO_PRIORITY
;
401 * @template: an XSLT template
403 * Free up the memory allocated by @template
406 xsltFreeTemplate(xsltTemplatePtr
template) {
407 if (template == NULL
)
409 if (template->match
) xmlFree(template->match
);
411 * NOTE: @name and @nameURI are put into the string dict now.
412 * if (template->name) xmlFree(template->name);
413 * if (template->nameURI) xmlFree(template->nameURI);
416 if (template->mode) xmlFree(template->mode);
417 if (template->modeURI) xmlFree(template->modeURI);
419 if (template->inheritedNs
) xmlFree(template->inheritedNs
);
420 memset(template, -1, sizeof(xsltTemplate
));
425 * xsltFreeTemplateList:
426 * @template: an XSLT template list
428 * Free up the memory allocated by all the elements of @template
431 xsltFreeTemplateList(xsltTemplatePtr
template) {
434 while (template != NULL
) {
436 template = template->next
;
437 xsltFreeTemplate(cur
);
441 #ifdef XSLT_REFACTORED
444 xsltFreeNsAliasList(xsltNsAliasPtr item
)
456 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
458 xsltFreeNamespaceMap(xsltNsMapPtr item
)
471 xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt
,
478 if ((cctxt
== NULL
) || (doc
== NULL
) || (ns
== NULL
))
481 ret
= (xsltNsMapPtr
) xmlMalloc(sizeof(xsltNsMap
));
483 xsltTransformError(NULL
, cctxt
->style
, elem
,
484 "Internal error: (xsltNewNamespaceMapItem) "
485 "memory allocation failed.\n");
488 memset(ret
, 0, sizeof(xsltNsMap
));
491 ret
->origNsName
= ns
->href
;
493 * Store the item at current stylesheet-level.
495 if (cctxt
->psData
->nsMap
!= NULL
)
496 ret
->next
= cctxt
->psData
->nsMap
;
497 cctxt
->psData
->nsMap
= ret
;
501 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
504 * xsltCompilerVarInfoFree:
505 * @cctxt: the compilation context
507 * Frees the list of information for vars/params.
510 xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt
)
512 xsltVarInfoPtr ivar
= cctxt
->ivars
, ivartmp
;
522 * xsltCompilerCtxtFree:
524 * Free an XSLT compiler context.
527 xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt
)
531 #ifdef WITH_XSLT_DEBUG_PARSING
532 xsltGenericDebug(xsltGenericDebugContext
,
533 "Freeing compilation context\n");
534 xsltGenericDebug(xsltGenericDebugContext
,
535 "### Max inodes: %d\n", cctxt
->maxNodeInfos
);
536 xsltGenericDebug(xsltGenericDebugContext
,
537 "### Max LREs : %d\n", cctxt
->maxLREs
);
542 if (cctxt
->inodeList
!= NULL
) {
543 xsltCompilerNodeInfoPtr tmp
, cur
= cctxt
->inodeList
;
544 while (cur
!= NULL
) {
550 if (cctxt
->tmpList
!= NULL
)
551 xsltPointerListFree(cctxt
->tmpList
);
552 #ifdef XSLT_REFACTORED_XPATHCOMP
553 if (cctxt
->xpathCtxt
!= NULL
)
554 xmlXPathFreeContext(cctxt
->xpathCtxt
);
556 if (cctxt
->nsAliases
!= NULL
)
557 xsltFreeNsAliasList(cctxt
->nsAliases
);
560 xsltCompilerVarInfoFree(cctxt
);
566 * xsltCompilerCreate:
568 * Creates an XSLT compiler context.
570 * Returns the pointer to the created xsltCompilerCtxt or
571 * NULL in case of an internal error.
573 static xsltCompilerCtxtPtr
574 xsltCompilationCtxtCreate(xsltStylesheetPtr style
) {
575 xsltCompilerCtxtPtr ret
;
577 ret
= (xsltCompilerCtxtPtr
) xmlMalloc(sizeof(xsltCompilerCtxt
));
579 xsltTransformError(NULL
, style
, NULL
,
580 "xsltCompilerCreate: allocation of compiler "
581 "context failed.\n");
584 memset(ret
, 0, sizeof(xsltCompilerCtxt
));
586 ret
->errSeverity
= XSLT_ERROR_SEVERITY_ERROR
;
587 ret
->tmpList
= xsltPointerListCreate(20);
588 if (ret
->tmpList
== NULL
) {
591 #ifdef XSLT_REFACTORED_XPATHCOMP
593 * Create the XPath compilation context in order
594 * to speed up precompilation of XPath expressions.
596 ret
->xpathCtxt
= xmlXPathNewContext(NULL
);
597 if (ret
->xpathCtxt
== NULL
)
604 xsltCompilationCtxtFree(ret
);
609 xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first
)
611 xsltEffectiveNsPtr tmp
;
613 while (first
!= NULL
) {
615 first
= first
->nextInStore
;
621 xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data
)
626 if (data
->inScopeNamespaces
!= NULL
) {
628 xsltNsListContainerPtr nsi
;
629 xsltPointerListPtr list
=
630 (xsltPointerListPtr
) data
->inScopeNamespaces
;
632 for (i
= 0; i
< list
->number
; i
++) {
634 * REVISIT TODO: Free info of in-scope namespaces.
636 nsi
= (xsltNsListContainerPtr
) list
->items
[i
];
637 if (nsi
->list
!= NULL
)
641 xsltPointerListFree(list
);
642 data
->inScopeNamespaces
= NULL
;
645 if (data
->exclResultNamespaces
!= NULL
) {
647 xsltPointerListPtr list
= (xsltPointerListPtr
)
648 data
->exclResultNamespaces
;
650 for (i
= 0; i
< list
->number
; i
++)
651 xsltPointerListFree((xsltPointerListPtr
) list
->items
[i
]);
653 xsltPointerListFree(list
);
654 data
->exclResultNamespaces
= NULL
;
657 if (data
->extElemNamespaces
!= NULL
) {
658 xsltPointerListPtr list
= (xsltPointerListPtr
)
659 data
->extElemNamespaces
;
662 for (i
= 0; i
< list
->number
; i
++)
663 xsltPointerListFree((xsltPointerListPtr
) list
->items
[i
]);
665 xsltPointerListFree(list
);
666 data
->extElemNamespaces
= NULL
;
668 if (data
->effectiveNs
) {
669 xsltLREEffectiveNsNodesFree(data
->effectiveNs
);
670 data
->effectiveNs
= NULL
;
672 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
673 xsltFreeNamespaceMap(data
->nsMap
);
678 static xsltPrincipalStylesheetDataPtr
679 xsltNewPrincipalStylesheetData(void)
681 xsltPrincipalStylesheetDataPtr ret
;
683 ret
= (xsltPrincipalStylesheetDataPtr
)
684 xmlMalloc(sizeof(xsltPrincipalStylesheetData
));
686 xsltTransformError(NULL
, NULL
, NULL
,
687 "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
690 memset(ret
, 0, sizeof(xsltPrincipalStylesheetData
));
693 * Global list of in-scope namespaces.
695 ret
->inScopeNamespaces
= xsltPointerListCreate(-1);
696 if (ret
->inScopeNamespaces
== NULL
)
699 * Global list of excluded result ns-decls.
701 ret
->exclResultNamespaces
= xsltPointerListCreate(-1);
702 if (ret
->exclResultNamespaces
== NULL
)
705 * Global list of extension instruction namespace names.
707 ret
->extElemNamespaces
= xsltPointerListCreate(-1);
708 if (ret
->extElemNamespaces
== NULL
)
723 * Create a new XSLT Stylesheet
725 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
728 xsltNewStylesheet(void) {
729 xsltStylesheetPtr ret
= NULL
;
731 ret
= (xsltStylesheetPtr
) xmlMalloc(sizeof(xsltStylesheet
));
733 xsltTransformError(NULL
, NULL
, NULL
,
734 "xsltNewStylesheet : malloc failed\n");
737 memset(ret
, 0, sizeof(xsltStylesheet
));
739 ret
->omitXmlDeclaration
= -1;
740 ret
->standalone
= -1;
741 ret
->decimalFormat
= xsltNewDecimalFormat(NULL
);
745 ret
->exclPrefixNr
= 0;
746 ret
->exclPrefixMax
= 0;
747 ret
->exclPrefixTab
= NULL
;
748 ret
->extInfos
= NULL
;
750 ret
->internalized
= 1;
751 ret
->literal_result
= 0;
752 ret
->dict
= xmlDictCreate();
753 #ifdef WITH_XSLT_DEBUG
754 xsltGenericDebug(xsltGenericDebugContext
,
755 "creating dictionary for stylesheet\n");
764 xsltFreeStylesheet(ret
);
770 * @style: an XSLT stylesheet
772 * Allocate an extra runtime information slot statically while compiling
773 * the stylesheet and return its number
775 * Returns the number of the slot
778 xsltAllocateExtra(xsltStylesheetPtr style
)
780 return(style
->extrasNr
++);
784 * xsltAllocateExtraCtxt:
785 * @ctxt: an XSLT transformation context
787 * Allocate an extra runtime information slot at run-time
788 * and return its number
789 * This make sure there is a slot ready in the transformation context
791 * Returns the number of the slot
794 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt
)
796 if (ctxt
->extrasNr
>= ctxt
->extrasMax
) {
798 if (ctxt
->extrasNr
== 0) {
799 ctxt
->extrasMax
= 20;
800 ctxt
->extras
= (xsltRuntimeExtraPtr
)
801 xmlMalloc(ctxt
->extrasMax
* sizeof(xsltRuntimeExtra
));
802 if (ctxt
->extras
== NULL
) {
803 xmlGenericError(xmlGenericErrorContext
,
804 "xsltAllocateExtraCtxt: out of memory\n");
805 ctxt
->state
= XSLT_STATE_ERROR
;
808 for (i
= 0;i
< ctxt
->extrasMax
;i
++) {
809 ctxt
->extras
[i
].info
= NULL
;
810 ctxt
->extras
[i
].deallocate
= NULL
;
811 ctxt
->extras
[i
].val
.ptr
= NULL
;
815 xsltRuntimeExtraPtr tmp
;
817 ctxt
->extrasMax
+= 100;
818 tmp
= (xsltRuntimeExtraPtr
) xmlRealloc(ctxt
->extras
,
819 ctxt
->extrasMax
* sizeof(xsltRuntimeExtra
));
821 xmlGenericError(xmlGenericErrorContext
,
822 "xsltAllocateExtraCtxt: out of memory\n");
823 ctxt
->state
= XSLT_STATE_ERROR
;
827 for (i
= ctxt
->extrasNr
;i
< ctxt
->extrasMax
;i
++) {
828 ctxt
->extras
[i
].info
= NULL
;
829 ctxt
->extras
[i
].deallocate
= NULL
;
830 ctxt
->extras
[i
].val
.ptr
= NULL
;
834 return(ctxt
->extrasNr
++);
838 * xsltFreeStylesheetList:
839 * @style: an XSLT stylesheet list
841 * Free up the memory allocated by the list @style
844 xsltFreeStylesheetList(xsltStylesheetPtr style
) {
845 xsltStylesheetPtr next
;
847 while (style
!= NULL
) {
849 xsltFreeStylesheet(style
);
855 * xsltCleanupStylesheetTree:
857 * @doc: the document-node
858 * @node: the element where the stylesheet is rooted at
860 * Actually @node need not be the document-element, but
861 * currently Libxslt does not support embedded stylesheets.
863 * Returns 0 if OK, -1 on API or internal errors.
866 xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED
,
867 xmlNodePtr rootElem ATTRIBUTE_UNUSED
)
869 #if 0 /* TODO: Currently disabled, since probably not needed. */
872 if ((doc
== NULL
) || (rootElem
== NULL
) ||
873 (rootElem
->type
!= XML_ELEMENT_NODE
) ||
874 (doc
!= rootElem
->doc
))
878 * Cleanup was suggested by Aleksey Sanin:
879 * Clear the PSVI field to avoid problems if the
880 * node-tree of the stylesheet is intended to be used for
881 * further processing by the user (e.g. for compiling it
882 * once again - although not recommended).
886 while (cur
!= NULL
) {
887 if (cur
->type
== XML_ELEMENT_NODE
) {
889 * Clear the PSVI field.
901 if (cur
->next
!= NULL
)
915 * xsltFreeStylesheet:
916 * @style: an XSLT stylesheet
918 * Free up the memory allocated by @style
921 xsltFreeStylesheet(xsltStylesheetPtr style
)
926 #ifdef XSLT_REFACTORED
928 * Start with a cleanup of the main stylesheet's doc.
930 if ((style
->principal
== style
) && (style
->doc
))
931 xsltCleanupStylesheetTree(style
->doc
,
932 xmlDocGetRootElement(style
->doc
));
933 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
935 * Restore changed ns-decls before freeing the document.
937 if ((style
->doc
!= NULL
) &&
938 XSLT_HAS_INTERNAL_NSMAP(style
))
940 xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style
),
943 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
946 * Start with a cleanup of the main stylesheet's doc.
948 if ((style
->parent
== NULL
) && (style
->doc
))
949 xsltCleanupStylesheetTree(style
->doc
,
950 xmlDocGetRootElement(style
->doc
));
951 #endif /* XSLT_REFACTORED */
955 xsltFreeTemplateHashes(style
);
956 xsltFreeDecimalFormatList(style
);
957 xsltFreeTemplateList(style
->templates
);
958 xsltFreeAttributeSetsHashes(style
);
959 xsltFreeNamespaceAliasHashes(style
);
960 xsltFreeStylePreComps(style
);
962 * Free documents of all included stylsheet modules of this
965 xsltFreeStyleDocuments(style
);
967 * TODO: Best time to shutdown extension stuff?
969 xsltShutdownExts(style
);
971 if (style
->variables
!= NULL
)
972 xsltFreeStackElemList(style
->variables
);
973 if (style
->cdataSection
!= NULL
)
974 xmlHashFree(style
->cdataSection
, NULL
);
975 if (style
->stripSpaces
!= NULL
)
976 xmlHashFree(style
->stripSpaces
, NULL
);
977 if (style
->nsHash
!= NULL
)
978 xmlHashFree(style
->nsHash
, NULL
);
979 if (style
->exclPrefixTab
!= NULL
)
980 xmlFree(style
->exclPrefixTab
);
981 if (style
->method
!= NULL
)
982 xmlFree(style
->method
);
983 if (style
->methodURI
!= NULL
)
984 xmlFree(style
->methodURI
);
985 if (style
->version
!= NULL
)
986 xmlFree(style
->version
);
987 if (style
->encoding
!= NULL
)
988 xmlFree(style
->encoding
);
989 if (style
->doctypePublic
!= NULL
)
990 xmlFree(style
->doctypePublic
);
991 if (style
->doctypeSystem
!= NULL
)
992 xmlFree(style
->doctypeSystem
);
993 if (style
->mediaType
!= NULL
)
994 xmlFree(style
->mediaType
);
996 xsltFreeAVTList(style
->attVTs
);
997 if (style
->imports
!= NULL
)
998 xsltFreeStylesheetList(style
->imports
);
1000 #ifdef XSLT_REFACTORED
1002 * If this is the principal stylesheet, then
1003 * free its internal data.
1005 if (style
->principal
== style
) {
1006 if (style
->principalData
) {
1007 xsltFreePrincipalStylesheetData(style
->principalData
);
1008 style
->principalData
= NULL
;
1013 * Better to free the main document of this stylesheet level
1014 * at the end - so here.
1016 if (style
->doc
!= NULL
) {
1017 xmlFreeDoc(style
->doc
);
1020 #ifdef WITH_XSLT_DEBUG
1021 xsltGenericDebug(xsltGenericDebugContext
,
1022 "freeing dictionary from stylesheet\n");
1024 xmlDictFree(style
->dict
);
1026 memset(style
, -1, sizeof(xsltStylesheet
));
1030 /************************************************************************
1032 * Parsing of an XSLT Stylesheet *
1034 ************************************************************************/
1036 #ifdef XSLT_REFACTORED
1038 * This is now performed in an optimized way in xsltParseXSLTTemplate.
1042 * xsltGetInheritedNsList:
1043 * @style: the stylesheet
1044 * @template: the template
1045 * @node: the current node
1047 * Search all the namespace applying to a given element except the ones
1048 * from excluded output prefixes currently in scope. Initialize the
1049 * template inheritedNs list with it.
1051 * Returns the number of entries found
1054 xsltGetInheritedNsList(xsltStylesheetPtr style
,
1055 xsltTemplatePtr
template,
1059 xmlNsPtr
*ret
= NULL
;
1064 if ((style
== NULL
) || (template == NULL
) || (node
== NULL
) ||
1065 (template->inheritedNsNr
!= 0) || (template->inheritedNs
!= NULL
))
1067 while (node
!= NULL
) {
1068 if (node
->type
== XML_ELEMENT_NODE
) {
1070 while (cur
!= NULL
) {
1071 if (xmlStrEqual(cur
->href
, XSLT_NAMESPACE
))
1074 if ((cur
->prefix
!= NULL
) &&
1075 (xsltCheckExtPrefix(style
, cur
->prefix
)))
1078 * Check if this namespace was excluded.
1079 * Note that at this point only the exclusions defined
1080 * on the topmost stylesheet element are in the exclusion-list.
1082 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
1083 if (xmlStrEqual(cur
->href
, style
->exclPrefixTab
[i
]))
1088 (xmlNsPtr
*) xmlMalloc((maxns
+ 1) *
1091 xmlGenericError(xmlGenericErrorContext
,
1092 "xsltGetInheritedNsList : out of memory!\n");
1098 * Skip shadowed namespace bindings.
1100 for (i
= 0; i
< nbns
; i
++) {
1101 if ((cur
->prefix
== ret
[i
]->prefix
) ||
1102 (xmlStrEqual(cur
->prefix
, ret
[i
]->prefix
)))
1106 if (nbns
>= maxns
) {
1108 ret
= (xmlNsPtr
*) xmlRealloc(ret
,
1113 xmlGenericError(xmlGenericErrorContext
,
1114 "xsltGetInheritedNsList : realloc failed!\n");
1125 node
= node
->parent
;
1128 #ifdef WITH_XSLT_DEBUG_PARSING
1129 xsltGenericDebug(xsltGenericDebugContext
,
1130 "template has %d inherited namespaces\n", nbns
);
1132 template->inheritedNsNr
= nbns
;
1133 template->inheritedNs
= ret
;
1137 #endif /* else of XSLT_REFACTORED */
1140 * xsltParseStylesheetOutput:
1141 * @style: the XSLT stylesheet
1142 * @cur: the "output" element
1144 * parse an XSLT stylesheet output element and record
1145 * information related to the stylesheet output
1149 xsltParseStylesheetOutput(xsltStylesheetPtr style
, xmlNodePtr cur
)
1156 if ((cur
== NULL
) || (style
== NULL
))
1159 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "version", NULL
);
1161 if (style
->version
!= NULL
)
1162 xmlFree(style
->version
);
1163 style
->version
= prop
;
1166 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "encoding", NULL
);
1168 if (style
->encoding
!= NULL
)
1169 xmlFree(style
->encoding
);
1170 style
->encoding
= prop
;
1173 /* relaxed to support xt:document
1174 * TODO KB: What does "relaxed to support xt:document" mean?
1176 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "method", NULL
);
1180 if (style
->method
!= NULL
)
1181 xmlFree(style
->method
);
1182 style
->method
= NULL
;
1183 if (style
->methodURI
!= NULL
)
1184 xmlFree(style
->methodURI
);
1185 style
->methodURI
= NULL
;
1188 * TODO: Don't use xsltGetQNameURI().
1190 URI
= xsltGetQNameURI(cur
, &prop
);
1192 if (style
!= NULL
) style
->errors
++;
1193 } else if (URI
== NULL
) {
1194 if ((xmlStrEqual(prop
, (const xmlChar
*) "xml")) ||
1195 (xmlStrEqual(prop
, (const xmlChar
*) "html")) ||
1196 (xmlStrEqual(prop
, (const xmlChar
*) "text"))) {
1197 style
->method
= prop
;
1199 xsltTransformError(NULL
, style
, cur
,
1200 "invalid value for method: %s\n", prop
);
1201 if (style
!= NULL
) style
->warnings
++;
1204 style
->method
= prop
;
1205 style
->methodURI
= xmlStrdup(URI
);
1209 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "doctype-system", NULL
);
1211 if (style
->doctypeSystem
!= NULL
)
1212 xmlFree(style
->doctypeSystem
);
1213 style
->doctypeSystem
= prop
;
1216 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "doctype-public", NULL
);
1218 if (style
->doctypePublic
!= NULL
)
1219 xmlFree(style
->doctypePublic
);
1220 style
->doctypePublic
= prop
;
1223 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "standalone", NULL
);
1225 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1226 style
->standalone
= 1;
1227 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1228 style
->standalone
= 0;
1230 xsltTransformError(NULL
, style
, cur
,
1231 "invalid value for standalone: %s\n", prop
);
1237 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "indent", NULL
);
1239 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1241 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1244 xsltTransformError(NULL
, style
, cur
,
1245 "invalid value for indent: %s\n", prop
);
1251 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "omit-xml-declaration", NULL
);
1253 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1254 style
->omitXmlDeclaration
= 1;
1255 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1256 style
->omitXmlDeclaration
= 0;
1258 xsltTransformError(NULL
, style
, cur
,
1259 "invalid value for omit-xml-declaration: %s\n",
1266 elements
= xmlGetNsProp(cur
, (const xmlChar
*) "cdata-section-elements",
1268 if (elements
!= NULL
) {
1269 if (style
->cdataSection
== NULL
)
1270 style
->cdataSection
= xmlHashCreate(10);
1271 if (style
->cdataSection
== NULL
)
1275 while (*element
!= 0) {
1276 while (IS_BLANK(*element
))
1281 while ((*end
!= 0) && (!IS_BLANK(*end
)))
1283 element
= xmlStrndup(element
, end
- element
);
1285 #ifdef WITH_XSLT_DEBUG_PARSING
1286 xsltGenericDebug(xsltGenericDebugContext
,
1287 "add cdata section output element %s\n",
1290 if (xmlValidateQName(BAD_CAST element
, 0) != 0) {
1291 xsltTransformError(NULL
, style
, cur
,
1292 "Attribute 'cdata-section-elements': The value "
1293 "'%s' is not a valid QName.\n", element
);
1300 * TODO: Don't use xsltGetQNameURI().
1302 URI
= xsltGetQNameURI(cur
, &element
);
1303 if (element
== NULL
) {
1305 * TODO: We'll report additionally an error
1306 * via the stylesheet's error handling.
1308 xsltTransformError(NULL
, style
, cur
,
1309 "Attribute 'cdata-section-elements': The value "
1310 "'%s' is not a valid QName.\n", element
);
1316 * XSLT-1.0 "Each QName is expanded into an
1317 * expanded-name using the namespace declarations in
1318 * effect on the xsl:output element in which the QName
1319 * occurs; if there is a default namespace, it is used
1320 * for QNames that do not have a prefix"
1321 * NOTE: Fix of bug #339570.
1324 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1328 xmlHashAddEntry2(style
->cdataSection
, element
, URI
,
1339 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "media-type", NULL
);
1341 if (style
->mediaType
)
1342 xmlFree(style
->mediaType
);
1343 style
->mediaType
= prop
;
1345 if (cur
->children
!= NULL
) {
1346 xsltParseContentError(style
, cur
->children
);
1351 * xsltParseStylesheetDecimalFormat:
1352 * @style: the XSLT stylesheet
1353 * @cur: the "decimal-format" element
1355 * <!-- Category: top-level-element -->
1356 * <xsl:decimal-format
1357 * name = qname, decimal-separator = char, grouping-separator = char,
1358 * infinity = string, minus-sign = char, NaN = string, percent = char
1359 * per-mille = char, zero-digit = char, digit = char,
1360 * pattern-separator = char />
1362 * parse an XSLT stylesheet decimal-format element and
1363 * and record the formatting characteristics
1366 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style
, xmlNodePtr cur
)
1369 xsltDecimalFormatPtr format
;
1370 xsltDecimalFormatPtr iter
;
1372 if ((cur
== NULL
) || (style
== NULL
))
1375 format
= style
->decimalFormat
;
1377 prop
= xmlGetNsProp(cur
, BAD_CAST("name"), NULL
);
1379 format
= xsltDecimalFormatGetByName(style
, prop
);
1380 if (format
!= NULL
) {
1381 xsltTransformError(NULL
, style
, cur
,
1382 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop
);
1383 if (style
!= NULL
) style
->warnings
++;
1386 format
= xsltNewDecimalFormat(prop
);
1387 if (format
== NULL
) {
1388 xsltTransformError(NULL
, style
, cur
,
1389 "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
1390 if (style
!= NULL
) style
->errors
++;
1393 /* Append new decimal-format structure */
1394 for (iter
= style
->decimalFormat
; iter
->next
; iter
= iter
->next
)
1397 iter
->next
= format
;
1400 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"decimal-separator", NULL
);
1402 if (format
->decimalPoint
!= NULL
) xmlFree(format
->decimalPoint
);
1403 format
->decimalPoint
= prop
;
1406 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"grouping-separator", NULL
);
1408 if (format
->grouping
!= NULL
) xmlFree(format
->grouping
);
1409 format
->grouping
= prop
;
1412 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"infinity", NULL
);
1414 if (format
->infinity
!= NULL
) xmlFree(format
->infinity
);
1415 format
->infinity
= prop
;
1418 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"minus-sign", NULL
);
1420 if (format
->minusSign
!= NULL
) xmlFree(format
->minusSign
);
1421 format
->minusSign
= prop
;
1424 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"NaN", NULL
);
1426 if (format
->noNumber
!= NULL
) xmlFree(format
->noNumber
);
1427 format
->noNumber
= prop
;
1430 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"percent", NULL
);
1432 if (format
->percent
!= NULL
) xmlFree(format
->percent
);
1433 format
->percent
= prop
;
1436 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"per-mille", NULL
);
1438 if (format
->permille
!= NULL
) xmlFree(format
->permille
);
1439 format
->permille
= prop
;
1442 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"zero-digit", NULL
);
1444 if (format
->zeroDigit
!= NULL
) xmlFree(format
->zeroDigit
);
1445 format
->zeroDigit
= prop
;
1448 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"digit", NULL
);
1450 if (format
->digit
!= NULL
) xmlFree(format
->digit
);
1451 format
->digit
= prop
;
1454 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"pattern-separator", NULL
);
1456 if (format
->patternSeparator
!= NULL
) xmlFree(format
->patternSeparator
);
1457 format
->patternSeparator
= prop
;
1459 if (cur
->children
!= NULL
) {
1460 xsltParseContentError(style
, cur
->children
);
1465 * xsltParseStylesheetPreserveSpace:
1466 * @style: the XSLT stylesheet
1467 * @cur: the "preserve-space" element
1469 * parse an XSLT stylesheet preserve-space element and record
1470 * elements needing preserving
1474 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style
, xmlNodePtr cur
) {
1476 xmlChar
*element
, *end
;
1478 if ((cur
== NULL
) || (style
== NULL
))
1481 elements
= xmlGetNsProp(cur
, (const xmlChar
*)"elements", NULL
);
1482 if (elements
== NULL
) {
1483 xsltTransformError(NULL
, style
, cur
,
1484 "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
1485 if (style
!= NULL
) style
->warnings
++;
1489 if (style
->stripSpaces
== NULL
)
1490 style
->stripSpaces
= xmlHashCreate(10);
1491 if (style
->stripSpaces
== NULL
)
1495 while (*element
!= 0) {
1496 while (IS_BLANK(*element
)) element
++;
1500 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1501 element
= xmlStrndup(element
, end
- element
);
1503 #ifdef WITH_XSLT_DEBUG_PARSING
1504 xsltGenericDebug(xsltGenericDebugContext
,
1505 "add preserved space element %s\n", element
);
1507 if (xmlStrEqual(element
, (const xmlChar
*)"*")) {
1508 style
->stripAll
= -1;
1513 * TODO: Don't use xsltGetQNameURI().
1515 URI
= xsltGetQNameURI(cur
, &element
);
1517 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
1518 (xmlChar
*) "preserve");
1525 if (cur
->children
!= NULL
) {
1526 xsltParseContentError(style
, cur
->children
);
1530 #ifdef XSLT_REFACTORED
1533 * xsltParseStylesheetExtPrefix:
1534 * @style: the XSLT stylesheet
1535 * @template: the "extension-element-prefixes" prefix
1537 * parse an XSLT stylesheet's "extension-element-prefix" attribute value
1538 * and register the namespaces of extension instruction.
1539 * SPEC "A namespace is designated as an extension namespace by using
1540 * an extension-element-prefixes attribute on:
1541 * 1) an xsl:stylesheet element
1542 * 2) an xsl:extension-element-prefixes attribute on a
1543 * literal result element
1544 * 3) an extension instruction."
1547 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style
, xmlNodePtr cur
,
1550 xmlChar
*prefix
, *end
;
1552 if ((cur
== NULL
) || (style
== NULL
))
1556 /* For xsl:stylesheet/xsl:transform. */
1557 prefixes
= xmlGetNsProp(cur
,
1558 (const xmlChar
*)"extension-element-prefixes", NULL
);
1560 /* For literal result elements and extension instructions. */
1561 prefixes
= xmlGetNsProp(cur
,
1562 (const xmlChar
*)"extension-element-prefixes", XSLT_NAMESPACE
);
1564 if (prefixes
== NULL
) {
1569 while (*prefix
!= 0) {
1570 while (IS_BLANK(*prefix
)) prefix
++;
1574 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1575 prefix
= xmlStrndup(prefix
, end
- prefix
);
1579 if (xmlStrEqual(prefix
, (const xmlChar
*)"#default"))
1580 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1582 ns
= xmlSearchNs(style
->doc
, cur
, prefix
);
1584 xsltTransformError(NULL
, style
, cur
,
1585 "xsl:extension-element-prefix : undefined namespace %s\n",
1587 if (style
!= NULL
) style
->warnings
++;
1589 #ifdef WITH_XSLT_DEBUG_PARSING
1590 xsltGenericDebug(xsltGenericDebugContext
,
1591 "add extension prefix %s\n", prefix
);
1593 xsltRegisterExtPrefix(style
, prefix
, ns
->href
);
1601 #endif /* else of XSLT_REFACTORED */
1604 * xsltParseStylesheetStripSpace:
1605 * @style: the XSLT stylesheet
1606 * @cur: the "strip-space" element
1608 * parse an XSLT stylesheet's strip-space element and record
1609 * the elements needing stripping
1613 xsltParseStylesheetStripSpace(xsltStylesheetPtr style
, xmlNodePtr cur
) {
1615 xmlChar
*element
, *end
;
1617 if ((cur
== NULL
) || (style
== NULL
))
1620 elements
= xmlGetNsProp(cur
, (const xmlChar
*)"elements", NULL
);
1621 if (elements
== NULL
) {
1622 xsltTransformError(NULL
, style
, cur
,
1623 "xsltParseStylesheetStripSpace: missing elements attribute\n");
1624 if (style
!= NULL
) style
->warnings
++;
1628 if (style
->stripSpaces
== NULL
)
1629 style
->stripSpaces
= xmlHashCreate(10);
1630 if (style
->stripSpaces
== NULL
)
1634 while (*element
!= 0) {
1635 while (IS_BLANK(*element
)) element
++;
1639 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1640 element
= xmlStrndup(element
, end
- element
);
1642 #ifdef WITH_XSLT_DEBUG_PARSING
1643 xsltGenericDebug(xsltGenericDebugContext
,
1644 "add stripped space element %s\n", element
);
1646 if (xmlStrEqual(element
, (const xmlChar
*)"*")) {
1647 style
->stripAll
= 1;
1652 * TODO: Don't use xsltGetQNameURI().
1654 URI
= xsltGetQNameURI(cur
, &element
);
1656 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
1657 (xmlChar
*) "strip");
1664 if (cur
->children
!= NULL
) {
1665 xsltParseContentError(style
, cur
->children
);
1669 #ifdef XSLT_REFACTORED
1672 * xsltParseStylesheetExcludePrefix:
1673 * @style: the XSLT stylesheet
1674 * @cur: the current point in the stylesheet
1676 * parse an XSLT stylesheet exclude prefix and record
1677 * namespaces needing stripping
1679 * Returns the number of Excluded prefixes added at that level
1683 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style
, xmlNodePtr cur
,
1688 xmlChar
*prefix
, *end
;
1690 if ((cur
== NULL
) || (style
== NULL
))
1694 prefixes
= xmlGetNsProp(cur
,
1695 (const xmlChar
*)"exclude-result-prefixes", NULL
);
1697 prefixes
= xmlGetNsProp(cur
,
1698 (const xmlChar
*)"exclude-result-prefixes", XSLT_NAMESPACE
);
1700 if (prefixes
== NULL
) {
1705 while (*prefix
!= 0) {
1706 while (IS_BLANK(*prefix
)) prefix
++;
1710 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1711 prefix
= xmlStrndup(prefix
, end
- prefix
);
1715 if (xmlStrEqual(prefix
, (const xmlChar
*)"#default"))
1716 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1718 ns
= xmlSearchNs(style
->doc
, cur
, prefix
);
1720 xsltTransformError(NULL
, style
, cur
,
1721 "xsl:exclude-result-prefixes : undefined namespace %s\n",
1723 if (style
!= NULL
) style
->warnings
++;
1725 if (exclPrefixPush(style
, (xmlChar
*) ns
->href
) >= 0) {
1726 #ifdef WITH_XSLT_DEBUG_PARSING
1727 xsltGenericDebug(xsltGenericDebugContext
,
1728 "exclude result prefix %s\n", prefix
);
1740 #endif /* else of XSLT_REFACTORED */
1742 #ifdef XSLT_REFACTORED
1745 * xsltTreeEnsureXMLDecl:
1749 * This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
1750 * Ensures that there is an XML namespace declaration on the doc.
1752 * Returns the XML ns-struct or NULL on API and internal errors.
1755 xsltTreeEnsureXMLDecl(xmlDocPtr doc
)
1759 if (doc
->oldNs
!= NULL
)
1760 return (doc
->oldNs
);
1763 ns
= (xmlNsPtr
) xmlMalloc(sizeof(xmlNs
));
1765 xmlGenericError(xmlGenericErrorContext
,
1766 "xsltTreeEnsureXMLDecl: Failed to allocate "
1767 "the XML namespace.\n");
1770 memset(ns
, 0, sizeof(xmlNs
));
1771 ns
->type
= XML_LOCAL_NAMESPACE
;
1773 * URGENT TODO: revisit this.
1775 #ifdef LIBXML_NAMESPACE_DICT
1777 ns
->href
= xmlDictLookup(doc
->dict
, XML_XML_NAMESPACE
, -1);
1779 ns
->href
= xmlStrdup(XML_XML_NAMESPACE
);
1781 ns
->href
= xmlStrdup(XML_XML_NAMESPACE
);
1783 ns
->prefix
= xmlStrdup((const xmlChar
*)"xml");
1790 * xsltTreeAcquireStoredNs:
1792 * @nsName: the namespace name
1793 * @prefix: the prefix
1796 * This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
1797 * Creates or reuses an xmlNs struct on doc->oldNs with
1798 * the given prefix and namespace name.
1800 * Returns the aquired ns struct or NULL in case of an API
1801 * or internal error.
1804 xsltTreeAcquireStoredNs(xmlDocPtr doc
,
1805 const xmlChar
*nsName
,
1806 const xmlChar
*prefix
)
1812 if (doc
->oldNs
!= NULL
)
1815 ns
= xsltTreeEnsureXMLDecl(doc
);
1818 if (ns
->next
!= NULL
) {
1821 while (ns
!= NULL
) {
1822 if ((ns
->prefix
== NULL
) != (prefix
== NULL
)) {
1824 } else if (prefix
== NULL
) {
1825 if (xmlStrEqual(ns
->href
, nsName
))
1828 if ((ns
->prefix
[0] == prefix
[0]) &&
1829 xmlStrEqual(ns
->prefix
, prefix
) &&
1830 xmlStrEqual(ns
->href
, nsName
))
1834 if (ns
->next
== NULL
)
1840 ns
->next
= xmlNewNs(NULL
, nsName
, prefix
);
1845 * xsltLREBuildEffectiveNs:
1847 * Apply ns-aliasing on the namespace of the given @elem and
1851 xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt
,
1855 xsltNsAliasPtr alias
;
1857 if ((cctxt
== NULL
) || (elem
== NULL
))
1859 if ((cctxt
->nsAliases
== NULL
) || (! cctxt
->hasNsAliases
))
1862 alias
= cctxt
->nsAliases
;
1863 while (alias
!= NULL
) {
1864 if ( /* If both namespaces are NULL... */
1865 ( (elem
->ns
== NULL
) &&
1866 ((alias
->literalNs
== NULL
) ||
1867 (alias
->literalNs
->href
== NULL
)) ) ||
1868 /* ... or both namespace are equal */
1869 ( (elem
->ns
!= NULL
) &&
1870 (alias
->literalNs
!= NULL
) &&
1871 xmlStrEqual(elem
->ns
->href
, alias
->literalNs
->href
) ) )
1873 if ((alias
->targetNs
!= NULL
) &&
1874 (alias
->targetNs
->href
!= NULL
))
1877 * Convert namespace.
1879 if (elem
->doc
== alias
->docOfTargetNs
) {
1881 * This is the nice case: same docs.
1882 * This will eventually assign a ns-decl which
1883 * is shadowed, but this has no negative effect on
1884 * the generation of the result tree.
1886 elem
->ns
= alias
->targetNs
;
1889 * This target xmlNs originates from a different
1890 * stylesheet tree. Try to locate it in the
1891 * in-scope namespaces.
1892 * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
1894 ns
= xmlSearchNs(elem
->doc
, elem
,
1895 alias
->targetNs
->prefix
);
1897 * If no matching ns-decl found, then assign a
1898 * ns-decl stored in xmlDoc.
1901 (! xmlStrEqual(ns
->href
, alias
->targetNs
->href
)))
1904 * BIG NOTE: The use of xsltTreeAcquireStoredNs()
1905 * is not very efficient, but currently I don't
1906 * see an other way of *safely* changing a node's
1907 * namespace, since the xmlNs struct in
1908 * alias->targetNs might come from an other
1909 * stylesheet tree. So we need to anchor it in the
1910 * current document, without adding it to the tree,
1911 * which would otherwise change the in-scope-ns
1912 * semantic of the tree.
1914 ns
= xsltTreeAcquireStoredNs(elem
->doc
,
1915 alias
->targetNs
->href
,
1916 alias
->targetNs
->prefix
);
1919 xsltTransformError(NULL
, cctxt
->style
, elem
,
1920 "Internal error in "
1921 "xsltLREBuildEffectiveNs(): "
1922 "failed to acquire a stored "
1923 "ns-declaration.\n");
1924 cctxt
->style
->errors
++;
1933 * Move into or leave in the NULL namespace.
1939 alias
= alias
->next
;
1942 * Same with attributes of literal result elements.
1944 if (elem
->properties
!= NULL
) {
1945 xmlAttrPtr attr
= elem
->properties
;
1947 while (attr
!= NULL
) {
1948 if (attr
->ns
== NULL
) {
1952 alias
= cctxt
->nsAliases
;
1953 while (alias
!= NULL
) {
1954 if ( /* If both namespaces are NULL... */
1955 ( (elem
->ns
== NULL
) &&
1956 ((alias
->literalNs
== NULL
) ||
1957 (alias
->literalNs
->href
== NULL
)) ) ||
1958 /* ... or both namespace are equal */
1959 ( (elem
->ns
!= NULL
) &&
1960 (alias
->literalNs
!= NULL
) &&
1961 xmlStrEqual(elem
->ns
->href
, alias
->literalNs
->href
) ) )
1963 if ((alias
->targetNs
!= NULL
) &&
1964 (alias
->targetNs
->href
!= NULL
))
1966 if (elem
->doc
== alias
->docOfTargetNs
) {
1967 elem
->ns
= alias
->targetNs
;
1969 ns
= xmlSearchNs(elem
->doc
, elem
,
1970 alias
->targetNs
->prefix
);
1972 (! xmlStrEqual(ns
->href
, alias
->targetNs
->href
)))
1974 ns
= xsltTreeAcquireStoredNs(elem
->doc
,
1975 alias
->targetNs
->href
,
1976 alias
->targetNs
->prefix
);
1979 xsltTransformError(NULL
, cctxt
->style
, elem
,
1980 "Internal error in "
1981 "xsltLREBuildEffectiveNs(): "
1982 "failed to acquire a stored "
1983 "ns-declaration.\n");
1984 cctxt
->style
->errors
++;
1993 * Move into or leave in the NULL namespace.
1999 alias
= alias
->next
;
2009 * xsltLREBuildEffectiveNsNodes:
2011 * Computes the effective namespaces nodes for a literal result
2013 * @effectiveNs is the set of effective ns-nodes
2014 * on the literal result element, which will be added to the result
2015 * element if not already existing in the result tree.
2016 * This means that excluded namespaces (via exclude-result-prefixes,
2017 * extension-element-prefixes and the XSLT namespace) not added
2019 * Namespace-aliasing was applied on the @effectiveNs.
2022 xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt
,
2023 xsltStyleItemLRElementInfoPtr item
,
2028 xsltEffectiveNsPtr effNs
, lastEffNs
= NULL
;
2029 int i
, j
, holdByElem
;
2030 xsltPointerListPtr extElemNs
= cctxt
->inode
->extElemNs
;
2031 xsltPointerListPtr exclResultNs
= cctxt
->inode
->exclResultNs
;
2033 if ((cctxt
== NULL
) || (cctxt
->inode
== NULL
) || (elem
== NULL
) ||
2034 (item
== NULL
) || (item
->effectiveNs
!= NULL
))
2037 if (item
->inScopeNs
== NULL
)
2040 extElemNs
= cctxt
->inode
->extElemNs
;
2041 exclResultNs
= cctxt
->inode
->exclResultNs
;
2043 for (i
= 0; i
< item
->inScopeNs
->totalNumber
; i
++) {
2044 ns
= item
->inScopeNs
->list
[i
];
2046 * Skip namespaces designated as excluded namespaces
2047 * -------------------------------------------------
2049 * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
2050 * which are target namespaces of namespace-aliases
2051 * regardless if designated as excluded.
2053 * Exclude the XSLT namespace.
2055 if (xmlStrEqual(ns
->href
, XSLT_NAMESPACE
))
2059 * Apply namespace aliasing
2060 * ------------------------
2063 * "- A namespace node whose string value is a literal namespace
2064 * URI is not copied to the result tree.
2065 * - A namespace node whose string value is a target namespace URI
2066 * is copied to the result tree, whether or not the URI
2067 * identifies an excluded namespace."
2069 * NOTE: The ns-aliasing machanism is non-cascading.
2070 * (checked with Saxon, Xalan and MSXML .NET).
2071 * URGENT TODO: is style->nsAliases the effective list of
2072 * ns-aliases, or do we need to lookup the whole
2074 * TODO: Get rid of import-tree lookup.
2076 if (cctxt
->hasNsAliases
) {
2077 xsltNsAliasPtr alias
;
2079 * First check for being a target namespace.
2081 alias
= cctxt
->nsAliases
;
2084 * TODO: Is xmlns="" handled already?
2086 if ((alias
->targetNs
!= NULL
) &&
2087 (xmlStrEqual(alias
->targetNs
->href
, ns
->href
)))
2090 * Recognized as a target namespace; use it regardless
2091 * if excluded otherwise.
2093 goto add_effective_ns
;
2095 alias
= alias
->next
;
2096 } while (alias
!= NULL
);
2098 alias
= cctxt
->nsAliases
;
2101 * TODO: Is xmlns="" handled already?
2103 if ((alias
->literalNs
!= NULL
) &&
2104 (xmlStrEqual(alias
->literalNs
->href
, ns
->href
)))
2107 * Recognized as an namespace alias; do not use it.
2111 alias
= alias
->next
;
2112 } while (alias
!= NULL
);
2116 * Exclude excluded result namespaces.
2119 for (j
= 0; j
< exclResultNs
->number
; j
++)
2120 if (xmlStrEqual(ns
->href
, BAD_CAST exclResultNs
->items
[j
]))
2124 * Exclude extension-element namespaces.
2127 for (j
= 0; j
< extElemNs
->number
; j
++)
2128 if (xmlStrEqual(ns
->href
, BAD_CAST extElemNs
->items
[j
]))
2134 * OPTIMIZE TODO: This information may not be needed.
2136 if (isLRE
&& (elem
->nsDef
!= NULL
)) {
2138 tmpns
= elem
->nsDef
;
2144 tmpns
= tmpns
->next
;
2145 } while (tmpns
!= NULL
);
2151 * Add the effective namespace declaration.
2153 effNs
= (xsltEffectiveNsPtr
) xmlMalloc(sizeof(xsltEffectiveNs
));
2154 if (effNs
== NULL
) {
2155 xsltTransformError(NULL
, cctxt
->style
, elem
,
2156 "Internal error in xsltLREBuildEffectiveNs(): "
2157 "failed to allocate memory.\n");
2158 cctxt
->style
->errors
++;
2161 if (cctxt
->psData
->effectiveNs
== NULL
) {
2162 cctxt
->psData
->effectiveNs
= effNs
;
2163 effNs
->nextInStore
= NULL
;
2165 effNs
->nextInStore
= cctxt
->psData
->effectiveNs
;
2166 cctxt
->psData
->effectiveNs
= effNs
;
2170 effNs
->prefix
= ns
->prefix
;
2171 effNs
->nsName
= ns
->href
;
2172 effNs
->holdByElem
= holdByElem
;
2174 if (lastEffNs
== NULL
)
2175 item
->effectiveNs
= effNs
;
2177 lastEffNs
->next
= effNs
;
2188 * xsltLREInfoCreate:
2190 * @isLRE: indicates if the given @elem is a literal result element
2192 * Creates a new info for a literal result element.
2195 xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt
,
2199 xsltStyleItemLRElementInfoPtr item
;
2201 if ((cctxt
== NULL
) || (cctxt
->inode
== NULL
))
2204 item
= (xsltStyleItemLRElementInfoPtr
)
2205 xmlMalloc(sizeof(xsltStyleItemLRElementInfo
));
2207 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2208 "Internal error in xsltLREInfoCreate(): "
2209 "memory allocation failed.\n");
2210 cctxt
->style
->errors
++;
2213 memset(item
, 0, sizeof(xsltStyleItemLRElementInfo
));
2214 item
->type
= XSLT_FUNC_LITERAL_RESULT_ELEMENT
;
2216 * Store it in the stylesheet.
2218 item
->next
= cctxt
->style
->preComps
;
2219 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
2221 * @inScopeNs are used for execution of XPath expressions
2224 item
->inScopeNs
= cctxt
->inode
->inScopeNs
;
2227 xsltLREBuildEffectiveNsNodes(cctxt
, item
, elem
, isLRE
);
2229 cctxt
->inode
->litResElemInfo
= item
;
2230 cctxt
->inode
->nsChanged
= 0;
2236 * xsltCompilerVarInfoPush:
2237 * @cctxt: the compilation context
2239 * Pushes a new var/param info onto the stack.
2241 * Returns the acquired variable info.
2243 static xsltVarInfoPtr
2244 xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt
,
2246 const xmlChar
*name
,
2247 const xmlChar
*nsName
)
2249 xsltVarInfoPtr ivar
;
2251 if ((cctxt
->ivar
!= NULL
) && (cctxt
->ivar
->next
!= NULL
)) {
2252 ivar
= cctxt
->ivar
->next
;
2253 } else if ((cctxt
->ivar
== NULL
) && (cctxt
->ivars
!= NULL
)) {
2254 ivar
= cctxt
->ivars
;
2256 ivar
= (xsltVarInfoPtr
) xmlMalloc(sizeof(xsltVarInfo
));
2258 xsltTransformError(NULL
, cctxt
->style
, inst
,
2259 "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
2260 cctxt
->style
->errors
++;
2263 /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
2264 if (cctxt
->ivars
== NULL
) {
2265 cctxt
->ivars
= ivar
;
2268 cctxt
->ivar
->next
= ivar
;
2269 ivar
->prev
= cctxt
->ivar
;
2274 ivar
->depth
= cctxt
->depth
;
2276 ivar
->nsName
= nsName
;
2281 * xsltCompilerVarInfoPop:
2282 * @cctxt: the compilation context
2284 * Pops all var/param infos from the stack, which
2285 * have the current depth.
2288 xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt
)
2291 while ((cctxt
->ivar
!= NULL
) &&
2292 (cctxt
->ivar
->depth
> cctxt
->depth
))
2294 cctxt
->ivar
= cctxt
->ivar
->prev
;
2299 * xsltCompilerNodePush:
2301 * @cctxt: the compilation context
2302 * @node: the node to be pushed (this can also be the doc-node)
2306 * Returns the current node info structure or
2307 * NULL in case of an internal error.
2309 static xsltCompilerNodeInfoPtr
2310 xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2312 xsltCompilerNodeInfoPtr inode
, iprev
;
2314 if ((cctxt
->inode
!= NULL
) && (cctxt
->inode
->next
!= NULL
)) {
2315 inode
= cctxt
->inode
->next
;
2316 } else if ((cctxt
->inode
== NULL
) && (cctxt
->inodeList
!= NULL
)) {
2317 inode
= cctxt
->inodeList
;
2320 * Create a new node-info.
2322 inode
= (xsltCompilerNodeInfoPtr
)
2323 xmlMalloc(sizeof(xsltCompilerNodeInfo
));
2324 if (inode
== NULL
) {
2325 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2326 "xsltCompilerNodePush: malloc failed.\n");
2329 memset(inode
, 0, sizeof(xsltCompilerNodeInfo
));
2330 if (cctxt
->inodeList
== NULL
)
2331 cctxt
->inodeList
= inode
;
2333 cctxt
->inodeLast
->next
= inode
;
2334 inode
->prev
= cctxt
->inodeLast
;
2336 cctxt
->inodeLast
= inode
;
2337 cctxt
->maxNodeInfos
++;
2338 if (cctxt
->inode
== NULL
) {
2339 cctxt
->inode
= inode
;
2341 * Create an initial literal result element info for
2342 * the root of the stylesheet.
2344 xsltLREInfoCreate(cctxt
, NULL
, 0);
2348 cctxt
->inode
= inode
;
2350 * REVISIT TODO: Keep the reset always complete.
2351 * NOTE: Be carefull with the @node, since it might be
2355 inode
->depth
= cctxt
->depth
;
2356 inode
->templ
= NULL
;
2357 inode
->category
= XSLT_ELEMENT_CATEGORY_XSLT
;
2360 inode
->curChildType
= 0;
2361 inode
->extContentHandled
= 0;
2364 if (inode
->prev
!= NULL
) {
2365 iprev
= inode
->prev
;
2367 * Inherit the following information:
2368 * ---------------------------------
2370 * In-scope namespaces
2372 inode
->inScopeNs
= iprev
->inScopeNs
;
2374 * Info for literal result elements
2376 inode
->litResElemInfo
= iprev
->litResElemInfo
;
2377 inode
->nsChanged
= iprev
->nsChanged
;
2379 * Excluded result namespaces
2381 inode
->exclResultNs
= iprev
->exclResultNs
;
2383 * Extension instruction namespaces
2385 inode
->extElemNs
= iprev
->extElemNs
;
2387 * Whitespace preservation
2389 inode
->preserveWhitespace
= iprev
->preserveWhitespace
;
2391 * Forwards-compatible mode
2393 inode
->forwardsCompat
= iprev
->forwardsCompat
;
2395 inode
->inScopeNs
= NULL
;
2396 inode
->exclResultNs
= NULL
;
2397 inode
->extElemNs
= NULL
;
2398 inode
->preserveWhitespace
= 0;
2399 inode
->forwardsCompat
= 0;
2406 * xsltCompilerNodePop:
2408 * @cctxt: the compilation context
2409 * @node: the node to be pushed (this can also be the doc-node)
2411 * Pops the current node info.
2414 xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2416 if (cctxt
->inode
== NULL
) {
2417 xmlGenericError(xmlGenericErrorContext
,
2418 "xsltCompilerNodePop: Top-node mismatch.\n");
2422 * NOTE: Be carefull with the @node, since it might be
2425 if (cctxt
->inode
->node
!= node
) {
2426 xmlGenericError(xmlGenericErrorContext
,
2427 "xsltCompilerNodePop: Node mismatch.\n");
2430 if (cctxt
->inode
->depth
!= cctxt
->depth
) {
2431 xmlGenericError(xmlGenericErrorContext
,
2432 "xsltCompilerNodePop: Depth mismatch.\n");
2436 * Pop information of variables.
2438 if ((cctxt
->ivar
) && (cctxt
->ivar
->depth
> cctxt
->depth
))
2439 xsltCompilerVarInfoPop(cctxt
);
2442 cctxt
->inode
= cctxt
->inode
->prev
;
2443 if (cctxt
->inode
!= NULL
)
2444 cctxt
->inode
->curChildType
= 0;
2449 const xmlChar
*nsName
= NULL
, *name
= NULL
;
2450 const xmlChar
*infnsName
= NULL
, *infname
= NULL
;
2453 if (node
->type
== XML_ELEMENT_NODE
) {
2455 if (node
->ns
!= NULL
)
2456 nsName
= node
->ns
->href
;
2458 nsName
= BAD_CAST
"";
2460 name
= BAD_CAST
"#document";
2461 nsName
= BAD_CAST
"";
2464 name
= BAD_CAST
"Not given";
2466 if (cctxt
->inode
->node
) {
2467 if (node
->type
== XML_ELEMENT_NODE
) {
2468 infname
= cctxt
->inode
->node
->name
;
2469 if (cctxt
->inode
->node
->ns
!= NULL
)
2470 infnsName
= cctxt
->inode
->node
->ns
->href
;
2472 infnsName
= BAD_CAST
"";
2474 infname
= BAD_CAST
"#document";
2475 infnsName
= BAD_CAST
"";
2478 infname
= BAD_CAST
"Not given";
2481 xmlGenericError(xmlGenericErrorContext
,
2482 "xsltCompilerNodePop: Given : '%s' URI '%s'\n",
2484 xmlGenericError(xmlGenericErrorContext
,
2485 "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
2486 infname
, infnsName
);
2491 * xsltCompilerBuildInScopeNsList:
2493 * Create and store the list of in-scope namespaces for the given
2494 * node in the stylesheet. If there are no changes in the in-scope
2495 * namespaces then the last ns-info of the ancestor axis will be returned.
2496 * Compilation-time only.
2498 * Returns the ns-info or NULL if there are no namespaces in scope.
2500 static xsltNsListContainerPtr
2501 xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2503 xsltNsListContainerPtr nsi
= NULL
;
2504 xmlNsPtr
*list
= NULL
, ns
;
2507 * Create a new ns-list for this position in the node-tree.
2508 * xmlGetNsList() will return NULL, if there are no ns-decls in the
2509 * tree. Note that the ns-decl for the XML namespace is not added
2510 * to the resulting list; the XPath module handles the XML namespace
2513 while (node
!= NULL
) {
2514 if (node
->type
== XML_ELEMENT_NODE
) {
2516 while (ns
!= NULL
) {
2518 nsi
= (xsltNsListContainerPtr
)
2519 xmlMalloc(sizeof(xsltNsListContainer
));
2521 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2522 "xsltCompilerBuildInScopeNsList: "
2523 "malloc failed!\n");
2526 memset(nsi
, 0, sizeof(xsltNsListContainer
));
2528 (xmlNsPtr
*) xmlMalloc(maxns
* sizeof(xmlNsPtr
));
2529 if (nsi
->list
== NULL
) {
2530 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2531 "xsltCompilerBuildInScopeNsList: "
2532 "malloc failed!\n");
2535 nsi
->list
[0] = NULL
;
2538 * Skip shadowed namespace bindings.
2540 for (i
= 0; i
< nsi
->totalNumber
; i
++) {
2541 if ((ns
->prefix
== nsi
->list
[i
]->prefix
) ||
2542 (xmlStrEqual(ns
->prefix
, nsi
->list
[i
]->prefix
)))
2545 if (i
>= nsi
->totalNumber
) {
2546 if (nsi
->totalNumber
+1 >= maxns
) {
2549 (xmlNsPtr
*) xmlRealloc(nsi
->list
,
2550 maxns
* sizeof(xmlNsPtr
));
2551 if (nsi
->list
== NULL
) {
2552 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2553 "xsltCompilerBuildInScopeNsList: "
2554 "realloc failed!\n");
2558 nsi
->list
[nsi
->totalNumber
++] = ns
;
2559 nsi
->list
[nsi
->totalNumber
] = NULL
;
2565 node
= node
->parent
;
2570 * Move the default namespace to last position.
2572 nsi
->xpathNumber
= nsi
->totalNumber
;
2573 for (i
= 0; i
< nsi
->totalNumber
; i
++) {
2574 if (nsi
->list
[i
]->prefix
== NULL
) {
2576 nsi
->list
[i
] = nsi
->list
[nsi
->totalNumber
-1];
2577 nsi
->list
[nsi
->totalNumber
-1] = ns
;
2583 * Store the ns-list in the stylesheet.
2585 if (xsltPointerListAddSize(
2586 (xsltPointerListPtr
)cctxt
->psData
->inScopeNamespaces
,
2587 (void *) nsi
, 5) == -1)
2591 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2592 "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
2596 * Notify of change in status wrt namespaces.
2598 if (cctxt
->inode
!= NULL
)
2599 cctxt
->inode
->nsChanged
= 1;
2606 cctxt
->style
->errors
++;
2611 xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt
,
2612 xsltPointerListPtr list
,
2614 const xmlChar
*value
)
2619 if ((cctxt
== NULL
) || (value
== NULL
) || (list
== NULL
))
2624 cur
= (xmlChar
*) value
;
2626 while (IS_BLANK(*cur
)) cur
++;
2630 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
2631 cur
= xmlStrndup(cur
, end
- cur
);
2637 * TODO: Export and use xmlSearchNsByPrefixStrict()
2638 * in Libxml2, tree.c, since xmlSearchNs() is in most
2639 * cases not efficient and in some cases not correct.
2641 * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
2643 if ((cur
[0] == '#') &&
2644 xmlStrEqual(cur
, (const xmlChar
*)"#default"))
2645 ns
= xmlSearchNs(cctxt
->style
->doc
, node
, NULL
);
2647 ns
= xmlSearchNs(cctxt
->style
->doc
, node
, cur
);
2651 * TODO: Better to report the attr-node, otherwise
2652 * the user won't know which attribute was invalid.
2654 xsltTransformError(NULL
, cctxt
->style
, node
,
2655 "No namespace binding in scope for prefix '%s'.\n", cur
);
2657 * XSLT-1.0: "It is an error if there is no namespace
2658 * bound to the prefix on the element bearing the
2659 * exclude-result-prefixes or xsl:exclude-result-prefixes
2662 cctxt
->style
->errors
++;
2664 #ifdef WITH_XSLT_DEBUG_PARSING
2665 xsltGenericDebug(xsltGenericDebugContext
,
2666 "resolved prefix '%s'\n", cur
);
2669 * Note that we put the namespace name into the dict.
2671 if (xsltPointerListAddSize(list
,
2672 (void *) xmlDictLookup(cctxt
->style
->dict
,
2673 ns
->href
, -1), 5) == -1)
2686 cctxt
->style
->errors
++;
2691 * xsltCompilerUtilsCreateMergedList:
2692 * @dest: the destination list (optional)
2693 * @first: the first list
2694 * @second: the second list (optional)
2696 * Appends the content of @second to @first into @destination.
2697 * If @destination is NULL a new list will be created.
2699 * Returns the merged list of items or NULL if there's nothing to merge.
2701 static xsltPointerListPtr
2702 xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first
,
2703 xsltPointerListPtr second
)
2705 xsltPointerListPtr ret
;
2709 num
= first
->number
;
2713 num
+= second
->number
;
2716 ret
= xsltPointerListCreate(num
);
2722 if ((first
!= NULL
) && (first
->number
!= 0)) {
2723 memcpy(ret
->items
, first
->items
,
2724 first
->number
* sizeof(void *));
2725 if ((second
!= NULL
) && (second
->number
!= 0))
2726 memcpy(ret
->items
+ first
->number
, second
->items
,
2727 second
->number
* sizeof(void *));
2728 } else if ((second
!= NULL
) && (second
->number
!= 0))
2729 memcpy(ret
->items
, (void *) second
->items
,
2730 second
->number
* sizeof(void *));
2736 * xsltParseExclResultPrefixes:
2738 * Create and store the list of in-scope namespaces for the given
2739 * node in the stylesheet. If there are no changes in the in-scope
2740 * namespaces then the last ns-info of the ancestor axis will be returned.
2741 * Compilation-time only.
2743 * Returns the ns-info or NULL if there are no namespaces in scope.
2745 static xsltPointerListPtr
2746 xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2747 xsltPointerListPtr def
,
2750 xsltPointerListPtr list
= NULL
;
2754 if ((cctxt
== NULL
) || (node
== NULL
))
2757 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2758 attr
= xmlHasNsProp(node
, BAD_CAST
"exclude-result-prefixes", NULL
);
2760 attr
= xmlHasNsProp(node
, BAD_CAST
"exclude-result-prefixes",
2765 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
2767 * Mark the XSLT attr.
2769 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2772 if ((attr
->children
!= NULL
) &&
2773 (attr
->children
->content
!= NULL
))
2774 value
= attr
->children
->content
;
2776 xsltTransformError(NULL
, cctxt
->style
, node
,
2777 "Attribute 'exclude-result-prefixes': Invalid value.\n");
2778 cctxt
->style
->errors
++;
2782 if (xsltParseNsPrefixList(cctxt
, cctxt
->tmpList
, node
,
2783 BAD_CAST value
) != 0)
2785 if (cctxt
->tmpList
->number
== 0)
2788 * Merge the list with the inherited list.
2790 list
= xsltCompilerUtilsCreateMergedList(def
, cctxt
->tmpList
);
2794 * Store the list in the stylesheet/compiler context.
2796 if (xsltPointerListAddSize(
2797 cctxt
->psData
->exclResultNamespaces
, list
, 5) == -1)
2799 xsltPointerListFree(list
);
2804 * Notify of change in status wrt namespaces.
2806 if (cctxt
->inode
!= NULL
)
2807 cctxt
->inode
->nsChanged
= 1;
2817 * xsltParseExtElemPrefixes:
2819 * Create and store the list of in-scope namespaces for the given
2820 * node in the stylesheet. If there are no changes in the in-scope
2821 * namespaces then the last ns-info of the ancestor axis will be returned.
2822 * Compilation-time only.
2824 * Returns the ns-info or NULL if there are no namespaces in scope.
2826 static xsltPointerListPtr
2827 xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2828 xsltPointerListPtr def
,
2831 xsltPointerListPtr list
= NULL
;
2836 if ((cctxt
== NULL
) || (node
== NULL
))
2839 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2840 attr
= xmlHasNsProp(node
, BAD_CAST
"extension-element-prefixes", NULL
);
2842 attr
= xmlHasNsProp(node
, BAD_CAST
"extension-element-prefixes",
2847 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
2849 * Mark the XSLT attr.
2851 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2854 if ((attr
->children
!= NULL
) &&
2855 (attr
->children
->content
!= NULL
))
2856 value
= attr
->children
->content
;
2858 xsltTransformError(NULL
, cctxt
->style
, node
,
2859 "Attribute 'extension-element-prefixes': Invalid value.\n");
2860 cctxt
->style
->errors
++;
2865 if (xsltParseNsPrefixList(cctxt
, cctxt
->tmpList
, node
,
2866 BAD_CAST value
) != 0)
2869 if (cctxt
->tmpList
->number
== 0)
2872 * REVISIT: Register the extension namespaces.
2874 for (i
= 0; i
< cctxt
->tmpList
->number
; i
++)
2875 xsltRegisterExtPrefix(cctxt
->style
, NULL
,
2876 BAD_CAST cctxt
->tmpList
->items
[i
]);
2878 * Merge the list with the inherited list.
2880 list
= xsltCompilerUtilsCreateMergedList(def
, cctxt
->tmpList
);
2884 * Store the list in the stylesheet.
2886 if (xsltPointerListAddSize(
2887 cctxt
->psData
->extElemNamespaces
, list
, 5) == -1)
2889 xsltPointerListFree(list
);
2894 * Notify of change in status wrt namespaces.
2896 if (cctxt
->inode
!= NULL
)
2897 cctxt
->inode
->nsChanged
= 1;
2907 * xsltParseAttrXSLTVersion:
2909 * @cctxt: the compilation context
2910 * @node: the element-node
2911 * @isXsltElem: whether this is an XSLT element
2913 * Parses the attribute xsl:version.
2915 * Returns 1 if there was such an attribute, 0 if not and
2916 * -1 if an internal or API error occured.
2919 xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2925 if ((cctxt
== NULL
) || (node
== NULL
))
2928 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2929 attr
= xmlHasNsProp(node
, BAD_CAST
"version", NULL
);
2931 attr
= xmlHasNsProp(node
, BAD_CAST
"version", XSLT_NAMESPACE
);
2936 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2938 if ((attr
->children
!= NULL
) &&
2939 (attr
->children
->content
!= NULL
))
2940 value
= attr
->children
->content
;
2942 xsltTransformError(NULL
, cctxt
->style
, node
,
2943 "Attribute 'version': Invalid value.\n");
2944 cctxt
->style
->errors
++;
2948 if (! xmlStrEqual(value
, (const xmlChar
*)"1.0")) {
2949 cctxt
->inode
->forwardsCompat
= 1;
2951 * TODO: To what extent do we support the
2952 * forwards-compatible mode?
2955 * Report this only once per compilation episode.
2957 if (! cctxt
->hasForwardsCompat
) {
2958 cctxt
->hasForwardsCompat
= 1;
2959 cctxt
->errSeverity
= XSLT_ERROR_SEVERITY_WARNING
;
2960 xsltTransformError(NULL
, cctxt
->style
, node
,
2961 "Warning: the attribute xsl:version specifies a value "
2962 "different from '1.0'. Switching to forwards-compatible "
2963 "mode. Only features of XSLT 1.0 are supported by this "
2965 cctxt
->style
->warnings
++;
2966 cctxt
->errSeverity
= XSLT_ERROR_SEVERITY_ERROR
;
2969 cctxt
->inode
->forwardsCompat
= 0;
2972 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
2974 * Set a marker on XSLT attributes.
2976 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2982 xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2984 xmlNodePtr deleteNode
, cur
, txt
, textNode
= NULL
;
2986 xsltStylesheetPtr style
;
2987 int internalize
= 0, findSpaceAttr
;
2988 int xsltStylesheetElemDepth
;
2991 const xmlChar
*name
, *nsNameXSLT
= NULL
;
2992 int strictWhitespace
, inXSLText
= 0;
2993 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
2994 xsltNsMapPtr nsMapItem
;
2997 if ((cctxt
== NULL
) || (cctxt
->style
== NULL
) ||
2998 (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
3005 style
= cctxt
->style
;
3006 if ((style
->dict
!= NULL
) && (doc
->dict
== style
->dict
))
3009 style
->internalized
= 0;
3012 * Init value of xml:space. Since this might be an embedded
3013 * stylesheet, this is needed to be performed on the element
3014 * where the stylesheet is rooted at, taking xml:space of
3015 * ancestors into account.
3017 if (! cctxt
->simplified
)
3018 xsltStylesheetElemDepth
= cctxt
->depth
+1;
3020 xsltStylesheetElemDepth
= 0;
3022 if (xmlNodeGetSpacePreserve(node
) != 1)
3023 cctxt
->inode
->preserveWhitespace
= 0;
3025 cctxt
->inode
->preserveWhitespace
= 1;
3028 * Eval if we should keep the old incorrect behaviour.
3030 strictWhitespace
= (cctxt
->strict
!= 0) ? 1 : 0;
3032 nsNameXSLT
= xsltConstNamespaceNameXSLT
;
3036 while (cur
!= NULL
) {
3037 if (deleteNode
!= NULL
) {
3039 #ifdef WITH_XSLT_DEBUG_BLANKS
3040 xsltGenericDebug(xsltGenericDebugContext
,
3041 "xsltParsePreprocessStylesheetTree: removing node\n");
3043 xmlUnlinkNode(deleteNode
);
3044 xmlFreeNode(deleteNode
);
3047 if (cur
->type
== XML_ELEMENT_NODE
) {
3050 * Clear the PSVI field.
3054 xsltCompilerNodePush(cctxt
, cur
);
3059 cctxt
->inode
->stripWhitespace
= 0;
3061 * TODO: I'd love to use a string pointer comparison here :-/
3063 if (IS_XSLT_ELEM(cur
)) {
3064 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3065 if (cur
->ns
->href
!= nsNameXSLT
) {
3066 nsMapItem
= xsltNewNamespaceMapItem(cctxt
,
3068 if (nsMapItem
== NULL
)
3070 cur
->ns
->href
= nsNameXSLT
;
3074 if (cur
->name
== NULL
)
3075 goto process_attributes
;
3077 * Mark the XSLT element for later recognition.
3078 * TODO: Using the marker is still too dangerous, since if
3079 * the parsing mechanism leaves out an XSLT element, then
3080 * this might hit the transformation-mechanism, which
3081 * will break if it doesn't expect such a marker.
3083 /* cur->psvi = (void *) xsltXSLTElemMarker; */
3086 * XSLT 2.0: "Any whitespace text node whose parent is
3087 * one of the following elements is removed from the "
3088 * tree, regardless of any xml:space attributes:..."
3089 * xsl:apply-imports,
3090 * xsl:apply-templates,
3091 * xsl:attribute-set,
3092 * xsl:call-template,
3094 * xsl:stylesheet, xsl:transform.
3095 * XSLT 2.0: xsl:analyze-string,
3096 * xsl:character-map,
3099 * TODO: I'd love to use a string pointer comparison here :-/
3104 if ((name
[0] == 't') && (name
[1] == 'e') &&
3105 (name
[2] == 'x') && (name
[3] == 't') &&
3109 * Process the xsl:text element.
3110 * ----------------------------
3111 * Mark it for later recognition.
3113 cur
->psvi
= (void *) xsltXSLTTextMarker
;
3115 * For stylesheets, the set of
3116 * whitespace-preserving element names
3117 * consists of just xsl:text.
3120 cctxt
->inode
->preserveWhitespace
= 1;
3125 if (xmlStrEqual(name
, BAD_CAST
"choose") ||
3126 xmlStrEqual(name
, BAD_CAST
"call-template"))
3127 cctxt
->inode
->stripWhitespace
= 1;
3130 if (xmlStrEqual(name
, BAD_CAST
"apply-templates") ||
3131 xmlStrEqual(name
, BAD_CAST
"apply-imports") ||
3132 xmlStrEqual(name
, BAD_CAST
"attribute-set"))
3134 cctxt
->inode
->stripWhitespace
= 1;
3137 if (xsltStylesheetElemDepth
== cctxt
->depth
) {
3139 * This is a xsl:stylesheet/xsl:transform.
3141 cctxt
->inode
->stripWhitespace
= 1;
3145 if ((cur
->prev
!= NULL
) &&
3146 (cur
->prev
->type
== XML_TEXT_NODE
))
3149 * XSLT 2.0 : "Any whitespace text node whose
3150 * following-sibling node is an xsl:param or
3151 * xsl:sort element is removed from the tree,
3152 * regardless of any xml:space attributes."
3154 if (((*name
== 'p') || (*name
== 's')) &&
3155 (xmlStrEqual(name
, BAD_CAST
"param") ||
3156 xmlStrEqual(name
, BAD_CAST
"sort")))
3159 if (IS_BLANK_NODE(cur
->prev
)) {
3165 * This will result in a content
3166 * error, when hitting the parsing
3171 } while (cur
->prev
);
3180 * Process attributes.
3181 * ------------------
3183 if (cur
->properties
!= NULL
) {
3184 if (cur
->children
== NULL
)
3186 attr
= cur
->properties
;
3188 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3189 if ((attr
->ns
) && (attr
->ns
->href
!= nsNameXSLT
) &&
3190 xmlStrEqual(attr
->ns
->href
, nsNameXSLT
))
3192 nsMapItem
= xsltNewNamespaceMapItem(cctxt
,
3193 doc
, attr
->ns
, cur
);
3194 if (nsMapItem
== NULL
)
3196 attr
->ns
->href
= nsNameXSLT
;
3201 * Internalize the attribute's value; the goal is to
3202 * speed up operations and minimize used space by
3203 * compiled stylesheets.
3205 txt
= attr
->children
;
3207 * NOTE that this assumes only one
3208 * text-node in the attribute's content.
3210 if ((txt
!= NULL
) && (txt
->content
!= NULL
) &&
3211 (!xmlDictOwns(style
->dict
, txt
->content
)))
3213 value
= (xmlChar
*) xmlDictLookup(style
->dict
,
3215 xmlNodeSetContent(txt
, NULL
);
3216 txt
->content
= value
;
3220 * Process xml:space attributes.
3221 * ----------------------------
3223 if ((findSpaceAttr
!= 0) &&
3224 (attr
->ns
!= NULL
) &&
3225 (attr
->name
!= NULL
) &&
3226 (attr
->name
[0] == 's') &&
3227 (attr
->ns
->prefix
!= NULL
) &&
3228 (attr
->ns
->prefix
[0] == 'x') &&
3229 (attr
->ns
->prefix
[1] == 'm') &&
3230 (attr
->ns
->prefix
[2] == 'l') &&
3231 (attr
->ns
->prefix
[3] == 0))
3233 value
= xmlGetNsProp(cur
, BAD_CAST
"space",
3235 if (value
!= NULL
) {
3236 if (xmlStrEqual(value
, BAD_CAST
"preserve")) {
3237 cctxt
->inode
->preserveWhitespace
= 1;
3238 } else if (xmlStrEqual(value
, BAD_CAST
"default")) {
3239 cctxt
->inode
->preserveWhitespace
= 0;
3241 /* Invalid value for xml:space. */
3242 xsltTransformError(NULL
, style
, cur
,
3243 "Attribute xml:space: Invalid value.\n");
3244 cctxt
->style
->warnings
++;
3252 } while (attr
!= NULL
);
3255 * We'll descend into the children of element nodes only.
3257 if (cur
->children
!= NULL
) {
3258 cur
= cur
->children
;
3261 } else if ((cur
->type
== XML_TEXT_NODE
) ||
3262 (cur
->type
== XML_CDATA_SECTION_NODE
))
3265 * Merge adjacent text/CDATA-section-nodes
3266 * ---------------------------------------
3267 * In order to avoid breaking of existing stylesheets,
3268 * if the old behaviour is wanted (strictWhitespace == 0),
3269 * then we *won't* merge adjacent text-nodes
3270 * (except in xsl:text); this will ensure that whitespace-only
3271 * text nodes are (incorrectly) not stripped in some cases.
3273 * Example: : <foo> <!-- bar -->zoo</foo>
3274 * Corrent (strict) result: <foo> zoo</foo>
3275 * Incorrect (old) result : <foo>zoo</foo>
3277 * NOTE that we *will* merge adjacent text-nodes if
3278 * they are in xsl:text.
3279 * Example, the following:
3280 * <xsl:text> <!-- bar -->zoo<xsl:text>
3281 * will result in both cases in:
3282 * <xsl:text> zoo<xsl:text>
3284 cur
->type
= XML_TEXT_NODE
;
3285 if ((strictWhitespace
!= 0) || (inXSLText
!= 0)) {
3287 * New behaviour; merge nodes.
3289 if (textNode
== NULL
)
3292 if (cur
->content
!= NULL
)
3293 xmlNodeAddContent(textNode
, cur
->content
);
3296 if ((cur
->next
== NULL
) ||
3297 (cur
->next
->type
== XML_ELEMENT_NODE
))
3305 if (textNode
== NULL
)
3309 } else if ((cur
->type
== XML_COMMENT_NODE
) ||
3310 (cur
->type
== XML_PI_NODE
))
3313 * Remove processing instructions and comments.
3316 if ((cur
->next
== NULL
) ||
3317 (cur
->next
->type
== XML_ELEMENT_NODE
))
3324 * Invalid node-type for this data-model.
3326 xsltTransformError(NULL
, style
, cur
,
3327 "Invalid type of node for the XSLT data model.\n");
3328 cctxt
->style
->errors
++;
3334 value
= textNode
->content
;
3336 * At this point all adjacent text/CDATA-section nodes
3339 * Strip whitespace-only text-nodes.
3340 * (cctxt->inode->stripWhitespace)
3342 if ((value
== NULL
) || (*value
== 0) ||
3343 (((cctxt
->inode
->stripWhitespace
) ||
3344 (! cctxt
->inode
->preserveWhitespace
)) &&
3346 xsltIsBlank(value
)))
3348 if (textNode
!= cur
) {
3349 xmlUnlinkNode(textNode
);
3350 xmlFreeNode(textNode
);
3352 deleteNode
= textNode
;
3357 * Convert CDATA-section nodes to text-nodes.
3358 * TODO: Can this produce problems?
3360 if (textNode
->type
!= XML_TEXT_NODE
) {
3361 textNode
->type
= XML_TEXT_NODE
;
3362 textNode
->name
= xmlStringText
;
3365 (textNode
->content
!= NULL
) &&
3366 (!xmlDictOwns(style
->dict
, textNode
->content
)))
3369 * Internalize the string.
3371 value
= (xmlChar
*) xmlDictLookup(style
->dict
,
3372 textNode
->content
, -1);
3373 xmlNodeSetContent(textNode
, NULL
);
3374 textNode
->content
= value
;
3378 * Note that "disable-output-escaping" of the xsl:text
3379 * element will be applied at a later level, when
3380 * XSLT elements are processed.
3385 if (cur
->type
== XML_ELEMENT_NODE
) {
3386 xsltCompilerNodePop(cctxt
, cur
);
3390 if (cur
->next
!= NULL
) {
3398 if (deleteNode
!= NULL
) {
3399 #ifdef WITH_XSLT_DEBUG_PARSING
3400 xsltGenericDebug(xsltGenericDebugContext
,
3401 "xsltParsePreprocessStylesheetTree: removing node\n");
3403 xmlUnlinkNode(deleteNode
);
3404 xmlFreeNode(deleteNode
);
3412 #endif /* XSLT_REFACTORED */
3414 #ifdef XSLT_REFACTORED
3417 xsltPrecomputeStylesheet(xsltStylesheetPtr style
, xmlNodePtr cur
)
3419 xmlNodePtr deleteNode
, styleelem
;
3420 int internalize
= 0;
3422 if ((style
== NULL
) || (cur
== NULL
))
3425 if ((cur
->doc
!= NULL
) && (style
->dict
!= NULL
) &&
3426 (cur
->doc
->dict
== style
->dict
))
3429 style
->internalized
= 0;
3431 if ((cur
!= NULL
) && (IS_XSLT_ELEM(cur
)) &&
3432 (IS_XSLT_NAME(cur
, "stylesheet"))) {
3439 * This content comes from the stylesheet
3440 * For stylesheets, the set of whitespace-preserving
3441 * element names consists of just xsl:text.
3444 while (cur
!= NULL
) {
3445 if (deleteNode
!= NULL
) {
3446 #ifdef WITH_XSLT_DEBUG_BLANKS
3447 xsltGenericDebug(xsltGenericDebugContext
,
3448 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
3450 xmlUnlinkNode(deleteNode
);
3451 xmlFreeNode(deleteNode
);
3454 if (cur
->type
== XML_ELEMENT_NODE
) {
3457 * Internalize attributes values.
3459 if ((internalize
) && (cur
->properties
!= NULL
)) {
3460 xmlAttrPtr attr
= cur
->properties
;
3463 while (attr
!= NULL
) {
3464 txt
= attr
->children
;
3465 if ((txt
!= NULL
) && (txt
->type
== XML_TEXT_NODE
) &&
3466 (txt
->content
!= NULL
) &&
3467 (!xmlDictOwns(style
->dict
, txt
->content
)))
3472 * internalize the text string, goal is to speed
3473 * up operations and minimize used space by compiled
3476 tmp
= (xmlChar
*) xmlDictLookup(style
->dict
,
3478 if (tmp
!= txt
->content
) {
3479 xmlNodeSetContent(txt
, NULL
);
3486 if (IS_XSLT_ELEM(cur
)) {
3488 xsltStylePreCompute(style
, cur
);
3489 if (IS_XSLT_NAME(cur
, "text")) {
3490 for (;exclPrefixes
> 0;exclPrefixes
--)
3491 exclPrefixPop(style
);
3495 exclPrefixes
= xsltParseStylesheetExcludePrefix(style
, cur
, 0);
3498 if ((cur
->nsDef
!= NULL
) && (style
->exclPrefixNr
> 0)) {
3499 xmlNsPtr ns
= cur
->nsDef
, prev
= NULL
, next
;
3500 xmlNodePtr root
= NULL
;
3503 root
= xmlDocGetRootElement(cur
->doc
);
3504 if ((root
!= NULL
) && (root
!= cur
)) {
3505 while (ns
!= NULL
) {
3508 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
3509 if ((ns
->prefix
!= NULL
) &&
3510 (xmlStrEqual(ns
->href
,
3511 style
->exclPrefixTab
[i
]))) {
3513 * Move the namespace definition on the root
3514 * element to avoid duplicating it without
3518 cur
->nsDef
= ns
->next
;
3520 prev
->next
= ns
->next
;
3522 ns
->next
= root
->nsDef
;
3535 * If we have prefixes locally, recurse and pop them up when
3538 if (exclPrefixes
> 0) {
3539 xsltPrecomputeStylesheet(style
, cur
->children
);
3540 for (;exclPrefixes
> 0;exclPrefixes
--)
3541 exclPrefixPop(style
);
3544 } else if (cur
->type
== XML_TEXT_NODE
) {
3545 if (IS_BLANK_NODE(cur
)) {
3546 if (xmlNodeGetSpacePreserve(cur
) != 1) {
3549 } else if ((cur
->content
!= NULL
) && (internalize
) &&
3550 (!xmlDictOwns(style
->dict
, cur
->content
))) {
3554 * internalize the text string, goal is to speed
3555 * up operations and minimize used space by compiled
3558 tmp
= (xmlChar
*) xmlDictLookup(style
->dict
, cur
->content
, -1);
3559 xmlNodeSetContent(cur
, NULL
);
3562 } else if ((cur
->type
!= XML_ELEMENT_NODE
) &&
3563 (cur
->type
!= XML_CDATA_SECTION_NODE
)) {
3569 * Skip to next node. In case of a namespaced element children of
3570 * the stylesheet and not in the XSLT namespace and not an extension
3571 * element, ignore its content.
3573 if ((cur
->type
== XML_ELEMENT_NODE
) && (cur
->ns
!= NULL
) &&
3574 (styleelem
!= NULL
) && (cur
->parent
== styleelem
) &&
3575 (!xmlStrEqual(cur
->ns
->href
, XSLT_NAMESPACE
)) &&
3576 (!xsltCheckExtURI(style
, cur
->ns
->href
))) {
3578 } else if (cur
->children
!= NULL
) {
3579 if ((cur
->children
->type
!= XML_ENTITY_DECL
) &&
3580 (cur
->children
->type
!= XML_ENTITY_REF_NODE
) &&
3581 (cur
->children
->type
!= XML_ENTITY_NODE
)) {
3582 cur
= cur
->children
;
3588 if (cur
->next
!= NULL
) {
3597 if (cur
== (xmlNodePtr
) style
->doc
) {
3601 if (cur
->next
!= NULL
) {
3605 } while (cur
!= NULL
);
3607 if (deleteNode
!= NULL
) {
3608 #ifdef WITH_XSLT_DEBUG_PARSING
3609 xsltGenericDebug(xsltGenericDebugContext
,
3610 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
3612 xmlUnlinkNode(deleteNode
);
3613 xmlFreeNode(deleteNode
);
3616 #endif /* end of else XSLT_REFACTORED */
3619 * xsltGatherNamespaces:
3620 * @style: the XSLT stylesheet
3622 * Browse the stylesheet and build the namspace hash table which
3623 * will be used for XPath interpretation. If needed do a bit of normalization
3627 xsltGatherNamespaces(xsltStylesheetPtr style
) {
3634 * TODO: basically if the stylesheet uses the same prefix for different
3635 * patterns, well they may be in problem, hopefully they will get
3639 * TODO: Eliminate the use of the hash for XPath expressions.
3640 * An expression should be evaluated in the context of the in-scope
3641 * namespaces; eliminate the restriction of an XML document to contain
3642 * no duplicate prefixes for different namespace names.
3645 cur
= xmlDocGetRootElement(style
->doc
);
3646 while (cur
!= NULL
) {
3647 if (cur
->type
== XML_ELEMENT_NODE
) {
3648 xmlNsPtr ns
= cur
->nsDef
;
3649 while (ns
!= NULL
) {
3650 if (ns
->prefix
!= NULL
) {
3651 if (style
->nsHash
== NULL
) {
3652 style
->nsHash
= xmlHashCreate(10);
3653 if (style
->nsHash
== NULL
) {
3654 xsltTransformError(NULL
, style
, cur
,
3655 "xsltGatherNamespaces: failed to create hash table\n");
3660 URI
= xmlHashLookup(style
->nsHash
, ns
->prefix
);
3661 if ((URI
!= NULL
) && (!xmlStrEqual(URI
, ns
->href
))) {
3662 xsltTransformError(NULL
, style
, cur
,
3663 "Namespaces prefix %s used for multiple namespaces\n",ns
->prefix
);
3665 } else if (URI
== NULL
) {
3666 xmlHashUpdateEntry(style
->nsHash
, ns
->prefix
,
3667 (void *) ns
->href
, (xmlHashDeallocator
)xmlFree
);
3669 #ifdef WITH_XSLT_DEBUG_PARSING
3670 xsltGenericDebug(xsltGenericDebugContext
,
3671 "Added namespace: %s mapped to %s\n", ns
->prefix
, ns
->href
);
3682 if (cur
->children
!= NULL
) {
3683 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
3684 cur
= cur
->children
;
3688 if (cur
->next
!= NULL
) {
3697 if (cur
== (xmlNodePtr
) style
->doc
) {
3701 if (cur
->next
!= NULL
) {
3705 } while (cur
!= NULL
);
3709 #ifdef XSLT_REFACTORED
3711 static xsltStyleType
3712 xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt
,
3715 if ((node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
) ||
3716 (node
->name
== NULL
))
3719 if (node
->name
[0] == 'a') {
3720 if (IS_XSLT_NAME(node
, "apply-templates"))
3721 return(XSLT_FUNC_APPLYTEMPLATES
);
3722 else if (IS_XSLT_NAME(node
, "attribute"))
3723 return(XSLT_FUNC_ATTRIBUTE
);
3724 else if (IS_XSLT_NAME(node
, "apply-imports"))
3725 return(XSLT_FUNC_APPLYIMPORTS
);
3726 else if (IS_XSLT_NAME(node
, "attribute-set"))
3729 } else if (node
->name
[0] == 'c') {
3730 if (IS_XSLT_NAME(node
, "choose"))
3731 return(XSLT_FUNC_CHOOSE
);
3732 else if (IS_XSLT_NAME(node
, "copy"))
3733 return(XSLT_FUNC_COPY
);
3734 else if (IS_XSLT_NAME(node
, "copy-of"))
3735 return(XSLT_FUNC_COPYOF
);
3736 else if (IS_XSLT_NAME(node
, "call-template"))
3737 return(XSLT_FUNC_CALLTEMPLATE
);
3738 else if (IS_XSLT_NAME(node
, "comment"))
3739 return(XSLT_FUNC_COMMENT
);
3741 } else if (node
->name
[0] == 'd') {
3742 if (IS_XSLT_NAME(node
, "document"))
3743 return(XSLT_FUNC_DOCUMENT
);
3744 else if (IS_XSLT_NAME(node
, "decimal-format"))
3747 } else if (node
->name
[0] == 'e') {
3748 if (IS_XSLT_NAME(node
, "element"))
3749 return(XSLT_FUNC_ELEMENT
);
3751 } else if (node
->name
[0] == 'f') {
3752 if (IS_XSLT_NAME(node
, "for-each"))
3753 return(XSLT_FUNC_FOREACH
);
3754 else if (IS_XSLT_NAME(node
, "fallback"))
3755 return(XSLT_FUNC_FALLBACK
);
3757 } else if (*(node
->name
) == 'i') {
3758 if (IS_XSLT_NAME(node
, "if"))
3759 return(XSLT_FUNC_IF
);
3760 else if (IS_XSLT_NAME(node
, "include"))
3762 else if (IS_XSLT_NAME(node
, "import"))
3765 } else if (*(node
->name
) == 'k') {
3766 if (IS_XSLT_NAME(node
, "key"))
3769 } else if (*(node
->name
) == 'm') {
3770 if (IS_XSLT_NAME(node
, "message"))
3771 return(XSLT_FUNC_MESSAGE
);
3773 } else if (*(node
->name
) == 'n') {
3774 if (IS_XSLT_NAME(node
, "number"))
3775 return(XSLT_FUNC_NUMBER
);
3776 else if (IS_XSLT_NAME(node
, "namespace-alias"))
3779 } else if (*(node
->name
) == 'o') {
3780 if (IS_XSLT_NAME(node
, "otherwise"))
3781 return(XSLT_FUNC_OTHERWISE
);
3782 else if (IS_XSLT_NAME(node
, "output"))
3785 } else if (*(node
->name
) == 'p') {
3786 if (IS_XSLT_NAME(node
, "param"))
3787 return(XSLT_FUNC_PARAM
);
3788 else if (IS_XSLT_NAME(node
, "processing-instruction"))
3789 return(XSLT_FUNC_PI
);
3790 else if (IS_XSLT_NAME(node
, "preserve-space"))
3793 } else if (*(node
->name
) == 's') {
3794 if (IS_XSLT_NAME(node
, "sort"))
3795 return(XSLT_FUNC_SORT
);
3796 else if (IS_XSLT_NAME(node
, "strip-space"))
3798 else if (IS_XSLT_NAME(node
, "stylesheet"))
3801 } else if (node
->name
[0] == 't') {
3802 if (IS_XSLT_NAME(node
, "text"))
3803 return(XSLT_FUNC_TEXT
);
3804 else if (IS_XSLT_NAME(node
, "template"))
3806 else if (IS_XSLT_NAME(node
, "transform"))
3809 } else if (*(node
->name
) == 'v') {
3810 if (IS_XSLT_NAME(node
, "value-of"))
3811 return(XSLT_FUNC_VALUEOF
);
3812 else if (IS_XSLT_NAME(node
, "variable"))
3813 return(XSLT_FUNC_VARIABLE
);
3815 } else if (*(node
->name
) == 'w') {
3816 if (IS_XSLT_NAME(node
, "when"))
3817 return(XSLT_FUNC_WHEN
);
3818 if (IS_XSLT_NAME(node
, "with-param"))
3819 return(XSLT_FUNC_WITHPARAM
);
3825 * xsltParseAnyXSLTElem:
3827 * @cctxt: the compilation context
3828 * @elem: the element node of the XSLT instruction
3830 * Parses, validates the content models and compiles XSLT instructions.
3832 * Returns 0 if everything's fine;
3833 * -1 on API or internal errors.
3836 xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr elem
)
3838 if ((cctxt
== NULL
) || (elem
== NULL
) ||
3839 (elem
->type
!= XML_ELEMENT_NODE
))
3844 if (! (IS_XSLT_ELEM_FAST(elem
)))
3847 * Detection of handled content of extension instructions.
3849 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
3850 cctxt
->inode
->extContentHandled
= 1;
3853 xsltCompilerNodePush(cctxt
, elem
);
3855 * URGENT TODO: Find a way to speed up this annoying redundant
3856 * textual node-name and namespace comparison.
3858 if (cctxt
->inode
->prev
->curChildType
!= 0)
3859 cctxt
->inode
->type
= cctxt
->inode
->prev
->curChildType
;
3861 cctxt
->inode
->type
= xsltGetXSLTElementTypeByNode(cctxt
, elem
);
3863 * Update the in-scope namespaces if needed.
3865 if (elem
->nsDef
!= NULL
)
3866 cctxt
->inode
->inScopeNs
=
3867 xsltCompilerBuildInScopeNsList(cctxt
, elem
);
3869 * xsltStylePreCompute():
3870 * This will compile the information found on the current
3871 * element's attributes. NOTE that this won't process the
3872 * children of the instruction.
3874 xsltStylePreCompute(cctxt
->style
, elem
);
3876 * TODO: How to react on errors in xsltStylePreCompute() ?
3880 * Validate the content model of the XSLT-element.
3882 switch (cctxt
->inode
->type
) {
3883 case XSLT_FUNC_APPLYIMPORTS
:
3886 case XSLT_FUNC_APPLYTEMPLATES
:
3887 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
3888 goto apply_templates
;
3889 case XSLT_FUNC_ATTRIBUTE
:
3890 /* <!-- Content: template --> */
3891 goto sequence_constructor
;
3892 case XSLT_FUNC_CALLTEMPLATE
:
3893 /* <!-- Content: xsl:with-param* --> */
3895 case XSLT_FUNC_CHOOSE
:
3896 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
3898 case XSLT_FUNC_COMMENT
:
3899 /* <!-- Content: template --> */
3900 goto sequence_constructor
;
3901 case XSLT_FUNC_COPY
:
3902 /* <!-- Content: template --> */
3903 goto sequence_constructor
;
3904 case XSLT_FUNC_COPYOF
:
3907 case XSLT_FUNC_DOCUMENT
: /* Extra one */
3908 /* ?? template ?? */
3909 goto sequence_constructor
;
3910 case XSLT_FUNC_ELEMENT
:
3911 /* <!-- Content: template --> */
3912 goto sequence_constructor
;
3913 case XSLT_FUNC_FALLBACK
:
3914 /* <!-- Content: template --> */
3915 goto sequence_constructor
;
3916 case XSLT_FUNC_FOREACH
:
3917 /* <!-- Content: (xsl:sort*, template) --> */
3920 /* <!-- Content: template --> */
3921 goto sequence_constructor
;
3922 case XSLT_FUNC_OTHERWISE
:
3923 /* <!-- Content: template --> */
3924 goto sequence_constructor
;
3925 case XSLT_FUNC_MESSAGE
:
3926 /* <!-- Content: template --> */
3927 goto sequence_constructor
;
3928 case XSLT_FUNC_NUMBER
:
3931 case XSLT_FUNC_PARAM
:
3933 * Check for redefinition.
3935 if ((elem
->psvi
!= NULL
) && (cctxt
->ivar
!= NULL
)) {
3936 xsltVarInfoPtr ivar
= cctxt
->ivar
;
3940 ((xsltStyleItemParamPtr
) elem
->psvi
)->name
) &&
3942 ((xsltStyleItemParamPtr
) elem
->psvi
)->ns
))
3945 xsltTransformError(NULL
, cctxt
->style
, elem
,
3946 "Redefinition of variable or parameter '%s'.\n",
3948 cctxt
->style
->errors
++;
3952 } while (ivar
!= NULL
);
3954 /* <!-- Content: template --> */
3955 goto sequence_constructor
;
3957 /* <!-- Content: template --> */
3958 goto sequence_constructor
;
3959 case XSLT_FUNC_SORT
:
3962 case XSLT_FUNC_TEXT
:
3963 /* <!-- Content: #PCDATA --> */
3965 case XSLT_FUNC_VALUEOF
:
3968 case XSLT_FUNC_VARIABLE
:
3970 * Check for redefinition.
3972 if ((elem
->psvi
!= NULL
) && (cctxt
->ivar
!= NULL
)) {
3973 xsltVarInfoPtr ivar
= cctxt
->ivar
;
3977 ((xsltStyleItemVariablePtr
) elem
->psvi
)->name
) &&
3979 ((xsltStyleItemVariablePtr
) elem
->psvi
)->ns
))
3982 xsltTransformError(NULL
, cctxt
->style
, elem
,
3983 "Redefinition of variable or parameter '%s'.\n",
3985 cctxt
->style
->errors
++;
3989 } while (ivar
!= NULL
);
3991 /* <!-- Content: template --> */
3992 goto sequence_constructor
;
3993 case XSLT_FUNC_WHEN
:
3994 /* <!-- Content: template --> */
3995 goto sequence_constructor
;
3996 case XSLT_FUNC_WITHPARAM
:
3997 /* <!-- Content: template --> */
3998 goto sequence_constructor
;
4000 #ifdef WITH_XSLT_DEBUG_PARSING
4001 xsltGenericDebug(xsltGenericDebugContext
,
4002 "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
4005 xsltTransformError(NULL
, cctxt
->style
, elem
,
4006 "xsltParseXSLTNode: Internal error; "
4007 "unhandled XSLT element '%s'.\n", elem
->name
);
4008 cctxt
->style
->errors
++;
4013 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
4014 if (elem
->children
!= NULL
) {
4015 xmlNodePtr child
= elem
->children
;
4017 if (child
->type
== XML_ELEMENT_NODE
) {
4018 if (IS_XSLT_ELEM_FAST(child
)) {
4019 if (xmlStrEqual(child
->name
, BAD_CAST
"with-param")) {
4020 cctxt
->inode
->curChildType
= XSLT_FUNC_WITHPARAM
;
4021 xsltParseAnyXSLTElem(cctxt
, child
);
4022 } else if (xmlStrEqual(child
->name
, BAD_CAST
"sort")) {
4023 cctxt
->inode
->curChildType
= XSLT_FUNC_SORT
;
4024 xsltParseAnyXSLTElem(cctxt
, child
);
4026 xsltParseContentError(cctxt
->style
, child
);
4028 xsltParseContentError(cctxt
->style
, child
);
4030 child
= child
->next
;
4031 } while (child
!= NULL
);
4036 /* <!-- Content: xsl:with-param* --> */
4037 if (elem
->children
!= NULL
) {
4038 xmlNodePtr child
= elem
->children
;
4040 if (child
->type
== XML_ELEMENT_NODE
) {
4041 if (IS_XSLT_ELEM_FAST(child
)) {
4044 type
= xsltGetXSLTElementTypeByNode(cctxt
, child
);
4045 if (type
== XSLT_FUNC_WITHPARAM
) {
4046 cctxt
->inode
->curChildType
= XSLT_FUNC_WITHPARAM
;
4047 xsltParseAnyXSLTElem(cctxt
, child
);
4049 xsltParseContentError(cctxt
->style
, child
);
4052 xsltParseContentError(cctxt
->style
, child
);
4054 child
= child
->next
;
4055 } while (child
!= NULL
);
4060 if (elem
->children
!= NULL
) {
4061 xmlNodePtr child
= elem
->children
;
4063 if ((child
->type
!= XML_TEXT_NODE
) &&
4064 (child
->type
!= XML_CDATA_SECTION_NODE
))
4066 xsltTransformError(NULL
, cctxt
->style
, elem
,
4067 "The XSLT 'text' element must have only character "
4068 "data as content.\n");
4070 child
= child
->next
;
4071 } while (child
!= NULL
);
4076 if (elem
->children
!= NULL
) {
4077 xmlNodePtr child
= elem
->children
;
4079 * Relaxed behaviour: we will allow whitespace-only text-nodes.
4082 if (((child
->type
!= XML_TEXT_NODE
) &&
4083 (child
->type
!= XML_CDATA_SECTION_NODE
)) ||
4084 (! IS_BLANK_NODE(child
)))
4086 xsltTransformError(NULL
, cctxt
->style
, elem
,
4087 "This XSLT element must have no content.\n");
4088 cctxt
->style
->errors
++;
4091 child
= child
->next
;
4092 } while (child
!= NULL
);
4097 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
4099 * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
4100 * The old behaviour did not check this.
4101 * NOTE: In XSLT 2.0 they are stripped beforehand
4102 * if whitespace-only (regardless of xml:space).
4104 if (elem
->children
!= NULL
) {
4105 xmlNodePtr child
= elem
->children
;
4106 int nbWhen
= 0, nbOtherwise
= 0, err
= 0;
4108 if (child
->type
== XML_ELEMENT_NODE
) {
4109 if (IS_XSLT_ELEM_FAST(child
)) {
4112 type
= xsltGetXSLTElementTypeByNode(cctxt
, child
);
4113 if (type
== XSLT_FUNC_WHEN
) {
4116 xsltParseContentError(cctxt
->style
, child
);
4120 cctxt
->inode
->curChildType
= XSLT_FUNC_WHEN
;
4121 xsltParseAnyXSLTElem(cctxt
, child
);
4122 } else if (type
== XSLT_FUNC_OTHERWISE
) {
4124 xsltParseContentError(cctxt
->style
, child
);
4129 xsltTransformError(NULL
, cctxt
->style
, elem
,
4130 "The XSLT 'choose' element must not contain "
4131 "more than one XSLT 'otherwise' element.\n");
4132 cctxt
->style
->errors
++;
4137 cctxt
->inode
->curChildType
= XSLT_FUNC_OTHERWISE
;
4138 xsltParseAnyXSLTElem(cctxt
, child
);
4140 xsltParseContentError(cctxt
->style
, child
);
4142 xsltParseContentError(cctxt
->style
, child
);
4146 xsltParseContentError(cctxt, child);
4148 child
= child
->next
;
4149 } while (child
!= NULL
);
4150 if ((! err
) && (! nbWhen
)) {
4151 xsltTransformError(NULL
, cctxt
->style
, elem
,
4152 "The XSLT element 'choose' must contain at least one "
4153 "XSLT element 'when'.\n");
4154 cctxt
->style
->errors
++;
4160 /* <!-- Content: (xsl:sort*, template) --> */
4162 * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
4163 * The old behaviour did not allow this, but it catched this
4164 * only at transformation-time.
4165 * In XSLT 2.0 they are stripped beforehand if whitespace-only
4166 * (regardless of xml:space).
4168 if (elem
->children
!= NULL
) {
4169 xmlNodePtr child
= elem
->children
;
4171 * Parse xsl:sort first.
4174 if ((child
->type
== XML_ELEMENT_NODE
) &&
4175 IS_XSLT_ELEM_FAST(child
))
4177 if (xsltGetXSLTElementTypeByNode(cctxt
, child
) ==
4180 cctxt
->inode
->curChildType
= XSLT_FUNC_SORT
;
4181 xsltParseAnyXSLTElem(cctxt
, child
);
4186 child
= child
->next
;
4187 } while (child
!= NULL
);
4189 * Parse the sequece constructor.
4192 xsltParseSequenceConstructor(cctxt
, child
);
4196 sequence_constructor
:
4198 * Parse the sequence constructor.
4200 if (elem
->children
!= NULL
)
4201 xsltParseSequenceConstructor(cctxt
, elem
->children
);
4204 * Register information for vars/params. Only needed if there
4205 * are any following siblings.
4207 if ((elem
->next
!= NULL
) &&
4208 ((cctxt
->inode
->type
== XSLT_FUNC_VARIABLE
) ||
4209 (cctxt
->inode
->type
== XSLT_FUNC_PARAM
)))
4211 if ((elem
->psvi
!= NULL
) &&
4212 (((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->name
))
4214 xsltCompilerVarInfoPush(cctxt
, elem
,
4215 ((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->name
,
4216 ((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->ns
);
4222 xsltCompilerNodePop(cctxt
, elem
);
4226 xsltCompilerNodePop(cctxt
, elem
);
4231 * xsltForwardsCompatUnkownItemCreate:
4233 * @cctxt: the compilation context
4235 * Creates a compiled representation of the unknown
4238 * Returns the compiled representation.
4240 static xsltStyleItemUknownPtr
4241 xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt
)
4243 xsltStyleItemUknownPtr item
;
4245 item
= (xsltStyleItemUknownPtr
) xmlMalloc(sizeof(xsltStyleItemUknown
));
4247 xsltTransformError(NULL
, cctxt
->style
, NULL
,
4248 "Internal error in xsltForwardsCompatUnkownItemCreate(): "
4249 "Failed to allocate memory.\n");
4250 cctxt
->style
->errors
++;
4253 memset(item
, 0, sizeof(xsltStyleItemUknown
));
4254 item
->type
= XSLT_FUNC_UNKOWN_FORWARDS_COMPAT
;
4256 * Store it in the stylesheet.
4258 item
->next
= cctxt
->style
->preComps
;
4259 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
4264 * xsltParseUnknownXSLTElem:
4266 * @cctxt: the compilation context
4267 * @node: the element of the unknown XSLT instruction
4269 * Parses an unknown XSLT element.
4270 * If forwards compatible mode is enabled this will allow
4271 * such an unknown XSLT and; otherwise it is rejected.
4273 * Returns 1 in the unknown XSLT instruction is rejected,
4274 * 0 if everything's fine and
4275 * -1 on API or internal errors.
4278 xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt
,
4281 if ((cctxt
== NULL
) || (node
== NULL
))
4285 * Detection of handled content of extension instructions.
4287 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4288 cctxt
->inode
->extContentHandled
= 1;
4290 if (cctxt
->inode
->forwardsCompat
== 0) {
4292 * We are not in forwards-compatible mode, so raise an error.
4294 xsltTransformError(NULL
, cctxt
->style
, node
,
4295 "Unknown XSLT element '%s'.\n", node
->name
);
4296 cctxt
->style
->errors
++;
4300 * Forwards-compatible mode.
4301 * ------------------------
4303 * Parse/compile xsl:fallback elements.
4305 * QUESTION: Do we have to raise an error if there's no xsl:fallback?
4306 * ANSWER: No, since in the stylesheet the fallback behaviour might
4307 * also be provided by using the XSLT function "element-available".
4309 if (cctxt
->unknownItem
== NULL
) {
4311 * Create a singleton for all unknown XSLT instructions.
4313 cctxt
->unknownItem
= xsltForwardsCompatUnkownItemCreate(cctxt
);
4314 if (cctxt
->unknownItem
== NULL
) {
4319 node
->psvi
= cctxt
->unknownItem
;
4320 if (node
->children
== NULL
)
4323 xmlNodePtr child
= node
->children
;
4325 xsltCompilerNodePush(cctxt
, node
);
4327 * Update the in-scope namespaces if needed.
4329 if (node
->nsDef
!= NULL
)
4330 cctxt
->inode
->inScopeNs
=
4331 xsltCompilerBuildInScopeNsList(cctxt
, node
);
4333 * Parse all xsl:fallback children.
4336 if ((child
->type
== XML_ELEMENT_NODE
) &&
4337 IS_XSLT_ELEM_FAST(child
) &&
4338 IS_XSLT_NAME(child
, "fallback"))
4340 cctxt
->inode
->curChildType
= XSLT_FUNC_FALLBACK
;
4341 xsltParseAnyXSLTElem(cctxt
, child
);
4343 child
= child
->next
;
4344 } while (child
!= NULL
);
4346 xsltCompilerNodePop(cctxt
, node
);
4352 * xsltParseSequenceConstructor:
4354 * @cctxt: the compilation context
4355 * @cur: the start-node of the content to be parsed
4357 * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
4358 * This will additionally remove xsl:text elements from the tree.
4361 xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt
, xmlNodePtr cur
)
4364 xmlNodePtr deleteNode
= NULL
;
4366 if (cctxt
== NULL
) {
4367 xmlGenericError(xmlGenericErrorContext
,
4368 "xsltParseSequenceConstructor: Bad arguments\n");
4369 cctxt
->style
->errors
++;
4373 * Detection of handled content of extension instructions.
4375 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4376 cctxt
->inode
->extContentHandled
= 1;
4381 * This is the content reffered to as a "template".
4382 * E.g. an xsl:element has such content model:
4385 * namespace = { uri-reference }
4386 * use-attribute-sets = qnames>
4387 * <!-- Content: template -->
4389 * NOTE that in XSLT-2 the term "template" was abandoned due to
4390 * confusion with xsl:template and the term "sequence constructor"
4391 * was introduced instead.
4393 * The following XSLT-instructions are allowed to appear:
4394 * xsl:apply-templates, xsl:call-template, xsl:apply-imports,
4395 * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
4396 * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
4397 * xsl:message, xsl:fallback,
4398 * xsl:processing-instruction, xsl:comment, xsl:element
4400 * Additional allowed content:
4401 * 1) extension instructions
4402 * 2) literal result elements
4405 * NOTE that this content model does *not* allow xsl:param.
4407 while (cur
!= NULL
) {
4408 if (deleteNode
!= NULL
) {
4409 #ifdef WITH_XSLT_DEBUG_BLANKS
4410 xsltGenericDebug(xsltGenericDebugContext
,
4411 "xsltParseSequenceConstructor: removing xsl:text element\n");
4413 xmlUnlinkNode(deleteNode
);
4414 xmlFreeNode(deleteNode
);
4417 if (cur
->type
== XML_ELEMENT_NODE
) {
4419 if (cur
->psvi
== xsltXSLTTextMarker
) {
4422 * --------------------------------------------------------
4428 * Mark the xsl:text element for later deletion.
4434 tmp
= cur
->children
;
4437 * We don't expect more than one text-node in the
4438 * content, since we already merged adjacent
4439 * text/CDATA-nodes and eliminated PI/comment-nodes.
4441 if ((tmp
->type
== XML_TEXT_NODE
) ||
4442 (tmp
->next
== NULL
))
4445 * Leave the contained text-node in the tree.
4448 xmlAddPrevSibling(cur
, tmp
);
4451 xsltTransformError(NULL
, cctxt
->style
, cur
,
4452 "Element 'xsl:text': Invalid type "
4453 "of node found in content.\n");
4454 cctxt
->style
->errors
++;
4457 if (cur
->properties
) {
4460 * TODO: We need to report errors for
4463 attr
= cur
->properties
;
4465 if ((attr
->ns
== NULL
) &&
4466 (attr
->name
!= NULL
) &&
4467 (attr
->name
[0] == 'd') &&
4468 xmlStrEqual(attr
->name
,
4469 BAD_CAST
"disable-output-escaping"))
4472 * Attr "disable-output-escaping".
4473 * XSLT-2: This attribute is deprecated.
4475 if ((attr
->children
!= NULL
) &&
4476 xmlStrEqual(attr
->children
->content
,
4480 * Disable output escaping for this
4484 tmp
->name
= xmlStringTextNoenc
;
4485 } else if ((attr
->children
== NULL
) ||
4486 (attr
->children
->content
== NULL
) ||
4487 (!xmlStrEqual(attr
->children
->content
,
4490 xsltTransformError(NULL
, cctxt
->style
,
4492 "Attribute 'disable-output-escaping': "
4493 "Invalid value. Expected is "
4494 "'yes' or 'no'.\n");
4495 cctxt
->style
->errors
++;
4500 } while (attr
!= NULL
);
4502 } else if (IS_XSLT_ELEM_FAST(cur
)) {
4504 * TODO: Using the XSLT-marker is still not stable yet.
4506 /* if (cur->psvi == xsltXSLTElemMarker) { */
4509 * --------------------------------------------------------
4512 type
= xsltGetXSLTElementTypeByNode(cctxt
, cur
);
4514 case XSLT_FUNC_APPLYIMPORTS
:
4515 case XSLT_FUNC_APPLYTEMPLATES
:
4516 case XSLT_FUNC_ATTRIBUTE
:
4517 case XSLT_FUNC_CALLTEMPLATE
:
4518 case XSLT_FUNC_CHOOSE
:
4519 case XSLT_FUNC_COMMENT
:
4520 case XSLT_FUNC_COPY
:
4521 case XSLT_FUNC_COPYOF
:
4522 case XSLT_FUNC_DOCUMENT
: /* Extra one */
4523 case XSLT_FUNC_ELEMENT
:
4524 case XSLT_FUNC_FALLBACK
:
4525 case XSLT_FUNC_FOREACH
:
4527 case XSLT_FUNC_MESSAGE
:
4528 case XSLT_FUNC_NUMBER
:
4530 case XSLT_FUNC_TEXT
:
4531 case XSLT_FUNC_VALUEOF
:
4532 case XSLT_FUNC_VARIABLE
:
4534 * Parse the XSLT element.
4536 cctxt
->inode
->curChildType
= type
;
4537 xsltParseAnyXSLTElem(cctxt
, cur
);
4540 xsltParseUnknownXSLTElem(cctxt
, cur
);
4549 xsltCompilerNodePush(cctxt
, cur
);
4551 * Update the in-scope namespaces if needed.
4553 if (cur
->nsDef
!= NULL
)
4554 cctxt
->inode
->inScopeNs
=
4555 xsltCompilerBuildInScopeNsList(cctxt
, cur
);
4557 * The current element is either a literal result element
4558 * or an extension instruction.
4560 * Process attr "xsl:extension-element-prefixes".
4561 * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
4562 * processed by the implementor of the extension function;
4563 * i.e., it won't be handled by the XSLT processor.
4566 * "exclude-result-prefixes" is only allowed on literal
4567 * result elements and "xsl:exclude-result-prefixes"
4568 * on xsl:stylesheet/xsl:transform.
4570 * "There are a number of standard attributes
4571 * that may appear on any XSLT element: specifically
4572 * version, exclude-result-prefixes,
4573 * extension-element-prefixes, xpath-default-namespace,
4574 * default-collation, and use-when."
4577 * For literal result elements:
4578 * "xsl:version, xsl:exclude-result-prefixes,
4579 * xsl:extension-element-prefixes,
4580 * xsl:xpath-default-namespace,
4581 * xsl:default-collation, or xsl:use-when."
4583 if (cur
->properties
)
4584 cctxt
->inode
->extElemNs
=
4585 xsltParseExtElemPrefixes(cctxt
,
4586 cur
, cctxt
->inode
->extElemNs
,
4587 XSLT_ELEMENT_CATEGORY_LRE
);
4589 * Eval if we have an extension instruction here.
4591 if ((cur
->ns
!= NULL
) &&
4592 (cctxt
->inode
->extElemNs
!= NULL
) &&
4593 (xsltCheckExtPrefix(cctxt
->style
, cur
->ns
->href
) == 1))
4596 * Extension instructions
4597 * ----------------------------------------------------
4598 * Mark the node information.
4600 cctxt
->inode
->category
= XSLT_ELEMENT_CATEGORY_EXTENSION
;
4601 cctxt
->inode
->extContentHandled
= 0;
4602 if (cur
->psvi
!= NULL
) {
4605 * TODO: Temporary sanity check.
4607 xsltTransformError(NULL
, cctxt
->style
, cur
,
4608 "Internal error in xsltParseSequenceConstructor(): "
4609 "Occupied PSVI field.\n");
4610 cctxt
->style
->errors
++;
4614 cur
->psvi
= (void *)
4615 xsltPreComputeExtModuleElement(cctxt
->style
, cur
);
4617 if (cur
->psvi
== NULL
) {
4619 * OLD COMMENT: "Unknown element, maybe registered
4620 * at the context level. Mark it for later
4622 * QUESTION: What does the xsltExtMarker mean?
4623 * ANSWER: It is used in
4624 * xsltApplySequenceConstructor() at
4625 * transformation-time to look out for extension
4626 * registered in the transformation context.
4628 cur
->psvi
= (void *) xsltExtMarker
;
4631 * BIG NOTE: Now the ugly part. In previous versions
4632 * of Libxslt (until 1.1.16), all the content of an
4633 * extension instruction was processed and compiled without
4634 * the need of the extension-author to explicitely call
4635 * such a processing;.We now need to mimic this old
4636 * behaviour in order to avoid breaking old code
4637 * on the extension-author's side.
4639 * 1) If the author does *not* set the
4640 * compile-time-flag @extContentHandled, then we'll
4641 * parse the content assuming that it's a "template"
4642 * (or "sequence constructor in XSLT 2.0 terms).
4643 * NOTE: If the extension is registered at
4644 * transformation-time only, then there's no way of
4645 * knowing that content shall be valid, and we'll
4646 * process the content the same way.
4647 * 2) If the author *does* set the flag, then we'll assume
4648 * that the author has handled the parsing him/herself
4649 * (e.g. called xsltParseSequenceConstructor(), etc.
4650 * explicitely in his/her code).
4652 if ((cur
->children
!= NULL
) &&
4653 (cctxt
->inode
->extContentHandled
== 0))
4656 * Default parsing of the content using the
4657 * sequence-constructor model.
4659 xsltParseSequenceConstructor(cctxt
, cur
->children
);
4663 * Literal result element
4664 * ----------------------------------------------------
4665 * Allowed XSLT attributes:
4666 * xsl:extension-element-prefixes CDATA #IMPLIED
4667 * xsl:exclude-result-prefixes CDATA #IMPLIED
4668 * TODO: xsl:use-attribute-sets %qnames; #IMPLIED
4669 * xsl:version NMTOKEN #IMPLIED
4672 cctxt
->inode
->category
= XSLT_ELEMENT_CATEGORY_LRE
;
4673 if (cur
->properties
!= NULL
) {
4674 xmlAttrPtr attr
= cur
->properties
;
4676 * Attribute "xsl:exclude-result-prefixes".
4678 cctxt
->inode
->exclResultNs
=
4679 xsltParseExclResultPrefixes(cctxt
, cur
,
4680 cctxt
->inode
->exclResultNs
,
4681 XSLT_ELEMENT_CATEGORY_LRE
);
4683 * Attribute "xsl:version".
4685 xsltParseAttrXSLTVersion(cctxt
, cur
,
4686 XSLT_ELEMENT_CATEGORY_LRE
);
4688 * Report invalid XSLT attributes.
4689 * For XSLT 1.0 only xsl:use-attribute-sets is allowed
4690 * next to xsl:version, xsl:exclude-result-prefixes and
4691 * xsl:extension-element-prefixes.
4693 * Mark all XSLT attributes, in order to skip such
4694 * attributes when instantiating the LRE.
4697 if ((attr
->psvi
!= xsltXSLTAttrMarker
) &&
4698 IS_XSLT_ATTR_FAST(attr
))
4700 if (! xmlStrEqual(attr
->name
,
4701 BAD_CAST
"use-attribute-sets"))
4703 xsltTransformError(NULL
, cctxt
->style
,
4705 "Unknown XSLT attribute '%s'.\n",
4707 cctxt
->style
->errors
++;
4712 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
4716 } while (attr
!= NULL
);
4719 * Create/reuse info for the literal result element.
4721 if (cctxt
->inode
->nsChanged
)
4722 xsltLREInfoCreate(cctxt
, cur
, 1);
4723 cur
->psvi
= cctxt
->inode
->litResElemInfo
;
4725 * Apply ns-aliasing on the element and on its attributes.
4727 if (cctxt
->hasNsAliases
)
4728 xsltLREBuildEffectiveNs(cctxt
, cur
);
4730 * Compile attribute value templates (AVT).
4732 if (cur
->properties
) {
4733 xmlAttrPtr attr
= cur
->properties
;
4735 while (attr
!= NULL
) {
4736 xsltCompileAttr(cctxt
->style
, attr
);
4741 * Parse the content, which is defined to be a "template"
4742 * (or "sequence constructor" in XSLT 2.0 terms).
4744 if (cur
->children
!= NULL
) {
4745 xsltParseSequenceConstructor(cctxt
, cur
->children
);
4749 * Leave the non-XSLT element.
4751 xsltCompilerNodePop(cctxt
, cur
);
4756 if (deleteNode
!= NULL
) {
4757 #ifdef WITH_XSLT_DEBUG_BLANKS
4758 xsltGenericDebug(xsltGenericDebugContext
,
4759 "xsltParseSequenceConstructor: removing xsl:text element\n");
4761 xmlUnlinkNode(deleteNode
);
4762 xmlFreeNode(deleteNode
);
4768 * xsltParseTemplateContent:
4769 * @style: the XSLT stylesheet
4770 * @templ: the node containing the content to be parsed
4772 * Parses and compiles the content-model of an xsl:template element.
4773 * Note that this is *not* the "template" content model (or "sequence
4774 * constructor" in XSLT 2.0); it it allows addional xsl:param
4775 * elements as immediate children of @templ.
4778 * exsltFuncFunctionComp() (EXSLT, functions.c)
4779 * So this is intended to be called from extension functions.
4782 xsltParseTemplateContent(xsltStylesheetPtr style
, xmlNodePtr templ
) {
4783 if ((style
== NULL
) || (templ
== NULL
))
4787 * Detection of handled content of extension instructions.
4789 if (XSLT_CCTXT(style
)->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4790 XSLT_CCTXT(style
)->inode
->extContentHandled
= 1;
4793 if (templ
->children
!= NULL
) {
4794 xmlNodePtr child
= templ
->children
;
4796 * Process xsl:param elements, which can only occur as the
4797 * immediate children of xsl:template (well, and of any
4798 * user-defined extension instruction if needed).
4801 if ((child
->type
== XML_ELEMENT_NODE
) &&
4802 IS_XSLT_ELEM_FAST(child
) &&
4803 IS_XSLT_NAME(child
, "param"))
4805 XSLT_CCTXT(style
)->inode
->curChildType
= XSLT_FUNC_PARAM
;
4806 xsltParseAnyXSLTElem(XSLT_CCTXT(style
), child
);
4809 child
= child
->next
;
4810 } while (child
!= NULL
);
4812 * Parse the content and register the pattern.
4814 xsltParseSequenceConstructor(XSLT_CCTXT(style
), child
);
4818 #else /* XSLT_REFACTORED */
4821 * xsltParseTemplateContent:
4822 * @style: the XSLT stylesheet
4823 * @templ: the container node (can be a document for literal results)
4825 * parse a template content-model
4826 * Clean-up the template content from unwanted ignorable blank nodes
4827 * and process xslt:text
4830 xsltParseTemplateContent(xsltStylesheetPtr style
, xmlNodePtr templ
) {
4831 xmlNodePtr cur
, delete;
4833 * This content comes from the stylesheet
4834 * For stylesheets, the set of whitespace-preserving
4835 * element names consists of just xsl:text.
4837 cur
= templ
->children
;
4839 while (cur
!= NULL
) {
4840 if (delete != NULL
) {
4841 #ifdef WITH_XSLT_DEBUG_BLANKS
4842 xsltGenericDebug(xsltGenericDebugContext
,
4843 "xsltParseTemplateContent: removing text\n");
4845 xmlUnlinkNode(delete);
4846 xmlFreeNode(delete);
4849 if (IS_XSLT_ELEM(cur
)) {
4850 if (IS_XSLT_NAME(cur
, "text")) {
4852 * TODO: Processing of xsl:text should be moved to
4853 * xsltPrecomputeStylesheet(), since otherwise this
4854 * will be performed for every multiply included
4855 * stylesheet; i.e. this here is not skipped with
4856 * the use of the style->nopreproc flag.
4858 if (cur
->children
!= NULL
) {
4860 xmlNodePtr text
= cur
->children
, next
;
4863 prop
= xmlGetNsProp(cur
,
4864 (const xmlChar
*)"disable-output-escaping",
4867 #ifdef WITH_XSLT_DEBUG_PARSING
4868 xsltGenericDebug(xsltGenericDebugContext
,
4869 "Disable escaping: %s\n", text
->content
);
4871 if (xmlStrEqual(prop
, (const xmlChar
*)"yes")) {
4873 } else if (!xmlStrEqual(prop
,
4874 (const xmlChar
*)"no")){
4875 xsltTransformError(NULL
, style
, cur
,
4876 "xsl:text: disable-output-escaping allows only yes or no\n");
4883 while (text
!= NULL
) {
4884 if (text
->type
== XML_COMMENT_NODE
) {
4888 if ((text
->type
!= XML_TEXT_NODE
) &&
4889 (text
->type
!= XML_CDATA_SECTION_NODE
)) {
4890 xsltTransformError(NULL
, style
, cur
,
4891 "xsltParseTemplateContent: xslt:text content problem\n");
4895 if ((noesc
) && (text
->type
!= XML_CDATA_SECTION_NODE
))
4896 text
->name
= xmlStringTextNoenc
;
4901 * replace xsl:text by the list of childs
4904 text
= cur
->children
;
4905 while (text
!= NULL
) {
4906 if ((style
->internalized
) &&
4907 (text
->content
!= NULL
) &&
4908 (!xmlDictOwns(style
->dict
, text
->content
))) {
4911 * internalize the text string
4913 if (text
->doc
->dict
!= NULL
) {
4916 tmp
= xmlDictLookup(text
->doc
->dict
,
4918 if (tmp
!= text
->content
) {
4919 xmlNodeSetContent(text
, NULL
);
4920 text
->content
= (xmlChar
*) tmp
;
4926 xmlUnlinkNode(text
);
4927 xmlAddPrevSibling(cur
, text
);
4936 else if ((cur
->ns
!= NULL
) && (style
->nsDefs
!= NULL
) &&
4937 (xsltCheckExtPrefix(style
, cur
->ns
->prefix
)))
4940 * okay this is an extension element compile it too
4942 xsltStylePreCompute(style
, cur
);
4944 else if (cur
->type
== XML_ELEMENT_NODE
)
4947 * This is an element which will be output as part of the
4948 * template exectution, precompile AVT if found.
4950 if ((cur
->ns
== NULL
) && (style
->defaultAlias
!= NULL
)) {
4951 cur
->ns
= xmlSearchNsByHref(cur
->doc
, cur
,
4952 style
->defaultAlias
);
4954 if (cur
->properties
!= NULL
) {
4955 xmlAttrPtr attr
= cur
->properties
;
4957 while (attr
!= NULL
) {
4958 xsltCompileAttr(style
, attr
);
4966 if (cur
->children
!= NULL
) {
4967 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
4968 cur
= cur
->children
;
4973 if (cur
->next
!= NULL
) {
4986 if (cur
->next
!= NULL
) {
4990 } while (cur
!= NULL
);
4992 if (delete != NULL
) {
4993 #ifdef WITH_XSLT_DEBUG_PARSING
4994 xsltGenericDebug(xsltGenericDebugContext
,
4995 "xsltParseTemplateContent: removing text\n");
4997 xmlUnlinkNode(delete);
4998 xmlFreeNode(delete);
5003 * Skip the first params
5005 cur
= templ
->children
;
5006 while (cur
!= NULL
) {
5007 if ((IS_XSLT_ELEM(cur
)) && (!(IS_XSLT_NAME(cur
, "param"))))
5013 * Browse the remainder of the template
5015 while (cur
!= NULL
) {
5016 if ((IS_XSLT_ELEM(cur
)) && (IS_XSLT_NAME(cur
, "param"))) {
5017 xmlNodePtr param
= cur
;
5019 xsltTransformError(NULL
, style
, cur
,
5020 "xsltParseTemplateContent: ignoring misplaced param element\n");
5021 if (style
!= NULL
) style
->warnings
++;
5023 xmlUnlinkNode(param
);
5030 #endif /* else XSLT_REFACTORED */
5033 * xsltParseStylesheetKey:
5034 * @style: the XSLT stylesheet
5035 * @key: the "key" element
5037 * <!-- Category: top-level-element -->
5038 * <xsl:key name = qname, match = pattern, use = expression />
5040 * parse an XSLT stylesheet key definition and register it
5044 xsltParseStylesheetKey(xsltStylesheetPtr style
, xmlNodePtr key
) {
5045 xmlChar
*prop
= NULL
;
5046 xmlChar
*use
= NULL
;
5047 xmlChar
*match
= NULL
;
5048 xmlChar
*name
= NULL
;
5049 xmlChar
*nameURI
= NULL
;
5051 if ((style
== NULL
) || (key
== NULL
))
5057 prop
= xmlGetNsProp(key
, (const xmlChar
*)"name", NULL
);
5062 * TODO: Don't use xsltGetQNameURI().
5064 URI
= xsltGetQNameURI(key
, &prop
);
5066 if (style
!= NULL
) style
->errors
++;
5071 nameURI
= xmlStrdup(URI
);
5073 #ifdef WITH_XSLT_DEBUG_PARSING
5074 xsltGenericDebug(xsltGenericDebugContext
,
5075 "xsltParseStylesheetKey: name %s\n", name
);
5078 xsltTransformError(NULL
, style
, key
,
5079 "xsl:key : error missing name\n");
5080 if (style
!= NULL
) style
->errors
++;
5084 match
= xmlGetNsProp(key
, (const xmlChar
*)"match", NULL
);
5085 if (match
== NULL
) {
5086 xsltTransformError(NULL
, style
, key
,
5087 "xsl:key : error missing match\n");
5088 if (style
!= NULL
) style
->errors
++;
5092 use
= xmlGetNsProp(key
, (const xmlChar
*)"use", NULL
);
5094 xsltTransformError(NULL
, style
, key
,
5095 "xsl:key : error missing use\n");
5096 if (style
!= NULL
) style
->errors
++;
5103 xsltAddKey(style
, name
, nameURI
, match
, use
, key
);
5113 if (nameURI
!= NULL
)
5116 if (key
->children
!= NULL
) {
5117 xsltParseContentError(style
, key
->children
);
5121 #ifdef XSLT_REFACTORED
5123 * xsltParseXSLTTemplate:
5124 * @style: the XSLT stylesheet
5125 * @template: the "template" element
5127 * parse an XSLT stylesheet template building the associated structures
5128 * TODO: Is @style ever expected to be NULL?
5131 * xsltParseXSLTStylesheet()
5132 * xsltParseStylesheetTop()
5136 xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt
, xmlNodePtr templNode
) {
5137 xsltTemplatePtr templ
;
5141 if ((cctxt
== NULL
) || (templNode
== NULL
))
5145 * Create and link the structure
5147 templ
= xsltNewTemplate();
5151 xsltCompilerNodePush(cctxt
, templNode
);
5152 if (templNode
->nsDef
!= NULL
)
5153 cctxt
->inode
->inScopeNs
=
5154 xsltCompilerBuildInScopeNsList(cctxt
, templNode
);
5156 templ
->next
= cctxt
->style
->templates
;
5157 cctxt
->style
->templates
= templ
;
5158 templ
->style
= cctxt
->style
;
5163 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"mode", NULL
);
5165 const xmlChar
*modeURI
;
5168 * TODO: We need a standardized function for extraction
5169 * of namespace names and local names from QNames.
5170 * Don't use xsltGetQNameURI() as it cannot channeö
5171 * reports through the context.
5173 modeURI
= xsltGetQNameURI(templNode
, &prop
);
5175 cctxt
->style
->errors
++;
5178 templ
->mode
= xmlDictLookup(cctxt
->style
->dict
, prop
, -1);
5181 if (xmlValidateNCName(templ
->mode
, 0)) {
5182 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5183 "xsl:template: Attribute 'mode': The local part '%s' "
5184 "of the value is not a valid NCName.\n", templ
->name
);
5185 cctxt
->style
->errors
++;
5188 if (modeURI
!= NULL
)
5189 templ
->modeURI
= xmlDictLookup(cctxt
->style
->dict
, modeURI
, -1);
5190 #ifdef WITH_XSLT_DEBUG_PARSING
5191 xsltGenericDebug(xsltGenericDebugContext
,
5192 "xsltParseXSLTTemplate: mode %s\n", templ
->mode
);
5196 * Attribute "match".
5198 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"match", NULL
);
5200 templ
->match
= prop
;
5204 * Attribute "priority".
5206 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"priority", NULL
);
5208 priority
= xmlXPathStringEvalNumber(prop
);
5209 templ
->priority
= (float) priority
;
5216 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"name", NULL
);
5218 const xmlChar
*nameURI
;
5219 xsltTemplatePtr curTempl
;
5222 * TODO: Don't use xsltGetQNameURI().
5224 nameURI
= xsltGetQNameURI(templNode
, &prop
);
5226 cctxt
->style
->errors
++;
5229 templ
->name
= xmlDictLookup(cctxt
->style
->dict
, prop
, -1);
5232 if (xmlValidateNCName(templ
->name
, 0)) {
5233 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5234 "xsl:template: Attribute 'name': The local part '%s' of "
5235 "the value is not a valid NCName.\n", templ
->name
);
5236 cctxt
->style
->errors
++;
5239 if (nameURI
!= NULL
)
5240 templ
->nameURI
= xmlDictLookup(cctxt
->style
->dict
, nameURI
, -1);
5241 curTempl
= templ
->next
;
5242 while (curTempl
!= NULL
) {
5243 if ((nameURI
!= NULL
&& xmlStrEqual(curTempl
->name
, templ
->name
) &&
5244 xmlStrEqual(curTempl
->nameURI
, nameURI
) ) ||
5245 (nameURI
== NULL
&& curTempl
->nameURI
== NULL
&&
5246 xmlStrEqual(curTempl
->name
, templ
->name
)))
5248 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5249 "xsl:template: error duplicate name '%s'\n", templ
->name
);
5250 cctxt
->style
->errors
++;
5253 curTempl
= curTempl
->next
;
5256 if (templNode
->children
!= NULL
) {
5257 xsltParseTemplateContent(cctxt
->style
, templNode
);
5259 * MAYBE TODO: Custom behaviour: In order to stay compatible with
5260 * Xalan and MSXML(.NET), we could allow whitespace
5261 * to appear before an xml:param element; this whitespace
5262 * will additionally become part of the "template".
5263 * NOTE that this is totally deviates from the spec, but
5264 * is the de facto behaviour of Xalan and MSXML(.NET).
5265 * Personally I wouldn't allow this, since if we have:
5266 * <xsl:template ...xml:space="preserve">
5267 * <xsl:param name="foo"/>
5268 * <xsl:param name="bar"/>
5269 * <xsl:param name="zoo"/>
5270 * ... the whitespace between every xsl:param would be
5271 * added to the result tree.
5275 templ
->elem
= templNode
;
5276 templ
->content
= templNode
->children
;
5277 xsltAddTemplate(cctxt
->style
, templ
, templ
->mode
, templ
->modeURI
);
5280 xsltCompilerNodePop(cctxt
, templNode
);
5284 #else /* XSLT_REFACTORED */
5287 * xsltParseStylesheetTemplate:
5288 * @style: the XSLT stylesheet
5289 * @template: the "template" element
5291 * parse an XSLT stylesheet template building the associated structures
5295 xsltParseStylesheetTemplate(xsltStylesheetPtr style
, xmlNodePtr
template) {
5296 xsltTemplatePtr ret
;
5298 xmlChar
*mode
= NULL
;
5299 xmlChar
*modeURI
= NULL
;
5302 if (template == NULL
)
5306 * Create and link the structure
5308 ret
= xsltNewTemplate();
5311 ret
->next
= style
->templates
;
5312 style
->templates
= ret
;
5316 * Get inherited namespaces
5319 * TODO: Apply the optimized in-scope-namespace mechanism
5320 * as for the other XSLT instructions.
5322 xsltGetInheritedNsList(style
, ret
, template);
5327 prop
= xmlGetNsProp(template, (const xmlChar
*)"mode", NULL
);
5332 * TODO: Don't use xsltGetQNameURI().
5334 URI
= xsltGetQNameURI(template, &prop
);
5336 if (style
!= NULL
) style
->errors
++;
5341 modeURI
= xmlStrdup(URI
);
5343 ret
->mode
= xmlDictLookup(style
->dict
, mode
, -1);
5344 ret
->modeURI
= xmlDictLookup(style
->dict
, modeURI
, -1);
5345 #ifdef WITH_XSLT_DEBUG_PARSING
5346 xsltGenericDebug(xsltGenericDebugContext
,
5347 "xsltParseStylesheetTemplate: mode %s\n", mode
);
5349 if (mode
!= NULL
) xmlFree(mode
);
5350 if (modeURI
!= NULL
) xmlFree(modeURI
);
5352 prop
= xmlGetNsProp(template, (const xmlChar
*)"match", NULL
);
5354 if (ret
->match
!= NULL
) xmlFree(ret
->match
);
5358 prop
= xmlGetNsProp(template, (const xmlChar
*)"priority", NULL
);
5360 priority
= xmlXPathStringEvalNumber(prop
);
5361 ret
->priority
= (float) priority
;
5365 prop
= xmlGetNsProp(template, (const xmlChar
*)"name", NULL
);
5368 xsltTemplatePtr cur
;
5371 * TODO: Don't use xsltGetQNameURI().
5373 URI
= xsltGetQNameURI(template, &prop
);
5375 if (style
!= NULL
) style
->errors
++;
5378 if (xmlValidateNCName(prop
,0)) {
5379 xsltTransformError(NULL
, style
, template,
5380 "xsl:template : error invalid name '%s'\n", prop
);
5381 if (style
!= NULL
) style
->errors
++;
5384 ret
->name
= xmlDictLookup(style
->dict
, BAD_CAST prop
, -1);
5388 ret
->nameURI
= xmlDictLookup(style
->dict
, BAD_CAST URI
, -1);
5390 ret
->nameURI
= NULL
;
5392 while (cur
!= NULL
) {
5393 if ((URI
!= NULL
&& xmlStrEqual(cur
->name
, ret
->name
) &&
5394 xmlStrEqual(cur
->nameURI
, URI
) ) ||
5395 (URI
== NULL
&& cur
->nameURI
== NULL
&&
5396 xmlStrEqual(cur
->name
, ret
->name
))) {
5397 xsltTransformError(NULL
, style
, template,
5398 "xsl:template: error duplicate name '%s'\n", ret
->name
);
5408 * parse the content and register the pattern
5410 xsltParseTemplateContent(style
, template);
5411 ret
->elem
= template;
5412 ret
->content
= template->children
;
5413 xsltAddTemplate(style
, ret
, ret
->mode
, ret
->modeURI
);
5419 #endif /* else XSLT_REFACTORED */
5421 #ifdef XSLT_REFACTORED
5425 * @cctxt: the compilation contenxt
5426 * @node: the xsl:include node
5428 * Process the xslt include node on the source node
5430 static xsltStyleItemIncludePtr
5431 xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
) {
5432 xsltStyleItemIncludePtr item
;
5434 if ((cctxt
== NULL
) || (node
== NULL
))
5438 item
= (xsltStyleItemIncludePtr
) xmlMalloc(sizeof(xsltStyleItemInclude
));
5440 xsltTransformError(NULL
, cctxt
->style
, node
,
5441 "xsltIncludeComp : malloc failed\n");
5442 cctxt
->style
->errors
++;
5445 memset(item
, 0, sizeof(xsltStyleItemInclude
));
5449 item
->type
= XSLT_FUNC_INCLUDE
;
5451 item
->next
= cctxt
->style
->preComps
;
5452 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
5458 * xsltParseFindTopLevelElem:
5461 xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt
,
5463 const xmlChar
*name
,
5464 const xmlChar
*namespaceURI
,
5465 int breakOnOtherElem
,
5466 xmlNodePtr
*resultNode
)
5472 while (cur
!= NULL
) {
5473 if (cur
->type
== XML_ELEMENT_NODE
) {
5474 if ((cur
->ns
!= NULL
) && (cur
->name
!= NULL
)) {
5475 if ((*(cur
->name
) == *name
) &&
5476 xmlStrEqual(cur
->name
, name
) &&
5477 xmlStrEqual(cur
->ns
->href
, namespaceURI
))
5483 if (breakOnOtherElem
)
5493 xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt
,
5500 * TODO: The reason why this function exists:
5501 * due to historical reasons some of the
5502 * top-level declarations are processed by functions
5503 * in other files. Since we need still to set
5504 * up the node-info and generate information like
5505 * in-scope namespaces, this is a wrapper around
5506 * those old parsing functions.
5508 xsltCompilerNodePush(cctxt
, node
);
5509 if (node
->nsDef
!= NULL
)
5510 cctxt
->inode
->inScopeNs
=
5511 xsltCompilerBuildInScopeNsList(cctxt
, node
);
5512 cctxt
->inode
->type
= type
;
5515 case XSLT_FUNC_INCLUDE
:
5519 if (xsltCompileXSLTIncludeElem(cctxt
, node
) == NULL
)
5522 * Mark this stylesheet tree as being currently included.
5524 oldIsInclude
= cctxt
->isInclude
;
5525 cctxt
->isInclude
= 1;
5527 if (xsltParseStylesheetInclude(cctxt
->style
, node
) != 0) {
5528 cctxt
->style
->errors
++;
5530 cctxt
->isInclude
= oldIsInclude
;
5533 case XSLT_FUNC_PARAM
:
5534 xsltStylePreCompute(cctxt
->style
, node
);
5535 xsltParseGlobalParam(cctxt
->style
, node
);
5537 case XSLT_FUNC_VARIABLE
:
5538 xsltStylePreCompute(cctxt
->style
, node
);
5539 xsltParseGlobalVariable(cctxt
->style
, node
);
5541 case XSLT_FUNC_ATTRSET
:
5542 xsltParseStylesheetAttributeSet(cctxt
->style
, node
);
5545 xsltTransformError(NULL
, cctxt
->style
, node
,
5546 "Internal error: (xsltParseTopLevelXSLTElem) "
5547 "Cannot handle this top-level declaration.\n");
5548 cctxt
->style
->errors
++;
5553 xsltCompilerNodePop(cctxt
, node
);
5560 xsltParseRemoveWhitespace(xmlNodePtr node
)
5562 if ((node
== NULL
) || (node
->children
== NULL
))
5565 xmlNodePtr delNode
= NULL
, child
= node
->children
;
5569 xmlUnlinkNode(delNode
);
5570 xmlFreeNode(delNode
);
5573 if (((child
->type
== XML_TEXT_NODE
) ||
5574 (child
->type
== XML_CDATA_SECTION_NODE
)) &&
5575 (IS_BLANK_NODE(child
)))
5577 child
= child
->next
;
5578 } while (child
!= NULL
);
5580 xmlUnlinkNode(delNode
);
5581 xmlFreeNode(delNode
);
5590 xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
5592 #ifdef WITH_XSLT_DEBUG_PARSING
5595 xmlNodePtr cur
, start
= NULL
;
5596 xsltStylesheetPtr style
;
5598 if ((cctxt
== NULL
) || (node
== NULL
) ||
5599 (node
->type
!= XML_ELEMENT_NODE
))
5602 style
= cctxt
->style
;
5604 * At this stage all import declarations of all stylesheet modules
5605 * with the same stylesheet level have been processed.
5606 * Now we can safely parse the rest of the declarations.
5608 if (IS_XSLT_ELEM_FAST(node
) && IS_XSLT_NAME(node
, "include"))
5610 xsltDocumentPtr include
;
5612 * URGENT TODO: Make this work with simplified stylesheets!
5613 * I.e., when we won't find an xsl:stylesheet element.
5616 * This is as include declaration.
5618 include
= ((xsltStyleItemIncludePtr
) node
->psvi
)->include
;
5619 if (include
== NULL
) {
5620 /* TODO: raise error? */
5624 * TODO: Actually an xsl:include should locate an embedded
5625 * stylesheet as well; so the document-element won't always
5626 * be the element where the actual stylesheet is rooted at.
5627 * But such embedded stylesheets are not supported by Libxslt yet.
5629 node
= xmlDocGetRootElement(include
->doc
);
5635 if (node
->children
== NULL
)
5638 * Push the xsl:stylesheet/xsl:transform element.
5640 xsltCompilerNodePush(cctxt
, node
);
5641 cctxt
->inode
->isRoot
= 1;
5642 cctxt
->inode
->nsChanged
= 0;
5644 * Start with the naked dummy info for literal result elements.
5646 cctxt
->inode
->litResElemInfo
= cctxt
->inodeList
->litResElemInfo
;
5649 * In every case, we need to have
5650 * the in-scope namespaces of the element, where the
5651 * stylesheet is rooted at, regardless if it's an XSLT
5652 * instruction or a literal result instruction (or if
5653 * this is an embedded stylesheet).
5655 cctxt
->inode
->inScopeNs
=
5656 xsltCompilerBuildInScopeNsList(cctxt
, node
);
5659 * Process attributes of xsl:stylesheet/xsl:transform.
5660 * --------------------------------------------------
5663 * extension-element-prefixes = tokens
5664 * exclude-result-prefixes = tokens
5665 * version = number (mandatory)
5667 if (xsltParseAttrXSLTVersion(cctxt
, node
,
5668 XSLT_ELEMENT_CATEGORY_XSLT
) == 0)
5671 * Attribute "version".
5672 * XSLT 1.0: "An xsl:stylesheet element *must* have a version
5673 * attribute, indicating the version of XSLT that the
5674 * stylesheet requires".
5675 * The root element of a simplified stylesheet must also have
5678 #ifdef XSLT_REFACTORED_MANDATORY_VERSION
5680 xsltTransformError(NULL
, cctxt
->style
, node
,
5681 "The attribute 'version' is missing.\n");
5682 cctxt
->style
->errors
++;
5684 /* OLD behaviour. */
5685 xsltTransformError(NULL
, cctxt
->style
, node
,
5686 "xsl:version is missing: document may not be a stylesheet\n");
5687 cctxt
->style
->warnings
++;
5691 * The namespaces declared by the attributes
5692 * "extension-element-prefixes" and
5693 * "exclude-result-prefixes" are local to *this*
5694 * stylesheet tree; i.e., they are *not* visible to
5695 * other stylesheet-modules, whether imported or included.
5697 * Attribute "extension-element-prefixes".
5699 cctxt
->inode
->extElemNs
=
5700 xsltParseExtElemPrefixes(cctxt
, node
, NULL
,
5701 XSLT_ELEMENT_CATEGORY_XSLT
);
5703 * Attribute "exclude-result-prefixes".
5705 cctxt
->inode
->exclResultNs
=
5706 xsltParseExclResultPrefixes(cctxt
, node
, NULL
,
5707 XSLT_ELEMENT_CATEGORY_XSLT
);
5709 * Create/reuse info for the literal result element.
5711 if (cctxt
->inode
->nsChanged
)
5712 xsltLREInfoCreate(cctxt
, node
, 0);
5714 * Processed top-level elements:
5715 * ----------------------------
5716 * xsl:variable, xsl:param (QName, in-scope ns,
5717 * expression (vars allowed))
5718 * xsl:attribute-set (QName, in-scope ns)
5719 * xsl:strip-space, xsl:preserve-space (XPath NameTests,
5721 * I *think* global scope, merge with includes
5722 * xsl:output (QName, in-scope ns)
5723 * xsl:key (QName, in-scope ns, pattern,
5724 * expression (vars *not* allowed))
5725 * xsl:decimal-format (QName, needs in-scope ns)
5726 * xsl:namespace-alias (in-scope ns)
5727 * global scope, merge with includes
5728 * xsl:template (last, QName, pattern)
5730 * (whitespace-only text-nodes have *not* been removed
5731 * yet; this will be done in xsltParseSequenceConstructor)
5733 * Report misplaced child-nodes first.
5735 cur
= node
->children
;
5736 while (cur
!= NULL
) {
5737 if (cur
->type
== XML_TEXT_NODE
) {
5738 xsltTransformError(NULL
, style
, cur
,
5739 "Misplaced text node (content: '%s').\n",
5740 (cur
->content
!= NULL
) ? cur
->content
: BAD_CAST
"");
5742 } else if (cur
->type
!= XML_ELEMENT_NODE
) {
5743 xsltTransformError(NULL
, style
, cur
, "Misplaced node.\n");
5749 * Skip xsl:import elements; they have been processed
5752 cur
= node
->children
;
5753 while ((cur
!= NULL
) && xsltParseFindTopLevelElem(cctxt
, cur
,
5754 BAD_CAST
"import", XSLT_NAMESPACE
, 1, &cur
) == 1)
5761 * Process all top-level xsl:param elements.
5763 while ((cur
!= NULL
) &&
5764 xsltParseFindTopLevelElem(cctxt
, cur
,
5765 BAD_CAST
"param", XSLT_NAMESPACE
, 0, &cur
) == 1)
5767 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_PARAM
);
5771 * Process all top-level xsl:variable elements.
5774 while ((cur
!= NULL
) &&
5775 xsltParseFindTopLevelElem(cctxt
, cur
,
5776 BAD_CAST
"variable", XSLT_NAMESPACE
, 0, &cur
) == 1)
5778 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_VARIABLE
);
5782 * Process all the rest of top-level elements.
5785 while (cur
!= NULL
) {
5787 * Process element nodes.
5789 if (cur
->type
== XML_ELEMENT_NODE
) {
5790 if (cur
->ns
== NULL
) {
5791 xsltTransformError(NULL
, style
, cur
,
5792 "Unexpected top-level element in no namespace.\n");
5798 * Process all XSLT elements.
5800 if (IS_XSLT_ELEM_FAST(cur
)) {
5802 * xsl:import is only allowed at the beginning.
5804 if (IS_XSLT_NAME(cur
, "import")) {
5805 xsltTransformError(NULL
, style
, cur
,
5806 "Misplaced xsl:import element.\n");
5812 * TODO: Change the return type of the parsing functions
5815 if (IS_XSLT_NAME(cur
, "template")) {
5816 #ifdef WITH_XSLT_DEBUG_PARSING
5820 * TODO: Is the position of xsl:template in the
5821 * tree significant? If not it would be easier to
5822 * parse them at a later stage.
5824 xsltParseXSLTTemplate(cctxt
, cur
);
5825 } else if (IS_XSLT_NAME(cur
, "variable")) {
5826 /* NOP; done already */
5827 } else if (IS_XSLT_NAME(cur
, "param")) {
5828 /* NOP; done already */
5829 } else if (IS_XSLT_NAME(cur
, "include")) {
5830 if (cur
->psvi
!= NULL
)
5831 xsltParseXSLTStylesheetElemCore(cctxt
, cur
);
5833 xsltTransformError(NULL
, style
, cur
,
5835 "(xsltParseXSLTStylesheetElemCore) "
5836 "The xsl:include element was not compiled.\n");
5839 } else if (IS_XSLT_NAME(cur
, "strip-space")) {
5840 /* No node info needed. */
5841 xsltParseStylesheetStripSpace(style
, cur
);
5842 } else if (IS_XSLT_NAME(cur
, "preserve-space")) {
5843 /* No node info needed. */
5844 xsltParseStylesheetPreserveSpace(style
, cur
);
5845 } else if (IS_XSLT_NAME(cur
, "output")) {
5846 /* No node-info needed. */
5847 xsltParseStylesheetOutput(style
, cur
);
5848 } else if (IS_XSLT_NAME(cur
, "key")) {
5849 /* TODO: node-info needed for expressions ? */
5850 xsltParseStylesheetKey(style
, cur
);
5851 } else if (IS_XSLT_NAME(cur
, "decimal-format")) {
5852 /* No node-info needed. */
5853 xsltParseStylesheetDecimalFormat(style
, cur
);
5854 } else if (IS_XSLT_NAME(cur
, "attribute-set")) {
5855 xsltParseTopLevelXSLTElem(cctxt
, cur
,
5857 } else if (IS_XSLT_NAME(cur
, "namespace-alias")) {
5858 /* NOP; done already */
5860 if (cctxt
->inode
->forwardsCompat
) {
5862 * Forwards-compatible mode:
5864 * XSLT-1: "if it is a top-level element and
5865 * XSLT 1.0 does not allow such elements as top-level
5866 * elements, then the element must be ignored along
5867 * with its content;"
5870 * TODO: I don't think we should generate a warning.
5872 xsltTransformError(NULL
, style
, cur
,
5873 "Forwards-compatible mode: Ignoring unknown XSLT "
5874 "element '%s'.\n", cur
->name
);
5877 xsltTransformError(NULL
, style
, cur
,
5878 "Unknown XSLT element '%s'.\n", cur
->name
);
5883 xsltTopLevelFunction function
;
5886 * Process non-XSLT elements, which are in a
5887 * non-NULL namespace.
5890 * QUESTION: What does xsltExtModuleTopLevelLookup()
5893 function
= xsltExtModuleTopLevelLookup(cur
->name
,
5895 if (function
!= NULL
)
5896 function(style
, cur
);
5897 #ifdef WITH_XSLT_DEBUG_PARSING
5898 xsltGenericDebug(xsltGenericDebugContext
,
5899 "xsltParseXSLTStylesheetElemCore : User-defined "
5900 "data element '%s'.\n", cur
->name
);
5909 #ifdef WITH_XSLT_DEBUG_PARSING
5910 xsltGenericDebug(xsltGenericDebugContext
,
5911 "### END of parsing top-level elements of doc '%s'.\n",
5913 xsltGenericDebug(xsltGenericDebugContext
,
5914 "### Templates: %d\n", templates
);
5915 #ifdef XSLT_REFACTORED
5916 xsltGenericDebug(xsltGenericDebugContext
,
5917 "### Max inodes: %d\n", cctxt
->maxNodeInfos
);
5918 xsltGenericDebug(xsltGenericDebugContext
,
5919 "### Max LREs : %d\n", cctxt
->maxLREs
);
5920 #endif /* XSLT_REFACTORED */
5921 #endif /* WITH_XSLT_DEBUG_PARSING */
5923 xsltCompilerNodePop(cctxt
, node
);
5928 * xsltParseXSLTStylesheet:
5929 * @cctxt: the compiler context
5930 * @node: the xsl:stylesheet/xsl:transform element-node
5932 * Parses the xsl:stylesheet and xsl:transform element.
5936 * extension-element-prefixes = tokens
5937 * exclude-result-prefixes = tokens
5939 * <!-- Content: (xsl:import*, top-level-elements) -->
5942 * BIG TODO: The xsl:include stuff.
5944 * Called by xsltParseStylesheetTree()
5946 * Returns 0 on success, a positive result on errors and
5947 * -1 on API or internal errors.
5950 xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
5952 xmlNodePtr cur
, start
;
5954 if ((cctxt
== NULL
) || (node
== NULL
))
5957 if (node
->children
== NULL
)
5961 * Process top-level elements:
5962 * xsl:import (must be first)
5963 * xsl:include (this is just a pre-processing)
5965 cur
= node
->children
;
5967 * Process xsl:import elements.
5968 * XSLT 1.0: "The xsl:import element children must precede all
5969 * other element children of an xsl:stylesheet element,
5970 * including any xsl:include element children."
5972 while ((cur
!= NULL
) &&
5973 xsltParseFindTopLevelElem(cctxt
, cur
,
5974 BAD_CAST
"import", XSLT_NAMESPACE
, 1, &cur
) == 1)
5976 if (xsltParseStylesheetImport(cctxt
->style
, cur
) != 0) {
5977 cctxt
->style
->errors
++;
5985 * Pre-process all xsl:include elements.
5988 while ((cur
!= NULL
) &&
5989 xsltParseFindTopLevelElem(cctxt
, cur
,
5990 BAD_CAST
"include", XSLT_NAMESPACE
, 0, &cur
) == 1)
5992 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_INCLUDE
);
5996 * Pre-process all xsl:namespace-alias elements.
5997 * URGENT TODO: This won't work correctly: the order of included
5998 * aliases and aliases defined here is significant.
6001 while ((cur
!= NULL
) &&
6002 xsltParseFindTopLevelElem(cctxt
, cur
,
6003 BAD_CAST
"namespace-alias", XSLT_NAMESPACE
, 0, &cur
) == 1)
6005 xsltNamespaceAlias(cctxt
->style
, cur
);
6009 if (cctxt
->isInclude
) {
6011 * If this stylesheet is intended for inclusion, then
6012 * we will process only imports and includes.
6017 * Now parse the rest of the top-level elements.
6019 xsltParseXSLTStylesheetElemCore(cctxt
, node
);
6025 #else /* XSLT_REFACTORED */
6028 * xsltParseStylesheetTop:
6029 * @style: the XSLT stylesheet
6030 * @top: the top level "stylesheet" or "transform" element
6032 * scan the top level elements of an XSL stylesheet
6035 xsltParseStylesheetTop(xsltStylesheetPtr style
, xmlNodePtr top
) {
6038 #ifdef WITH_XSLT_DEBUG_PARSING
6045 prop
= xmlGetNsProp(top
, (const xmlChar
*)"version", NULL
);
6047 xsltTransformError(NULL
, style
, top
,
6048 "xsl:version is missing: document may not be a stylesheet\n");
6049 if (style
!= NULL
) style
->warnings
++;
6051 if ((!xmlStrEqual(prop
, (const xmlChar
*)"1.0")) &&
6052 (!xmlStrEqual(prop
, (const xmlChar
*)"1.1"))) {
6053 xsltTransformError(NULL
, style
, top
,
6054 "xsl:version: only 1.0 features are supported\n");
6055 /* TODO set up compatibility when not XSLT 1.0 */
6056 if (style
!= NULL
) style
->warnings
++;
6062 * process xsl:import elements
6064 cur
= top
->children
;
6065 while (cur
!= NULL
) {
6066 if (IS_BLANK_NODE(cur
)) {
6070 if (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "import")) {
6071 if (xsltParseStylesheetImport(style
, cur
) != 0)
6072 if (style
!= NULL
) style
->errors
++;
6079 * process other top-level elements
6081 while (cur
!= NULL
) {
6082 if (IS_BLANK_NODE(cur
)) {
6086 if (cur
->type
== XML_TEXT_NODE
) {
6087 if (cur
->content
!= NULL
) {
6088 xsltTransformError(NULL
, style
, cur
,
6089 "misplaced text node: '%s'\n", cur
->content
);
6091 if (style
!= NULL
) style
->errors
++;
6095 if ((cur
->type
== XML_ELEMENT_NODE
) && (cur
->ns
== NULL
)) {
6096 xsltGenericError(xsltGenericErrorContext
,
6097 "Found a top-level element %s with null namespace URI\n",
6099 if (style
!= NULL
) style
->errors
++;
6103 if ((cur
->type
== XML_ELEMENT_NODE
) && (!(IS_XSLT_ELEM(cur
)))) {
6104 xsltTopLevelFunction function
;
6106 function
= xsltExtModuleTopLevelLookup(cur
->name
,
6108 if (function
!= NULL
)
6109 function(style
, cur
);
6111 #ifdef WITH_XSLT_DEBUG_PARSING
6112 xsltGenericDebug(xsltGenericDebugContext
,
6113 "xsltParseStylesheetTop : found foreign element %s\n",
6119 if (IS_XSLT_NAME(cur
, "import")) {
6120 xsltTransformError(NULL
, style
, cur
,
6121 "xsltParseStylesheetTop: ignoring misplaced import element\n");
6122 if (style
!= NULL
) style
->errors
++;
6123 } else if (IS_XSLT_NAME(cur
, "include")) {
6124 if (xsltParseStylesheetInclude(style
, cur
) != 0)
6125 if (style
!= NULL
) style
->errors
++;
6126 } else if (IS_XSLT_NAME(cur
, "strip-space")) {
6127 xsltParseStylesheetStripSpace(style
, cur
);
6128 } else if (IS_XSLT_NAME(cur
, "preserve-space")) {
6129 xsltParseStylesheetPreserveSpace(style
, cur
);
6130 } else if (IS_XSLT_NAME(cur
, "output")) {
6131 xsltParseStylesheetOutput(style
, cur
);
6132 } else if (IS_XSLT_NAME(cur
, "key")) {
6133 xsltParseStylesheetKey(style
, cur
);
6134 } else if (IS_XSLT_NAME(cur
, "decimal-format")) {
6135 xsltParseStylesheetDecimalFormat(style
, cur
);
6136 } else if (IS_XSLT_NAME(cur
, "attribute-set")) {
6137 xsltParseStylesheetAttributeSet(style
, cur
);
6138 } else if (IS_XSLT_NAME(cur
, "variable")) {
6139 xsltParseGlobalVariable(style
, cur
);
6140 } else if (IS_XSLT_NAME(cur
, "param")) {
6141 xsltParseGlobalParam(style
, cur
);
6142 } else if (IS_XSLT_NAME(cur
, "template")) {
6143 #ifdef WITH_XSLT_DEBUG_PARSING
6146 xsltParseStylesheetTemplate(style
, cur
);
6147 } else if (IS_XSLT_NAME(cur
, "namespace-alias")) {
6148 xsltNamespaceAlias(style
, cur
);
6151 * BUG TODO: The version of the *doc* is irrelevant for
6152 * the forwards-compatible mode.
6154 if ((style
!= NULL
) && (style
->doc
->version
!= NULL
) &&
6155 (!strncmp((const char *) style
->doc
->version
, "1.0", 3))) {
6156 xsltTransformError(NULL
, style
, cur
,
6157 "xsltParseStylesheetTop: unknown %s element\n",
6159 if (style
!= NULL
) style
->errors
++;
6162 /* do Forwards-Compatible Processing */
6163 xsltTransformError(NULL
, style
, cur
,
6164 "xsltParseStylesheetTop: ignoring unknown %s element\n",
6166 if (style
!= NULL
) style
->warnings
++;
6171 #ifdef WITH_XSLT_DEBUG_PARSING
6172 xsltGenericDebug(xsltGenericDebugContext
,
6173 "parsed %d templates\n", templates
);
6177 #endif /* else of XSLT_REFACTORED */
6179 #ifdef XSLT_REFACTORED
6181 * xsltParseSimplifiedStylesheetTree:
6183 * @style: the stylesheet (TODO: Change this to the compiler context)
6184 * @doc: the document containing the stylesheet.
6185 * @node: the node where the stylesheet is rooted at
6187 * Returns 0 in case of success, a positive result if an error occurred
6188 * and -1 on API and internal errors.
6191 xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt
,
6195 xsltTemplatePtr templ
;
6197 if ((cctxt
== NULL
) || (node
== NULL
))
6200 if (xsltParseAttrXSLTVersion(cctxt
, node
, 0) == XSLT_ELEMENT_CATEGORY_LRE
)
6203 * TODO: Adjust report, since this might be an
6204 * embedded stylesheet.
6206 xsltTransformError(NULL
, cctxt
->style
, node
,
6207 "The attribute 'xsl:version' is missing; cannot identify "
6208 "this document as an XSLT stylesheet document.\n");
6209 cctxt
->style
->errors
++;
6213 #ifdef WITH_XSLT_DEBUG_PARSING
6214 xsltGenericDebug(xsltGenericDebugContext
,
6215 "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
6219 * Create and link the template
6221 templ
= xsltNewTemplate();
6222 if (templ
== NULL
) {
6225 templ
->next
= cctxt
->style
->templates
;
6226 cctxt
->style
->templates
= templ
;
6227 templ
->match
= xmlStrdup(BAD_CAST
"/");
6230 * Note that we push the document-node in this special case.
6232 xsltCompilerNodePush(cctxt
, (xmlNodePtr
) doc
);
6234 * In every case, we need to have
6235 * the in-scope namespaces of the element, where the
6236 * stylesheet is rooted at, regardless if it's an XSLT
6237 * instruction or a literal result instruction (or if
6238 * this is an embedded stylesheet).
6240 cctxt
->inode
->inScopeNs
=
6241 xsltCompilerBuildInScopeNsList(cctxt
, node
);
6243 * Parse the content and register the match-pattern.
6245 xsltParseSequenceConstructor(cctxt
, node
);
6246 xsltCompilerNodePop(cctxt
, (xmlNodePtr
) doc
);
6248 templ
->elem
= (xmlNodePtr
) doc
;
6249 templ
->content
= node
;
6250 xsltAddTemplate(cctxt
->style
, templ
, NULL
, NULL
);
6251 cctxt
->style
->literal_result
= 1;
6255 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6257 * xsltRestoreDocumentNamespaces:
6258 * @ns: map of namespaces
6259 * @doc: the document
6261 * Restore the namespaces for the document
6263 * Returns 0 in case of success, -1 in case of failure
6266 xsltRestoreDocumentNamespaces(xsltNsMapPtr ns
, xmlDocPtr doc
)
6271 * Revert the changes we have applied to the namespace-URIs of
6274 while (ns
!= NULL
) {
6275 if ((ns
->doc
== doc
) && (ns
->ns
!= NULL
)) {
6276 ns
->ns
->href
= ns
->origNsName
;
6277 ns
->origNsName
= NULL
;
6284 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
6287 * xsltParseStylesheetProcess:
6288 * @style: the XSLT stylesheet (the current stylesheet-level)
6289 * @doc: and xmlDoc parsed XML
6291 * Parses an XSLT stylesheet, adding the associated structures.
6293 * xsltParseStylesheetImportedDoc() (xslt.c)
6294 * xsltParseStylesheetInclude() (imports.c)
6296 * Returns the value of the @style parameter if everything
6297 * went right, NULL if something went amiss.
6300 xsltParseStylesheetProcess(xsltStylesheetPtr style
, xmlDocPtr doc
)
6302 xsltCompilerCtxtPtr cctxt
;
6304 int oldIsSimplifiedStylesheet
;
6308 if ((style
== NULL
) || (doc
== NULL
))
6311 cctxt
= XSLT_CCTXT(style
);
6313 cur
= xmlDocGetRootElement(doc
);
6315 xsltTransformError(NULL
, style
, (xmlNodePtr
) doc
,
6316 "xsltParseStylesheetProcess : empty stylesheet\n");
6319 oldIsSimplifiedStylesheet
= cctxt
->simplified
;
6321 if ((IS_XSLT_ELEM(cur
)) &&
6322 ((IS_XSLT_NAME(cur
, "stylesheet")) ||
6323 (IS_XSLT_NAME(cur
, "transform")))) {
6324 #ifdef WITH_XSLT_DEBUG_PARSING
6325 xsltGenericDebug(xsltGenericDebugContext
,
6326 "xsltParseStylesheetProcess : found stylesheet\n");
6328 cctxt
->simplified
= 0;
6329 style
->literal_result
= 0;
6331 cctxt
->simplified
= 1;
6332 style
->literal_result
= 1;
6335 * Pre-process the stylesheet if not already done before.
6336 * This will remove PIs and comments, merge adjacent
6337 * text nodes, internalize strings, etc.
6339 if (! style
->nopreproc
)
6340 xsltParsePreprocessStylesheetTree(cctxt
, cur
);
6342 * Parse and compile the stylesheet.
6344 if (style
->literal_result
== 0) {
6345 if (xsltParseXSLTStylesheetElem(cctxt
, cur
) != 0)
6348 if (xsltParseSimplifiedStylesheetTree(cctxt
, doc
, cur
) != 0)
6352 cctxt
->simplified
= oldIsSimplifiedStylesheet
;
6357 #else /* XSLT_REFACTORED */
6360 * xsltParseStylesheetProcess:
6361 * @ret: the XSLT stylesheet (the current stylesheet-level)
6362 * @doc: and xmlDoc parsed XML
6364 * Parses an XSLT stylesheet, adding the associated structures.
6366 * xsltParseStylesheetImportedDoc() (xslt.c)
6367 * xsltParseStylesheetInclude() (imports.c)
6369 * Returns the value of the @style parameter if everything
6370 * went right, NULL if something went amiss.
6373 xsltParseStylesheetProcess(xsltStylesheetPtr ret
, xmlDocPtr doc
) {
6384 * First steps, remove blank nodes,
6385 * locate the xsl:stylesheet element and the
6386 * namespace declaration.
6388 cur
= xmlDocGetRootElement(doc
);
6390 xsltTransformError(NULL
, ret
, (xmlNodePtr
) doc
,
6391 "xsltParseStylesheetProcess : empty stylesheet\n");
6395 if ((IS_XSLT_ELEM(cur
)) &&
6396 ((IS_XSLT_NAME(cur
, "stylesheet")) ||
6397 (IS_XSLT_NAME(cur
, "transform")))) {
6398 #ifdef WITH_XSLT_DEBUG_PARSING
6399 xsltGenericDebug(xsltGenericDebugContext
,
6400 "xsltParseStylesheetProcess : found stylesheet\n");
6402 ret
->literal_result
= 0;
6403 xsltParseStylesheetExcludePrefix(ret
, cur
, 1);
6404 xsltParseStylesheetExtPrefix(ret
, cur
, 1);
6406 xsltParseStylesheetExcludePrefix(ret
, cur
, 0);
6407 xsltParseStylesheetExtPrefix(ret
, cur
, 0);
6408 ret
->literal_result
= 1;
6410 if (!ret
->nopreproc
) {
6411 xsltPrecomputeStylesheet(ret
, cur
);
6413 if (ret
->literal_result
== 0) {
6414 xsltParseStylesheetTop(ret
, cur
);
6417 xsltTemplatePtr
template;
6420 * the document itself might be the template, check xsl:version
6422 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"version", XSLT_NAMESPACE
);
6424 xsltTransformError(NULL
, ret
, cur
,
6425 "xsltParseStylesheetProcess : document is not a stylesheet\n");
6429 #ifdef WITH_XSLT_DEBUG_PARSING
6430 xsltGenericDebug(xsltGenericDebugContext
,
6431 "xsltParseStylesheetProcess : document is stylesheet\n");
6434 if (!xmlStrEqual(prop
, (const xmlChar
*)"1.0")) {
6435 xsltTransformError(NULL
, ret
, cur
,
6436 "xsl:version: only 1.0 features are supported\n");
6437 /* TODO set up compatibility when not XSLT 1.0 */
6443 * Create and link the template
6445 template = xsltNewTemplate();
6446 if (template == NULL
) {
6449 template->next
= ret
->templates
;
6450 ret
->templates
= template;
6451 template->match
= xmlStrdup((const xmlChar
*)"/");
6454 * parse the content and register the pattern
6456 xsltParseTemplateContent(ret
, (xmlNodePtr
) doc
);
6457 template->elem
= (xmlNodePtr
) doc
;
6458 template->content
= doc
->children
;
6459 xsltAddTemplate(ret
, template, NULL
, NULL
);
6460 ret
->literal_result
= 1;
6466 #endif /* else of XSLT_REFACTORED */
6469 * xsltParseStylesheetImportedDoc:
6470 * @doc: an xmlDoc parsed XML
6471 * @parentStyle: pointer to the parent stylesheet (if it exists)
6473 * parse an XSLT stylesheet building the associated structures
6474 * except the processing not needed for imported documents.
6476 * Returns a new XSLT stylesheet structure.
6480 xsltParseStylesheetImportedDoc(xmlDocPtr doc
,
6481 xsltStylesheetPtr parentStyle
) {
6482 xsltStylesheetPtr retStyle
;
6487 retStyle
= xsltNewStylesheet();
6488 if (retStyle
== NULL
)
6491 * Set the importing stylesheet module; also used to detect recursion.
6493 retStyle
->parent
= parentStyle
;
6495 * Adjust the string dict.
6497 if (doc
->dict
!= NULL
) {
6498 xmlDictFree(retStyle
->dict
);
6499 retStyle
->dict
= doc
->dict
;
6500 #ifdef WITH_XSLT_DEBUG
6501 xsltGenericDebug(xsltGenericDebugContext
,
6502 "reusing dictionary from %s for stylesheet\n",
6505 xmlDictReference(retStyle
->dict
);
6509 * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
6510 * the stylesheet to containt distinct namespace prefixes.
6512 xsltGatherNamespaces(retStyle
);
6514 #ifdef XSLT_REFACTORED
6516 xsltCompilerCtxtPtr cctxt
;
6517 xsltStylesheetPtr oldCurSheet
;
6519 if (parentStyle
== NULL
) {
6520 xsltPrincipalStylesheetDataPtr principalData
;
6522 * Principal stylesheet
6523 * --------------------
6525 retStyle
->principal
= retStyle
;
6527 * Create extra data for the principal stylesheet.
6529 principalData
= xsltNewPrincipalStylesheetData();
6530 if (principalData
== NULL
) {
6531 xsltFreeStylesheet(retStyle
);
6534 retStyle
->principalData
= principalData
;
6536 * Create the compilation context
6537 * ------------------------------
6538 * (only once; for the principal stylesheet).
6539 * This is currently the only function where the
6540 * compilation context is created.
6542 cctxt
= xsltCompilationCtxtCreate(retStyle
);
6543 if (cctxt
== NULL
) {
6544 xsltFreeStylesheet(retStyle
);
6547 retStyle
->compCtxt
= (void *) cctxt
;
6548 cctxt
->style
= retStyle
;
6549 cctxt
->dict
= retStyle
->dict
;
6550 cctxt
->psData
= principalData
;
6552 * Push initial dummy node info.
6555 xsltCompilerNodePush(cctxt
, (xmlNodePtr
) doc
);
6558 * Imported stylesheet.
6560 retStyle
->principal
= parentStyle
->principal
;
6561 cctxt
= parentStyle
->compCtxt
;
6562 retStyle
->compCtxt
= cctxt
;
6565 * Save the old and set the current stylesheet structure in the
6566 * compilation context.
6568 oldCurSheet
= cctxt
->style
;
6569 cctxt
->style
= retStyle
;
6571 retStyle
->doc
= doc
;
6572 xsltParseStylesheetProcess(retStyle
, doc
);
6574 cctxt
->style
= oldCurSheet
;
6575 if (parentStyle
== NULL
) {
6577 * Pop the initial dummy node info.
6579 xsltCompilerNodePop(cctxt
, (xmlNodePtr
) doc
);
6582 * Clear the compilation context of imported
6586 /* retStyle->compCtxt = NULL; */
6589 * Free the stylesheet if there were errors.
6591 if (retStyle
!= NULL
) {
6592 if (retStyle
->errors
!= 0) {
6593 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6595 * Restore all changes made to namespace URIs of ns-decls.
6597 if (cctxt
->psData
->nsMap
)
6598 xsltRestoreDocumentNamespaces(cctxt
->psData
->nsMap
, doc
);
6601 * Detach the doc from the stylesheet; otherwise the doc
6602 * will be freed in xsltFreeStylesheet().
6604 retStyle
->doc
= NULL
;
6606 * Cleanup the doc if its the main stylesheet.
6608 if (parentStyle
== NULL
) {
6609 xsltCleanupStylesheetTree(doc
, xmlDocGetRootElement(doc
));
6610 if (retStyle
->compCtxt
!= NULL
) {
6611 xsltCompilationCtxtFree(retStyle
->compCtxt
);
6612 retStyle
->compCtxt
= NULL
;
6616 xsltFreeStylesheet(retStyle
);
6622 #else /* XSLT_REFACTORED */
6626 retStyle
->doc
= doc
;
6627 if (xsltParseStylesheetProcess(retStyle
, doc
) == NULL
) {
6628 retStyle
->doc
= NULL
;
6629 xsltFreeStylesheet(retStyle
);
6632 if (retStyle
!= NULL
) {
6633 if (retStyle
->errors
!= 0) {
6634 retStyle
->doc
= NULL
;
6635 if (parentStyle
== NULL
)
6636 xsltCleanupStylesheetTree(doc
,
6637 xmlDocGetRootElement(doc
));
6638 xsltFreeStylesheet(retStyle
);
6642 #endif /* else of XSLT_REFACTORED */
6648 * xsltParseStylesheetDoc:
6649 * @doc: and xmlDoc parsed XML
6651 * parse an XSLT stylesheet, building the associated structures. doc
6652 * is kept as a reference within the returned stylesheet, so changes
6653 * to doc after the parsing will be reflected when the stylesheet
6654 * is applied, and the doc is automatically freed when the
6655 * stylesheet is closed.
6657 * Returns a new XSLT stylesheet structure.
6661 xsltParseStylesheetDoc(xmlDocPtr doc
) {
6662 xsltStylesheetPtr ret
;
6666 ret
= xsltParseStylesheetImportedDoc(doc
, NULL
);
6670 xsltResolveStylesheetAttributeSet(ret
);
6671 #ifdef XSLT_REFACTORED
6673 * Free the compilation context.
6674 * TODO: Check if it's better to move this cleanup to
6675 * xsltParseStylesheetImportedDoc().
6677 if (ret
->compCtxt
!= NULL
) {
6678 xsltCompilationCtxtFree(XSLT_CCTXT(ret
));
6679 ret
->compCtxt
= NULL
;
6686 * xsltParseStylesheetFile:
6687 * @filename: the filename/URL to the stylesheet
6689 * Load and parse an XSLT stylesheet
6691 * Returns a new XSLT stylesheet structure.
6695 xsltParseStylesheetFile(const xmlChar
* filename
) {
6696 xsltSecurityPrefsPtr sec
;
6697 xsltStylesheetPtr ret
;
6702 if (filename
== NULL
)
6705 #ifdef WITH_XSLT_DEBUG_PARSING
6706 xsltGenericDebug(xsltGenericDebugContext
,
6707 "xsltParseStylesheetFile : parse %s\n", filename
);
6711 * Security framework check
6713 sec
= xsltGetDefaultSecurityPrefs();
6717 res
= xsltCheckRead(sec
, NULL
, filename
);
6719 xsltTransformError(NULL
, NULL
, NULL
,
6720 "xsltParseStylesheetFile: read rights for %s denied\n",
6726 doc
= xsltDocDefaultLoader(filename
, NULL
, XSLT_PARSE_OPTIONS
,
6727 NULL
, XSLT_LOAD_START
);
6729 xsltTransformError(NULL
, NULL
, NULL
,
6730 "xsltParseStylesheetFile : cannot parse %s\n", filename
);
6733 ret
= xsltParseStylesheetDoc(doc
);
6742 /************************************************************************
6744 * Handling of Stylesheet PI *
6746 ************************************************************************/
6749 #define SKIP(val) cur += (val)
6750 #define NXT(val) cur[(val)]
6751 #define SKIP_BLANKS \
6752 while (IS_BLANK(CUR)) NEXT
6753 #define NEXT ((*cur) ? cur++ : cur)
6756 * xsltParseStylesheetPI:
6757 * @value: the value of the PI
6759 * This function checks that the type is text/xml and extracts
6760 * the URI-Reference for the stylesheet
6762 * Returns the URI-Reference for the stylesheet or NULL (it need to
6763 * be freed by the caller)
6766 xsltParseStylesheetPI(const xmlChar
*value
) {
6768 const xmlChar
*start
;
6771 xmlChar
*href
= NULL
;
6780 if ((CUR
== 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
6787 if ((CUR
!= '\'') && (CUR
!= '"'))
6792 while ((CUR
!= 0) && (CUR
!= tmp
))
6796 val
= xmlStrndup(start
, cur
- start
);
6800 if ((xmlStrcasecmp(val
, BAD_CAST
"text/xml")) &&
6801 (xmlStrcasecmp(val
, BAD_CAST
"text/xsl"))) {
6807 } else if ((CUR
== 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
6814 if ((CUR
!= '\'') && (CUR
!= '"'))
6819 while ((CUR
!= 0) && (CUR
!= tmp
))
6824 href
= xmlStrndup(start
, cur
- start
);
6827 while ((CUR
!= 0) && (!IS_BLANK(CUR
)))
6842 * xsltLoadStylesheetPI:
6843 * @doc: a document to process
6845 * This function tries to locate the stylesheet PI in the given document
6846 * If found, and if contained within the document, it will extract
6847 * that subtree to build the stylesheet to process @doc (doc itself will
6848 * be modified). If found but referencing an external document it will
6849 * attempt to load it and generate a stylesheet from it. In both cases,
6850 * the resulting stylesheet and the document need to be freed once the
6851 * transformation is done.
6853 * Returns a new XSLT stylesheet structure or NULL if not found.
6856 xsltLoadStylesheetPI(xmlDocPtr doc
) {
6858 xsltStylesheetPtr ret
= NULL
;
6859 xmlChar
*href
= NULL
;
6868 * Find the text/xml stylesheet PI id any before the root
6870 child
= doc
->children
;
6871 while ((child
!= NULL
) && (child
->type
!= XML_ELEMENT_NODE
)) {
6872 if ((child
->type
== XML_PI_NODE
) &&
6873 (xmlStrEqual(child
->name
, BAD_CAST
"xml-stylesheet"))) {
6874 href
= xsltParseStylesheetPI(child
->content
);
6878 child
= child
->next
;
6882 * If found check the href to select processing
6885 #ifdef WITH_XSLT_DEBUG_PARSING
6886 xsltGenericDebug(xsltGenericDebugContext
,
6887 "xsltLoadStylesheetPI : found PI href=%s\n", href
);
6889 URI
= xmlParseURI((const char *) href
);
6891 xsltTransformError(NULL
, NULL
, child
,
6892 "xml-stylesheet : href %s is not valid\n", href
);
6896 if ((URI
->fragment
!= NULL
) && (URI
->scheme
== NULL
) &&
6897 (URI
->opaque
== NULL
) && (URI
->authority
== NULL
) &&
6898 (URI
->server
== NULL
) && (URI
->user
== NULL
) &&
6899 (URI
->path
== NULL
) && (URI
->query
== NULL
)) {
6902 #ifdef WITH_XSLT_DEBUG_PARSING
6903 xsltGenericDebug(xsltGenericDebugContext
,
6904 "xsltLoadStylesheetPI : Reference to ID %s\n", href
);
6906 if (URI
->fragment
[0] == '#')
6907 ID
= xmlGetID(doc
, (const xmlChar
*) &(URI
->fragment
[1]));
6909 ID
= xmlGetID(doc
, (const xmlChar
*) URI
->fragment
);
6911 xsltTransformError(NULL
, NULL
, child
,
6912 "xml-stylesheet : no ID %s found\n", URI
->fragment
);
6915 xmlNodePtr subtree
, newtree
;
6918 #ifdef WITH_XSLT_DEBUG
6919 xsltGenericDebug(xsltGenericDebugContext
,
6920 "creating new document from %s for embedded stylesheet\n",
6924 * move the subtree in a new document passed to
6925 * the stylesheet analyzer
6927 subtree
= ID
->parent
;
6928 fake
= xmlNewDoc(NULL
);
6931 * Should the dictionary still be shared even though
6932 * the nodes are being copied rather than moved?
6934 fake
->dict
= doc
->dict
;
6935 xmlDictReference(doc
->dict
);
6936 #ifdef WITH_XSLT_DEBUG
6937 xsltGenericDebug(xsltGenericDebugContext
,
6938 "reusing dictionary from %s for embedded stylesheet\n",
6942 newtree
= xmlDocCopyNode(subtree
, fake
, 1);
6944 fake
->URL
= xmlNodeGetBase(doc
, subtree
->parent
);
6945 #ifdef WITH_XSLT_DEBUG
6946 xsltGenericDebug(xsltGenericDebugContext
,
6947 "set base URI for embedded stylesheet as %s\n",
6952 * Add all namespaces in scope of embedded stylesheet to
6953 * root element of newly created stylesheet document
6955 while ((subtree
= subtree
->parent
) != (xmlNodePtr
)doc
) {
6956 for (ns
= subtree
->ns
; ns
; ns
= ns
->next
) {
6957 xmlNewNs(newtree
, ns
->href
, ns
->prefix
);
6961 xmlAddChild((xmlNodePtr
)fake
, newtree
);
6962 ret
= xsltParseStylesheetDoc(fake
);
6968 xmlChar
*URL
, *base
;
6971 * Reference to an external stylesheet
6974 base
= xmlNodeGetBase(doc
, (xmlNodePtr
) doc
);
6975 URL
= xmlBuildURI(href
, base
);
6977 #ifdef WITH_XSLT_DEBUG_PARSING
6978 xsltGenericDebug(xsltGenericDebugContext
,
6979 "xsltLoadStylesheetPI : fetching %s\n", URL
);
6981 ret
= xsltParseStylesheetFile(URL
);
6984 #ifdef WITH_XSLT_DEBUG_PARSING
6985 xsltGenericDebug(xsltGenericDebugContext
,
6986 "xsltLoadStylesheetPI : fetching %s\n", href
);
6988 ret
= xsltParseStylesheetFile(href
);