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.
246 #ifdef XSLT_LOCALE_WINAPI
247 xmlFreeRMutex(xsltLocaleMutex
);
248 xsltLocaleMutex
= NULL
;
257 * Check if a string is ignorable
259 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
262 xsltIsBlank(xmlChar
*str
) {
266 if (!(IS_BLANK(*str
))) return(0);
272 /************************************************************************
274 * Routines to handle XSLT data structures *
276 ************************************************************************/
277 static xsltDecimalFormatPtr
278 xsltNewDecimalFormat(xmlChar
*name
)
280 xsltDecimalFormatPtr self
;
281 /* UTF-8 for 0x2030 */
282 static const xmlChar permille
[4] = {0xe2, 0x80, 0xb0, 0};
284 self
= xmlMalloc(sizeof(xsltDecimalFormat
));
290 self
->digit
= xmlStrdup(BAD_CAST("#"));
291 self
->patternSeparator
= xmlStrdup(BAD_CAST(";"));
292 self
->decimalPoint
= xmlStrdup(BAD_CAST("."));
293 self
->grouping
= xmlStrdup(BAD_CAST(","));
294 self
->percent
= xmlStrdup(BAD_CAST("%"));
295 self
->permille
= xmlStrdup(BAD_CAST(permille
));
296 self
->zeroDigit
= xmlStrdup(BAD_CAST("0"));
297 self
->minusSign
= xmlStrdup(BAD_CAST("-"));
298 self
->infinity
= xmlStrdup(BAD_CAST("Infinity"));
299 self
->noNumber
= xmlStrdup(BAD_CAST("NaN"));
305 xsltFreeDecimalFormat(xsltDecimalFormatPtr self
)
309 xmlFree(self
->digit
);
310 if (self
->patternSeparator
)
311 xmlFree(self
->patternSeparator
);
312 if (self
->decimalPoint
)
313 xmlFree(self
->decimalPoint
);
315 xmlFree(self
->grouping
);
317 xmlFree(self
->percent
);
319 xmlFree(self
->permille
);
321 xmlFree(self
->zeroDigit
);
323 xmlFree(self
->minusSign
);
325 xmlFree(self
->infinity
);
327 xmlFree(self
->noNumber
);
335 xsltFreeDecimalFormatList(xsltStylesheetPtr self
)
337 xsltDecimalFormatPtr iter
;
338 xsltDecimalFormatPtr tmp
;
343 iter
= self
->decimalFormat
;
344 while (iter
!= NULL
) {
346 xsltFreeDecimalFormat(iter
);
352 * xsltDecimalFormatGetByName:
353 * @style: the XSLT stylesheet
354 * @name: the decimal-format name to find
356 * Find decimal-format by name
358 * Returns the xsltDecimalFormatPtr
361 xsltDecimalFormatGetByName(xsltStylesheetPtr style
, xmlChar
*name
)
363 xsltDecimalFormatPtr result
= NULL
;
366 return style
->decimalFormat
;
368 while (style
!= NULL
) {
369 for (result
= style
->decimalFormat
->next
;
371 result
= result
->next
) {
372 if (xmlStrEqual(name
, result
->name
))
375 style
= xsltNextImport(style
);
384 * Create a new XSLT Template
386 * Returns the newly allocated xsltTemplatePtr or NULL in case of error
388 static xsltTemplatePtr
389 xsltNewTemplate(void) {
392 cur
= (xsltTemplatePtr
) xmlMalloc(sizeof(xsltTemplate
));
394 xsltTransformError(NULL
, NULL
, NULL
,
395 "xsltNewTemplate : malloc failed\n");
398 memset(cur
, 0, sizeof(xsltTemplate
));
399 cur
->priority
= XSLT_PAT_NO_PRIORITY
;
405 * @template: an XSLT template
407 * Free up the memory allocated by @template
410 xsltFreeTemplate(xsltTemplatePtr
template) {
411 if (template == NULL
)
413 if (template->match
) xmlFree(template->match
);
415 * NOTE: @name and @nameURI are put into the string dict now.
416 * if (template->name) xmlFree(template->name);
417 * if (template->nameURI) xmlFree(template->nameURI);
420 if (template->mode) xmlFree(template->mode);
421 if (template->modeURI) xmlFree(template->modeURI);
423 if (template->inheritedNs
) xmlFree(template->inheritedNs
);
425 /* free profiling data */
426 if (template->templCalledTab
) xmlFree(template->templCalledTab
);
427 if (template->templCountTab
) xmlFree(template->templCountTab
);
429 memset(template, -1, sizeof(xsltTemplate
));
434 * xsltFreeTemplateList:
435 * @template: an XSLT template list
437 * Free up the memory allocated by all the elements of @template
440 xsltFreeTemplateList(xsltTemplatePtr
template) {
443 while (template != NULL
) {
445 template = template->next
;
446 xsltFreeTemplate(cur
);
450 #ifdef XSLT_REFACTORED
453 xsltFreeNsAliasList(xsltNsAliasPtr item
)
465 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
467 xsltFreeNamespaceMap(xsltNsMapPtr item
)
480 xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt
,
487 if ((cctxt
== NULL
) || (doc
== NULL
) || (ns
== NULL
))
490 ret
= (xsltNsMapPtr
) xmlMalloc(sizeof(xsltNsMap
));
492 xsltTransformError(NULL
, cctxt
->style
, elem
,
493 "Internal error: (xsltNewNamespaceMapItem) "
494 "memory allocation failed.\n");
497 memset(ret
, 0, sizeof(xsltNsMap
));
500 ret
->origNsName
= ns
->href
;
502 * Store the item at current stylesheet-level.
504 if (cctxt
->psData
->nsMap
!= NULL
)
505 ret
->next
= cctxt
->psData
->nsMap
;
506 cctxt
->psData
->nsMap
= ret
;
510 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
513 * xsltCompilerVarInfoFree:
514 * @cctxt: the compilation context
516 * Frees the list of information for vars/params.
519 xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt
)
521 xsltVarInfoPtr ivar
= cctxt
->ivars
, ivartmp
;
531 * xsltCompilerCtxtFree:
533 * Free an XSLT compiler context.
536 xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt
)
540 #ifdef WITH_XSLT_DEBUG_PARSING
541 xsltGenericDebug(xsltGenericDebugContext
,
542 "Freeing compilation context\n");
543 xsltGenericDebug(xsltGenericDebugContext
,
544 "### Max inodes: %d\n", cctxt
->maxNodeInfos
);
545 xsltGenericDebug(xsltGenericDebugContext
,
546 "### Max LREs : %d\n", cctxt
->maxLREs
);
551 if (cctxt
->inodeList
!= NULL
) {
552 xsltCompilerNodeInfoPtr tmp
, cur
= cctxt
->inodeList
;
553 while (cur
!= NULL
) {
559 if (cctxt
->tmpList
!= NULL
)
560 xsltPointerListFree(cctxt
->tmpList
);
561 #ifdef XSLT_REFACTORED_XPATHCOMP
562 if (cctxt
->xpathCtxt
!= NULL
)
563 xmlXPathFreeContext(cctxt
->xpathCtxt
);
565 if (cctxt
->nsAliases
!= NULL
)
566 xsltFreeNsAliasList(cctxt
->nsAliases
);
569 xsltCompilerVarInfoFree(cctxt
);
575 * xsltCompilerCreate:
577 * Creates an XSLT compiler context.
579 * Returns the pointer to the created xsltCompilerCtxt or
580 * NULL in case of an internal error.
582 static xsltCompilerCtxtPtr
583 xsltCompilationCtxtCreate(xsltStylesheetPtr style
) {
584 xsltCompilerCtxtPtr ret
;
586 ret
= (xsltCompilerCtxtPtr
) xmlMalloc(sizeof(xsltCompilerCtxt
));
588 xsltTransformError(NULL
, style
, NULL
,
589 "xsltCompilerCreate: allocation of compiler "
590 "context failed.\n");
593 memset(ret
, 0, sizeof(xsltCompilerCtxt
));
595 ret
->errSeverity
= XSLT_ERROR_SEVERITY_ERROR
;
596 ret
->tmpList
= xsltPointerListCreate(20);
597 if (ret
->tmpList
== NULL
) {
600 #ifdef XSLT_REFACTORED_XPATHCOMP
602 * Create the XPath compilation context in order
603 * to speed up precompilation of XPath expressions.
605 ret
->xpathCtxt
= xmlXPathNewContext(NULL
);
606 if (ret
->xpathCtxt
== NULL
)
613 xsltCompilationCtxtFree(ret
);
618 xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first
)
620 xsltEffectiveNsPtr tmp
;
622 while (first
!= NULL
) {
624 first
= first
->nextInStore
;
630 xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data
)
635 if (data
->inScopeNamespaces
!= NULL
) {
637 xsltNsListContainerPtr nsi
;
638 xsltPointerListPtr list
=
639 (xsltPointerListPtr
) data
->inScopeNamespaces
;
641 for (i
= 0; i
< list
->number
; i
++) {
643 * REVISIT TODO: Free info of in-scope namespaces.
645 nsi
= (xsltNsListContainerPtr
) list
->items
[i
];
646 if (nsi
->list
!= NULL
)
650 xsltPointerListFree(list
);
651 data
->inScopeNamespaces
= NULL
;
654 if (data
->exclResultNamespaces
!= NULL
) {
656 xsltPointerListPtr list
= (xsltPointerListPtr
)
657 data
->exclResultNamespaces
;
659 for (i
= 0; i
< list
->number
; i
++)
660 xsltPointerListFree((xsltPointerListPtr
) list
->items
[i
]);
662 xsltPointerListFree(list
);
663 data
->exclResultNamespaces
= NULL
;
666 if (data
->extElemNamespaces
!= NULL
) {
667 xsltPointerListPtr list
= (xsltPointerListPtr
)
668 data
->extElemNamespaces
;
671 for (i
= 0; i
< list
->number
; i
++)
672 xsltPointerListFree((xsltPointerListPtr
) list
->items
[i
]);
674 xsltPointerListFree(list
);
675 data
->extElemNamespaces
= NULL
;
677 if (data
->effectiveNs
) {
678 xsltLREEffectiveNsNodesFree(data
->effectiveNs
);
679 data
->effectiveNs
= NULL
;
681 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
682 xsltFreeNamespaceMap(data
->nsMap
);
687 static xsltPrincipalStylesheetDataPtr
688 xsltNewPrincipalStylesheetData(void)
690 xsltPrincipalStylesheetDataPtr ret
;
692 ret
= (xsltPrincipalStylesheetDataPtr
)
693 xmlMalloc(sizeof(xsltPrincipalStylesheetData
));
695 xsltTransformError(NULL
, NULL
, NULL
,
696 "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
699 memset(ret
, 0, sizeof(xsltPrincipalStylesheetData
));
702 * Global list of in-scope namespaces.
704 ret
->inScopeNamespaces
= xsltPointerListCreate(-1);
705 if (ret
->inScopeNamespaces
== NULL
)
708 * Global list of excluded result ns-decls.
710 ret
->exclResultNamespaces
= xsltPointerListCreate(-1);
711 if (ret
->exclResultNamespaces
== NULL
)
714 * Global list of extension instruction namespace names.
716 ret
->extElemNamespaces
= xsltPointerListCreate(-1);
717 if (ret
->extElemNamespaces
== NULL
)
732 * Create a new XSLT Stylesheet
734 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
737 xsltNewStylesheet(void) {
738 xsltStylesheetPtr ret
= NULL
;
740 ret
= (xsltStylesheetPtr
) xmlMalloc(sizeof(xsltStylesheet
));
742 xsltTransformError(NULL
, NULL
, NULL
,
743 "xsltNewStylesheet : malloc failed\n");
746 memset(ret
, 0, sizeof(xsltStylesheet
));
748 ret
->omitXmlDeclaration
= -1;
749 ret
->standalone
= -1;
750 ret
->decimalFormat
= xsltNewDecimalFormat(NULL
);
754 ret
->exclPrefixNr
= 0;
755 ret
->exclPrefixMax
= 0;
756 ret
->exclPrefixTab
= NULL
;
757 ret
->extInfos
= NULL
;
759 ret
->internalized
= 1;
760 ret
->literal_result
= 0;
761 ret
->forwards_compatible
= 0;
762 ret
->dict
= xmlDictCreate();
763 #ifdef WITH_XSLT_DEBUG
764 xsltGenericDebug(xsltGenericDebugContext
,
765 "creating dictionary for stylesheet\n");
774 xsltFreeStylesheet(ret
);
780 * @style: an XSLT stylesheet
782 * Allocate an extra runtime information slot statically while compiling
783 * the stylesheet and return its number
785 * Returns the number of the slot
788 xsltAllocateExtra(xsltStylesheetPtr style
)
790 return(style
->extrasNr
++);
794 * xsltAllocateExtraCtxt:
795 * @ctxt: an XSLT transformation context
797 * Allocate an extra runtime information slot at run-time
798 * and return its number
799 * This make sure there is a slot ready in the transformation context
801 * Returns the number of the slot
804 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt
)
806 if (ctxt
->extrasNr
>= ctxt
->extrasMax
) {
808 if (ctxt
->extrasNr
== 0) {
809 ctxt
->extrasMax
= 20;
810 ctxt
->extras
= (xsltRuntimeExtraPtr
)
811 xmlMalloc(ctxt
->extrasMax
* sizeof(xsltRuntimeExtra
));
812 if (ctxt
->extras
== NULL
) {
813 xmlGenericError(xmlGenericErrorContext
,
814 "xsltAllocateExtraCtxt: out of memory\n");
815 ctxt
->state
= XSLT_STATE_ERROR
;
818 for (i
= 0;i
< ctxt
->extrasMax
;i
++) {
819 ctxt
->extras
[i
].info
= NULL
;
820 ctxt
->extras
[i
].deallocate
= NULL
;
821 ctxt
->extras
[i
].val
.ptr
= NULL
;
825 xsltRuntimeExtraPtr tmp
;
827 ctxt
->extrasMax
+= 100;
828 tmp
= (xsltRuntimeExtraPtr
) xmlRealloc(ctxt
->extras
,
829 ctxt
->extrasMax
* sizeof(xsltRuntimeExtra
));
831 xmlGenericError(xmlGenericErrorContext
,
832 "xsltAllocateExtraCtxt: out of memory\n");
833 ctxt
->state
= XSLT_STATE_ERROR
;
837 for (i
= ctxt
->extrasNr
;i
< ctxt
->extrasMax
;i
++) {
838 ctxt
->extras
[i
].info
= NULL
;
839 ctxt
->extras
[i
].deallocate
= NULL
;
840 ctxt
->extras
[i
].val
.ptr
= NULL
;
844 return(ctxt
->extrasNr
++);
848 * xsltFreeStylesheetList:
849 * @style: an XSLT stylesheet list
851 * Free up the memory allocated by the list @style
854 xsltFreeStylesheetList(xsltStylesheetPtr style
) {
855 xsltStylesheetPtr next
;
857 while (style
!= NULL
) {
859 xsltFreeStylesheet(style
);
865 * xsltCleanupStylesheetTree:
867 * @doc: the document-node
868 * @node: the element where the stylesheet is rooted at
870 * Actually @node need not be the document-element, but
871 * currently Libxslt does not support embedded stylesheets.
873 * Returns 0 if OK, -1 on API or internal errors.
876 xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED
,
877 xmlNodePtr rootElem ATTRIBUTE_UNUSED
)
879 #if 0 /* TODO: Currently disabled, since probably not needed. */
882 if ((doc
== NULL
) || (rootElem
== NULL
) ||
883 (rootElem
->type
!= XML_ELEMENT_NODE
) ||
884 (doc
!= rootElem
->doc
))
888 * Cleanup was suggested by Aleksey Sanin:
889 * Clear the PSVI field to avoid problems if the
890 * node-tree of the stylesheet is intended to be used for
891 * further processing by the user (e.g. for compiling it
892 * once again - although not recommended).
896 while (cur
!= NULL
) {
897 if (cur
->type
== XML_ELEMENT_NODE
) {
899 * Clear the PSVI field.
911 if (cur
->next
!= NULL
)
925 * xsltFreeStylesheet:
926 * @style: an XSLT stylesheet
928 * Free up the memory allocated by @style
931 xsltFreeStylesheet(xsltStylesheetPtr style
)
936 #ifdef XSLT_REFACTORED
938 * Start with a cleanup of the main stylesheet's doc.
940 if ((style
->principal
== style
) && (style
->doc
))
941 xsltCleanupStylesheetTree(style
->doc
,
942 xmlDocGetRootElement(style
->doc
));
943 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
945 * Restore changed ns-decls before freeing the document.
947 if ((style
->doc
!= NULL
) &&
948 XSLT_HAS_INTERNAL_NSMAP(style
))
950 xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style
),
953 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
956 * Start with a cleanup of the main stylesheet's doc.
958 if ((style
->parent
== NULL
) && (style
->doc
))
959 xsltCleanupStylesheetTree(style
->doc
,
960 xmlDocGetRootElement(style
->doc
));
961 #endif /* XSLT_REFACTORED */
965 xsltFreeTemplateHashes(style
);
966 xsltFreeDecimalFormatList(style
);
967 xsltFreeTemplateList(style
->templates
);
968 xsltFreeAttributeSetsHashes(style
);
969 xsltFreeNamespaceAliasHashes(style
);
970 xsltFreeStylePreComps(style
);
972 * Free documents of all included stylsheet modules of this
975 xsltFreeStyleDocuments(style
);
977 * TODO: Best time to shutdown extension stuff?
979 xsltShutdownExts(style
);
981 if (style
->variables
!= NULL
)
982 xsltFreeStackElemList(style
->variables
);
983 if (style
->cdataSection
!= NULL
)
984 xmlHashFree(style
->cdataSection
, NULL
);
985 if (style
->stripSpaces
!= NULL
)
986 xmlHashFree(style
->stripSpaces
, NULL
);
987 if (style
->nsHash
!= NULL
)
988 xmlHashFree(style
->nsHash
, NULL
);
989 if (style
->exclPrefixTab
!= NULL
)
990 xmlFree(style
->exclPrefixTab
);
991 if (style
->method
!= NULL
)
992 xmlFree(style
->method
);
993 if (style
->methodURI
!= NULL
)
994 xmlFree(style
->methodURI
);
995 if (style
->version
!= NULL
)
996 xmlFree(style
->version
);
997 if (style
->encoding
!= NULL
)
998 xmlFree(style
->encoding
);
999 if (style
->doctypePublic
!= NULL
)
1000 xmlFree(style
->doctypePublic
);
1001 if (style
->doctypeSystem
!= NULL
)
1002 xmlFree(style
->doctypeSystem
);
1003 if (style
->mediaType
!= NULL
)
1004 xmlFree(style
->mediaType
);
1006 xsltFreeAVTList(style
->attVTs
);
1007 if (style
->imports
!= NULL
)
1008 xsltFreeStylesheetList(style
->imports
);
1010 #ifdef XSLT_REFACTORED
1012 * If this is the principal stylesheet, then
1013 * free its internal data.
1015 if (style
->principal
== style
) {
1016 if (style
->principalData
) {
1017 xsltFreePrincipalStylesheetData(style
->principalData
);
1018 style
->principalData
= NULL
;
1023 * Better to free the main document of this stylesheet level
1024 * at the end - so here.
1026 if (style
->doc
!= NULL
) {
1027 xmlFreeDoc(style
->doc
);
1030 #ifdef WITH_XSLT_DEBUG
1031 xsltGenericDebug(xsltGenericDebugContext
,
1032 "freeing dictionary from stylesheet\n");
1034 xmlDictFree(style
->dict
);
1036 memset(style
, -1, sizeof(xsltStylesheet
));
1040 /************************************************************************
1042 * Parsing of an XSLT Stylesheet *
1044 ************************************************************************/
1046 #ifdef XSLT_REFACTORED
1048 * This is now performed in an optimized way in xsltParseXSLTTemplate.
1052 * xsltGetInheritedNsList:
1053 * @style: the stylesheet
1054 * @template: the template
1055 * @node: the current node
1057 * Search all the namespace applying to a given element except the ones
1058 * from excluded output prefixes currently in scope. Initialize the
1059 * template inheritedNs list with it.
1061 * Returns the number of entries found
1064 xsltGetInheritedNsList(xsltStylesheetPtr style
,
1065 xsltTemplatePtr
template,
1069 xmlNsPtr
*ret
= NULL
;
1074 if ((style
== NULL
) || (template == NULL
) || (node
== NULL
) ||
1075 (template->inheritedNsNr
!= 0) || (template->inheritedNs
!= NULL
))
1077 while (node
!= NULL
) {
1078 if (node
->type
== XML_ELEMENT_NODE
) {
1080 while (cur
!= NULL
) {
1081 if (xmlStrEqual(cur
->href
, XSLT_NAMESPACE
))
1084 if ((cur
->prefix
!= NULL
) &&
1085 (xsltCheckExtPrefix(style
, cur
->prefix
)))
1088 * Check if this namespace was excluded.
1089 * Note that at this point only the exclusions defined
1090 * on the topmost stylesheet element are in the exclusion-list.
1092 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
1093 if (xmlStrEqual(cur
->href
, style
->exclPrefixTab
[i
]))
1098 (xmlNsPtr
*) xmlMalloc((maxns
+ 1) *
1101 xmlGenericError(xmlGenericErrorContext
,
1102 "xsltGetInheritedNsList : out of memory!\n");
1108 * Skip shadowed namespace bindings.
1110 for (i
= 0; i
< nbns
; i
++) {
1111 if ((cur
->prefix
== ret
[i
]->prefix
) ||
1112 (xmlStrEqual(cur
->prefix
, ret
[i
]->prefix
)))
1116 if (nbns
>= maxns
) {
1118 ret
= (xmlNsPtr
*) xmlRealloc(ret
,
1123 xmlGenericError(xmlGenericErrorContext
,
1124 "xsltGetInheritedNsList : realloc failed!\n");
1135 node
= node
->parent
;
1138 #ifdef WITH_XSLT_DEBUG_PARSING
1139 xsltGenericDebug(xsltGenericDebugContext
,
1140 "template has %d inherited namespaces\n", nbns
);
1142 template->inheritedNsNr
= nbns
;
1143 template->inheritedNs
= ret
;
1147 #endif /* else of XSLT_REFACTORED */
1150 * xsltParseStylesheetOutput:
1151 * @style: the XSLT stylesheet
1152 * @cur: the "output" element
1154 * parse an XSLT stylesheet output element and record
1155 * information related to the stylesheet output
1159 xsltParseStylesheetOutput(xsltStylesheetPtr style
, xmlNodePtr cur
)
1166 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1169 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "version", NULL
);
1171 if (style
->version
!= NULL
)
1172 xmlFree(style
->version
);
1173 style
->version
= prop
;
1176 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "encoding", NULL
);
1178 if (style
->encoding
!= NULL
)
1179 xmlFree(style
->encoding
);
1180 style
->encoding
= prop
;
1183 /* relaxed to support xt:document
1184 * TODO KB: What does "relaxed to support xt:document" mean?
1186 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "method", NULL
);
1190 if (style
->method
!= NULL
)
1191 xmlFree(style
->method
);
1192 style
->method
= NULL
;
1193 if (style
->methodURI
!= NULL
)
1194 xmlFree(style
->methodURI
);
1195 style
->methodURI
= NULL
;
1198 * TODO: Don't use xsltGetQNameURI().
1200 URI
= xsltGetQNameURI(cur
, &prop
);
1202 if (style
!= NULL
) style
->errors
++;
1203 } else if (URI
== NULL
) {
1204 if ((xmlStrEqual(prop
, (const xmlChar
*) "xml")) ||
1205 (xmlStrEqual(prop
, (const xmlChar
*) "html")) ||
1206 (xmlStrEqual(prop
, (const xmlChar
*) "text"))) {
1207 style
->method
= prop
;
1209 xsltTransformError(NULL
, style
, cur
,
1210 "invalid value for method: %s\n", prop
);
1211 if (style
!= NULL
) style
->warnings
++;
1214 style
->method
= prop
;
1215 style
->methodURI
= xmlStrdup(URI
);
1219 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "doctype-system", NULL
);
1221 if (style
->doctypeSystem
!= NULL
)
1222 xmlFree(style
->doctypeSystem
);
1223 style
->doctypeSystem
= prop
;
1226 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "doctype-public", NULL
);
1228 if (style
->doctypePublic
!= NULL
)
1229 xmlFree(style
->doctypePublic
);
1230 style
->doctypePublic
= prop
;
1233 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "standalone", NULL
);
1235 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1236 style
->standalone
= 1;
1237 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1238 style
->standalone
= 0;
1240 xsltTransformError(NULL
, style
, cur
,
1241 "invalid value for standalone: %s\n", prop
);
1247 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "indent", NULL
);
1249 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1251 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1254 xsltTransformError(NULL
, style
, cur
,
1255 "invalid value for indent: %s\n", prop
);
1261 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "omit-xml-declaration", NULL
);
1263 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1264 style
->omitXmlDeclaration
= 1;
1265 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1266 style
->omitXmlDeclaration
= 0;
1268 xsltTransformError(NULL
, style
, cur
,
1269 "invalid value for omit-xml-declaration: %s\n",
1276 elements
= xmlGetNsProp(cur
, (const xmlChar
*) "cdata-section-elements",
1278 if (elements
!= NULL
) {
1279 if (style
->cdataSection
== NULL
)
1280 style
->cdataSection
= xmlHashCreate(10);
1281 if (style
->cdataSection
== NULL
)
1285 while (*element
!= 0) {
1286 while (IS_BLANK(*element
))
1291 while ((*end
!= 0) && (!IS_BLANK(*end
)))
1293 element
= xmlStrndup(element
, end
- element
);
1295 #ifdef WITH_XSLT_DEBUG_PARSING
1296 xsltGenericDebug(xsltGenericDebugContext
,
1297 "add cdata section output element %s\n",
1300 if (xmlValidateQName(BAD_CAST element
, 0) != 0) {
1301 xsltTransformError(NULL
, style
, cur
,
1302 "Attribute 'cdata-section-elements': The value "
1303 "'%s' is not a valid QName.\n", element
);
1310 * TODO: Don't use xsltGetQNameURI().
1312 URI
= xsltGetQNameURI(cur
, &element
);
1313 if (element
== NULL
) {
1315 * TODO: We'll report additionally an error
1316 * via the stylesheet's error handling.
1318 xsltTransformError(NULL
, style
, cur
,
1319 "Attribute 'cdata-section-elements': The value "
1320 "'%s' is not a valid QName.\n", element
);
1326 * XSLT-1.0 "Each QName is expanded into an
1327 * expanded-name using the namespace declarations in
1328 * effect on the xsl:output element in which the QName
1329 * occurs; if there is a default namespace, it is used
1330 * for QNames that do not have a prefix"
1331 * NOTE: Fix of bug #339570.
1334 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1338 xmlHashAddEntry2(style
->cdataSection
, element
, URI
,
1349 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "media-type", NULL
);
1351 if (style
->mediaType
)
1352 xmlFree(style
->mediaType
);
1353 style
->mediaType
= prop
;
1355 if (cur
->children
!= NULL
) {
1356 xsltParseContentError(style
, cur
->children
);
1361 * xsltParseStylesheetDecimalFormat:
1362 * @style: the XSLT stylesheet
1363 * @cur: the "decimal-format" element
1365 * <!-- Category: top-level-element -->
1366 * <xsl:decimal-format
1367 * name = qname, decimal-separator = char, grouping-separator = char,
1368 * infinity = string, minus-sign = char, NaN = string, percent = char
1369 * per-mille = char, zero-digit = char, digit = char,
1370 * pattern-separator = char />
1372 * parse an XSLT stylesheet decimal-format element and
1373 * and record the formatting characteristics
1376 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style
, xmlNodePtr cur
)
1379 xsltDecimalFormatPtr format
;
1380 xsltDecimalFormatPtr iter
;
1382 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1385 format
= style
->decimalFormat
;
1387 prop
= xmlGetNsProp(cur
, BAD_CAST("name"), NULL
);
1389 format
= xsltDecimalFormatGetByName(style
, prop
);
1390 if (format
!= NULL
) {
1391 xsltTransformError(NULL
, style
, cur
,
1392 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop
);
1393 if (style
!= NULL
) style
->warnings
++;
1396 format
= xsltNewDecimalFormat(prop
);
1397 if (format
== NULL
) {
1398 xsltTransformError(NULL
, style
, cur
,
1399 "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
1400 if (style
!= NULL
) style
->errors
++;
1403 /* Append new decimal-format structure */
1404 for (iter
= style
->decimalFormat
; iter
->next
; iter
= iter
->next
)
1407 iter
->next
= format
;
1410 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"decimal-separator", NULL
);
1412 if (format
->decimalPoint
!= NULL
) xmlFree(format
->decimalPoint
);
1413 format
->decimalPoint
= prop
;
1416 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"grouping-separator", NULL
);
1418 if (format
->grouping
!= NULL
) xmlFree(format
->grouping
);
1419 format
->grouping
= prop
;
1422 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"infinity", NULL
);
1424 if (format
->infinity
!= NULL
) xmlFree(format
->infinity
);
1425 format
->infinity
= prop
;
1428 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"minus-sign", NULL
);
1430 if (format
->minusSign
!= NULL
) xmlFree(format
->minusSign
);
1431 format
->minusSign
= prop
;
1434 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"NaN", NULL
);
1436 if (format
->noNumber
!= NULL
) xmlFree(format
->noNumber
);
1437 format
->noNumber
= prop
;
1440 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"percent", NULL
);
1442 if (format
->percent
!= NULL
) xmlFree(format
->percent
);
1443 format
->percent
= prop
;
1446 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"per-mille", NULL
);
1448 if (format
->permille
!= NULL
) xmlFree(format
->permille
);
1449 format
->permille
= prop
;
1452 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"zero-digit", NULL
);
1454 if (format
->zeroDigit
!= NULL
) xmlFree(format
->zeroDigit
);
1455 format
->zeroDigit
= prop
;
1458 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"digit", NULL
);
1460 if (format
->digit
!= NULL
) xmlFree(format
->digit
);
1461 format
->digit
= prop
;
1464 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"pattern-separator", NULL
);
1466 if (format
->patternSeparator
!= NULL
) xmlFree(format
->patternSeparator
);
1467 format
->patternSeparator
= prop
;
1469 if (cur
->children
!= NULL
) {
1470 xsltParseContentError(style
, cur
->children
);
1475 * xsltParseStylesheetPreserveSpace:
1476 * @style: the XSLT stylesheet
1477 * @cur: the "preserve-space" element
1479 * parse an XSLT stylesheet preserve-space element and record
1480 * elements needing preserving
1484 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style
, xmlNodePtr cur
) {
1486 xmlChar
*element
, *end
;
1488 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1491 elements
= xmlGetNsProp(cur
, (const xmlChar
*)"elements", NULL
);
1492 if (elements
== NULL
) {
1493 xsltTransformError(NULL
, style
, cur
,
1494 "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
1495 if (style
!= NULL
) style
->warnings
++;
1499 if (style
->stripSpaces
== NULL
)
1500 style
->stripSpaces
= xmlHashCreate(10);
1501 if (style
->stripSpaces
== NULL
)
1505 while (*element
!= 0) {
1506 while (IS_BLANK(*element
)) element
++;
1510 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1511 element
= xmlStrndup(element
, end
- element
);
1513 #ifdef WITH_XSLT_DEBUG_PARSING
1514 xsltGenericDebug(xsltGenericDebugContext
,
1515 "add preserved space element %s\n", element
);
1517 if (xmlStrEqual(element
, (const xmlChar
*)"*")) {
1518 style
->stripAll
= -1;
1523 * TODO: Don't use xsltGetQNameURI().
1525 URI
= xsltGetQNameURI(cur
, &element
);
1527 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
1528 (xmlChar
*) "preserve");
1535 if (cur
->children
!= NULL
) {
1536 xsltParseContentError(style
, cur
->children
);
1540 #ifdef XSLT_REFACTORED
1543 * xsltParseStylesheetExtPrefix:
1544 * @style: the XSLT stylesheet
1545 * @template: the "extension-element-prefixes" prefix
1547 * parse an XSLT stylesheet's "extension-element-prefix" attribute value
1548 * and register the namespaces of extension instruction.
1549 * SPEC "A namespace is designated as an extension namespace by using
1550 * an extension-element-prefixes attribute on:
1551 * 1) an xsl:stylesheet element
1552 * 2) an xsl:extension-element-prefixes attribute on a
1553 * literal result element
1554 * 3) an extension instruction."
1557 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style
, xmlNodePtr cur
,
1560 xmlChar
*prefix
, *end
;
1562 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1566 /* For xsl:stylesheet/xsl:transform. */
1567 prefixes
= xmlGetNsProp(cur
,
1568 (const xmlChar
*)"extension-element-prefixes", NULL
);
1570 /* For literal result elements and extension instructions. */
1571 prefixes
= xmlGetNsProp(cur
,
1572 (const xmlChar
*)"extension-element-prefixes", XSLT_NAMESPACE
);
1574 if (prefixes
== NULL
) {
1579 while (*prefix
!= 0) {
1580 while (IS_BLANK(*prefix
)) prefix
++;
1584 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1585 prefix
= xmlStrndup(prefix
, end
- prefix
);
1589 if (xmlStrEqual(prefix
, (const xmlChar
*)"#default"))
1590 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1592 ns
= xmlSearchNs(style
->doc
, cur
, prefix
);
1594 xsltTransformError(NULL
, style
, cur
,
1595 "xsl:extension-element-prefix : undefined namespace %s\n",
1597 if (style
!= NULL
) style
->warnings
++;
1599 #ifdef WITH_XSLT_DEBUG_PARSING
1600 xsltGenericDebug(xsltGenericDebugContext
,
1601 "add extension prefix %s\n", prefix
);
1603 xsltRegisterExtPrefix(style
, prefix
, ns
->href
);
1611 #endif /* else of XSLT_REFACTORED */
1614 * xsltParseStylesheetStripSpace:
1615 * @style: the XSLT stylesheet
1616 * @cur: the "strip-space" element
1618 * parse an XSLT stylesheet's strip-space element and record
1619 * the elements needing stripping
1623 xsltParseStylesheetStripSpace(xsltStylesheetPtr style
, xmlNodePtr cur
) {
1625 xmlChar
*element
, *end
;
1627 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1630 elements
= xmlGetNsProp(cur
, (const xmlChar
*)"elements", NULL
);
1631 if (elements
== NULL
) {
1632 xsltTransformError(NULL
, style
, cur
,
1633 "xsltParseStylesheetStripSpace: missing elements attribute\n");
1634 if (style
!= NULL
) style
->warnings
++;
1638 if (style
->stripSpaces
== NULL
)
1639 style
->stripSpaces
= xmlHashCreate(10);
1640 if (style
->stripSpaces
== NULL
)
1644 while (*element
!= 0) {
1645 while (IS_BLANK(*element
)) element
++;
1649 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1650 element
= xmlStrndup(element
, end
- element
);
1652 #ifdef WITH_XSLT_DEBUG_PARSING
1653 xsltGenericDebug(xsltGenericDebugContext
,
1654 "add stripped space element %s\n", element
);
1656 if (xmlStrEqual(element
, (const xmlChar
*)"*")) {
1657 style
->stripAll
= 1;
1662 * TODO: Don't use xsltGetQNameURI().
1664 URI
= xsltGetQNameURI(cur
, &element
);
1666 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
1667 (xmlChar
*) "strip");
1674 if (cur
->children
!= NULL
) {
1675 xsltParseContentError(style
, cur
->children
);
1679 #ifdef XSLT_REFACTORED
1682 * xsltParseStylesheetExcludePrefix:
1683 * @style: the XSLT stylesheet
1684 * @cur: the current point in the stylesheet
1686 * parse an XSLT stylesheet exclude prefix and record
1687 * namespaces needing stripping
1689 * Returns the number of Excluded prefixes added at that level
1693 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style
, xmlNodePtr cur
,
1698 xmlChar
*prefix
, *end
;
1700 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1704 prefixes
= xmlGetNsProp(cur
,
1705 (const xmlChar
*)"exclude-result-prefixes", NULL
);
1707 prefixes
= xmlGetNsProp(cur
,
1708 (const xmlChar
*)"exclude-result-prefixes", XSLT_NAMESPACE
);
1710 if (prefixes
== NULL
) {
1715 while (*prefix
!= 0) {
1716 while (IS_BLANK(*prefix
)) prefix
++;
1720 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1721 prefix
= xmlStrndup(prefix
, end
- prefix
);
1725 if (xmlStrEqual(prefix
, (const xmlChar
*)"#default"))
1726 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1728 ns
= xmlSearchNs(style
->doc
, cur
, prefix
);
1730 xsltTransformError(NULL
, style
, cur
,
1731 "xsl:exclude-result-prefixes : undefined namespace %s\n",
1733 if (style
!= NULL
) style
->warnings
++;
1735 if (exclPrefixPush(style
, (xmlChar
*) ns
->href
) >= 0) {
1736 #ifdef WITH_XSLT_DEBUG_PARSING
1737 xsltGenericDebug(xsltGenericDebugContext
,
1738 "exclude result prefix %s\n", prefix
);
1750 #endif /* else of XSLT_REFACTORED */
1752 #ifdef XSLT_REFACTORED
1755 * xsltTreeEnsureXMLDecl:
1759 * This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
1760 * Ensures that there is an XML namespace declaration on the doc.
1762 * Returns the XML ns-struct or NULL on API and internal errors.
1765 xsltTreeEnsureXMLDecl(xmlDocPtr doc
)
1769 if (doc
->oldNs
!= NULL
)
1770 return (doc
->oldNs
);
1773 ns
= (xmlNsPtr
) xmlMalloc(sizeof(xmlNs
));
1775 xmlGenericError(xmlGenericErrorContext
,
1776 "xsltTreeEnsureXMLDecl: Failed to allocate "
1777 "the XML namespace.\n");
1780 memset(ns
, 0, sizeof(xmlNs
));
1781 ns
->type
= XML_LOCAL_NAMESPACE
;
1783 * URGENT TODO: revisit this.
1785 #ifdef LIBXML_NAMESPACE_DICT
1787 ns
->href
= xmlDictLookup(doc
->dict
, XML_XML_NAMESPACE
, -1);
1789 ns
->href
= xmlStrdup(XML_XML_NAMESPACE
);
1791 ns
->href
= xmlStrdup(XML_XML_NAMESPACE
);
1793 ns
->prefix
= xmlStrdup((const xmlChar
*)"xml");
1800 * xsltTreeAcquireStoredNs:
1802 * @nsName: the namespace name
1803 * @prefix: the prefix
1806 * This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
1807 * Creates or reuses an xmlNs struct on doc->oldNs with
1808 * the given prefix and namespace name.
1810 * Returns the aquired ns struct or NULL in case of an API
1811 * or internal error.
1814 xsltTreeAcquireStoredNs(xmlDocPtr doc
,
1815 const xmlChar
*nsName
,
1816 const xmlChar
*prefix
)
1822 if (doc
->oldNs
!= NULL
)
1825 ns
= xsltTreeEnsureXMLDecl(doc
);
1828 if (ns
->next
!= NULL
) {
1831 while (ns
!= NULL
) {
1832 if ((ns
->prefix
== NULL
) != (prefix
== NULL
)) {
1834 } else if (prefix
== NULL
) {
1835 if (xmlStrEqual(ns
->href
, nsName
))
1838 if ((ns
->prefix
[0] == prefix
[0]) &&
1839 xmlStrEqual(ns
->prefix
, prefix
) &&
1840 xmlStrEqual(ns
->href
, nsName
))
1844 if (ns
->next
== NULL
)
1850 ns
->next
= xmlNewNs(NULL
, nsName
, prefix
);
1855 * xsltLREBuildEffectiveNs:
1857 * Apply ns-aliasing on the namespace of the given @elem and
1861 xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt
,
1865 xsltNsAliasPtr alias
;
1867 if ((cctxt
== NULL
) || (elem
== NULL
))
1869 if ((cctxt
->nsAliases
== NULL
) || (! cctxt
->hasNsAliases
))
1872 alias
= cctxt
->nsAliases
;
1873 while (alias
!= NULL
) {
1874 if ( /* If both namespaces are NULL... */
1875 ( (elem
->ns
== NULL
) &&
1876 ((alias
->literalNs
== NULL
) ||
1877 (alias
->literalNs
->href
== NULL
)) ) ||
1878 /* ... or both namespace are equal */
1879 ( (elem
->ns
!= NULL
) &&
1880 (alias
->literalNs
!= NULL
) &&
1881 xmlStrEqual(elem
->ns
->href
, alias
->literalNs
->href
) ) )
1883 if ((alias
->targetNs
!= NULL
) &&
1884 (alias
->targetNs
->href
!= NULL
))
1887 * Convert namespace.
1889 if (elem
->doc
== alias
->docOfTargetNs
) {
1891 * This is the nice case: same docs.
1892 * This will eventually assign a ns-decl which
1893 * is shadowed, but this has no negative effect on
1894 * the generation of the result tree.
1896 elem
->ns
= alias
->targetNs
;
1899 * This target xmlNs originates from a different
1900 * stylesheet tree. Try to locate it in the
1901 * in-scope namespaces.
1902 * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
1904 ns
= xmlSearchNs(elem
->doc
, elem
,
1905 alias
->targetNs
->prefix
);
1907 * If no matching ns-decl found, then assign a
1908 * ns-decl stored in xmlDoc.
1911 (! xmlStrEqual(ns
->href
, alias
->targetNs
->href
)))
1914 * BIG NOTE: The use of xsltTreeAcquireStoredNs()
1915 * is not very efficient, but currently I don't
1916 * see an other way of *safely* changing a node's
1917 * namespace, since the xmlNs struct in
1918 * alias->targetNs might come from an other
1919 * stylesheet tree. So we need to anchor it in the
1920 * current document, without adding it to the tree,
1921 * which would otherwise change the in-scope-ns
1922 * semantic of the tree.
1924 ns
= xsltTreeAcquireStoredNs(elem
->doc
,
1925 alias
->targetNs
->href
,
1926 alias
->targetNs
->prefix
);
1929 xsltTransformError(NULL
, cctxt
->style
, elem
,
1930 "Internal error in "
1931 "xsltLREBuildEffectiveNs(): "
1932 "failed to acquire a stored "
1933 "ns-declaration.\n");
1934 cctxt
->style
->errors
++;
1943 * Move into or leave in the NULL namespace.
1949 alias
= alias
->next
;
1952 * Same with attributes of literal result elements.
1954 if (elem
->properties
!= NULL
) {
1955 xmlAttrPtr attr
= elem
->properties
;
1957 while (attr
!= NULL
) {
1958 if (attr
->ns
== NULL
) {
1962 alias
= cctxt
->nsAliases
;
1963 while (alias
!= NULL
) {
1964 if ( /* If both namespaces are NULL... */
1965 ( (elem
->ns
== NULL
) &&
1966 ((alias
->literalNs
== NULL
) ||
1967 (alias
->literalNs
->href
== NULL
)) ) ||
1968 /* ... or both namespace are equal */
1969 ( (elem
->ns
!= NULL
) &&
1970 (alias
->literalNs
!= NULL
) &&
1971 xmlStrEqual(elem
->ns
->href
, alias
->literalNs
->href
) ) )
1973 if ((alias
->targetNs
!= NULL
) &&
1974 (alias
->targetNs
->href
!= NULL
))
1976 if (elem
->doc
== alias
->docOfTargetNs
) {
1977 elem
->ns
= alias
->targetNs
;
1979 ns
= xmlSearchNs(elem
->doc
, elem
,
1980 alias
->targetNs
->prefix
);
1982 (! xmlStrEqual(ns
->href
, alias
->targetNs
->href
)))
1984 ns
= xsltTreeAcquireStoredNs(elem
->doc
,
1985 alias
->targetNs
->href
,
1986 alias
->targetNs
->prefix
);
1989 xsltTransformError(NULL
, cctxt
->style
, elem
,
1990 "Internal error in "
1991 "xsltLREBuildEffectiveNs(): "
1992 "failed to acquire a stored "
1993 "ns-declaration.\n");
1994 cctxt
->style
->errors
++;
2003 * Move into or leave in the NULL namespace.
2009 alias
= alias
->next
;
2019 * xsltLREBuildEffectiveNsNodes:
2021 * Computes the effective namespaces nodes for a literal result
2023 * @effectiveNs is the set of effective ns-nodes
2024 * on the literal result element, which will be added to the result
2025 * element if not already existing in the result tree.
2026 * This means that excluded namespaces (via exclude-result-prefixes,
2027 * extension-element-prefixes and the XSLT namespace) not added
2029 * Namespace-aliasing was applied on the @effectiveNs.
2032 xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt
,
2033 xsltStyleItemLRElementInfoPtr item
,
2038 xsltEffectiveNsPtr effNs
, lastEffNs
= NULL
;
2039 int i
, j
, holdByElem
;
2040 xsltPointerListPtr extElemNs
= cctxt
->inode
->extElemNs
;
2041 xsltPointerListPtr exclResultNs
= cctxt
->inode
->exclResultNs
;
2043 if ((cctxt
== NULL
) || (cctxt
->inode
== NULL
) || (elem
== NULL
) ||
2044 (item
== NULL
) || (item
->effectiveNs
!= NULL
))
2047 if (item
->inScopeNs
== NULL
)
2050 extElemNs
= cctxt
->inode
->extElemNs
;
2051 exclResultNs
= cctxt
->inode
->exclResultNs
;
2053 for (i
= 0; i
< item
->inScopeNs
->totalNumber
; i
++) {
2054 ns
= item
->inScopeNs
->list
[i
];
2056 * Skip namespaces designated as excluded namespaces
2057 * -------------------------------------------------
2059 * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
2060 * which are target namespaces of namespace-aliases
2061 * regardless if designated as excluded.
2063 * Exclude the XSLT namespace.
2065 if (xmlStrEqual(ns
->href
, XSLT_NAMESPACE
))
2069 * Apply namespace aliasing
2070 * ------------------------
2073 * "- A namespace node whose string value is a literal namespace
2074 * URI is not copied to the result tree.
2075 * - A namespace node whose string value is a target namespace URI
2076 * is copied to the result tree, whether or not the URI
2077 * identifies an excluded namespace."
2079 * NOTE: The ns-aliasing machanism is non-cascading.
2080 * (checked with Saxon, Xalan and MSXML .NET).
2081 * URGENT TODO: is style->nsAliases the effective list of
2082 * ns-aliases, or do we need to lookup the whole
2084 * TODO: Get rid of import-tree lookup.
2086 if (cctxt
->hasNsAliases
) {
2087 xsltNsAliasPtr alias
;
2089 * First check for being a target namespace.
2091 alias
= cctxt
->nsAliases
;
2094 * TODO: Is xmlns="" handled already?
2096 if ((alias
->targetNs
!= NULL
) &&
2097 (xmlStrEqual(alias
->targetNs
->href
, ns
->href
)))
2100 * Recognized as a target namespace; use it regardless
2101 * if excluded otherwise.
2103 goto add_effective_ns
;
2105 alias
= alias
->next
;
2106 } while (alias
!= NULL
);
2108 alias
= cctxt
->nsAliases
;
2111 * TODO: Is xmlns="" handled already?
2113 if ((alias
->literalNs
!= NULL
) &&
2114 (xmlStrEqual(alias
->literalNs
->href
, ns
->href
)))
2117 * Recognized as an namespace alias; do not use it.
2121 alias
= alias
->next
;
2122 } while (alias
!= NULL
);
2126 * Exclude excluded result namespaces.
2129 for (j
= 0; j
< exclResultNs
->number
; j
++)
2130 if (xmlStrEqual(ns
->href
, BAD_CAST exclResultNs
->items
[j
]))
2134 * Exclude extension-element namespaces.
2137 for (j
= 0; j
< extElemNs
->number
; j
++)
2138 if (xmlStrEqual(ns
->href
, BAD_CAST extElemNs
->items
[j
]))
2144 * OPTIMIZE TODO: This information may not be needed.
2146 if (isLRE
&& (elem
->nsDef
!= NULL
)) {
2148 tmpns
= elem
->nsDef
;
2154 tmpns
= tmpns
->next
;
2155 } while (tmpns
!= NULL
);
2161 * Add the effective namespace declaration.
2163 effNs
= (xsltEffectiveNsPtr
) xmlMalloc(sizeof(xsltEffectiveNs
));
2164 if (effNs
== NULL
) {
2165 xsltTransformError(NULL
, cctxt
->style
, elem
,
2166 "Internal error in xsltLREBuildEffectiveNs(): "
2167 "failed to allocate memory.\n");
2168 cctxt
->style
->errors
++;
2171 if (cctxt
->psData
->effectiveNs
== NULL
) {
2172 cctxt
->psData
->effectiveNs
= effNs
;
2173 effNs
->nextInStore
= NULL
;
2175 effNs
->nextInStore
= cctxt
->psData
->effectiveNs
;
2176 cctxt
->psData
->effectiveNs
= effNs
;
2180 effNs
->prefix
= ns
->prefix
;
2181 effNs
->nsName
= ns
->href
;
2182 effNs
->holdByElem
= holdByElem
;
2184 if (lastEffNs
== NULL
)
2185 item
->effectiveNs
= effNs
;
2187 lastEffNs
->next
= effNs
;
2198 * xsltLREInfoCreate:
2200 * @isLRE: indicates if the given @elem is a literal result element
2202 * Creates a new info for a literal result element.
2205 xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt
,
2209 xsltStyleItemLRElementInfoPtr item
;
2211 if ((cctxt
== NULL
) || (cctxt
->inode
== NULL
))
2214 item
= (xsltStyleItemLRElementInfoPtr
)
2215 xmlMalloc(sizeof(xsltStyleItemLRElementInfo
));
2217 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2218 "Internal error in xsltLREInfoCreate(): "
2219 "memory allocation failed.\n");
2220 cctxt
->style
->errors
++;
2223 memset(item
, 0, sizeof(xsltStyleItemLRElementInfo
));
2224 item
->type
= XSLT_FUNC_LITERAL_RESULT_ELEMENT
;
2226 * Store it in the stylesheet.
2228 item
->next
= cctxt
->style
->preComps
;
2229 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
2231 * @inScopeNs are used for execution of XPath expressions
2234 item
->inScopeNs
= cctxt
->inode
->inScopeNs
;
2237 xsltLREBuildEffectiveNsNodes(cctxt
, item
, elem
, isLRE
);
2239 cctxt
->inode
->litResElemInfo
= item
;
2240 cctxt
->inode
->nsChanged
= 0;
2246 * xsltCompilerVarInfoPush:
2247 * @cctxt: the compilation context
2249 * Pushes a new var/param info onto the stack.
2251 * Returns the acquired variable info.
2253 static xsltVarInfoPtr
2254 xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt
,
2256 const xmlChar
*name
,
2257 const xmlChar
*nsName
)
2259 xsltVarInfoPtr ivar
;
2261 if ((cctxt
->ivar
!= NULL
) && (cctxt
->ivar
->next
!= NULL
)) {
2262 ivar
= cctxt
->ivar
->next
;
2263 } else if ((cctxt
->ivar
== NULL
) && (cctxt
->ivars
!= NULL
)) {
2264 ivar
= cctxt
->ivars
;
2266 ivar
= (xsltVarInfoPtr
) xmlMalloc(sizeof(xsltVarInfo
));
2268 xsltTransformError(NULL
, cctxt
->style
, inst
,
2269 "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
2270 cctxt
->style
->errors
++;
2273 /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
2274 if (cctxt
->ivars
== NULL
) {
2275 cctxt
->ivars
= ivar
;
2278 cctxt
->ivar
->next
= ivar
;
2279 ivar
->prev
= cctxt
->ivar
;
2284 ivar
->depth
= cctxt
->depth
;
2286 ivar
->nsName
= nsName
;
2291 * xsltCompilerVarInfoPop:
2292 * @cctxt: the compilation context
2294 * Pops all var/param infos from the stack, which
2295 * have the current depth.
2298 xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt
)
2301 while ((cctxt
->ivar
!= NULL
) &&
2302 (cctxt
->ivar
->depth
> cctxt
->depth
))
2304 cctxt
->ivar
= cctxt
->ivar
->prev
;
2309 * xsltCompilerNodePush:
2311 * @cctxt: the compilation context
2312 * @node: the node to be pushed (this can also be the doc-node)
2316 * Returns the current node info structure or
2317 * NULL in case of an internal error.
2319 static xsltCompilerNodeInfoPtr
2320 xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2322 xsltCompilerNodeInfoPtr inode
, iprev
;
2324 if ((cctxt
->inode
!= NULL
) && (cctxt
->inode
->next
!= NULL
)) {
2325 inode
= cctxt
->inode
->next
;
2326 } else if ((cctxt
->inode
== NULL
) && (cctxt
->inodeList
!= NULL
)) {
2327 inode
= cctxt
->inodeList
;
2330 * Create a new node-info.
2332 inode
= (xsltCompilerNodeInfoPtr
)
2333 xmlMalloc(sizeof(xsltCompilerNodeInfo
));
2334 if (inode
== NULL
) {
2335 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2336 "xsltCompilerNodePush: malloc failed.\n");
2339 memset(inode
, 0, sizeof(xsltCompilerNodeInfo
));
2340 if (cctxt
->inodeList
== NULL
)
2341 cctxt
->inodeList
= inode
;
2343 cctxt
->inodeLast
->next
= inode
;
2344 inode
->prev
= cctxt
->inodeLast
;
2346 cctxt
->inodeLast
= inode
;
2347 cctxt
->maxNodeInfos
++;
2348 if (cctxt
->inode
== NULL
) {
2349 cctxt
->inode
= inode
;
2351 * Create an initial literal result element info for
2352 * the root of the stylesheet.
2354 xsltLREInfoCreate(cctxt
, NULL
, 0);
2358 cctxt
->inode
= inode
;
2360 * REVISIT TODO: Keep the reset always complete.
2361 * NOTE: Be carefull with the @node, since it might be
2365 inode
->depth
= cctxt
->depth
;
2366 inode
->templ
= NULL
;
2367 inode
->category
= XSLT_ELEMENT_CATEGORY_XSLT
;
2370 inode
->curChildType
= 0;
2371 inode
->extContentHandled
= 0;
2374 if (inode
->prev
!= NULL
) {
2375 iprev
= inode
->prev
;
2377 * Inherit the following information:
2378 * ---------------------------------
2380 * In-scope namespaces
2382 inode
->inScopeNs
= iprev
->inScopeNs
;
2384 * Info for literal result elements
2386 inode
->litResElemInfo
= iprev
->litResElemInfo
;
2387 inode
->nsChanged
= iprev
->nsChanged
;
2389 * Excluded result namespaces
2391 inode
->exclResultNs
= iprev
->exclResultNs
;
2393 * Extension instruction namespaces
2395 inode
->extElemNs
= iprev
->extElemNs
;
2397 * Whitespace preservation
2399 inode
->preserveWhitespace
= iprev
->preserveWhitespace
;
2401 * Forwards-compatible mode
2403 inode
->forwardsCompat
= iprev
->forwardsCompat
;
2405 inode
->inScopeNs
= NULL
;
2406 inode
->exclResultNs
= NULL
;
2407 inode
->extElemNs
= NULL
;
2408 inode
->preserveWhitespace
= 0;
2409 inode
->forwardsCompat
= 0;
2416 * xsltCompilerNodePop:
2418 * @cctxt: the compilation context
2419 * @node: the node to be pushed (this can also be the doc-node)
2421 * Pops the current node info.
2424 xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2426 if (cctxt
->inode
== NULL
) {
2427 xmlGenericError(xmlGenericErrorContext
,
2428 "xsltCompilerNodePop: Top-node mismatch.\n");
2432 * NOTE: Be carefull with the @node, since it might be
2435 if (cctxt
->inode
->node
!= node
) {
2436 xmlGenericError(xmlGenericErrorContext
,
2437 "xsltCompilerNodePop: Node mismatch.\n");
2440 if (cctxt
->inode
->depth
!= cctxt
->depth
) {
2441 xmlGenericError(xmlGenericErrorContext
,
2442 "xsltCompilerNodePop: Depth mismatch.\n");
2447 * Pop information of variables.
2449 if ((cctxt
->ivar
) && (cctxt
->ivar
->depth
> cctxt
->depth
))
2450 xsltCompilerVarInfoPop(cctxt
);
2452 cctxt
->inode
= cctxt
->inode
->prev
;
2453 if (cctxt
->inode
!= NULL
)
2454 cctxt
->inode
->curChildType
= 0;
2459 const xmlChar
*nsName
= NULL
, *name
= NULL
;
2460 const xmlChar
*infnsName
= NULL
, *infname
= NULL
;
2463 if (node
->type
== XML_ELEMENT_NODE
) {
2465 if (node
->ns
!= NULL
)
2466 nsName
= node
->ns
->href
;
2468 nsName
= BAD_CAST
"";
2470 name
= BAD_CAST
"#document";
2471 nsName
= BAD_CAST
"";
2474 name
= BAD_CAST
"Not given";
2476 if (cctxt
->inode
->node
) {
2477 if (node
->type
== XML_ELEMENT_NODE
) {
2478 infname
= cctxt
->inode
->node
->name
;
2479 if (cctxt
->inode
->node
->ns
!= NULL
)
2480 infnsName
= cctxt
->inode
->node
->ns
->href
;
2482 infnsName
= BAD_CAST
"";
2484 infname
= BAD_CAST
"#document";
2485 infnsName
= BAD_CAST
"";
2488 infname
= BAD_CAST
"Not given";
2491 xmlGenericError(xmlGenericErrorContext
,
2492 "xsltCompilerNodePop: Given : '%s' URI '%s'\n",
2494 xmlGenericError(xmlGenericErrorContext
,
2495 "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
2496 infname
, infnsName
);
2501 * xsltCompilerBuildInScopeNsList:
2503 * Create and store the list of in-scope namespaces for the given
2504 * node in the stylesheet. If there are no changes in the in-scope
2505 * namespaces then the last ns-info of the ancestor axis will be returned.
2506 * Compilation-time only.
2508 * Returns the ns-info or NULL if there are no namespaces in scope.
2510 static xsltNsListContainerPtr
2511 xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2513 xsltNsListContainerPtr nsi
= NULL
;
2514 xmlNsPtr
*list
= NULL
, ns
;
2517 * Create a new ns-list for this position in the node-tree.
2518 * xmlGetNsList() will return NULL, if there are no ns-decls in the
2519 * tree. Note that the ns-decl for the XML namespace is not added
2520 * to the resulting list; the XPath module handles the XML namespace
2523 while (node
!= NULL
) {
2524 if (node
->type
== XML_ELEMENT_NODE
) {
2526 while (ns
!= NULL
) {
2528 nsi
= (xsltNsListContainerPtr
)
2529 xmlMalloc(sizeof(xsltNsListContainer
));
2531 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2532 "xsltCompilerBuildInScopeNsList: "
2533 "malloc failed!\n");
2536 memset(nsi
, 0, sizeof(xsltNsListContainer
));
2538 (xmlNsPtr
*) xmlMalloc(maxns
* sizeof(xmlNsPtr
));
2539 if (nsi
->list
== NULL
) {
2540 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2541 "xsltCompilerBuildInScopeNsList: "
2542 "malloc failed!\n");
2545 nsi
->list
[0] = NULL
;
2548 * Skip shadowed namespace bindings.
2550 for (i
= 0; i
< nsi
->totalNumber
; i
++) {
2551 if ((ns
->prefix
== nsi
->list
[i
]->prefix
) ||
2552 (xmlStrEqual(ns
->prefix
, nsi
->list
[i
]->prefix
)))
2555 if (i
>= nsi
->totalNumber
) {
2556 if (nsi
->totalNumber
+1 >= maxns
) {
2559 (xmlNsPtr
*) xmlRealloc(nsi
->list
,
2560 maxns
* sizeof(xmlNsPtr
));
2561 if (nsi
->list
== NULL
) {
2562 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2563 "xsltCompilerBuildInScopeNsList: "
2564 "realloc failed!\n");
2568 nsi
->list
[nsi
->totalNumber
++] = ns
;
2569 nsi
->list
[nsi
->totalNumber
] = NULL
;
2575 node
= node
->parent
;
2580 * Move the default namespace to last position.
2582 nsi
->xpathNumber
= nsi
->totalNumber
;
2583 for (i
= 0; i
< nsi
->totalNumber
; i
++) {
2584 if (nsi
->list
[i
]->prefix
== NULL
) {
2586 nsi
->list
[i
] = nsi
->list
[nsi
->totalNumber
-1];
2587 nsi
->list
[nsi
->totalNumber
-1] = ns
;
2593 * Store the ns-list in the stylesheet.
2595 if (xsltPointerListAddSize(
2596 (xsltPointerListPtr
)cctxt
->psData
->inScopeNamespaces
,
2597 (void *) nsi
, 5) == -1)
2601 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2602 "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
2606 * Notify of change in status wrt namespaces.
2608 if (cctxt
->inode
!= NULL
)
2609 cctxt
->inode
->nsChanged
= 1;
2616 cctxt
->style
->errors
++;
2621 xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt
,
2622 xsltPointerListPtr list
,
2624 const xmlChar
*value
)
2629 if ((cctxt
== NULL
) || (value
== NULL
) || (list
== NULL
))
2634 cur
= (xmlChar
*) value
;
2636 while (IS_BLANK(*cur
)) cur
++;
2640 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
2641 cur
= xmlStrndup(cur
, end
- cur
);
2647 * TODO: Export and use xmlSearchNsByPrefixStrict()
2648 * in Libxml2, tree.c, since xmlSearchNs() is in most
2649 * cases not efficient and in some cases not correct.
2651 * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
2653 if ((cur
[0] == '#') &&
2654 xmlStrEqual(cur
, (const xmlChar
*)"#default"))
2655 ns
= xmlSearchNs(cctxt
->style
->doc
, node
, NULL
);
2657 ns
= xmlSearchNs(cctxt
->style
->doc
, node
, cur
);
2661 * TODO: Better to report the attr-node, otherwise
2662 * the user won't know which attribute was invalid.
2664 xsltTransformError(NULL
, cctxt
->style
, node
,
2665 "No namespace binding in scope for prefix '%s'.\n", cur
);
2667 * XSLT-1.0: "It is an error if there is no namespace
2668 * bound to the prefix on the element bearing the
2669 * exclude-result-prefixes or xsl:exclude-result-prefixes
2672 cctxt
->style
->errors
++;
2674 #ifdef WITH_XSLT_DEBUG_PARSING
2675 xsltGenericDebug(xsltGenericDebugContext
,
2676 "resolved prefix '%s'\n", cur
);
2679 * Note that we put the namespace name into the dict.
2681 if (xsltPointerListAddSize(list
,
2682 (void *) xmlDictLookup(cctxt
->style
->dict
,
2683 ns
->href
, -1), 5) == -1)
2696 cctxt
->style
->errors
++;
2701 * xsltCompilerUtilsCreateMergedList:
2702 * @dest: the destination list (optional)
2703 * @first: the first list
2704 * @second: the second list (optional)
2706 * Appends the content of @second to @first into @destination.
2707 * If @destination is NULL a new list will be created.
2709 * Returns the merged list of items or NULL if there's nothing to merge.
2711 static xsltPointerListPtr
2712 xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first
,
2713 xsltPointerListPtr second
)
2715 xsltPointerListPtr ret
;
2719 num
= first
->number
;
2723 num
+= second
->number
;
2726 ret
= xsltPointerListCreate(num
);
2732 if ((first
!= NULL
) && (first
->number
!= 0)) {
2733 memcpy(ret
->items
, first
->items
,
2734 first
->number
* sizeof(void *));
2735 if ((second
!= NULL
) && (second
->number
!= 0))
2736 memcpy(ret
->items
+ first
->number
, second
->items
,
2737 second
->number
* sizeof(void *));
2738 } else if ((second
!= NULL
) && (second
->number
!= 0))
2739 memcpy(ret
->items
, (void *) second
->items
,
2740 second
->number
* sizeof(void *));
2746 * xsltParseExclResultPrefixes:
2748 * Create and store the list of in-scope namespaces for the given
2749 * node in the stylesheet. If there are no changes in the in-scope
2750 * namespaces then the last ns-info of the ancestor axis will be returned.
2751 * Compilation-time only.
2753 * Returns the ns-info or NULL if there are no namespaces in scope.
2755 static xsltPointerListPtr
2756 xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2757 xsltPointerListPtr def
,
2760 xsltPointerListPtr list
= NULL
;
2764 if ((cctxt
== NULL
) || (node
== NULL
))
2767 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2768 attr
= xmlHasNsProp(node
, BAD_CAST
"exclude-result-prefixes", NULL
);
2770 attr
= xmlHasNsProp(node
, BAD_CAST
"exclude-result-prefixes",
2775 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
2777 * Mark the XSLT attr.
2779 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2782 if ((attr
->children
!= NULL
) &&
2783 (attr
->children
->content
!= NULL
))
2784 value
= attr
->children
->content
;
2786 xsltTransformError(NULL
, cctxt
->style
, node
,
2787 "Attribute 'exclude-result-prefixes': Invalid value.\n");
2788 cctxt
->style
->errors
++;
2792 if (xsltParseNsPrefixList(cctxt
, cctxt
->tmpList
, node
,
2793 BAD_CAST value
) != 0)
2795 if (cctxt
->tmpList
->number
== 0)
2798 * Merge the list with the inherited list.
2800 list
= xsltCompilerUtilsCreateMergedList(def
, cctxt
->tmpList
);
2804 * Store the list in the stylesheet/compiler context.
2806 if (xsltPointerListAddSize(
2807 cctxt
->psData
->exclResultNamespaces
, list
, 5) == -1)
2809 xsltPointerListFree(list
);
2814 * Notify of change in status wrt namespaces.
2816 if (cctxt
->inode
!= NULL
)
2817 cctxt
->inode
->nsChanged
= 1;
2827 * xsltParseExtElemPrefixes:
2829 * Create and store the list of in-scope namespaces for the given
2830 * node in the stylesheet. If there are no changes in the in-scope
2831 * namespaces then the last ns-info of the ancestor axis will be returned.
2832 * Compilation-time only.
2834 * Returns the ns-info or NULL if there are no namespaces in scope.
2836 static xsltPointerListPtr
2837 xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2838 xsltPointerListPtr def
,
2841 xsltPointerListPtr list
= NULL
;
2846 if ((cctxt
== NULL
) || (node
== NULL
))
2849 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2850 attr
= xmlHasNsProp(node
, BAD_CAST
"extension-element-prefixes", NULL
);
2852 attr
= xmlHasNsProp(node
, BAD_CAST
"extension-element-prefixes",
2857 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
2859 * Mark the XSLT attr.
2861 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2864 if ((attr
->children
!= NULL
) &&
2865 (attr
->children
->content
!= NULL
))
2866 value
= attr
->children
->content
;
2868 xsltTransformError(NULL
, cctxt
->style
, node
,
2869 "Attribute 'extension-element-prefixes': Invalid value.\n");
2870 cctxt
->style
->errors
++;
2875 if (xsltParseNsPrefixList(cctxt
, cctxt
->tmpList
, node
,
2876 BAD_CAST value
) != 0)
2879 if (cctxt
->tmpList
->number
== 0)
2882 * REVISIT: Register the extension namespaces.
2884 for (i
= 0; i
< cctxt
->tmpList
->number
; i
++)
2885 xsltRegisterExtPrefix(cctxt
->style
, NULL
,
2886 BAD_CAST cctxt
->tmpList
->items
[i
]);
2888 * Merge the list with the inherited list.
2890 list
= xsltCompilerUtilsCreateMergedList(def
, cctxt
->tmpList
);
2894 * Store the list in the stylesheet.
2896 if (xsltPointerListAddSize(
2897 cctxt
->psData
->extElemNamespaces
, list
, 5) == -1)
2899 xsltPointerListFree(list
);
2904 * Notify of change in status wrt namespaces.
2906 if (cctxt
->inode
!= NULL
)
2907 cctxt
->inode
->nsChanged
= 1;
2917 * xsltParseAttrXSLTVersion:
2919 * @cctxt: the compilation context
2920 * @node: the element-node
2921 * @isXsltElem: whether this is an XSLT element
2923 * Parses the attribute xsl:version.
2925 * Returns 1 if there was such an attribute, 0 if not and
2926 * -1 if an internal or API error occured.
2929 xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2935 if ((cctxt
== NULL
) || (node
== NULL
))
2938 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2939 attr
= xmlHasNsProp(node
, BAD_CAST
"version", NULL
);
2941 attr
= xmlHasNsProp(node
, BAD_CAST
"version", XSLT_NAMESPACE
);
2946 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2948 if ((attr
->children
!= NULL
) &&
2949 (attr
->children
->content
!= NULL
))
2950 value
= attr
->children
->content
;
2952 xsltTransformError(NULL
, cctxt
->style
, node
,
2953 "Attribute 'version': Invalid value.\n");
2954 cctxt
->style
->errors
++;
2958 if (! xmlStrEqual(value
, (const xmlChar
*)"1.0")) {
2959 cctxt
->inode
->forwardsCompat
= 1;
2961 * TODO: To what extent do we support the
2962 * forwards-compatible mode?
2965 * Report this only once per compilation episode.
2967 if (! cctxt
->hasForwardsCompat
) {
2968 cctxt
->hasForwardsCompat
= 1;
2969 cctxt
->errSeverity
= XSLT_ERROR_SEVERITY_WARNING
;
2970 xsltTransformError(NULL
, cctxt
->style
, node
,
2971 "Warning: the attribute xsl:version specifies a value "
2972 "different from '1.0'. Switching to forwards-compatible "
2973 "mode. Only features of XSLT 1.0 are supported by this "
2975 cctxt
->style
->warnings
++;
2976 cctxt
->errSeverity
= XSLT_ERROR_SEVERITY_ERROR
;
2979 cctxt
->inode
->forwardsCompat
= 0;
2982 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
2984 * Set a marker on XSLT attributes.
2986 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2992 xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2994 xmlNodePtr deleteNode
, cur
, txt
, textNode
= NULL
;
2996 xsltStylesheetPtr style
;
2997 int internalize
= 0, findSpaceAttr
;
2998 int xsltStylesheetElemDepth
;
3001 const xmlChar
*name
, *nsNameXSLT
= NULL
;
3002 int strictWhitespace
, inXSLText
= 0;
3003 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3004 xsltNsMapPtr nsMapItem
;
3007 if ((cctxt
== NULL
) || (cctxt
->style
== NULL
) ||
3008 (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
3015 style
= cctxt
->style
;
3016 if ((style
->dict
!= NULL
) && (doc
->dict
== style
->dict
))
3019 style
->internalized
= 0;
3022 * Init value of xml:space. Since this might be an embedded
3023 * stylesheet, this is needed to be performed on the element
3024 * where the stylesheet is rooted at, taking xml:space of
3025 * ancestors into account.
3027 if (! cctxt
->simplified
)
3028 xsltStylesheetElemDepth
= cctxt
->depth
+1;
3030 xsltStylesheetElemDepth
= 0;
3032 if (xmlNodeGetSpacePreserve(node
) != 1)
3033 cctxt
->inode
->preserveWhitespace
= 0;
3035 cctxt
->inode
->preserveWhitespace
= 1;
3038 * Eval if we should keep the old incorrect behaviour.
3040 strictWhitespace
= (cctxt
->strict
!= 0) ? 1 : 0;
3042 nsNameXSLT
= xsltConstNamespaceNameXSLT
;
3046 while (cur
!= NULL
) {
3047 if (deleteNode
!= NULL
) {
3049 #ifdef WITH_XSLT_DEBUG_BLANKS
3050 xsltGenericDebug(xsltGenericDebugContext
,
3051 "xsltParsePreprocessStylesheetTree: removing node\n");
3053 xmlUnlinkNode(deleteNode
);
3054 xmlFreeNode(deleteNode
);
3057 if (cur
->type
== XML_ELEMENT_NODE
) {
3060 * Clear the PSVI field.
3064 xsltCompilerNodePush(cctxt
, cur
);
3069 cctxt
->inode
->stripWhitespace
= 0;
3071 * TODO: I'd love to use a string pointer comparison here :-/
3073 if (IS_XSLT_ELEM(cur
)) {
3074 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3075 if (cur
->ns
->href
!= nsNameXSLT
) {
3076 nsMapItem
= xsltNewNamespaceMapItem(cctxt
,
3078 if (nsMapItem
== NULL
)
3080 cur
->ns
->href
= nsNameXSLT
;
3084 if (cur
->name
== NULL
)
3085 goto process_attributes
;
3087 * Mark the XSLT element for later recognition.
3088 * TODO: Using the marker is still too dangerous, since if
3089 * the parsing mechanism leaves out an XSLT element, then
3090 * this might hit the transformation-mechanism, which
3091 * will break if it doesn't expect such a marker.
3093 /* cur->psvi = (void *) xsltXSLTElemMarker; */
3096 * XSLT 2.0: "Any whitespace text node whose parent is
3097 * one of the following elements is removed from the "
3098 * tree, regardless of any xml:space attributes:..."
3099 * xsl:apply-imports,
3100 * xsl:apply-templates,
3101 * xsl:attribute-set,
3102 * xsl:call-template,
3104 * xsl:stylesheet, xsl:transform.
3105 * XSLT 2.0: xsl:analyze-string,
3106 * xsl:character-map,
3109 * TODO: I'd love to use a string pointer comparison here :-/
3114 if ((name
[0] == 't') && (name
[1] == 'e') &&
3115 (name
[2] == 'x') && (name
[3] == 't') &&
3119 * Process the xsl:text element.
3120 * ----------------------------
3121 * Mark it for later recognition.
3123 cur
->psvi
= (void *) xsltXSLTTextMarker
;
3125 * For stylesheets, the set of
3126 * whitespace-preserving element names
3127 * consists of just xsl:text.
3130 cctxt
->inode
->preserveWhitespace
= 1;
3135 if (xmlStrEqual(name
, BAD_CAST
"choose") ||
3136 xmlStrEqual(name
, BAD_CAST
"call-template"))
3137 cctxt
->inode
->stripWhitespace
= 1;
3140 if (xmlStrEqual(name
, BAD_CAST
"apply-templates") ||
3141 xmlStrEqual(name
, BAD_CAST
"apply-imports") ||
3142 xmlStrEqual(name
, BAD_CAST
"attribute-set"))
3144 cctxt
->inode
->stripWhitespace
= 1;
3147 if (xsltStylesheetElemDepth
== cctxt
->depth
) {
3149 * This is a xsl:stylesheet/xsl:transform.
3151 cctxt
->inode
->stripWhitespace
= 1;
3155 if ((cur
->prev
!= NULL
) &&
3156 (cur
->prev
->type
== XML_TEXT_NODE
))
3159 * XSLT 2.0 : "Any whitespace text node whose
3160 * following-sibling node is an xsl:param or
3161 * xsl:sort element is removed from the tree,
3162 * regardless of any xml:space attributes."
3164 if (((*name
== 'p') || (*name
== 's')) &&
3165 (xmlStrEqual(name
, BAD_CAST
"param") ||
3166 xmlStrEqual(name
, BAD_CAST
"sort")))
3169 if (IS_BLANK_NODE(cur
->prev
)) {
3175 * This will result in a content
3176 * error, when hitting the parsing
3181 } while (cur
->prev
);
3190 * Process attributes.
3191 * ------------------
3193 if (cur
->properties
!= NULL
) {
3194 if (cur
->children
== NULL
)
3196 attr
= cur
->properties
;
3198 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3199 if ((attr
->ns
) && (attr
->ns
->href
!= nsNameXSLT
) &&
3200 xmlStrEqual(attr
->ns
->href
, nsNameXSLT
))
3202 nsMapItem
= xsltNewNamespaceMapItem(cctxt
,
3203 doc
, attr
->ns
, cur
);
3204 if (nsMapItem
== NULL
)
3206 attr
->ns
->href
= nsNameXSLT
;
3211 * Internalize the attribute's value; the goal is to
3212 * speed up operations and minimize used space by
3213 * compiled stylesheets.
3215 txt
= attr
->children
;
3217 * NOTE that this assumes only one
3218 * text-node in the attribute's content.
3220 if ((txt
!= NULL
) && (txt
->content
!= NULL
) &&
3221 (!xmlDictOwns(style
->dict
, txt
->content
)))
3223 value
= (xmlChar
*) xmlDictLookup(style
->dict
,
3225 xmlNodeSetContent(txt
, NULL
);
3226 txt
->content
= value
;
3230 * Process xml:space attributes.
3231 * ----------------------------
3233 if ((findSpaceAttr
!= 0) &&
3234 (attr
->ns
!= NULL
) &&
3235 (attr
->name
!= NULL
) &&
3236 (attr
->name
[0] == 's') &&
3237 (attr
->ns
->prefix
!= NULL
) &&
3238 (attr
->ns
->prefix
[0] == 'x') &&
3239 (attr
->ns
->prefix
[1] == 'm') &&
3240 (attr
->ns
->prefix
[2] == 'l') &&
3241 (attr
->ns
->prefix
[3] == 0))
3243 value
= xmlGetNsProp(cur
, BAD_CAST
"space",
3245 if (value
!= NULL
) {
3246 if (xmlStrEqual(value
, BAD_CAST
"preserve")) {
3247 cctxt
->inode
->preserveWhitespace
= 1;
3248 } else if (xmlStrEqual(value
, BAD_CAST
"default")) {
3249 cctxt
->inode
->preserveWhitespace
= 0;
3251 /* Invalid value for xml:space. */
3252 xsltTransformError(NULL
, style
, cur
,
3253 "Attribute xml:space: Invalid value.\n");
3254 cctxt
->style
->warnings
++;
3262 } while (attr
!= NULL
);
3265 * We'll descend into the children of element nodes only.
3267 if (cur
->children
!= NULL
) {
3268 cur
= cur
->children
;
3271 } else if ((cur
->type
== XML_TEXT_NODE
) ||
3272 (cur
->type
== XML_CDATA_SECTION_NODE
))
3275 * Merge adjacent text/CDATA-section-nodes
3276 * ---------------------------------------
3277 * In order to avoid breaking of existing stylesheets,
3278 * if the old behaviour is wanted (strictWhitespace == 0),
3279 * then we *won't* merge adjacent text-nodes
3280 * (except in xsl:text); this will ensure that whitespace-only
3281 * text nodes are (incorrectly) not stripped in some cases.
3283 * Example: : <foo> <!-- bar -->zoo</foo>
3284 * Corrent (strict) result: <foo> zoo</foo>
3285 * Incorrect (old) result : <foo>zoo</foo>
3287 * NOTE that we *will* merge adjacent text-nodes if
3288 * they are in xsl:text.
3289 * Example, the following:
3290 * <xsl:text> <!-- bar -->zoo<xsl:text>
3291 * will result in both cases in:
3292 * <xsl:text> zoo<xsl:text>
3294 cur
->type
= XML_TEXT_NODE
;
3295 if ((strictWhitespace
!= 0) || (inXSLText
!= 0)) {
3297 * New behaviour; merge nodes.
3299 if (textNode
== NULL
)
3302 if (cur
->content
!= NULL
)
3303 xmlNodeAddContent(textNode
, cur
->content
);
3306 if ((cur
->next
== NULL
) ||
3307 (cur
->next
->type
== XML_ELEMENT_NODE
))
3315 if (textNode
== NULL
)
3319 } else if ((cur
->type
== XML_COMMENT_NODE
) ||
3320 (cur
->type
== XML_PI_NODE
))
3323 * Remove processing instructions and comments.
3326 if ((cur
->next
== NULL
) ||
3327 (cur
->next
->type
== XML_ELEMENT_NODE
))
3334 * Invalid node-type for this data-model.
3336 xsltTransformError(NULL
, style
, cur
,
3337 "Invalid type of node for the XSLT data model.\n");
3338 cctxt
->style
->errors
++;
3344 value
= textNode
->content
;
3346 * At this point all adjacent text/CDATA-section nodes
3349 * Strip whitespace-only text-nodes.
3350 * (cctxt->inode->stripWhitespace)
3352 if ((value
== NULL
) || (*value
== 0) ||
3353 (((cctxt
->inode
->stripWhitespace
) ||
3354 (! cctxt
->inode
->preserveWhitespace
)) &&
3356 xsltIsBlank(value
)))
3358 if (textNode
!= cur
) {
3359 xmlUnlinkNode(textNode
);
3360 xmlFreeNode(textNode
);
3362 deleteNode
= textNode
;
3367 * Convert CDATA-section nodes to text-nodes.
3368 * TODO: Can this produce problems?
3370 if (textNode
->type
!= XML_TEXT_NODE
) {
3371 textNode
->type
= XML_TEXT_NODE
;
3372 textNode
->name
= xmlStringText
;
3375 (textNode
->content
!= NULL
) &&
3376 (!xmlDictOwns(style
->dict
, textNode
->content
)))
3379 * Internalize the string.
3381 value
= (xmlChar
*) xmlDictLookup(style
->dict
,
3382 textNode
->content
, -1);
3383 xmlNodeSetContent(textNode
, NULL
);
3384 textNode
->content
= value
;
3388 * Note that "disable-output-escaping" of the xsl:text
3389 * element will be applied at a later level, when
3390 * XSLT elements are processed.
3395 if (cur
->type
== XML_ELEMENT_NODE
) {
3396 xsltCompilerNodePop(cctxt
, cur
);
3400 if (cur
->next
!= NULL
) {
3408 if (deleteNode
!= NULL
) {
3409 #ifdef WITH_XSLT_DEBUG_PARSING
3410 xsltGenericDebug(xsltGenericDebugContext
,
3411 "xsltParsePreprocessStylesheetTree: removing node\n");
3413 xmlUnlinkNode(deleteNode
);
3414 xmlFreeNode(deleteNode
);
3422 #endif /* XSLT_REFACTORED */
3424 #ifdef XSLT_REFACTORED
3427 xsltPrecomputeStylesheet(xsltStylesheetPtr style
, xmlNodePtr cur
)
3429 xmlNodePtr deleteNode
, styleelem
;
3430 int internalize
= 0;
3432 if ((style
== NULL
) || (cur
== NULL
))
3435 if ((cur
->doc
!= NULL
) && (style
->dict
!= NULL
) &&
3436 (cur
->doc
->dict
== style
->dict
))
3439 style
->internalized
= 0;
3441 if ((cur
!= NULL
) && (IS_XSLT_ELEM(cur
)) &&
3442 (IS_XSLT_NAME(cur
, "stylesheet"))) {
3449 * This content comes from the stylesheet
3450 * For stylesheets, the set of whitespace-preserving
3451 * element names consists of just xsl:text.
3454 while (cur
!= NULL
) {
3455 if (deleteNode
!= NULL
) {
3456 #ifdef WITH_XSLT_DEBUG_BLANKS
3457 xsltGenericDebug(xsltGenericDebugContext
,
3458 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
3460 xmlUnlinkNode(deleteNode
);
3461 xmlFreeNode(deleteNode
);
3464 if (cur
->type
== XML_ELEMENT_NODE
) {
3467 * Internalize attributes values.
3469 if ((internalize
) && (cur
->properties
!= NULL
)) {
3470 xmlAttrPtr attr
= cur
->properties
;
3473 while (attr
!= NULL
) {
3474 txt
= attr
->children
;
3475 if ((txt
!= NULL
) && (txt
->type
== XML_TEXT_NODE
) &&
3476 (txt
->content
!= NULL
) &&
3477 (!xmlDictOwns(style
->dict
, txt
->content
)))
3482 * internalize the text string, goal is to speed
3483 * up operations and minimize used space by compiled
3486 tmp
= (xmlChar
*) xmlDictLookup(style
->dict
,
3488 if (tmp
!= txt
->content
) {
3489 xmlNodeSetContent(txt
, NULL
);
3496 if (IS_XSLT_ELEM(cur
)) {
3498 xsltStylePreCompute(style
, cur
);
3499 if (IS_XSLT_NAME(cur
, "text")) {
3500 for (;exclPrefixes
> 0;exclPrefixes
--)
3501 exclPrefixPop(style
);
3505 exclPrefixes
= xsltParseStylesheetExcludePrefix(style
, cur
, 0);
3508 if ((cur
->nsDef
!= NULL
) && (style
->exclPrefixNr
> 0)) {
3509 xmlNsPtr ns
= cur
->nsDef
, prev
= NULL
, next
;
3510 xmlNodePtr root
= NULL
;
3513 root
= xmlDocGetRootElement(cur
->doc
);
3514 if ((root
!= NULL
) && (root
!= cur
)) {
3515 while (ns
!= NULL
) {
3518 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
3519 if ((ns
->prefix
!= NULL
) &&
3520 (xmlStrEqual(ns
->href
,
3521 style
->exclPrefixTab
[i
]))) {
3523 * Move the namespace definition on the root
3524 * element to avoid duplicating it without
3528 cur
->nsDef
= ns
->next
;
3530 prev
->next
= ns
->next
;
3532 ns
->next
= root
->nsDef
;
3545 * If we have prefixes locally, recurse and pop them up when
3548 if (exclPrefixes
> 0) {
3549 xsltPrecomputeStylesheet(style
, cur
->children
);
3550 for (;exclPrefixes
> 0;exclPrefixes
--)
3551 exclPrefixPop(style
);
3554 } else if (cur
->type
== XML_TEXT_NODE
) {
3555 if (IS_BLANK_NODE(cur
)) {
3556 if (xmlNodeGetSpacePreserve(cur
) != 1) {
3559 } else if ((cur
->content
!= NULL
) && (internalize
) &&
3560 (!xmlDictOwns(style
->dict
, cur
->content
))) {
3564 * internalize the text string, goal is to speed
3565 * up operations and minimize used space by compiled
3568 tmp
= (xmlChar
*) xmlDictLookup(style
->dict
, cur
->content
, -1);
3569 xmlNodeSetContent(cur
, NULL
);
3572 } else if ((cur
->type
!= XML_ELEMENT_NODE
) &&
3573 (cur
->type
!= XML_CDATA_SECTION_NODE
)) {
3579 * Skip to next node. In case of a namespaced element children of
3580 * the stylesheet and not in the XSLT namespace and not an extension
3581 * element, ignore its content.
3583 if ((cur
->type
== XML_ELEMENT_NODE
) && (cur
->ns
!= NULL
) &&
3584 (styleelem
!= NULL
) && (cur
->parent
== styleelem
) &&
3585 (!xmlStrEqual(cur
->ns
->href
, XSLT_NAMESPACE
)) &&
3586 (!xsltCheckExtURI(style
, cur
->ns
->href
))) {
3588 } else if (cur
->children
!= NULL
) {
3589 if ((cur
->children
->type
!= XML_ENTITY_DECL
) &&
3590 (cur
->children
->type
!= XML_ENTITY_REF_NODE
) &&
3591 (cur
->children
->type
!= XML_ENTITY_NODE
)) {
3592 cur
= cur
->children
;
3598 if (cur
->next
!= NULL
) {
3607 if (cur
== (xmlNodePtr
) style
->doc
) {
3611 if (cur
->next
!= NULL
) {
3615 } while (cur
!= NULL
);
3617 if (deleteNode
!= NULL
) {
3618 #ifdef WITH_XSLT_DEBUG_PARSING
3619 xsltGenericDebug(xsltGenericDebugContext
,
3620 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
3622 xmlUnlinkNode(deleteNode
);
3623 xmlFreeNode(deleteNode
);
3626 #endif /* end of else XSLT_REFACTORED */
3629 * xsltGatherNamespaces:
3630 * @style: the XSLT stylesheet
3632 * Browse the stylesheet and build the namspace hash table which
3633 * will be used for XPath interpretation. If needed do a bit of normalization
3637 xsltGatherNamespaces(xsltStylesheetPtr style
) {
3644 * TODO: basically if the stylesheet uses the same prefix for different
3645 * patterns, well they may be in problem, hopefully they will get
3649 * TODO: Eliminate the use of the hash for XPath expressions.
3650 * An expression should be evaluated in the context of the in-scope
3651 * namespaces; eliminate the restriction of an XML document to contain
3652 * no duplicate prefixes for different namespace names.
3655 cur
= xmlDocGetRootElement(style
->doc
);
3656 while (cur
!= NULL
) {
3657 if (cur
->type
== XML_ELEMENT_NODE
) {
3658 xmlNsPtr ns
= cur
->nsDef
;
3659 while (ns
!= NULL
) {
3660 if (ns
->prefix
!= NULL
) {
3661 if (style
->nsHash
== NULL
) {
3662 style
->nsHash
= xmlHashCreate(10);
3663 if (style
->nsHash
== NULL
) {
3664 xsltTransformError(NULL
, style
, cur
,
3665 "xsltGatherNamespaces: failed to create hash table\n");
3670 URI
= xmlHashLookup(style
->nsHash
, ns
->prefix
);
3671 if ((URI
!= NULL
) && (!xmlStrEqual(URI
, ns
->href
))) {
3672 xsltTransformError(NULL
, style
, cur
,
3673 "Namespaces prefix %s used for multiple namespaces\n",ns
->prefix
);
3675 } else if (URI
== NULL
) {
3676 xmlHashUpdateEntry(style
->nsHash
, ns
->prefix
,
3677 (void *) ns
->href
, (xmlHashDeallocator
)xmlFree
);
3679 #ifdef WITH_XSLT_DEBUG_PARSING
3680 xsltGenericDebug(xsltGenericDebugContext
,
3681 "Added namespace: %s mapped to %s\n", ns
->prefix
, ns
->href
);
3692 if (cur
->children
!= NULL
) {
3693 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
3694 cur
= cur
->children
;
3698 if (cur
->next
!= NULL
) {
3707 if (cur
== (xmlNodePtr
) style
->doc
) {
3711 if (cur
->next
!= NULL
) {
3715 } while (cur
!= NULL
);
3719 #ifdef XSLT_REFACTORED
3721 static xsltStyleType
3722 xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt
,
3725 if ((node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
) ||
3726 (node
->name
== NULL
))
3729 if (node
->name
[0] == 'a') {
3730 if (IS_XSLT_NAME(node
, "apply-templates"))
3731 return(XSLT_FUNC_APPLYTEMPLATES
);
3732 else if (IS_XSLT_NAME(node
, "attribute"))
3733 return(XSLT_FUNC_ATTRIBUTE
);
3734 else if (IS_XSLT_NAME(node
, "apply-imports"))
3735 return(XSLT_FUNC_APPLYIMPORTS
);
3736 else if (IS_XSLT_NAME(node
, "attribute-set"))
3739 } else if (node
->name
[0] == 'c') {
3740 if (IS_XSLT_NAME(node
, "choose"))
3741 return(XSLT_FUNC_CHOOSE
);
3742 else if (IS_XSLT_NAME(node
, "copy"))
3743 return(XSLT_FUNC_COPY
);
3744 else if (IS_XSLT_NAME(node
, "copy-of"))
3745 return(XSLT_FUNC_COPYOF
);
3746 else if (IS_XSLT_NAME(node
, "call-template"))
3747 return(XSLT_FUNC_CALLTEMPLATE
);
3748 else if (IS_XSLT_NAME(node
, "comment"))
3749 return(XSLT_FUNC_COMMENT
);
3751 } else if (node
->name
[0] == 'd') {
3752 if (IS_XSLT_NAME(node
, "document"))
3753 return(XSLT_FUNC_DOCUMENT
);
3754 else if (IS_XSLT_NAME(node
, "decimal-format"))
3757 } else if (node
->name
[0] == 'e') {
3758 if (IS_XSLT_NAME(node
, "element"))
3759 return(XSLT_FUNC_ELEMENT
);
3761 } else if (node
->name
[0] == 'f') {
3762 if (IS_XSLT_NAME(node
, "for-each"))
3763 return(XSLT_FUNC_FOREACH
);
3764 else if (IS_XSLT_NAME(node
, "fallback"))
3765 return(XSLT_FUNC_FALLBACK
);
3767 } else if (*(node
->name
) == 'i') {
3768 if (IS_XSLT_NAME(node
, "if"))
3769 return(XSLT_FUNC_IF
);
3770 else if (IS_XSLT_NAME(node
, "include"))
3772 else if (IS_XSLT_NAME(node
, "import"))
3775 } else if (*(node
->name
) == 'k') {
3776 if (IS_XSLT_NAME(node
, "key"))
3779 } else if (*(node
->name
) == 'm') {
3780 if (IS_XSLT_NAME(node
, "message"))
3781 return(XSLT_FUNC_MESSAGE
);
3783 } else if (*(node
->name
) == 'n') {
3784 if (IS_XSLT_NAME(node
, "number"))
3785 return(XSLT_FUNC_NUMBER
);
3786 else if (IS_XSLT_NAME(node
, "namespace-alias"))
3789 } else if (*(node
->name
) == 'o') {
3790 if (IS_XSLT_NAME(node
, "otherwise"))
3791 return(XSLT_FUNC_OTHERWISE
);
3792 else if (IS_XSLT_NAME(node
, "output"))
3795 } else if (*(node
->name
) == 'p') {
3796 if (IS_XSLT_NAME(node
, "param"))
3797 return(XSLT_FUNC_PARAM
);
3798 else if (IS_XSLT_NAME(node
, "processing-instruction"))
3799 return(XSLT_FUNC_PI
);
3800 else if (IS_XSLT_NAME(node
, "preserve-space"))
3803 } else if (*(node
->name
) == 's') {
3804 if (IS_XSLT_NAME(node
, "sort"))
3805 return(XSLT_FUNC_SORT
);
3806 else if (IS_XSLT_NAME(node
, "strip-space"))
3808 else if (IS_XSLT_NAME(node
, "stylesheet"))
3811 } else if (node
->name
[0] == 't') {
3812 if (IS_XSLT_NAME(node
, "text"))
3813 return(XSLT_FUNC_TEXT
);
3814 else if (IS_XSLT_NAME(node
, "template"))
3816 else if (IS_XSLT_NAME(node
, "transform"))
3819 } else if (*(node
->name
) == 'v') {
3820 if (IS_XSLT_NAME(node
, "value-of"))
3821 return(XSLT_FUNC_VALUEOF
);
3822 else if (IS_XSLT_NAME(node
, "variable"))
3823 return(XSLT_FUNC_VARIABLE
);
3825 } else if (*(node
->name
) == 'w') {
3826 if (IS_XSLT_NAME(node
, "when"))
3827 return(XSLT_FUNC_WHEN
);
3828 if (IS_XSLT_NAME(node
, "with-param"))
3829 return(XSLT_FUNC_WITHPARAM
);
3835 * xsltParseAnyXSLTElem:
3837 * @cctxt: the compilation context
3838 * @elem: the element node of the XSLT instruction
3840 * Parses, validates the content models and compiles XSLT instructions.
3842 * Returns 0 if everything's fine;
3843 * -1 on API or internal errors.
3846 xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr elem
)
3848 if ((cctxt
== NULL
) || (elem
== NULL
) ||
3849 (elem
->type
!= XML_ELEMENT_NODE
))
3854 if (! (IS_XSLT_ELEM_FAST(elem
)))
3857 * Detection of handled content of extension instructions.
3859 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
3860 cctxt
->inode
->extContentHandled
= 1;
3863 xsltCompilerNodePush(cctxt
, elem
);
3865 * URGENT TODO: Find a way to speed up this annoying redundant
3866 * textual node-name and namespace comparison.
3868 if (cctxt
->inode
->prev
->curChildType
!= 0)
3869 cctxt
->inode
->type
= cctxt
->inode
->prev
->curChildType
;
3871 cctxt
->inode
->type
= xsltGetXSLTElementTypeByNode(cctxt
, elem
);
3873 * Update the in-scope namespaces if needed.
3875 if (elem
->nsDef
!= NULL
)
3876 cctxt
->inode
->inScopeNs
=
3877 xsltCompilerBuildInScopeNsList(cctxt
, elem
);
3879 * xsltStylePreCompute():
3880 * This will compile the information found on the current
3881 * element's attributes. NOTE that this won't process the
3882 * children of the instruction.
3884 xsltStylePreCompute(cctxt
->style
, elem
);
3886 * TODO: How to react on errors in xsltStylePreCompute() ?
3890 * Validate the content model of the XSLT-element.
3892 switch (cctxt
->inode
->type
) {
3893 case XSLT_FUNC_APPLYIMPORTS
:
3896 case XSLT_FUNC_APPLYTEMPLATES
:
3897 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
3898 goto apply_templates
;
3899 case XSLT_FUNC_ATTRIBUTE
:
3900 /* <!-- Content: template --> */
3901 goto sequence_constructor
;
3902 case XSLT_FUNC_CALLTEMPLATE
:
3903 /* <!-- Content: xsl:with-param* --> */
3905 case XSLT_FUNC_CHOOSE
:
3906 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
3908 case XSLT_FUNC_COMMENT
:
3909 /* <!-- Content: template --> */
3910 goto sequence_constructor
;
3911 case XSLT_FUNC_COPY
:
3912 /* <!-- Content: template --> */
3913 goto sequence_constructor
;
3914 case XSLT_FUNC_COPYOF
:
3917 case XSLT_FUNC_DOCUMENT
: /* Extra one */
3918 /* ?? template ?? */
3919 goto sequence_constructor
;
3920 case XSLT_FUNC_ELEMENT
:
3921 /* <!-- Content: template --> */
3922 goto sequence_constructor
;
3923 case XSLT_FUNC_FALLBACK
:
3924 /* <!-- Content: template --> */
3925 goto sequence_constructor
;
3926 case XSLT_FUNC_FOREACH
:
3927 /* <!-- Content: (xsl:sort*, template) --> */
3930 /* <!-- Content: template --> */
3931 goto sequence_constructor
;
3932 case XSLT_FUNC_OTHERWISE
:
3933 /* <!-- Content: template --> */
3934 goto sequence_constructor
;
3935 case XSLT_FUNC_MESSAGE
:
3936 /* <!-- Content: template --> */
3937 goto sequence_constructor
;
3938 case XSLT_FUNC_NUMBER
:
3941 case XSLT_FUNC_PARAM
:
3943 * Check for redefinition.
3945 if ((elem
->psvi
!= NULL
) && (cctxt
->ivar
!= NULL
)) {
3946 xsltVarInfoPtr ivar
= cctxt
->ivar
;
3950 ((xsltStyleItemParamPtr
) elem
->psvi
)->name
) &&
3952 ((xsltStyleItemParamPtr
) elem
->psvi
)->ns
))
3955 xsltTransformError(NULL
, cctxt
->style
, elem
,
3956 "Redefinition of variable or parameter '%s'.\n",
3958 cctxt
->style
->errors
++;
3962 } while (ivar
!= NULL
);
3964 /* <!-- Content: template --> */
3965 goto sequence_constructor
;
3967 /* <!-- Content: template --> */
3968 goto sequence_constructor
;
3969 case XSLT_FUNC_SORT
:
3972 case XSLT_FUNC_TEXT
:
3973 /* <!-- Content: #PCDATA --> */
3975 case XSLT_FUNC_VALUEOF
:
3978 case XSLT_FUNC_VARIABLE
:
3980 * Check for redefinition.
3982 if ((elem
->psvi
!= NULL
) && (cctxt
->ivar
!= NULL
)) {
3983 xsltVarInfoPtr ivar
= cctxt
->ivar
;
3987 ((xsltStyleItemVariablePtr
) elem
->psvi
)->name
) &&
3989 ((xsltStyleItemVariablePtr
) elem
->psvi
)->ns
))
3992 xsltTransformError(NULL
, cctxt
->style
, elem
,
3993 "Redefinition of variable or parameter '%s'.\n",
3995 cctxt
->style
->errors
++;
3999 } while (ivar
!= NULL
);
4001 /* <!-- Content: template --> */
4002 goto sequence_constructor
;
4003 case XSLT_FUNC_WHEN
:
4004 /* <!-- Content: template --> */
4005 goto sequence_constructor
;
4006 case XSLT_FUNC_WITHPARAM
:
4007 /* <!-- Content: template --> */
4008 goto sequence_constructor
;
4010 #ifdef WITH_XSLT_DEBUG_PARSING
4011 xsltGenericDebug(xsltGenericDebugContext
,
4012 "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
4015 xsltTransformError(NULL
, cctxt
->style
, elem
,
4016 "xsltParseXSLTNode: Internal error; "
4017 "unhandled XSLT element '%s'.\n", elem
->name
);
4018 cctxt
->style
->errors
++;
4023 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
4024 if (elem
->children
!= NULL
) {
4025 xmlNodePtr child
= elem
->children
;
4027 if (child
->type
== XML_ELEMENT_NODE
) {
4028 if (IS_XSLT_ELEM_FAST(child
)) {
4029 if (xmlStrEqual(child
->name
, BAD_CAST
"with-param")) {
4030 cctxt
->inode
->curChildType
= XSLT_FUNC_WITHPARAM
;
4031 xsltParseAnyXSLTElem(cctxt
, child
);
4032 } else if (xmlStrEqual(child
->name
, BAD_CAST
"sort")) {
4033 cctxt
->inode
->curChildType
= XSLT_FUNC_SORT
;
4034 xsltParseAnyXSLTElem(cctxt
, child
);
4036 xsltParseContentError(cctxt
->style
, child
);
4038 xsltParseContentError(cctxt
->style
, child
);
4040 child
= child
->next
;
4041 } while (child
!= NULL
);
4046 /* <!-- Content: xsl:with-param* --> */
4047 if (elem
->children
!= NULL
) {
4048 xmlNodePtr child
= elem
->children
;
4050 if (child
->type
== XML_ELEMENT_NODE
) {
4051 if (IS_XSLT_ELEM_FAST(child
)) {
4054 type
= xsltGetXSLTElementTypeByNode(cctxt
, child
);
4055 if (type
== XSLT_FUNC_WITHPARAM
) {
4056 cctxt
->inode
->curChildType
= XSLT_FUNC_WITHPARAM
;
4057 xsltParseAnyXSLTElem(cctxt
, child
);
4059 xsltParseContentError(cctxt
->style
, child
);
4062 xsltParseContentError(cctxt
->style
, child
);
4064 child
= child
->next
;
4065 } while (child
!= NULL
);
4070 if (elem
->children
!= NULL
) {
4071 xmlNodePtr child
= elem
->children
;
4073 if ((child
->type
!= XML_TEXT_NODE
) &&
4074 (child
->type
!= XML_CDATA_SECTION_NODE
))
4076 xsltTransformError(NULL
, cctxt
->style
, elem
,
4077 "The XSLT 'text' element must have only character "
4078 "data as content.\n");
4080 child
= child
->next
;
4081 } while (child
!= NULL
);
4086 if (elem
->children
!= NULL
) {
4087 xmlNodePtr child
= elem
->children
;
4089 * Relaxed behaviour: we will allow whitespace-only text-nodes.
4092 if (((child
->type
!= XML_TEXT_NODE
) &&
4093 (child
->type
!= XML_CDATA_SECTION_NODE
)) ||
4094 (! IS_BLANK_NODE(child
)))
4096 xsltTransformError(NULL
, cctxt
->style
, elem
,
4097 "This XSLT element must have no content.\n");
4098 cctxt
->style
->errors
++;
4101 child
= child
->next
;
4102 } while (child
!= NULL
);
4107 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
4109 * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
4110 * The old behaviour did not check this.
4111 * NOTE: In XSLT 2.0 they are stripped beforehand
4112 * if whitespace-only (regardless of xml:space).
4114 if (elem
->children
!= NULL
) {
4115 xmlNodePtr child
= elem
->children
;
4116 int nbWhen
= 0, nbOtherwise
= 0, err
= 0;
4118 if (child
->type
== XML_ELEMENT_NODE
) {
4119 if (IS_XSLT_ELEM_FAST(child
)) {
4122 type
= xsltGetXSLTElementTypeByNode(cctxt
, child
);
4123 if (type
== XSLT_FUNC_WHEN
) {
4126 xsltParseContentError(cctxt
->style
, child
);
4130 cctxt
->inode
->curChildType
= XSLT_FUNC_WHEN
;
4131 xsltParseAnyXSLTElem(cctxt
, child
);
4132 } else if (type
== XSLT_FUNC_OTHERWISE
) {
4134 xsltParseContentError(cctxt
->style
, child
);
4139 xsltTransformError(NULL
, cctxt
->style
, elem
,
4140 "The XSLT 'choose' element must not contain "
4141 "more than one XSLT 'otherwise' element.\n");
4142 cctxt
->style
->errors
++;
4147 cctxt
->inode
->curChildType
= XSLT_FUNC_OTHERWISE
;
4148 xsltParseAnyXSLTElem(cctxt
, child
);
4150 xsltParseContentError(cctxt
->style
, child
);
4152 xsltParseContentError(cctxt
->style
, child
);
4156 xsltParseContentError(cctxt, child);
4158 child
= child
->next
;
4159 } while (child
!= NULL
);
4160 if ((! err
) && (! nbWhen
)) {
4161 xsltTransformError(NULL
, cctxt
->style
, elem
,
4162 "The XSLT element 'choose' must contain at least one "
4163 "XSLT element 'when'.\n");
4164 cctxt
->style
->errors
++;
4170 /* <!-- Content: (xsl:sort*, template) --> */
4172 * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
4173 * The old behaviour did not allow this, but it catched this
4174 * only at transformation-time.
4175 * In XSLT 2.0 they are stripped beforehand if whitespace-only
4176 * (regardless of xml:space).
4178 if (elem
->children
!= NULL
) {
4179 xmlNodePtr child
= elem
->children
;
4181 * Parse xsl:sort first.
4184 if ((child
->type
== XML_ELEMENT_NODE
) &&
4185 IS_XSLT_ELEM_FAST(child
))
4187 if (xsltGetXSLTElementTypeByNode(cctxt
, child
) ==
4190 cctxt
->inode
->curChildType
= XSLT_FUNC_SORT
;
4191 xsltParseAnyXSLTElem(cctxt
, child
);
4196 child
= child
->next
;
4197 } while (child
!= NULL
);
4199 * Parse the sequece constructor.
4202 xsltParseSequenceConstructor(cctxt
, child
);
4206 sequence_constructor
:
4208 * Parse the sequence constructor.
4210 if (elem
->children
!= NULL
)
4211 xsltParseSequenceConstructor(cctxt
, elem
->children
);
4214 * Register information for vars/params. Only needed if there
4215 * are any following siblings.
4217 if ((elem
->next
!= NULL
) &&
4218 ((cctxt
->inode
->type
== XSLT_FUNC_VARIABLE
) ||
4219 (cctxt
->inode
->type
== XSLT_FUNC_PARAM
)))
4221 if ((elem
->psvi
!= NULL
) &&
4222 (((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->name
))
4224 xsltCompilerVarInfoPush(cctxt
, elem
,
4225 ((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->name
,
4226 ((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->ns
);
4232 xsltCompilerNodePop(cctxt
, elem
);
4236 xsltCompilerNodePop(cctxt
, elem
);
4241 * xsltForwardsCompatUnkownItemCreate:
4243 * @cctxt: the compilation context
4245 * Creates a compiled representation of the unknown
4248 * Returns the compiled representation.
4250 static xsltStyleItemUknownPtr
4251 xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt
)
4253 xsltStyleItemUknownPtr item
;
4255 item
= (xsltStyleItemUknownPtr
) xmlMalloc(sizeof(xsltStyleItemUknown
));
4257 xsltTransformError(NULL
, cctxt
->style
, NULL
,
4258 "Internal error in xsltForwardsCompatUnkownItemCreate(): "
4259 "Failed to allocate memory.\n");
4260 cctxt
->style
->errors
++;
4263 memset(item
, 0, sizeof(xsltStyleItemUknown
));
4264 item
->type
= XSLT_FUNC_UNKOWN_FORWARDS_COMPAT
;
4266 * Store it in the stylesheet.
4268 item
->next
= cctxt
->style
->preComps
;
4269 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
4274 * xsltParseUnknownXSLTElem:
4276 * @cctxt: the compilation context
4277 * @node: the element of the unknown XSLT instruction
4279 * Parses an unknown XSLT element.
4280 * If forwards compatible mode is enabled this will allow
4281 * such an unknown XSLT and; otherwise it is rejected.
4283 * Returns 1 in the unknown XSLT instruction is rejected,
4284 * 0 if everything's fine and
4285 * -1 on API or internal errors.
4288 xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt
,
4291 if ((cctxt
== NULL
) || (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
4295 * Detection of handled content of extension instructions.
4297 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4298 cctxt
->inode
->extContentHandled
= 1;
4300 if (cctxt
->inode
->forwardsCompat
== 0) {
4302 * We are not in forwards-compatible mode, so raise an error.
4304 xsltTransformError(NULL
, cctxt
->style
, node
,
4305 "Unknown XSLT element '%s'.\n", node
->name
);
4306 cctxt
->style
->errors
++;
4310 * Forwards-compatible mode.
4311 * ------------------------
4313 * Parse/compile xsl:fallback elements.
4315 * QUESTION: Do we have to raise an error if there's no xsl:fallback?
4316 * ANSWER: No, since in the stylesheet the fallback behaviour might
4317 * also be provided by using the XSLT function "element-available".
4319 if (cctxt
->unknownItem
== NULL
) {
4321 * Create a singleton for all unknown XSLT instructions.
4323 cctxt
->unknownItem
= xsltForwardsCompatUnkownItemCreate(cctxt
);
4324 if (cctxt
->unknownItem
== NULL
) {
4329 node
->psvi
= cctxt
->unknownItem
;
4330 if (node
->children
== NULL
)
4333 xmlNodePtr child
= node
->children
;
4335 xsltCompilerNodePush(cctxt
, node
);
4337 * Update the in-scope namespaces if needed.
4339 if (node
->nsDef
!= NULL
)
4340 cctxt
->inode
->inScopeNs
=
4341 xsltCompilerBuildInScopeNsList(cctxt
, node
);
4343 * Parse all xsl:fallback children.
4346 if ((child
->type
== XML_ELEMENT_NODE
) &&
4347 IS_XSLT_ELEM_FAST(child
) &&
4348 IS_XSLT_NAME(child
, "fallback"))
4350 cctxt
->inode
->curChildType
= XSLT_FUNC_FALLBACK
;
4351 xsltParseAnyXSLTElem(cctxt
, child
);
4353 child
= child
->next
;
4354 } while (child
!= NULL
);
4356 xsltCompilerNodePop(cctxt
, node
);
4362 * xsltParseSequenceConstructor:
4364 * @cctxt: the compilation context
4365 * @cur: the start-node of the content to be parsed
4367 * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
4368 * This will additionally remove xsl:text elements from the tree.
4371 xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt
, xmlNodePtr cur
)
4374 xmlNodePtr deleteNode
= NULL
;
4376 if (cctxt
== NULL
) {
4377 xmlGenericError(xmlGenericErrorContext
,
4378 "xsltParseSequenceConstructor: Bad arguments\n");
4379 cctxt
->style
->errors
++;
4383 * Detection of handled content of extension instructions.
4385 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4386 cctxt
->inode
->extContentHandled
= 1;
4388 if ((cur
== NULL
) || (cur
->type
== XML_NAMESPACE_DECL
))
4391 * This is the content reffered to as a "template".
4392 * E.g. an xsl:element has such content model:
4395 * namespace = { uri-reference }
4396 * use-attribute-sets = qnames>
4397 * <!-- Content: template -->
4399 * NOTE that in XSLT-2 the term "template" was abandoned due to
4400 * confusion with xsl:template and the term "sequence constructor"
4401 * was introduced instead.
4403 * The following XSLT-instructions are allowed to appear:
4404 * xsl:apply-templates, xsl:call-template, xsl:apply-imports,
4405 * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
4406 * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
4407 * xsl:message, xsl:fallback,
4408 * xsl:processing-instruction, xsl:comment, xsl:element
4410 * Additional allowed content:
4411 * 1) extension instructions
4412 * 2) literal result elements
4415 * NOTE that this content model does *not* allow xsl:param.
4417 while (cur
!= NULL
) {
4418 if (deleteNode
!= NULL
) {
4419 #ifdef WITH_XSLT_DEBUG_BLANKS
4420 xsltGenericDebug(xsltGenericDebugContext
,
4421 "xsltParseSequenceConstructor: removing xsl:text element\n");
4423 xmlUnlinkNode(deleteNode
);
4424 xmlFreeNode(deleteNode
);
4427 if (cur
->type
== XML_ELEMENT_NODE
) {
4429 if (cur
->psvi
== xsltXSLTTextMarker
) {
4432 * --------------------------------------------------------
4438 * Mark the xsl:text element for later deletion.
4444 tmp
= cur
->children
;
4447 * We don't expect more than one text-node in the
4448 * content, since we already merged adjacent
4449 * text/CDATA-nodes and eliminated PI/comment-nodes.
4451 if ((tmp
->type
== XML_TEXT_NODE
) ||
4452 (tmp
->next
== NULL
))
4455 * Leave the contained text-node in the tree.
4458 xmlAddPrevSibling(cur
, tmp
);
4461 xsltTransformError(NULL
, cctxt
->style
, cur
,
4462 "Element 'xsl:text': Invalid type "
4463 "of node found in content.\n");
4464 cctxt
->style
->errors
++;
4467 if (cur
->properties
) {
4470 * TODO: We need to report errors for
4473 attr
= cur
->properties
;
4475 if ((attr
->ns
== NULL
) &&
4476 (attr
->name
!= NULL
) &&
4477 (attr
->name
[0] == 'd') &&
4478 xmlStrEqual(attr
->name
,
4479 BAD_CAST
"disable-output-escaping"))
4482 * Attr "disable-output-escaping".
4483 * XSLT-2: This attribute is deprecated.
4485 if ((attr
->children
!= NULL
) &&
4486 xmlStrEqual(attr
->children
->content
,
4490 * Disable output escaping for this
4494 tmp
->name
= xmlStringTextNoenc
;
4495 } else if ((attr
->children
== NULL
) ||
4496 (attr
->children
->content
== NULL
) ||
4497 (!xmlStrEqual(attr
->children
->content
,
4500 xsltTransformError(NULL
, cctxt
->style
,
4502 "Attribute 'disable-output-escaping': "
4503 "Invalid value. Expected is "
4504 "'yes' or 'no'.\n");
4505 cctxt
->style
->errors
++;
4510 } while (attr
!= NULL
);
4512 } else if (IS_XSLT_ELEM_FAST(cur
)) {
4514 * TODO: Using the XSLT-marker is still not stable yet.
4516 /* if (cur->psvi == xsltXSLTElemMarker) { */
4519 * --------------------------------------------------------
4522 type
= xsltGetXSLTElementTypeByNode(cctxt
, cur
);
4524 case XSLT_FUNC_APPLYIMPORTS
:
4525 case XSLT_FUNC_APPLYTEMPLATES
:
4526 case XSLT_FUNC_ATTRIBUTE
:
4527 case XSLT_FUNC_CALLTEMPLATE
:
4528 case XSLT_FUNC_CHOOSE
:
4529 case XSLT_FUNC_COMMENT
:
4530 case XSLT_FUNC_COPY
:
4531 case XSLT_FUNC_COPYOF
:
4532 case XSLT_FUNC_DOCUMENT
: /* Extra one */
4533 case XSLT_FUNC_ELEMENT
:
4534 case XSLT_FUNC_FALLBACK
:
4535 case XSLT_FUNC_FOREACH
:
4537 case XSLT_FUNC_MESSAGE
:
4538 case XSLT_FUNC_NUMBER
:
4540 case XSLT_FUNC_TEXT
:
4541 case XSLT_FUNC_VALUEOF
:
4542 case XSLT_FUNC_VARIABLE
:
4544 * Parse the XSLT element.
4546 cctxt
->inode
->curChildType
= type
;
4547 xsltParseAnyXSLTElem(cctxt
, cur
);
4550 xsltParseUnknownXSLTElem(cctxt
, cur
);
4559 xsltCompilerNodePush(cctxt
, cur
);
4561 * Update the in-scope namespaces if needed.
4563 if (cur
->nsDef
!= NULL
)
4564 cctxt
->inode
->inScopeNs
=
4565 xsltCompilerBuildInScopeNsList(cctxt
, cur
);
4567 * The current element is either a literal result element
4568 * or an extension instruction.
4570 * Process attr "xsl:extension-element-prefixes".
4571 * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
4572 * processed by the implementor of the extension function;
4573 * i.e., it won't be handled by the XSLT processor.
4576 * "exclude-result-prefixes" is only allowed on literal
4577 * result elements and "xsl:exclude-result-prefixes"
4578 * on xsl:stylesheet/xsl:transform.
4580 * "There are a number of standard attributes
4581 * that may appear on any XSLT element: specifically
4582 * version, exclude-result-prefixes,
4583 * extension-element-prefixes, xpath-default-namespace,
4584 * default-collation, and use-when."
4587 * For literal result elements:
4588 * "xsl:version, xsl:exclude-result-prefixes,
4589 * xsl:extension-element-prefixes,
4590 * xsl:xpath-default-namespace,
4591 * xsl:default-collation, or xsl:use-when."
4593 if (cur
->properties
)
4594 cctxt
->inode
->extElemNs
=
4595 xsltParseExtElemPrefixes(cctxt
,
4596 cur
, cctxt
->inode
->extElemNs
,
4597 XSLT_ELEMENT_CATEGORY_LRE
);
4599 * Eval if we have an extension instruction here.
4601 if ((cur
->ns
!= NULL
) &&
4602 (cctxt
->inode
->extElemNs
!= NULL
) &&
4603 (xsltCheckExtPrefix(cctxt
->style
, cur
->ns
->href
) == 1))
4606 * Extension instructions
4607 * ----------------------------------------------------
4608 * Mark the node information.
4610 cctxt
->inode
->category
= XSLT_ELEMENT_CATEGORY_EXTENSION
;
4611 cctxt
->inode
->extContentHandled
= 0;
4612 if (cur
->psvi
!= NULL
) {
4615 * TODO: Temporary sanity check.
4617 xsltTransformError(NULL
, cctxt
->style
, cur
,
4618 "Internal error in xsltParseSequenceConstructor(): "
4619 "Occupied PSVI field.\n");
4620 cctxt
->style
->errors
++;
4624 cur
->psvi
= (void *)
4625 xsltPreComputeExtModuleElement(cctxt
->style
, cur
);
4627 if (cur
->psvi
== NULL
) {
4629 * OLD COMMENT: "Unknown element, maybe registered
4630 * at the context level. Mark it for later
4632 * QUESTION: What does the xsltExtMarker mean?
4633 * ANSWER: It is used in
4634 * xsltApplySequenceConstructor() at
4635 * transformation-time to look out for extension
4636 * registered in the transformation context.
4638 cur
->psvi
= (void *) xsltExtMarker
;
4641 * BIG NOTE: Now the ugly part. In previous versions
4642 * of Libxslt (until 1.1.16), all the content of an
4643 * extension instruction was processed and compiled without
4644 * the need of the extension-author to explicitely call
4645 * such a processing;.We now need to mimic this old
4646 * behaviour in order to avoid breaking old code
4647 * on the extension-author's side.
4649 * 1) If the author does *not* set the
4650 * compile-time-flag @extContentHandled, then we'll
4651 * parse the content assuming that it's a "template"
4652 * (or "sequence constructor in XSLT 2.0 terms).
4653 * NOTE: If the extension is registered at
4654 * transformation-time only, then there's no way of
4655 * knowing that content shall be valid, and we'll
4656 * process the content the same way.
4657 * 2) If the author *does* set the flag, then we'll assume
4658 * that the author has handled the parsing him/herself
4659 * (e.g. called xsltParseSequenceConstructor(), etc.
4660 * explicitely in his/her code).
4662 if ((cur
->children
!= NULL
) &&
4663 (cctxt
->inode
->extContentHandled
== 0))
4666 * Default parsing of the content using the
4667 * sequence-constructor model.
4669 xsltParseSequenceConstructor(cctxt
, cur
->children
);
4673 * Literal result element
4674 * ----------------------------------------------------
4675 * Allowed XSLT attributes:
4676 * xsl:extension-element-prefixes CDATA #IMPLIED
4677 * xsl:exclude-result-prefixes CDATA #IMPLIED
4678 * TODO: xsl:use-attribute-sets %qnames; #IMPLIED
4679 * xsl:version NMTOKEN #IMPLIED
4682 cctxt
->inode
->category
= XSLT_ELEMENT_CATEGORY_LRE
;
4683 if (cur
->properties
!= NULL
) {
4684 xmlAttrPtr attr
= cur
->properties
;
4686 * Attribute "xsl:exclude-result-prefixes".
4688 cctxt
->inode
->exclResultNs
=
4689 xsltParseExclResultPrefixes(cctxt
, cur
,
4690 cctxt
->inode
->exclResultNs
,
4691 XSLT_ELEMENT_CATEGORY_LRE
);
4693 * Attribute "xsl:version".
4695 xsltParseAttrXSLTVersion(cctxt
, cur
,
4696 XSLT_ELEMENT_CATEGORY_LRE
);
4698 * Report invalid XSLT attributes.
4699 * For XSLT 1.0 only xsl:use-attribute-sets is allowed
4700 * next to xsl:version, xsl:exclude-result-prefixes and
4701 * xsl:extension-element-prefixes.
4703 * Mark all XSLT attributes, in order to skip such
4704 * attributes when instantiating the LRE.
4707 if ((attr
->psvi
!= xsltXSLTAttrMarker
) &&
4708 IS_XSLT_ATTR_FAST(attr
))
4710 if (! xmlStrEqual(attr
->name
,
4711 BAD_CAST
"use-attribute-sets"))
4713 xsltTransformError(NULL
, cctxt
->style
,
4715 "Unknown XSLT attribute '%s'.\n",
4717 cctxt
->style
->errors
++;
4722 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
4726 } while (attr
!= NULL
);
4729 * Create/reuse info for the literal result element.
4731 if (cctxt
->inode
->nsChanged
)
4732 xsltLREInfoCreate(cctxt
, cur
, 1);
4733 cur
->psvi
= cctxt
->inode
->litResElemInfo
;
4735 * Apply ns-aliasing on the element and on its attributes.
4737 if (cctxt
->hasNsAliases
)
4738 xsltLREBuildEffectiveNs(cctxt
, cur
);
4740 * Compile attribute value templates (AVT).
4742 if (cur
->properties
) {
4743 xmlAttrPtr attr
= cur
->properties
;
4745 while (attr
!= NULL
) {
4746 xsltCompileAttr(cctxt
->style
, attr
);
4751 * Parse the content, which is defined to be a "template"
4752 * (or "sequence constructor" in XSLT 2.0 terms).
4754 if (cur
->children
!= NULL
) {
4755 xsltParseSequenceConstructor(cctxt
, cur
->children
);
4759 * Leave the non-XSLT element.
4761 xsltCompilerNodePop(cctxt
, cur
);
4766 if (deleteNode
!= NULL
) {
4767 #ifdef WITH_XSLT_DEBUG_BLANKS
4768 xsltGenericDebug(xsltGenericDebugContext
,
4769 "xsltParseSequenceConstructor: removing xsl:text element\n");
4771 xmlUnlinkNode(deleteNode
);
4772 xmlFreeNode(deleteNode
);
4778 * xsltParseTemplateContent:
4779 * @style: the XSLT stylesheet
4780 * @templ: the node containing the content to be parsed
4782 * Parses and compiles the content-model of an xsl:template element.
4783 * Note that this is *not* the "template" content model (or "sequence
4784 * constructor" in XSLT 2.0); it it allows addional xsl:param
4785 * elements as immediate children of @templ.
4788 * exsltFuncFunctionComp() (EXSLT, functions.c)
4789 * So this is intended to be called from extension functions.
4792 xsltParseTemplateContent(xsltStylesheetPtr style
, xmlNodePtr templ
) {
4793 if ((style
== NULL
) || (templ
== NULL
) ||
4794 (templ
->type
== XML_NAMESPACE_DECL
))
4798 * Detection of handled content of extension instructions.
4800 if (XSLT_CCTXT(style
)->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4801 XSLT_CCTXT(style
)->inode
->extContentHandled
= 1;
4804 if (templ
->children
!= NULL
) {
4805 xmlNodePtr child
= templ
->children
;
4807 * Process xsl:param elements, which can only occur as the
4808 * immediate children of xsl:template (well, and of any
4809 * user-defined extension instruction if needed).
4812 if ((child
->type
== XML_ELEMENT_NODE
) &&
4813 IS_XSLT_ELEM_FAST(child
) &&
4814 IS_XSLT_NAME(child
, "param"))
4816 XSLT_CCTXT(style
)->inode
->curChildType
= XSLT_FUNC_PARAM
;
4817 xsltParseAnyXSLTElem(XSLT_CCTXT(style
), child
);
4820 child
= child
->next
;
4821 } while (child
!= NULL
);
4823 * Parse the content and register the pattern.
4825 xsltParseSequenceConstructor(XSLT_CCTXT(style
), child
);
4829 #else /* XSLT_REFACTORED */
4832 * xsltParseTemplateContent:
4833 * @style: the XSLT stylesheet
4834 * @templ: the container node (can be a document for literal results)
4836 * parse a template content-model
4837 * Clean-up the template content from unwanted ignorable blank nodes
4838 * and process xslt:text
4841 xsltParseTemplateContent(xsltStylesheetPtr style
, xmlNodePtr templ
) {
4842 xmlNodePtr cur
, delete;
4844 if ((style
== NULL
) || (templ
== NULL
) ||
4845 (templ
->type
== XML_NAMESPACE_DECL
)) return;
4848 * This content comes from the stylesheet
4849 * For stylesheets, the set of whitespace-preserving
4850 * element names consists of just xsl:text.
4852 cur
= templ
->children
;
4854 while (cur
!= NULL
) {
4855 if (delete != NULL
) {
4856 #ifdef WITH_XSLT_DEBUG_BLANKS
4857 xsltGenericDebug(xsltGenericDebugContext
,
4858 "xsltParseTemplateContent: removing text\n");
4860 xmlUnlinkNode(delete);
4861 xmlFreeNode(delete);
4864 if (IS_XSLT_ELEM(cur
)) {
4865 if (IS_XSLT_NAME(cur
, "text")) {
4867 * TODO: Processing of xsl:text should be moved to
4868 * xsltPrecomputeStylesheet(), since otherwise this
4869 * will be performed for every multiply included
4870 * stylesheet; i.e. this here is not skipped with
4871 * the use of the style->nopreproc flag.
4873 if (cur
->children
!= NULL
) {
4875 xmlNodePtr text
= cur
->children
, next
;
4878 prop
= xmlGetNsProp(cur
,
4879 (const xmlChar
*)"disable-output-escaping",
4882 #ifdef WITH_XSLT_DEBUG_PARSING
4883 xsltGenericDebug(xsltGenericDebugContext
,
4884 "Disable escaping: %s\n", text
->content
);
4886 if (xmlStrEqual(prop
, (const xmlChar
*)"yes")) {
4888 } else if (!xmlStrEqual(prop
,
4889 (const xmlChar
*)"no")){
4890 xsltTransformError(NULL
, style
, cur
,
4891 "xsl:text: disable-output-escaping allows only yes or no\n");
4898 while (text
!= NULL
) {
4899 if (text
->type
== XML_COMMENT_NODE
) {
4903 if ((text
->type
!= XML_TEXT_NODE
) &&
4904 (text
->type
!= XML_CDATA_SECTION_NODE
)) {
4905 xsltTransformError(NULL
, style
, cur
,
4906 "xsltParseTemplateContent: xslt:text content problem\n");
4910 if ((noesc
) && (text
->type
!= XML_CDATA_SECTION_NODE
))
4911 text
->name
= xmlStringTextNoenc
;
4916 * replace xsl:text by the list of childs
4919 text
= cur
->children
;
4920 while (text
!= NULL
) {
4921 if ((style
->internalized
) &&
4922 (text
->content
!= NULL
) &&
4923 (!xmlDictOwns(style
->dict
, text
->content
))) {
4926 * internalize the text string
4928 if (text
->doc
->dict
!= NULL
) {
4931 tmp
= xmlDictLookup(text
->doc
->dict
,
4933 if (tmp
!= text
->content
) {
4934 xmlNodeSetContent(text
, NULL
);
4935 text
->content
= (xmlChar
*) tmp
;
4941 xmlUnlinkNode(text
);
4942 xmlAddPrevSibling(cur
, text
);
4951 else if ((cur
->ns
!= NULL
) && (style
->nsDefs
!= NULL
) &&
4952 (xsltCheckExtPrefix(style
, cur
->ns
->prefix
)))
4955 * okay this is an extension element compile it too
4957 xsltStylePreCompute(style
, cur
);
4959 else if (cur
->type
== XML_ELEMENT_NODE
)
4962 * This is an element which will be output as part of the
4963 * template exectution, precompile AVT if found.
4965 if ((cur
->ns
== NULL
) && (style
->defaultAlias
!= NULL
)) {
4966 cur
->ns
= xmlSearchNsByHref(cur
->doc
, cur
,
4967 style
->defaultAlias
);
4969 if (cur
->properties
!= NULL
) {
4970 xmlAttrPtr attr
= cur
->properties
;
4972 while (attr
!= NULL
) {
4973 xsltCompileAttr(style
, attr
);
4981 if (cur
->children
!= NULL
) {
4982 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
4983 cur
= cur
->children
;
4988 if (cur
->next
!= NULL
) {
5001 if (cur
->next
!= NULL
) {
5005 } while (cur
!= NULL
);
5007 if (delete != NULL
) {
5008 #ifdef WITH_XSLT_DEBUG_PARSING
5009 xsltGenericDebug(xsltGenericDebugContext
,
5010 "xsltParseTemplateContent: removing text\n");
5012 xmlUnlinkNode(delete);
5013 xmlFreeNode(delete);
5018 * Skip the first params
5020 cur
= templ
->children
;
5021 while (cur
!= NULL
) {
5022 if ((IS_XSLT_ELEM(cur
)) && (!(IS_XSLT_NAME(cur
, "param"))))
5028 * Browse the remainder of the template
5030 while (cur
!= NULL
) {
5031 if ((IS_XSLT_ELEM(cur
)) && (IS_XSLT_NAME(cur
, "param"))) {
5032 xmlNodePtr param
= cur
;
5034 xsltTransformError(NULL
, style
, cur
,
5035 "xsltParseTemplateContent: ignoring misplaced param element\n");
5036 if (style
!= NULL
) style
->warnings
++;
5038 xmlUnlinkNode(param
);
5045 #endif /* else XSLT_REFACTORED */
5048 * xsltParseStylesheetKey:
5049 * @style: the XSLT stylesheet
5050 * @key: the "key" element
5052 * <!-- Category: top-level-element -->
5053 * <xsl:key name = qname, match = pattern, use = expression />
5055 * parse an XSLT stylesheet key definition and register it
5059 xsltParseStylesheetKey(xsltStylesheetPtr style
, xmlNodePtr key
) {
5060 xmlChar
*prop
= NULL
;
5061 xmlChar
*use
= NULL
;
5062 xmlChar
*match
= NULL
;
5063 xmlChar
*name
= NULL
;
5064 xmlChar
*nameURI
= NULL
;
5066 if ((style
== NULL
) || (key
== NULL
) || (key
->type
!= XML_ELEMENT_NODE
))
5072 prop
= xmlGetNsProp(key
, (const xmlChar
*)"name", NULL
);
5077 * TODO: Don't use xsltGetQNameURI().
5079 URI
= xsltGetQNameURI(key
, &prop
);
5081 if (style
!= NULL
) style
->errors
++;
5086 nameURI
= xmlStrdup(URI
);
5088 #ifdef WITH_XSLT_DEBUG_PARSING
5089 xsltGenericDebug(xsltGenericDebugContext
,
5090 "xsltParseStylesheetKey: name %s\n", name
);
5093 xsltTransformError(NULL
, style
, key
,
5094 "xsl:key : error missing name\n");
5095 if (style
!= NULL
) style
->errors
++;
5099 match
= xmlGetNsProp(key
, (const xmlChar
*)"match", NULL
);
5100 if (match
== NULL
) {
5101 xsltTransformError(NULL
, style
, key
,
5102 "xsl:key : error missing match\n");
5103 if (style
!= NULL
) style
->errors
++;
5107 use
= xmlGetNsProp(key
, (const xmlChar
*)"use", NULL
);
5109 xsltTransformError(NULL
, style
, key
,
5110 "xsl:key : error missing use\n");
5111 if (style
!= NULL
) style
->errors
++;
5118 xsltAddKey(style
, name
, nameURI
, match
, use
, key
);
5128 if (nameURI
!= NULL
)
5131 if (key
->children
!= NULL
) {
5132 xsltParseContentError(style
, key
->children
);
5136 #ifdef XSLT_REFACTORED
5138 * xsltParseXSLTTemplate:
5139 * @style: the XSLT stylesheet
5140 * @template: the "template" element
5142 * parse an XSLT stylesheet template building the associated structures
5143 * TODO: Is @style ever expected to be NULL?
5146 * xsltParseXSLTStylesheet()
5147 * xsltParseStylesheetTop()
5151 xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt
, xmlNodePtr templNode
) {
5152 xsltTemplatePtr templ
;
5156 if ((cctxt
== NULL
) || (templNode
== NULL
) ||
5157 (templNode
->type
!= XML_ELEMENT_NODE
))
5161 * Create and link the structure
5163 templ
= xsltNewTemplate();
5167 xsltCompilerNodePush(cctxt
, templNode
);
5168 if (templNode
->nsDef
!= NULL
)
5169 cctxt
->inode
->inScopeNs
=
5170 xsltCompilerBuildInScopeNsList(cctxt
, templNode
);
5172 templ
->next
= cctxt
->style
->templates
;
5173 cctxt
->style
->templates
= templ
;
5174 templ
->style
= cctxt
->style
;
5179 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"mode", NULL
);
5181 const xmlChar
*modeURI
;
5184 * TODO: We need a standardized function for extraction
5185 * of namespace names and local names from QNames.
5186 * Don't use xsltGetQNameURI() as it cannot channe�
5187 * reports through the context.
5189 modeURI
= xsltGetQNameURI(templNode
, &prop
);
5191 cctxt
->style
->errors
++;
5194 templ
->mode
= xmlDictLookup(cctxt
->style
->dict
, prop
, -1);
5197 if (xmlValidateNCName(templ
->mode
, 0)) {
5198 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5199 "xsl:template: Attribute 'mode': The local part '%s' "
5200 "of the value is not a valid NCName.\n", templ
->name
);
5201 cctxt
->style
->errors
++;
5204 if (modeURI
!= NULL
)
5205 templ
->modeURI
= xmlDictLookup(cctxt
->style
->dict
, modeURI
, -1);
5206 #ifdef WITH_XSLT_DEBUG_PARSING
5207 xsltGenericDebug(xsltGenericDebugContext
,
5208 "xsltParseXSLTTemplate: mode %s\n", templ
->mode
);
5212 * Attribute "match".
5214 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"match", NULL
);
5216 templ
->match
= prop
;
5220 * Attribute "priority".
5222 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"priority", NULL
);
5224 priority
= xmlXPathStringEvalNumber(prop
);
5225 templ
->priority
= (float) priority
;
5232 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"name", NULL
);
5234 const xmlChar
*nameURI
;
5235 xsltTemplatePtr curTempl
;
5238 * TODO: Don't use xsltGetQNameURI().
5240 nameURI
= xsltGetQNameURI(templNode
, &prop
);
5242 cctxt
->style
->errors
++;
5245 templ
->name
= xmlDictLookup(cctxt
->style
->dict
, prop
, -1);
5248 if (xmlValidateNCName(templ
->name
, 0)) {
5249 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5250 "xsl:template: Attribute 'name': The local part '%s' of "
5251 "the value is not a valid NCName.\n", templ
->name
);
5252 cctxt
->style
->errors
++;
5255 if (nameURI
!= NULL
)
5256 templ
->nameURI
= xmlDictLookup(cctxt
->style
->dict
, nameURI
, -1);
5257 curTempl
= templ
->next
;
5258 while (curTempl
!= NULL
) {
5259 if ((nameURI
!= NULL
&& xmlStrEqual(curTempl
->name
, templ
->name
) &&
5260 xmlStrEqual(curTempl
->nameURI
, nameURI
) ) ||
5261 (nameURI
== NULL
&& curTempl
->nameURI
== NULL
&&
5262 xmlStrEqual(curTempl
->name
, templ
->name
)))
5264 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5265 "xsl:template: error duplicate name '%s'\n", templ
->name
);
5266 cctxt
->style
->errors
++;
5269 curTempl
= curTempl
->next
;
5272 if (templNode
->children
!= NULL
) {
5273 xsltParseTemplateContent(cctxt
->style
, templNode
);
5275 * MAYBE TODO: Custom behaviour: In order to stay compatible with
5276 * Xalan and MSXML(.NET), we could allow whitespace
5277 * to appear before an xml:param element; this whitespace
5278 * will additionally become part of the "template".
5279 * NOTE that this is totally deviates from the spec, but
5280 * is the de facto behaviour of Xalan and MSXML(.NET).
5281 * Personally I wouldn't allow this, since if we have:
5282 * <xsl:template ...xml:space="preserve">
5283 * <xsl:param name="foo"/>
5284 * <xsl:param name="bar"/>
5285 * <xsl:param name="zoo"/>
5286 * ... the whitespace between every xsl:param would be
5287 * added to the result tree.
5291 templ
->elem
= templNode
;
5292 templ
->content
= templNode
->children
;
5293 xsltAddTemplate(cctxt
->style
, templ
, templ
->mode
, templ
->modeURI
);
5296 xsltCompilerNodePop(cctxt
, templNode
);
5300 #else /* XSLT_REFACTORED */
5303 * xsltParseStylesheetTemplate:
5304 * @style: the XSLT stylesheet
5305 * @template: the "template" element
5307 * parse an XSLT stylesheet template building the associated structures
5311 xsltParseStylesheetTemplate(xsltStylesheetPtr style
, xmlNodePtr
template) {
5312 xsltTemplatePtr ret
;
5314 xmlChar
*mode
= NULL
;
5315 xmlChar
*modeURI
= NULL
;
5318 if ((style
== NULL
) || (template == NULL
) ||
5319 (template->type
!= XML_ELEMENT_NODE
))
5323 * Create and link the structure
5325 ret
= xsltNewTemplate();
5328 ret
->next
= style
->templates
;
5329 style
->templates
= ret
;
5333 * Get inherited namespaces
5336 * TODO: Apply the optimized in-scope-namespace mechanism
5337 * as for the other XSLT instructions.
5339 xsltGetInheritedNsList(style
, ret
, template);
5344 prop
= xmlGetNsProp(template, (const xmlChar
*)"mode", NULL
);
5349 * TODO: Don't use xsltGetQNameURI().
5351 URI
= xsltGetQNameURI(template, &prop
);
5353 if (style
!= NULL
) style
->errors
++;
5358 modeURI
= xmlStrdup(URI
);
5360 ret
->mode
= xmlDictLookup(style
->dict
, mode
, -1);
5361 ret
->modeURI
= xmlDictLookup(style
->dict
, modeURI
, -1);
5362 #ifdef WITH_XSLT_DEBUG_PARSING
5363 xsltGenericDebug(xsltGenericDebugContext
,
5364 "xsltParseStylesheetTemplate: mode %s\n", mode
);
5366 if (mode
!= NULL
) xmlFree(mode
);
5367 if (modeURI
!= NULL
) xmlFree(modeURI
);
5369 prop
= xmlGetNsProp(template, (const xmlChar
*)"match", NULL
);
5371 if (ret
->match
!= NULL
) xmlFree(ret
->match
);
5375 prop
= xmlGetNsProp(template, (const xmlChar
*)"priority", NULL
);
5377 priority
= xmlXPathStringEvalNumber(prop
);
5378 ret
->priority
= (float) priority
;
5382 prop
= xmlGetNsProp(template, (const xmlChar
*)"name", NULL
);
5385 xsltTemplatePtr cur
;
5388 * TODO: Don't use xsltGetQNameURI().
5390 URI
= xsltGetQNameURI(template, &prop
);
5392 if (style
!= NULL
) style
->errors
++;
5395 if (xmlValidateNCName(prop
,0)) {
5396 xsltTransformError(NULL
, style
, template,
5397 "xsl:template : error invalid name '%s'\n", prop
);
5398 if (style
!= NULL
) style
->errors
++;
5401 ret
->name
= xmlDictLookup(style
->dict
, BAD_CAST prop
, -1);
5405 ret
->nameURI
= xmlDictLookup(style
->dict
, BAD_CAST URI
, -1);
5407 ret
->nameURI
= NULL
;
5409 while (cur
!= NULL
) {
5410 if ((URI
!= NULL
&& xmlStrEqual(cur
->name
, ret
->name
) &&
5411 xmlStrEqual(cur
->nameURI
, URI
) ) ||
5412 (URI
== NULL
&& cur
->nameURI
== NULL
&&
5413 xmlStrEqual(cur
->name
, ret
->name
))) {
5414 xsltTransformError(NULL
, style
, template,
5415 "xsl:template: error duplicate name '%s'\n", ret
->name
);
5425 * parse the content and register the pattern
5427 xsltParseTemplateContent(style
, template);
5428 ret
->elem
= template;
5429 ret
->content
= template->children
;
5430 xsltAddTemplate(style
, ret
, ret
->mode
, ret
->modeURI
);
5436 #endif /* else XSLT_REFACTORED */
5438 #ifdef XSLT_REFACTORED
5442 * @cctxt: the compilation contenxt
5443 * @node: the xsl:include node
5445 * Process the xslt include node on the source node
5447 static xsltStyleItemIncludePtr
5448 xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
) {
5449 xsltStyleItemIncludePtr item
;
5451 if ((cctxt
== NULL
) || (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
5455 item
= (xsltStyleItemIncludePtr
) xmlMalloc(sizeof(xsltStyleItemInclude
));
5457 xsltTransformError(NULL
, cctxt
->style
, node
,
5458 "xsltIncludeComp : malloc failed\n");
5459 cctxt
->style
->errors
++;
5462 memset(item
, 0, sizeof(xsltStyleItemInclude
));
5466 item
->type
= XSLT_FUNC_INCLUDE
;
5468 item
->next
= cctxt
->style
->preComps
;
5469 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
5475 * xsltParseFindTopLevelElem:
5478 xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt
,
5480 const xmlChar
*name
,
5481 const xmlChar
*namespaceURI
,
5482 int breakOnOtherElem
,
5483 xmlNodePtr
*resultNode
)
5489 while (cur
!= NULL
) {
5490 if (cur
->type
== XML_ELEMENT_NODE
) {
5491 if ((cur
->ns
!= NULL
) && (cur
->name
!= NULL
)) {
5492 if ((*(cur
->name
) == *name
) &&
5493 xmlStrEqual(cur
->name
, name
) &&
5494 xmlStrEqual(cur
->ns
->href
, namespaceURI
))
5500 if (breakOnOtherElem
)
5510 xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt
,
5517 * TODO: The reason why this function exists:
5518 * due to historical reasons some of the
5519 * top-level declarations are processed by functions
5520 * in other files. Since we need still to set
5521 * up the node-info and generate information like
5522 * in-scope namespaces, this is a wrapper around
5523 * those old parsing functions.
5525 xsltCompilerNodePush(cctxt
, node
);
5526 if (node
->nsDef
!= NULL
)
5527 cctxt
->inode
->inScopeNs
=
5528 xsltCompilerBuildInScopeNsList(cctxt
, node
);
5529 cctxt
->inode
->type
= type
;
5532 case XSLT_FUNC_INCLUDE
:
5536 if (xsltCompileXSLTIncludeElem(cctxt
, node
) == NULL
)
5539 * Mark this stylesheet tree as being currently included.
5541 oldIsInclude
= cctxt
->isInclude
;
5542 cctxt
->isInclude
= 1;
5544 if (xsltParseStylesheetInclude(cctxt
->style
, node
) != 0) {
5545 cctxt
->style
->errors
++;
5547 cctxt
->isInclude
= oldIsInclude
;
5550 case XSLT_FUNC_PARAM
:
5551 xsltStylePreCompute(cctxt
->style
, node
);
5552 xsltParseGlobalParam(cctxt
->style
, node
);
5554 case XSLT_FUNC_VARIABLE
:
5555 xsltStylePreCompute(cctxt
->style
, node
);
5556 xsltParseGlobalVariable(cctxt
->style
, node
);
5558 case XSLT_FUNC_ATTRSET
:
5559 xsltParseStylesheetAttributeSet(cctxt
->style
, node
);
5562 xsltTransformError(NULL
, cctxt
->style
, node
,
5563 "Internal error: (xsltParseTopLevelXSLTElem) "
5564 "Cannot handle this top-level declaration.\n");
5565 cctxt
->style
->errors
++;
5570 xsltCompilerNodePop(cctxt
, node
);
5577 xsltParseRemoveWhitespace(xmlNodePtr node
)
5579 if ((node
== NULL
) || (node
->children
== NULL
))
5582 xmlNodePtr delNode
= NULL
, child
= node
->children
;
5586 xmlUnlinkNode(delNode
);
5587 xmlFreeNode(delNode
);
5590 if (((child
->type
== XML_TEXT_NODE
) ||
5591 (child
->type
== XML_CDATA_SECTION_NODE
)) &&
5592 (IS_BLANK_NODE(child
)))
5594 child
= child
->next
;
5595 } while (child
!= NULL
);
5597 xmlUnlinkNode(delNode
);
5598 xmlFreeNode(delNode
);
5607 xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
5609 #ifdef WITH_XSLT_DEBUG_PARSING
5612 xmlNodePtr cur
, start
= NULL
;
5613 xsltStylesheetPtr style
;
5615 if ((cctxt
== NULL
) || (node
== NULL
) ||
5616 (node
->type
!= XML_ELEMENT_NODE
))
5619 style
= cctxt
->style
;
5621 * At this stage all import declarations of all stylesheet modules
5622 * with the same stylesheet level have been processed.
5623 * Now we can safely parse the rest of the declarations.
5625 if (IS_XSLT_ELEM_FAST(node
) && IS_XSLT_NAME(node
, "include"))
5627 xsltDocumentPtr include
;
5629 * URGENT TODO: Make this work with simplified stylesheets!
5630 * I.e., when we won't find an xsl:stylesheet element.
5633 * This is as include declaration.
5635 include
= ((xsltStyleItemIncludePtr
) node
->psvi
)->include
;
5636 if (include
== NULL
) {
5637 /* TODO: raise error? */
5641 * TODO: Actually an xsl:include should locate an embedded
5642 * stylesheet as well; so the document-element won't always
5643 * be the element where the actual stylesheet is rooted at.
5644 * But such embedded stylesheets are not supported by Libxslt yet.
5646 node
= xmlDocGetRootElement(include
->doc
);
5652 if (node
->children
== NULL
)
5655 * Push the xsl:stylesheet/xsl:transform element.
5657 xsltCompilerNodePush(cctxt
, node
);
5658 cctxt
->inode
->isRoot
= 1;
5659 cctxt
->inode
->nsChanged
= 0;
5661 * Start with the naked dummy info for literal result elements.
5663 cctxt
->inode
->litResElemInfo
= cctxt
->inodeList
->litResElemInfo
;
5666 * In every case, we need to have
5667 * the in-scope namespaces of the element, where the
5668 * stylesheet is rooted at, regardless if it's an XSLT
5669 * instruction or a literal result instruction (or if
5670 * this is an embedded stylesheet).
5672 cctxt
->inode
->inScopeNs
=
5673 xsltCompilerBuildInScopeNsList(cctxt
, node
);
5676 * Process attributes of xsl:stylesheet/xsl:transform.
5677 * --------------------------------------------------
5680 * extension-element-prefixes = tokens
5681 * exclude-result-prefixes = tokens
5682 * version = number (mandatory)
5684 if (xsltParseAttrXSLTVersion(cctxt
, node
,
5685 XSLT_ELEMENT_CATEGORY_XSLT
) == 0)
5688 * Attribute "version".
5689 * XSLT 1.0: "An xsl:stylesheet element *must* have a version
5690 * attribute, indicating the version of XSLT that the
5691 * stylesheet requires".
5692 * The root element of a simplified stylesheet must also have
5695 #ifdef XSLT_REFACTORED_MANDATORY_VERSION
5697 xsltTransformError(NULL
, cctxt
->style
, node
,
5698 "The attribute 'version' is missing.\n");
5699 cctxt
->style
->errors
++;
5701 /* OLD behaviour. */
5702 xsltTransformError(NULL
, cctxt
->style
, node
,
5703 "xsl:version is missing: document may not be a stylesheet\n");
5704 cctxt
->style
->warnings
++;
5708 * The namespaces declared by the attributes
5709 * "extension-element-prefixes" and
5710 * "exclude-result-prefixes" are local to *this*
5711 * stylesheet tree; i.e., they are *not* visible to
5712 * other stylesheet-modules, whether imported or included.
5714 * Attribute "extension-element-prefixes".
5716 cctxt
->inode
->extElemNs
=
5717 xsltParseExtElemPrefixes(cctxt
, node
, NULL
,
5718 XSLT_ELEMENT_CATEGORY_XSLT
);
5720 * Attribute "exclude-result-prefixes".
5722 cctxt
->inode
->exclResultNs
=
5723 xsltParseExclResultPrefixes(cctxt
, node
, NULL
,
5724 XSLT_ELEMENT_CATEGORY_XSLT
);
5726 * Create/reuse info for the literal result element.
5728 if (cctxt
->inode
->nsChanged
)
5729 xsltLREInfoCreate(cctxt
, node
, 0);
5731 * Processed top-level elements:
5732 * ----------------------------
5733 * xsl:variable, xsl:param (QName, in-scope ns,
5734 * expression (vars allowed))
5735 * xsl:attribute-set (QName, in-scope ns)
5736 * xsl:strip-space, xsl:preserve-space (XPath NameTests,
5738 * I *think* global scope, merge with includes
5739 * xsl:output (QName, in-scope ns)
5740 * xsl:key (QName, in-scope ns, pattern,
5741 * expression (vars *not* allowed))
5742 * xsl:decimal-format (QName, needs in-scope ns)
5743 * xsl:namespace-alias (in-scope ns)
5744 * global scope, merge with includes
5745 * xsl:template (last, QName, pattern)
5747 * (whitespace-only text-nodes have *not* been removed
5748 * yet; this will be done in xsltParseSequenceConstructor)
5750 * Report misplaced child-nodes first.
5752 cur
= node
->children
;
5753 while (cur
!= NULL
) {
5754 if (cur
->type
== XML_TEXT_NODE
) {
5755 xsltTransformError(NULL
, style
, cur
,
5756 "Misplaced text node (content: '%s').\n",
5757 (cur
->content
!= NULL
) ? cur
->content
: BAD_CAST
"");
5759 } else if (cur
->type
!= XML_ELEMENT_NODE
) {
5760 xsltTransformError(NULL
, style
, cur
, "Misplaced node.\n");
5766 * Skip xsl:import elements; they have been processed
5769 cur
= node
->children
;
5770 while ((cur
!= NULL
) && xsltParseFindTopLevelElem(cctxt
, cur
,
5771 BAD_CAST
"import", XSLT_NAMESPACE
, 1, &cur
) == 1)
5778 * Process all top-level xsl:param elements.
5780 while ((cur
!= NULL
) &&
5781 xsltParseFindTopLevelElem(cctxt
, cur
,
5782 BAD_CAST
"param", XSLT_NAMESPACE
, 0, &cur
) == 1)
5784 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_PARAM
);
5788 * Process all top-level xsl:variable elements.
5791 while ((cur
!= NULL
) &&
5792 xsltParseFindTopLevelElem(cctxt
, cur
,
5793 BAD_CAST
"variable", XSLT_NAMESPACE
, 0, &cur
) == 1)
5795 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_VARIABLE
);
5799 * Process all the rest of top-level elements.
5802 while (cur
!= NULL
) {
5804 * Process element nodes.
5806 if (cur
->type
== XML_ELEMENT_NODE
) {
5807 if (cur
->ns
== NULL
) {
5808 xsltTransformError(NULL
, style
, cur
,
5809 "Unexpected top-level element in no namespace.\n");
5815 * Process all XSLT elements.
5817 if (IS_XSLT_ELEM_FAST(cur
)) {
5819 * xsl:import is only allowed at the beginning.
5821 if (IS_XSLT_NAME(cur
, "import")) {
5822 xsltTransformError(NULL
, style
, cur
,
5823 "Misplaced xsl:import element.\n");
5829 * TODO: Change the return type of the parsing functions
5832 if (IS_XSLT_NAME(cur
, "template")) {
5833 #ifdef WITH_XSLT_DEBUG_PARSING
5837 * TODO: Is the position of xsl:template in the
5838 * tree significant? If not it would be easier to
5839 * parse them at a later stage.
5841 xsltParseXSLTTemplate(cctxt
, cur
);
5842 } else if (IS_XSLT_NAME(cur
, "variable")) {
5843 /* NOP; done already */
5844 } else if (IS_XSLT_NAME(cur
, "param")) {
5845 /* NOP; done already */
5846 } else if (IS_XSLT_NAME(cur
, "include")) {
5847 if (cur
->psvi
!= NULL
)
5848 xsltParseXSLTStylesheetElemCore(cctxt
, cur
);
5850 xsltTransformError(NULL
, style
, cur
,
5852 "(xsltParseXSLTStylesheetElemCore) "
5853 "The xsl:include element was not compiled.\n");
5856 } else if (IS_XSLT_NAME(cur
, "strip-space")) {
5857 /* No node info needed. */
5858 xsltParseStylesheetStripSpace(style
, cur
);
5859 } else if (IS_XSLT_NAME(cur
, "preserve-space")) {
5860 /* No node info needed. */
5861 xsltParseStylesheetPreserveSpace(style
, cur
);
5862 } else if (IS_XSLT_NAME(cur
, "output")) {
5863 /* No node-info needed. */
5864 xsltParseStylesheetOutput(style
, cur
);
5865 } else if (IS_XSLT_NAME(cur
, "key")) {
5866 /* TODO: node-info needed for expressions ? */
5867 xsltParseStylesheetKey(style
, cur
);
5868 } else if (IS_XSLT_NAME(cur
, "decimal-format")) {
5869 /* No node-info needed. */
5870 xsltParseStylesheetDecimalFormat(style
, cur
);
5871 } else if (IS_XSLT_NAME(cur
, "attribute-set")) {
5872 xsltParseTopLevelXSLTElem(cctxt
, cur
,
5874 } else if (IS_XSLT_NAME(cur
, "namespace-alias")) {
5875 /* NOP; done already */
5877 if (cctxt
->inode
->forwardsCompat
) {
5879 * Forwards-compatible mode:
5881 * XSLT-1: "if it is a top-level element and
5882 * XSLT 1.0 does not allow such elements as top-level
5883 * elements, then the element must be ignored along
5884 * with its content;"
5887 * TODO: I don't think we should generate a warning.
5889 xsltTransformError(NULL
, style
, cur
,
5890 "Forwards-compatible mode: Ignoring unknown XSLT "
5891 "element '%s'.\n", cur
->name
);
5894 xsltTransformError(NULL
, style
, cur
,
5895 "Unknown XSLT element '%s'.\n", cur
->name
);
5900 xsltTopLevelFunction function
;
5903 * Process non-XSLT elements, which are in a
5904 * non-NULL namespace.
5907 * QUESTION: What does xsltExtModuleTopLevelLookup()
5910 function
= xsltExtModuleTopLevelLookup(cur
->name
,
5912 if (function
!= NULL
)
5913 function(style
, cur
);
5914 #ifdef WITH_XSLT_DEBUG_PARSING
5915 xsltGenericDebug(xsltGenericDebugContext
,
5916 "xsltParseXSLTStylesheetElemCore : User-defined "
5917 "data element '%s'.\n", cur
->name
);
5926 #ifdef WITH_XSLT_DEBUG_PARSING
5927 xsltGenericDebug(xsltGenericDebugContext
,
5928 "### END of parsing top-level elements of doc '%s'.\n",
5930 xsltGenericDebug(xsltGenericDebugContext
,
5931 "### Templates: %d\n", templates
);
5932 #ifdef XSLT_REFACTORED
5933 xsltGenericDebug(xsltGenericDebugContext
,
5934 "### Max inodes: %d\n", cctxt
->maxNodeInfos
);
5935 xsltGenericDebug(xsltGenericDebugContext
,
5936 "### Max LREs : %d\n", cctxt
->maxLREs
);
5937 #endif /* XSLT_REFACTORED */
5938 #endif /* WITH_XSLT_DEBUG_PARSING */
5940 xsltCompilerNodePop(cctxt
, node
);
5945 * xsltParseXSLTStylesheet:
5946 * @cctxt: the compiler context
5947 * @node: the xsl:stylesheet/xsl:transform element-node
5949 * Parses the xsl:stylesheet and xsl:transform element.
5953 * extension-element-prefixes = tokens
5954 * exclude-result-prefixes = tokens
5956 * <!-- Content: (xsl:import*, top-level-elements) -->
5959 * BIG TODO: The xsl:include stuff.
5961 * Called by xsltParseStylesheetTree()
5963 * Returns 0 on success, a positive result on errors and
5964 * -1 on API or internal errors.
5967 xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
5969 xmlNodePtr cur
, start
;
5971 if ((cctxt
== NULL
) || (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
5974 if (node
->children
== NULL
)
5978 * Process top-level elements:
5979 * xsl:import (must be first)
5980 * xsl:include (this is just a pre-processing)
5982 cur
= node
->children
;
5984 * Process xsl:import elements.
5985 * XSLT 1.0: "The xsl:import element children must precede all
5986 * other element children of an xsl:stylesheet element,
5987 * including any xsl:include element children."
5989 while ((cur
!= NULL
) &&
5990 xsltParseFindTopLevelElem(cctxt
, cur
,
5991 BAD_CAST
"import", XSLT_NAMESPACE
, 1, &cur
) == 1)
5993 if (xsltParseStylesheetImport(cctxt
->style
, cur
) != 0) {
5994 cctxt
->style
->errors
++;
6002 * Pre-process all xsl:include elements.
6005 while ((cur
!= NULL
) &&
6006 xsltParseFindTopLevelElem(cctxt
, cur
,
6007 BAD_CAST
"include", XSLT_NAMESPACE
, 0, &cur
) == 1)
6009 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_INCLUDE
);
6013 * Pre-process all xsl:namespace-alias elements.
6014 * URGENT TODO: This won't work correctly: the order of included
6015 * aliases and aliases defined here is significant.
6018 while ((cur
!= NULL
) &&
6019 xsltParseFindTopLevelElem(cctxt
, cur
,
6020 BAD_CAST
"namespace-alias", XSLT_NAMESPACE
, 0, &cur
) == 1)
6022 xsltNamespaceAlias(cctxt
->style
, cur
);
6026 if (cctxt
->isInclude
) {
6028 * If this stylesheet is intended for inclusion, then
6029 * we will process only imports and includes.
6034 * Now parse the rest of the top-level elements.
6036 xsltParseXSLTStylesheetElemCore(cctxt
, node
);
6042 #else /* XSLT_REFACTORED */
6045 * xsltParseStylesheetTop:
6046 * @style: the XSLT stylesheet
6047 * @top: the top level "stylesheet" or "transform" element
6049 * scan the top level elements of an XSL stylesheet
6052 xsltParseStylesheetTop(xsltStylesheetPtr style
, xmlNodePtr top
) {
6055 #ifdef WITH_XSLT_DEBUG_PARSING
6059 if ((top
== NULL
) || (top
->type
!= XML_ELEMENT_NODE
))
6062 prop
= xmlGetNsProp(top
, (const xmlChar
*)"version", NULL
);
6064 xsltTransformError(NULL
, style
, top
,
6065 "xsl:version is missing: document may not be a stylesheet\n");
6066 if (style
!= NULL
) style
->warnings
++;
6068 if ((!xmlStrEqual(prop
, (const xmlChar
*)"1.0")) &&
6069 (!xmlStrEqual(prop
, (const xmlChar
*)"1.1"))) {
6070 xsltTransformError(NULL
, style
, top
,
6071 "xsl:version: only 1.0 features are supported\n");
6072 if (style
!= NULL
) {
6073 style
->forwards_compatible
= 1;
6081 * process xsl:import elements
6083 cur
= top
->children
;
6084 while (cur
!= NULL
) {
6085 if (IS_BLANK_NODE(cur
)) {
6089 if (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "import")) {
6090 if (xsltParseStylesheetImport(style
, cur
) != 0)
6091 if (style
!= NULL
) style
->errors
++;
6098 * process other top-level elements
6100 while (cur
!= NULL
) {
6101 if (IS_BLANK_NODE(cur
)) {
6105 if (cur
->type
== XML_TEXT_NODE
) {
6106 if (cur
->content
!= NULL
) {
6107 xsltTransformError(NULL
, style
, cur
,
6108 "misplaced text node: '%s'\n", cur
->content
);
6110 if (style
!= NULL
) style
->errors
++;
6114 if ((cur
->type
== XML_ELEMENT_NODE
) && (cur
->ns
== NULL
)) {
6115 xsltGenericError(xsltGenericErrorContext
,
6116 "Found a top-level element %s with null namespace URI\n",
6118 if (style
!= NULL
) style
->errors
++;
6122 if ((cur
->type
== XML_ELEMENT_NODE
) && (!(IS_XSLT_ELEM(cur
)))) {
6123 xsltTopLevelFunction function
;
6125 function
= xsltExtModuleTopLevelLookup(cur
->name
,
6127 if (function
!= NULL
)
6128 function(style
, cur
);
6130 #ifdef WITH_XSLT_DEBUG_PARSING
6131 xsltGenericDebug(xsltGenericDebugContext
,
6132 "xsltParseStylesheetTop : found foreign element %s\n",
6138 if (IS_XSLT_NAME(cur
, "import")) {
6139 xsltTransformError(NULL
, style
, cur
,
6140 "xsltParseStylesheetTop: ignoring misplaced import element\n");
6141 if (style
!= NULL
) style
->errors
++;
6142 } else if (IS_XSLT_NAME(cur
, "include")) {
6143 if (xsltParseStylesheetInclude(style
, cur
) != 0)
6144 if (style
!= NULL
) style
->errors
++;
6145 } else if (IS_XSLT_NAME(cur
, "strip-space")) {
6146 xsltParseStylesheetStripSpace(style
, cur
);
6147 } else if (IS_XSLT_NAME(cur
, "preserve-space")) {
6148 xsltParseStylesheetPreserveSpace(style
, cur
);
6149 } else if (IS_XSLT_NAME(cur
, "output")) {
6150 xsltParseStylesheetOutput(style
, cur
);
6151 } else if (IS_XSLT_NAME(cur
, "key")) {
6152 xsltParseStylesheetKey(style
, cur
);
6153 } else if (IS_XSLT_NAME(cur
, "decimal-format")) {
6154 xsltParseStylesheetDecimalFormat(style
, cur
);
6155 } else if (IS_XSLT_NAME(cur
, "attribute-set")) {
6156 xsltParseStylesheetAttributeSet(style
, cur
);
6157 } else if (IS_XSLT_NAME(cur
, "variable")) {
6158 xsltParseGlobalVariable(style
, cur
);
6159 } else if (IS_XSLT_NAME(cur
, "param")) {
6160 xsltParseGlobalParam(style
, cur
);
6161 } else if (IS_XSLT_NAME(cur
, "template")) {
6162 #ifdef WITH_XSLT_DEBUG_PARSING
6165 xsltParseStylesheetTemplate(style
, cur
);
6166 } else if (IS_XSLT_NAME(cur
, "namespace-alias")) {
6167 xsltNamespaceAlias(style
, cur
);
6169 if ((style
!= NULL
) && (style
->forwards_compatible
== 0)) {
6170 xsltTransformError(NULL
, style
, cur
,
6171 "xsltParseStylesheetTop: unknown %s element\n",
6173 if (style
!= NULL
) style
->errors
++;
6176 /* do Forwards-Compatible Processing */
6177 xsltTransformError(NULL
, style
, cur
,
6178 "xsltParseStylesheetTop: ignoring unknown %s element\n",
6180 if (style
!= NULL
) style
->warnings
++;
6185 #ifdef WITH_XSLT_DEBUG_PARSING
6186 xsltGenericDebug(xsltGenericDebugContext
,
6187 "parsed %d templates\n", templates
);
6191 #endif /* else of XSLT_REFACTORED */
6193 #ifdef XSLT_REFACTORED
6195 * xsltParseSimplifiedStylesheetTree:
6197 * @style: the stylesheet (TODO: Change this to the compiler context)
6198 * @doc: the document containing the stylesheet.
6199 * @node: the node where the stylesheet is rooted at
6201 * Returns 0 in case of success, a positive result if an error occurred
6202 * and -1 on API and internal errors.
6205 xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt
,
6209 xsltTemplatePtr templ
;
6211 if ((cctxt
== NULL
) || (node
== NULL
))
6214 if (xsltParseAttrXSLTVersion(cctxt
, node
, 0) == XSLT_ELEMENT_CATEGORY_LRE
)
6217 * TODO: Adjust report, since this might be an
6218 * embedded stylesheet.
6220 xsltTransformError(NULL
, cctxt
->style
, node
,
6221 "The attribute 'xsl:version' is missing; cannot identify "
6222 "this document as an XSLT stylesheet document.\n");
6223 cctxt
->style
->errors
++;
6227 #ifdef WITH_XSLT_DEBUG_PARSING
6228 xsltGenericDebug(xsltGenericDebugContext
,
6229 "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
6233 * Create and link the template
6235 templ
= xsltNewTemplate();
6236 if (templ
== NULL
) {
6239 templ
->next
= cctxt
->style
->templates
;
6240 cctxt
->style
->templates
= templ
;
6241 templ
->match
= xmlStrdup(BAD_CAST
"/");
6244 * Note that we push the document-node in this special case.
6246 xsltCompilerNodePush(cctxt
, (xmlNodePtr
) doc
);
6248 * In every case, we need to have
6249 * the in-scope namespaces of the element, where the
6250 * stylesheet is rooted at, regardless if it's an XSLT
6251 * instruction or a literal result instruction (or if
6252 * this is an embedded stylesheet).
6254 cctxt
->inode
->inScopeNs
=
6255 xsltCompilerBuildInScopeNsList(cctxt
, node
);
6257 * Parse the content and register the match-pattern.
6259 xsltParseSequenceConstructor(cctxt
, node
);
6260 xsltCompilerNodePop(cctxt
, (xmlNodePtr
) doc
);
6262 templ
->elem
= (xmlNodePtr
) doc
;
6263 templ
->content
= node
;
6264 xsltAddTemplate(cctxt
->style
, templ
, NULL
, NULL
);
6265 cctxt
->style
->literal_result
= 1;
6269 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6271 * xsltRestoreDocumentNamespaces:
6272 * @ns: map of namespaces
6273 * @doc: the document
6275 * Restore the namespaces for the document
6277 * Returns 0 in case of success, -1 in case of failure
6280 xsltRestoreDocumentNamespaces(xsltNsMapPtr ns
, xmlDocPtr doc
)
6285 * Revert the changes we have applied to the namespace-URIs of
6288 while (ns
!= NULL
) {
6289 if ((ns
->doc
== doc
) && (ns
->ns
!= NULL
)) {
6290 ns
->ns
->href
= ns
->origNsName
;
6291 ns
->origNsName
= NULL
;
6298 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
6301 * xsltParseStylesheetProcess:
6302 * @style: the XSLT stylesheet (the current stylesheet-level)
6303 * @doc: and xmlDoc parsed XML
6305 * Parses an XSLT stylesheet, adding the associated structures.
6307 * xsltParseStylesheetImportedDoc() (xslt.c)
6308 * xsltParseStylesheetInclude() (imports.c)
6310 * Returns the value of the @style parameter if everything
6311 * went right, NULL if something went amiss.
6314 xsltParseStylesheetProcess(xsltStylesheetPtr style
, xmlDocPtr doc
)
6316 xsltCompilerCtxtPtr cctxt
;
6318 int oldIsSimplifiedStylesheet
;
6322 if ((style
== NULL
) || (doc
== NULL
))
6325 cctxt
= XSLT_CCTXT(style
);
6327 cur
= xmlDocGetRootElement(doc
);
6329 xsltTransformError(NULL
, style
, (xmlNodePtr
) doc
,
6330 "xsltParseStylesheetProcess : empty stylesheet\n");
6333 oldIsSimplifiedStylesheet
= cctxt
->simplified
;
6335 if ((IS_XSLT_ELEM(cur
)) &&
6336 ((IS_XSLT_NAME(cur
, "stylesheet")) ||
6337 (IS_XSLT_NAME(cur
, "transform")))) {
6338 #ifdef WITH_XSLT_DEBUG_PARSING
6339 xsltGenericDebug(xsltGenericDebugContext
,
6340 "xsltParseStylesheetProcess : found stylesheet\n");
6342 cctxt
->simplified
= 0;
6343 style
->literal_result
= 0;
6345 cctxt
->simplified
= 1;
6346 style
->literal_result
= 1;
6349 * Pre-process the stylesheet if not already done before.
6350 * This will remove PIs and comments, merge adjacent
6351 * text nodes, internalize strings, etc.
6353 if (! style
->nopreproc
)
6354 xsltParsePreprocessStylesheetTree(cctxt
, cur
);
6356 * Parse and compile the stylesheet.
6358 if (style
->literal_result
== 0) {
6359 if (xsltParseXSLTStylesheetElem(cctxt
, cur
) != 0)
6362 if (xsltParseSimplifiedStylesheetTree(cctxt
, doc
, cur
) != 0)
6366 cctxt
->simplified
= oldIsSimplifiedStylesheet
;
6371 #else /* XSLT_REFACTORED */
6374 * xsltParseStylesheetProcess:
6375 * @ret: the XSLT stylesheet (the current stylesheet-level)
6376 * @doc: and xmlDoc parsed XML
6378 * Parses an XSLT stylesheet, adding the associated structures.
6380 * xsltParseStylesheetImportedDoc() (xslt.c)
6381 * xsltParseStylesheetInclude() (imports.c)
6383 * Returns the value of the @style parameter if everything
6384 * went right, NULL if something went amiss.
6387 xsltParseStylesheetProcess(xsltStylesheetPtr ret
, xmlDocPtr doc
) {
6398 * First steps, remove blank nodes,
6399 * locate the xsl:stylesheet element and the
6400 * namespace declaration.
6402 cur
= xmlDocGetRootElement(doc
);
6404 xsltTransformError(NULL
, ret
, (xmlNodePtr
) doc
,
6405 "xsltParseStylesheetProcess : empty stylesheet\n");
6409 if ((IS_XSLT_ELEM(cur
)) &&
6410 ((IS_XSLT_NAME(cur
, "stylesheet")) ||
6411 (IS_XSLT_NAME(cur
, "transform")))) {
6412 #ifdef WITH_XSLT_DEBUG_PARSING
6413 xsltGenericDebug(xsltGenericDebugContext
,
6414 "xsltParseStylesheetProcess : found stylesheet\n");
6416 ret
->literal_result
= 0;
6417 xsltParseStylesheetExcludePrefix(ret
, cur
, 1);
6418 xsltParseStylesheetExtPrefix(ret
, cur
, 1);
6420 xsltParseStylesheetExcludePrefix(ret
, cur
, 0);
6421 xsltParseStylesheetExtPrefix(ret
, cur
, 0);
6422 ret
->literal_result
= 1;
6424 if (!ret
->nopreproc
) {
6425 xsltPrecomputeStylesheet(ret
, cur
);
6427 if (ret
->literal_result
== 0) {
6428 xsltParseStylesheetTop(ret
, cur
);
6431 xsltTemplatePtr
template;
6434 * the document itself might be the template, check xsl:version
6436 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"version", XSLT_NAMESPACE
);
6438 xsltTransformError(NULL
, ret
, cur
,
6439 "xsltParseStylesheetProcess : document is not a stylesheet\n");
6443 #ifdef WITH_XSLT_DEBUG_PARSING
6444 xsltGenericDebug(xsltGenericDebugContext
,
6445 "xsltParseStylesheetProcess : document is stylesheet\n");
6448 if (!xmlStrEqual(prop
, (const xmlChar
*)"1.0")) {
6449 xsltTransformError(NULL
, ret
, cur
,
6450 "xsl:version: only 1.0 features are supported\n");
6451 /* TODO set up compatibility when not XSLT 1.0 */
6457 * Create and link the template
6459 template = xsltNewTemplate();
6460 if (template == NULL
) {
6463 template->next
= ret
->templates
;
6464 ret
->templates
= template;
6465 template->match
= xmlStrdup((const xmlChar
*)"/");
6468 * parse the content and register the pattern
6470 xsltParseTemplateContent(ret
, (xmlNodePtr
) doc
);
6471 template->elem
= (xmlNodePtr
) doc
;
6472 template->content
= doc
->children
;
6473 xsltAddTemplate(ret
, template, NULL
, NULL
);
6474 ret
->literal_result
= 1;
6480 #endif /* else of XSLT_REFACTORED */
6483 * xsltParseStylesheetImportedDoc:
6484 * @doc: an xmlDoc parsed XML
6485 * @parentStyle: pointer to the parent stylesheet (if it exists)
6487 * parse an XSLT stylesheet building the associated structures
6488 * except the processing not needed for imported documents.
6490 * Returns a new XSLT stylesheet structure.
6494 xsltParseStylesheetImportedDoc(xmlDocPtr doc
,
6495 xsltStylesheetPtr parentStyle
) {
6496 xsltStylesheetPtr retStyle
;
6501 retStyle
= xsltNewStylesheet();
6502 if (retStyle
== NULL
)
6505 * Set the importing stylesheet module; also used to detect recursion.
6507 retStyle
->parent
= parentStyle
;
6509 * Adjust the string dict.
6511 if (doc
->dict
!= NULL
) {
6512 xmlDictFree(retStyle
->dict
);
6513 retStyle
->dict
= doc
->dict
;
6514 #ifdef WITH_XSLT_DEBUG
6515 xsltGenericDebug(xsltGenericDebugContext
,
6516 "reusing dictionary from %s for stylesheet\n",
6519 xmlDictReference(retStyle
->dict
);
6523 * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
6524 * the stylesheet to containt distinct namespace prefixes.
6526 xsltGatherNamespaces(retStyle
);
6528 #ifdef XSLT_REFACTORED
6530 xsltCompilerCtxtPtr cctxt
;
6531 xsltStylesheetPtr oldCurSheet
;
6533 if (parentStyle
== NULL
) {
6534 xsltPrincipalStylesheetDataPtr principalData
;
6536 * Principal stylesheet
6537 * --------------------
6539 retStyle
->principal
= retStyle
;
6541 * Create extra data for the principal stylesheet.
6543 principalData
= xsltNewPrincipalStylesheetData();
6544 if (principalData
== NULL
) {
6545 xsltFreeStylesheet(retStyle
);
6548 retStyle
->principalData
= principalData
;
6550 * Create the compilation context
6551 * ------------------------------
6552 * (only once; for the principal stylesheet).
6553 * This is currently the only function where the
6554 * compilation context is created.
6556 cctxt
= xsltCompilationCtxtCreate(retStyle
);
6557 if (cctxt
== NULL
) {
6558 xsltFreeStylesheet(retStyle
);
6561 retStyle
->compCtxt
= (void *) cctxt
;
6562 cctxt
->style
= retStyle
;
6563 cctxt
->dict
= retStyle
->dict
;
6564 cctxt
->psData
= principalData
;
6566 * Push initial dummy node info.
6569 xsltCompilerNodePush(cctxt
, (xmlNodePtr
) doc
);
6572 * Imported stylesheet.
6574 retStyle
->principal
= parentStyle
->principal
;
6575 cctxt
= parentStyle
->compCtxt
;
6576 retStyle
->compCtxt
= cctxt
;
6579 * Save the old and set the current stylesheet structure in the
6580 * compilation context.
6582 oldCurSheet
= cctxt
->style
;
6583 cctxt
->style
= retStyle
;
6585 retStyle
->doc
= doc
;
6586 xsltParseStylesheetProcess(retStyle
, doc
);
6588 cctxt
->style
= oldCurSheet
;
6589 if (parentStyle
== NULL
) {
6591 * Pop the initial dummy node info.
6593 xsltCompilerNodePop(cctxt
, (xmlNodePtr
) doc
);
6596 * Clear the compilation context of imported
6600 /* retStyle->compCtxt = NULL; */
6603 * Free the stylesheet if there were errors.
6605 if (retStyle
!= NULL
) {
6606 if (retStyle
->errors
!= 0) {
6607 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6609 * Restore all changes made to namespace URIs of ns-decls.
6611 if (cctxt
->psData
->nsMap
)
6612 xsltRestoreDocumentNamespaces(cctxt
->psData
->nsMap
, doc
);
6615 * Detach the doc from the stylesheet; otherwise the doc
6616 * will be freed in xsltFreeStylesheet().
6618 retStyle
->doc
= NULL
;
6620 * Cleanup the doc if its the main stylesheet.
6622 if (parentStyle
== NULL
) {
6623 xsltCleanupStylesheetTree(doc
, xmlDocGetRootElement(doc
));
6624 if (retStyle
->compCtxt
!= NULL
) {
6625 xsltCompilationCtxtFree(retStyle
->compCtxt
);
6626 retStyle
->compCtxt
= NULL
;
6630 xsltFreeStylesheet(retStyle
);
6636 #else /* XSLT_REFACTORED */
6640 retStyle
->doc
= doc
;
6641 if (xsltParseStylesheetProcess(retStyle
, doc
) == NULL
) {
6642 retStyle
->doc
= NULL
;
6643 xsltFreeStylesheet(retStyle
);
6646 if (retStyle
!= NULL
) {
6647 if (retStyle
->errors
!= 0) {
6648 retStyle
->doc
= NULL
;
6649 if (parentStyle
== NULL
)
6650 xsltCleanupStylesheetTree(doc
,
6651 xmlDocGetRootElement(doc
));
6652 xsltFreeStylesheet(retStyle
);
6656 #endif /* else of XSLT_REFACTORED */
6662 * xsltParseStylesheetDoc:
6663 * @doc: and xmlDoc parsed XML
6665 * parse an XSLT stylesheet, building the associated structures. doc
6666 * is kept as a reference within the returned stylesheet, so changes
6667 * to doc after the parsing will be reflected when the stylesheet
6668 * is applied, and the doc is automatically freed when the
6669 * stylesheet is closed.
6671 * Returns a new XSLT stylesheet structure.
6675 xsltParseStylesheetDoc(xmlDocPtr doc
) {
6676 xsltStylesheetPtr ret
;
6680 ret
= xsltParseStylesheetImportedDoc(doc
, NULL
);
6684 xsltResolveStylesheetAttributeSet(ret
);
6685 #ifdef XSLT_REFACTORED
6687 * Free the compilation context.
6688 * TODO: Check if it's better to move this cleanup to
6689 * xsltParseStylesheetImportedDoc().
6691 if (ret
->compCtxt
!= NULL
) {
6692 xsltCompilationCtxtFree(XSLT_CCTXT(ret
));
6693 ret
->compCtxt
= NULL
;
6700 * xsltParseStylesheetFile:
6701 * @filename: the filename/URL to the stylesheet
6703 * Load and parse an XSLT stylesheet
6705 * Returns a new XSLT stylesheet structure.
6709 xsltParseStylesheetFile(const xmlChar
* filename
) {
6710 xsltSecurityPrefsPtr sec
;
6711 xsltStylesheetPtr ret
;
6716 if (filename
== NULL
)
6719 #ifdef WITH_XSLT_DEBUG_PARSING
6720 xsltGenericDebug(xsltGenericDebugContext
,
6721 "xsltParseStylesheetFile : parse %s\n", filename
);
6725 * Security framework check
6727 sec
= xsltGetDefaultSecurityPrefs();
6731 res
= xsltCheckRead(sec
, NULL
, filename
);
6733 xsltTransformError(NULL
, NULL
, NULL
,
6734 "xsltParseStylesheetFile: read rights for %s denied\n",
6740 doc
= xsltDocDefaultLoader(filename
, NULL
, XSLT_PARSE_OPTIONS
,
6741 NULL
, XSLT_LOAD_START
);
6743 xsltTransformError(NULL
, NULL
, NULL
,
6744 "xsltParseStylesheetFile : cannot parse %s\n", filename
);
6747 ret
= xsltParseStylesheetDoc(doc
);
6756 /************************************************************************
6758 * Handling of Stylesheet PI *
6760 ************************************************************************/
6763 #define SKIP(val) cur += (val)
6764 #define NXT(val) cur[(val)]
6765 #define SKIP_BLANKS \
6766 while (IS_BLANK(CUR)) NEXT
6767 #define NEXT ((*cur) ? cur++ : cur)
6770 * xsltParseStylesheetPI:
6771 * @value: the value of the PI
6773 * This function checks that the type is text/xml and extracts
6774 * the URI-Reference for the stylesheet
6776 * Returns the URI-Reference for the stylesheet or NULL (it need to
6777 * be freed by the caller)
6780 xsltParseStylesheetPI(const xmlChar
*value
) {
6782 const xmlChar
*start
;
6785 xmlChar
*href
= NULL
;
6794 if ((CUR
== 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
6801 if ((CUR
!= '\'') && (CUR
!= '"'))
6806 while ((CUR
!= 0) && (CUR
!= tmp
))
6810 val
= xmlStrndup(start
, cur
- start
);
6814 if ((xmlStrcasecmp(val
, BAD_CAST
"text/xml")) &&
6815 (xmlStrcasecmp(val
, BAD_CAST
"text/xsl"))) {
6821 } else if ((CUR
== 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
6828 if ((CUR
!= '\'') && (CUR
!= '"'))
6833 while ((CUR
!= 0) && (CUR
!= tmp
))
6838 href
= xmlStrndup(start
, cur
- start
);
6841 while ((CUR
!= 0) && (!IS_BLANK(CUR
)))
6856 * xsltLoadStylesheetPI:
6857 * @doc: a document to process
6859 * This function tries to locate the stylesheet PI in the given document
6860 * If found, and if contained within the document, it will extract
6861 * that subtree to build the stylesheet to process @doc (doc itself will
6862 * be modified). If found but referencing an external document it will
6863 * attempt to load it and generate a stylesheet from it. In both cases,
6864 * the resulting stylesheet and the document need to be freed once the
6865 * transformation is done.
6867 * Returns a new XSLT stylesheet structure or NULL if not found.
6870 xsltLoadStylesheetPI(xmlDocPtr doc
) {
6872 xsltStylesheetPtr ret
= NULL
;
6873 xmlChar
*href
= NULL
;
6882 * Find the text/xml stylesheet PI id any before the root
6884 child
= doc
->children
;
6885 while ((child
!= NULL
) && (child
->type
!= XML_ELEMENT_NODE
)) {
6886 if ((child
->type
== XML_PI_NODE
) &&
6887 (xmlStrEqual(child
->name
, BAD_CAST
"xml-stylesheet"))) {
6888 href
= xsltParseStylesheetPI(child
->content
);
6892 child
= child
->next
;
6896 * If found check the href to select processing
6899 #ifdef WITH_XSLT_DEBUG_PARSING
6900 xsltGenericDebug(xsltGenericDebugContext
,
6901 "xsltLoadStylesheetPI : found PI href=%s\n", href
);
6903 URI
= xmlParseURI((const char *) href
);
6905 xsltTransformError(NULL
, NULL
, child
,
6906 "xml-stylesheet : href %s is not valid\n", href
);
6910 if ((URI
->fragment
!= NULL
) && (URI
->scheme
== NULL
) &&
6911 (URI
->opaque
== NULL
) && (URI
->authority
== NULL
) &&
6912 (URI
->server
== NULL
) && (URI
->user
== NULL
) &&
6913 (URI
->path
== NULL
) && (URI
->query
== NULL
)) {
6916 #ifdef WITH_XSLT_DEBUG_PARSING
6917 xsltGenericDebug(xsltGenericDebugContext
,
6918 "xsltLoadStylesheetPI : Reference to ID %s\n", href
);
6920 if (URI
->fragment
[0] == '#')
6921 ID
= xmlGetID(doc
, (const xmlChar
*) &(URI
->fragment
[1]));
6923 ID
= xmlGetID(doc
, (const xmlChar
*) URI
->fragment
);
6925 xsltTransformError(NULL
, NULL
, child
,
6926 "xml-stylesheet : no ID %s found\n", URI
->fragment
);
6929 xmlNodePtr subtree
, newtree
;
6932 #ifdef WITH_XSLT_DEBUG
6933 xsltGenericDebug(xsltGenericDebugContext
,
6934 "creating new document from %s for embedded stylesheet\n",
6938 * move the subtree in a new document passed to
6939 * the stylesheet analyzer
6941 subtree
= ID
->parent
;
6942 fake
= xmlNewDoc(NULL
);
6945 * Should the dictionary still be shared even though
6946 * the nodes are being copied rather than moved?
6948 fake
->dict
= doc
->dict
;
6949 xmlDictReference(doc
->dict
);
6950 #ifdef WITH_XSLT_DEBUG
6951 xsltGenericDebug(xsltGenericDebugContext
,
6952 "reusing dictionary from %s for embedded stylesheet\n",
6956 newtree
= xmlDocCopyNode(subtree
, fake
, 1);
6958 fake
->URL
= xmlNodeGetBase(doc
, subtree
->parent
);
6959 #ifdef WITH_XSLT_DEBUG
6960 xsltGenericDebug(xsltGenericDebugContext
,
6961 "set base URI for embedded stylesheet as %s\n",
6966 * Add all namespaces in scope of embedded stylesheet to
6967 * root element of newly created stylesheet document
6969 while ((subtree
= subtree
->parent
) != (xmlNodePtr
)doc
) {
6970 for (ns
= subtree
->ns
; ns
; ns
= ns
->next
) {
6971 xmlNewNs(newtree
, ns
->href
, ns
->prefix
);
6975 xmlAddChild((xmlNodePtr
)fake
, newtree
);
6976 ret
= xsltParseStylesheetDoc(fake
);
6982 xmlChar
*URL
, *base
;
6985 * Reference to an external stylesheet
6988 base
= xmlNodeGetBase(doc
, (xmlNodePtr
) doc
);
6989 URL
= xmlBuildURI(href
, base
);
6991 #ifdef WITH_XSLT_DEBUG_PARSING
6992 xsltGenericDebug(xsltGenericDebugContext
,
6993 "xsltLoadStylesheetPI : fetching %s\n", URL
);
6995 ret
= xsltParseStylesheetFile(URL
);
6998 #ifdef WITH_XSLT_DEBUG_PARSING
6999 xsltGenericDebug(xsltGenericDebugContext
,
7000 "xsltLoadStylesheetPI : fetching %s\n", href
);
7002 ret
= xsltParseStylesheetFile(href
);