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"
45 #include "xsltlocale.h"
47 #ifdef WITH_XSLT_DEBUG
48 #define WITH_XSLT_DEBUG_PARSING
49 /* #define WITH_XSLT_DEBUG_BLANKS */
52 const char *xsltEngineVersion
= LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA
;
53 const int xsltLibxsltVersion
= LIBXSLT_VERSION
;
54 const int xsltLibxmlVersion
= LIBXML_VERSION
;
56 #ifdef XSLT_REFACTORED
58 const xmlChar
*xsltConstNamespaceNameXSLT
= (const xmlChar
*) XSLT_NAMESPACE
;
60 #define XSLT_ELEMENT_CATEGORY_XSLT 0
61 #define XSLT_ELEMENT_CATEGORY_EXTENSION 1
62 #define XSLT_ELEMENT_CATEGORY_LRE 2
65 * xsltLiteralResultMarker:
66 * Marker for Literal result elements, in order to avoid multiple attempts
67 * to recognize such elements in the stylesheet's tree.
68 * This marker is set on node->psvi during the initial traversal
69 * of a stylesheet's node tree.
71 const xmlChar *xsltLiteralResultMarker =
72 (const xmlChar *) "Literal Result Element";
77 * Marker for xsl:text elements. Used to recognize xsl:text elements
78 * for post-processing of the stylesheet's tree, where those
79 * elements are removed from the tree.
81 const xmlChar
*xsltXSLTTextMarker
= (const xmlChar
*) "XSLT Text Element";
85 * Marker for XSLT attribute on Literal Result Elements.
87 const xmlChar
*xsltXSLTAttrMarker
= (const xmlChar
*) "LRE XSLT Attr";
91 #ifdef XSLT_LOCALE_WINAPI
92 extern xmlRMutexPtr xsltLocaleMutex
;
95 * Harmless but avoiding a problem when compiling against a
96 * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
98 #ifndef LIBXML_DEBUG_ENABLED
99 double xmlXPathStringEvalNumber(const xmlChar
*str
);
108 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
114 #define IS_BLANK_NODE(n) \
115 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
118 * xsltParseContentError:
120 * @style: the stylesheet
121 * @node: the node where the error occured
123 * Compile-time error function.
126 xsltParseContentError(xsltStylesheetPtr style
,
129 if ((style
== NULL
) || (node
== NULL
))
132 if (IS_XSLT_ELEM(node
))
133 xsltTransformError(NULL
, style
, node
,
134 "The XSLT-element '%s' is not allowed at this position.\n",
137 xsltTransformError(NULL
, style
, node
,
138 "The element '%s' is not allowed at this position.\n",
143 #ifdef XSLT_REFACTORED
147 * @style: the transformation stylesheet
148 * @value: the excluded namespace name to push on the stack
150 * Push an excluded namespace name on the stack
152 * Returns the new index in the stack or -1 if already present or
156 exclPrefixPush(xsltStylesheetPtr style
, xmlChar
* value
)
160 if (style
->exclPrefixMax
== 0) {
161 style
->exclPrefixMax
= 4;
162 style
->exclPrefixTab
=
163 (xmlChar
* *)xmlMalloc(style
->exclPrefixMax
*
164 sizeof(style
->exclPrefixTab
[0]));
165 if (style
->exclPrefixTab
== NULL
) {
166 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
170 /* do not push duplicates */
171 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
172 if (xmlStrEqual(style
->exclPrefixTab
[i
], value
))
175 if (style
->exclPrefixNr
>= style
->exclPrefixMax
) {
176 style
->exclPrefixMax
*= 2;
177 style
->exclPrefixTab
=
178 (xmlChar
* *)xmlRealloc(style
->exclPrefixTab
,
179 style
->exclPrefixMax
*
180 sizeof(style
->exclPrefixTab
[0]));
181 if (style
->exclPrefixTab
== NULL
) {
182 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
186 style
->exclPrefixTab
[style
->exclPrefixNr
] = value
;
187 style
->exclPrefix
= value
;
188 return (style
->exclPrefixNr
++);
192 * @style: the transformation stylesheet
194 * Pop an excluded prefix value from the stack
196 * Returns the stored excluded prefix value
199 exclPrefixPop(xsltStylesheetPtr style
)
203 if (style
->exclPrefixNr
<= 0)
205 style
->exclPrefixNr
--;
206 if (style
->exclPrefixNr
> 0)
207 style
->exclPrefix
= style
->exclPrefixTab
[style
->exclPrefixNr
- 1];
209 style
->exclPrefix
= NULL
;
210 ret
= style
->exclPrefixTab
[style
->exclPrefixNr
];
211 style
->exclPrefixTab
[style
->exclPrefixNr
] = 0;
216 /************************************************************************
220 ************************************************************************/
222 static int initialized
= 0;
226 * Initializes the processor (e.g. registers built-in extensions,
231 if (initialized
== 0) {
233 #ifdef XSLT_LOCALE_WINAPI
234 xsltLocaleMutex
= xmlNewRMutex();
236 xsltRegisterAllExtras();
243 * Uninitializes the processor.
247 #ifdef XSLT_LOCALE_WINAPI
248 xmlFreeRMutex(xsltLocaleMutex
);
249 xsltLocaleMutex
= NULL
;
258 * Check if a string is ignorable
260 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
263 xsltIsBlank(xmlChar
*str
) {
267 if (!(IS_BLANK(*str
))) return(0);
273 /************************************************************************
275 * Routines to handle XSLT data structures *
277 ************************************************************************/
278 static xsltDecimalFormatPtr
279 xsltNewDecimalFormat(const xmlChar
*nsUri
, xmlChar
*name
)
281 xsltDecimalFormatPtr self
;
282 /* UTF-8 for 0x2030 */
283 static const xmlChar permille
[4] = {0xe2, 0x80, 0xb0, 0};
285 self
= xmlMalloc(sizeof(xsltDecimalFormat
));
292 self
->digit
= xmlStrdup(BAD_CAST("#"));
293 self
->patternSeparator
= xmlStrdup(BAD_CAST(";"));
294 self
->decimalPoint
= xmlStrdup(BAD_CAST("."));
295 self
->grouping
= xmlStrdup(BAD_CAST(","));
296 self
->percent
= xmlStrdup(BAD_CAST("%"));
297 self
->permille
= xmlStrdup(BAD_CAST(permille
));
298 self
->zeroDigit
= xmlStrdup(BAD_CAST("0"));
299 self
->minusSign
= xmlStrdup(BAD_CAST("-"));
300 self
->infinity
= xmlStrdup(BAD_CAST("Infinity"));
301 self
->noNumber
= xmlStrdup(BAD_CAST("NaN"));
307 xsltFreeDecimalFormat(xsltDecimalFormatPtr self
)
311 xmlFree(self
->digit
);
312 if (self
->patternSeparator
)
313 xmlFree(self
->patternSeparator
);
314 if (self
->decimalPoint
)
315 xmlFree(self
->decimalPoint
);
317 xmlFree(self
->grouping
);
319 xmlFree(self
->percent
);
321 xmlFree(self
->permille
);
323 xmlFree(self
->zeroDigit
);
325 xmlFree(self
->minusSign
);
327 xmlFree(self
->infinity
);
329 xmlFree(self
->noNumber
);
337 xsltFreeDecimalFormatList(xsltStylesheetPtr self
)
339 xsltDecimalFormatPtr iter
;
340 xsltDecimalFormatPtr tmp
;
345 iter
= self
->decimalFormat
;
346 while (iter
!= NULL
) {
348 xsltFreeDecimalFormat(iter
);
354 * xsltDecimalFormatGetByName:
355 * @style: the XSLT stylesheet
356 * @name: the decimal-format name to find
358 * Find decimal-format by name
360 * Returns the xsltDecimalFormatPtr
363 xsltDecimalFormatGetByName(xsltStylesheetPtr style
, xmlChar
*name
)
365 xsltDecimalFormatPtr result
= NULL
;
368 return style
->decimalFormat
;
370 while (style
!= NULL
) {
371 for (result
= style
->decimalFormat
->next
;
373 result
= result
->next
) {
374 if ((result
->nsUri
== NULL
) && xmlStrEqual(name
, result
->name
))
377 style
= xsltNextImport(style
);
383 * xsltDecimalFormatGetByQName:
384 * @style: the XSLT stylesheet
385 * @nsUri: the namespace URI of the QName
386 * @name: the local part of the QName
388 * Find decimal-format by QName
390 * Returns the xsltDecimalFormatPtr
393 xsltDecimalFormatGetByQName(xsltStylesheetPtr style
, const xmlChar
*nsUri
,
396 xsltDecimalFormatPtr result
= NULL
;
399 return style
->decimalFormat
;
401 while (style
!= NULL
) {
402 for (result
= style
->decimalFormat
->next
;
404 result
= result
->next
) {
405 if (xmlStrEqual(nsUri
, result
->nsUri
) &&
406 xmlStrEqual(name
, result
->name
))
409 style
= xsltNextImport(style
);
418 * Create a new XSLT Template
420 * Returns the newly allocated xsltTemplatePtr or NULL in case of error
422 static xsltTemplatePtr
423 xsltNewTemplate(void) {
426 cur
= (xsltTemplatePtr
) xmlMalloc(sizeof(xsltTemplate
));
428 xsltTransformError(NULL
, NULL
, NULL
,
429 "xsltNewTemplate : malloc failed\n");
432 memset(cur
, 0, sizeof(xsltTemplate
));
433 cur
->priority
= XSLT_PAT_NO_PRIORITY
;
439 * @template: an XSLT template
441 * Free up the memory allocated by @template
444 xsltFreeTemplate(xsltTemplatePtr
template) {
445 if (template == NULL
)
447 if (template->match
) xmlFree(template->match
);
449 * NOTE: @name and @nameURI are put into the string dict now.
450 * if (template->name) xmlFree(template->name);
451 * if (template->nameURI) xmlFree(template->nameURI);
454 if (template->mode) xmlFree(template->mode);
455 if (template->modeURI) xmlFree(template->modeURI);
457 if (template->inheritedNs
) xmlFree(template->inheritedNs
);
459 /* free profiling data */
460 if (template->templCalledTab
) xmlFree(template->templCalledTab
);
461 if (template->templCountTab
) xmlFree(template->templCountTab
);
463 memset(template, -1, sizeof(xsltTemplate
));
468 * xsltFreeTemplateList:
469 * @template: an XSLT template list
471 * Free up the memory allocated by all the elements of @template
474 xsltFreeTemplateList(xsltTemplatePtr
template) {
477 while (template != NULL
) {
479 template = template->next
;
480 xsltFreeTemplate(cur
);
484 #ifdef XSLT_REFACTORED
487 xsltFreeNsAliasList(xsltNsAliasPtr item
)
499 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
501 xsltFreeNamespaceMap(xsltNsMapPtr item
)
514 xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt
,
521 if ((cctxt
== NULL
) || (doc
== NULL
) || (ns
== NULL
))
524 ret
= (xsltNsMapPtr
) xmlMalloc(sizeof(xsltNsMap
));
526 xsltTransformError(NULL
, cctxt
->style
, elem
,
527 "Internal error: (xsltNewNamespaceMapItem) "
528 "memory allocation failed.\n");
531 memset(ret
, 0, sizeof(xsltNsMap
));
534 ret
->origNsName
= ns
->href
;
536 * Store the item at current stylesheet-level.
538 if (cctxt
->psData
->nsMap
!= NULL
)
539 ret
->next
= cctxt
->psData
->nsMap
;
540 cctxt
->psData
->nsMap
= ret
;
544 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
547 * xsltCompilerVarInfoFree:
548 * @cctxt: the compilation context
550 * Frees the list of information for vars/params.
553 xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt
)
555 xsltVarInfoPtr ivar
= cctxt
->ivars
, ivartmp
;
565 * xsltCompilerCtxtFree:
567 * Free an XSLT compiler context.
570 xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt
)
574 #ifdef WITH_XSLT_DEBUG_PARSING
575 xsltGenericDebug(xsltGenericDebugContext
,
576 "Freeing compilation context\n");
577 xsltGenericDebug(xsltGenericDebugContext
,
578 "### Max inodes: %d\n", cctxt
->maxNodeInfos
);
579 xsltGenericDebug(xsltGenericDebugContext
,
580 "### Max LREs : %d\n", cctxt
->maxLREs
);
585 if (cctxt
->inodeList
!= NULL
) {
586 xsltCompilerNodeInfoPtr tmp
, cur
= cctxt
->inodeList
;
587 while (cur
!= NULL
) {
593 if (cctxt
->tmpList
!= NULL
)
594 xsltPointerListFree(cctxt
->tmpList
);
595 if (cctxt
->nsAliases
!= NULL
)
596 xsltFreeNsAliasList(cctxt
->nsAliases
);
599 xsltCompilerVarInfoFree(cctxt
);
605 * xsltCompilerCreate:
607 * Creates an XSLT compiler context.
609 * Returns the pointer to the created xsltCompilerCtxt or
610 * NULL in case of an internal error.
612 static xsltCompilerCtxtPtr
613 xsltCompilationCtxtCreate(xsltStylesheetPtr style
) {
614 xsltCompilerCtxtPtr ret
;
616 ret
= (xsltCompilerCtxtPtr
) xmlMalloc(sizeof(xsltCompilerCtxt
));
618 xsltTransformError(NULL
, style
, NULL
,
619 "xsltCompilerCreate: allocation of compiler "
620 "context failed.\n");
623 memset(ret
, 0, sizeof(xsltCompilerCtxt
));
625 ret
->errSeverity
= XSLT_ERROR_SEVERITY_ERROR
;
626 ret
->tmpList
= xsltPointerListCreate(20);
627 if (ret
->tmpList
== NULL
) {
634 xsltCompilationCtxtFree(ret
);
639 xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first
)
641 xsltEffectiveNsPtr tmp
;
643 while (first
!= NULL
) {
645 first
= first
->nextInStore
;
651 xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data
)
656 if (data
->inScopeNamespaces
!= NULL
) {
658 xsltNsListContainerPtr nsi
;
659 xsltPointerListPtr list
=
660 (xsltPointerListPtr
) data
->inScopeNamespaces
;
662 for (i
= 0; i
< list
->number
; i
++) {
664 * REVISIT TODO: Free info of in-scope namespaces.
666 nsi
= (xsltNsListContainerPtr
) list
->items
[i
];
667 if (nsi
->list
!= NULL
)
671 xsltPointerListFree(list
);
672 data
->inScopeNamespaces
= NULL
;
675 if (data
->exclResultNamespaces
!= NULL
) {
677 xsltPointerListPtr list
= (xsltPointerListPtr
)
678 data
->exclResultNamespaces
;
680 for (i
= 0; i
< list
->number
; i
++)
681 xsltPointerListFree((xsltPointerListPtr
) list
->items
[i
]);
683 xsltPointerListFree(list
);
684 data
->exclResultNamespaces
= NULL
;
687 if (data
->extElemNamespaces
!= NULL
) {
688 xsltPointerListPtr list
= (xsltPointerListPtr
)
689 data
->extElemNamespaces
;
692 for (i
= 0; i
< list
->number
; i
++)
693 xsltPointerListFree((xsltPointerListPtr
) list
->items
[i
]);
695 xsltPointerListFree(list
);
696 data
->extElemNamespaces
= NULL
;
698 if (data
->effectiveNs
) {
699 xsltLREEffectiveNsNodesFree(data
->effectiveNs
);
700 data
->effectiveNs
= NULL
;
702 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
703 xsltFreeNamespaceMap(data
->nsMap
);
708 static xsltPrincipalStylesheetDataPtr
709 xsltNewPrincipalStylesheetData(void)
711 xsltPrincipalStylesheetDataPtr ret
;
713 ret
= (xsltPrincipalStylesheetDataPtr
)
714 xmlMalloc(sizeof(xsltPrincipalStylesheetData
));
716 xsltTransformError(NULL
, NULL
, NULL
,
717 "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
720 memset(ret
, 0, sizeof(xsltPrincipalStylesheetData
));
723 * Global list of in-scope namespaces.
725 ret
->inScopeNamespaces
= xsltPointerListCreate(-1);
726 if (ret
->inScopeNamespaces
== NULL
)
729 * Global list of excluded result ns-decls.
731 ret
->exclResultNamespaces
= xsltPointerListCreate(-1);
732 if (ret
->exclResultNamespaces
== NULL
)
735 * Global list of extension instruction namespace names.
737 ret
->extElemNamespaces
= xsltPointerListCreate(-1);
738 if (ret
->extElemNamespaces
== NULL
)
751 * xsltNewStylesheetInternal:
752 * @parent: the parent stylesheet or NULL
754 * Create a new XSLT Stylesheet
756 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
758 static xsltStylesheetPtr
759 xsltNewStylesheetInternal(xsltStylesheetPtr parent
) {
760 xsltStylesheetPtr ret
= NULL
;
762 ret
= (xsltStylesheetPtr
) xmlMalloc(sizeof(xsltStylesheet
));
764 xsltTransformError(NULL
, NULL
, NULL
,
765 "xsltNewStylesheet : malloc failed\n");
768 memset(ret
, 0, sizeof(xsltStylesheet
));
770 ret
->parent
= parent
;
771 ret
->omitXmlDeclaration
= -1;
772 ret
->standalone
= -1;
773 ret
->decimalFormat
= xsltNewDecimalFormat(NULL
, NULL
);
777 ret
->exclPrefixNr
= 0;
778 ret
->exclPrefixMax
= 0;
779 ret
->exclPrefixTab
= NULL
;
780 ret
->extInfos
= NULL
;
782 ret
->internalized
= 1;
783 ret
->literal_result
= 0;
784 ret
->forwards_compatible
= 0;
785 ret
->dict
= xmlDictCreate();
786 #ifdef WITH_XSLT_DEBUG
787 xsltGenericDebug(xsltGenericDebugContext
,
788 "creating dictionary for stylesheet\n");
791 if (parent
== NULL
) {
792 ret
->principal
= ret
;
794 ret
->xpathCtxt
= xmlXPathNewContext(NULL
);
795 if (ret
->xpathCtxt
== NULL
) {
796 xsltTransformError(NULL
, NULL
, NULL
,
797 "xsltNewStylesheet: xmlXPathNewContext failed\n");
800 if (xmlXPathContextSetCache(ret
->xpathCtxt
, 1, -1, 0) == -1)
803 ret
->principal
= parent
->principal
;
812 xsltFreeStylesheet(ret
);
819 * Create a new XSLT Stylesheet
821 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
824 xsltNewStylesheet(void) {
825 return xsltNewStylesheetInternal(NULL
);
830 * @style: an XSLT stylesheet
832 * Allocate an extra runtime information slot statically while compiling
833 * the stylesheet and return its number
835 * Returns the number of the slot
838 xsltAllocateExtra(xsltStylesheetPtr style
)
840 return(style
->extrasNr
++);
844 * xsltAllocateExtraCtxt:
845 * @ctxt: an XSLT transformation context
847 * Allocate an extra runtime information slot at run-time
848 * and return its number
849 * This make sure there is a slot ready in the transformation context
851 * Returns the number of the slot
854 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt
)
856 if (ctxt
->extrasNr
>= ctxt
->extrasMax
) {
858 if (ctxt
->extrasNr
== 0) {
859 ctxt
->extrasMax
= 20;
860 ctxt
->extras
= (xsltRuntimeExtraPtr
)
861 xmlMalloc(ctxt
->extrasMax
* sizeof(xsltRuntimeExtra
));
862 if (ctxt
->extras
== NULL
) {
863 xsltTransformError(ctxt
, NULL
, NULL
,
864 "xsltAllocateExtraCtxt: out of memory\n");
867 for (i
= 0;i
< ctxt
->extrasMax
;i
++) {
868 ctxt
->extras
[i
].info
= NULL
;
869 ctxt
->extras
[i
].deallocate
= NULL
;
870 ctxt
->extras
[i
].val
.ptr
= NULL
;
874 xsltRuntimeExtraPtr tmp
;
876 ctxt
->extrasMax
+= 100;
877 tmp
= (xsltRuntimeExtraPtr
) xmlRealloc(ctxt
->extras
,
878 ctxt
->extrasMax
* sizeof(xsltRuntimeExtra
));
880 xsltTransformError(ctxt
, NULL
, NULL
,
881 "xsltAllocateExtraCtxt: out of memory\n");
885 for (i
= ctxt
->extrasNr
;i
< ctxt
->extrasMax
;i
++) {
886 ctxt
->extras
[i
].info
= NULL
;
887 ctxt
->extras
[i
].deallocate
= NULL
;
888 ctxt
->extras
[i
].val
.ptr
= NULL
;
892 return(ctxt
->extrasNr
++);
896 * xsltFreeStylesheetList:
897 * @style: an XSLT stylesheet list
899 * Free up the memory allocated by the list @style
902 xsltFreeStylesheetList(xsltStylesheetPtr style
) {
903 xsltStylesheetPtr next
;
905 while (style
!= NULL
) {
907 xsltFreeStylesheet(style
);
913 * xsltCleanupStylesheetTree:
915 * @doc: the document-node
916 * @node: the element where the stylesheet is rooted at
918 * Actually @node need not be the document-element, but
919 * currently Libxslt does not support embedded stylesheets.
921 * Returns 0 if OK, -1 on API or internal errors.
924 xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED
,
925 xmlNodePtr rootElem ATTRIBUTE_UNUSED
)
927 #if 0 /* TODO: Currently disabled, since probably not needed. */
930 if ((doc
== NULL
) || (rootElem
== NULL
) ||
931 (rootElem
->type
!= XML_ELEMENT_NODE
) ||
932 (doc
!= rootElem
->doc
))
936 * Cleanup was suggested by Aleksey Sanin:
937 * Clear the PSVI field to avoid problems if the
938 * node-tree of the stylesheet is intended to be used for
939 * further processing by the user (e.g. for compiling it
940 * once again - although not recommended).
944 while (cur
!= NULL
) {
945 if (cur
->type
== XML_ELEMENT_NODE
) {
947 * Clear the PSVI field.
959 if (cur
->next
!= NULL
)
973 * xsltFreeStylesheet:
974 * @style: an XSLT stylesheet
976 * Free up the memory allocated by @style
979 xsltFreeStylesheet(xsltStylesheetPtr style
)
984 #ifdef XSLT_REFACTORED
986 * Start with a cleanup of the main stylesheet's doc.
988 if ((style
->principal
== style
) && (style
->doc
))
989 xsltCleanupStylesheetTree(style
->doc
,
990 xmlDocGetRootElement(style
->doc
));
991 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
993 * Restore changed ns-decls before freeing the document.
995 if ((style
->doc
!= NULL
) &&
996 XSLT_HAS_INTERNAL_NSMAP(style
))
998 xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style
),
1001 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
1004 * Start with a cleanup of the main stylesheet's doc.
1006 if ((style
->parent
== NULL
) && (style
->doc
))
1007 xsltCleanupStylesheetTree(style
->doc
,
1008 xmlDocGetRootElement(style
->doc
));
1009 #endif /* XSLT_REFACTORED */
1011 xsltFreeKeys(style
);
1012 xsltFreeExts(style
);
1013 xsltFreeTemplateHashes(style
);
1014 xsltFreeDecimalFormatList(style
);
1015 xsltFreeTemplateList(style
->templates
);
1016 xsltFreeAttributeSetsHashes(style
);
1017 xsltFreeNamespaceAliasHashes(style
);
1018 xsltFreeStylePreComps(style
);
1020 * Free documents of all included stylsheet modules of this
1023 xsltFreeStyleDocuments(style
);
1025 * TODO: Best time to shutdown extension stuff?
1027 xsltShutdownExts(style
);
1029 if (style
->variables
!= NULL
)
1030 xsltFreeStackElemList(style
->variables
);
1031 if (style
->cdataSection
!= NULL
)
1032 xmlHashFree(style
->cdataSection
, NULL
);
1033 if (style
->stripSpaces
!= NULL
)
1034 xmlHashFree(style
->stripSpaces
, NULL
);
1035 if (style
->nsHash
!= NULL
)
1036 xmlHashFree(style
->nsHash
, NULL
);
1037 if (style
->exclPrefixTab
!= NULL
)
1038 xmlFree(style
->exclPrefixTab
);
1039 if (style
->method
!= NULL
)
1040 xmlFree(style
->method
);
1041 if (style
->methodURI
!= NULL
)
1042 xmlFree(style
->methodURI
);
1043 if (style
->version
!= NULL
)
1044 xmlFree(style
->version
);
1045 if (style
->encoding
!= NULL
)
1046 xmlFree(style
->encoding
);
1047 if (style
->doctypePublic
!= NULL
)
1048 xmlFree(style
->doctypePublic
);
1049 if (style
->doctypeSystem
!= NULL
)
1050 xmlFree(style
->doctypeSystem
);
1051 if (style
->mediaType
!= NULL
)
1052 xmlFree(style
->mediaType
);
1054 xsltFreeAVTList(style
->attVTs
);
1055 if (style
->imports
!= NULL
)
1056 xsltFreeStylesheetList(style
->imports
);
1058 #ifdef XSLT_REFACTORED
1060 * If this is the principal stylesheet, then
1061 * free its internal data.
1063 if (style
->principal
== style
) {
1064 if (style
->principalData
) {
1065 xsltFreePrincipalStylesheetData(style
->principalData
);
1066 style
->principalData
= NULL
;
1071 * Better to free the main document of this stylesheet level
1072 * at the end - so here.
1074 if (style
->doc
!= NULL
) {
1075 xmlFreeDoc(style
->doc
);
1078 #ifdef WITH_XSLT_DEBUG
1079 xsltGenericDebug(xsltGenericDebugContext
,
1080 "freeing dictionary from stylesheet\n");
1082 xmlDictFree(style
->dict
);
1084 if (style
->xpathCtxt
!= NULL
)
1085 xmlXPathFreeContext(style
->xpathCtxt
);
1087 memset(style
, -1, sizeof(xsltStylesheet
));
1091 /************************************************************************
1093 * Parsing of an XSLT Stylesheet *
1095 ************************************************************************/
1097 #ifdef XSLT_REFACTORED
1099 * This is now performed in an optimized way in xsltParseXSLTTemplate.
1103 * xsltGetInheritedNsList:
1104 * @style: the stylesheet
1105 * @template: the template
1106 * @node: the current node
1108 * Search all the namespace applying to a given element except the ones
1109 * from excluded output prefixes currently in scope. Initialize the
1110 * template inheritedNs list with it.
1112 * Returns the number of entries found
1115 xsltGetInheritedNsList(xsltStylesheetPtr style
,
1116 xsltTemplatePtr
template,
1120 xmlNsPtr
*ret
= NULL
;
1125 if ((style
== NULL
) || (template == NULL
) || (node
== NULL
) ||
1126 (template->inheritedNsNr
!= 0) || (template->inheritedNs
!= NULL
))
1128 while (node
!= NULL
) {
1129 if (node
->type
== XML_ELEMENT_NODE
) {
1131 while (cur
!= NULL
) {
1132 if (xmlStrEqual(cur
->href
, XSLT_NAMESPACE
))
1135 if ((cur
->prefix
!= NULL
) &&
1136 (xsltCheckExtPrefix(style
, cur
->prefix
)))
1139 * Check if this namespace was excluded.
1140 * Note that at this point only the exclusions defined
1141 * on the topmost stylesheet element are in the exclusion-list.
1143 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
1144 if (xmlStrEqual(cur
->href
, style
->exclPrefixTab
[i
]))
1149 (xmlNsPtr
*) xmlMalloc((maxns
+ 1) *
1152 xmlGenericError(xmlGenericErrorContext
,
1153 "xsltGetInheritedNsList : out of memory!\n");
1159 * Skip shadowed namespace bindings.
1161 for (i
= 0; i
< nbns
; i
++) {
1162 if ((cur
->prefix
== ret
[i
]->prefix
) ||
1163 (xmlStrEqual(cur
->prefix
, ret
[i
]->prefix
)))
1167 if (nbns
>= maxns
) {
1169 ret
= (xmlNsPtr
*) xmlRealloc(ret
,
1174 xmlGenericError(xmlGenericErrorContext
,
1175 "xsltGetInheritedNsList : realloc failed!\n");
1186 node
= node
->parent
;
1189 #ifdef WITH_XSLT_DEBUG_PARSING
1190 xsltGenericDebug(xsltGenericDebugContext
,
1191 "template has %d inherited namespaces\n", nbns
);
1193 template->inheritedNsNr
= nbns
;
1194 template->inheritedNs
= ret
;
1198 #endif /* else of XSLT_REFACTORED */
1201 * xsltParseStylesheetOutput:
1202 * @style: the XSLT stylesheet
1203 * @cur: the "output" element
1205 * parse an XSLT stylesheet output element and record
1206 * information related to the stylesheet output
1210 xsltParseStylesheetOutput(xsltStylesheetPtr style
, xmlNodePtr cur
)
1217 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1220 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "version", NULL
);
1222 if (style
->version
!= NULL
)
1223 xmlFree(style
->version
);
1224 style
->version
= prop
;
1227 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "encoding", NULL
);
1229 if (style
->encoding
!= NULL
)
1230 xmlFree(style
->encoding
);
1231 style
->encoding
= prop
;
1234 /* relaxed to support xt:document
1235 * TODO KB: What does "relaxed to support xt:document" mean?
1237 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "method", NULL
);
1241 if (style
->method
!= NULL
)
1242 xmlFree(style
->method
);
1243 style
->method
= NULL
;
1244 if (style
->methodURI
!= NULL
)
1245 xmlFree(style
->methodURI
);
1246 style
->methodURI
= NULL
;
1249 * TODO: Don't use xsltGetQNameURI().
1251 URI
= xsltGetQNameURI(cur
, &prop
);
1253 if (style
!= NULL
) style
->errors
++;
1254 } else if (URI
== NULL
) {
1255 if ((xmlStrEqual(prop
, (const xmlChar
*) "xml")) ||
1256 (xmlStrEqual(prop
, (const xmlChar
*) "html")) ||
1257 (xmlStrEqual(prop
, (const xmlChar
*) "text"))) {
1258 style
->method
= prop
;
1260 xsltTransformError(NULL
, style
, cur
,
1261 "invalid value for method: %s\n", prop
);
1262 if (style
!= NULL
) style
->warnings
++;
1266 style
->method
= prop
;
1267 style
->methodURI
= xmlStrdup(URI
);
1271 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "doctype-system", NULL
);
1273 if (style
->doctypeSystem
!= NULL
)
1274 xmlFree(style
->doctypeSystem
);
1275 style
->doctypeSystem
= prop
;
1278 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "doctype-public", NULL
);
1280 if (style
->doctypePublic
!= NULL
)
1281 xmlFree(style
->doctypePublic
);
1282 style
->doctypePublic
= prop
;
1285 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "standalone", NULL
);
1287 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1288 style
->standalone
= 1;
1289 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1290 style
->standalone
= 0;
1292 xsltTransformError(NULL
, style
, cur
,
1293 "invalid value for standalone: %s\n", prop
);
1299 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "indent", NULL
);
1301 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1303 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1306 xsltTransformError(NULL
, style
, cur
,
1307 "invalid value for indent: %s\n", prop
);
1313 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "omit-xml-declaration", NULL
);
1315 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1316 style
->omitXmlDeclaration
= 1;
1317 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1318 style
->omitXmlDeclaration
= 0;
1320 xsltTransformError(NULL
, style
, cur
,
1321 "invalid value for omit-xml-declaration: %s\n",
1328 elements
= xmlGetNsProp(cur
, (const xmlChar
*) "cdata-section-elements",
1330 if (elements
!= NULL
) {
1331 if (style
->cdataSection
== NULL
)
1332 style
->cdataSection
= xmlHashCreate(10);
1333 if (style
->cdataSection
== NULL
)
1337 while (*element
!= 0) {
1338 while (IS_BLANK(*element
))
1343 while ((*end
!= 0) && (!IS_BLANK(*end
)))
1345 element
= xmlStrndup(element
, end
- element
);
1347 #ifdef WITH_XSLT_DEBUG_PARSING
1348 xsltGenericDebug(xsltGenericDebugContext
,
1349 "add cdata section output element %s\n",
1352 if (xmlValidateQName(BAD_CAST element
, 0) != 0) {
1353 xsltTransformError(NULL
, style
, cur
,
1354 "Attribute 'cdata-section-elements': The value "
1355 "'%s' is not a valid QName.\n", element
);
1362 * TODO: Don't use xsltGetQNameURI().
1364 URI
= xsltGetQNameURI(cur
, &element
);
1365 if (element
== NULL
) {
1367 * TODO: We'll report additionally an error
1368 * via the stylesheet's error handling.
1370 xsltTransformError(NULL
, style
, cur
,
1371 "Attribute 'cdata-section-elements': "
1372 "Not a valid QName.\n");
1378 * XSLT-1.0 "Each QName is expanded into an
1379 * expanded-name using the namespace declarations in
1380 * effect on the xsl:output element in which the QName
1381 * occurs; if there is a default namespace, it is used
1382 * for QNames that do not have a prefix"
1383 * NOTE: Fix of bug #339570.
1386 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1390 xmlHashAddEntry2(style
->cdataSection
, element
, URI
,
1401 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "media-type", NULL
);
1403 if (style
->mediaType
)
1404 xmlFree(style
->mediaType
);
1405 style
->mediaType
= prop
;
1407 if (cur
->children
!= NULL
) {
1408 xsltParseContentError(style
, cur
->children
);
1413 * xsltParseStylesheetDecimalFormat:
1414 * @style: the XSLT stylesheet
1415 * @cur: the "decimal-format" element
1417 * <!-- Category: top-level-element -->
1418 * <xsl:decimal-format
1419 * name = qname, decimal-separator = char, grouping-separator = char,
1420 * infinity = string, minus-sign = char, NaN = string, percent = char
1421 * per-mille = char, zero-digit = char, digit = char,
1422 * pattern-separator = char />
1424 * parse an XSLT stylesheet decimal-format element and
1425 * and record the formatting characteristics
1428 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style
, xmlNodePtr cur
)
1431 xsltDecimalFormatPtr format
;
1432 xsltDecimalFormatPtr iter
;
1434 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1437 format
= style
->decimalFormat
;
1439 prop
= xmlGetNsProp(cur
, BAD_CAST("name"), NULL
);
1441 const xmlChar
*nsUri
;
1443 if (xmlValidateQName(prop
, 0) != 0) {
1444 xsltTransformError(NULL
, style
, cur
,
1445 "xsl:decimal-format: Invalid QName '%s'.\n", prop
);
1451 * TODO: Don't use xsltGetQNameURI().
1453 nsUri
= xsltGetQNameURI(cur
, &prop
);
1458 format
= xsltDecimalFormatGetByQName(style
, nsUri
, prop
);
1459 if (format
!= NULL
) {
1460 xsltTransformError(NULL
, style
, cur
,
1461 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop
);
1466 format
= xsltNewDecimalFormat(nsUri
, prop
);
1467 if (format
== NULL
) {
1468 xsltTransformError(NULL
, style
, cur
,
1469 "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
1474 /* Append new decimal-format structure */
1475 for (iter
= style
->decimalFormat
; iter
->next
; iter
= iter
->next
)
1478 iter
->next
= format
;
1481 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"decimal-separator", NULL
);
1483 if (format
->decimalPoint
!= NULL
) xmlFree(format
->decimalPoint
);
1484 format
->decimalPoint
= prop
;
1487 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"grouping-separator", NULL
);
1489 if (format
->grouping
!= NULL
) xmlFree(format
->grouping
);
1490 format
->grouping
= prop
;
1493 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"infinity", NULL
);
1495 if (format
->infinity
!= NULL
) xmlFree(format
->infinity
);
1496 format
->infinity
= prop
;
1499 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"minus-sign", NULL
);
1501 if (format
->minusSign
!= NULL
) xmlFree(format
->minusSign
);
1502 format
->minusSign
= prop
;
1505 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"NaN", NULL
);
1507 if (format
->noNumber
!= NULL
) xmlFree(format
->noNumber
);
1508 format
->noNumber
= prop
;
1511 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"percent", NULL
);
1513 if (format
->percent
!= NULL
) xmlFree(format
->percent
);
1514 format
->percent
= prop
;
1517 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"per-mille", NULL
);
1519 if (format
->permille
!= NULL
) xmlFree(format
->permille
);
1520 format
->permille
= prop
;
1523 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"zero-digit", NULL
);
1525 if (format
->zeroDigit
!= NULL
) xmlFree(format
->zeroDigit
);
1526 format
->zeroDigit
= prop
;
1529 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"digit", NULL
);
1531 if (format
->digit
!= NULL
) xmlFree(format
->digit
);
1532 format
->digit
= prop
;
1535 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"pattern-separator", NULL
);
1537 if (format
->patternSeparator
!= NULL
) xmlFree(format
->patternSeparator
);
1538 format
->patternSeparator
= prop
;
1540 if (cur
->children
!= NULL
) {
1541 xsltParseContentError(style
, cur
->children
);
1546 * xsltParseStylesheetPreserveSpace:
1547 * @style: the XSLT stylesheet
1548 * @cur: the "preserve-space" element
1550 * parse an XSLT stylesheet preserve-space element and record
1551 * elements needing preserving
1555 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style
, xmlNodePtr cur
) {
1557 xmlChar
*element
, *end
;
1559 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1562 elements
= xmlGetNsProp(cur
, (const xmlChar
*)"elements", NULL
);
1563 if (elements
== NULL
) {
1564 xsltTransformError(NULL
, style
, cur
,
1565 "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
1566 if (style
!= NULL
) style
->warnings
++;
1570 if (style
->stripSpaces
== NULL
)
1571 style
->stripSpaces
= xmlHashCreate(10);
1572 if (style
->stripSpaces
== NULL
)
1576 while (*element
!= 0) {
1577 while (IS_BLANK(*element
)) element
++;
1581 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1582 element
= xmlStrndup(element
, end
- element
);
1584 #ifdef WITH_XSLT_DEBUG_PARSING
1585 xsltGenericDebug(xsltGenericDebugContext
,
1586 "add preserved space element %s\n", element
);
1588 if (xmlStrEqual(element
, (const xmlChar
*)"*")) {
1589 style
->stripAll
= -1;
1594 * TODO: Don't use xsltGetQNameURI().
1596 URI
= xsltGetQNameURI(cur
, &element
);
1598 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
1599 (xmlChar
*) "preserve");
1606 if (cur
->children
!= NULL
) {
1607 xsltParseContentError(style
, cur
->children
);
1611 #ifdef XSLT_REFACTORED
1614 * xsltParseStylesheetExtPrefix:
1615 * @style: the XSLT stylesheet
1616 * @template: the "extension-element-prefixes" prefix
1618 * parse an XSLT stylesheet's "extension-element-prefix" attribute value
1619 * and register the namespaces of extension instruction.
1620 * SPEC "A namespace is designated as an extension namespace by using
1621 * an extension-element-prefixes attribute on:
1622 * 1) an xsl:stylesheet element
1623 * 2) an xsl:extension-element-prefixes attribute on a
1624 * literal result element
1625 * 3) an extension instruction."
1628 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style
, xmlNodePtr cur
,
1631 xmlChar
*prefix
, *end
;
1633 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1637 /* For xsl:stylesheet/xsl:transform. */
1638 prefixes
= xmlGetNsProp(cur
,
1639 (const xmlChar
*)"extension-element-prefixes", NULL
);
1641 /* For literal result elements and extension instructions. */
1642 prefixes
= xmlGetNsProp(cur
,
1643 (const xmlChar
*)"extension-element-prefixes", XSLT_NAMESPACE
);
1645 if (prefixes
== NULL
) {
1650 while (*prefix
!= 0) {
1651 while (IS_BLANK(*prefix
)) prefix
++;
1655 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1656 prefix
= xmlStrndup(prefix
, end
- prefix
);
1660 if (xmlStrEqual(prefix
, (const xmlChar
*)"#default"))
1661 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1663 ns
= xmlSearchNs(style
->doc
, cur
, prefix
);
1665 xsltTransformError(NULL
, style
, cur
,
1666 "xsl:extension-element-prefix : undefined namespace %s\n",
1668 if (style
!= NULL
) style
->warnings
++;
1670 #ifdef WITH_XSLT_DEBUG_PARSING
1671 xsltGenericDebug(xsltGenericDebugContext
,
1672 "add extension prefix %s\n", prefix
);
1674 xsltRegisterExtPrefix(style
, prefix
, ns
->href
);
1682 #endif /* else of XSLT_REFACTORED */
1685 * xsltParseStylesheetStripSpace:
1686 * @style: the XSLT stylesheet
1687 * @cur: the "strip-space" element
1689 * parse an XSLT stylesheet's strip-space element and record
1690 * the elements needing stripping
1694 xsltParseStylesheetStripSpace(xsltStylesheetPtr style
, xmlNodePtr cur
) {
1696 xmlChar
*element
, *end
;
1698 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1701 elements
= xmlGetNsProp(cur
, (const xmlChar
*)"elements", NULL
);
1702 if (elements
== NULL
) {
1703 xsltTransformError(NULL
, style
, cur
,
1704 "xsltParseStylesheetStripSpace: missing elements attribute\n");
1705 if (style
!= NULL
) style
->warnings
++;
1709 if (style
->stripSpaces
== NULL
)
1710 style
->stripSpaces
= xmlHashCreate(10);
1711 if (style
->stripSpaces
== NULL
)
1715 while (*element
!= 0) {
1716 while (IS_BLANK(*element
)) element
++;
1720 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1721 element
= xmlStrndup(element
, end
- element
);
1723 #ifdef WITH_XSLT_DEBUG_PARSING
1724 xsltGenericDebug(xsltGenericDebugContext
,
1725 "add stripped space element %s\n", element
);
1727 if (xmlStrEqual(element
, (const xmlChar
*)"*")) {
1728 style
->stripAll
= 1;
1733 * TODO: Don't use xsltGetQNameURI().
1735 URI
= xsltGetQNameURI(cur
, &element
);
1737 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
1738 (xmlChar
*) "strip");
1745 if (cur
->children
!= NULL
) {
1746 xsltParseContentError(style
, cur
->children
);
1750 #ifdef XSLT_REFACTORED
1753 * xsltParseStylesheetExcludePrefix:
1754 * @style: the XSLT stylesheet
1755 * @cur: the current point in the stylesheet
1757 * parse an XSLT stylesheet exclude prefix and record
1758 * namespaces needing stripping
1760 * Returns the number of Excluded prefixes added at that level
1764 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style
, xmlNodePtr cur
,
1769 xmlChar
*prefix
, *end
;
1771 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1775 prefixes
= xmlGetNsProp(cur
,
1776 (const xmlChar
*)"exclude-result-prefixes", NULL
);
1778 prefixes
= xmlGetNsProp(cur
,
1779 (const xmlChar
*)"exclude-result-prefixes", XSLT_NAMESPACE
);
1781 if (prefixes
== NULL
) {
1786 while (*prefix
!= 0) {
1787 while (IS_BLANK(*prefix
)) prefix
++;
1791 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1792 prefix
= xmlStrndup(prefix
, end
- prefix
);
1796 if (xmlStrEqual(prefix
, (const xmlChar
*)"#default"))
1797 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1799 ns
= xmlSearchNs(style
->doc
, cur
, prefix
);
1801 xsltTransformError(NULL
, style
, cur
,
1802 "xsl:exclude-result-prefixes : undefined namespace %s\n",
1804 if (style
!= NULL
) style
->warnings
++;
1806 if (exclPrefixPush(style
, (xmlChar
*) ns
->href
) >= 0) {
1807 #ifdef WITH_XSLT_DEBUG_PARSING
1808 xsltGenericDebug(xsltGenericDebugContext
,
1809 "exclude result prefix %s\n", prefix
);
1821 #endif /* else of XSLT_REFACTORED */
1823 #ifdef XSLT_REFACTORED
1826 * xsltTreeEnsureXMLDecl:
1830 * This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
1831 * Ensures that there is an XML namespace declaration on the doc.
1833 * Returns the XML ns-struct or NULL on API and internal errors.
1836 xsltTreeEnsureXMLDecl(xmlDocPtr doc
)
1840 if (doc
->oldNs
!= NULL
)
1841 return (doc
->oldNs
);
1844 ns
= (xmlNsPtr
) xmlMalloc(sizeof(xmlNs
));
1846 xmlGenericError(xmlGenericErrorContext
,
1847 "xsltTreeEnsureXMLDecl: Failed to allocate "
1848 "the XML namespace.\n");
1851 memset(ns
, 0, sizeof(xmlNs
));
1852 ns
->type
= XML_LOCAL_NAMESPACE
;
1854 * URGENT TODO: revisit this.
1856 #ifdef LIBXML_NAMESPACE_DICT
1858 ns
->href
= xmlDictLookup(doc
->dict
, XML_XML_NAMESPACE
, -1);
1860 ns
->href
= xmlStrdup(XML_XML_NAMESPACE
);
1862 ns
->href
= xmlStrdup(XML_XML_NAMESPACE
);
1864 ns
->prefix
= xmlStrdup((const xmlChar
*)"xml");
1871 * xsltTreeAcquireStoredNs:
1873 * @nsName: the namespace name
1874 * @prefix: the prefix
1877 * This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
1878 * Creates or reuses an xmlNs struct on doc->oldNs with
1879 * the given prefix and namespace name.
1881 * Returns the aquired ns struct or NULL in case of an API
1882 * or internal error.
1885 xsltTreeAcquireStoredNs(xmlDocPtr doc
,
1886 const xmlChar
*nsName
,
1887 const xmlChar
*prefix
)
1893 if (doc
->oldNs
!= NULL
)
1896 ns
= xsltTreeEnsureXMLDecl(doc
);
1899 if (ns
->next
!= NULL
) {
1902 while (ns
!= NULL
) {
1903 if ((ns
->prefix
== NULL
) != (prefix
== NULL
)) {
1905 } else if (prefix
== NULL
) {
1906 if (xmlStrEqual(ns
->href
, nsName
))
1909 if ((ns
->prefix
[0] == prefix
[0]) &&
1910 xmlStrEqual(ns
->prefix
, prefix
) &&
1911 xmlStrEqual(ns
->href
, nsName
))
1915 if (ns
->next
== NULL
)
1921 ns
->next
= xmlNewNs(NULL
, nsName
, prefix
);
1926 * xsltLREBuildEffectiveNs:
1928 * Apply ns-aliasing on the namespace of the given @elem and
1932 xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt
,
1936 xsltNsAliasPtr alias
;
1938 if ((cctxt
== NULL
) || (elem
== NULL
))
1940 if ((cctxt
->nsAliases
== NULL
) || (! cctxt
->hasNsAliases
))
1943 alias
= cctxt
->nsAliases
;
1944 while (alias
!= NULL
) {
1945 if ( /* If both namespaces are NULL... */
1946 ( (elem
->ns
== NULL
) &&
1947 ((alias
->literalNs
== NULL
) ||
1948 (alias
->literalNs
->href
== NULL
)) ) ||
1949 /* ... or both namespace are equal */
1950 ( (elem
->ns
!= NULL
) &&
1951 (alias
->literalNs
!= NULL
) &&
1952 xmlStrEqual(elem
->ns
->href
, alias
->literalNs
->href
) ) )
1954 if ((alias
->targetNs
!= NULL
) &&
1955 (alias
->targetNs
->href
!= NULL
))
1958 * Convert namespace.
1960 if (elem
->doc
== alias
->docOfTargetNs
) {
1962 * This is the nice case: same docs.
1963 * This will eventually assign a ns-decl which
1964 * is shadowed, but this has no negative effect on
1965 * the generation of the result tree.
1967 elem
->ns
= alias
->targetNs
;
1970 * This target xmlNs originates from a different
1971 * stylesheet tree. Try to locate it in the
1972 * in-scope namespaces.
1973 * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
1975 ns
= xmlSearchNs(elem
->doc
, elem
,
1976 alias
->targetNs
->prefix
);
1978 * If no matching ns-decl found, then assign a
1979 * ns-decl stored in xmlDoc.
1982 (! xmlStrEqual(ns
->href
, alias
->targetNs
->href
)))
1985 * BIG NOTE: The use of xsltTreeAcquireStoredNs()
1986 * is not very efficient, but currently I don't
1987 * see an other way of *safely* changing a node's
1988 * namespace, since the xmlNs struct in
1989 * alias->targetNs might come from an other
1990 * stylesheet tree. So we need to anchor it in the
1991 * current document, without adding it to the tree,
1992 * which would otherwise change the in-scope-ns
1993 * semantic of the tree.
1995 ns
= xsltTreeAcquireStoredNs(elem
->doc
,
1996 alias
->targetNs
->href
,
1997 alias
->targetNs
->prefix
);
2000 xsltTransformError(NULL
, cctxt
->style
, elem
,
2001 "Internal error in "
2002 "xsltLREBuildEffectiveNs(): "
2003 "failed to acquire a stored "
2004 "ns-declaration.\n");
2005 cctxt
->style
->errors
++;
2014 * Move into or leave in the NULL namespace.
2020 alias
= alias
->next
;
2023 * Same with attributes of literal result elements.
2025 if (elem
->properties
!= NULL
) {
2026 xmlAttrPtr attr
= elem
->properties
;
2028 while (attr
!= NULL
) {
2029 if (attr
->ns
== NULL
) {
2033 alias
= cctxt
->nsAliases
;
2034 while (alias
!= NULL
) {
2035 if ( /* If both namespaces are NULL... */
2036 ( (elem
->ns
== NULL
) &&
2037 ((alias
->literalNs
== NULL
) ||
2038 (alias
->literalNs
->href
== NULL
)) ) ||
2039 /* ... or both namespace are equal */
2040 ( (elem
->ns
!= NULL
) &&
2041 (alias
->literalNs
!= NULL
) &&
2042 xmlStrEqual(elem
->ns
->href
, alias
->literalNs
->href
) ) )
2044 if ((alias
->targetNs
!= NULL
) &&
2045 (alias
->targetNs
->href
!= NULL
))
2047 if (elem
->doc
== alias
->docOfTargetNs
) {
2048 elem
->ns
= alias
->targetNs
;
2050 ns
= xmlSearchNs(elem
->doc
, elem
,
2051 alias
->targetNs
->prefix
);
2053 (! xmlStrEqual(ns
->href
, alias
->targetNs
->href
)))
2055 ns
= xsltTreeAcquireStoredNs(elem
->doc
,
2056 alias
->targetNs
->href
,
2057 alias
->targetNs
->prefix
);
2060 xsltTransformError(NULL
, cctxt
->style
, elem
,
2061 "Internal error in "
2062 "xsltLREBuildEffectiveNs(): "
2063 "failed to acquire a stored "
2064 "ns-declaration.\n");
2065 cctxt
->style
->errors
++;
2074 * Move into or leave in the NULL namespace.
2080 alias
= alias
->next
;
2090 * xsltLREBuildEffectiveNsNodes:
2092 * Computes the effective namespaces nodes for a literal result
2094 * @effectiveNs is the set of effective ns-nodes
2095 * on the literal result element, which will be added to the result
2096 * element if not already existing in the result tree.
2097 * This means that excluded namespaces (via exclude-result-prefixes,
2098 * extension-element-prefixes and the XSLT namespace) not added
2100 * Namespace-aliasing was applied on the @effectiveNs.
2103 xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt
,
2104 xsltStyleItemLRElementInfoPtr item
,
2109 xsltEffectiveNsPtr effNs
, lastEffNs
= NULL
;
2110 int i
, j
, holdByElem
;
2111 xsltPointerListPtr extElemNs
= cctxt
->inode
->extElemNs
;
2112 xsltPointerListPtr exclResultNs
= cctxt
->inode
->exclResultNs
;
2114 if ((cctxt
== NULL
) || (cctxt
->inode
== NULL
) || (elem
== NULL
) ||
2115 (item
== NULL
) || (item
->effectiveNs
!= NULL
))
2118 if (item
->inScopeNs
== NULL
)
2121 extElemNs
= cctxt
->inode
->extElemNs
;
2122 exclResultNs
= cctxt
->inode
->exclResultNs
;
2124 for (i
= 0; i
< item
->inScopeNs
->totalNumber
; i
++) {
2125 ns
= item
->inScopeNs
->list
[i
];
2127 * Skip namespaces designated as excluded namespaces
2128 * -------------------------------------------------
2130 * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
2131 * which are target namespaces of namespace-aliases
2132 * regardless if designated as excluded.
2134 * Exclude the XSLT namespace.
2136 if (xmlStrEqual(ns
->href
, XSLT_NAMESPACE
))
2140 * Apply namespace aliasing
2141 * ------------------------
2144 * "- A namespace node whose string value is a literal namespace
2145 * URI is not copied to the result tree.
2146 * - A namespace node whose string value is a target namespace URI
2147 * is copied to the result tree, whether or not the URI
2148 * identifies an excluded namespace."
2150 * NOTE: The ns-aliasing machanism is non-cascading.
2151 * (checked with Saxon, Xalan and MSXML .NET).
2152 * URGENT TODO: is style->nsAliases the effective list of
2153 * ns-aliases, or do we need to lookup the whole
2155 * TODO: Get rid of import-tree lookup.
2157 if (cctxt
->hasNsAliases
) {
2158 xsltNsAliasPtr alias
;
2160 * First check for being a target namespace.
2162 alias
= cctxt
->nsAliases
;
2165 * TODO: Is xmlns="" handled already?
2167 if ((alias
->targetNs
!= NULL
) &&
2168 (xmlStrEqual(alias
->targetNs
->href
, ns
->href
)))
2171 * Recognized as a target namespace; use it regardless
2172 * if excluded otherwise.
2174 goto add_effective_ns
;
2176 alias
= alias
->next
;
2177 } while (alias
!= NULL
);
2179 alias
= cctxt
->nsAliases
;
2182 * TODO: Is xmlns="" handled already?
2184 if ((alias
->literalNs
!= NULL
) &&
2185 (xmlStrEqual(alias
->literalNs
->href
, ns
->href
)))
2188 * Recognized as an namespace alias; do not use it.
2192 alias
= alias
->next
;
2193 } while (alias
!= NULL
);
2197 * Exclude excluded result namespaces.
2200 for (j
= 0; j
< exclResultNs
->number
; j
++)
2201 if (xmlStrEqual(ns
->href
, BAD_CAST exclResultNs
->items
[j
]))
2205 * Exclude extension-element namespaces.
2208 for (j
= 0; j
< extElemNs
->number
; j
++)
2209 if (xmlStrEqual(ns
->href
, BAD_CAST extElemNs
->items
[j
]))
2215 * OPTIMIZE TODO: This information may not be needed.
2217 if (isLRE
&& (elem
->nsDef
!= NULL
)) {
2219 tmpns
= elem
->nsDef
;
2225 tmpns
= tmpns
->next
;
2226 } while (tmpns
!= NULL
);
2232 * Add the effective namespace declaration.
2234 effNs
= (xsltEffectiveNsPtr
) xmlMalloc(sizeof(xsltEffectiveNs
));
2235 if (effNs
== NULL
) {
2236 xsltTransformError(NULL
, cctxt
->style
, elem
,
2237 "Internal error in xsltLREBuildEffectiveNs(): "
2238 "failed to allocate memory.\n");
2239 cctxt
->style
->errors
++;
2242 if (cctxt
->psData
->effectiveNs
== NULL
) {
2243 cctxt
->psData
->effectiveNs
= effNs
;
2244 effNs
->nextInStore
= NULL
;
2246 effNs
->nextInStore
= cctxt
->psData
->effectiveNs
;
2247 cctxt
->psData
->effectiveNs
= effNs
;
2251 effNs
->prefix
= ns
->prefix
;
2252 effNs
->nsName
= ns
->href
;
2253 effNs
->holdByElem
= holdByElem
;
2255 if (lastEffNs
== NULL
)
2256 item
->effectiveNs
= effNs
;
2258 lastEffNs
->next
= effNs
;
2269 * xsltLREInfoCreate:
2271 * @isLRE: indicates if the given @elem is a literal result element
2273 * Creates a new info for a literal result element.
2276 xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt
,
2280 xsltStyleItemLRElementInfoPtr item
;
2282 if ((cctxt
== NULL
) || (cctxt
->inode
== NULL
))
2285 item
= (xsltStyleItemLRElementInfoPtr
)
2286 xmlMalloc(sizeof(xsltStyleItemLRElementInfo
));
2288 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2289 "Internal error in xsltLREInfoCreate(): "
2290 "memory allocation failed.\n");
2291 cctxt
->style
->errors
++;
2294 memset(item
, 0, sizeof(xsltStyleItemLRElementInfo
));
2295 item
->type
= XSLT_FUNC_LITERAL_RESULT_ELEMENT
;
2297 * Store it in the stylesheet.
2299 item
->next
= cctxt
->style
->preComps
;
2300 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
2302 * @inScopeNs are used for execution of XPath expressions
2305 item
->inScopeNs
= cctxt
->inode
->inScopeNs
;
2308 xsltLREBuildEffectiveNsNodes(cctxt
, item
, elem
, isLRE
);
2310 cctxt
->inode
->litResElemInfo
= item
;
2311 cctxt
->inode
->nsChanged
= 0;
2317 * xsltCompilerVarInfoPush:
2318 * @cctxt: the compilation context
2320 * Pushes a new var/param info onto the stack.
2322 * Returns the acquired variable info.
2324 static xsltVarInfoPtr
2325 xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt
,
2327 const xmlChar
*name
,
2328 const xmlChar
*nsName
)
2330 xsltVarInfoPtr ivar
;
2332 if ((cctxt
->ivar
!= NULL
) && (cctxt
->ivar
->next
!= NULL
)) {
2333 ivar
= cctxt
->ivar
->next
;
2334 } else if ((cctxt
->ivar
== NULL
) && (cctxt
->ivars
!= NULL
)) {
2335 ivar
= cctxt
->ivars
;
2337 ivar
= (xsltVarInfoPtr
) xmlMalloc(sizeof(xsltVarInfo
));
2339 xsltTransformError(NULL
, cctxt
->style
, inst
,
2340 "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
2341 cctxt
->style
->errors
++;
2344 /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
2345 if (cctxt
->ivars
== NULL
) {
2346 cctxt
->ivars
= ivar
;
2349 cctxt
->ivar
->next
= ivar
;
2350 ivar
->prev
= cctxt
->ivar
;
2355 ivar
->depth
= cctxt
->depth
;
2357 ivar
->nsName
= nsName
;
2362 * xsltCompilerVarInfoPop:
2363 * @cctxt: the compilation context
2365 * Pops all var/param infos from the stack, which
2366 * have the current depth.
2369 xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt
)
2372 while ((cctxt
->ivar
!= NULL
) &&
2373 (cctxt
->ivar
->depth
> cctxt
->depth
))
2375 cctxt
->ivar
= cctxt
->ivar
->prev
;
2380 * xsltCompilerNodePush:
2382 * @cctxt: the compilation context
2383 * @node: the node to be pushed (this can also be the doc-node)
2387 * Returns the current node info structure or
2388 * NULL in case of an internal error.
2390 static xsltCompilerNodeInfoPtr
2391 xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2393 xsltCompilerNodeInfoPtr inode
, iprev
;
2395 if ((cctxt
->inode
!= NULL
) && (cctxt
->inode
->next
!= NULL
)) {
2396 inode
= cctxt
->inode
->next
;
2397 } else if ((cctxt
->inode
== NULL
) && (cctxt
->inodeList
!= NULL
)) {
2398 inode
= cctxt
->inodeList
;
2401 * Create a new node-info.
2403 inode
= (xsltCompilerNodeInfoPtr
)
2404 xmlMalloc(sizeof(xsltCompilerNodeInfo
));
2405 if (inode
== NULL
) {
2406 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2407 "xsltCompilerNodePush: malloc failed.\n");
2410 memset(inode
, 0, sizeof(xsltCompilerNodeInfo
));
2411 if (cctxt
->inodeList
== NULL
)
2412 cctxt
->inodeList
= inode
;
2414 cctxt
->inodeLast
->next
= inode
;
2415 inode
->prev
= cctxt
->inodeLast
;
2417 cctxt
->inodeLast
= inode
;
2418 cctxt
->maxNodeInfos
++;
2419 if (cctxt
->inode
== NULL
) {
2420 cctxt
->inode
= inode
;
2422 * Create an initial literal result element info for
2423 * the root of the stylesheet.
2425 xsltLREInfoCreate(cctxt
, NULL
, 0);
2429 cctxt
->inode
= inode
;
2431 * REVISIT TODO: Keep the reset always complete.
2432 * NOTE: Be carefull with the @node, since it might be
2436 inode
->depth
= cctxt
->depth
;
2437 inode
->templ
= NULL
;
2438 inode
->category
= XSLT_ELEMENT_CATEGORY_XSLT
;
2441 inode
->curChildType
= 0;
2442 inode
->extContentHandled
= 0;
2445 if (inode
->prev
!= NULL
) {
2446 iprev
= inode
->prev
;
2448 * Inherit the following information:
2449 * ---------------------------------
2451 * In-scope namespaces
2453 inode
->inScopeNs
= iprev
->inScopeNs
;
2455 * Info for literal result elements
2457 inode
->litResElemInfo
= iprev
->litResElemInfo
;
2458 inode
->nsChanged
= iprev
->nsChanged
;
2460 * Excluded result namespaces
2462 inode
->exclResultNs
= iprev
->exclResultNs
;
2464 * Extension instruction namespaces
2466 inode
->extElemNs
= iprev
->extElemNs
;
2468 * Whitespace preservation
2470 inode
->preserveWhitespace
= iprev
->preserveWhitespace
;
2472 * Forwards-compatible mode
2474 inode
->forwardsCompat
= iprev
->forwardsCompat
;
2476 inode
->inScopeNs
= NULL
;
2477 inode
->exclResultNs
= NULL
;
2478 inode
->extElemNs
= NULL
;
2479 inode
->preserveWhitespace
= 0;
2480 inode
->forwardsCompat
= 0;
2487 * xsltCompilerNodePop:
2489 * @cctxt: the compilation context
2490 * @node: the node to be pushed (this can also be the doc-node)
2492 * Pops the current node info.
2495 xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2497 if (cctxt
->inode
== NULL
) {
2498 xmlGenericError(xmlGenericErrorContext
,
2499 "xsltCompilerNodePop: Top-node mismatch.\n");
2503 * NOTE: Be carefull with the @node, since it might be
2506 if (cctxt
->inode
->node
!= node
) {
2507 xmlGenericError(xmlGenericErrorContext
,
2508 "xsltCompilerNodePop: Node mismatch.\n");
2511 if (cctxt
->inode
->depth
!= cctxt
->depth
) {
2512 xmlGenericError(xmlGenericErrorContext
,
2513 "xsltCompilerNodePop: Depth mismatch.\n");
2518 * Pop information of variables.
2520 if ((cctxt
->ivar
) && (cctxt
->ivar
->depth
> cctxt
->depth
))
2521 xsltCompilerVarInfoPop(cctxt
);
2523 cctxt
->inode
= cctxt
->inode
->prev
;
2524 if (cctxt
->inode
!= NULL
)
2525 cctxt
->inode
->curChildType
= 0;
2530 const xmlChar
*nsName
= NULL
, *name
= NULL
;
2531 const xmlChar
*infnsName
= NULL
, *infname
= NULL
;
2534 if (node
->type
== XML_ELEMENT_NODE
) {
2536 if (node
->ns
!= NULL
)
2537 nsName
= node
->ns
->href
;
2539 nsName
= BAD_CAST
"";
2541 name
= BAD_CAST
"#document";
2542 nsName
= BAD_CAST
"";
2545 name
= BAD_CAST
"Not given";
2547 if (cctxt
->inode
->node
) {
2548 if (node
->type
== XML_ELEMENT_NODE
) {
2549 infname
= cctxt
->inode
->node
->name
;
2550 if (cctxt
->inode
->node
->ns
!= NULL
)
2551 infnsName
= cctxt
->inode
->node
->ns
->href
;
2553 infnsName
= BAD_CAST
"";
2555 infname
= BAD_CAST
"#document";
2556 infnsName
= BAD_CAST
"";
2559 infname
= BAD_CAST
"Not given";
2562 xmlGenericError(xmlGenericErrorContext
,
2563 "xsltCompilerNodePop: Given : '%s' URI '%s'\n",
2565 xmlGenericError(xmlGenericErrorContext
,
2566 "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
2567 infname
, infnsName
);
2572 * xsltCompilerBuildInScopeNsList:
2574 * Create and store the list of in-scope namespaces for the given
2575 * node in the stylesheet. If there are no changes in the in-scope
2576 * namespaces then the last ns-info of the ancestor axis will be returned.
2577 * Compilation-time only.
2579 * Returns the ns-info or NULL if there are no namespaces in scope.
2581 static xsltNsListContainerPtr
2582 xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2584 xsltNsListContainerPtr nsi
= NULL
;
2585 xmlNsPtr
*list
= NULL
, ns
;
2588 * Create a new ns-list for this position in the node-tree.
2589 * xmlGetNsList() will return NULL, if there are no ns-decls in the
2590 * tree. Note that the ns-decl for the XML namespace is not added
2591 * to the resulting list; the XPath module handles the XML namespace
2594 while (node
!= NULL
) {
2595 if (node
->type
== XML_ELEMENT_NODE
) {
2597 while (ns
!= NULL
) {
2599 nsi
= (xsltNsListContainerPtr
)
2600 xmlMalloc(sizeof(xsltNsListContainer
));
2602 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2603 "xsltCompilerBuildInScopeNsList: "
2604 "malloc failed!\n");
2607 memset(nsi
, 0, sizeof(xsltNsListContainer
));
2609 (xmlNsPtr
*) xmlMalloc(maxns
* sizeof(xmlNsPtr
));
2610 if (nsi
->list
== NULL
) {
2611 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2612 "xsltCompilerBuildInScopeNsList: "
2613 "malloc failed!\n");
2616 nsi
->list
[0] = NULL
;
2619 * Skip shadowed namespace bindings.
2621 for (i
= 0; i
< nsi
->totalNumber
; i
++) {
2622 if ((ns
->prefix
== nsi
->list
[i
]->prefix
) ||
2623 (xmlStrEqual(ns
->prefix
, nsi
->list
[i
]->prefix
)))
2626 if (i
>= nsi
->totalNumber
) {
2627 if (nsi
->totalNumber
+1 >= maxns
) {
2630 (xmlNsPtr
*) xmlRealloc(nsi
->list
,
2631 maxns
* sizeof(xmlNsPtr
));
2632 if (nsi
->list
== NULL
) {
2633 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2634 "xsltCompilerBuildInScopeNsList: "
2635 "realloc failed!\n");
2639 nsi
->list
[nsi
->totalNumber
++] = ns
;
2640 nsi
->list
[nsi
->totalNumber
] = NULL
;
2646 node
= node
->parent
;
2651 * Move the default namespace to last position.
2653 nsi
->xpathNumber
= nsi
->totalNumber
;
2654 for (i
= 0; i
< nsi
->totalNumber
; i
++) {
2655 if (nsi
->list
[i
]->prefix
== NULL
) {
2657 nsi
->list
[i
] = nsi
->list
[nsi
->totalNumber
-1];
2658 nsi
->list
[nsi
->totalNumber
-1] = ns
;
2664 * Store the ns-list in the stylesheet.
2666 if (xsltPointerListAddSize(
2667 (xsltPointerListPtr
)cctxt
->psData
->inScopeNamespaces
,
2668 (void *) nsi
, 5) == -1)
2672 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2673 "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
2677 * Notify of change in status wrt namespaces.
2679 if (cctxt
->inode
!= NULL
)
2680 cctxt
->inode
->nsChanged
= 1;
2687 cctxt
->style
->errors
++;
2692 xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt
,
2693 xsltPointerListPtr list
,
2695 const xmlChar
*value
)
2700 if ((cctxt
== NULL
) || (value
== NULL
) || (list
== NULL
))
2705 cur
= (xmlChar
*) value
;
2707 while (IS_BLANK(*cur
)) cur
++;
2711 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
2712 cur
= xmlStrndup(cur
, end
- cur
);
2718 * TODO: Export and use xmlSearchNsByPrefixStrict()
2719 * in Libxml2, tree.c, since xmlSearchNs() is in most
2720 * cases not efficient and in some cases not correct.
2722 * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
2724 if ((cur
[0] == '#') &&
2725 xmlStrEqual(cur
, (const xmlChar
*)"#default"))
2726 ns
= xmlSearchNs(cctxt
->style
->doc
, node
, NULL
);
2728 ns
= xmlSearchNs(cctxt
->style
->doc
, node
, cur
);
2732 * TODO: Better to report the attr-node, otherwise
2733 * the user won't know which attribute was invalid.
2735 xsltTransformError(NULL
, cctxt
->style
, node
,
2736 "No namespace binding in scope for prefix '%s'.\n", cur
);
2738 * XSLT-1.0: "It is an error if there is no namespace
2739 * bound to the prefix on the element bearing the
2740 * exclude-result-prefixes or xsl:exclude-result-prefixes
2743 cctxt
->style
->errors
++;
2745 #ifdef WITH_XSLT_DEBUG_PARSING
2746 xsltGenericDebug(xsltGenericDebugContext
,
2747 "resolved prefix '%s'\n", cur
);
2750 * Note that we put the namespace name into the dict.
2752 if (xsltPointerListAddSize(list
,
2753 (void *) xmlDictLookup(cctxt
->style
->dict
,
2754 ns
->href
, -1), 5) == -1)
2767 cctxt
->style
->errors
++;
2772 * xsltCompilerUtilsCreateMergedList:
2773 * @dest: the destination list (optional)
2774 * @first: the first list
2775 * @second: the second list (optional)
2777 * Appends the content of @second to @first into @destination.
2778 * If @destination is NULL a new list will be created.
2780 * Returns the merged list of items or NULL if there's nothing to merge.
2782 static xsltPointerListPtr
2783 xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first
,
2784 xsltPointerListPtr second
)
2786 xsltPointerListPtr ret
;
2790 num
= first
->number
;
2794 num
+= second
->number
;
2797 ret
= xsltPointerListCreate(num
);
2803 if ((first
!= NULL
) && (first
->number
!= 0)) {
2804 memcpy(ret
->items
, first
->items
,
2805 first
->number
* sizeof(void *));
2806 if ((second
!= NULL
) && (second
->number
!= 0))
2807 memcpy(ret
->items
+ first
->number
, second
->items
,
2808 second
->number
* sizeof(void *));
2809 } else if ((second
!= NULL
) && (second
->number
!= 0))
2810 memcpy(ret
->items
, (void *) second
->items
,
2811 second
->number
* sizeof(void *));
2817 * xsltParseExclResultPrefixes:
2819 * Create and store the list of in-scope namespaces for the given
2820 * node in the stylesheet. If there are no changes in the in-scope
2821 * namespaces then the last ns-info of the ancestor axis will be returned.
2822 * Compilation-time only.
2824 * Returns the ns-info or NULL if there are no namespaces in scope.
2826 static xsltPointerListPtr
2827 xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2828 xsltPointerListPtr def
,
2831 xsltPointerListPtr list
= NULL
;
2835 if ((cctxt
== NULL
) || (node
== NULL
))
2838 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2839 attr
= xmlHasNsProp(node
, BAD_CAST
"exclude-result-prefixes", NULL
);
2841 attr
= xmlHasNsProp(node
, BAD_CAST
"exclude-result-prefixes",
2846 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
2848 * Mark the XSLT attr.
2850 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2853 if ((attr
->children
!= NULL
) &&
2854 (attr
->children
->content
!= NULL
))
2855 value
= attr
->children
->content
;
2857 xsltTransformError(NULL
, cctxt
->style
, node
,
2858 "Attribute 'exclude-result-prefixes': Invalid value.\n");
2859 cctxt
->style
->errors
++;
2863 if (xsltParseNsPrefixList(cctxt
, cctxt
->tmpList
, node
,
2864 BAD_CAST value
) != 0)
2866 if (cctxt
->tmpList
->number
== 0)
2869 * Merge the list with the inherited list.
2871 list
= xsltCompilerUtilsCreateMergedList(def
, cctxt
->tmpList
);
2875 * Store the list in the stylesheet/compiler context.
2877 if (xsltPointerListAddSize(
2878 cctxt
->psData
->exclResultNamespaces
, list
, 5) == -1)
2880 xsltPointerListFree(list
);
2885 * Notify of change in status wrt namespaces.
2887 if (cctxt
->inode
!= NULL
)
2888 cctxt
->inode
->nsChanged
= 1;
2898 * xsltParseExtElemPrefixes:
2900 * Create and store the list of in-scope namespaces for the given
2901 * node in the stylesheet. If there are no changes in the in-scope
2902 * namespaces then the last ns-info of the ancestor axis will be returned.
2903 * Compilation-time only.
2905 * Returns the ns-info or NULL if there are no namespaces in scope.
2907 static xsltPointerListPtr
2908 xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2909 xsltPointerListPtr def
,
2912 xsltPointerListPtr list
= NULL
;
2917 if ((cctxt
== NULL
) || (node
== NULL
))
2920 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2921 attr
= xmlHasNsProp(node
, BAD_CAST
"extension-element-prefixes", NULL
);
2923 attr
= xmlHasNsProp(node
, BAD_CAST
"extension-element-prefixes",
2928 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
2930 * Mark the XSLT attr.
2932 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2935 if ((attr
->children
!= NULL
) &&
2936 (attr
->children
->content
!= NULL
))
2937 value
= attr
->children
->content
;
2939 xsltTransformError(NULL
, cctxt
->style
, node
,
2940 "Attribute 'extension-element-prefixes': Invalid value.\n");
2941 cctxt
->style
->errors
++;
2946 if (xsltParseNsPrefixList(cctxt
, cctxt
->tmpList
, node
,
2947 BAD_CAST value
) != 0)
2950 if (cctxt
->tmpList
->number
== 0)
2953 * REVISIT: Register the extension namespaces.
2955 for (i
= 0; i
< cctxt
->tmpList
->number
; i
++)
2956 xsltRegisterExtPrefix(cctxt
->style
, NULL
,
2957 BAD_CAST cctxt
->tmpList
->items
[i
]);
2959 * Merge the list with the inherited list.
2961 list
= xsltCompilerUtilsCreateMergedList(def
, cctxt
->tmpList
);
2965 * Store the list in the stylesheet.
2967 if (xsltPointerListAddSize(
2968 cctxt
->psData
->extElemNamespaces
, list
, 5) == -1)
2970 xsltPointerListFree(list
);
2975 * Notify of change in status wrt namespaces.
2977 if (cctxt
->inode
!= NULL
)
2978 cctxt
->inode
->nsChanged
= 1;
2988 * xsltParseAttrXSLTVersion:
2990 * @cctxt: the compilation context
2991 * @node: the element-node
2992 * @isXsltElem: whether this is an XSLT element
2994 * Parses the attribute xsl:version.
2996 * Returns 1 if there was such an attribute, 0 if not and
2997 * -1 if an internal or API error occured.
3000 xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
3006 if ((cctxt
== NULL
) || (node
== NULL
))
3009 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
3010 attr
= xmlHasNsProp(node
, BAD_CAST
"version", NULL
);
3012 attr
= xmlHasNsProp(node
, BAD_CAST
"version", XSLT_NAMESPACE
);
3017 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
3019 if ((attr
->children
!= NULL
) &&
3020 (attr
->children
->content
!= NULL
))
3021 value
= attr
->children
->content
;
3023 xsltTransformError(NULL
, cctxt
->style
, node
,
3024 "Attribute 'version': Invalid value.\n");
3025 cctxt
->style
->errors
++;
3029 if (! xmlStrEqual(value
, (const xmlChar
*)"1.0")) {
3030 cctxt
->inode
->forwardsCompat
= 1;
3032 * TODO: To what extent do we support the
3033 * forwards-compatible mode?
3036 * Report this only once per compilation episode.
3038 if (! cctxt
->hasForwardsCompat
) {
3039 cctxt
->hasForwardsCompat
= 1;
3040 cctxt
->errSeverity
= XSLT_ERROR_SEVERITY_WARNING
;
3041 xsltTransformError(NULL
, cctxt
->style
, node
,
3042 "Warning: the attribute xsl:version specifies a value "
3043 "different from '1.0'. Switching to forwards-compatible "
3044 "mode. Only features of XSLT 1.0 are supported by this "
3046 cctxt
->style
->warnings
++;
3047 cctxt
->errSeverity
= XSLT_ERROR_SEVERITY_ERROR
;
3050 cctxt
->inode
->forwardsCompat
= 0;
3053 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
3055 * Set a marker on XSLT attributes.
3057 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
3063 xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
3065 xmlNodePtr deleteNode
, cur
, txt
, textNode
= NULL
;
3067 xsltStylesheetPtr style
;
3068 int internalize
= 0, findSpaceAttr
;
3069 int xsltStylesheetElemDepth
;
3072 const xmlChar
*name
, *nsNameXSLT
= NULL
;
3073 int strictWhitespace
, inXSLText
= 0;
3074 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3075 xsltNsMapPtr nsMapItem
;
3078 if ((cctxt
== NULL
) || (cctxt
->style
== NULL
) ||
3079 (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
3086 style
= cctxt
->style
;
3087 if ((style
->dict
!= NULL
) && (doc
->dict
== style
->dict
))
3090 style
->internalized
= 0;
3093 * Init value of xml:space. Since this might be an embedded
3094 * stylesheet, this is needed to be performed on the element
3095 * where the stylesheet is rooted at, taking xml:space of
3096 * ancestors into account.
3098 if (! cctxt
->simplified
)
3099 xsltStylesheetElemDepth
= cctxt
->depth
+1;
3101 xsltStylesheetElemDepth
= 0;
3103 if (xmlNodeGetSpacePreserve(node
) != 1)
3104 cctxt
->inode
->preserveWhitespace
= 0;
3106 cctxt
->inode
->preserveWhitespace
= 1;
3109 * Eval if we should keep the old incorrect behaviour.
3111 strictWhitespace
= (cctxt
->strict
!= 0) ? 1 : 0;
3113 nsNameXSLT
= xsltConstNamespaceNameXSLT
;
3117 while (cur
!= NULL
) {
3118 if (deleteNode
!= NULL
) {
3120 #ifdef WITH_XSLT_DEBUG_BLANKS
3121 xsltGenericDebug(xsltGenericDebugContext
,
3122 "xsltParsePreprocessStylesheetTree: removing node\n");
3124 xmlUnlinkNode(deleteNode
);
3125 xmlFreeNode(deleteNode
);
3128 if (cur
->type
== XML_ELEMENT_NODE
) {
3131 * Clear the PSVI field.
3135 xsltCompilerNodePush(cctxt
, cur
);
3140 cctxt
->inode
->stripWhitespace
= 0;
3142 * TODO: I'd love to use a string pointer comparison here :-/
3144 if (IS_XSLT_ELEM(cur
)) {
3145 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3146 if (cur
->ns
->href
!= nsNameXSLT
) {
3147 nsMapItem
= xsltNewNamespaceMapItem(cctxt
,
3149 if (nsMapItem
== NULL
)
3151 cur
->ns
->href
= nsNameXSLT
;
3155 if (cur
->name
== NULL
)
3156 goto process_attributes
;
3158 * Mark the XSLT element for later recognition.
3159 * TODO: Using the marker is still too dangerous, since if
3160 * the parsing mechanism leaves out an XSLT element, then
3161 * this might hit the transformation-mechanism, which
3162 * will break if it doesn't expect such a marker.
3164 /* cur->psvi = (void *) xsltXSLTElemMarker; */
3167 * XSLT 2.0: "Any whitespace text node whose parent is
3168 * one of the following elements is removed from the "
3169 * tree, regardless of any xml:space attributes:..."
3170 * xsl:apply-imports,
3171 * xsl:apply-templates,
3172 * xsl:attribute-set,
3173 * xsl:call-template,
3175 * xsl:stylesheet, xsl:transform.
3176 * XSLT 2.0: xsl:analyze-string,
3177 * xsl:character-map,
3180 * TODO: I'd love to use a string pointer comparison here :-/
3185 if ((name
[0] == 't') && (name
[1] == 'e') &&
3186 (name
[2] == 'x') && (name
[3] == 't') &&
3190 * Process the xsl:text element.
3191 * ----------------------------
3192 * Mark it for later recognition.
3194 cur
->psvi
= (void *) xsltXSLTTextMarker
;
3196 * For stylesheets, the set of
3197 * whitespace-preserving element names
3198 * consists of just xsl:text.
3201 cctxt
->inode
->preserveWhitespace
= 1;
3206 if (xmlStrEqual(name
, BAD_CAST
"choose") ||
3207 xmlStrEqual(name
, BAD_CAST
"call-template"))
3208 cctxt
->inode
->stripWhitespace
= 1;
3211 if (xmlStrEqual(name
, BAD_CAST
"apply-templates") ||
3212 xmlStrEqual(name
, BAD_CAST
"apply-imports") ||
3213 xmlStrEqual(name
, BAD_CAST
"attribute-set"))
3215 cctxt
->inode
->stripWhitespace
= 1;
3218 if (xsltStylesheetElemDepth
== cctxt
->depth
) {
3220 * This is a xsl:stylesheet/xsl:transform.
3222 cctxt
->inode
->stripWhitespace
= 1;
3226 if ((cur
->prev
!= NULL
) &&
3227 (cur
->prev
->type
== XML_TEXT_NODE
))
3230 * XSLT 2.0 : "Any whitespace text node whose
3231 * following-sibling node is an xsl:param or
3232 * xsl:sort element is removed from the tree,
3233 * regardless of any xml:space attributes."
3235 if (((*name
== 'p') || (*name
== 's')) &&
3236 (xmlStrEqual(name
, BAD_CAST
"param") ||
3237 xmlStrEqual(name
, BAD_CAST
"sort")))
3240 if (IS_BLANK_NODE(cur
->prev
)) {
3246 * This will result in a content
3247 * error, when hitting the parsing
3252 } while (cur
->prev
);
3261 * Process attributes.
3262 * ------------------
3264 if (cur
->properties
!= NULL
) {
3265 if (cur
->children
== NULL
)
3267 attr
= cur
->properties
;
3269 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3270 if ((attr
->ns
) && (attr
->ns
->href
!= nsNameXSLT
) &&
3271 xmlStrEqual(attr
->ns
->href
, nsNameXSLT
))
3273 nsMapItem
= xsltNewNamespaceMapItem(cctxt
,
3274 doc
, attr
->ns
, cur
);
3275 if (nsMapItem
== NULL
)
3277 attr
->ns
->href
= nsNameXSLT
;
3282 * Internalize the attribute's value; the goal is to
3283 * speed up operations and minimize used space by
3284 * compiled stylesheets.
3286 txt
= attr
->children
;
3288 * NOTE that this assumes only one
3289 * text-node in the attribute's content.
3291 if ((txt
!= NULL
) && (txt
->content
!= NULL
) &&
3292 (!xmlDictOwns(style
->dict
, txt
->content
)))
3294 value
= (xmlChar
*) xmlDictLookup(style
->dict
,
3296 xmlNodeSetContent(txt
, NULL
);
3297 txt
->content
= value
;
3301 * Process xml:space attributes.
3302 * ----------------------------
3304 if ((findSpaceAttr
!= 0) &&
3305 (attr
->ns
!= NULL
) &&
3306 (attr
->name
!= NULL
) &&
3307 (attr
->name
[0] == 's') &&
3308 (attr
->ns
->prefix
!= NULL
) &&
3309 (attr
->ns
->prefix
[0] == 'x') &&
3310 (attr
->ns
->prefix
[1] == 'm') &&
3311 (attr
->ns
->prefix
[2] == 'l') &&
3312 (attr
->ns
->prefix
[3] == 0))
3314 value
= xmlGetNsProp(cur
, BAD_CAST
"space",
3316 if (value
!= NULL
) {
3317 if (xmlStrEqual(value
, BAD_CAST
"preserve")) {
3318 cctxt
->inode
->preserveWhitespace
= 1;
3319 } else if (xmlStrEqual(value
, BAD_CAST
"default")) {
3320 cctxt
->inode
->preserveWhitespace
= 0;
3322 /* Invalid value for xml:space. */
3323 xsltTransformError(NULL
, style
, cur
,
3324 "Attribute xml:space: Invalid value.\n");
3325 cctxt
->style
->warnings
++;
3333 } while (attr
!= NULL
);
3336 * We'll descend into the children of element nodes only.
3338 if (cur
->children
!= NULL
) {
3339 cur
= cur
->children
;
3342 } else if ((cur
->type
== XML_TEXT_NODE
) ||
3343 (cur
->type
== XML_CDATA_SECTION_NODE
))
3346 * Merge adjacent text/CDATA-section-nodes
3347 * ---------------------------------------
3348 * In order to avoid breaking of existing stylesheets,
3349 * if the old behaviour is wanted (strictWhitespace == 0),
3350 * then we *won't* merge adjacent text-nodes
3351 * (except in xsl:text); this will ensure that whitespace-only
3352 * text nodes are (incorrectly) not stripped in some cases.
3354 * Example: : <foo> <!-- bar -->zoo</foo>
3355 * Corrent (strict) result: <foo> zoo</foo>
3356 * Incorrect (old) result : <foo>zoo</foo>
3358 * NOTE that we *will* merge adjacent text-nodes if
3359 * they are in xsl:text.
3360 * Example, the following:
3361 * <xsl:text> <!-- bar -->zoo<xsl:text>
3362 * will result in both cases in:
3363 * <xsl:text> zoo<xsl:text>
3365 cur
->type
= XML_TEXT_NODE
;
3366 if ((strictWhitespace
!= 0) || (inXSLText
!= 0)) {
3368 * New behaviour; merge nodes.
3370 if (textNode
== NULL
)
3373 if (cur
->content
!= NULL
)
3374 xmlNodeAddContent(textNode
, cur
->content
);
3377 if ((cur
->next
== NULL
) ||
3378 (cur
->next
->type
== XML_ELEMENT_NODE
))
3386 if (textNode
== NULL
)
3390 } else if ((cur
->type
== XML_COMMENT_NODE
) ||
3391 (cur
->type
== XML_PI_NODE
))
3394 * Remove processing instructions and comments.
3397 if ((cur
->next
== NULL
) ||
3398 (cur
->next
->type
== XML_ELEMENT_NODE
))
3405 * Invalid node-type for this data-model.
3407 xsltTransformError(NULL
, style
, cur
,
3408 "Invalid type of node for the XSLT data model.\n");
3409 cctxt
->style
->errors
++;
3415 value
= textNode
->content
;
3417 * At this point all adjacent text/CDATA-section nodes
3420 * Strip whitespace-only text-nodes.
3421 * (cctxt->inode->stripWhitespace)
3423 if ((value
== NULL
) || (*value
== 0) ||
3424 (((cctxt
->inode
->stripWhitespace
) ||
3425 (! cctxt
->inode
->preserveWhitespace
)) &&
3427 xsltIsBlank(value
)))
3429 if (textNode
!= cur
) {
3430 xmlUnlinkNode(textNode
);
3431 xmlFreeNode(textNode
);
3433 deleteNode
= textNode
;
3438 * Convert CDATA-section nodes to text-nodes.
3439 * TODO: Can this produce problems?
3441 if (textNode
->type
!= XML_TEXT_NODE
) {
3442 textNode
->type
= XML_TEXT_NODE
;
3443 textNode
->name
= xmlStringText
;
3446 (textNode
->content
!= NULL
) &&
3447 (!xmlDictOwns(style
->dict
, textNode
->content
)))
3450 * Internalize the string.
3452 value
= (xmlChar
*) xmlDictLookup(style
->dict
,
3453 textNode
->content
, -1);
3454 xmlNodeSetContent(textNode
, NULL
);
3455 textNode
->content
= value
;
3459 * Note that "disable-output-escaping" of the xsl:text
3460 * element will be applied at a later level, when
3461 * XSLT elements are processed.
3466 if (cur
->type
== XML_ELEMENT_NODE
) {
3467 xsltCompilerNodePop(cctxt
, cur
);
3471 if (cur
->next
!= NULL
) {
3479 if (deleteNode
!= NULL
) {
3480 #ifdef WITH_XSLT_DEBUG_PARSING
3481 xsltGenericDebug(xsltGenericDebugContext
,
3482 "xsltParsePreprocessStylesheetTree: removing node\n");
3484 xmlUnlinkNode(deleteNode
);
3485 xmlFreeNode(deleteNode
);
3493 #endif /* XSLT_REFACTORED */
3495 #ifdef XSLT_REFACTORED
3498 xsltPreprocessStylesheet(xsltStylesheetPtr style
, xmlNodePtr cur
)
3500 xmlNodePtr deleteNode
, styleelem
;
3501 int internalize
= 0;
3503 if ((style
== NULL
) || (cur
== NULL
))
3506 if ((cur
->doc
!= NULL
) && (style
->dict
!= NULL
) &&
3507 (cur
->doc
->dict
== style
->dict
))
3510 style
->internalized
= 0;
3512 if ((cur
!= NULL
) && (IS_XSLT_ELEM(cur
)) &&
3513 (IS_XSLT_NAME(cur
, "stylesheet"))) {
3520 * This content comes from the stylesheet
3521 * For stylesheets, the set of whitespace-preserving
3522 * element names consists of just xsl:text.
3525 while (cur
!= NULL
) {
3526 if (deleteNode
!= NULL
) {
3527 #ifdef WITH_XSLT_DEBUG_BLANKS
3528 xsltGenericDebug(xsltGenericDebugContext
,
3529 "xsltPreprocessStylesheet: removing ignorable blank node\n");
3531 xmlUnlinkNode(deleteNode
);
3532 xmlFreeNode(deleteNode
);
3535 if (cur
->type
== XML_ELEMENT_NODE
) {
3538 * Internalize attributes values.
3540 if ((internalize
) && (cur
->properties
!= NULL
)) {
3541 xmlAttrPtr attr
= cur
->properties
;
3544 while (attr
!= NULL
) {
3545 txt
= attr
->children
;
3546 if ((txt
!= NULL
) && (txt
->type
== XML_TEXT_NODE
) &&
3547 (txt
->content
!= NULL
) &&
3548 (!xmlDictOwns(style
->dict
, txt
->content
)))
3553 * internalize the text string, goal is to speed
3554 * up operations and minimize used space by compiled
3557 tmp
= (xmlChar
*) xmlDictLookup(style
->dict
,
3559 if (tmp
!= txt
->content
) {
3560 xmlNodeSetContent(txt
, NULL
);
3567 if (IS_XSLT_ELEM(cur
)) {
3569 if (IS_XSLT_NAME(cur
, "text")) {
3570 for (;exclPrefixes
> 0;exclPrefixes
--)
3571 exclPrefixPop(style
);
3575 exclPrefixes
= xsltParseStylesheetExcludePrefix(style
, cur
, 0);
3578 if ((cur
->nsDef
!= NULL
) && (style
->exclPrefixNr
> 0)) {
3579 xmlNsPtr ns
= cur
->nsDef
, prev
= NULL
, next
;
3580 xmlNodePtr root
= NULL
;
3583 root
= xmlDocGetRootElement(cur
->doc
);
3584 if ((root
!= NULL
) && (root
!= cur
)) {
3585 while (ns
!= NULL
) {
3588 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
3589 if ((ns
->prefix
!= NULL
) &&
3590 (xmlStrEqual(ns
->href
,
3591 style
->exclPrefixTab
[i
]))) {
3593 * Move the namespace definition on the root
3594 * element to avoid duplicating it without
3598 cur
->nsDef
= ns
->next
;
3600 prev
->next
= ns
->next
;
3602 ns
->next
= root
->nsDef
;
3615 * If we have prefixes locally, recurse and pop them up when
3618 if (exclPrefixes
> 0) {
3619 xsltPreprocessStylesheet(style
, cur
->children
);
3620 for (;exclPrefixes
> 0;exclPrefixes
--)
3621 exclPrefixPop(style
);
3624 } else if (cur
->type
== XML_TEXT_NODE
) {
3625 if (IS_BLANK_NODE(cur
)) {
3626 if (xmlNodeGetSpacePreserve(cur
->parent
) != 1) {
3629 } else if ((cur
->content
!= NULL
) && (internalize
) &&
3630 (!xmlDictOwns(style
->dict
, cur
->content
))) {
3634 * internalize the text string, goal is to speed
3635 * up operations and minimize used space by compiled
3638 tmp
= (xmlChar
*) xmlDictLookup(style
->dict
, cur
->content
, -1);
3639 xmlNodeSetContent(cur
, NULL
);
3642 } else if ((cur
->type
!= XML_ELEMENT_NODE
) &&
3643 (cur
->type
!= XML_CDATA_SECTION_NODE
)) {
3649 * Skip to next node. In case of a namespaced element children of
3650 * the stylesheet and not in the XSLT namespace and not an extension
3651 * element, ignore its content.
3653 if ((cur
->type
== XML_ELEMENT_NODE
) && (cur
->ns
!= NULL
) &&
3654 (styleelem
!= NULL
) && (cur
->parent
== styleelem
) &&
3655 (!xmlStrEqual(cur
->ns
->href
, XSLT_NAMESPACE
)) &&
3656 (!xsltCheckExtURI(style
, cur
->ns
->href
))) {
3658 } else if (cur
->children
!= NULL
) {
3659 cur
= cur
->children
;
3664 if (cur
->next
!= NULL
) {
3673 if (cur
== (xmlNodePtr
) style
->doc
) {
3677 if (cur
->next
!= NULL
) {
3681 } while (cur
!= NULL
);
3683 if (deleteNode
!= NULL
) {
3684 #ifdef WITH_XSLT_DEBUG_PARSING
3685 xsltGenericDebug(xsltGenericDebugContext
,
3686 "xsltPreprocessStylesheet: removing ignorable blank node\n");
3688 xmlUnlinkNode(deleteNode
);
3689 xmlFreeNode(deleteNode
);
3692 #endif /* end of else XSLT_REFACTORED */
3695 * xsltGatherNamespaces:
3696 * @style: the XSLT stylesheet
3698 * Browse the stylesheet and build the namspace hash table which
3699 * will be used for XPath interpretation. If needed do a bit of normalization
3703 xsltGatherNamespaces(xsltStylesheetPtr style
) {
3710 * TODO: basically if the stylesheet uses the same prefix for different
3711 * patterns, well they may be in problem, hopefully they will get
3715 * TODO: Eliminate the use of the hash for XPath expressions.
3716 * An expression should be evaluated in the context of the in-scope
3717 * namespaces; eliminate the restriction of an XML document to contain
3718 * no duplicate prefixes for different namespace names.
3721 cur
= xmlDocGetRootElement(style
->doc
);
3722 while (cur
!= NULL
) {
3723 if (cur
->type
== XML_ELEMENT_NODE
) {
3724 xmlNsPtr ns
= cur
->nsDef
;
3725 while (ns
!= NULL
) {
3726 if (ns
->prefix
!= NULL
) {
3727 if (style
->nsHash
== NULL
) {
3728 style
->nsHash
= xmlHashCreate(10);
3729 if (style
->nsHash
== NULL
) {
3730 xsltTransformError(NULL
, style
, cur
,
3731 "xsltGatherNamespaces: failed to create hash table\n");
3736 URI
= xmlHashLookup(style
->nsHash
, ns
->prefix
);
3737 if ((URI
!= NULL
) && (!xmlStrEqual(URI
, ns
->href
))) {
3738 xsltTransformError(NULL
, style
, cur
,
3739 "Namespaces prefix %s used for multiple namespaces\n",ns
->prefix
);
3741 } else if (URI
== NULL
) {
3742 xmlHashUpdateEntry(style
->nsHash
, ns
->prefix
,
3743 (void *) ns
->href
, NULL
);
3745 #ifdef WITH_XSLT_DEBUG_PARSING
3746 xsltGenericDebug(xsltGenericDebugContext
,
3747 "Added namespace: %s mapped to %s\n", ns
->prefix
, ns
->href
);
3758 if (cur
->children
!= NULL
) {
3759 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
3760 cur
= cur
->children
;
3764 if (cur
->next
!= NULL
) {
3773 if (cur
== (xmlNodePtr
) style
->doc
) {
3777 if (cur
->next
!= NULL
) {
3781 } while (cur
!= NULL
);
3785 #ifdef XSLT_REFACTORED
3787 static xsltStyleType
3788 xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt
,
3791 if ((node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
) ||
3792 (node
->name
== NULL
))
3795 if (node
->name
[0] == 'a') {
3796 if (IS_XSLT_NAME(node
, "apply-templates"))
3797 return(XSLT_FUNC_APPLYTEMPLATES
);
3798 else if (IS_XSLT_NAME(node
, "attribute"))
3799 return(XSLT_FUNC_ATTRIBUTE
);
3800 else if (IS_XSLT_NAME(node
, "apply-imports"))
3801 return(XSLT_FUNC_APPLYIMPORTS
);
3802 else if (IS_XSLT_NAME(node
, "attribute-set"))
3805 } else if (node
->name
[0] == 'c') {
3806 if (IS_XSLT_NAME(node
, "choose"))
3807 return(XSLT_FUNC_CHOOSE
);
3808 else if (IS_XSLT_NAME(node
, "copy"))
3809 return(XSLT_FUNC_COPY
);
3810 else if (IS_XSLT_NAME(node
, "copy-of"))
3811 return(XSLT_FUNC_COPYOF
);
3812 else if (IS_XSLT_NAME(node
, "call-template"))
3813 return(XSLT_FUNC_CALLTEMPLATE
);
3814 else if (IS_XSLT_NAME(node
, "comment"))
3815 return(XSLT_FUNC_COMMENT
);
3817 } else if (node
->name
[0] == 'd') {
3818 if (IS_XSLT_NAME(node
, "document"))
3819 return(XSLT_FUNC_DOCUMENT
);
3820 else if (IS_XSLT_NAME(node
, "decimal-format"))
3823 } else if (node
->name
[0] == 'e') {
3824 if (IS_XSLT_NAME(node
, "element"))
3825 return(XSLT_FUNC_ELEMENT
);
3827 } else if (node
->name
[0] == 'f') {
3828 if (IS_XSLT_NAME(node
, "for-each"))
3829 return(XSLT_FUNC_FOREACH
);
3830 else if (IS_XSLT_NAME(node
, "fallback"))
3831 return(XSLT_FUNC_FALLBACK
);
3833 } else if (*(node
->name
) == 'i') {
3834 if (IS_XSLT_NAME(node
, "if"))
3835 return(XSLT_FUNC_IF
);
3836 else if (IS_XSLT_NAME(node
, "include"))
3838 else if (IS_XSLT_NAME(node
, "import"))
3841 } else if (*(node
->name
) == 'k') {
3842 if (IS_XSLT_NAME(node
, "key"))
3845 } else if (*(node
->name
) == 'm') {
3846 if (IS_XSLT_NAME(node
, "message"))
3847 return(XSLT_FUNC_MESSAGE
);
3849 } else if (*(node
->name
) == 'n') {
3850 if (IS_XSLT_NAME(node
, "number"))
3851 return(XSLT_FUNC_NUMBER
);
3852 else if (IS_XSLT_NAME(node
, "namespace-alias"))
3855 } else if (*(node
->name
) == 'o') {
3856 if (IS_XSLT_NAME(node
, "otherwise"))
3857 return(XSLT_FUNC_OTHERWISE
);
3858 else if (IS_XSLT_NAME(node
, "output"))
3861 } else if (*(node
->name
) == 'p') {
3862 if (IS_XSLT_NAME(node
, "param"))
3863 return(XSLT_FUNC_PARAM
);
3864 else if (IS_XSLT_NAME(node
, "processing-instruction"))
3865 return(XSLT_FUNC_PI
);
3866 else if (IS_XSLT_NAME(node
, "preserve-space"))
3869 } else if (*(node
->name
) == 's') {
3870 if (IS_XSLT_NAME(node
, "sort"))
3871 return(XSLT_FUNC_SORT
);
3872 else if (IS_XSLT_NAME(node
, "strip-space"))
3874 else if (IS_XSLT_NAME(node
, "stylesheet"))
3877 } else if (node
->name
[0] == 't') {
3878 if (IS_XSLT_NAME(node
, "text"))
3879 return(XSLT_FUNC_TEXT
);
3880 else if (IS_XSLT_NAME(node
, "template"))
3882 else if (IS_XSLT_NAME(node
, "transform"))
3885 } else if (*(node
->name
) == 'v') {
3886 if (IS_XSLT_NAME(node
, "value-of"))
3887 return(XSLT_FUNC_VALUEOF
);
3888 else if (IS_XSLT_NAME(node
, "variable"))
3889 return(XSLT_FUNC_VARIABLE
);
3891 } else if (*(node
->name
) == 'w') {
3892 if (IS_XSLT_NAME(node
, "when"))
3893 return(XSLT_FUNC_WHEN
);
3894 if (IS_XSLT_NAME(node
, "with-param"))
3895 return(XSLT_FUNC_WITHPARAM
);
3901 * xsltParseAnyXSLTElem:
3903 * @cctxt: the compilation context
3904 * @elem: the element node of the XSLT instruction
3906 * Parses, validates the content models and compiles XSLT instructions.
3908 * Returns 0 if everything's fine;
3909 * -1 on API or internal errors.
3912 xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr elem
)
3914 if ((cctxt
== NULL
) || (elem
== NULL
) ||
3915 (elem
->type
!= XML_ELEMENT_NODE
))
3920 if (! (IS_XSLT_ELEM_FAST(elem
)))
3923 * Detection of handled content of extension instructions.
3925 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
3926 cctxt
->inode
->extContentHandled
= 1;
3929 xsltCompilerNodePush(cctxt
, elem
);
3931 * URGENT TODO: Find a way to speed up this annoying redundant
3932 * textual node-name and namespace comparison.
3934 if (cctxt
->inode
->prev
->curChildType
!= 0)
3935 cctxt
->inode
->type
= cctxt
->inode
->prev
->curChildType
;
3937 cctxt
->inode
->type
= xsltGetXSLTElementTypeByNode(cctxt
, elem
);
3939 * Update the in-scope namespaces if needed.
3941 if (elem
->nsDef
!= NULL
)
3942 cctxt
->inode
->inScopeNs
=
3943 xsltCompilerBuildInScopeNsList(cctxt
, elem
);
3945 * xsltStylePreCompute():
3946 * This will compile the information found on the current
3947 * element's attributes. NOTE that this won't process the
3948 * children of the instruction.
3950 xsltStylePreCompute(cctxt
->style
, elem
);
3952 * TODO: How to react on errors in xsltStylePreCompute() ?
3956 * Validate the content model of the XSLT-element.
3958 switch (cctxt
->inode
->type
) {
3959 case XSLT_FUNC_APPLYIMPORTS
:
3962 case XSLT_FUNC_APPLYTEMPLATES
:
3963 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
3964 goto apply_templates
;
3965 case XSLT_FUNC_ATTRIBUTE
:
3966 /* <!-- Content: template --> */
3967 goto sequence_constructor
;
3968 case XSLT_FUNC_CALLTEMPLATE
:
3969 /* <!-- Content: xsl:with-param* --> */
3971 case XSLT_FUNC_CHOOSE
:
3972 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
3974 case XSLT_FUNC_COMMENT
:
3975 /* <!-- Content: template --> */
3976 goto sequence_constructor
;
3977 case XSLT_FUNC_COPY
:
3978 /* <!-- Content: template --> */
3979 goto sequence_constructor
;
3980 case XSLT_FUNC_COPYOF
:
3983 case XSLT_FUNC_DOCUMENT
: /* Extra one */
3984 /* ?? template ?? */
3985 goto sequence_constructor
;
3986 case XSLT_FUNC_ELEMENT
:
3987 /* <!-- Content: template --> */
3988 goto sequence_constructor
;
3989 case XSLT_FUNC_FALLBACK
:
3990 /* <!-- Content: template --> */
3991 goto sequence_constructor
;
3992 case XSLT_FUNC_FOREACH
:
3993 /* <!-- Content: (xsl:sort*, template) --> */
3996 /* <!-- Content: template --> */
3997 goto sequence_constructor
;
3998 case XSLT_FUNC_OTHERWISE
:
3999 /* <!-- Content: template --> */
4000 goto sequence_constructor
;
4001 case XSLT_FUNC_MESSAGE
:
4002 /* <!-- Content: template --> */
4003 goto sequence_constructor
;
4004 case XSLT_FUNC_NUMBER
:
4007 case XSLT_FUNC_PARAM
:
4009 * Check for redefinition.
4011 if ((elem
->psvi
!= NULL
) && (cctxt
->ivar
!= NULL
)) {
4012 xsltVarInfoPtr ivar
= cctxt
->ivar
;
4016 ((xsltStyleItemParamPtr
) elem
->psvi
)->name
) &&
4018 ((xsltStyleItemParamPtr
) elem
->psvi
)->ns
))
4021 xsltTransformError(NULL
, cctxt
->style
, elem
,
4022 "Redefinition of variable or parameter '%s'.\n",
4024 cctxt
->style
->errors
++;
4028 } while (ivar
!= NULL
);
4030 /* <!-- Content: template --> */
4031 goto sequence_constructor
;
4033 /* <!-- Content: template --> */
4034 goto sequence_constructor
;
4035 case XSLT_FUNC_SORT
:
4038 case XSLT_FUNC_TEXT
:
4039 /* <!-- Content: #PCDATA --> */
4041 case XSLT_FUNC_VALUEOF
:
4044 case XSLT_FUNC_VARIABLE
:
4046 * Check for redefinition.
4048 if ((elem
->psvi
!= NULL
) && (cctxt
->ivar
!= NULL
)) {
4049 xsltVarInfoPtr ivar
= cctxt
->ivar
;
4053 ((xsltStyleItemVariablePtr
) elem
->psvi
)->name
) &&
4055 ((xsltStyleItemVariablePtr
) elem
->psvi
)->ns
))
4058 xsltTransformError(NULL
, cctxt
->style
, elem
,
4059 "Redefinition of variable or parameter '%s'.\n",
4061 cctxt
->style
->errors
++;
4065 } while (ivar
!= NULL
);
4067 /* <!-- Content: template --> */
4068 goto sequence_constructor
;
4069 case XSLT_FUNC_WHEN
:
4070 /* <!-- Content: template --> */
4071 goto sequence_constructor
;
4072 case XSLT_FUNC_WITHPARAM
:
4073 /* <!-- Content: template --> */
4074 goto sequence_constructor
;
4076 #ifdef WITH_XSLT_DEBUG_PARSING
4077 xsltGenericDebug(xsltGenericDebugContext
,
4078 "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
4081 xsltTransformError(NULL
, cctxt
->style
, elem
,
4082 "xsltParseXSLTNode: Internal error; "
4083 "unhandled XSLT element '%s'.\n", elem
->name
);
4084 cctxt
->style
->errors
++;
4089 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
4090 if (elem
->children
!= NULL
) {
4091 xmlNodePtr child
= elem
->children
;
4093 if (child
->type
== XML_ELEMENT_NODE
) {
4094 if (IS_XSLT_ELEM_FAST(child
)) {
4095 if (xmlStrEqual(child
->name
, BAD_CAST
"with-param")) {
4096 cctxt
->inode
->curChildType
= XSLT_FUNC_WITHPARAM
;
4097 xsltParseAnyXSLTElem(cctxt
, child
);
4098 } else if (xmlStrEqual(child
->name
, BAD_CAST
"sort")) {
4099 cctxt
->inode
->curChildType
= XSLT_FUNC_SORT
;
4100 xsltParseAnyXSLTElem(cctxt
, child
);
4102 xsltParseContentError(cctxt
->style
, child
);
4104 xsltParseContentError(cctxt
->style
, child
);
4106 child
= child
->next
;
4107 } while (child
!= NULL
);
4112 /* <!-- Content: xsl:with-param* --> */
4113 if (elem
->children
!= NULL
) {
4114 xmlNodePtr child
= elem
->children
;
4116 if (child
->type
== XML_ELEMENT_NODE
) {
4117 if (IS_XSLT_ELEM_FAST(child
)) {
4120 type
= xsltGetXSLTElementTypeByNode(cctxt
, child
);
4121 if (type
== XSLT_FUNC_WITHPARAM
) {
4122 cctxt
->inode
->curChildType
= XSLT_FUNC_WITHPARAM
;
4123 xsltParseAnyXSLTElem(cctxt
, child
);
4125 xsltParseContentError(cctxt
->style
, child
);
4128 xsltParseContentError(cctxt
->style
, child
);
4130 child
= child
->next
;
4131 } while (child
!= NULL
);
4136 if (elem
->children
!= NULL
) {
4137 xmlNodePtr child
= elem
->children
;
4139 if ((child
->type
!= XML_TEXT_NODE
) &&
4140 (child
->type
!= XML_CDATA_SECTION_NODE
))
4142 xsltTransformError(NULL
, cctxt
->style
, elem
,
4143 "The XSLT 'text' element must have only character "
4144 "data as content.\n");
4146 child
= child
->next
;
4147 } while (child
!= NULL
);
4152 if (elem
->children
!= NULL
) {
4153 xmlNodePtr child
= elem
->children
;
4155 * Relaxed behaviour: we will allow whitespace-only text-nodes.
4158 if (((child
->type
!= XML_TEXT_NODE
) &&
4159 (child
->type
!= XML_CDATA_SECTION_NODE
)) ||
4160 (! IS_BLANK_NODE(child
)))
4162 xsltTransformError(NULL
, cctxt
->style
, elem
,
4163 "This XSLT element must have no content.\n");
4164 cctxt
->style
->errors
++;
4167 child
= child
->next
;
4168 } while (child
!= NULL
);
4173 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
4175 * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
4176 * The old behaviour did not check this.
4177 * NOTE: In XSLT 2.0 they are stripped beforehand
4178 * if whitespace-only (regardless of xml:space).
4180 if (elem
->children
!= NULL
) {
4181 xmlNodePtr child
= elem
->children
;
4182 int nbWhen
= 0, nbOtherwise
= 0, err
= 0;
4184 if (child
->type
== XML_ELEMENT_NODE
) {
4185 if (IS_XSLT_ELEM_FAST(child
)) {
4188 type
= xsltGetXSLTElementTypeByNode(cctxt
, child
);
4189 if (type
== XSLT_FUNC_WHEN
) {
4192 xsltParseContentError(cctxt
->style
, child
);
4196 cctxt
->inode
->curChildType
= XSLT_FUNC_WHEN
;
4197 xsltParseAnyXSLTElem(cctxt
, child
);
4198 } else if (type
== XSLT_FUNC_OTHERWISE
) {
4200 xsltParseContentError(cctxt
->style
, child
);
4205 xsltTransformError(NULL
, cctxt
->style
, elem
,
4206 "The XSLT 'choose' element must not contain "
4207 "more than one XSLT 'otherwise' element.\n");
4208 cctxt
->style
->errors
++;
4213 cctxt
->inode
->curChildType
= XSLT_FUNC_OTHERWISE
;
4214 xsltParseAnyXSLTElem(cctxt
, child
);
4216 xsltParseContentError(cctxt
->style
, child
);
4218 xsltParseContentError(cctxt
->style
, child
);
4222 xsltParseContentError(cctxt, child);
4224 child
= child
->next
;
4225 } while (child
!= NULL
);
4226 if ((! err
) && (! nbWhen
)) {
4227 xsltTransformError(NULL
, cctxt
->style
, elem
,
4228 "The XSLT element 'choose' must contain at least one "
4229 "XSLT element 'when'.\n");
4230 cctxt
->style
->errors
++;
4236 /* <!-- Content: (xsl:sort*, template) --> */
4238 * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
4239 * The old behaviour did not allow this, but it catched this
4240 * only at transformation-time.
4241 * In XSLT 2.0 they are stripped beforehand if whitespace-only
4242 * (regardless of xml:space).
4244 if (elem
->children
!= NULL
) {
4245 xmlNodePtr child
= elem
->children
;
4247 * Parse xsl:sort first.
4250 if ((child
->type
== XML_ELEMENT_NODE
) &&
4251 IS_XSLT_ELEM_FAST(child
))
4253 if (xsltGetXSLTElementTypeByNode(cctxt
, child
) ==
4256 cctxt
->inode
->curChildType
= XSLT_FUNC_SORT
;
4257 xsltParseAnyXSLTElem(cctxt
, child
);
4262 child
= child
->next
;
4263 } while (child
!= NULL
);
4265 * Parse the sequece constructor.
4268 xsltParseSequenceConstructor(cctxt
, child
);
4272 sequence_constructor
:
4274 * Parse the sequence constructor.
4276 if (elem
->children
!= NULL
)
4277 xsltParseSequenceConstructor(cctxt
, elem
->children
);
4280 * Register information for vars/params. Only needed if there
4281 * are any following siblings.
4283 if ((elem
->next
!= NULL
) &&
4284 ((cctxt
->inode
->type
== XSLT_FUNC_VARIABLE
) ||
4285 (cctxt
->inode
->type
== XSLT_FUNC_PARAM
)))
4287 if ((elem
->psvi
!= NULL
) &&
4288 (((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->name
))
4290 xsltCompilerVarInfoPush(cctxt
, elem
,
4291 ((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->name
,
4292 ((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->ns
);
4298 xsltCompilerNodePop(cctxt
, elem
);
4302 xsltCompilerNodePop(cctxt
, elem
);
4307 * xsltForwardsCompatUnkownItemCreate:
4309 * @cctxt: the compilation context
4311 * Creates a compiled representation of the unknown
4314 * Returns the compiled representation.
4316 static xsltStyleItemUknownPtr
4317 xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt
)
4319 xsltStyleItemUknownPtr item
;
4321 item
= (xsltStyleItemUknownPtr
) xmlMalloc(sizeof(xsltStyleItemUknown
));
4323 xsltTransformError(NULL
, cctxt
->style
, NULL
,
4324 "Internal error in xsltForwardsCompatUnkownItemCreate(): "
4325 "Failed to allocate memory.\n");
4326 cctxt
->style
->errors
++;
4329 memset(item
, 0, sizeof(xsltStyleItemUknown
));
4330 item
->type
= XSLT_FUNC_UNKOWN_FORWARDS_COMPAT
;
4332 * Store it in the stylesheet.
4334 item
->next
= cctxt
->style
->preComps
;
4335 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
4340 * xsltParseUnknownXSLTElem:
4342 * @cctxt: the compilation context
4343 * @node: the element of the unknown XSLT instruction
4345 * Parses an unknown XSLT element.
4346 * If forwards compatible mode is enabled this will allow
4347 * such an unknown XSLT and; otherwise it is rejected.
4349 * Returns 1 in the unknown XSLT instruction is rejected,
4350 * 0 if everything's fine and
4351 * -1 on API or internal errors.
4354 xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt
,
4357 if ((cctxt
== NULL
) || (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
4361 * Detection of handled content of extension instructions.
4363 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4364 cctxt
->inode
->extContentHandled
= 1;
4366 if (cctxt
->inode
->forwardsCompat
== 0) {
4368 * We are not in forwards-compatible mode, so raise an error.
4370 xsltTransformError(NULL
, cctxt
->style
, node
,
4371 "Unknown XSLT element '%s'.\n", node
->name
);
4372 cctxt
->style
->errors
++;
4376 * Forwards-compatible mode.
4377 * ------------------------
4379 * Parse/compile xsl:fallback elements.
4381 * QUESTION: Do we have to raise an error if there's no xsl:fallback?
4382 * ANSWER: No, since in the stylesheet the fallback behaviour might
4383 * also be provided by using the XSLT function "element-available".
4385 if (cctxt
->unknownItem
== NULL
) {
4387 * Create a singleton for all unknown XSLT instructions.
4389 cctxt
->unknownItem
= xsltForwardsCompatUnkownItemCreate(cctxt
);
4390 if (cctxt
->unknownItem
== NULL
) {
4395 node
->psvi
= cctxt
->unknownItem
;
4396 if (node
->children
== NULL
)
4399 xmlNodePtr child
= node
->children
;
4401 xsltCompilerNodePush(cctxt
, node
);
4403 * Update the in-scope namespaces if needed.
4405 if (node
->nsDef
!= NULL
)
4406 cctxt
->inode
->inScopeNs
=
4407 xsltCompilerBuildInScopeNsList(cctxt
, node
);
4409 * Parse all xsl:fallback children.
4412 if ((child
->type
== XML_ELEMENT_NODE
) &&
4413 IS_XSLT_ELEM_FAST(child
) &&
4414 IS_XSLT_NAME(child
, "fallback"))
4416 cctxt
->inode
->curChildType
= XSLT_FUNC_FALLBACK
;
4417 xsltParseAnyXSLTElem(cctxt
, child
);
4419 child
= child
->next
;
4420 } while (child
!= NULL
);
4422 xsltCompilerNodePop(cctxt
, node
);
4428 * xsltParseSequenceConstructor:
4430 * @cctxt: the compilation context
4431 * @cur: the start-node of the content to be parsed
4433 * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
4434 * This will additionally remove xsl:text elements from the tree.
4437 xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt
, xmlNodePtr cur
)
4440 xmlNodePtr deleteNode
= NULL
;
4442 if (cctxt
== NULL
) {
4443 xmlGenericError(xmlGenericErrorContext
,
4444 "xsltParseSequenceConstructor: Bad arguments\n");
4445 cctxt
->style
->errors
++;
4449 * Detection of handled content of extension instructions.
4451 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4452 cctxt
->inode
->extContentHandled
= 1;
4454 if ((cur
== NULL
) || (cur
->type
== XML_NAMESPACE_DECL
))
4457 * This is the content reffered to as a "template".
4458 * E.g. an xsl:element has such content model:
4461 * namespace = { uri-reference }
4462 * use-attribute-sets = qnames>
4463 * <!-- Content: template -->
4465 * NOTE that in XSLT-2 the term "template" was abandoned due to
4466 * confusion with xsl:template and the term "sequence constructor"
4467 * was introduced instead.
4469 * The following XSLT-instructions are allowed to appear:
4470 * xsl:apply-templates, xsl:call-template, xsl:apply-imports,
4471 * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
4472 * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
4473 * xsl:message, xsl:fallback,
4474 * xsl:processing-instruction, xsl:comment, xsl:element
4476 * Additional allowed content:
4477 * 1) extension instructions
4478 * 2) literal result elements
4481 * NOTE that this content model does *not* allow xsl:param.
4483 while (cur
!= NULL
) {
4484 if (deleteNode
!= NULL
) {
4485 #ifdef WITH_XSLT_DEBUG_BLANKS
4486 xsltGenericDebug(xsltGenericDebugContext
,
4487 "xsltParseSequenceConstructor: removing xsl:text element\n");
4489 xmlUnlinkNode(deleteNode
);
4490 xmlFreeNode(deleteNode
);
4493 if (cur
->type
== XML_ELEMENT_NODE
) {
4495 if (cur
->psvi
== xsltXSLTTextMarker
) {
4498 * --------------------------------------------------------
4504 * Mark the xsl:text element for later deletion.
4510 tmp
= cur
->children
;
4513 * We don't expect more than one text-node in the
4514 * content, since we already merged adjacent
4515 * text/CDATA-nodes and eliminated PI/comment-nodes.
4517 if ((tmp
->type
== XML_TEXT_NODE
) ||
4518 (tmp
->next
== NULL
))
4521 * Leave the contained text-node in the tree.
4524 xmlAddPrevSibling(cur
, tmp
);
4527 xsltTransformError(NULL
, cctxt
->style
, cur
,
4528 "Element 'xsl:text': Invalid type "
4529 "of node found in content.\n");
4530 cctxt
->style
->errors
++;
4533 if (cur
->properties
) {
4536 * TODO: We need to report errors for
4539 attr
= cur
->properties
;
4541 if ((attr
->ns
== NULL
) &&
4542 (attr
->name
!= NULL
) &&
4543 (attr
->name
[0] == 'd') &&
4544 xmlStrEqual(attr
->name
,
4545 BAD_CAST
"disable-output-escaping"))
4548 * Attr "disable-output-escaping".
4549 * XSLT-2: This attribute is deprecated.
4551 if ((attr
->children
!= NULL
) &&
4552 xmlStrEqual(attr
->children
->content
,
4556 * Disable output escaping for this
4560 tmp
->name
= xmlStringTextNoenc
;
4561 } else if ((attr
->children
== NULL
) ||
4562 (attr
->children
->content
== NULL
) ||
4563 (!xmlStrEqual(attr
->children
->content
,
4566 xsltTransformError(NULL
, cctxt
->style
,
4568 "Attribute 'disable-output-escaping': "
4569 "Invalid value. Expected is "
4570 "'yes' or 'no'.\n");
4571 cctxt
->style
->errors
++;
4576 } while (attr
!= NULL
);
4578 } else if (IS_XSLT_ELEM_FAST(cur
)) {
4580 * TODO: Using the XSLT-marker is still not stable yet.
4582 /* if (cur->psvi == xsltXSLTElemMarker) { */
4585 * --------------------------------------------------------
4588 type
= xsltGetXSLTElementTypeByNode(cctxt
, cur
);
4590 case XSLT_FUNC_APPLYIMPORTS
:
4591 case XSLT_FUNC_APPLYTEMPLATES
:
4592 case XSLT_FUNC_ATTRIBUTE
:
4593 case XSLT_FUNC_CALLTEMPLATE
:
4594 case XSLT_FUNC_CHOOSE
:
4595 case XSLT_FUNC_COMMENT
:
4596 case XSLT_FUNC_COPY
:
4597 case XSLT_FUNC_COPYOF
:
4598 case XSLT_FUNC_DOCUMENT
: /* Extra one */
4599 case XSLT_FUNC_ELEMENT
:
4600 case XSLT_FUNC_FALLBACK
:
4601 case XSLT_FUNC_FOREACH
:
4603 case XSLT_FUNC_MESSAGE
:
4604 case XSLT_FUNC_NUMBER
:
4606 case XSLT_FUNC_TEXT
:
4607 case XSLT_FUNC_VALUEOF
:
4608 case XSLT_FUNC_VARIABLE
:
4610 * Parse the XSLT element.
4612 cctxt
->inode
->curChildType
= type
;
4613 xsltParseAnyXSLTElem(cctxt
, cur
);
4616 xsltParseUnknownXSLTElem(cctxt
, cur
);
4625 xsltCompilerNodePush(cctxt
, cur
);
4627 * Update the in-scope namespaces if needed.
4629 if (cur
->nsDef
!= NULL
)
4630 cctxt
->inode
->inScopeNs
=
4631 xsltCompilerBuildInScopeNsList(cctxt
, cur
);
4633 * The current element is either a literal result element
4634 * or an extension instruction.
4636 * Process attr "xsl:extension-element-prefixes".
4637 * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
4638 * processed by the implementor of the extension function;
4639 * i.e., it won't be handled by the XSLT processor.
4642 * "exclude-result-prefixes" is only allowed on literal
4643 * result elements and "xsl:exclude-result-prefixes"
4644 * on xsl:stylesheet/xsl:transform.
4646 * "There are a number of standard attributes
4647 * that may appear on any XSLT element: specifically
4648 * version, exclude-result-prefixes,
4649 * extension-element-prefixes, xpath-default-namespace,
4650 * default-collation, and use-when."
4653 * For literal result elements:
4654 * "xsl:version, xsl:exclude-result-prefixes,
4655 * xsl:extension-element-prefixes,
4656 * xsl:xpath-default-namespace,
4657 * xsl:default-collation, or xsl:use-when."
4659 if (cur
->properties
)
4660 cctxt
->inode
->extElemNs
=
4661 xsltParseExtElemPrefixes(cctxt
,
4662 cur
, cctxt
->inode
->extElemNs
,
4663 XSLT_ELEMENT_CATEGORY_LRE
);
4665 * Eval if we have an extension instruction here.
4667 if ((cur
->ns
!= NULL
) &&
4668 (cctxt
->inode
->extElemNs
!= NULL
) &&
4669 (xsltCheckExtPrefix(cctxt
->style
, cur
->ns
->href
) == 1))
4672 * Extension instructions
4673 * ----------------------------------------------------
4674 * Mark the node information.
4676 cctxt
->inode
->category
= XSLT_ELEMENT_CATEGORY_EXTENSION
;
4677 cctxt
->inode
->extContentHandled
= 0;
4678 if (cur
->psvi
!= NULL
) {
4681 * TODO: Temporary sanity check.
4683 xsltTransformError(NULL
, cctxt
->style
, cur
,
4684 "Internal error in xsltParseSequenceConstructor(): "
4685 "Occupied PSVI field.\n");
4686 cctxt
->style
->errors
++;
4690 cur
->psvi
= (void *)
4691 xsltPreComputeExtModuleElement(cctxt
->style
, cur
);
4693 if (cur
->psvi
== NULL
) {
4695 * OLD COMMENT: "Unknown element, maybe registered
4696 * at the context level. Mark it for later
4698 * QUESTION: What does the xsltExtMarker mean?
4699 * ANSWER: It is used in
4700 * xsltApplySequenceConstructor() at
4701 * transformation-time to look out for extension
4702 * registered in the transformation context.
4704 cur
->psvi
= (void *) xsltExtMarker
;
4707 * BIG NOTE: Now the ugly part. In previous versions
4708 * of Libxslt (until 1.1.16), all the content of an
4709 * extension instruction was processed and compiled without
4710 * the need of the extension-author to explicitely call
4711 * such a processing;.We now need to mimic this old
4712 * behaviour in order to avoid breaking old code
4713 * on the extension-author's side.
4715 * 1) If the author does *not* set the
4716 * compile-time-flag @extContentHandled, then we'll
4717 * parse the content assuming that it's a "template"
4718 * (or "sequence constructor in XSLT 2.0 terms).
4719 * NOTE: If the extension is registered at
4720 * transformation-time only, then there's no way of
4721 * knowing that content shall be valid, and we'll
4722 * process the content the same way.
4723 * 2) If the author *does* set the flag, then we'll assume
4724 * that the author has handled the parsing him/herself
4725 * (e.g. called xsltParseSequenceConstructor(), etc.
4726 * explicitely in his/her code).
4728 if ((cur
->children
!= NULL
) &&
4729 (cctxt
->inode
->extContentHandled
== 0))
4732 * Default parsing of the content using the
4733 * sequence-constructor model.
4735 xsltParseSequenceConstructor(cctxt
, cur
->children
);
4739 * Literal result element
4740 * ----------------------------------------------------
4741 * Allowed XSLT attributes:
4742 * xsl:extension-element-prefixes CDATA #IMPLIED
4743 * xsl:exclude-result-prefixes CDATA #IMPLIED
4744 * TODO: xsl:use-attribute-sets %qnames; #IMPLIED
4745 * xsl:version NMTOKEN #IMPLIED
4748 cctxt
->inode
->category
= XSLT_ELEMENT_CATEGORY_LRE
;
4749 if (cur
->properties
!= NULL
) {
4750 xmlAttrPtr attr
= cur
->properties
;
4752 * Attribute "xsl:exclude-result-prefixes".
4754 cctxt
->inode
->exclResultNs
=
4755 xsltParseExclResultPrefixes(cctxt
, cur
,
4756 cctxt
->inode
->exclResultNs
,
4757 XSLT_ELEMENT_CATEGORY_LRE
);
4759 * Attribute "xsl:version".
4761 xsltParseAttrXSLTVersion(cctxt
, cur
,
4762 XSLT_ELEMENT_CATEGORY_LRE
);
4764 * Report invalid XSLT attributes.
4765 * For XSLT 1.0 only xsl:use-attribute-sets is allowed
4766 * next to xsl:version, xsl:exclude-result-prefixes and
4767 * xsl:extension-element-prefixes.
4769 * Mark all XSLT attributes, in order to skip such
4770 * attributes when instantiating the LRE.
4773 if ((attr
->psvi
!= xsltXSLTAttrMarker
) &&
4774 IS_XSLT_ATTR_FAST(attr
))
4776 if (! xmlStrEqual(attr
->name
,
4777 BAD_CAST
"use-attribute-sets"))
4779 xsltTransformError(NULL
, cctxt
->style
,
4781 "Unknown XSLT attribute '%s'.\n",
4783 cctxt
->style
->errors
++;
4788 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
4792 } while (attr
!= NULL
);
4795 * Create/reuse info for the literal result element.
4797 if (cctxt
->inode
->nsChanged
)
4798 xsltLREInfoCreate(cctxt
, cur
, 1);
4799 cur
->psvi
= cctxt
->inode
->litResElemInfo
;
4801 * Apply ns-aliasing on the element and on its attributes.
4803 if (cctxt
->hasNsAliases
)
4804 xsltLREBuildEffectiveNs(cctxt
, cur
);
4806 * Compile attribute value templates (AVT).
4808 if (cur
->properties
) {
4809 xmlAttrPtr attr
= cur
->properties
;
4811 while (attr
!= NULL
) {
4812 xsltCompileAttr(cctxt
->style
, attr
);
4817 * Parse the content, which is defined to be a "template"
4818 * (or "sequence constructor" in XSLT 2.0 terms).
4820 if (cur
->children
!= NULL
) {
4821 xsltParseSequenceConstructor(cctxt
, cur
->children
);
4825 * Leave the non-XSLT element.
4827 xsltCompilerNodePop(cctxt
, cur
);
4832 if (deleteNode
!= NULL
) {
4833 #ifdef WITH_XSLT_DEBUG_BLANKS
4834 xsltGenericDebug(xsltGenericDebugContext
,
4835 "xsltParseSequenceConstructor: removing xsl:text element\n");
4837 xmlUnlinkNode(deleteNode
);
4838 xmlFreeNode(deleteNode
);
4844 * xsltParseTemplateContent:
4845 * @style: the XSLT stylesheet
4846 * @templ: the node containing the content to be parsed
4848 * Parses and compiles the content-model of an xsl:template element.
4849 * Note that this is *not* the "template" content model (or "sequence
4850 * constructor" in XSLT 2.0); it it allows addional xsl:param
4851 * elements as immediate children of @templ.
4854 * exsltFuncFunctionComp() (EXSLT, functions.c)
4855 * So this is intended to be called from extension functions.
4858 xsltParseTemplateContent(xsltStylesheetPtr style
, xmlNodePtr templ
) {
4859 if ((style
== NULL
) || (templ
== NULL
) ||
4860 (templ
->type
== XML_NAMESPACE_DECL
))
4864 * Detection of handled content of extension instructions.
4866 if (XSLT_CCTXT(style
)->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4867 XSLT_CCTXT(style
)->inode
->extContentHandled
= 1;
4870 if (templ
->children
!= NULL
) {
4871 xmlNodePtr child
= templ
->children
;
4873 * Process xsl:param elements, which can only occur as the
4874 * immediate children of xsl:template (well, and of any
4875 * user-defined extension instruction if needed).
4878 if ((child
->type
== XML_ELEMENT_NODE
) &&
4879 IS_XSLT_ELEM_FAST(child
) &&
4880 IS_XSLT_NAME(child
, "param"))
4882 XSLT_CCTXT(style
)->inode
->curChildType
= XSLT_FUNC_PARAM
;
4883 xsltParseAnyXSLTElem(XSLT_CCTXT(style
), child
);
4886 child
= child
->next
;
4887 } while (child
!= NULL
);
4889 * Parse the content and register the pattern.
4891 xsltParseSequenceConstructor(XSLT_CCTXT(style
), child
);
4895 #else /* XSLT_REFACTORED */
4898 * xsltParseTemplateContent:
4899 * @style: the XSLT stylesheet
4900 * @templ: the container node (can be a document for literal results)
4902 * parse a template content-model
4903 * Clean-up the template content from unwanted ignorable blank nodes
4904 * and process xslt:text
4907 xsltParseTemplateContent(xsltStylesheetPtr style
, xmlNodePtr templ
) {
4908 xmlNodePtr cur
, delete;
4910 if ((style
== NULL
) || (templ
== NULL
) ||
4911 (templ
->type
== XML_NAMESPACE_DECL
)) return;
4914 * This content comes from the stylesheet
4915 * For stylesheets, the set of whitespace-preserving
4916 * element names consists of just xsl:text.
4918 cur
= templ
->children
;
4920 while (cur
!= NULL
) {
4921 if (delete != NULL
) {
4922 #ifdef WITH_XSLT_DEBUG_BLANKS
4923 xsltGenericDebug(xsltGenericDebugContext
,
4924 "xsltParseTemplateContent: removing text\n");
4926 xmlUnlinkNode(delete);
4927 xmlFreeNode(delete);
4930 if (IS_XSLT_ELEM(cur
)) {
4931 xsltStylePreCompute(style
, cur
);
4933 if (IS_XSLT_NAME(cur
, "text")) {
4935 * TODO: Processing of xsl:text should be moved to
4936 * xsltPreprocessStylesheet(), since otherwise this
4937 * will be performed for every multiply included
4938 * stylesheet; i.e. this here is not skipped with
4939 * the use of the style->nopreproc flag.
4941 if (cur
->children
!= NULL
) {
4943 xmlNodePtr text
= cur
->children
, next
;
4946 prop
= xmlGetNsProp(cur
,
4947 (const xmlChar
*)"disable-output-escaping",
4950 #ifdef WITH_XSLT_DEBUG_PARSING
4951 xsltGenericDebug(xsltGenericDebugContext
,
4952 "Disable escaping: %s\n", text
->content
);
4954 if (xmlStrEqual(prop
, (const xmlChar
*)"yes")) {
4956 } else if (!xmlStrEqual(prop
,
4957 (const xmlChar
*)"no")){
4958 xsltTransformError(NULL
, style
, cur
,
4959 "xsl:text: disable-output-escaping allows only yes or no\n");
4966 while (text
!= NULL
) {
4967 if (text
->type
== XML_COMMENT_NODE
) {
4971 if ((text
->type
!= XML_TEXT_NODE
) &&
4972 (text
->type
!= XML_CDATA_SECTION_NODE
)) {
4973 xsltTransformError(NULL
, style
, cur
,
4974 "xsltParseTemplateContent: xslt:text content problem\n");
4978 if ((noesc
) && (text
->type
!= XML_CDATA_SECTION_NODE
))
4979 text
->name
= xmlStringTextNoenc
;
4984 * replace xsl:text by the list of childs
4987 text
= cur
->children
;
4988 while (text
!= NULL
) {
4989 if ((style
->internalized
) &&
4990 (text
->content
!= NULL
) &&
4991 (!xmlDictOwns(style
->dict
, text
->content
))) {
4994 * internalize the text string
4996 if (text
->doc
->dict
!= NULL
) {
4999 tmp
= xmlDictLookup(text
->doc
->dict
,
5001 if (tmp
!= text
->content
) {
5002 xmlNodeSetContent(text
, NULL
);
5003 text
->content
= (xmlChar
*) tmp
;
5009 xmlUnlinkNode(text
);
5010 xmlAddPrevSibling(cur
, text
);
5019 else if ((cur
->ns
!= NULL
) && (style
->nsDefs
!= NULL
) &&
5020 (xsltCheckExtPrefix(style
, cur
->ns
->prefix
)))
5023 * okay this is an extension element compile it too
5025 xsltStylePreCompute(style
, cur
);
5027 else if (cur
->type
== XML_ELEMENT_NODE
)
5030 * This is an element which will be output as part of the
5031 * template exectution, precompile AVT if found.
5033 if ((cur
->ns
== NULL
) && (style
->defaultAlias
!= NULL
)) {
5034 cur
->ns
= xmlSearchNsByHref(cur
->doc
, cur
,
5035 style
->defaultAlias
);
5037 if (cur
->properties
!= NULL
) {
5038 xmlAttrPtr attr
= cur
->properties
;
5040 while (attr
!= NULL
) {
5041 xsltCompileAttr(style
, attr
);
5049 if (cur
->children
!= NULL
) {
5050 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
5051 cur
= cur
->children
;
5056 if (cur
->next
!= NULL
) {
5069 if (cur
->next
!= NULL
) {
5073 } while (cur
!= NULL
);
5075 if (delete != NULL
) {
5076 #ifdef WITH_XSLT_DEBUG_PARSING
5077 xsltGenericDebug(xsltGenericDebugContext
,
5078 "xsltParseTemplateContent: removing text\n");
5080 xmlUnlinkNode(delete);
5081 xmlFreeNode(delete);
5086 * Skip the first params
5088 cur
= templ
->children
;
5089 while (cur
!= NULL
) {
5090 if ((IS_XSLT_ELEM(cur
)) && (!(IS_XSLT_NAME(cur
, "param"))))
5096 * Browse the remainder of the template
5098 while (cur
!= NULL
) {
5099 if ((IS_XSLT_ELEM(cur
)) && (IS_XSLT_NAME(cur
, "param"))) {
5100 xmlNodePtr param
= cur
;
5102 xsltTransformError(NULL
, style
, cur
,
5103 "xsltParseTemplateContent: ignoring misplaced param element\n");
5104 if (style
!= NULL
) style
->warnings
++;
5106 xmlUnlinkNode(param
);
5113 #endif /* else XSLT_REFACTORED */
5116 * xsltParseStylesheetKey:
5117 * @style: the XSLT stylesheet
5118 * @key: the "key" element
5120 * <!-- Category: top-level-element -->
5121 * <xsl:key name = qname, match = pattern, use = expression />
5123 * parse an XSLT stylesheet key definition and register it
5127 xsltParseStylesheetKey(xsltStylesheetPtr style
, xmlNodePtr key
) {
5128 xmlChar
*prop
= NULL
;
5129 xmlChar
*use
= NULL
;
5130 xmlChar
*match
= NULL
;
5131 xmlChar
*name
= NULL
;
5132 xmlChar
*nameURI
= NULL
;
5134 if ((style
== NULL
) || (key
== NULL
) || (key
->type
!= XML_ELEMENT_NODE
))
5140 prop
= xmlGetNsProp(key
, (const xmlChar
*)"name", NULL
);
5145 * TODO: Don't use xsltGetQNameURI().
5147 URI
= xsltGetQNameURI(key
, &prop
);
5149 if (style
!= NULL
) style
->errors
++;
5154 nameURI
= xmlStrdup(URI
);
5156 #ifdef WITH_XSLT_DEBUG_PARSING
5157 xsltGenericDebug(xsltGenericDebugContext
,
5158 "xsltParseStylesheetKey: name %s\n", name
);
5161 xsltTransformError(NULL
, style
, key
,
5162 "xsl:key : error missing name\n");
5163 if (style
!= NULL
) style
->errors
++;
5167 match
= xmlGetNsProp(key
, (const xmlChar
*)"match", NULL
);
5168 if (match
== NULL
) {
5169 xsltTransformError(NULL
, style
, key
,
5170 "xsl:key : error missing match\n");
5171 if (style
!= NULL
) style
->errors
++;
5175 use
= xmlGetNsProp(key
, (const xmlChar
*)"use", NULL
);
5177 xsltTransformError(NULL
, style
, key
,
5178 "xsl:key : error missing use\n");
5179 if (style
!= NULL
) style
->errors
++;
5186 xsltAddKey(style
, name
, nameURI
, match
, use
, key
);
5196 if (nameURI
!= NULL
)
5199 if (key
->children
!= NULL
) {
5200 xsltParseContentError(style
, key
->children
);
5204 #ifdef XSLT_REFACTORED
5206 * xsltParseXSLTTemplate:
5207 * @style: the XSLT stylesheet
5208 * @template: the "template" element
5210 * parse an XSLT stylesheet template building the associated structures
5211 * TODO: Is @style ever expected to be NULL?
5214 * xsltParseXSLTStylesheet()
5215 * xsltParseStylesheetTop()
5219 xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt
, xmlNodePtr templNode
) {
5220 xsltTemplatePtr templ
;
5224 if ((cctxt
== NULL
) || (templNode
== NULL
) ||
5225 (templNode
->type
!= XML_ELEMENT_NODE
))
5229 * Create and link the structure
5231 templ
= xsltNewTemplate();
5235 xsltCompilerNodePush(cctxt
, templNode
);
5236 if (templNode
->nsDef
!= NULL
)
5237 cctxt
->inode
->inScopeNs
=
5238 xsltCompilerBuildInScopeNsList(cctxt
, templNode
);
5240 templ
->next
= cctxt
->style
->templates
;
5241 cctxt
->style
->templates
= templ
;
5242 templ
->style
= cctxt
->style
;
5247 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"mode", NULL
);
5249 const xmlChar
*modeURI
;
5252 * TODO: We need a standardized function for extraction
5253 * of namespace names and local names from QNames.
5254 * Don't use xsltGetQNameURI() as it cannot channe�
5255 * reports through the context.
5257 modeURI
= xsltGetQNameURI(templNode
, &prop
);
5259 cctxt
->style
->errors
++;
5262 templ
->mode
= xmlDictLookup(cctxt
->style
->dict
, prop
, -1);
5265 if (xmlValidateNCName(templ
->mode
, 0)) {
5266 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5267 "xsl:template: Attribute 'mode': The local part '%s' "
5268 "of the value is not a valid NCName.\n", templ
->name
);
5269 cctxt
->style
->errors
++;
5272 if (modeURI
!= NULL
)
5273 templ
->modeURI
= xmlDictLookup(cctxt
->style
->dict
, modeURI
, -1);
5274 #ifdef WITH_XSLT_DEBUG_PARSING
5275 xsltGenericDebug(xsltGenericDebugContext
,
5276 "xsltParseXSLTTemplate: mode %s\n", templ
->mode
);
5280 * Attribute "match".
5282 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"match", NULL
);
5284 templ
->match
= prop
;
5288 * Attribute "priority".
5290 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"priority", NULL
);
5292 priority
= xmlXPathStringEvalNumber(prop
);
5293 templ
->priority
= (float) priority
;
5300 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"name", NULL
);
5302 const xmlChar
*nameURI
;
5303 xsltTemplatePtr curTempl
;
5306 * TODO: Don't use xsltGetQNameURI().
5308 nameURI
= xsltGetQNameURI(templNode
, &prop
);
5310 cctxt
->style
->errors
++;
5313 templ
->name
= xmlDictLookup(cctxt
->style
->dict
, prop
, -1);
5316 if (xmlValidateNCName(templ
->name
, 0)) {
5317 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5318 "xsl:template: Attribute 'name': The local part '%s' of "
5319 "the value is not a valid NCName.\n", templ
->name
);
5320 cctxt
->style
->errors
++;
5323 if (nameURI
!= NULL
)
5324 templ
->nameURI
= xmlDictLookup(cctxt
->style
->dict
, nameURI
, -1);
5325 curTempl
= templ
->next
;
5326 while (curTempl
!= NULL
) {
5327 if ((nameURI
!= NULL
&& xmlStrEqual(curTempl
->name
, templ
->name
) &&
5328 xmlStrEqual(curTempl
->nameURI
, nameURI
) ) ||
5329 (nameURI
== NULL
&& curTempl
->nameURI
== NULL
&&
5330 xmlStrEqual(curTempl
->name
, templ
->name
)))
5332 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5333 "xsl:template: error duplicate name '%s'\n", templ
->name
);
5334 cctxt
->style
->errors
++;
5337 curTempl
= curTempl
->next
;
5340 if (templNode
->children
!= NULL
) {
5341 xsltParseTemplateContent(cctxt
->style
, templNode
);
5343 * MAYBE TODO: Custom behaviour: In order to stay compatible with
5344 * Xalan and MSXML(.NET), we could allow whitespace
5345 * to appear before an xml:param element; this whitespace
5346 * will additionally become part of the "template".
5347 * NOTE that this is totally deviates from the spec, but
5348 * is the de facto behaviour of Xalan and MSXML(.NET).
5349 * Personally I wouldn't allow this, since if we have:
5350 * <xsl:template ...xml:space="preserve">
5351 * <xsl:param name="foo"/>
5352 * <xsl:param name="bar"/>
5353 * <xsl:param name="zoo"/>
5354 * ... the whitespace between every xsl:param would be
5355 * added to the result tree.
5359 templ
->elem
= templNode
;
5360 templ
->content
= templNode
->children
;
5361 xsltAddTemplate(cctxt
->style
, templ
, templ
->mode
, templ
->modeURI
);
5364 xsltCompilerNodePop(cctxt
, templNode
);
5368 #else /* XSLT_REFACTORED */
5371 * xsltParseStylesheetTemplate:
5372 * @style: the XSLT stylesheet
5373 * @template: the "template" element
5375 * parse an XSLT stylesheet template building the associated structures
5379 xsltParseStylesheetTemplate(xsltStylesheetPtr style
, xmlNodePtr
template) {
5380 xsltTemplatePtr ret
;
5382 xmlChar
*mode
= NULL
;
5383 xmlChar
*modeURI
= NULL
;
5386 if ((style
== NULL
) || (template == NULL
) ||
5387 (template->type
!= XML_ELEMENT_NODE
))
5391 * Create and link the structure
5393 ret
= xsltNewTemplate();
5396 ret
->next
= style
->templates
;
5397 style
->templates
= ret
;
5401 * Get inherited namespaces
5404 * TODO: Apply the optimized in-scope-namespace mechanism
5405 * as for the other XSLT instructions.
5407 xsltGetInheritedNsList(style
, ret
, template);
5412 prop
= xmlGetNsProp(template, (const xmlChar
*)"mode", NULL
);
5417 * TODO: Don't use xsltGetQNameURI().
5419 URI
= xsltGetQNameURI(template, &prop
);
5421 if (style
!= NULL
) style
->errors
++;
5426 modeURI
= xmlStrdup(URI
);
5428 ret
->mode
= xmlDictLookup(style
->dict
, mode
, -1);
5429 ret
->modeURI
= xmlDictLookup(style
->dict
, modeURI
, -1);
5430 #ifdef WITH_XSLT_DEBUG_PARSING
5431 xsltGenericDebug(xsltGenericDebugContext
,
5432 "xsltParseStylesheetTemplate: mode %s\n", mode
);
5434 if (mode
!= NULL
) xmlFree(mode
);
5435 if (modeURI
!= NULL
) xmlFree(modeURI
);
5437 prop
= xmlGetNsProp(template, (const xmlChar
*)"match", NULL
);
5439 if (ret
->match
!= NULL
) xmlFree(ret
->match
);
5443 prop
= xmlGetNsProp(template, (const xmlChar
*)"priority", NULL
);
5445 priority
= xmlXPathStringEvalNumber(prop
);
5446 ret
->priority
= (float) priority
;
5450 prop
= xmlGetNsProp(template, (const xmlChar
*)"name", NULL
);
5455 * TODO: Don't use xsltGetQNameURI().
5457 URI
= xsltGetQNameURI(template, &prop
);
5459 if (style
!= NULL
) style
->errors
++;
5462 if (xmlValidateNCName(prop
,0)) {
5463 xsltTransformError(NULL
, style
, template,
5464 "xsl:template : error invalid name '%s'\n", prop
);
5465 if (style
!= NULL
) style
->errors
++;
5469 ret
->name
= xmlDictLookup(style
->dict
, BAD_CAST prop
, -1);
5473 ret
->nameURI
= xmlDictLookup(style
->dict
, BAD_CAST URI
, -1);
5475 ret
->nameURI
= NULL
;
5480 * parse the content and register the pattern
5482 xsltParseTemplateContent(style
, template);
5483 ret
->elem
= template;
5484 ret
->content
= template->children
;
5485 xsltAddTemplate(style
, ret
, ret
->mode
, ret
->modeURI
);
5491 #endif /* else XSLT_REFACTORED */
5493 #ifdef XSLT_REFACTORED
5497 * @cctxt: the compilation context
5498 * @node: the xsl:include node
5500 * Process the xslt include node on the source node
5502 static xsltStyleItemIncludePtr
5503 xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
) {
5504 xsltStyleItemIncludePtr item
;
5506 if ((cctxt
== NULL
) || (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
5510 item
= (xsltStyleItemIncludePtr
) xmlMalloc(sizeof(xsltStyleItemInclude
));
5512 xsltTransformError(NULL
, cctxt
->style
, node
,
5513 "xsltIncludeComp : malloc failed\n");
5514 cctxt
->style
->errors
++;
5517 memset(item
, 0, sizeof(xsltStyleItemInclude
));
5521 item
->type
= XSLT_FUNC_INCLUDE
;
5523 item
->next
= cctxt
->style
->preComps
;
5524 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
5530 * xsltParseFindTopLevelElem:
5533 xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt
,
5535 const xmlChar
*name
,
5536 const xmlChar
*namespaceURI
,
5537 int breakOnOtherElem
,
5538 xmlNodePtr
*resultNode
)
5544 while (cur
!= NULL
) {
5545 if (cur
->type
== XML_ELEMENT_NODE
) {
5546 if ((cur
->ns
!= NULL
) && (cur
->name
!= NULL
)) {
5547 if ((*(cur
->name
) == *name
) &&
5548 xmlStrEqual(cur
->name
, name
) &&
5549 xmlStrEqual(cur
->ns
->href
, namespaceURI
))
5555 if (breakOnOtherElem
)
5565 xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt
,
5572 * TODO: The reason why this function exists:
5573 * due to historical reasons some of the
5574 * top-level declarations are processed by functions
5575 * in other files. Since we need still to set
5576 * up the node-info and generate information like
5577 * in-scope namespaces, this is a wrapper around
5578 * those old parsing functions.
5580 xsltCompilerNodePush(cctxt
, node
);
5581 if (node
->nsDef
!= NULL
)
5582 cctxt
->inode
->inScopeNs
=
5583 xsltCompilerBuildInScopeNsList(cctxt
, node
);
5584 cctxt
->inode
->type
= type
;
5587 case XSLT_FUNC_INCLUDE
:
5591 if (xsltCompileXSLTIncludeElem(cctxt
, node
) == NULL
)
5594 * Mark this stylesheet tree as being currently included.
5596 oldIsInclude
= cctxt
->isInclude
;
5597 cctxt
->isInclude
= 1;
5599 if (xsltParseStylesheetInclude(cctxt
->style
, node
) != 0) {
5600 cctxt
->style
->errors
++;
5602 cctxt
->isInclude
= oldIsInclude
;
5605 case XSLT_FUNC_PARAM
:
5606 xsltStylePreCompute(cctxt
->style
, node
);
5607 xsltParseGlobalParam(cctxt
->style
, node
);
5609 case XSLT_FUNC_VARIABLE
:
5610 xsltStylePreCompute(cctxt
->style
, node
);
5611 xsltParseGlobalVariable(cctxt
->style
, node
);
5613 case XSLT_FUNC_ATTRSET
:
5614 xsltParseStylesheetAttributeSet(cctxt
->style
, node
);
5617 xsltTransformError(NULL
, cctxt
->style
, node
,
5618 "Internal error: (xsltParseTopLevelXSLTElem) "
5619 "Cannot handle this top-level declaration.\n");
5620 cctxt
->style
->errors
++;
5625 xsltCompilerNodePop(cctxt
, node
);
5632 xsltParseRemoveWhitespace(xmlNodePtr node
)
5634 if ((node
== NULL
) || (node
->children
== NULL
))
5637 xmlNodePtr delNode
= NULL
, child
= node
->children
;
5641 xmlUnlinkNode(delNode
);
5642 xmlFreeNode(delNode
);
5645 if (((child
->type
== XML_TEXT_NODE
) ||
5646 (child
->type
== XML_CDATA_SECTION_NODE
)) &&
5647 (IS_BLANK_NODE(child
)))
5649 child
= child
->next
;
5650 } while (child
!= NULL
);
5652 xmlUnlinkNode(delNode
);
5653 xmlFreeNode(delNode
);
5662 xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
5664 #ifdef WITH_XSLT_DEBUG_PARSING
5667 xmlNodePtr cur
, start
= NULL
;
5668 xsltStylesheetPtr style
;
5670 if ((cctxt
== NULL
) || (node
== NULL
) ||
5671 (node
->type
!= XML_ELEMENT_NODE
))
5674 style
= cctxt
->style
;
5676 * At this stage all import declarations of all stylesheet modules
5677 * with the same stylesheet level have been processed.
5678 * Now we can safely parse the rest of the declarations.
5680 if (IS_XSLT_ELEM_FAST(node
) && IS_XSLT_NAME(node
, "include"))
5682 xsltDocumentPtr include
;
5684 * URGENT TODO: Make this work with simplified stylesheets!
5685 * I.e., when we won't find an xsl:stylesheet element.
5688 * This is as include declaration.
5690 include
= ((xsltStyleItemIncludePtr
) node
->psvi
)->include
;
5691 if (include
== NULL
) {
5692 /* TODO: raise error? */
5696 * TODO: Actually an xsl:include should locate an embedded
5697 * stylesheet as well; so the document-element won't always
5698 * be the element where the actual stylesheet is rooted at.
5699 * But such embedded stylesheets are not supported by Libxslt yet.
5701 node
= xmlDocGetRootElement(include
->doc
);
5707 if (node
->children
== NULL
)
5710 * Push the xsl:stylesheet/xsl:transform element.
5712 xsltCompilerNodePush(cctxt
, node
);
5713 cctxt
->inode
->isRoot
= 1;
5714 cctxt
->inode
->nsChanged
= 0;
5716 * Start with the naked dummy info for literal result elements.
5718 cctxt
->inode
->litResElemInfo
= cctxt
->inodeList
->litResElemInfo
;
5721 * In every case, we need to have
5722 * the in-scope namespaces of the element, where the
5723 * stylesheet is rooted at, regardless if it's an XSLT
5724 * instruction or a literal result instruction (or if
5725 * this is an embedded stylesheet).
5727 cctxt
->inode
->inScopeNs
=
5728 xsltCompilerBuildInScopeNsList(cctxt
, node
);
5731 * Process attributes of xsl:stylesheet/xsl:transform.
5732 * --------------------------------------------------
5735 * extension-element-prefixes = tokens
5736 * exclude-result-prefixes = tokens
5737 * version = number (mandatory)
5739 if (xsltParseAttrXSLTVersion(cctxt
, node
,
5740 XSLT_ELEMENT_CATEGORY_XSLT
) == 0)
5743 * Attribute "version".
5744 * XSLT 1.0: "An xsl:stylesheet element *must* have a version
5745 * attribute, indicating the version of XSLT that the
5746 * stylesheet requires".
5747 * The root element of a simplified stylesheet must also have
5750 #ifdef XSLT_REFACTORED_MANDATORY_VERSION
5752 xsltTransformError(NULL
, cctxt
->style
, node
,
5753 "The attribute 'version' is missing.\n");
5754 cctxt
->style
->errors
++;
5756 /* OLD behaviour. */
5757 xsltTransformError(NULL
, cctxt
->style
, node
,
5758 "xsl:version is missing: document may not be a stylesheet\n");
5759 cctxt
->style
->warnings
++;
5763 * The namespaces declared by the attributes
5764 * "extension-element-prefixes" and
5765 * "exclude-result-prefixes" are local to *this*
5766 * stylesheet tree; i.e., they are *not* visible to
5767 * other stylesheet-modules, whether imported or included.
5769 * Attribute "extension-element-prefixes".
5771 cctxt
->inode
->extElemNs
=
5772 xsltParseExtElemPrefixes(cctxt
, node
, NULL
,
5773 XSLT_ELEMENT_CATEGORY_XSLT
);
5775 * Attribute "exclude-result-prefixes".
5777 cctxt
->inode
->exclResultNs
=
5778 xsltParseExclResultPrefixes(cctxt
, node
, NULL
,
5779 XSLT_ELEMENT_CATEGORY_XSLT
);
5781 * Create/reuse info for the literal result element.
5783 if (cctxt
->inode
->nsChanged
)
5784 xsltLREInfoCreate(cctxt
, node
, 0);
5786 * Processed top-level elements:
5787 * ----------------------------
5788 * xsl:variable, xsl:param (QName, in-scope ns,
5789 * expression (vars allowed))
5790 * xsl:attribute-set (QName, in-scope ns)
5791 * xsl:strip-space, xsl:preserve-space (XPath NameTests,
5793 * I *think* global scope, merge with includes
5794 * xsl:output (QName, in-scope ns)
5795 * xsl:key (QName, in-scope ns, pattern,
5796 * expression (vars *not* allowed))
5797 * xsl:decimal-format (QName, needs in-scope ns)
5798 * xsl:namespace-alias (in-scope ns)
5799 * global scope, merge with includes
5800 * xsl:template (last, QName, pattern)
5802 * (whitespace-only text-nodes have *not* been removed
5803 * yet; this will be done in xsltParseSequenceConstructor)
5805 * Report misplaced child-nodes first.
5807 cur
= node
->children
;
5808 while (cur
!= NULL
) {
5809 if (cur
->type
== XML_TEXT_NODE
) {
5810 xsltTransformError(NULL
, style
, cur
,
5811 "Misplaced text node (content: '%s').\n",
5812 (cur
->content
!= NULL
) ? cur
->content
: BAD_CAST
"");
5814 } else if (cur
->type
!= XML_ELEMENT_NODE
) {
5815 xsltTransformError(NULL
, style
, cur
, "Misplaced node.\n");
5821 * Skip xsl:import elements; they have been processed
5824 cur
= node
->children
;
5825 while ((cur
!= NULL
) && xsltParseFindTopLevelElem(cctxt
, cur
,
5826 BAD_CAST
"import", XSLT_NAMESPACE
, 1, &cur
) == 1)
5833 * Process all top-level xsl:param elements.
5835 while ((cur
!= NULL
) &&
5836 xsltParseFindTopLevelElem(cctxt
, cur
,
5837 BAD_CAST
"param", XSLT_NAMESPACE
, 0, &cur
) == 1)
5839 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_PARAM
);
5843 * Process all top-level xsl:variable elements.
5846 while ((cur
!= NULL
) &&
5847 xsltParseFindTopLevelElem(cctxt
, cur
,
5848 BAD_CAST
"variable", XSLT_NAMESPACE
, 0, &cur
) == 1)
5850 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_VARIABLE
);
5854 * Process all the rest of top-level elements.
5857 while (cur
!= NULL
) {
5859 * Process element nodes.
5861 if (cur
->type
== XML_ELEMENT_NODE
) {
5862 if (cur
->ns
== NULL
) {
5863 xsltTransformError(NULL
, style
, cur
,
5864 "Unexpected top-level element in no namespace.\n");
5870 * Process all XSLT elements.
5872 if (IS_XSLT_ELEM_FAST(cur
)) {
5874 * xsl:import is only allowed at the beginning.
5876 if (IS_XSLT_NAME(cur
, "import")) {
5877 xsltTransformError(NULL
, style
, cur
,
5878 "Misplaced xsl:import element.\n");
5884 * TODO: Change the return type of the parsing functions
5887 if (IS_XSLT_NAME(cur
, "template")) {
5888 #ifdef WITH_XSLT_DEBUG_PARSING
5892 * TODO: Is the position of xsl:template in the
5893 * tree significant? If not it would be easier to
5894 * parse them at a later stage.
5896 xsltParseXSLTTemplate(cctxt
, cur
);
5897 } else if (IS_XSLT_NAME(cur
, "variable")) {
5898 /* NOP; done already */
5899 } else if (IS_XSLT_NAME(cur
, "param")) {
5900 /* NOP; done already */
5901 } else if (IS_XSLT_NAME(cur
, "include")) {
5902 if (cur
->psvi
!= NULL
)
5903 xsltParseXSLTStylesheetElemCore(cctxt
, cur
);
5905 xsltTransformError(NULL
, style
, cur
,
5907 "(xsltParseXSLTStylesheetElemCore) "
5908 "The xsl:include element was not compiled.\n");
5911 } else if (IS_XSLT_NAME(cur
, "strip-space")) {
5912 /* No node info needed. */
5913 xsltParseStylesheetStripSpace(style
, cur
);
5914 } else if (IS_XSLT_NAME(cur
, "preserve-space")) {
5915 /* No node info needed. */
5916 xsltParseStylesheetPreserveSpace(style
, cur
);
5917 } else if (IS_XSLT_NAME(cur
, "output")) {
5918 /* No node-info needed. */
5919 xsltParseStylesheetOutput(style
, cur
);
5920 } else if (IS_XSLT_NAME(cur
, "key")) {
5921 /* TODO: node-info needed for expressions ? */
5922 xsltParseStylesheetKey(style
, cur
);
5923 } else if (IS_XSLT_NAME(cur
, "decimal-format")) {
5924 /* No node-info needed. */
5925 xsltParseStylesheetDecimalFormat(style
, cur
);
5926 } else if (IS_XSLT_NAME(cur
, "attribute-set")) {
5927 xsltParseTopLevelXSLTElem(cctxt
, cur
,
5929 } else if (IS_XSLT_NAME(cur
, "namespace-alias")) {
5930 /* NOP; done already */
5932 if (cctxt
->inode
->forwardsCompat
) {
5934 * Forwards-compatible mode:
5936 * XSLT-1: "if it is a top-level element and
5937 * XSLT 1.0 does not allow such elements as top-level
5938 * elements, then the element must be ignored along
5939 * with its content;"
5942 * TODO: I don't think we should generate a warning.
5944 xsltTransformError(NULL
, style
, cur
,
5945 "Forwards-compatible mode: Ignoring unknown XSLT "
5946 "element '%s'.\n", cur
->name
);
5949 xsltTransformError(NULL
, style
, cur
,
5950 "Unknown XSLT element '%s'.\n", cur
->name
);
5955 xsltTopLevelFunction function
;
5958 * Process non-XSLT elements, which are in a
5959 * non-NULL namespace.
5962 * QUESTION: What does xsltExtModuleTopLevelLookup()
5965 function
= xsltExtModuleTopLevelLookup(cur
->name
,
5967 if (function
!= NULL
)
5968 function(style
, cur
);
5969 #ifdef WITH_XSLT_DEBUG_PARSING
5970 xsltGenericDebug(xsltGenericDebugContext
,
5971 "xsltParseXSLTStylesheetElemCore : User-defined "
5972 "data element '%s'.\n", cur
->name
);
5981 #ifdef WITH_XSLT_DEBUG_PARSING
5982 xsltGenericDebug(xsltGenericDebugContext
,
5983 "### END of parsing top-level elements of doc '%s'.\n",
5985 xsltGenericDebug(xsltGenericDebugContext
,
5986 "### Templates: %d\n", templates
);
5987 #ifdef XSLT_REFACTORED
5988 xsltGenericDebug(xsltGenericDebugContext
,
5989 "### Max inodes: %d\n", cctxt
->maxNodeInfos
);
5990 xsltGenericDebug(xsltGenericDebugContext
,
5991 "### Max LREs : %d\n", cctxt
->maxLREs
);
5992 #endif /* XSLT_REFACTORED */
5993 #endif /* WITH_XSLT_DEBUG_PARSING */
5995 xsltCompilerNodePop(cctxt
, node
);
6000 * xsltParseXSLTStylesheet:
6001 * @cctxt: the compiler context
6002 * @node: the xsl:stylesheet/xsl:transform element-node
6004 * Parses the xsl:stylesheet and xsl:transform element.
6008 * extension-element-prefixes = tokens
6009 * exclude-result-prefixes = tokens
6011 * <!-- Content: (xsl:import*, top-level-elements) -->
6014 * BIG TODO: The xsl:include stuff.
6016 * Called by xsltParseStylesheetTree()
6018 * Returns 0 on success, a positive result on errors and
6019 * -1 on API or internal errors.
6022 xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
6024 xmlNodePtr cur
, start
;
6026 if ((cctxt
== NULL
) || (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
6029 if (node
->children
== NULL
)
6033 * Process top-level elements:
6034 * xsl:import (must be first)
6035 * xsl:include (this is just a pre-processing)
6037 cur
= node
->children
;
6039 * Process xsl:import elements.
6040 * XSLT 1.0: "The xsl:import element children must precede all
6041 * other element children of an xsl:stylesheet element,
6042 * including any xsl:include element children."
6044 while ((cur
!= NULL
) &&
6045 xsltParseFindTopLevelElem(cctxt
, cur
,
6046 BAD_CAST
"import", XSLT_NAMESPACE
, 1, &cur
) == 1)
6048 if (xsltParseStylesheetImport(cctxt
->style
, cur
) != 0) {
6049 cctxt
->style
->errors
++;
6057 * Pre-process all xsl:include elements.
6060 while ((cur
!= NULL
) &&
6061 xsltParseFindTopLevelElem(cctxt
, cur
,
6062 BAD_CAST
"include", XSLT_NAMESPACE
, 0, &cur
) == 1)
6064 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_INCLUDE
);
6068 * Pre-process all xsl:namespace-alias elements.
6069 * URGENT TODO: This won't work correctly: the order of included
6070 * aliases and aliases defined here is significant.
6073 while ((cur
!= NULL
) &&
6074 xsltParseFindTopLevelElem(cctxt
, cur
,
6075 BAD_CAST
"namespace-alias", XSLT_NAMESPACE
, 0, &cur
) == 1)
6077 xsltNamespaceAlias(cctxt
->style
, cur
);
6081 if (cctxt
->isInclude
) {
6083 * If this stylesheet is intended for inclusion, then
6084 * we will process only imports and includes.
6089 * Now parse the rest of the top-level elements.
6091 xsltParseXSLTStylesheetElemCore(cctxt
, node
);
6097 #else /* XSLT_REFACTORED */
6100 * xsltParseStylesheetTop:
6101 * @style: the XSLT stylesheet
6102 * @top: the top level "stylesheet" or "transform" element
6104 * scan the top level elements of an XSL stylesheet
6107 xsltParseStylesheetTop(xsltStylesheetPtr style
, xmlNodePtr top
) {
6110 #ifdef WITH_XSLT_DEBUG_PARSING
6114 if ((top
== NULL
) || (top
->type
!= XML_ELEMENT_NODE
))
6117 prop
= xmlGetNsProp(top
, (const xmlChar
*)"version", NULL
);
6119 xsltTransformError(NULL
, style
, top
,
6120 "xsl:version is missing: document may not be a stylesheet\n");
6121 if (style
!= NULL
) style
->warnings
++;
6123 if ((!xmlStrEqual(prop
, (const xmlChar
*)"1.0")) &&
6124 (!xmlStrEqual(prop
, (const xmlChar
*)"1.1"))) {
6125 xsltTransformError(NULL
, style
, top
,
6126 "xsl:version: only 1.1 features are supported\n");
6127 if (style
!= NULL
) {
6128 style
->forwards_compatible
= 1;
6136 * process xsl:import elements
6138 cur
= top
->children
;
6139 while (cur
!= NULL
) {
6140 if (IS_BLANK_NODE(cur
)) {
6144 if (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "import")) {
6145 if (xsltParseStylesheetImport(style
, cur
) != 0)
6146 if (style
!= NULL
) style
->errors
++;
6153 * process other top-level elements
6155 while (cur
!= NULL
) {
6156 if (IS_BLANK_NODE(cur
)) {
6160 if (cur
->type
== XML_TEXT_NODE
) {
6161 if (cur
->content
!= NULL
) {
6162 xsltTransformError(NULL
, style
, cur
,
6163 "misplaced text node: '%s'\n", cur
->content
);
6165 if (style
!= NULL
) style
->errors
++;
6169 if ((cur
->type
== XML_ELEMENT_NODE
) && (cur
->ns
== NULL
)) {
6170 xsltGenericError(xsltGenericErrorContext
,
6171 "Found a top-level element %s with null namespace URI\n",
6173 if (style
!= NULL
) style
->errors
++;
6177 if ((cur
->type
== XML_ELEMENT_NODE
) && (!(IS_XSLT_ELEM(cur
)))) {
6178 xsltTopLevelFunction function
;
6180 function
= xsltExtModuleTopLevelLookup(cur
->name
,
6182 if (function
!= NULL
)
6183 function(style
, cur
);
6185 #ifdef WITH_XSLT_DEBUG_PARSING
6186 xsltGenericDebug(xsltGenericDebugContext
,
6187 "xsltParseStylesheetTop : found foreign element %s\n",
6193 if (IS_XSLT_NAME(cur
, "import")) {
6194 xsltTransformError(NULL
, style
, cur
,
6195 "xsltParseStylesheetTop: ignoring misplaced import element\n");
6196 if (style
!= NULL
) style
->errors
++;
6197 } else if (IS_XSLT_NAME(cur
, "include")) {
6198 if (xsltParseStylesheetInclude(style
, cur
) != 0)
6199 if (style
!= NULL
) style
->errors
++;
6200 } else if (IS_XSLT_NAME(cur
, "strip-space")) {
6201 xsltParseStylesheetStripSpace(style
, cur
);
6202 } else if (IS_XSLT_NAME(cur
, "preserve-space")) {
6203 xsltParseStylesheetPreserveSpace(style
, cur
);
6204 } else if (IS_XSLT_NAME(cur
, "output")) {
6205 xsltParseStylesheetOutput(style
, cur
);
6206 } else if (IS_XSLT_NAME(cur
, "key")) {
6207 xsltParseStylesheetKey(style
, cur
);
6208 } else if (IS_XSLT_NAME(cur
, "decimal-format")) {
6209 xsltParseStylesheetDecimalFormat(style
, cur
);
6210 } else if (IS_XSLT_NAME(cur
, "attribute-set")) {
6211 xsltParseStylesheetAttributeSet(style
, cur
);
6212 } else if (IS_XSLT_NAME(cur
, "variable")) {
6213 xsltParseGlobalVariable(style
, cur
);
6214 } else if (IS_XSLT_NAME(cur
, "param")) {
6215 xsltParseGlobalParam(style
, cur
);
6216 } else if (IS_XSLT_NAME(cur
, "template")) {
6217 #ifdef WITH_XSLT_DEBUG_PARSING
6220 xsltParseStylesheetTemplate(style
, cur
);
6221 } else if (IS_XSLT_NAME(cur
, "namespace-alias")) {
6222 xsltNamespaceAlias(style
, cur
);
6224 if ((style
!= NULL
) && (style
->forwards_compatible
== 0)) {
6225 xsltTransformError(NULL
, style
, cur
,
6226 "xsltParseStylesheetTop: unknown %s element\n",
6228 if (style
!= NULL
) style
->errors
++;
6233 #ifdef WITH_XSLT_DEBUG_PARSING
6234 xsltGenericDebug(xsltGenericDebugContext
,
6235 "parsed %d templates\n", templates
);
6239 #endif /* else of XSLT_REFACTORED */
6241 #ifdef XSLT_REFACTORED
6243 * xsltParseSimplifiedStylesheetTree:
6245 * @style: the stylesheet (TODO: Change this to the compiler context)
6246 * @doc: the document containing the stylesheet.
6247 * @node: the node where the stylesheet is rooted at
6249 * Returns 0 in case of success, a positive result if an error occurred
6250 * and -1 on API and internal errors.
6253 xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt
,
6257 xsltTemplatePtr templ
;
6259 if ((cctxt
== NULL
) || (node
== NULL
))
6262 if (xsltParseAttrXSLTVersion(cctxt
, node
, 0) == XSLT_ELEMENT_CATEGORY_LRE
)
6265 * TODO: Adjust report, since this might be an
6266 * embedded stylesheet.
6268 xsltTransformError(NULL
, cctxt
->style
, node
,
6269 "The attribute 'xsl:version' is missing; cannot identify "
6270 "this document as an XSLT stylesheet document.\n");
6271 cctxt
->style
->errors
++;
6275 #ifdef WITH_XSLT_DEBUG_PARSING
6276 xsltGenericDebug(xsltGenericDebugContext
,
6277 "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
6281 * Create and link the template
6283 templ
= xsltNewTemplate();
6284 if (templ
== NULL
) {
6287 templ
->next
= cctxt
->style
->templates
;
6288 cctxt
->style
->templates
= templ
;
6289 templ
->match
= xmlStrdup(BAD_CAST
"/");
6292 * Note that we push the document-node in this special case.
6294 xsltCompilerNodePush(cctxt
, (xmlNodePtr
) doc
);
6296 * In every case, we need to have
6297 * the in-scope namespaces of the element, where the
6298 * stylesheet is rooted at, regardless if it's an XSLT
6299 * instruction or a literal result instruction (or if
6300 * this is an embedded stylesheet).
6302 cctxt
->inode
->inScopeNs
=
6303 xsltCompilerBuildInScopeNsList(cctxt
, node
);
6305 * Parse the content and register the match-pattern.
6307 xsltParseSequenceConstructor(cctxt
, node
);
6308 xsltCompilerNodePop(cctxt
, (xmlNodePtr
) doc
);
6310 templ
->elem
= (xmlNodePtr
) doc
;
6311 templ
->content
= node
;
6312 xsltAddTemplate(cctxt
->style
, templ
, NULL
, NULL
);
6313 cctxt
->style
->literal_result
= 1;
6317 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6319 * xsltRestoreDocumentNamespaces:
6320 * @ns: map of namespaces
6321 * @doc: the document
6323 * Restore the namespaces for the document
6325 * Returns 0 in case of success, -1 in case of failure
6328 xsltRestoreDocumentNamespaces(xsltNsMapPtr ns
, xmlDocPtr doc
)
6333 * Revert the changes we have applied to the namespace-URIs of
6336 while (ns
!= NULL
) {
6337 if ((ns
->doc
== doc
) && (ns
->ns
!= NULL
)) {
6338 ns
->ns
->href
= ns
->origNsName
;
6339 ns
->origNsName
= NULL
;
6346 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
6349 * xsltParseStylesheetProcess:
6350 * @style: the XSLT stylesheet (the current stylesheet-level)
6351 * @doc: and xmlDoc parsed XML
6353 * Parses an XSLT stylesheet, adding the associated structures.
6355 * xsltParseStylesheetImportedDoc() (xslt.c)
6356 * xsltParseStylesheetInclude() (imports.c)
6358 * Returns the value of the @style parameter if everything
6359 * went right, NULL if something went amiss.
6362 xsltParseStylesheetProcess(xsltStylesheetPtr style
, xmlDocPtr doc
)
6364 xsltCompilerCtxtPtr cctxt
;
6366 int oldIsSimplifiedStylesheet
;
6370 if ((style
== NULL
) || (doc
== NULL
))
6373 cctxt
= XSLT_CCTXT(style
);
6375 cur
= xmlDocGetRootElement(doc
);
6377 xsltTransformError(NULL
, style
, (xmlNodePtr
) doc
,
6378 "xsltParseStylesheetProcess : empty stylesheet\n");
6381 oldIsSimplifiedStylesheet
= cctxt
->simplified
;
6383 if ((IS_XSLT_ELEM(cur
)) &&
6384 ((IS_XSLT_NAME(cur
, "stylesheet")) ||
6385 (IS_XSLT_NAME(cur
, "transform")))) {
6386 #ifdef WITH_XSLT_DEBUG_PARSING
6387 xsltGenericDebug(xsltGenericDebugContext
,
6388 "xsltParseStylesheetProcess : found stylesheet\n");
6390 cctxt
->simplified
= 0;
6391 style
->literal_result
= 0;
6393 cctxt
->simplified
= 1;
6394 style
->literal_result
= 1;
6397 * Pre-process the stylesheet if not already done before.
6398 * This will remove PIs and comments, merge adjacent
6399 * text nodes, internalize strings, etc.
6401 if (! style
->nopreproc
)
6402 xsltParsePreprocessStylesheetTree(cctxt
, cur
);
6404 * Parse and compile the stylesheet.
6406 if (style
->literal_result
== 0) {
6407 if (xsltParseXSLTStylesheetElem(cctxt
, cur
) != 0)
6410 if (xsltParseSimplifiedStylesheetTree(cctxt
, doc
, cur
) != 0)
6414 cctxt
->simplified
= oldIsSimplifiedStylesheet
;
6419 #else /* XSLT_REFACTORED */
6422 * xsltParseStylesheetProcess:
6423 * @ret: the XSLT stylesheet (the current stylesheet-level)
6424 * @doc: and xmlDoc parsed XML
6426 * Parses an XSLT stylesheet, adding the associated structures.
6428 * xsltParseStylesheetImportedDoc() (xslt.c)
6429 * xsltParseStylesheetInclude() (imports.c)
6431 * Returns the value of the @style parameter if everything
6432 * went right, NULL if something went amiss.
6435 xsltParseStylesheetProcess(xsltStylesheetPtr ret
, xmlDocPtr doc
) {
6446 * First steps, remove blank nodes,
6447 * locate the xsl:stylesheet element and the
6448 * namespace declaration.
6450 cur
= xmlDocGetRootElement(doc
);
6452 xsltTransformError(NULL
, ret
, (xmlNodePtr
) doc
,
6453 "xsltParseStylesheetProcess : empty stylesheet\n");
6457 if ((IS_XSLT_ELEM(cur
)) &&
6458 ((IS_XSLT_NAME(cur
, "stylesheet")) ||
6459 (IS_XSLT_NAME(cur
, "transform")))) {
6460 #ifdef WITH_XSLT_DEBUG_PARSING
6461 xsltGenericDebug(xsltGenericDebugContext
,
6462 "xsltParseStylesheetProcess : found stylesheet\n");
6464 ret
->literal_result
= 0;
6465 xsltParseStylesheetExcludePrefix(ret
, cur
, 1);
6466 xsltParseStylesheetExtPrefix(ret
, cur
, 1);
6468 xsltParseStylesheetExcludePrefix(ret
, cur
, 0);
6469 xsltParseStylesheetExtPrefix(ret
, cur
, 0);
6470 ret
->literal_result
= 1;
6472 if (!ret
->nopreproc
) {
6473 xsltPreprocessStylesheet(ret
, cur
);
6475 if (ret
->literal_result
== 0) {
6476 xsltParseStylesheetTop(ret
, cur
);
6479 xsltTemplatePtr
template;
6482 * the document itself might be the template, check xsl:version
6484 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"version", XSLT_NAMESPACE
);
6486 xsltTransformError(NULL
, ret
, cur
,
6487 "xsltParseStylesheetProcess : document is not a stylesheet\n");
6491 #ifdef WITH_XSLT_DEBUG_PARSING
6492 xsltGenericDebug(xsltGenericDebugContext
,
6493 "xsltParseStylesheetProcess : document is stylesheet\n");
6496 if ((!xmlStrEqual(prop
, (const xmlChar
*)"1.0")) &&
6497 (!xmlStrEqual(prop
, (const xmlChar
*)"1.1"))) {
6498 xsltTransformError(NULL
, ret
, cur
,
6499 "xsl:version: only 1.1 features are supported\n");
6500 ret
->forwards_compatible
= 1;
6506 * Create and link the template
6508 template = xsltNewTemplate();
6509 if (template == NULL
) {
6512 template->next
= ret
->templates
;
6513 ret
->templates
= template;
6514 template->match
= xmlStrdup((const xmlChar
*)"/");
6517 * parse the content and register the pattern
6519 xsltParseTemplateContent(ret
, (xmlNodePtr
) doc
);
6520 template->elem
= (xmlNodePtr
) doc
;
6521 template->content
= doc
->children
;
6522 xsltAddTemplate(ret
, template, NULL
, NULL
);
6523 ret
->literal_result
= 1;
6529 #endif /* else of XSLT_REFACTORED */
6532 * xsltParseStylesheetImportedDoc:
6533 * @doc: an xmlDoc parsed XML
6534 * @parentStyle: pointer to the parent stylesheet (if it exists)
6536 * parse an XSLT stylesheet building the associated structures
6537 * except the processing not needed for imported documents.
6539 * Returns a new XSLT stylesheet structure.
6543 xsltParseStylesheetImportedDoc(xmlDocPtr doc
,
6544 xsltStylesheetPtr parentStyle
) {
6545 xsltStylesheetPtr retStyle
;
6550 retStyle
= xsltNewStylesheetInternal(parentStyle
);
6551 if (retStyle
== NULL
)
6554 if (xsltParseStylesheetUser(retStyle
, doc
) != 0) {
6555 xsltFreeStylesheet(retStyle
);
6563 * xsltParseStylesheetUser:
6564 * @style: pointer to the stylesheet
6565 * @doc: an xmlDoc parsed XML
6567 * Parse an XSLT stylesheet with a user-provided stylesheet struct.
6569 * Returns 0 if successful, -1 in case of error.
6572 xsltParseStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
) {
6573 if ((style
== NULL
) || (doc
== NULL
))
6577 * Adjust the string dict.
6579 if (doc
->dict
!= NULL
) {
6580 xmlDictFree(style
->dict
);
6581 style
->dict
= doc
->dict
;
6582 #ifdef WITH_XSLT_DEBUG
6583 xsltGenericDebug(xsltGenericDebugContext
,
6584 "reusing dictionary from %s for stylesheet\n",
6587 xmlDictReference(style
->dict
);
6591 * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
6592 * the stylesheet to containt distinct namespace prefixes.
6594 xsltGatherNamespaces(style
);
6596 #ifdef XSLT_REFACTORED
6598 xsltCompilerCtxtPtr cctxt
;
6599 xsltStylesheetPtr oldCurSheet
;
6601 if (style
->parent
== NULL
) {
6602 xsltPrincipalStylesheetDataPtr principalData
;
6604 * Create extra data for the principal stylesheet.
6606 principalData
= xsltNewPrincipalStylesheetData();
6607 if (principalData
== NULL
) {
6610 style
->principalData
= principalData
;
6612 * Create the compilation context
6613 * ------------------------------
6614 * (only once; for the principal stylesheet).
6615 * This is currently the only function where the
6616 * compilation context is created.
6618 cctxt
= xsltCompilationCtxtCreate(style
);
6619 if (cctxt
== NULL
) {
6622 style
->compCtxt
= (void *) cctxt
;
6623 cctxt
->style
= style
;
6624 cctxt
->dict
= style
->dict
;
6625 cctxt
->psData
= principalData
;
6627 * Push initial dummy node info.
6630 xsltCompilerNodePush(cctxt
, (xmlNodePtr
) doc
);
6633 * Imported stylesheet.
6635 cctxt
= style
->parent
->compCtxt
;
6636 style
->compCtxt
= cctxt
;
6639 * Save the old and set the current stylesheet structure in the
6640 * compilation context.
6642 oldCurSheet
= cctxt
->style
;
6643 cctxt
->style
= style
;
6646 xsltParseStylesheetProcess(style
, doc
);
6648 cctxt
->style
= oldCurSheet
;
6649 if (style
->parent
== NULL
) {
6651 * Pop the initial dummy node info.
6653 xsltCompilerNodePop(cctxt
, (xmlNodePtr
) doc
);
6656 * Clear the compilation context of imported
6660 /* style->compCtxt = NULL; */
6663 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6664 if (style
->errors
!= 0) {
6666 * Restore all changes made to namespace URIs of ns-decls.
6668 if (cctxt
->psData
->nsMap
)
6669 xsltRestoreDocumentNamespaces(cctxt
->psData
->nsMap
, doc
);
6673 if (style
->parent
== NULL
) {
6674 xsltCompilationCtxtFree(style
->compCtxt
);
6675 style
->compCtxt
= NULL
;
6679 #else /* XSLT_REFACTORED */
6684 if (xsltParseStylesheetProcess(style
, doc
) == NULL
) {
6688 #endif /* else of XSLT_REFACTORED */
6690 if (style
->errors
!= 0) {
6692 * Detach the doc from the stylesheet; otherwise the doc
6693 * will be freed in xsltFreeStylesheet().
6697 * Cleanup the doc if its the main stylesheet.
6699 if (style
->parent
== NULL
)
6700 xsltCleanupStylesheetTree(doc
, xmlDocGetRootElement(doc
));
6704 if (style
->parent
== NULL
)
6705 xsltResolveStylesheetAttributeSet(style
);
6711 * xsltParseStylesheetDoc:
6712 * @doc: and xmlDoc parsed XML
6714 * parse an XSLT stylesheet, building the associated structures. doc
6715 * is kept as a reference within the returned stylesheet, so changes
6716 * to doc after the parsing will be reflected when the stylesheet
6717 * is applied, and the doc is automatically freed when the
6718 * stylesheet is closed.
6720 * Returns a new XSLT stylesheet structure.
6724 xsltParseStylesheetDoc(xmlDocPtr doc
) {
6727 return(xsltParseStylesheetImportedDoc(doc
, NULL
));
6731 * xsltParseStylesheetFile:
6732 * @filename: the filename/URL to the stylesheet
6734 * Load and parse an XSLT stylesheet
6736 * Returns a new XSLT stylesheet structure.
6740 xsltParseStylesheetFile(const xmlChar
* filename
) {
6741 xsltSecurityPrefsPtr sec
;
6742 xsltStylesheetPtr ret
;
6747 if (filename
== NULL
)
6750 #ifdef WITH_XSLT_DEBUG_PARSING
6751 xsltGenericDebug(xsltGenericDebugContext
,
6752 "xsltParseStylesheetFile : parse %s\n", filename
);
6756 * Security framework check
6758 sec
= xsltGetDefaultSecurityPrefs();
6762 res
= xsltCheckRead(sec
, NULL
, filename
);
6765 xsltTransformError(NULL
, NULL
, NULL
,
6766 "xsltParseStylesheetFile: read rights for %s denied\n",
6772 doc
= xsltDocDefaultLoader(filename
, NULL
, XSLT_PARSE_OPTIONS
,
6773 NULL
, XSLT_LOAD_START
);
6775 xsltTransformError(NULL
, NULL
, NULL
,
6776 "xsltParseStylesheetFile : cannot parse %s\n", filename
);
6779 ret
= xsltParseStylesheetDoc(doc
);
6788 /************************************************************************
6790 * Handling of Stylesheet PI *
6792 ************************************************************************/
6795 #define SKIP(val) cur += (val)
6796 #define NXT(val) cur[(val)]
6797 #define SKIP_BLANKS \
6798 while (IS_BLANK(CUR)) NEXT
6799 #define NEXT ((*cur) ? cur++ : cur)
6802 * xsltParseStylesheetPI:
6803 * @value: the value of the PI
6805 * This function checks that the type is text/xml and extracts
6806 * the URI-Reference for the stylesheet
6808 * Returns the URI-Reference for the stylesheet or NULL (it need to
6809 * be freed by the caller)
6812 xsltParseStylesheetPI(const xmlChar
*value
) {
6814 const xmlChar
*start
;
6817 xmlChar
*href
= NULL
;
6826 if ((CUR
== 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
6833 if ((CUR
!= '\'') && (CUR
!= '"'))
6838 while ((CUR
!= 0) && (CUR
!= tmp
))
6842 val
= xmlStrndup(start
, cur
- start
);
6846 if ((xmlStrcasecmp(val
, BAD_CAST
"text/xml")) &&
6847 (xmlStrcasecmp(val
, BAD_CAST
"text/xsl"))) {
6853 } else if ((CUR
== 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
6860 if ((CUR
!= '\'') && (CUR
!= '"'))
6865 while ((CUR
!= 0) && (CUR
!= tmp
))
6870 href
= xmlStrndup(start
, cur
- start
);
6873 while ((CUR
!= 0) && (!IS_BLANK(CUR
)))
6888 * xsltLoadStylesheetPI:
6889 * @doc: a document to process
6891 * This function tries to locate the stylesheet PI in the given document
6892 * If found, and if contained within the document, it will extract
6893 * that subtree to build the stylesheet to process @doc (doc itself will
6894 * be modified). If found but referencing an external document it will
6895 * attempt to load it and generate a stylesheet from it. In both cases,
6896 * the resulting stylesheet and the document need to be freed once the
6897 * transformation is done.
6899 * Returns a new XSLT stylesheet structure or NULL if not found.
6902 xsltLoadStylesheetPI(xmlDocPtr doc
) {
6904 xsltStylesheetPtr ret
= NULL
;
6905 xmlChar
*href
= NULL
;
6914 * Find the text/xml stylesheet PI id any before the root
6916 child
= doc
->children
;
6917 while ((child
!= NULL
) && (child
->type
!= XML_ELEMENT_NODE
)) {
6918 if ((child
->type
== XML_PI_NODE
) &&
6919 (xmlStrEqual(child
->name
, BAD_CAST
"xml-stylesheet"))) {
6920 href
= xsltParseStylesheetPI(child
->content
);
6924 child
= child
->next
;
6928 * If found check the href to select processing
6931 #ifdef WITH_XSLT_DEBUG_PARSING
6932 xsltGenericDebug(xsltGenericDebugContext
,
6933 "xsltLoadStylesheetPI : found PI href=%s\n", href
);
6935 URI
= xmlParseURI((const char *) href
);
6937 xsltTransformError(NULL
, NULL
, child
,
6938 "xml-stylesheet : href %s is not valid\n", href
);
6942 if ((URI
->fragment
!= NULL
) && (URI
->scheme
== NULL
) &&
6943 (URI
->opaque
== NULL
) && (URI
->authority
== NULL
) &&
6944 (URI
->server
== NULL
) && (URI
->user
== NULL
) &&
6945 (URI
->path
== NULL
) && (URI
->query
== NULL
)) {
6948 #ifdef WITH_XSLT_DEBUG_PARSING
6949 xsltGenericDebug(xsltGenericDebugContext
,
6950 "xsltLoadStylesheetPI : Reference to ID %s\n", href
);
6952 if (URI
->fragment
[0] == '#')
6953 ID
= xmlGetID(doc
, (const xmlChar
*) &(URI
->fragment
[1]));
6955 ID
= xmlGetID(doc
, (const xmlChar
*) URI
->fragment
);
6957 xsltTransformError(NULL
, NULL
, child
,
6958 "xml-stylesheet : no ID %s found\n", URI
->fragment
);
6961 xmlNodePtr subtree
, newtree
;
6964 #ifdef WITH_XSLT_DEBUG
6965 xsltGenericDebug(xsltGenericDebugContext
,
6966 "creating new document from %s for embedded stylesheet\n",
6970 * move the subtree in a new document passed to
6971 * the stylesheet analyzer
6973 subtree
= ID
->parent
;
6974 fake
= xmlNewDoc(NULL
);
6977 * Should the dictionary still be shared even though
6978 * the nodes are being copied rather than moved?
6980 fake
->dict
= doc
->dict
;
6981 xmlDictReference(doc
->dict
);
6982 #ifdef WITH_XSLT_DEBUG
6983 xsltGenericDebug(xsltGenericDebugContext
,
6984 "reusing dictionary from %s for embedded stylesheet\n",
6988 newtree
= xmlDocCopyNode(subtree
, fake
, 1);
6990 fake
->URL
= xmlNodeGetBase(doc
, subtree
->parent
);
6991 #ifdef WITH_XSLT_DEBUG
6992 xsltGenericDebug(xsltGenericDebugContext
,
6993 "set base URI for embedded stylesheet as %s\n",
6998 * Add all namespaces in scope of embedded stylesheet to
6999 * root element of newly created stylesheet document
7001 while ((subtree
= subtree
->parent
) != (xmlNodePtr
)doc
) {
7002 for (ns
= subtree
->ns
; ns
; ns
= ns
->next
) {
7003 xmlNewNs(newtree
, ns
->href
, ns
->prefix
);
7007 xmlAddChild((xmlNodePtr
)fake
, newtree
);
7008 ret
= xsltParseStylesheetDoc(fake
);
7014 xmlChar
*URL
, *base
;
7017 * Reference to an external stylesheet
7020 base
= xmlNodeGetBase(doc
, (xmlNodePtr
) doc
);
7021 URL
= xmlBuildURI(href
, base
);
7023 #ifdef WITH_XSLT_DEBUG_PARSING
7024 xsltGenericDebug(xsltGenericDebugContext
,
7025 "xsltLoadStylesheetPI : fetching %s\n", URL
);
7027 ret
= xsltParseStylesheetFile(URL
);
7030 #ifdef WITH_XSLT_DEBUG_PARSING
7031 xsltGenericDebug(xsltGenericDebugContext
,
7032 "xsltLoadStylesheetPI : fetching %s\n", href
);
7034 ret
= xsltParseStylesheetFile(href
);