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
;
102 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
108 #define IS_BLANK_NODE(n) \
109 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
112 * xsltParseContentError:
114 * @style: the stylesheet
115 * @node: the node where the error occured
117 * Compile-time error function.
120 xsltParseContentError(xsltStylesheetPtr style
,
123 if ((style
== NULL
) || (node
== NULL
))
126 if (IS_XSLT_ELEM(node
))
127 xsltTransformError(NULL
, style
, node
,
128 "The XSLT-element '%s' is not allowed at this position.\n",
131 xsltTransformError(NULL
, style
, node
,
132 "The element '%s' is not allowed at this position.\n",
137 #ifdef XSLT_REFACTORED
141 * @style: the transformation stylesheet
142 * @value: the excluded namespace name to push on the stack
144 * Push an excluded namespace name on the stack
146 * Returns the new index in the stack or -1 if already present or
150 exclPrefixPush(xsltStylesheetPtr style
, xmlChar
* value
)
154 /* do not push duplicates */
155 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
156 if (xmlStrEqual(style
->exclPrefixTab
[i
], value
))
159 if (style
->exclPrefixNr
>= style
->exclPrefixMax
) {
161 size_t max
= style
->exclPrefixMax
? style
->exclPrefixMax
* 2 : 4;
163 tmp
= xmlRealloc(style
->exclPrefixTab
,
164 max
* sizeof(style
->exclPrefixTab
[0]));
166 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
169 style
->exclPrefixTab
= tmp
;
170 style
->exclPrefixMax
= max
;
172 style
->exclPrefixTab
[style
->exclPrefixNr
] = value
;
173 style
->exclPrefix
= value
;
174 return (style
->exclPrefixNr
++);
178 * @style: the transformation stylesheet
180 * Pop an excluded prefix value from the stack
182 * Returns the stored excluded prefix value
185 exclPrefixPop(xsltStylesheetPtr style
)
189 if (style
->exclPrefixNr
<= 0)
191 style
->exclPrefixNr
--;
192 if (style
->exclPrefixNr
> 0)
193 style
->exclPrefix
= style
->exclPrefixTab
[style
->exclPrefixNr
- 1];
195 style
->exclPrefix
= NULL
;
196 ret
= style
->exclPrefixTab
[style
->exclPrefixNr
];
197 style
->exclPrefixTab
[style
->exclPrefixNr
] = 0;
202 /************************************************************************
206 ************************************************************************/
208 static int initialized
= 0;
212 * Initializes the processor (e.g. registers built-in extensions,
217 if (initialized
== 0) {
219 #ifdef XSLT_LOCALE_WINAPI
220 xsltLocaleMutex
= xmlNewRMutex();
222 xsltRegisterAllExtras();
229 * Uninitializes the processor.
233 #ifdef XSLT_LOCALE_WINAPI
234 xmlFreeRMutex(xsltLocaleMutex
);
235 xsltLocaleMutex
= NULL
;
244 * Check if a string is ignorable
246 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
249 xsltIsBlank(xmlChar
*str
) {
253 if (!(IS_BLANK(*str
))) return(0);
259 /************************************************************************
261 * Routines to handle XSLT data structures *
263 ************************************************************************/
264 static xsltDecimalFormatPtr
265 xsltNewDecimalFormat(const xmlChar
*nsUri
, xmlChar
*name
)
267 xsltDecimalFormatPtr self
;
268 /* UTF-8 for 0x2030 */
269 static const xmlChar permille
[4] = {0xe2, 0x80, 0xb0, 0};
271 self
= xmlMalloc(sizeof(xsltDecimalFormat
));
278 self
->digit
= xmlStrdup(BAD_CAST("#"));
279 self
->patternSeparator
= xmlStrdup(BAD_CAST(";"));
280 self
->decimalPoint
= xmlStrdup(BAD_CAST("."));
281 self
->grouping
= xmlStrdup(BAD_CAST(","));
282 self
->percent
= xmlStrdup(BAD_CAST("%"));
283 self
->permille
= xmlStrdup(BAD_CAST(permille
));
284 self
->zeroDigit
= xmlStrdup(BAD_CAST("0"));
285 self
->minusSign
= xmlStrdup(BAD_CAST("-"));
286 self
->infinity
= xmlStrdup(BAD_CAST("Infinity"));
287 self
->noNumber
= xmlStrdup(BAD_CAST("NaN"));
293 xsltFreeDecimalFormat(xsltDecimalFormatPtr self
)
297 xmlFree(self
->digit
);
298 if (self
->patternSeparator
)
299 xmlFree(self
->patternSeparator
);
300 if (self
->decimalPoint
)
301 xmlFree(self
->decimalPoint
);
303 xmlFree(self
->grouping
);
305 xmlFree(self
->percent
);
307 xmlFree(self
->permille
);
309 xmlFree(self
->zeroDigit
);
311 xmlFree(self
->minusSign
);
313 xmlFree(self
->infinity
);
315 xmlFree(self
->noNumber
);
323 xsltFreeDecimalFormatList(xsltStylesheetPtr self
)
325 xsltDecimalFormatPtr iter
;
326 xsltDecimalFormatPtr tmp
;
331 iter
= self
->decimalFormat
;
332 while (iter
!= NULL
) {
334 xsltFreeDecimalFormat(iter
);
340 * xsltDecimalFormatGetByName:
341 * @style: the XSLT stylesheet
342 * @name: the decimal-format name to find
344 * Find decimal-format by name
346 * Returns the xsltDecimalFormatPtr
349 xsltDecimalFormatGetByName(xsltStylesheetPtr style
, xmlChar
*name
)
351 xsltDecimalFormatPtr result
= NULL
;
354 return style
->decimalFormat
;
356 while (style
!= NULL
) {
357 for (result
= style
->decimalFormat
->next
;
359 result
= result
->next
) {
360 if ((result
->nsUri
== NULL
) && xmlStrEqual(name
, result
->name
))
363 style
= xsltNextImport(style
);
369 * xsltDecimalFormatGetByQName:
370 * @style: the XSLT stylesheet
371 * @nsUri: the namespace URI of the QName
372 * @name: the local part of the QName
374 * Find decimal-format by QName
376 * Returns the xsltDecimalFormatPtr
379 xsltDecimalFormatGetByQName(xsltStylesheetPtr style
, const xmlChar
*nsUri
,
382 xsltDecimalFormatPtr result
= NULL
;
385 return style
->decimalFormat
;
387 while (style
!= NULL
) {
388 for (result
= style
->decimalFormat
->next
;
390 result
= result
->next
) {
391 if (xmlStrEqual(nsUri
, result
->nsUri
) &&
392 xmlStrEqual(name
, result
->name
))
395 style
= xsltNextImport(style
);
404 * Create a new XSLT Template
406 * Returns the newly allocated xsltTemplatePtr or NULL in case of error
408 static xsltTemplatePtr
409 xsltNewTemplate(void) {
412 cur
= (xsltTemplatePtr
) xmlMalloc(sizeof(xsltTemplate
));
414 xsltTransformError(NULL
, NULL
, NULL
,
415 "xsltNewTemplate : malloc failed\n");
418 memset(cur
, 0, sizeof(xsltTemplate
));
419 cur
->priority
= XSLT_PAT_NO_PRIORITY
;
425 * @template: an XSLT template
427 * Free up the memory allocated by @template
430 xsltFreeTemplate(xsltTemplatePtr
template) {
431 if (template == NULL
)
433 if (template->match
) xmlFree(template->match
);
435 * NOTE: @name and @nameURI are put into the string dict now.
436 * if (template->name) xmlFree(template->name);
437 * if (template->nameURI) xmlFree(template->nameURI);
440 if (template->mode) xmlFree(template->mode);
441 if (template->modeURI) xmlFree(template->modeURI);
443 if (template->inheritedNs
) xmlFree(template->inheritedNs
);
445 /* free profiling data */
446 if (template->templCalledTab
) xmlFree(template->templCalledTab
);
447 if (template->templCountTab
) xmlFree(template->templCountTab
);
449 memset(template, -1, sizeof(xsltTemplate
));
454 * xsltFreeTemplateList:
455 * @template: an XSLT template list
457 * Free up the memory allocated by all the elements of @template
460 xsltFreeTemplateList(xsltTemplatePtr
template) {
463 while (template != NULL
) {
465 template = template->next
;
466 xsltFreeTemplate(cur
);
470 #ifdef XSLT_REFACTORED
473 xsltFreeNsAliasList(xsltNsAliasPtr item
)
485 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
487 xsltFreeNamespaceMap(xsltNsMapPtr item
)
500 xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt
,
507 if ((cctxt
== NULL
) || (doc
== NULL
) || (ns
== NULL
))
510 ret
= (xsltNsMapPtr
) xmlMalloc(sizeof(xsltNsMap
));
512 xsltTransformError(NULL
, cctxt
->style
, elem
,
513 "Internal error: (xsltNewNamespaceMapItem) "
514 "memory allocation failed.\n");
517 memset(ret
, 0, sizeof(xsltNsMap
));
520 ret
->origNsName
= ns
->href
;
522 * Store the item at current stylesheet-level.
524 if (cctxt
->psData
->nsMap
!= NULL
)
525 ret
->next
= cctxt
->psData
->nsMap
;
526 cctxt
->psData
->nsMap
= ret
;
530 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
533 * xsltCompilerVarInfoFree:
534 * @cctxt: the compilation context
536 * Frees the list of information for vars/params.
539 xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt
)
541 xsltVarInfoPtr ivar
= cctxt
->ivars
, ivartmp
;
551 * xsltCompilerCtxtFree:
553 * Free an XSLT compiler context.
556 xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt
)
560 #ifdef WITH_XSLT_DEBUG_PARSING
561 xsltGenericDebug(xsltGenericDebugContext
,
562 "Freeing compilation context\n");
563 xsltGenericDebug(xsltGenericDebugContext
,
564 "### Max inodes: %d\n", cctxt
->maxNodeInfos
);
565 xsltGenericDebug(xsltGenericDebugContext
,
566 "### Max LREs : %d\n", cctxt
->maxLREs
);
571 if (cctxt
->inodeList
!= NULL
) {
572 xsltCompilerNodeInfoPtr tmp
, cur
= cctxt
->inodeList
;
573 while (cur
!= NULL
) {
579 if (cctxt
->tmpList
!= NULL
)
580 xsltPointerListFree(cctxt
->tmpList
);
581 if (cctxt
->nsAliases
!= NULL
)
582 xsltFreeNsAliasList(cctxt
->nsAliases
);
585 xsltCompilerVarInfoFree(cctxt
);
591 * xsltCompilerCreate:
593 * Creates an XSLT compiler context.
595 * Returns the pointer to the created xsltCompilerCtxt or
596 * NULL in case of an internal error.
598 static xsltCompilerCtxtPtr
599 xsltCompilationCtxtCreate(xsltStylesheetPtr style
) {
600 xsltCompilerCtxtPtr ret
;
602 ret
= (xsltCompilerCtxtPtr
) xmlMalloc(sizeof(xsltCompilerCtxt
));
604 xsltTransformError(NULL
, style
, NULL
,
605 "xsltCompilerCreate: allocation of compiler "
606 "context failed.\n");
609 memset(ret
, 0, sizeof(xsltCompilerCtxt
));
611 ret
->errSeverity
= XSLT_ERROR_SEVERITY_ERROR
;
612 ret
->tmpList
= xsltPointerListCreate(20);
613 if (ret
->tmpList
== NULL
) {
620 xsltCompilationCtxtFree(ret
);
625 xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first
)
627 xsltEffectiveNsPtr tmp
;
629 while (first
!= NULL
) {
631 first
= first
->nextInStore
;
637 xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data
)
642 if (data
->inScopeNamespaces
!= NULL
) {
644 xsltNsListContainerPtr nsi
;
645 xsltPointerListPtr list
=
646 (xsltPointerListPtr
) data
->inScopeNamespaces
;
648 for (i
= 0; i
< list
->number
; i
++) {
650 * REVISIT TODO: Free info of in-scope namespaces.
652 nsi
= (xsltNsListContainerPtr
) list
->items
[i
];
653 if (nsi
->list
!= NULL
)
657 xsltPointerListFree(list
);
658 data
->inScopeNamespaces
= NULL
;
661 if (data
->exclResultNamespaces
!= NULL
) {
663 xsltPointerListPtr list
= (xsltPointerListPtr
)
664 data
->exclResultNamespaces
;
666 for (i
= 0; i
< list
->number
; i
++)
667 xsltPointerListFree((xsltPointerListPtr
) list
->items
[i
]);
669 xsltPointerListFree(list
);
670 data
->exclResultNamespaces
= NULL
;
673 if (data
->extElemNamespaces
!= NULL
) {
674 xsltPointerListPtr list
= (xsltPointerListPtr
)
675 data
->extElemNamespaces
;
678 for (i
= 0; i
< list
->number
; i
++)
679 xsltPointerListFree((xsltPointerListPtr
) list
->items
[i
]);
681 xsltPointerListFree(list
);
682 data
->extElemNamespaces
= NULL
;
684 if (data
->effectiveNs
) {
685 xsltLREEffectiveNsNodesFree(data
->effectiveNs
);
686 data
->effectiveNs
= NULL
;
688 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
689 xsltFreeNamespaceMap(data
->nsMap
);
694 static xsltPrincipalStylesheetDataPtr
695 xsltNewPrincipalStylesheetData(void)
697 xsltPrincipalStylesheetDataPtr ret
;
699 ret
= (xsltPrincipalStylesheetDataPtr
)
700 xmlMalloc(sizeof(xsltPrincipalStylesheetData
));
702 xsltTransformError(NULL
, NULL
, NULL
,
703 "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
706 memset(ret
, 0, sizeof(xsltPrincipalStylesheetData
));
709 * Global list of in-scope namespaces.
711 ret
->inScopeNamespaces
= xsltPointerListCreate(-1);
712 if (ret
->inScopeNamespaces
== NULL
)
715 * Global list of excluded result ns-decls.
717 ret
->exclResultNamespaces
= xsltPointerListCreate(-1);
718 if (ret
->exclResultNamespaces
== NULL
)
721 * Global list of extension instruction namespace names.
723 ret
->extElemNamespaces
= xsltPointerListCreate(-1);
724 if (ret
->extElemNamespaces
== NULL
)
737 * xsltNewStylesheetInternal:
738 * @parent: the parent stylesheet or NULL
740 * Create a new XSLT Stylesheet
742 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
744 static xsltStylesheetPtr
745 xsltNewStylesheetInternal(xsltStylesheetPtr parent
) {
746 xsltStylesheetPtr ret
= NULL
;
748 ret
= (xsltStylesheetPtr
) xmlMalloc(sizeof(xsltStylesheet
));
750 xsltTransformError(NULL
, NULL
, NULL
,
751 "xsltNewStylesheet : malloc failed\n");
754 memset(ret
, 0, sizeof(xsltStylesheet
));
756 ret
->parent
= parent
;
757 ret
->omitXmlDeclaration
= -1;
758 ret
->standalone
= -1;
759 ret
->decimalFormat
= xsltNewDecimalFormat(NULL
, NULL
);
763 ret
->exclPrefixNr
= 0;
764 ret
->exclPrefixMax
= 0;
765 ret
->exclPrefixTab
= NULL
;
766 ret
->extInfos
= NULL
;
768 ret
->internalized
= 1;
769 ret
->literal_result
= 0;
770 ret
->forwards_compatible
= 0;
771 ret
->dict
= xmlDictCreate();
772 #ifdef WITH_XSLT_DEBUG
773 xsltGenericDebug(xsltGenericDebugContext
,
774 "creating dictionary for stylesheet\n");
777 if (parent
== NULL
) {
778 ret
->principal
= ret
;
780 ret
->xpathCtxt
= xmlXPathNewContext(NULL
);
781 if (ret
->xpathCtxt
== NULL
) {
782 xsltTransformError(NULL
, NULL
, NULL
,
783 "xsltNewStylesheet: xmlXPathNewContext failed\n");
786 if (xmlXPathContextSetCache(ret
->xpathCtxt
, 1, -1, 0) == -1)
789 ret
->principal
= parent
->principal
;
798 xsltFreeStylesheet(ret
);
805 * Create a new XSLT Stylesheet
807 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
810 xsltNewStylesheet(void) {
811 return xsltNewStylesheetInternal(NULL
);
816 * @style: an XSLT stylesheet
818 * Allocate an extra runtime information slot statically while compiling
819 * the stylesheet and return its number
821 * Returns the number of the slot
824 xsltAllocateExtra(xsltStylesheetPtr style
)
826 return(style
->extrasNr
++);
830 * xsltAllocateExtraCtxt:
831 * @ctxt: an XSLT transformation context
833 * Allocate an extra runtime information slot at run-time
834 * and return its number
835 * This make sure there is a slot ready in the transformation context
837 * Returns the number of the slot
840 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt
)
842 if (ctxt
->extrasNr
>= ctxt
->extrasMax
) {
844 if (ctxt
->extrasNr
== 0) {
845 ctxt
->extrasMax
= 20;
846 ctxt
->extras
= (xsltRuntimeExtraPtr
)
847 xmlMalloc(ctxt
->extrasMax
* sizeof(xsltRuntimeExtra
));
848 if (ctxt
->extras
== NULL
) {
849 xsltTransformError(ctxt
, NULL
, NULL
,
850 "xsltAllocateExtraCtxt: out of memory\n");
853 for (i
= 0;i
< ctxt
->extrasMax
;i
++) {
854 ctxt
->extras
[i
].info
= NULL
;
855 ctxt
->extras
[i
].deallocate
= NULL
;
856 ctxt
->extras
[i
].val
.ptr
= NULL
;
860 xsltRuntimeExtraPtr tmp
;
862 ctxt
->extrasMax
+= 100;
863 tmp
= (xsltRuntimeExtraPtr
) xmlRealloc(ctxt
->extras
,
864 ctxt
->extrasMax
* sizeof(xsltRuntimeExtra
));
866 xsltTransformError(ctxt
, NULL
, NULL
,
867 "xsltAllocateExtraCtxt: out of memory\n");
871 for (i
= ctxt
->extrasNr
;i
< ctxt
->extrasMax
;i
++) {
872 ctxt
->extras
[i
].info
= NULL
;
873 ctxt
->extras
[i
].deallocate
= NULL
;
874 ctxt
->extras
[i
].val
.ptr
= NULL
;
878 return(ctxt
->extrasNr
++);
882 * xsltFreeStylesheetList:
883 * @style: an XSLT stylesheet list
885 * Free up the memory allocated by the list @style
888 xsltFreeStylesheetList(xsltStylesheetPtr style
) {
889 xsltStylesheetPtr next
;
891 while (style
!= NULL
) {
893 xsltFreeStylesheet(style
);
899 * xsltCleanupStylesheetTree:
901 * @doc: the document-node
902 * @node: the element where the stylesheet is rooted at
904 * Actually @node need not be the document-element, but
905 * currently Libxslt does not support embedded stylesheets.
907 * Returns 0 if OK, -1 on API or internal errors.
910 xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED
,
911 xmlNodePtr rootElem ATTRIBUTE_UNUSED
)
913 #if 0 /* TODO: Currently disabled, since probably not needed. */
916 if ((doc
== NULL
) || (rootElem
== NULL
) ||
917 (rootElem
->type
!= XML_ELEMENT_NODE
) ||
918 (doc
!= rootElem
->doc
))
922 * Cleanup was suggested by Aleksey Sanin:
923 * Clear the PSVI field to avoid problems if the
924 * node-tree of the stylesheet is intended to be used for
925 * further processing by the user (e.g. for compiling it
926 * once again - although not recommended).
930 while (cur
!= NULL
) {
931 if (cur
->type
== XML_ELEMENT_NODE
) {
933 * Clear the PSVI field.
945 if (cur
->next
!= NULL
)
959 * xsltFreeStylesheet:
960 * @style: an XSLT stylesheet
962 * Free up the memory allocated by @style
965 xsltFreeStylesheet(xsltStylesheetPtr style
)
970 #ifdef XSLT_REFACTORED
972 * Start with a cleanup of the main stylesheet's doc.
974 if ((style
->principal
== style
) && (style
->doc
))
975 xsltCleanupStylesheetTree(style
->doc
,
976 xmlDocGetRootElement(style
->doc
));
977 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
979 * Restore changed ns-decls before freeing the document.
981 if ((style
->doc
!= NULL
) &&
982 XSLT_HAS_INTERNAL_NSMAP(style
))
984 xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style
),
987 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
990 * Start with a cleanup of the main stylesheet's doc.
992 if ((style
->parent
== NULL
) && (style
->doc
))
993 xsltCleanupStylesheetTree(style
->doc
,
994 xmlDocGetRootElement(style
->doc
));
995 #endif /* XSLT_REFACTORED */
999 xsltFreeTemplateHashes(style
);
1000 xsltFreeDecimalFormatList(style
);
1001 xsltFreeTemplateList(style
->templates
);
1002 xsltFreeAttributeSetsHashes(style
);
1003 xsltFreeNamespaceAliasHashes(style
);
1004 xsltFreeStylePreComps(style
);
1006 * Free documents of all included stylsheet modules of this
1009 xsltFreeStyleDocuments(style
);
1011 * TODO: Best time to shutdown extension stuff?
1013 xsltShutdownExts(style
);
1015 if (style
->variables
!= NULL
)
1016 xsltFreeStackElemList(style
->variables
);
1017 if (style
->cdataSection
!= NULL
)
1018 xmlHashFree(style
->cdataSection
, NULL
);
1019 if (style
->stripSpaces
!= NULL
)
1020 xmlHashFree(style
->stripSpaces
, NULL
);
1021 if (style
->nsHash
!= NULL
)
1022 xmlHashFree(style
->nsHash
, NULL
);
1023 if (style
->exclPrefixTab
!= NULL
)
1024 xmlFree(style
->exclPrefixTab
);
1025 if (style
->method
!= NULL
)
1026 xmlFree(style
->method
);
1027 if (style
->methodURI
!= NULL
)
1028 xmlFree(style
->methodURI
);
1029 if (style
->version
!= NULL
)
1030 xmlFree(style
->version
);
1031 if (style
->encoding
!= NULL
)
1032 xmlFree(style
->encoding
);
1033 if (style
->doctypePublic
!= NULL
)
1034 xmlFree(style
->doctypePublic
);
1035 if (style
->doctypeSystem
!= NULL
)
1036 xmlFree(style
->doctypeSystem
);
1037 if (style
->mediaType
!= NULL
)
1038 xmlFree(style
->mediaType
);
1040 xsltFreeAVTList(style
->attVTs
);
1041 if (style
->imports
!= NULL
)
1042 xsltFreeStylesheetList(style
->imports
);
1044 #ifdef XSLT_REFACTORED
1046 * If this is the principal stylesheet, then
1047 * free its internal data.
1049 if (style
->principal
== style
) {
1050 if (style
->principalData
) {
1051 xsltFreePrincipalStylesheetData(style
->principalData
);
1052 style
->principalData
= NULL
;
1057 * Better to free the main document of this stylesheet level
1058 * at the end - so here.
1060 if (style
->doc
!= NULL
) {
1061 xmlFreeDoc(style
->doc
);
1064 #ifdef WITH_XSLT_DEBUG
1065 xsltGenericDebug(xsltGenericDebugContext
,
1066 "freeing dictionary from stylesheet\n");
1068 xmlDictFree(style
->dict
);
1070 if (style
->xpathCtxt
!= NULL
)
1071 xmlXPathFreeContext(style
->xpathCtxt
);
1073 memset(style
, -1, sizeof(xsltStylesheet
));
1077 /************************************************************************
1079 * Parsing of an XSLT Stylesheet *
1081 ************************************************************************/
1083 #ifdef XSLT_REFACTORED
1085 * This is now performed in an optimized way in xsltParseXSLTTemplate.
1089 * xsltGetInheritedNsList:
1090 * @style: the stylesheet
1091 * @template: the template
1092 * @node: the current node
1094 * Search all the namespace applying to a given element except the ones
1095 * from excluded output prefixes currently in scope. Initialize the
1096 * template inheritedNs list with it.
1098 * Returns the number of entries found
1101 xsltGetInheritedNsList(xsltStylesheetPtr style
,
1102 xsltTemplatePtr
template,
1106 xmlNsPtr
*ret
= NULL
, *tmp
;
1111 if ((style
== NULL
) || (template == NULL
) || (node
== NULL
) ||
1112 (template->inheritedNsNr
!= 0) || (template->inheritedNs
!= NULL
))
1114 while (node
!= NULL
) {
1115 if (node
->type
== XML_ELEMENT_NODE
) {
1117 while (cur
!= NULL
) {
1118 if (xmlStrEqual(cur
->href
, XSLT_NAMESPACE
))
1121 if ((cur
->prefix
!= NULL
) &&
1122 (xsltCheckExtPrefix(style
, cur
->prefix
)))
1125 * Check if this namespace was excluded.
1126 * Note that at this point only the exclusions defined
1127 * on the topmost stylesheet element are in the exclusion-list.
1129 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
1130 if (xmlStrEqual(cur
->href
, style
->exclPrefixTab
[i
]))
1134 * Skip shadowed namespace bindings.
1136 for (i
= 0; i
< nbns
; i
++) {
1137 if ((cur
->prefix
== ret
[i
]->prefix
) ||
1138 (xmlStrEqual(cur
->prefix
, ret
[i
]->prefix
)))
1142 if (nbns
>= maxns
) {
1143 maxns
= (maxns
== 0) ? 10 : 2 * maxns
;
1144 tmp
= (xmlNsPtr
*) xmlRealloc(ret
,
1145 (maxns
+ 1) * sizeof(xmlNsPtr
));
1147 xmlGenericError(xmlGenericErrorContext
,
1148 "xsltGetInheritedNsList : realloc failed!\n");
1161 node
= node
->parent
;
1164 #ifdef WITH_XSLT_DEBUG_PARSING
1165 xsltGenericDebug(xsltGenericDebugContext
,
1166 "template has %d inherited namespaces\n", nbns
);
1168 template->inheritedNsNr
= nbns
;
1169 template->inheritedNs
= ret
;
1173 #endif /* else of XSLT_REFACTORED */
1176 * xsltParseStylesheetOutput:
1177 * @style: the XSLT stylesheet
1178 * @cur: the "output" element
1180 * parse an XSLT stylesheet output element and record
1181 * information related to the stylesheet output
1185 xsltParseStylesheetOutput(xsltStylesheetPtr style
, xmlNodePtr cur
)
1192 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1195 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "version", NULL
);
1197 if (style
->version
!= NULL
)
1198 xmlFree(style
->version
);
1199 style
->version
= prop
;
1202 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "encoding", NULL
);
1204 if (style
->encoding
!= NULL
)
1205 xmlFree(style
->encoding
);
1206 style
->encoding
= prop
;
1209 /* relaxed to support xt:document
1210 * TODO KB: What does "relaxed to support xt:document" mean?
1212 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "method", NULL
);
1216 if (style
->method
!= NULL
)
1217 xmlFree(style
->method
);
1218 style
->method
= NULL
;
1219 if (style
->methodURI
!= NULL
)
1220 xmlFree(style
->methodURI
);
1221 style
->methodURI
= NULL
;
1224 * TODO: Don't use xsltGetQNameURI().
1226 URI
= xsltGetQNameURI(cur
, &prop
);
1228 if (style
!= NULL
) style
->errors
++;
1229 } else if (URI
== NULL
) {
1230 if ((xmlStrEqual(prop
, (const xmlChar
*) "xml")) ||
1231 (xmlStrEqual(prop
, (const xmlChar
*) "html")) ||
1232 (xmlStrEqual(prop
, (const xmlChar
*) "text"))) {
1233 style
->method
= prop
;
1235 xsltTransformError(NULL
, style
, cur
,
1236 "invalid value for method: %s\n", prop
);
1237 if (style
!= NULL
) style
->warnings
++;
1241 style
->method
= prop
;
1242 style
->methodURI
= xmlStrdup(URI
);
1246 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "doctype-system", NULL
);
1248 if (style
->doctypeSystem
!= NULL
)
1249 xmlFree(style
->doctypeSystem
);
1250 style
->doctypeSystem
= prop
;
1253 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "doctype-public", NULL
);
1255 if (style
->doctypePublic
!= NULL
)
1256 xmlFree(style
->doctypePublic
);
1257 style
->doctypePublic
= prop
;
1260 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "standalone", NULL
);
1262 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1263 style
->standalone
= 1;
1264 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1265 style
->standalone
= 0;
1267 xsltTransformError(NULL
, style
, cur
,
1268 "invalid value for standalone: %s\n", prop
);
1274 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "indent", NULL
);
1276 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1278 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1281 xsltTransformError(NULL
, style
, cur
,
1282 "invalid value for indent: %s\n", prop
);
1288 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "omit-xml-declaration", NULL
);
1290 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1291 style
->omitXmlDeclaration
= 1;
1292 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1293 style
->omitXmlDeclaration
= 0;
1295 xsltTransformError(NULL
, style
, cur
,
1296 "invalid value for omit-xml-declaration: %s\n",
1303 elements
= xmlGetNsProp(cur
, (const xmlChar
*) "cdata-section-elements",
1305 if (elements
!= NULL
) {
1306 if (style
->cdataSection
== NULL
)
1307 style
->cdataSection
= xmlHashCreate(10);
1308 if (style
->cdataSection
== NULL
) {
1314 while (*element
!= 0) {
1315 while (IS_BLANK(*element
))
1320 while ((*end
!= 0) && (!IS_BLANK(*end
)))
1322 element
= xmlStrndup(element
, end
- element
);
1324 #ifdef WITH_XSLT_DEBUG_PARSING
1325 xsltGenericDebug(xsltGenericDebugContext
,
1326 "add cdata section output element %s\n",
1329 if (xmlValidateQName(BAD_CAST element
, 0) != 0) {
1330 xsltTransformError(NULL
, style
, cur
,
1331 "Attribute 'cdata-section-elements': The value "
1332 "'%s' is not a valid QName.\n", element
);
1339 * TODO: Don't use xsltGetQNameURI().
1341 URI
= xsltGetQNameURI(cur
, &element
);
1342 if (element
== NULL
) {
1344 * TODO: We'll report additionally an error
1345 * via the stylesheet's error handling.
1347 xsltTransformError(NULL
, style
, cur
,
1348 "Attribute 'cdata-section-elements': "
1349 "Not a valid QName.\n");
1355 * XSLT-1.0 "Each QName is expanded into an
1356 * expanded-name using the namespace declarations in
1357 * effect on the xsl:output element in which the QName
1358 * occurs; if there is a default namespace, it is used
1359 * for QNames that do not have a prefix"
1360 * NOTE: Fix of bug #339570.
1363 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1367 xmlHashAddEntry2(style
->cdataSection
, element
, URI
,
1378 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "media-type", NULL
);
1380 if (style
->mediaType
)
1381 xmlFree(style
->mediaType
);
1382 style
->mediaType
= prop
;
1384 if (cur
->children
!= NULL
) {
1385 xsltParseContentError(style
, cur
->children
);
1390 * xsltParseStylesheetDecimalFormat:
1391 * @style: the XSLT stylesheet
1392 * @cur: the "decimal-format" element
1394 * <!-- Category: top-level-element -->
1395 * <xsl:decimal-format
1396 * name = qname, decimal-separator = char, grouping-separator = char,
1397 * infinity = string, minus-sign = char, NaN = string, percent = char
1398 * per-mille = char, zero-digit = char, digit = char,
1399 * pattern-separator = char />
1401 * parse an XSLT stylesheet decimal-format element and
1402 * and record the formatting characteristics
1405 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style
, xmlNodePtr cur
)
1408 xsltDecimalFormatPtr format
;
1409 xsltDecimalFormatPtr iter
;
1411 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1414 format
= style
->decimalFormat
;
1416 prop
= xmlGetNsProp(cur
, BAD_CAST("name"), NULL
);
1418 const xmlChar
*nsUri
;
1420 if (xmlValidateQName(prop
, 0) != 0) {
1421 xsltTransformError(NULL
, style
, cur
,
1422 "xsl:decimal-format: Invalid QName '%s'.\n", prop
);
1428 * TODO: Don't use xsltGetQNameURI().
1430 nsUri
= xsltGetQNameURI(cur
, &prop
);
1435 format
= xsltDecimalFormatGetByQName(style
, nsUri
, prop
);
1436 if (format
!= NULL
) {
1437 xsltTransformError(NULL
, style
, cur
,
1438 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop
);
1443 format
= xsltNewDecimalFormat(nsUri
, prop
);
1444 if (format
== NULL
) {
1445 xsltTransformError(NULL
, style
, cur
,
1446 "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
1451 /* Append new decimal-format structure */
1452 for (iter
= style
->decimalFormat
; iter
->next
; iter
= iter
->next
)
1455 iter
->next
= format
;
1458 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"decimal-separator", NULL
);
1460 if (format
->decimalPoint
!= NULL
) xmlFree(format
->decimalPoint
);
1461 format
->decimalPoint
= prop
;
1464 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"grouping-separator", NULL
);
1466 if (format
->grouping
!= NULL
) xmlFree(format
->grouping
);
1467 format
->grouping
= prop
;
1470 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"infinity", NULL
);
1472 if (format
->infinity
!= NULL
) xmlFree(format
->infinity
);
1473 format
->infinity
= prop
;
1476 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"minus-sign", NULL
);
1478 if (format
->minusSign
!= NULL
) xmlFree(format
->minusSign
);
1479 format
->minusSign
= prop
;
1482 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"NaN", NULL
);
1484 if (format
->noNumber
!= NULL
) xmlFree(format
->noNumber
);
1485 format
->noNumber
= prop
;
1488 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"percent", NULL
);
1490 if (format
->percent
!= NULL
) xmlFree(format
->percent
);
1491 format
->percent
= prop
;
1494 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"per-mille", NULL
);
1496 if (format
->permille
!= NULL
) xmlFree(format
->permille
);
1497 format
->permille
= prop
;
1500 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"zero-digit", NULL
);
1502 if (format
->zeroDigit
!= NULL
) xmlFree(format
->zeroDigit
);
1503 format
->zeroDigit
= prop
;
1506 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"digit", NULL
);
1508 if (format
->digit
!= NULL
) xmlFree(format
->digit
);
1509 format
->digit
= prop
;
1512 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"pattern-separator", NULL
);
1514 if (format
->patternSeparator
!= NULL
) xmlFree(format
->patternSeparator
);
1515 format
->patternSeparator
= prop
;
1517 if (cur
->children
!= NULL
) {
1518 xsltParseContentError(style
, cur
->children
);
1523 * xsltParseStylesheetPreserveSpace:
1524 * @style: the XSLT stylesheet
1525 * @cur: the "preserve-space" element
1527 * parse an XSLT stylesheet preserve-space element and record
1528 * elements needing preserving
1532 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style
, xmlNodePtr cur
) {
1534 xmlChar
*element
, *end
;
1536 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1539 elements
= xmlGetNsProp(cur
, (const xmlChar
*)"elements", NULL
);
1540 if (elements
== NULL
) {
1541 xsltTransformError(NULL
, style
, cur
,
1542 "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
1543 if (style
!= NULL
) style
->warnings
++;
1547 if (style
->stripSpaces
== NULL
)
1548 style
->stripSpaces
= xmlHashCreate(10);
1549 if (style
->stripSpaces
== NULL
) {
1555 while (*element
!= 0) {
1556 while (IS_BLANK(*element
)) element
++;
1560 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1561 element
= xmlStrndup(element
, end
- element
);
1563 #ifdef WITH_XSLT_DEBUG_PARSING
1564 xsltGenericDebug(xsltGenericDebugContext
,
1565 "add preserved space element %s\n", element
);
1567 if (xmlStrEqual(element
, (const xmlChar
*)"*")) {
1568 style
->stripAll
= -1;
1573 * TODO: Don't use xsltGetQNameURI().
1575 URI
= xsltGetQNameURI(cur
, &element
);
1577 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
1578 (xmlChar
*) "preserve");
1585 if (cur
->children
!= NULL
) {
1586 xsltParseContentError(style
, cur
->children
);
1590 #ifdef XSLT_REFACTORED
1593 * xsltParseStylesheetExtPrefix:
1594 * @style: the XSLT stylesheet
1595 * @template: the "extension-element-prefixes" prefix
1597 * parse an XSLT stylesheet's "extension-element-prefix" attribute value
1598 * and register the namespaces of extension instruction.
1599 * SPEC "A namespace is designated as an extension namespace by using
1600 * an extension-element-prefixes attribute on:
1601 * 1) an xsl:stylesheet element
1602 * 2) an xsl:extension-element-prefixes attribute on a
1603 * literal result element
1604 * 3) an extension instruction."
1607 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style
, xmlNodePtr cur
,
1610 xmlChar
*prefix
, *end
;
1612 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1616 /* For xsl:stylesheet/xsl:transform. */
1617 prefixes
= xmlGetNsProp(cur
,
1618 (const xmlChar
*)"extension-element-prefixes", NULL
);
1620 /* For literal result elements and extension instructions. */
1621 prefixes
= xmlGetNsProp(cur
,
1622 (const xmlChar
*)"extension-element-prefixes", XSLT_NAMESPACE
);
1624 if (prefixes
== NULL
) {
1629 while (*prefix
!= 0) {
1630 while (IS_BLANK(*prefix
)) prefix
++;
1634 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1635 prefix
= xmlStrndup(prefix
, end
- prefix
);
1639 if (xmlStrEqual(prefix
, (const xmlChar
*)"#default"))
1640 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1642 ns
= xmlSearchNs(style
->doc
, cur
, prefix
);
1644 xsltTransformError(NULL
, style
, cur
,
1645 "xsl:extension-element-prefix : undefined namespace %s\n",
1647 if (style
!= NULL
) style
->warnings
++;
1649 #ifdef WITH_XSLT_DEBUG_PARSING
1650 xsltGenericDebug(xsltGenericDebugContext
,
1651 "add extension prefix %s\n", prefix
);
1653 xsltRegisterExtPrefix(style
, prefix
, ns
->href
);
1661 #endif /* else of XSLT_REFACTORED */
1664 * xsltParseStylesheetStripSpace:
1665 * @style: the XSLT stylesheet
1666 * @cur: the "strip-space" element
1668 * parse an XSLT stylesheet's strip-space element and record
1669 * the elements needing stripping
1673 xsltParseStylesheetStripSpace(xsltStylesheetPtr style
, xmlNodePtr cur
) {
1675 xmlChar
*element
, *end
;
1677 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1680 if (style
->stripSpaces
== NULL
)
1681 style
->stripSpaces
= xmlHashCreate(10);
1682 if (style
->stripSpaces
== NULL
)
1685 elements
= xmlGetNsProp(cur
, (const xmlChar
*)"elements", NULL
);
1686 if (elements
== NULL
) {
1687 xsltTransformError(NULL
, style
, cur
,
1688 "xsltParseStylesheetStripSpace: missing elements attribute\n");
1689 if (style
!= NULL
) style
->warnings
++;
1694 while (*element
!= 0) {
1695 while (IS_BLANK(*element
)) element
++;
1699 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1700 element
= xmlStrndup(element
, end
- element
);
1702 #ifdef WITH_XSLT_DEBUG_PARSING
1703 xsltGenericDebug(xsltGenericDebugContext
,
1704 "add stripped space element %s\n", element
);
1706 if (xmlStrEqual(element
, (const xmlChar
*)"*")) {
1707 style
->stripAll
= 1;
1712 * TODO: Don't use xsltGetQNameURI().
1714 URI
= xsltGetQNameURI(cur
, &element
);
1716 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
1717 (xmlChar
*) "strip");
1724 if (cur
->children
!= NULL
) {
1725 xsltParseContentError(style
, cur
->children
);
1729 #ifdef XSLT_REFACTORED
1732 * xsltParseStylesheetExcludePrefix:
1733 * @style: the XSLT stylesheet
1734 * @cur: the current point in the stylesheet
1736 * parse an XSLT stylesheet exclude prefix and record
1737 * namespaces needing stripping
1739 * Returns the number of Excluded prefixes added at that level
1743 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style
, xmlNodePtr cur
,
1748 xmlChar
*prefix
, *end
;
1750 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1754 prefixes
= xmlGetNsProp(cur
,
1755 (const xmlChar
*)"exclude-result-prefixes", NULL
);
1757 prefixes
= xmlGetNsProp(cur
,
1758 (const xmlChar
*)"exclude-result-prefixes", XSLT_NAMESPACE
);
1760 if (prefixes
== NULL
) {
1765 while (*prefix
!= 0) {
1766 while (IS_BLANK(*prefix
)) prefix
++;
1770 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1771 prefix
= xmlStrndup(prefix
, end
- prefix
);
1775 if (xmlStrEqual(prefix
, (const xmlChar
*)"#default"))
1776 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1778 ns
= xmlSearchNs(style
->doc
, cur
, prefix
);
1780 xsltTransformError(NULL
, style
, cur
,
1781 "xsl:exclude-result-prefixes : undefined namespace %s\n",
1783 if (style
!= NULL
) style
->warnings
++;
1785 if (exclPrefixPush(style
, (xmlChar
*) ns
->href
) >= 0) {
1786 #ifdef WITH_XSLT_DEBUG_PARSING
1787 xsltGenericDebug(xsltGenericDebugContext
,
1788 "exclude result prefix %s\n", prefix
);
1800 #endif /* else of XSLT_REFACTORED */
1802 #ifdef XSLT_REFACTORED
1805 * xsltTreeEnsureXMLDecl:
1809 * This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
1810 * Ensures that there is an XML namespace declaration on the doc.
1812 * Returns the XML ns-struct or NULL on API and internal errors.
1815 xsltTreeEnsureXMLDecl(xmlDocPtr doc
)
1819 if (doc
->oldNs
!= NULL
)
1820 return (doc
->oldNs
);
1823 ns
= (xmlNsPtr
) xmlMalloc(sizeof(xmlNs
));
1825 xmlGenericError(xmlGenericErrorContext
,
1826 "xsltTreeEnsureXMLDecl: Failed to allocate "
1827 "the XML namespace.\n");
1830 memset(ns
, 0, sizeof(xmlNs
));
1831 ns
->type
= XML_LOCAL_NAMESPACE
;
1833 * URGENT TODO: revisit this.
1835 #ifdef LIBXML_NAMESPACE_DICT
1837 ns
->href
= xmlDictLookup(doc
->dict
, XML_XML_NAMESPACE
, -1);
1839 ns
->href
= xmlStrdup(XML_XML_NAMESPACE
);
1841 ns
->href
= xmlStrdup(XML_XML_NAMESPACE
);
1843 ns
->prefix
= xmlStrdup((const xmlChar
*)"xml");
1850 * xsltTreeAcquireStoredNs:
1852 * @nsName: the namespace name
1853 * @prefix: the prefix
1856 * This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
1857 * Creates or reuses an xmlNs struct on doc->oldNs with
1858 * the given prefix and namespace name.
1860 * Returns the aquired ns struct or NULL in case of an API
1861 * or internal error.
1864 xsltTreeAcquireStoredNs(xmlDocPtr doc
,
1865 const xmlChar
*nsName
,
1866 const xmlChar
*prefix
)
1872 if (doc
->oldNs
!= NULL
)
1875 ns
= xsltTreeEnsureXMLDecl(doc
);
1878 if (ns
->next
!= NULL
) {
1881 while (ns
!= NULL
) {
1882 if ((ns
->prefix
== NULL
) != (prefix
== NULL
)) {
1884 } else if (prefix
== NULL
) {
1885 if (xmlStrEqual(ns
->href
, nsName
))
1888 if ((ns
->prefix
[0] == prefix
[0]) &&
1889 xmlStrEqual(ns
->prefix
, prefix
) &&
1890 xmlStrEqual(ns
->href
, nsName
))
1894 if (ns
->next
== NULL
)
1900 ns
->next
= xmlNewNs(NULL
, nsName
, prefix
);
1905 * xsltLREBuildEffectiveNs:
1907 * Apply ns-aliasing on the namespace of the given @elem and
1911 xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt
,
1915 xsltNsAliasPtr alias
;
1917 if ((cctxt
== NULL
) || (elem
== NULL
))
1919 if ((cctxt
->nsAliases
== NULL
) || (! cctxt
->hasNsAliases
))
1922 alias
= cctxt
->nsAliases
;
1923 while (alias
!= NULL
) {
1924 if ( /* If both namespaces are NULL... */
1925 ( (elem
->ns
== NULL
) &&
1926 ((alias
->literalNs
== NULL
) ||
1927 (alias
->literalNs
->href
== NULL
)) ) ||
1928 /* ... or both namespace are equal */
1929 ( (elem
->ns
!= NULL
) &&
1930 (alias
->literalNs
!= NULL
) &&
1931 xmlStrEqual(elem
->ns
->href
, alias
->literalNs
->href
) ) )
1933 if ((alias
->targetNs
!= NULL
) &&
1934 (alias
->targetNs
->href
!= NULL
))
1937 * Convert namespace.
1939 if (elem
->doc
== alias
->docOfTargetNs
) {
1941 * This is the nice case: same docs.
1942 * This will eventually assign a ns-decl which
1943 * is shadowed, but this has no negative effect on
1944 * the generation of the result tree.
1946 elem
->ns
= alias
->targetNs
;
1949 * This target xmlNs originates from a different
1950 * stylesheet tree. Try to locate it in the
1951 * in-scope namespaces.
1952 * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
1954 ns
= xmlSearchNs(elem
->doc
, elem
,
1955 alias
->targetNs
->prefix
);
1957 * If no matching ns-decl found, then assign a
1958 * ns-decl stored in xmlDoc.
1961 (! xmlStrEqual(ns
->href
, alias
->targetNs
->href
)))
1964 * BIG NOTE: The use of xsltTreeAcquireStoredNs()
1965 * is not very efficient, but currently I don't
1966 * see an other way of *safely* changing a node's
1967 * namespace, since the xmlNs struct in
1968 * alias->targetNs might come from an other
1969 * stylesheet tree. So we need to anchor it in the
1970 * current document, without adding it to the tree,
1971 * which would otherwise change the in-scope-ns
1972 * semantic of the tree.
1974 ns
= xsltTreeAcquireStoredNs(elem
->doc
,
1975 alias
->targetNs
->href
,
1976 alias
->targetNs
->prefix
);
1979 xsltTransformError(NULL
, cctxt
->style
, elem
,
1980 "Internal error in "
1981 "xsltLREBuildEffectiveNs(): "
1982 "failed to acquire a stored "
1983 "ns-declaration.\n");
1984 cctxt
->style
->errors
++;
1993 * Move into or leave in the NULL namespace.
1999 alias
= alias
->next
;
2002 * Same with attributes of literal result elements.
2004 if (elem
->properties
!= NULL
) {
2005 xmlAttrPtr attr
= elem
->properties
;
2007 while (attr
!= NULL
) {
2008 if (attr
->ns
== NULL
) {
2012 alias
= cctxt
->nsAliases
;
2013 while (alias
!= NULL
) {
2014 if ( /* If both namespaces are NULL... */
2015 ( (elem
->ns
== NULL
) &&
2016 ((alias
->literalNs
== NULL
) ||
2017 (alias
->literalNs
->href
== NULL
)) ) ||
2018 /* ... or both namespace are equal */
2019 ( (elem
->ns
!= NULL
) &&
2020 (alias
->literalNs
!= NULL
) &&
2021 xmlStrEqual(elem
->ns
->href
, alias
->literalNs
->href
) ) )
2023 if ((alias
->targetNs
!= NULL
) &&
2024 (alias
->targetNs
->href
!= NULL
))
2026 if (elem
->doc
== alias
->docOfTargetNs
) {
2027 elem
->ns
= alias
->targetNs
;
2029 ns
= xmlSearchNs(elem
->doc
, elem
,
2030 alias
->targetNs
->prefix
);
2032 (! xmlStrEqual(ns
->href
, alias
->targetNs
->href
)))
2034 ns
= xsltTreeAcquireStoredNs(elem
->doc
,
2035 alias
->targetNs
->href
,
2036 alias
->targetNs
->prefix
);
2039 xsltTransformError(NULL
, cctxt
->style
, elem
,
2040 "Internal error in "
2041 "xsltLREBuildEffectiveNs(): "
2042 "failed to acquire a stored "
2043 "ns-declaration.\n");
2044 cctxt
->style
->errors
++;
2053 * Move into or leave in the NULL namespace.
2059 alias
= alias
->next
;
2069 * xsltLREBuildEffectiveNsNodes:
2071 * Computes the effective namespaces nodes for a literal result
2073 * @effectiveNs is the set of effective ns-nodes
2074 * on the literal result element, which will be added to the result
2075 * element if not already existing in the result tree.
2076 * This means that excluded namespaces (via exclude-result-prefixes,
2077 * extension-element-prefixes and the XSLT namespace) not added
2079 * Namespace-aliasing was applied on the @effectiveNs.
2082 xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt
,
2083 xsltStyleItemLRElementInfoPtr item
,
2088 xsltEffectiveNsPtr effNs
, lastEffNs
= NULL
;
2089 int i
, j
, holdByElem
;
2090 xsltPointerListPtr extElemNs
= cctxt
->inode
->extElemNs
;
2091 xsltPointerListPtr exclResultNs
= cctxt
->inode
->exclResultNs
;
2093 if ((cctxt
== NULL
) || (cctxt
->inode
== NULL
) || (elem
== NULL
) ||
2094 (item
== NULL
) || (item
->effectiveNs
!= NULL
))
2097 if (item
->inScopeNs
== NULL
)
2100 extElemNs
= cctxt
->inode
->extElemNs
;
2101 exclResultNs
= cctxt
->inode
->exclResultNs
;
2103 for (i
= 0; i
< item
->inScopeNs
->totalNumber
; i
++) {
2104 ns
= item
->inScopeNs
->list
[i
];
2106 * Skip namespaces designated as excluded namespaces
2107 * -------------------------------------------------
2109 * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
2110 * which are target namespaces of namespace-aliases
2111 * regardless if designated as excluded.
2113 * Exclude the XSLT namespace.
2115 if (xmlStrEqual(ns
->href
, XSLT_NAMESPACE
))
2119 * Apply namespace aliasing
2120 * ------------------------
2123 * "- A namespace node whose string value is a literal namespace
2124 * URI is not copied to the result tree.
2125 * - A namespace node whose string value is a target namespace URI
2126 * is copied to the result tree, whether or not the URI
2127 * identifies an excluded namespace."
2129 * NOTE: The ns-aliasing machanism is non-cascading.
2130 * (checked with Saxon, Xalan and MSXML .NET).
2131 * URGENT TODO: is style->nsAliases the effective list of
2132 * ns-aliases, or do we need to lookup the whole
2134 * TODO: Get rid of import-tree lookup.
2136 if (cctxt
->hasNsAliases
) {
2137 xsltNsAliasPtr alias
;
2139 * First check for being a target namespace.
2141 alias
= cctxt
->nsAliases
;
2144 * TODO: Is xmlns="" handled already?
2146 if ((alias
->targetNs
!= NULL
) &&
2147 (xmlStrEqual(alias
->targetNs
->href
, ns
->href
)))
2150 * Recognized as a target namespace; use it regardless
2151 * if excluded otherwise.
2153 goto add_effective_ns
;
2155 alias
= alias
->next
;
2156 } while (alias
!= NULL
);
2158 alias
= cctxt
->nsAliases
;
2161 * TODO: Is xmlns="" handled already?
2163 if ((alias
->literalNs
!= NULL
) &&
2164 (xmlStrEqual(alias
->literalNs
->href
, ns
->href
)))
2167 * Recognized as an namespace alias; do not use it.
2171 alias
= alias
->next
;
2172 } while (alias
!= NULL
);
2176 * Exclude excluded result namespaces.
2179 for (j
= 0; j
< exclResultNs
->number
; j
++)
2180 if (xmlStrEqual(ns
->href
, BAD_CAST exclResultNs
->items
[j
]))
2184 * Exclude extension-element namespaces.
2187 for (j
= 0; j
< extElemNs
->number
; j
++)
2188 if (xmlStrEqual(ns
->href
, BAD_CAST extElemNs
->items
[j
]))
2194 * OPTIMIZE TODO: This information may not be needed.
2196 if (isLRE
&& (elem
->nsDef
!= NULL
)) {
2198 tmpns
= elem
->nsDef
;
2204 tmpns
= tmpns
->next
;
2205 } while (tmpns
!= NULL
);
2211 * Add the effective namespace declaration.
2213 effNs
= (xsltEffectiveNsPtr
) xmlMalloc(sizeof(xsltEffectiveNs
));
2214 if (effNs
== NULL
) {
2215 xsltTransformError(NULL
, cctxt
->style
, elem
,
2216 "Internal error in xsltLREBuildEffectiveNs(): "
2217 "failed to allocate memory.\n");
2218 cctxt
->style
->errors
++;
2221 if (cctxt
->psData
->effectiveNs
== NULL
) {
2222 cctxt
->psData
->effectiveNs
= effNs
;
2223 effNs
->nextInStore
= NULL
;
2225 effNs
->nextInStore
= cctxt
->psData
->effectiveNs
;
2226 cctxt
->psData
->effectiveNs
= effNs
;
2230 effNs
->prefix
= ns
->prefix
;
2231 effNs
->nsName
= ns
->href
;
2232 effNs
->holdByElem
= holdByElem
;
2234 if (lastEffNs
== NULL
)
2235 item
->effectiveNs
= effNs
;
2237 lastEffNs
->next
= effNs
;
2248 * xsltLREInfoCreate:
2250 * @isLRE: indicates if the given @elem is a literal result element
2252 * Creates a new info for a literal result element.
2255 xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt
,
2259 xsltStyleItemLRElementInfoPtr item
;
2261 if ((cctxt
== NULL
) || (cctxt
->inode
== NULL
))
2264 item
= (xsltStyleItemLRElementInfoPtr
)
2265 xmlMalloc(sizeof(xsltStyleItemLRElementInfo
));
2267 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2268 "Internal error in xsltLREInfoCreate(): "
2269 "memory allocation failed.\n");
2270 cctxt
->style
->errors
++;
2273 memset(item
, 0, sizeof(xsltStyleItemLRElementInfo
));
2274 item
->type
= XSLT_FUNC_LITERAL_RESULT_ELEMENT
;
2276 * Store it in the stylesheet.
2278 item
->next
= cctxt
->style
->preComps
;
2279 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
2281 * @inScopeNs are used for execution of XPath expressions
2284 item
->inScopeNs
= cctxt
->inode
->inScopeNs
;
2287 xsltLREBuildEffectiveNsNodes(cctxt
, item
, elem
, isLRE
);
2289 cctxt
->inode
->litResElemInfo
= item
;
2290 cctxt
->inode
->nsChanged
= 0;
2296 * xsltCompilerVarInfoPush:
2297 * @cctxt: the compilation context
2299 * Pushes a new var/param info onto the stack.
2301 * Returns the acquired variable info.
2303 static xsltVarInfoPtr
2304 xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt
,
2306 const xmlChar
*name
,
2307 const xmlChar
*nsName
)
2309 xsltVarInfoPtr ivar
;
2311 if ((cctxt
->ivar
!= NULL
) && (cctxt
->ivar
->next
!= NULL
)) {
2312 ivar
= cctxt
->ivar
->next
;
2313 } else if ((cctxt
->ivar
== NULL
) && (cctxt
->ivars
!= NULL
)) {
2314 ivar
= cctxt
->ivars
;
2316 ivar
= (xsltVarInfoPtr
) xmlMalloc(sizeof(xsltVarInfo
));
2318 xsltTransformError(NULL
, cctxt
->style
, inst
,
2319 "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
2320 cctxt
->style
->errors
++;
2323 /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
2324 if (cctxt
->ivars
== NULL
) {
2325 cctxt
->ivars
= ivar
;
2328 cctxt
->ivar
->next
= ivar
;
2329 ivar
->prev
= cctxt
->ivar
;
2334 ivar
->depth
= cctxt
->depth
;
2336 ivar
->nsName
= nsName
;
2341 * xsltCompilerVarInfoPop:
2342 * @cctxt: the compilation context
2344 * Pops all var/param infos from the stack, which
2345 * have the current depth.
2348 xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt
)
2351 while ((cctxt
->ivar
!= NULL
) &&
2352 (cctxt
->ivar
->depth
> cctxt
->depth
))
2354 cctxt
->ivar
= cctxt
->ivar
->prev
;
2359 * xsltCompilerNodePush:
2361 * @cctxt: the compilation context
2362 * @node: the node to be pushed (this can also be the doc-node)
2366 * Returns the current node info structure or
2367 * NULL in case of an internal error.
2369 static xsltCompilerNodeInfoPtr
2370 xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2372 xsltCompilerNodeInfoPtr inode
, iprev
;
2374 if ((cctxt
->inode
!= NULL
) && (cctxt
->inode
->next
!= NULL
)) {
2375 inode
= cctxt
->inode
->next
;
2376 } else if ((cctxt
->inode
== NULL
) && (cctxt
->inodeList
!= NULL
)) {
2377 inode
= cctxt
->inodeList
;
2380 * Create a new node-info.
2382 inode
= (xsltCompilerNodeInfoPtr
)
2383 xmlMalloc(sizeof(xsltCompilerNodeInfo
));
2384 if (inode
== NULL
) {
2385 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2386 "xsltCompilerNodePush: malloc failed.\n");
2389 memset(inode
, 0, sizeof(xsltCompilerNodeInfo
));
2390 if (cctxt
->inodeList
== NULL
)
2391 cctxt
->inodeList
= inode
;
2393 cctxt
->inodeLast
->next
= inode
;
2394 inode
->prev
= cctxt
->inodeLast
;
2396 cctxt
->inodeLast
= inode
;
2397 cctxt
->maxNodeInfos
++;
2398 if (cctxt
->inode
== NULL
) {
2399 cctxt
->inode
= inode
;
2401 * Create an initial literal result element info for
2402 * the root of the stylesheet.
2404 xsltLREInfoCreate(cctxt
, NULL
, 0);
2408 cctxt
->inode
= inode
;
2410 * REVISIT TODO: Keep the reset always complete.
2411 * NOTE: Be carefull with the @node, since it might be
2415 inode
->depth
= cctxt
->depth
;
2416 inode
->templ
= NULL
;
2417 inode
->category
= XSLT_ELEMENT_CATEGORY_XSLT
;
2420 inode
->curChildType
= 0;
2421 inode
->extContentHandled
= 0;
2424 if (inode
->prev
!= NULL
) {
2425 iprev
= inode
->prev
;
2427 * Inherit the following information:
2428 * ---------------------------------
2430 * In-scope namespaces
2432 inode
->inScopeNs
= iprev
->inScopeNs
;
2434 * Info for literal result elements
2436 inode
->litResElemInfo
= iprev
->litResElemInfo
;
2437 inode
->nsChanged
= iprev
->nsChanged
;
2439 * Excluded result namespaces
2441 inode
->exclResultNs
= iprev
->exclResultNs
;
2443 * Extension instruction namespaces
2445 inode
->extElemNs
= iprev
->extElemNs
;
2447 * Whitespace preservation
2449 inode
->preserveWhitespace
= iprev
->preserveWhitespace
;
2451 * Forwards-compatible mode
2453 inode
->forwardsCompat
= iprev
->forwardsCompat
;
2455 inode
->inScopeNs
= NULL
;
2456 inode
->exclResultNs
= NULL
;
2457 inode
->extElemNs
= NULL
;
2458 inode
->preserveWhitespace
= 0;
2459 inode
->forwardsCompat
= 0;
2466 * xsltCompilerNodePop:
2468 * @cctxt: the compilation context
2469 * @node: the node to be pushed (this can also be the doc-node)
2471 * Pops the current node info.
2474 xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2476 if (cctxt
->inode
== NULL
) {
2477 xmlGenericError(xmlGenericErrorContext
,
2478 "xsltCompilerNodePop: Top-node mismatch.\n");
2482 * NOTE: Be carefull with the @node, since it might be
2485 if (cctxt
->inode
->node
!= node
) {
2486 xmlGenericError(xmlGenericErrorContext
,
2487 "xsltCompilerNodePop: Node mismatch.\n");
2490 if (cctxt
->inode
->depth
!= cctxt
->depth
) {
2491 xmlGenericError(xmlGenericErrorContext
,
2492 "xsltCompilerNodePop: Depth mismatch.\n");
2497 * Pop information of variables.
2499 if ((cctxt
->ivar
) && (cctxt
->ivar
->depth
> cctxt
->depth
))
2500 xsltCompilerVarInfoPop(cctxt
);
2502 cctxt
->inode
= cctxt
->inode
->prev
;
2503 if (cctxt
->inode
!= NULL
)
2504 cctxt
->inode
->curChildType
= 0;
2509 const xmlChar
*nsName
= NULL
, *name
= NULL
;
2510 const xmlChar
*infnsName
= NULL
, *infname
= NULL
;
2513 if (node
->type
== XML_ELEMENT_NODE
) {
2515 if (node
->ns
!= NULL
)
2516 nsName
= node
->ns
->href
;
2518 nsName
= BAD_CAST
"";
2520 name
= BAD_CAST
"#document";
2521 nsName
= BAD_CAST
"";
2524 name
= BAD_CAST
"Not given";
2526 if (cctxt
->inode
->node
) {
2527 if (node
->type
== XML_ELEMENT_NODE
) {
2528 infname
= cctxt
->inode
->node
->name
;
2529 if (cctxt
->inode
->node
->ns
!= NULL
)
2530 infnsName
= cctxt
->inode
->node
->ns
->href
;
2532 infnsName
= BAD_CAST
"";
2534 infname
= BAD_CAST
"#document";
2535 infnsName
= BAD_CAST
"";
2538 infname
= BAD_CAST
"Not given";
2541 xmlGenericError(xmlGenericErrorContext
,
2542 "xsltCompilerNodePop: Given : '%s' URI '%s'\n",
2544 xmlGenericError(xmlGenericErrorContext
,
2545 "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
2546 infname
, infnsName
);
2551 * xsltCompilerBuildInScopeNsList:
2553 * Create and store the list of in-scope namespaces for the given
2554 * node in the stylesheet. If there are no changes in the in-scope
2555 * namespaces then the last ns-info of the ancestor axis will be returned.
2556 * Compilation-time only.
2558 * Returns the ns-info or NULL if there are no namespaces in scope.
2560 static xsltNsListContainerPtr
2561 xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2563 xsltNsListContainerPtr nsi
= NULL
;
2564 xmlNsPtr
*list
= NULL
, ns
;
2567 * Create a new ns-list for this position in the node-tree.
2568 * xmlGetNsList() will return NULL, if there are no ns-decls in the
2569 * tree. Note that the ns-decl for the XML namespace is not added
2570 * to the resulting list; the XPath module handles the XML namespace
2573 while (node
!= NULL
) {
2574 if (node
->type
== XML_ELEMENT_NODE
) {
2576 while (ns
!= NULL
) {
2578 nsi
= (xsltNsListContainerPtr
)
2579 xmlMalloc(sizeof(xsltNsListContainer
));
2581 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2582 "xsltCompilerBuildInScopeNsList: "
2583 "malloc failed!\n");
2586 memset(nsi
, 0, sizeof(xsltNsListContainer
));
2588 (xmlNsPtr
*) xmlMalloc(maxns
* sizeof(xmlNsPtr
));
2589 if (nsi
->list
== NULL
) {
2590 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2591 "xsltCompilerBuildInScopeNsList: "
2592 "malloc failed!\n");
2595 nsi
->list
[0] = NULL
;
2598 * Skip shadowed namespace bindings.
2600 for (i
= 0; i
< nsi
->totalNumber
; i
++) {
2601 if ((ns
->prefix
== nsi
->list
[i
]->prefix
) ||
2602 (xmlStrEqual(ns
->prefix
, nsi
->list
[i
]->prefix
)))
2605 if (i
>= nsi
->totalNumber
) {
2606 if (nsi
->totalNumber
+1 >= maxns
) {
2609 (xmlNsPtr
*) xmlRealloc(nsi
->list
,
2610 maxns
* sizeof(xmlNsPtr
));
2611 if (nsi
->list
== NULL
) {
2612 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2613 "xsltCompilerBuildInScopeNsList: "
2614 "realloc failed!\n");
2618 nsi
->list
[nsi
->totalNumber
++] = ns
;
2619 nsi
->list
[nsi
->totalNumber
] = NULL
;
2625 node
= node
->parent
;
2630 * Move the default namespace to last position.
2632 nsi
->xpathNumber
= nsi
->totalNumber
;
2633 for (i
= 0; i
< nsi
->totalNumber
; i
++) {
2634 if (nsi
->list
[i
]->prefix
== NULL
) {
2636 nsi
->list
[i
] = nsi
->list
[nsi
->totalNumber
-1];
2637 nsi
->list
[nsi
->totalNumber
-1] = ns
;
2643 * Store the ns-list in the stylesheet.
2645 if (xsltPointerListAddSize(
2646 (xsltPointerListPtr
)cctxt
->psData
->inScopeNamespaces
,
2647 (void *) nsi
, 5) == -1)
2651 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2652 "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
2656 * Notify of change in status wrt namespaces.
2658 if (cctxt
->inode
!= NULL
)
2659 cctxt
->inode
->nsChanged
= 1;
2666 cctxt
->style
->errors
++;
2671 xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt
,
2672 xsltPointerListPtr list
,
2674 const xmlChar
*value
)
2679 if ((cctxt
== NULL
) || (value
== NULL
) || (list
== NULL
))
2684 cur
= (xmlChar
*) value
;
2686 while (IS_BLANK(*cur
)) cur
++;
2690 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
2691 cur
= xmlStrndup(cur
, end
- cur
);
2697 * TODO: Export and use xmlSearchNsByPrefixStrict()
2698 * in Libxml2, tree.c, since xmlSearchNs() is in most
2699 * cases not efficient and in some cases not correct.
2701 * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
2703 if ((cur
[0] == '#') &&
2704 xmlStrEqual(cur
, (const xmlChar
*)"#default"))
2705 ns
= xmlSearchNs(cctxt
->style
->doc
, node
, NULL
);
2707 ns
= xmlSearchNs(cctxt
->style
->doc
, node
, cur
);
2711 * TODO: Better to report the attr-node, otherwise
2712 * the user won't know which attribute was invalid.
2714 xsltTransformError(NULL
, cctxt
->style
, node
,
2715 "No namespace binding in scope for prefix '%s'.\n", cur
);
2717 * XSLT-1.0: "It is an error if there is no namespace
2718 * bound to the prefix on the element bearing the
2719 * exclude-result-prefixes or xsl:exclude-result-prefixes
2722 cctxt
->style
->errors
++;
2724 #ifdef WITH_XSLT_DEBUG_PARSING
2725 xsltGenericDebug(xsltGenericDebugContext
,
2726 "resolved prefix '%s'\n", cur
);
2729 * Note that we put the namespace name into the dict.
2731 if (xsltPointerListAddSize(list
,
2732 (void *) xmlDictLookup(cctxt
->style
->dict
,
2733 ns
->href
, -1), 5) == -1)
2746 cctxt
->style
->errors
++;
2751 * xsltCompilerUtilsCreateMergedList:
2752 * @dest: the destination list (optional)
2753 * @first: the first list
2754 * @second: the second list (optional)
2756 * Appends the content of @second to @first into @destination.
2757 * If @destination is NULL a new list will be created.
2759 * Returns the merged list of items or NULL if there's nothing to merge.
2761 static xsltPointerListPtr
2762 xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first
,
2763 xsltPointerListPtr second
)
2765 xsltPointerListPtr ret
;
2769 num
= first
->number
;
2773 num
+= second
->number
;
2776 ret
= xsltPointerListCreate(num
);
2782 if ((first
!= NULL
) && (first
->number
!= 0)) {
2783 memcpy(ret
->items
, first
->items
,
2784 first
->number
* sizeof(void *));
2785 if ((second
!= NULL
) && (second
->number
!= 0))
2786 memcpy(ret
->items
+ first
->number
, second
->items
,
2787 second
->number
* sizeof(void *));
2788 } else if ((second
!= NULL
) && (second
->number
!= 0))
2789 memcpy(ret
->items
, (void *) second
->items
,
2790 second
->number
* sizeof(void *));
2796 * xsltParseExclResultPrefixes:
2798 * Create and store the list of in-scope namespaces for the given
2799 * node in the stylesheet. If there are no changes in the in-scope
2800 * namespaces then the last ns-info of the ancestor axis will be returned.
2801 * Compilation-time only.
2803 * Returns the ns-info or NULL if there are no namespaces in scope.
2805 static xsltPointerListPtr
2806 xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2807 xsltPointerListPtr def
,
2810 xsltPointerListPtr list
= NULL
;
2814 if ((cctxt
== NULL
) || (node
== NULL
))
2817 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2818 attr
= xmlHasNsProp(node
, BAD_CAST
"exclude-result-prefixes", NULL
);
2820 attr
= xmlHasNsProp(node
, BAD_CAST
"exclude-result-prefixes",
2825 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
2827 * Mark the XSLT attr.
2829 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2832 if ((attr
->children
!= NULL
) &&
2833 (attr
->children
->content
!= NULL
))
2834 value
= attr
->children
->content
;
2836 xsltTransformError(NULL
, cctxt
->style
, node
,
2837 "Attribute 'exclude-result-prefixes': Invalid value.\n");
2838 cctxt
->style
->errors
++;
2842 if (xsltParseNsPrefixList(cctxt
, cctxt
->tmpList
, node
,
2843 BAD_CAST value
) != 0)
2845 if (cctxt
->tmpList
->number
== 0)
2848 * Merge the list with the inherited list.
2850 list
= xsltCompilerUtilsCreateMergedList(def
, cctxt
->tmpList
);
2854 * Store the list in the stylesheet/compiler context.
2856 if (xsltPointerListAddSize(
2857 cctxt
->psData
->exclResultNamespaces
, list
, 5) == -1)
2859 xsltPointerListFree(list
);
2864 * Notify of change in status wrt namespaces.
2866 if (cctxt
->inode
!= NULL
)
2867 cctxt
->inode
->nsChanged
= 1;
2877 * xsltParseExtElemPrefixes:
2879 * Create and store the list of in-scope namespaces for the given
2880 * node in the stylesheet. If there are no changes in the in-scope
2881 * namespaces then the last ns-info of the ancestor axis will be returned.
2882 * Compilation-time only.
2884 * Returns the ns-info or NULL if there are no namespaces in scope.
2886 static xsltPointerListPtr
2887 xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2888 xsltPointerListPtr def
,
2891 xsltPointerListPtr list
= NULL
;
2896 if ((cctxt
== NULL
) || (node
== NULL
))
2899 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2900 attr
= xmlHasNsProp(node
, BAD_CAST
"extension-element-prefixes", NULL
);
2902 attr
= xmlHasNsProp(node
, BAD_CAST
"extension-element-prefixes",
2907 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
2909 * Mark the XSLT attr.
2911 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2914 if ((attr
->children
!= NULL
) &&
2915 (attr
->children
->content
!= NULL
))
2916 value
= attr
->children
->content
;
2918 xsltTransformError(NULL
, cctxt
->style
, node
,
2919 "Attribute 'extension-element-prefixes': Invalid value.\n");
2920 cctxt
->style
->errors
++;
2925 if (xsltParseNsPrefixList(cctxt
, cctxt
->tmpList
, node
,
2926 BAD_CAST value
) != 0)
2929 if (cctxt
->tmpList
->number
== 0)
2932 * REVISIT: Register the extension namespaces.
2934 for (i
= 0; i
< cctxt
->tmpList
->number
; i
++)
2935 xsltRegisterExtPrefix(cctxt
->style
, NULL
,
2936 BAD_CAST cctxt
->tmpList
->items
[i
]);
2938 * Merge the list with the inherited list.
2940 list
= xsltCompilerUtilsCreateMergedList(def
, cctxt
->tmpList
);
2944 * Store the list in the stylesheet.
2946 if (xsltPointerListAddSize(
2947 cctxt
->psData
->extElemNamespaces
, list
, 5) == -1)
2949 xsltPointerListFree(list
);
2954 * Notify of change in status wrt namespaces.
2956 if (cctxt
->inode
!= NULL
)
2957 cctxt
->inode
->nsChanged
= 1;
2967 * xsltParseAttrXSLTVersion:
2969 * @cctxt: the compilation context
2970 * @node: the element-node
2971 * @isXsltElem: whether this is an XSLT element
2973 * Parses the attribute xsl:version.
2975 * Returns 1 if there was such an attribute, 0 if not and
2976 * -1 if an internal or API error occured.
2979 xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2985 if ((cctxt
== NULL
) || (node
== NULL
))
2988 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2989 attr
= xmlHasNsProp(node
, BAD_CAST
"version", NULL
);
2991 attr
= xmlHasNsProp(node
, BAD_CAST
"version", XSLT_NAMESPACE
);
2996 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2998 if ((attr
->children
!= NULL
) &&
2999 (attr
->children
->content
!= NULL
))
3000 value
= attr
->children
->content
;
3002 xsltTransformError(NULL
, cctxt
->style
, node
,
3003 "Attribute 'version': Invalid value.\n");
3004 cctxt
->style
->errors
++;
3008 if (! xmlStrEqual(value
, (const xmlChar
*)"1.0")) {
3009 cctxt
->inode
->forwardsCompat
= 1;
3011 * TODO: To what extent do we support the
3012 * forwards-compatible mode?
3015 * Report this only once per compilation episode.
3017 if (! cctxt
->hasForwardsCompat
) {
3018 cctxt
->hasForwardsCompat
= 1;
3019 cctxt
->errSeverity
= XSLT_ERROR_SEVERITY_WARNING
;
3020 xsltTransformError(NULL
, cctxt
->style
, node
,
3021 "Warning: the attribute xsl:version specifies a value "
3022 "different from '1.0'. Switching to forwards-compatible "
3023 "mode. Only features of XSLT 1.0 are supported by this "
3025 cctxt
->style
->warnings
++;
3026 cctxt
->errSeverity
= XSLT_ERROR_SEVERITY_ERROR
;
3029 cctxt
->inode
->forwardsCompat
= 0;
3032 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
3034 * Set a marker on XSLT attributes.
3036 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
3042 xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
3044 xmlNodePtr deleteNode
, cur
, txt
, textNode
= NULL
;
3046 xsltStylesheetPtr style
;
3047 int internalize
= 0, findSpaceAttr
;
3048 int xsltStylesheetElemDepth
;
3051 const xmlChar
*name
, *nsNameXSLT
= NULL
;
3052 int strictWhitespace
, inXSLText
= 0;
3053 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3054 xsltNsMapPtr nsMapItem
;
3057 if ((cctxt
== NULL
) || (cctxt
->style
== NULL
) ||
3058 (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
3065 style
= cctxt
->style
;
3066 if ((style
->dict
!= NULL
) && (doc
->dict
== style
->dict
))
3069 style
->internalized
= 0;
3072 * Init value of xml:space. Since this might be an embedded
3073 * stylesheet, this is needed to be performed on the element
3074 * where the stylesheet is rooted at, taking xml:space of
3075 * ancestors into account.
3077 if (! cctxt
->simplified
)
3078 xsltStylesheetElemDepth
= cctxt
->depth
+1;
3080 xsltStylesheetElemDepth
= 0;
3082 if (xmlNodeGetSpacePreserve(node
) != 1)
3083 cctxt
->inode
->preserveWhitespace
= 0;
3085 cctxt
->inode
->preserveWhitespace
= 1;
3088 * Eval if we should keep the old incorrect behaviour.
3090 strictWhitespace
= (cctxt
->strict
!= 0) ? 1 : 0;
3092 nsNameXSLT
= xsltConstNamespaceNameXSLT
;
3096 while (cur
!= NULL
) {
3097 if (deleteNode
!= NULL
) {
3099 #ifdef WITH_XSLT_DEBUG_BLANKS
3100 xsltGenericDebug(xsltGenericDebugContext
,
3101 "xsltParsePreprocessStylesheetTree: removing node\n");
3103 xmlUnlinkNode(deleteNode
);
3104 xmlFreeNode(deleteNode
);
3107 if (cur
->type
== XML_ELEMENT_NODE
) {
3110 * Clear the PSVI field.
3114 xsltCompilerNodePush(cctxt
, cur
);
3119 cctxt
->inode
->stripWhitespace
= 0;
3121 * TODO: I'd love to use a string pointer comparison here :-/
3123 if (IS_XSLT_ELEM(cur
)) {
3124 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3125 if (cur
->ns
->href
!= nsNameXSLT
) {
3126 nsMapItem
= xsltNewNamespaceMapItem(cctxt
,
3128 if (nsMapItem
== NULL
)
3130 cur
->ns
->href
= nsNameXSLT
;
3134 if (cur
->name
== NULL
)
3135 goto process_attributes
;
3137 * Mark the XSLT element for later recognition.
3138 * TODO: Using the marker is still too dangerous, since if
3139 * the parsing mechanism leaves out an XSLT element, then
3140 * this might hit the transformation-mechanism, which
3141 * will break if it doesn't expect such a marker.
3143 /* cur->psvi = (void *) xsltXSLTElemMarker; */
3146 * XSLT 2.0: "Any whitespace text node whose parent is
3147 * one of the following elements is removed from the "
3148 * tree, regardless of any xml:space attributes:..."
3149 * xsl:apply-imports,
3150 * xsl:apply-templates,
3151 * xsl:attribute-set,
3152 * xsl:call-template,
3154 * xsl:stylesheet, xsl:transform.
3155 * XSLT 2.0: xsl:analyze-string,
3156 * xsl:character-map,
3159 * TODO: I'd love to use a string pointer comparison here :-/
3164 if ((name
[0] == 't') && (name
[1] == 'e') &&
3165 (name
[2] == 'x') && (name
[3] == 't') &&
3169 * Process the xsl:text element.
3170 * ----------------------------
3171 * Mark it for later recognition.
3173 cur
->psvi
= (void *) xsltXSLTTextMarker
;
3175 * For stylesheets, the set of
3176 * whitespace-preserving element names
3177 * consists of just xsl:text.
3180 cctxt
->inode
->preserveWhitespace
= 1;
3185 if (xmlStrEqual(name
, BAD_CAST
"choose") ||
3186 xmlStrEqual(name
, BAD_CAST
"call-template"))
3187 cctxt
->inode
->stripWhitespace
= 1;
3190 if (xmlStrEqual(name
, BAD_CAST
"apply-templates") ||
3191 xmlStrEqual(name
, BAD_CAST
"apply-imports") ||
3192 xmlStrEqual(name
, BAD_CAST
"attribute-set"))
3194 cctxt
->inode
->stripWhitespace
= 1;
3197 if (xsltStylesheetElemDepth
== cctxt
->depth
) {
3199 * This is a xsl:stylesheet/xsl:transform.
3201 cctxt
->inode
->stripWhitespace
= 1;
3205 if ((cur
->prev
!= NULL
) &&
3206 (cur
->prev
->type
== XML_TEXT_NODE
))
3209 * XSLT 2.0 : "Any whitespace text node whose
3210 * following-sibling node is an xsl:param or
3211 * xsl:sort element is removed from the tree,
3212 * regardless of any xml:space attributes."
3214 if (((*name
== 'p') || (*name
== 's')) &&
3215 (xmlStrEqual(name
, BAD_CAST
"param") ||
3216 xmlStrEqual(name
, BAD_CAST
"sort")))
3219 if (IS_BLANK_NODE(cur
->prev
)) {
3225 * This will result in a content
3226 * error, when hitting the parsing
3231 } while (cur
->prev
);
3240 * Process attributes.
3241 * ------------------
3243 if (cur
->properties
!= NULL
) {
3244 if (cur
->children
== NULL
)
3246 attr
= cur
->properties
;
3248 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3249 if ((attr
->ns
) && (attr
->ns
->href
!= nsNameXSLT
) &&
3250 xmlStrEqual(attr
->ns
->href
, nsNameXSLT
))
3252 nsMapItem
= xsltNewNamespaceMapItem(cctxt
,
3253 doc
, attr
->ns
, cur
);
3254 if (nsMapItem
== NULL
)
3256 attr
->ns
->href
= nsNameXSLT
;
3261 * Internalize the attribute's value; the goal is to
3262 * speed up operations and minimize used space by
3263 * compiled stylesheets.
3265 txt
= attr
->children
;
3267 * NOTE that this assumes only one
3268 * text-node in the attribute's content.
3270 if ((txt
!= NULL
) && (txt
->content
!= NULL
) &&
3271 (!xmlDictOwns(style
->dict
, txt
->content
)))
3273 value
= (xmlChar
*) xmlDictLookup(style
->dict
,
3275 xmlNodeSetContent(txt
, NULL
);
3276 txt
->content
= value
;
3280 * Process xml:space attributes.
3281 * ----------------------------
3283 if ((findSpaceAttr
!= 0) &&
3284 (attr
->ns
!= NULL
) &&
3285 (attr
->name
!= NULL
) &&
3286 (attr
->name
[0] == 's') &&
3287 (attr
->ns
->prefix
!= NULL
) &&
3288 (attr
->ns
->prefix
[0] == 'x') &&
3289 (attr
->ns
->prefix
[1] == 'm') &&
3290 (attr
->ns
->prefix
[2] == 'l') &&
3291 (attr
->ns
->prefix
[3] == 0))
3293 value
= xmlGetNsProp(cur
, BAD_CAST
"space",
3295 if (value
!= NULL
) {
3296 if (xmlStrEqual(value
, BAD_CAST
"preserve")) {
3297 cctxt
->inode
->preserveWhitespace
= 1;
3298 } else if (xmlStrEqual(value
, BAD_CAST
"default")) {
3299 cctxt
->inode
->preserveWhitespace
= 0;
3301 /* Invalid value for xml:space. */
3302 xsltTransformError(NULL
, style
, cur
,
3303 "Attribute xml:space: Invalid value.\n");
3304 cctxt
->style
->warnings
++;
3312 } while (attr
!= NULL
);
3315 * We'll descend into the children of element nodes only.
3317 if (cur
->children
!= NULL
) {
3318 cur
= cur
->children
;
3321 } else if ((cur
->type
== XML_TEXT_NODE
) ||
3322 (cur
->type
== XML_CDATA_SECTION_NODE
))
3325 * Merge adjacent text/CDATA-section-nodes
3326 * ---------------------------------------
3327 * In order to avoid breaking of existing stylesheets,
3328 * if the old behaviour is wanted (strictWhitespace == 0),
3329 * then we *won't* merge adjacent text-nodes
3330 * (except in xsl:text); this will ensure that whitespace-only
3331 * text nodes are (incorrectly) not stripped in some cases.
3333 * Example: : <foo> <!-- bar -->zoo</foo>
3334 * Corrent (strict) result: <foo> zoo</foo>
3335 * Incorrect (old) result : <foo>zoo</foo>
3337 * NOTE that we *will* merge adjacent text-nodes if
3338 * they are in xsl:text.
3339 * Example, the following:
3340 * <xsl:text> <!-- bar -->zoo<xsl:text>
3341 * will result in both cases in:
3342 * <xsl:text> zoo<xsl:text>
3344 cur
->type
= XML_TEXT_NODE
;
3345 if ((strictWhitespace
!= 0) || (inXSLText
!= 0)) {
3347 * New behaviour; merge nodes.
3349 if (textNode
== NULL
)
3352 if (cur
->content
!= NULL
)
3353 xmlNodeAddContent(textNode
, cur
->content
);
3356 if ((cur
->next
== NULL
) ||
3357 (cur
->next
->type
== XML_ELEMENT_NODE
))
3365 if (textNode
== NULL
)
3369 } else if ((cur
->type
== XML_COMMENT_NODE
) ||
3370 (cur
->type
== XML_PI_NODE
))
3373 * Remove processing instructions and comments.
3376 if ((cur
->next
== NULL
) ||
3377 (cur
->next
->type
== XML_ELEMENT_NODE
))
3384 * Invalid node-type for this data-model.
3386 xsltTransformError(NULL
, style
, cur
,
3387 "Invalid type of node for the XSLT data model.\n");
3388 cctxt
->style
->errors
++;
3394 value
= textNode
->content
;
3396 * At this point all adjacent text/CDATA-section nodes
3399 * Strip whitespace-only text-nodes.
3400 * (cctxt->inode->stripWhitespace)
3402 if ((value
== NULL
) || (*value
== 0) ||
3403 (((cctxt
->inode
->stripWhitespace
) ||
3404 (! cctxt
->inode
->preserveWhitespace
)) &&
3406 xsltIsBlank(value
)))
3408 if (textNode
!= cur
) {
3409 xmlUnlinkNode(textNode
);
3410 xmlFreeNode(textNode
);
3412 deleteNode
= textNode
;
3417 * Convert CDATA-section nodes to text-nodes.
3418 * TODO: Can this produce problems?
3420 if (textNode
->type
!= XML_TEXT_NODE
) {
3421 textNode
->type
= XML_TEXT_NODE
;
3422 textNode
->name
= xmlStringText
;
3425 (textNode
->content
!= NULL
) &&
3426 (!xmlDictOwns(style
->dict
, textNode
->content
)))
3429 * Internalize the string.
3431 value
= (xmlChar
*) xmlDictLookup(style
->dict
,
3432 textNode
->content
, -1);
3433 xmlNodeSetContent(textNode
, NULL
);
3434 textNode
->content
= value
;
3438 * Note that "disable-output-escaping" of the xsl:text
3439 * element will be applied at a later level, when
3440 * XSLT elements are processed.
3445 if (cur
->type
== XML_ELEMENT_NODE
) {
3446 xsltCompilerNodePop(cctxt
, cur
);
3450 if (cur
->next
!= NULL
) {
3458 if (deleteNode
!= NULL
) {
3459 #ifdef WITH_XSLT_DEBUG_PARSING
3460 xsltGenericDebug(xsltGenericDebugContext
,
3461 "xsltParsePreprocessStylesheetTree: removing node\n");
3463 xmlUnlinkNode(deleteNode
);
3464 xmlFreeNode(deleteNode
);
3472 #endif /* XSLT_REFACTORED */
3474 #ifdef XSLT_REFACTORED
3477 xsltPreprocessStylesheet(xsltStylesheetPtr style
, xmlNodePtr cur
)
3479 xmlNodePtr deleteNode
, styleelem
;
3480 int internalize
= 0;
3482 if ((style
== NULL
) || (cur
== NULL
))
3485 if ((cur
->doc
!= NULL
) && (style
->dict
!= NULL
) &&
3486 (cur
->doc
->dict
== style
->dict
))
3489 style
->internalized
= 0;
3491 if ((cur
!= NULL
) && (IS_XSLT_ELEM(cur
)) &&
3492 (IS_XSLT_NAME(cur
, "stylesheet"))) {
3499 * This content comes from the stylesheet
3500 * For stylesheets, the set of whitespace-preserving
3501 * element names consists of just xsl:text.
3504 while (cur
!= NULL
) {
3505 if (deleteNode
!= NULL
) {
3506 #ifdef WITH_XSLT_DEBUG_BLANKS
3507 xsltGenericDebug(xsltGenericDebugContext
,
3508 "xsltPreprocessStylesheet: removing ignorable blank node\n");
3510 xmlUnlinkNode(deleteNode
);
3511 xmlFreeNode(deleteNode
);
3514 if (cur
->type
== XML_ELEMENT_NODE
) {
3517 * Internalize attributes values.
3519 if ((internalize
) && (cur
->properties
!= NULL
)) {
3520 xmlAttrPtr attr
= cur
->properties
;
3523 while (attr
!= NULL
) {
3524 txt
= attr
->children
;
3525 if ((txt
!= NULL
) && (txt
->type
== XML_TEXT_NODE
) &&
3526 (txt
->content
!= NULL
) &&
3527 (!xmlDictOwns(style
->dict
, txt
->content
)))
3532 * internalize the text string, goal is to speed
3533 * up operations and minimize used space by compiled
3536 tmp
= (xmlChar
*) xmlDictLookup(style
->dict
,
3538 if (tmp
!= txt
->content
) {
3539 xmlNodeSetContent(txt
, NULL
);
3546 if (IS_XSLT_ELEM(cur
)) {
3548 if (IS_XSLT_NAME(cur
, "text")) {
3549 for (;exclPrefixes
> 0;exclPrefixes
--)
3550 exclPrefixPop(style
);
3554 exclPrefixes
= xsltParseStylesheetExcludePrefix(style
, cur
, 0);
3557 if ((cur
->nsDef
!= NULL
) && (style
->exclPrefixNr
> 0)) {
3558 xmlNsPtr ns
= cur
->nsDef
, prev
= NULL
, next
;
3559 xmlNodePtr root
= NULL
;
3562 root
= xmlDocGetRootElement(cur
->doc
);
3563 if ((root
!= NULL
) && (root
!= cur
)) {
3564 while (ns
!= NULL
) {
3567 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
3568 if ((ns
->prefix
!= NULL
) &&
3569 (xmlStrEqual(ns
->href
,
3570 style
->exclPrefixTab
[i
]))) {
3572 * Move the namespace definition on the root
3573 * element to avoid duplicating it without
3577 cur
->nsDef
= ns
->next
;
3579 prev
->next
= ns
->next
;
3581 ns
->next
= root
->nsDef
;
3594 * If we have prefixes locally, recurse and pop them up when
3597 if (exclPrefixes
> 0) {
3598 xsltPreprocessStylesheet(style
, cur
->children
);
3599 for (;exclPrefixes
> 0;exclPrefixes
--)
3600 exclPrefixPop(style
);
3603 } else if (cur
->type
== XML_TEXT_NODE
) {
3604 if (IS_BLANK_NODE(cur
)) {
3605 if (xmlNodeGetSpacePreserve(cur
->parent
) != 1) {
3608 } else if ((cur
->content
!= NULL
) && (internalize
) &&
3609 (!xmlDictOwns(style
->dict
, cur
->content
))) {
3613 * internalize the text string, goal is to speed
3614 * up operations and minimize used space by compiled
3617 tmp
= (xmlChar
*) xmlDictLookup(style
->dict
, cur
->content
, -1);
3618 xmlNodeSetContent(cur
, NULL
);
3621 } else if ((cur
->type
!= XML_ELEMENT_NODE
) &&
3622 (cur
->type
!= XML_CDATA_SECTION_NODE
)) {
3628 * Skip to next node. In case of a namespaced element children of
3629 * the stylesheet and not in the XSLT namespace and not an extension
3630 * element, ignore its content.
3632 if ((cur
->type
== XML_ELEMENT_NODE
) && (cur
->ns
!= NULL
) &&
3633 (styleelem
!= NULL
) && (cur
->parent
== styleelem
) &&
3634 (!xmlStrEqual(cur
->ns
->href
, XSLT_NAMESPACE
)) &&
3635 (!xsltCheckExtURI(style
, cur
->ns
->href
))) {
3637 } else if (cur
->children
!= NULL
) {
3638 cur
= cur
->children
;
3643 if (cur
->next
!= NULL
) {
3652 if (cur
== (xmlNodePtr
) style
->doc
) {
3656 if (cur
->next
!= NULL
) {
3660 } while (cur
!= NULL
);
3662 if (deleteNode
!= NULL
) {
3663 #ifdef WITH_XSLT_DEBUG_PARSING
3664 xsltGenericDebug(xsltGenericDebugContext
,
3665 "xsltPreprocessStylesheet: removing ignorable blank node\n");
3667 xmlUnlinkNode(deleteNode
);
3668 xmlFreeNode(deleteNode
);
3671 #endif /* end of else XSLT_REFACTORED */
3674 * xsltGatherNamespaces:
3675 * @style: the XSLT stylesheet
3677 * Browse the stylesheet and build the namspace hash table which
3678 * will be used for XPath interpretation. If needed do a bit of normalization
3682 xsltGatherNamespaces(xsltStylesheetPtr style
) {
3689 * TODO: basically if the stylesheet uses the same prefix for different
3690 * patterns, well they may be in problem, hopefully they will get
3694 * TODO: Eliminate the use of the hash for XPath expressions.
3695 * An expression should be evaluated in the context of the in-scope
3696 * namespaces; eliminate the restriction of an XML document to contain
3697 * no duplicate prefixes for different namespace names.
3700 cur
= xmlDocGetRootElement(style
->doc
);
3701 while (cur
!= NULL
) {
3702 if (cur
->type
== XML_ELEMENT_NODE
) {
3703 xmlNsPtr ns
= cur
->nsDef
;
3704 while (ns
!= NULL
) {
3705 if (ns
->prefix
!= NULL
) {
3706 if (style
->nsHash
== NULL
) {
3707 style
->nsHash
= xmlHashCreate(10);
3708 if (style
->nsHash
== NULL
) {
3709 xsltTransformError(NULL
, style
, cur
,
3710 "xsltGatherNamespaces: failed to create hash table\n");
3715 URI
= xmlHashLookup(style
->nsHash
, ns
->prefix
);
3716 if ((URI
!= NULL
) && (!xmlStrEqual(URI
, ns
->href
))) {
3717 xsltTransformError(NULL
, style
, cur
,
3718 "Namespaces prefix %s used for multiple namespaces\n",ns
->prefix
);
3720 } else if (URI
== NULL
) {
3721 xmlHashUpdateEntry(style
->nsHash
, ns
->prefix
,
3722 (void *) ns
->href
, NULL
);
3724 #ifdef WITH_XSLT_DEBUG_PARSING
3725 xsltGenericDebug(xsltGenericDebugContext
,
3726 "Added namespace: %s mapped to %s\n", ns
->prefix
, ns
->href
);
3737 if (cur
->children
!= NULL
) {
3738 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
3739 cur
= cur
->children
;
3743 if (cur
->next
!= NULL
) {
3752 if (cur
== (xmlNodePtr
) style
->doc
) {
3756 if (cur
->next
!= NULL
) {
3760 } while (cur
!= NULL
);
3764 #ifdef XSLT_REFACTORED
3766 static xsltStyleType
3767 xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt
,
3770 if ((node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
) ||
3771 (node
->name
== NULL
))
3774 if (node
->name
[0] == 'a') {
3775 if (IS_XSLT_NAME(node
, "apply-templates"))
3776 return(XSLT_FUNC_APPLYTEMPLATES
);
3777 else if (IS_XSLT_NAME(node
, "attribute"))
3778 return(XSLT_FUNC_ATTRIBUTE
);
3779 else if (IS_XSLT_NAME(node
, "apply-imports"))
3780 return(XSLT_FUNC_APPLYIMPORTS
);
3781 else if (IS_XSLT_NAME(node
, "attribute-set"))
3784 } else if (node
->name
[0] == 'c') {
3785 if (IS_XSLT_NAME(node
, "choose"))
3786 return(XSLT_FUNC_CHOOSE
);
3787 else if (IS_XSLT_NAME(node
, "copy"))
3788 return(XSLT_FUNC_COPY
);
3789 else if (IS_XSLT_NAME(node
, "copy-of"))
3790 return(XSLT_FUNC_COPYOF
);
3791 else if (IS_XSLT_NAME(node
, "call-template"))
3792 return(XSLT_FUNC_CALLTEMPLATE
);
3793 else if (IS_XSLT_NAME(node
, "comment"))
3794 return(XSLT_FUNC_COMMENT
);
3796 } else if (node
->name
[0] == 'd') {
3797 if (IS_XSLT_NAME(node
, "document"))
3798 return(XSLT_FUNC_DOCUMENT
);
3799 else if (IS_XSLT_NAME(node
, "decimal-format"))
3802 } else if (node
->name
[0] == 'e') {
3803 if (IS_XSLT_NAME(node
, "element"))
3804 return(XSLT_FUNC_ELEMENT
);
3806 } else if (node
->name
[0] == 'f') {
3807 if (IS_XSLT_NAME(node
, "for-each"))
3808 return(XSLT_FUNC_FOREACH
);
3809 else if (IS_XSLT_NAME(node
, "fallback"))
3810 return(XSLT_FUNC_FALLBACK
);
3812 } else if (*(node
->name
) == 'i') {
3813 if (IS_XSLT_NAME(node
, "if"))
3814 return(XSLT_FUNC_IF
);
3815 else if (IS_XSLT_NAME(node
, "include"))
3817 else if (IS_XSLT_NAME(node
, "import"))
3820 } else if (*(node
->name
) == 'k') {
3821 if (IS_XSLT_NAME(node
, "key"))
3824 } else if (*(node
->name
) == 'm') {
3825 if (IS_XSLT_NAME(node
, "message"))
3826 return(XSLT_FUNC_MESSAGE
);
3828 } else if (*(node
->name
) == 'n') {
3829 if (IS_XSLT_NAME(node
, "number"))
3830 return(XSLT_FUNC_NUMBER
);
3831 else if (IS_XSLT_NAME(node
, "namespace-alias"))
3834 } else if (*(node
->name
) == 'o') {
3835 if (IS_XSLT_NAME(node
, "otherwise"))
3836 return(XSLT_FUNC_OTHERWISE
);
3837 else if (IS_XSLT_NAME(node
, "output"))
3840 } else if (*(node
->name
) == 'p') {
3841 if (IS_XSLT_NAME(node
, "param"))
3842 return(XSLT_FUNC_PARAM
);
3843 else if (IS_XSLT_NAME(node
, "processing-instruction"))
3844 return(XSLT_FUNC_PI
);
3845 else if (IS_XSLT_NAME(node
, "preserve-space"))
3848 } else if (*(node
->name
) == 's') {
3849 if (IS_XSLT_NAME(node
, "sort"))
3850 return(XSLT_FUNC_SORT
);
3851 else if (IS_XSLT_NAME(node
, "strip-space"))
3853 else if (IS_XSLT_NAME(node
, "stylesheet"))
3856 } else if (node
->name
[0] == 't') {
3857 if (IS_XSLT_NAME(node
, "text"))
3858 return(XSLT_FUNC_TEXT
);
3859 else if (IS_XSLT_NAME(node
, "template"))
3861 else if (IS_XSLT_NAME(node
, "transform"))
3864 } else if (*(node
->name
) == 'v') {
3865 if (IS_XSLT_NAME(node
, "value-of"))
3866 return(XSLT_FUNC_VALUEOF
);
3867 else if (IS_XSLT_NAME(node
, "variable"))
3868 return(XSLT_FUNC_VARIABLE
);
3870 } else if (*(node
->name
) == 'w') {
3871 if (IS_XSLT_NAME(node
, "when"))
3872 return(XSLT_FUNC_WHEN
);
3873 if (IS_XSLT_NAME(node
, "with-param"))
3874 return(XSLT_FUNC_WITHPARAM
);
3880 * xsltParseAnyXSLTElem:
3882 * @cctxt: the compilation context
3883 * @elem: the element node of the XSLT instruction
3885 * Parses, validates the content models and compiles XSLT instructions.
3887 * Returns 0 if everything's fine;
3888 * -1 on API or internal errors.
3891 xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr elem
)
3893 if ((cctxt
== NULL
) || (elem
== NULL
) ||
3894 (elem
->type
!= XML_ELEMENT_NODE
))
3899 if (! (IS_XSLT_ELEM_FAST(elem
)))
3902 * Detection of handled content of extension instructions.
3904 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
3905 cctxt
->inode
->extContentHandled
= 1;
3908 xsltCompilerNodePush(cctxt
, elem
);
3910 * URGENT TODO: Find a way to speed up this annoying redundant
3911 * textual node-name and namespace comparison.
3913 if (cctxt
->inode
->prev
->curChildType
!= 0)
3914 cctxt
->inode
->type
= cctxt
->inode
->prev
->curChildType
;
3916 cctxt
->inode
->type
= xsltGetXSLTElementTypeByNode(cctxt
, elem
);
3918 * Update the in-scope namespaces if needed.
3920 if (elem
->nsDef
!= NULL
)
3921 cctxt
->inode
->inScopeNs
=
3922 xsltCompilerBuildInScopeNsList(cctxt
, elem
);
3924 * xsltStylePreCompute():
3925 * This will compile the information found on the current
3926 * element's attributes. NOTE that this won't process the
3927 * children of the instruction.
3929 xsltStylePreCompute(cctxt
->style
, elem
);
3931 * TODO: How to react on errors in xsltStylePreCompute() ?
3935 * Validate the content model of the XSLT-element.
3937 switch (cctxt
->inode
->type
) {
3938 case XSLT_FUNC_APPLYIMPORTS
:
3941 case XSLT_FUNC_APPLYTEMPLATES
:
3942 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
3943 goto apply_templates
;
3944 case XSLT_FUNC_ATTRIBUTE
:
3945 /* <!-- Content: template --> */
3946 goto sequence_constructor
;
3947 case XSLT_FUNC_CALLTEMPLATE
:
3948 /* <!-- Content: xsl:with-param* --> */
3950 case XSLT_FUNC_CHOOSE
:
3951 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
3953 case XSLT_FUNC_COMMENT
:
3954 /* <!-- Content: template --> */
3955 goto sequence_constructor
;
3956 case XSLT_FUNC_COPY
:
3957 /* <!-- Content: template --> */
3958 goto sequence_constructor
;
3959 case XSLT_FUNC_COPYOF
:
3962 case XSLT_FUNC_DOCUMENT
: /* Extra one */
3963 /* ?? template ?? */
3964 goto sequence_constructor
;
3965 case XSLT_FUNC_ELEMENT
:
3966 /* <!-- Content: template --> */
3967 goto sequence_constructor
;
3968 case XSLT_FUNC_FALLBACK
:
3969 /* <!-- Content: template --> */
3970 goto sequence_constructor
;
3971 case XSLT_FUNC_FOREACH
:
3972 /* <!-- Content: (xsl:sort*, template) --> */
3975 /* <!-- Content: template --> */
3976 goto sequence_constructor
;
3977 case XSLT_FUNC_OTHERWISE
:
3978 /* <!-- Content: template --> */
3979 goto sequence_constructor
;
3980 case XSLT_FUNC_MESSAGE
:
3981 /* <!-- Content: template --> */
3982 goto sequence_constructor
;
3983 case XSLT_FUNC_NUMBER
:
3986 case XSLT_FUNC_PARAM
:
3988 * Check for redefinition.
3990 if ((elem
->psvi
!= NULL
) && (cctxt
->ivar
!= NULL
)) {
3991 xsltVarInfoPtr ivar
= cctxt
->ivar
;
3995 ((xsltStyleItemParamPtr
) elem
->psvi
)->name
) &&
3997 ((xsltStyleItemParamPtr
) elem
->psvi
)->ns
))
4000 xsltTransformError(NULL
, cctxt
->style
, elem
,
4001 "Redefinition of variable or parameter '%s'.\n",
4003 cctxt
->style
->errors
++;
4007 } while (ivar
!= NULL
);
4009 /* <!-- Content: template --> */
4010 goto sequence_constructor
;
4012 /* <!-- Content: template --> */
4013 goto sequence_constructor
;
4014 case XSLT_FUNC_SORT
:
4017 case XSLT_FUNC_TEXT
:
4018 /* <!-- Content: #PCDATA --> */
4020 case XSLT_FUNC_VALUEOF
:
4023 case XSLT_FUNC_VARIABLE
:
4025 * Check for redefinition.
4027 if ((elem
->psvi
!= NULL
) && (cctxt
->ivar
!= NULL
)) {
4028 xsltVarInfoPtr ivar
= cctxt
->ivar
;
4032 ((xsltStyleItemVariablePtr
) elem
->psvi
)->name
) &&
4034 ((xsltStyleItemVariablePtr
) elem
->psvi
)->ns
))
4037 xsltTransformError(NULL
, cctxt
->style
, elem
,
4038 "Redefinition of variable or parameter '%s'.\n",
4040 cctxt
->style
->errors
++;
4044 } while (ivar
!= NULL
);
4046 /* <!-- Content: template --> */
4047 goto sequence_constructor
;
4048 case XSLT_FUNC_WHEN
:
4049 /* <!-- Content: template --> */
4050 goto sequence_constructor
;
4051 case XSLT_FUNC_WITHPARAM
:
4052 /* <!-- Content: template --> */
4053 goto sequence_constructor
;
4055 #ifdef WITH_XSLT_DEBUG_PARSING
4056 xsltGenericDebug(xsltGenericDebugContext
,
4057 "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
4060 xsltTransformError(NULL
, cctxt
->style
, elem
,
4061 "xsltParseXSLTNode: Internal error; "
4062 "unhandled XSLT element '%s'.\n", elem
->name
);
4063 cctxt
->style
->errors
++;
4068 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
4069 if (elem
->children
!= NULL
) {
4070 xmlNodePtr child
= elem
->children
;
4072 if (child
->type
== XML_ELEMENT_NODE
) {
4073 if (IS_XSLT_ELEM_FAST(child
)) {
4074 if (xmlStrEqual(child
->name
, BAD_CAST
"with-param")) {
4075 cctxt
->inode
->curChildType
= XSLT_FUNC_WITHPARAM
;
4076 xsltParseAnyXSLTElem(cctxt
, child
);
4077 } else if (xmlStrEqual(child
->name
, BAD_CAST
"sort")) {
4078 cctxt
->inode
->curChildType
= XSLT_FUNC_SORT
;
4079 xsltParseAnyXSLTElem(cctxt
, child
);
4081 xsltParseContentError(cctxt
->style
, child
);
4083 xsltParseContentError(cctxt
->style
, child
);
4085 child
= child
->next
;
4086 } while (child
!= NULL
);
4091 /* <!-- Content: xsl:with-param* --> */
4092 if (elem
->children
!= NULL
) {
4093 xmlNodePtr child
= elem
->children
;
4095 if (child
->type
== XML_ELEMENT_NODE
) {
4096 if (IS_XSLT_ELEM_FAST(child
)) {
4099 type
= xsltGetXSLTElementTypeByNode(cctxt
, child
);
4100 if (type
== XSLT_FUNC_WITHPARAM
) {
4101 cctxt
->inode
->curChildType
= XSLT_FUNC_WITHPARAM
;
4102 xsltParseAnyXSLTElem(cctxt
, child
);
4104 xsltParseContentError(cctxt
->style
, child
);
4107 xsltParseContentError(cctxt
->style
, child
);
4109 child
= child
->next
;
4110 } while (child
!= NULL
);
4115 if (elem
->children
!= NULL
) {
4116 xmlNodePtr child
= elem
->children
;
4118 if ((child
->type
!= XML_TEXT_NODE
) &&
4119 (child
->type
!= XML_CDATA_SECTION_NODE
))
4121 xsltTransformError(NULL
, cctxt
->style
, elem
,
4122 "The XSLT 'text' element must have only character "
4123 "data as content.\n");
4125 child
= child
->next
;
4126 } while (child
!= NULL
);
4131 if (elem
->children
!= NULL
) {
4132 xmlNodePtr child
= elem
->children
;
4134 * Relaxed behaviour: we will allow whitespace-only text-nodes.
4137 if (((child
->type
!= XML_TEXT_NODE
) &&
4138 (child
->type
!= XML_CDATA_SECTION_NODE
)) ||
4139 (! IS_BLANK_NODE(child
)))
4141 xsltTransformError(NULL
, cctxt
->style
, elem
,
4142 "This XSLT element must have no content.\n");
4143 cctxt
->style
->errors
++;
4146 child
= child
->next
;
4147 } while (child
!= NULL
);
4152 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
4154 * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
4155 * The old behaviour did not check this.
4156 * NOTE: In XSLT 2.0 they are stripped beforehand
4157 * if whitespace-only (regardless of xml:space).
4159 if (elem
->children
!= NULL
) {
4160 xmlNodePtr child
= elem
->children
;
4161 int nbWhen
= 0, nbOtherwise
= 0, err
= 0;
4163 if (child
->type
== XML_ELEMENT_NODE
) {
4164 if (IS_XSLT_ELEM_FAST(child
)) {
4167 type
= xsltGetXSLTElementTypeByNode(cctxt
, child
);
4168 if (type
== XSLT_FUNC_WHEN
) {
4171 xsltParseContentError(cctxt
->style
, child
);
4175 cctxt
->inode
->curChildType
= XSLT_FUNC_WHEN
;
4176 xsltParseAnyXSLTElem(cctxt
, child
);
4177 } else if (type
== XSLT_FUNC_OTHERWISE
) {
4179 xsltParseContentError(cctxt
->style
, child
);
4184 xsltTransformError(NULL
, cctxt
->style
, elem
,
4185 "The XSLT 'choose' element must not contain "
4186 "more than one XSLT 'otherwise' element.\n");
4187 cctxt
->style
->errors
++;
4192 cctxt
->inode
->curChildType
= XSLT_FUNC_OTHERWISE
;
4193 xsltParseAnyXSLTElem(cctxt
, child
);
4195 xsltParseContentError(cctxt
->style
, child
);
4197 xsltParseContentError(cctxt
->style
, child
);
4201 xsltParseContentError(cctxt, child);
4203 child
= child
->next
;
4204 } while (child
!= NULL
);
4205 if ((! err
) && (! nbWhen
)) {
4206 xsltTransformError(NULL
, cctxt
->style
, elem
,
4207 "The XSLT element 'choose' must contain at least one "
4208 "XSLT element 'when'.\n");
4209 cctxt
->style
->errors
++;
4215 /* <!-- Content: (xsl:sort*, template) --> */
4217 * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
4218 * The old behaviour did not allow this, but it catched this
4219 * only at transformation-time.
4220 * In XSLT 2.0 they are stripped beforehand if whitespace-only
4221 * (regardless of xml:space).
4223 if (elem
->children
!= NULL
) {
4224 xmlNodePtr child
= elem
->children
;
4226 * Parse xsl:sort first.
4229 if ((child
->type
== XML_ELEMENT_NODE
) &&
4230 IS_XSLT_ELEM_FAST(child
))
4232 if (xsltGetXSLTElementTypeByNode(cctxt
, child
) ==
4235 cctxt
->inode
->curChildType
= XSLT_FUNC_SORT
;
4236 xsltParseAnyXSLTElem(cctxt
, child
);
4241 child
= child
->next
;
4242 } while (child
!= NULL
);
4244 * Parse the sequece constructor.
4247 xsltParseSequenceConstructor(cctxt
, child
);
4251 sequence_constructor
:
4253 * Parse the sequence constructor.
4255 if (elem
->children
!= NULL
)
4256 xsltParseSequenceConstructor(cctxt
, elem
->children
);
4259 * Register information for vars/params. Only needed if there
4260 * are any following siblings.
4262 if ((elem
->next
!= NULL
) &&
4263 ((cctxt
->inode
->type
== XSLT_FUNC_VARIABLE
) ||
4264 (cctxt
->inode
->type
== XSLT_FUNC_PARAM
)))
4266 if ((elem
->psvi
!= NULL
) &&
4267 (((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->name
))
4269 xsltCompilerVarInfoPush(cctxt
, elem
,
4270 ((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->name
,
4271 ((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->ns
);
4277 xsltCompilerNodePop(cctxt
, elem
);
4281 xsltCompilerNodePop(cctxt
, elem
);
4286 * xsltForwardsCompatUnkownItemCreate:
4288 * @cctxt: the compilation context
4290 * Creates a compiled representation of the unknown
4293 * Returns the compiled representation.
4295 static xsltStyleItemUknownPtr
4296 xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt
)
4298 xsltStyleItemUknownPtr item
;
4300 item
= (xsltStyleItemUknownPtr
) xmlMalloc(sizeof(xsltStyleItemUknown
));
4302 xsltTransformError(NULL
, cctxt
->style
, NULL
,
4303 "Internal error in xsltForwardsCompatUnkownItemCreate(): "
4304 "Failed to allocate memory.\n");
4305 cctxt
->style
->errors
++;
4308 memset(item
, 0, sizeof(xsltStyleItemUknown
));
4309 item
->type
= XSLT_FUNC_UNKOWN_FORWARDS_COMPAT
;
4311 * Store it in the stylesheet.
4313 item
->next
= cctxt
->style
->preComps
;
4314 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
4319 * xsltParseUnknownXSLTElem:
4321 * @cctxt: the compilation context
4322 * @node: the element of the unknown XSLT instruction
4324 * Parses an unknown XSLT element.
4325 * If forwards compatible mode is enabled this will allow
4326 * such an unknown XSLT and; otherwise it is rejected.
4328 * Returns 1 in the unknown XSLT instruction is rejected,
4329 * 0 if everything's fine and
4330 * -1 on API or internal errors.
4333 xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt
,
4336 if ((cctxt
== NULL
) || (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
4340 * Detection of handled content of extension instructions.
4342 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4343 cctxt
->inode
->extContentHandled
= 1;
4345 if (cctxt
->inode
->forwardsCompat
== 0) {
4347 * We are not in forwards-compatible mode, so raise an error.
4349 xsltTransformError(NULL
, cctxt
->style
, node
,
4350 "Unknown XSLT element '%s'.\n", node
->name
);
4351 cctxt
->style
->errors
++;
4355 * Forwards-compatible mode.
4356 * ------------------------
4358 * Parse/compile xsl:fallback elements.
4360 * QUESTION: Do we have to raise an error if there's no xsl:fallback?
4361 * ANSWER: No, since in the stylesheet the fallback behaviour might
4362 * also be provided by using the XSLT function "element-available".
4364 if (cctxt
->unknownItem
== NULL
) {
4366 * Create a singleton for all unknown XSLT instructions.
4368 cctxt
->unknownItem
= xsltForwardsCompatUnkownItemCreate(cctxt
);
4369 if (cctxt
->unknownItem
== NULL
) {
4374 node
->psvi
= cctxt
->unknownItem
;
4375 if (node
->children
== NULL
)
4378 xmlNodePtr child
= node
->children
;
4380 xsltCompilerNodePush(cctxt
, node
);
4382 * Update the in-scope namespaces if needed.
4384 if (node
->nsDef
!= NULL
)
4385 cctxt
->inode
->inScopeNs
=
4386 xsltCompilerBuildInScopeNsList(cctxt
, node
);
4388 * Parse all xsl:fallback children.
4391 if ((child
->type
== XML_ELEMENT_NODE
) &&
4392 IS_XSLT_ELEM_FAST(child
) &&
4393 IS_XSLT_NAME(child
, "fallback"))
4395 cctxt
->inode
->curChildType
= XSLT_FUNC_FALLBACK
;
4396 xsltParseAnyXSLTElem(cctxt
, child
);
4398 child
= child
->next
;
4399 } while (child
!= NULL
);
4401 xsltCompilerNodePop(cctxt
, node
);
4407 * xsltParseSequenceConstructor:
4409 * @cctxt: the compilation context
4410 * @cur: the start-node of the content to be parsed
4412 * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
4413 * This will additionally remove xsl:text elements from the tree.
4416 xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt
, xmlNodePtr cur
)
4419 xmlNodePtr deleteNode
= NULL
;
4421 if (cctxt
== NULL
) {
4422 xmlGenericError(xmlGenericErrorContext
,
4423 "xsltParseSequenceConstructor: Bad arguments\n");
4424 cctxt
->style
->errors
++;
4428 * Detection of handled content of extension instructions.
4430 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4431 cctxt
->inode
->extContentHandled
= 1;
4433 if ((cur
== NULL
) || (cur
->type
== XML_NAMESPACE_DECL
))
4436 * This is the content reffered to as a "template".
4437 * E.g. an xsl:element has such content model:
4440 * namespace = { uri-reference }
4441 * use-attribute-sets = qnames>
4442 * <!-- Content: template -->
4444 * NOTE that in XSLT-2 the term "template" was abandoned due to
4445 * confusion with xsl:template and the term "sequence constructor"
4446 * was introduced instead.
4448 * The following XSLT-instructions are allowed to appear:
4449 * xsl:apply-templates, xsl:call-template, xsl:apply-imports,
4450 * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
4451 * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
4452 * xsl:message, xsl:fallback,
4453 * xsl:processing-instruction, xsl:comment, xsl:element
4455 * Additional allowed content:
4456 * 1) extension instructions
4457 * 2) literal result elements
4460 * NOTE that this content model does *not* allow xsl:param.
4462 while (cur
!= NULL
) {
4463 if (deleteNode
!= NULL
) {
4464 #ifdef WITH_XSLT_DEBUG_BLANKS
4465 xsltGenericDebug(xsltGenericDebugContext
,
4466 "xsltParseSequenceConstructor: removing xsl:text element\n");
4468 xmlUnlinkNode(deleteNode
);
4469 xmlFreeNode(deleteNode
);
4472 if (cur
->type
== XML_ELEMENT_NODE
) {
4474 if (cur
->psvi
== xsltXSLTTextMarker
) {
4477 * --------------------------------------------------------
4483 * Mark the xsl:text element for later deletion.
4489 tmp
= cur
->children
;
4492 * We don't expect more than one text-node in the
4493 * content, since we already merged adjacent
4494 * text/CDATA-nodes and eliminated PI/comment-nodes.
4496 if ((tmp
->type
== XML_TEXT_NODE
) ||
4497 (tmp
->next
== NULL
))
4500 * Leave the contained text-node in the tree.
4503 xmlAddPrevSibling(cur
, tmp
);
4506 xsltTransformError(NULL
, cctxt
->style
, cur
,
4507 "Element 'xsl:text': Invalid type "
4508 "of node found in content.\n");
4509 cctxt
->style
->errors
++;
4512 if (cur
->properties
) {
4515 * TODO: We need to report errors for
4518 attr
= cur
->properties
;
4520 if ((attr
->ns
== NULL
) &&
4521 (attr
->name
!= NULL
) &&
4522 (attr
->name
[0] == 'd') &&
4523 xmlStrEqual(attr
->name
,
4524 BAD_CAST
"disable-output-escaping"))
4527 * Attr "disable-output-escaping".
4528 * XSLT-2: This attribute is deprecated.
4530 if ((attr
->children
!= NULL
) &&
4531 xmlStrEqual(attr
->children
->content
,
4535 * Disable output escaping for this
4539 tmp
->name
= xmlStringTextNoenc
;
4540 } else if ((attr
->children
== NULL
) ||
4541 (attr
->children
->content
== NULL
) ||
4542 (!xmlStrEqual(attr
->children
->content
,
4545 xsltTransformError(NULL
, cctxt
->style
,
4547 "Attribute 'disable-output-escaping': "
4548 "Invalid value. Expected is "
4549 "'yes' or 'no'.\n");
4550 cctxt
->style
->errors
++;
4555 } while (attr
!= NULL
);
4557 } else if (IS_XSLT_ELEM_FAST(cur
)) {
4559 * TODO: Using the XSLT-marker is still not stable yet.
4561 /* if (cur->psvi == xsltXSLTElemMarker) { */
4564 * --------------------------------------------------------
4567 type
= xsltGetXSLTElementTypeByNode(cctxt
, cur
);
4569 case XSLT_FUNC_APPLYIMPORTS
:
4570 case XSLT_FUNC_APPLYTEMPLATES
:
4571 case XSLT_FUNC_ATTRIBUTE
:
4572 case XSLT_FUNC_CALLTEMPLATE
:
4573 case XSLT_FUNC_CHOOSE
:
4574 case XSLT_FUNC_COMMENT
:
4575 case XSLT_FUNC_COPY
:
4576 case XSLT_FUNC_COPYOF
:
4577 case XSLT_FUNC_DOCUMENT
: /* Extra one */
4578 case XSLT_FUNC_ELEMENT
:
4579 case XSLT_FUNC_FALLBACK
:
4580 case XSLT_FUNC_FOREACH
:
4582 case XSLT_FUNC_MESSAGE
:
4583 case XSLT_FUNC_NUMBER
:
4585 case XSLT_FUNC_TEXT
:
4586 case XSLT_FUNC_VALUEOF
:
4587 case XSLT_FUNC_VARIABLE
:
4589 * Parse the XSLT element.
4591 cctxt
->inode
->curChildType
= type
;
4592 xsltParseAnyXSLTElem(cctxt
, cur
);
4595 xsltParseUnknownXSLTElem(cctxt
, cur
);
4604 xsltCompilerNodePush(cctxt
, cur
);
4606 * Update the in-scope namespaces if needed.
4608 if (cur
->nsDef
!= NULL
)
4609 cctxt
->inode
->inScopeNs
=
4610 xsltCompilerBuildInScopeNsList(cctxt
, cur
);
4612 * The current element is either a literal result element
4613 * or an extension instruction.
4615 * Process attr "xsl:extension-element-prefixes".
4616 * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
4617 * processed by the implementor of the extension function;
4618 * i.e., it won't be handled by the XSLT processor.
4621 * "exclude-result-prefixes" is only allowed on literal
4622 * result elements and "xsl:exclude-result-prefixes"
4623 * on xsl:stylesheet/xsl:transform.
4625 * "There are a number of standard attributes
4626 * that may appear on any XSLT element: specifically
4627 * version, exclude-result-prefixes,
4628 * extension-element-prefixes, xpath-default-namespace,
4629 * default-collation, and use-when."
4632 * For literal result elements:
4633 * "xsl:version, xsl:exclude-result-prefixes,
4634 * xsl:extension-element-prefixes,
4635 * xsl:xpath-default-namespace,
4636 * xsl:default-collation, or xsl:use-when."
4638 if (cur
->properties
)
4639 cctxt
->inode
->extElemNs
=
4640 xsltParseExtElemPrefixes(cctxt
,
4641 cur
, cctxt
->inode
->extElemNs
,
4642 XSLT_ELEMENT_CATEGORY_LRE
);
4644 * Eval if we have an extension instruction here.
4646 if ((cur
->ns
!= NULL
) &&
4647 (cctxt
->inode
->extElemNs
!= NULL
) &&
4648 (xsltCheckExtPrefix(cctxt
->style
, cur
->ns
->href
) == 1))
4651 * Extension instructions
4652 * ----------------------------------------------------
4653 * Mark the node information.
4655 cctxt
->inode
->category
= XSLT_ELEMENT_CATEGORY_EXTENSION
;
4656 cctxt
->inode
->extContentHandled
= 0;
4657 if (cur
->psvi
!= NULL
) {
4660 * TODO: Temporary sanity check.
4662 xsltTransformError(NULL
, cctxt
->style
, cur
,
4663 "Internal error in xsltParseSequenceConstructor(): "
4664 "Occupied PSVI field.\n");
4665 cctxt
->style
->errors
++;
4669 cur
->psvi
= (void *)
4670 xsltPreComputeExtModuleElement(cctxt
->style
, cur
);
4672 if (cur
->psvi
== NULL
) {
4674 * OLD COMMENT: "Unknown element, maybe registered
4675 * at the context level. Mark it for later
4677 * QUESTION: What does the xsltExtMarker mean?
4678 * ANSWER: It is used in
4679 * xsltApplySequenceConstructor() at
4680 * transformation-time to look out for extension
4681 * registered in the transformation context.
4683 cur
->psvi
= (void *) xsltExtMarker
;
4686 * BIG NOTE: Now the ugly part. In previous versions
4687 * of Libxslt (until 1.1.16), all the content of an
4688 * extension instruction was processed and compiled without
4689 * the need of the extension-author to explicitely call
4690 * such a processing;.We now need to mimic this old
4691 * behaviour in order to avoid breaking old code
4692 * on the extension-author's side.
4694 * 1) If the author does *not* set the
4695 * compile-time-flag @extContentHandled, then we'll
4696 * parse the content assuming that it's a "template"
4697 * (or "sequence constructor in XSLT 2.0 terms).
4698 * NOTE: If the extension is registered at
4699 * transformation-time only, then there's no way of
4700 * knowing that content shall be valid, and we'll
4701 * process the content the same way.
4702 * 2) If the author *does* set the flag, then we'll assume
4703 * that the author has handled the parsing him/herself
4704 * (e.g. called xsltParseSequenceConstructor(), etc.
4705 * explicitely in his/her code).
4707 if ((cur
->children
!= NULL
) &&
4708 (cctxt
->inode
->extContentHandled
== 0))
4711 * Default parsing of the content using the
4712 * sequence-constructor model.
4714 xsltParseSequenceConstructor(cctxt
, cur
->children
);
4718 * Literal result element
4719 * ----------------------------------------------------
4720 * Allowed XSLT attributes:
4721 * xsl:extension-element-prefixes CDATA #IMPLIED
4722 * xsl:exclude-result-prefixes CDATA #IMPLIED
4723 * TODO: xsl:use-attribute-sets %qnames; #IMPLIED
4724 * xsl:version NMTOKEN #IMPLIED
4727 cctxt
->inode
->category
= XSLT_ELEMENT_CATEGORY_LRE
;
4728 if (cur
->properties
!= NULL
) {
4729 xmlAttrPtr attr
= cur
->properties
;
4731 * Attribute "xsl:exclude-result-prefixes".
4733 cctxt
->inode
->exclResultNs
=
4734 xsltParseExclResultPrefixes(cctxt
, cur
,
4735 cctxt
->inode
->exclResultNs
,
4736 XSLT_ELEMENT_CATEGORY_LRE
);
4738 * Attribute "xsl:version".
4740 xsltParseAttrXSLTVersion(cctxt
, cur
,
4741 XSLT_ELEMENT_CATEGORY_LRE
);
4743 * Report invalid XSLT attributes.
4744 * For XSLT 1.0 only xsl:use-attribute-sets is allowed
4745 * next to xsl:version, xsl:exclude-result-prefixes and
4746 * xsl:extension-element-prefixes.
4748 * Mark all XSLT attributes, in order to skip such
4749 * attributes when instantiating the LRE.
4752 if ((attr
->psvi
!= xsltXSLTAttrMarker
) &&
4753 IS_XSLT_ATTR_FAST(attr
))
4755 if (! xmlStrEqual(attr
->name
,
4756 BAD_CAST
"use-attribute-sets"))
4758 xsltTransformError(NULL
, cctxt
->style
,
4760 "Unknown XSLT attribute '%s'.\n",
4762 cctxt
->style
->errors
++;
4767 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
4771 } while (attr
!= NULL
);
4774 * Create/reuse info for the literal result element.
4776 if (cctxt
->inode
->nsChanged
)
4777 xsltLREInfoCreate(cctxt
, cur
, 1);
4778 cur
->psvi
= cctxt
->inode
->litResElemInfo
;
4780 * Apply ns-aliasing on the element and on its attributes.
4782 if (cctxt
->hasNsAliases
)
4783 xsltLREBuildEffectiveNs(cctxt
, cur
);
4785 * Compile attribute value templates (AVT).
4787 if (cur
->properties
) {
4788 xmlAttrPtr attr
= cur
->properties
;
4790 while (attr
!= NULL
) {
4791 xsltCompileAttr(cctxt
->style
, attr
);
4796 * Parse the content, which is defined to be a "template"
4797 * (or "sequence constructor" in XSLT 2.0 terms).
4799 if (cur
->children
!= NULL
) {
4800 xsltParseSequenceConstructor(cctxt
, cur
->children
);
4804 * Leave the non-XSLT element.
4806 xsltCompilerNodePop(cctxt
, cur
);
4811 if (deleteNode
!= NULL
) {
4812 #ifdef WITH_XSLT_DEBUG_BLANKS
4813 xsltGenericDebug(xsltGenericDebugContext
,
4814 "xsltParseSequenceConstructor: removing xsl:text element\n");
4816 xmlUnlinkNode(deleteNode
);
4817 xmlFreeNode(deleteNode
);
4823 * xsltParseTemplateContent:
4824 * @style: the XSLT stylesheet
4825 * @templ: the node containing the content to be parsed
4827 * Parses and compiles the content-model of an xsl:template element.
4828 * Note that this is *not* the "template" content model (or "sequence
4829 * constructor" in XSLT 2.0); it it allows addional xsl:param
4830 * elements as immediate children of @templ.
4833 * exsltFuncFunctionComp() (EXSLT, functions.c)
4834 * So this is intended to be called from extension functions.
4837 xsltParseTemplateContent(xsltStylesheetPtr style
, xmlNodePtr templ
) {
4838 if ((style
== NULL
) || (templ
== NULL
) ||
4839 (templ
->type
== XML_NAMESPACE_DECL
))
4843 * Detection of handled content of extension instructions.
4845 if (XSLT_CCTXT(style
)->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4846 XSLT_CCTXT(style
)->inode
->extContentHandled
= 1;
4849 if (templ
->children
!= NULL
) {
4850 xmlNodePtr child
= templ
->children
;
4852 * Process xsl:param elements, which can only occur as the
4853 * immediate children of xsl:template (well, and of any
4854 * user-defined extension instruction if needed).
4857 if ((child
->type
== XML_ELEMENT_NODE
) &&
4858 IS_XSLT_ELEM_FAST(child
) &&
4859 IS_XSLT_NAME(child
, "param"))
4861 XSLT_CCTXT(style
)->inode
->curChildType
= XSLT_FUNC_PARAM
;
4862 xsltParseAnyXSLTElem(XSLT_CCTXT(style
), child
);
4865 child
= child
->next
;
4866 } while (child
!= NULL
);
4868 * Parse the content and register the pattern.
4870 xsltParseSequenceConstructor(XSLT_CCTXT(style
), child
);
4874 #else /* XSLT_REFACTORED */
4877 * xsltParseTemplateContent:
4878 * @style: the XSLT stylesheet
4879 * @templ: the container node (can be a document for literal results)
4881 * parse a template content-model
4882 * Clean-up the template content from unwanted ignorable blank nodes
4883 * and process xslt:text
4886 xsltParseTemplateContent(xsltStylesheetPtr style
, xmlNodePtr templ
) {
4887 xmlNodePtr cur
, delete;
4889 if ((style
== NULL
) || (templ
== NULL
) ||
4890 (templ
->type
== XML_NAMESPACE_DECL
)) return;
4893 * This content comes from the stylesheet
4894 * For stylesheets, the set of whitespace-preserving
4895 * element names consists of just xsl:text.
4897 cur
= templ
->children
;
4899 while (cur
!= NULL
) {
4900 if (delete != NULL
) {
4901 #ifdef WITH_XSLT_DEBUG_BLANKS
4902 xsltGenericDebug(xsltGenericDebugContext
,
4903 "xsltParseTemplateContent: removing text\n");
4905 xmlUnlinkNode(delete);
4906 xmlFreeNode(delete);
4909 if (IS_XSLT_ELEM(cur
)) {
4910 xsltStylePreCompute(style
, cur
);
4912 if (IS_XSLT_NAME(cur
, "text")) {
4914 * TODO: Processing of xsl:text should be moved to
4915 * xsltPreprocessStylesheet(), since otherwise this
4916 * will be performed for every multiply included
4917 * stylesheet; i.e. this here is not skipped with
4918 * the use of the style->nopreproc flag.
4920 if (cur
->children
!= NULL
) {
4922 xmlNodePtr text
= cur
->children
, next
;
4925 prop
= xmlGetNsProp(cur
,
4926 (const xmlChar
*)"disable-output-escaping",
4929 #ifdef WITH_XSLT_DEBUG_PARSING
4930 xsltGenericDebug(xsltGenericDebugContext
,
4931 "Disable escaping: %s\n", text
->content
);
4933 if (xmlStrEqual(prop
, (const xmlChar
*)"yes")) {
4935 } else if (!xmlStrEqual(prop
,
4936 (const xmlChar
*)"no")){
4937 xsltTransformError(NULL
, style
, cur
,
4938 "xsl:text: disable-output-escaping allows only yes or no\n");
4945 while (text
!= NULL
) {
4946 if (text
->type
== XML_COMMENT_NODE
) {
4950 if ((text
->type
!= XML_TEXT_NODE
) &&
4951 (text
->type
!= XML_CDATA_SECTION_NODE
)) {
4952 xsltTransformError(NULL
, style
, cur
,
4953 "xsltParseTemplateContent: xslt:text content problem\n");
4957 if ((noesc
) && (text
->type
!= XML_CDATA_SECTION_NODE
))
4958 text
->name
= xmlStringTextNoenc
;
4963 * replace xsl:text by the list of childs
4966 text
= cur
->children
;
4967 while (text
!= NULL
) {
4968 if ((style
->internalized
) &&
4969 (text
->content
!= NULL
) &&
4970 (!xmlDictOwns(style
->dict
, text
->content
))) {
4973 * internalize the text string
4975 if (text
->doc
->dict
!= NULL
) {
4978 tmp
= xmlDictLookup(text
->doc
->dict
,
4980 if (tmp
!= text
->content
) {
4981 xmlNodeSetContent(text
, NULL
);
4982 text
->content
= (xmlChar
*) tmp
;
4988 xmlUnlinkNode(text
);
4989 xmlAddPrevSibling(cur
, text
);
4998 else if ((cur
->ns
!= NULL
) && (style
->nsDefs
!= NULL
) &&
4999 (xsltCheckExtPrefix(style
, cur
->ns
->prefix
)))
5002 * okay this is an extension element compile it too
5004 xsltStylePreCompute(style
, cur
);
5006 else if (cur
->type
== XML_ELEMENT_NODE
)
5009 * This is an element which will be output as part of the
5010 * template exectution, precompile AVT if found.
5012 if ((cur
->ns
== NULL
) && (style
->defaultAlias
!= NULL
)) {
5013 cur
->ns
= xmlSearchNsByHref(cur
->doc
, cur
,
5014 style
->defaultAlias
);
5016 if (cur
->properties
!= NULL
) {
5017 xmlAttrPtr attr
= cur
->properties
;
5019 while (attr
!= NULL
) {
5020 xsltCompileAttr(style
, attr
);
5028 if (cur
->children
!= NULL
) {
5029 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
5030 cur
= cur
->children
;
5035 if (cur
->next
!= NULL
) {
5048 if (cur
->next
!= NULL
) {
5052 } while (cur
!= NULL
);
5054 if (delete != NULL
) {
5055 #ifdef WITH_XSLT_DEBUG_PARSING
5056 xsltGenericDebug(xsltGenericDebugContext
,
5057 "xsltParseTemplateContent: removing text\n");
5059 xmlUnlinkNode(delete);
5060 xmlFreeNode(delete);
5065 * Skip the first params
5067 cur
= templ
->children
;
5068 while (cur
!= NULL
) {
5069 if ((IS_XSLT_ELEM(cur
)) && (!(IS_XSLT_NAME(cur
, "param"))))
5075 * Browse the remainder of the template
5077 while (cur
!= NULL
) {
5078 if ((IS_XSLT_ELEM(cur
)) && (IS_XSLT_NAME(cur
, "param"))) {
5079 xmlNodePtr param
= cur
;
5081 xsltTransformError(NULL
, style
, cur
,
5082 "xsltParseTemplateContent: ignoring misplaced param element\n");
5083 if (style
!= NULL
) style
->warnings
++;
5085 xmlUnlinkNode(param
);
5092 #endif /* else XSLT_REFACTORED */
5095 * xsltParseStylesheetKey:
5096 * @style: the XSLT stylesheet
5097 * @key: the "key" element
5099 * <!-- Category: top-level-element -->
5100 * <xsl:key name = qname, match = pattern, use = expression />
5102 * parse an XSLT stylesheet key definition and register it
5106 xsltParseStylesheetKey(xsltStylesheetPtr style
, xmlNodePtr key
) {
5107 xmlChar
*prop
= NULL
;
5108 xmlChar
*use
= NULL
;
5109 xmlChar
*match
= NULL
;
5110 xmlChar
*name
= NULL
;
5111 xmlChar
*nameURI
= NULL
;
5113 if ((style
== NULL
) || (key
== NULL
) || (key
->type
!= XML_ELEMENT_NODE
))
5119 prop
= xmlGetNsProp(key
, (const xmlChar
*)"name", NULL
);
5124 * TODO: Don't use xsltGetQNameURI().
5126 URI
= xsltGetQNameURI(key
, &prop
);
5128 if (style
!= NULL
) style
->errors
++;
5133 nameURI
= xmlStrdup(URI
);
5135 #ifdef WITH_XSLT_DEBUG_PARSING
5136 xsltGenericDebug(xsltGenericDebugContext
,
5137 "xsltParseStylesheetKey: name %s\n", name
);
5140 xsltTransformError(NULL
, style
, key
,
5141 "xsl:key : error missing name\n");
5142 if (style
!= NULL
) style
->errors
++;
5146 match
= xmlGetNsProp(key
, (const xmlChar
*)"match", NULL
);
5147 if (match
== NULL
) {
5148 xsltTransformError(NULL
, style
, key
,
5149 "xsl:key : error missing match\n");
5150 if (style
!= NULL
) style
->errors
++;
5154 use
= xmlGetNsProp(key
, (const xmlChar
*)"use", NULL
);
5156 xsltTransformError(NULL
, style
, key
,
5157 "xsl:key : error missing use\n");
5158 if (style
!= NULL
) style
->errors
++;
5165 xsltAddKey(style
, name
, nameURI
, match
, use
, key
);
5175 if (nameURI
!= NULL
)
5178 if (key
->children
!= NULL
) {
5179 xsltParseContentError(style
, key
->children
);
5183 #ifdef XSLT_REFACTORED
5185 * xsltParseXSLTTemplate:
5186 * @style: the XSLT stylesheet
5187 * @template: the "template" element
5189 * parse an XSLT stylesheet template building the associated structures
5190 * TODO: Is @style ever expected to be NULL?
5193 * xsltParseXSLTStylesheet()
5194 * xsltParseStylesheetTop()
5198 xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt
, xmlNodePtr templNode
) {
5199 xsltTemplatePtr templ
;
5203 if ((cctxt
== NULL
) || (templNode
== NULL
) ||
5204 (templNode
->type
!= XML_ELEMENT_NODE
))
5208 * Create and link the structure
5210 templ
= xsltNewTemplate();
5214 xsltCompilerNodePush(cctxt
, templNode
);
5215 if (templNode
->nsDef
!= NULL
)
5216 cctxt
->inode
->inScopeNs
=
5217 xsltCompilerBuildInScopeNsList(cctxt
, templNode
);
5219 templ
->next
= cctxt
->style
->templates
;
5220 cctxt
->style
->templates
= templ
;
5221 templ
->style
= cctxt
->style
;
5226 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"mode", NULL
);
5228 const xmlChar
*modeURI
;
5231 * TODO: We need a standardized function for extraction
5232 * of namespace names and local names from QNames.
5233 * Don't use xsltGetQNameURI() as it cannot channe�
5234 * reports through the context.
5236 modeURI
= xsltGetQNameURI(templNode
, &prop
);
5238 cctxt
->style
->errors
++;
5241 templ
->mode
= xmlDictLookup(cctxt
->style
->dict
, prop
, -1);
5244 if (xmlValidateNCName(templ
->mode
, 0)) {
5245 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5246 "xsl:template: Attribute 'mode': The local part '%s' "
5247 "of the value is not a valid NCName.\n", templ
->name
);
5248 cctxt
->style
->errors
++;
5251 if (modeURI
!= NULL
)
5252 templ
->modeURI
= xmlDictLookup(cctxt
->style
->dict
, modeURI
, -1);
5253 #ifdef WITH_XSLT_DEBUG_PARSING
5254 xsltGenericDebug(xsltGenericDebugContext
,
5255 "xsltParseXSLTTemplate: mode %s\n", templ
->mode
);
5259 * Attribute "match".
5261 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"match", NULL
);
5263 templ
->match
= prop
;
5267 * Attribute "priority".
5269 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"priority", NULL
);
5271 priority
= xmlXPathStringEvalNumber(prop
);
5272 templ
->priority
= (float) priority
;
5279 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"name", NULL
);
5281 const xmlChar
*nameURI
;
5282 xsltTemplatePtr curTempl
;
5285 * TODO: Don't use xsltGetQNameURI().
5287 nameURI
= xsltGetQNameURI(templNode
, &prop
);
5289 cctxt
->style
->errors
++;
5292 templ
->name
= xmlDictLookup(cctxt
->style
->dict
, prop
, -1);
5295 if (xmlValidateNCName(templ
->name
, 0)) {
5296 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5297 "xsl:template: Attribute 'name': The local part '%s' of "
5298 "the value is not a valid NCName.\n", templ
->name
);
5299 cctxt
->style
->errors
++;
5302 if (nameURI
!= NULL
)
5303 templ
->nameURI
= xmlDictLookup(cctxt
->style
->dict
, nameURI
, -1);
5304 curTempl
= templ
->next
;
5305 while (curTempl
!= NULL
) {
5306 if ((nameURI
!= NULL
&& xmlStrEqual(curTempl
->name
, templ
->name
) &&
5307 xmlStrEqual(curTempl
->nameURI
, nameURI
) ) ||
5308 (nameURI
== NULL
&& curTempl
->nameURI
== NULL
&&
5309 xmlStrEqual(curTempl
->name
, templ
->name
)))
5311 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5312 "xsl:template: error duplicate name '%s'\n", templ
->name
);
5313 cctxt
->style
->errors
++;
5316 curTempl
= curTempl
->next
;
5319 if (templNode
->children
!= NULL
) {
5320 xsltParseTemplateContent(cctxt
->style
, templNode
);
5322 * MAYBE TODO: Custom behaviour: In order to stay compatible with
5323 * Xalan and MSXML(.NET), we could allow whitespace
5324 * to appear before an xml:param element; this whitespace
5325 * will additionally become part of the "template".
5326 * NOTE that this is totally deviates from the spec, but
5327 * is the de facto behaviour of Xalan and MSXML(.NET).
5328 * Personally I wouldn't allow this, since if we have:
5329 * <xsl:template ...xml:space="preserve">
5330 * <xsl:param name="foo"/>
5331 * <xsl:param name="bar"/>
5332 * <xsl:param name="zoo"/>
5333 * ... the whitespace between every xsl:param would be
5334 * added to the result tree.
5338 templ
->elem
= templNode
;
5339 templ
->content
= templNode
->children
;
5340 xsltAddTemplate(cctxt
->style
, templ
, templ
->mode
, templ
->modeURI
);
5343 xsltCompilerNodePop(cctxt
, templNode
);
5347 #else /* XSLT_REFACTORED */
5350 * xsltParseStylesheetTemplate:
5351 * @style: the XSLT stylesheet
5352 * @template: the "template" element
5354 * parse an XSLT stylesheet template building the associated structures
5358 xsltParseStylesheetTemplate(xsltStylesheetPtr style
, xmlNodePtr
template) {
5359 xsltTemplatePtr ret
;
5361 xmlChar
*mode
= NULL
;
5362 xmlChar
*modeURI
= NULL
;
5365 if ((style
== NULL
) || (template == NULL
) ||
5366 (template->type
!= XML_ELEMENT_NODE
))
5370 * Create and link the structure
5372 ret
= xsltNewTemplate();
5375 ret
->next
= style
->templates
;
5376 style
->templates
= ret
;
5380 * Get inherited namespaces
5383 * TODO: Apply the optimized in-scope-namespace mechanism
5384 * as for the other XSLT instructions.
5386 xsltGetInheritedNsList(style
, ret
, template);
5391 prop
= xmlGetNsProp(template, (const xmlChar
*)"mode", NULL
);
5396 * TODO: Don't use xsltGetQNameURI().
5398 URI
= xsltGetQNameURI(template, &prop
);
5400 if (style
!= NULL
) style
->errors
++;
5405 modeURI
= xmlStrdup(URI
);
5407 ret
->mode
= xmlDictLookup(style
->dict
, mode
, -1);
5408 ret
->modeURI
= xmlDictLookup(style
->dict
, modeURI
, -1);
5409 #ifdef WITH_XSLT_DEBUG_PARSING
5410 xsltGenericDebug(xsltGenericDebugContext
,
5411 "xsltParseStylesheetTemplate: mode %s\n", mode
);
5413 if (mode
!= NULL
) xmlFree(mode
);
5414 if (modeURI
!= NULL
) xmlFree(modeURI
);
5416 prop
= xmlGetNsProp(template, (const xmlChar
*)"match", NULL
);
5418 if (ret
->match
!= NULL
) xmlFree(ret
->match
);
5422 prop
= xmlGetNsProp(template, (const xmlChar
*)"priority", NULL
);
5424 priority
= xmlXPathStringEvalNumber(prop
);
5425 ret
->priority
= (float) priority
;
5429 prop
= xmlGetNsProp(template, (const xmlChar
*)"name", NULL
);
5434 * TODO: Don't use xsltGetQNameURI().
5436 URI
= xsltGetQNameURI(template, &prop
);
5438 if (style
!= NULL
) style
->errors
++;
5441 if (xmlValidateNCName(prop
,0)) {
5442 xsltTransformError(NULL
, style
, template,
5443 "xsl:template : error invalid name '%s'\n", prop
);
5444 if (style
!= NULL
) style
->errors
++;
5448 ret
->name
= xmlDictLookup(style
->dict
, BAD_CAST prop
, -1);
5452 ret
->nameURI
= xmlDictLookup(style
->dict
, BAD_CAST URI
, -1);
5454 ret
->nameURI
= NULL
;
5459 * parse the content and register the pattern
5461 xsltParseTemplateContent(style
, template);
5462 ret
->elem
= template;
5463 ret
->content
= template->children
;
5464 xsltAddTemplate(style
, ret
, ret
->mode
, ret
->modeURI
);
5470 #endif /* else XSLT_REFACTORED */
5472 #ifdef XSLT_REFACTORED
5476 * @cctxt: the compilation context
5477 * @node: the xsl:include node
5479 * Process the xslt include node on the source node
5481 static xsltStyleItemIncludePtr
5482 xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
) {
5483 xsltStyleItemIncludePtr item
;
5485 if ((cctxt
== NULL
) || (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
5489 item
= (xsltStyleItemIncludePtr
) xmlMalloc(sizeof(xsltStyleItemInclude
));
5491 xsltTransformError(NULL
, cctxt
->style
, node
,
5492 "xsltIncludeComp : malloc failed\n");
5493 cctxt
->style
->errors
++;
5496 memset(item
, 0, sizeof(xsltStyleItemInclude
));
5500 item
->type
= XSLT_FUNC_INCLUDE
;
5502 item
->next
= cctxt
->style
->preComps
;
5503 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
5509 xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt
,
5511 const xmlChar
*name
,
5512 const xmlChar
*namespaceURI
,
5513 int breakOnOtherElem
,
5514 xmlNodePtr
*resultNode
)
5520 while (cur
!= NULL
) {
5521 if (cur
->type
== XML_ELEMENT_NODE
) {
5522 if ((cur
->ns
!= NULL
) && (cur
->name
!= NULL
)) {
5523 if ((*(cur
->name
) == *name
) &&
5524 xmlStrEqual(cur
->name
, name
) &&
5525 xmlStrEqual(cur
->ns
->href
, namespaceURI
))
5531 if (breakOnOtherElem
)
5541 xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt
,
5548 * TODO: The reason why this function exists:
5549 * due to historical reasons some of the
5550 * top-level declarations are processed by functions
5551 * in other files. Since we need still to set
5552 * up the node-info and generate information like
5553 * in-scope namespaces, this is a wrapper around
5554 * those old parsing functions.
5556 xsltCompilerNodePush(cctxt
, node
);
5557 if (node
->nsDef
!= NULL
)
5558 cctxt
->inode
->inScopeNs
=
5559 xsltCompilerBuildInScopeNsList(cctxt
, node
);
5560 cctxt
->inode
->type
= type
;
5563 case XSLT_FUNC_INCLUDE
:
5567 if (xsltCompileXSLTIncludeElem(cctxt
, node
) == NULL
)
5570 * Mark this stylesheet tree as being currently included.
5572 oldIsInclude
= cctxt
->isInclude
;
5573 cctxt
->isInclude
= 1;
5575 if (xsltParseStylesheetInclude(cctxt
->style
, node
) != 0) {
5576 cctxt
->style
->errors
++;
5578 cctxt
->isInclude
= oldIsInclude
;
5581 case XSLT_FUNC_PARAM
:
5582 xsltStylePreCompute(cctxt
->style
, node
);
5583 xsltParseGlobalParam(cctxt
->style
, node
);
5585 case XSLT_FUNC_VARIABLE
:
5586 xsltStylePreCompute(cctxt
->style
, node
);
5587 xsltParseGlobalVariable(cctxt
->style
, node
);
5589 case XSLT_FUNC_ATTRSET
:
5590 xsltParseStylesheetAttributeSet(cctxt
->style
, node
);
5593 xsltTransformError(NULL
, cctxt
->style
, node
,
5594 "Internal error: (xsltParseTopLevelXSLTElem) "
5595 "Cannot handle this top-level declaration.\n");
5596 cctxt
->style
->errors
++;
5601 xsltCompilerNodePop(cctxt
, node
);
5608 xsltParseRemoveWhitespace(xmlNodePtr node
)
5610 if ((node
== NULL
) || (node
->children
== NULL
))
5613 xmlNodePtr delNode
= NULL
, child
= node
->children
;
5617 xmlUnlinkNode(delNode
);
5618 xmlFreeNode(delNode
);
5621 if (((child
->type
== XML_TEXT_NODE
) ||
5622 (child
->type
== XML_CDATA_SECTION_NODE
)) &&
5623 (IS_BLANK_NODE(child
)))
5625 child
= child
->next
;
5626 } while (child
!= NULL
);
5628 xmlUnlinkNode(delNode
);
5629 xmlFreeNode(delNode
);
5638 xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
5640 #ifdef WITH_XSLT_DEBUG_PARSING
5643 xmlNodePtr cur
, start
= NULL
;
5644 xsltStylesheetPtr style
;
5646 if ((cctxt
== NULL
) || (node
== NULL
) ||
5647 (node
->type
!= XML_ELEMENT_NODE
))
5650 style
= cctxt
->style
;
5652 * At this stage all import declarations of all stylesheet modules
5653 * with the same stylesheet level have been processed.
5654 * Now we can safely parse the rest of the declarations.
5656 if (IS_XSLT_ELEM_FAST(node
) && IS_XSLT_NAME(node
, "include"))
5658 xsltDocumentPtr include
;
5660 * URGENT TODO: Make this work with simplified stylesheets!
5661 * I.e., when we won't find an xsl:stylesheet element.
5664 * This is as include declaration.
5666 include
= ((xsltStyleItemIncludePtr
) node
->psvi
)->include
;
5667 if (include
== NULL
) {
5668 /* TODO: raise error? */
5672 * TODO: Actually an xsl:include should locate an embedded
5673 * stylesheet as well; so the document-element won't always
5674 * be the element where the actual stylesheet is rooted at.
5675 * But such embedded stylesheets are not supported by Libxslt yet.
5677 node
= xmlDocGetRootElement(include
->doc
);
5683 if (node
->children
== NULL
)
5686 * Push the xsl:stylesheet/xsl:transform element.
5688 xsltCompilerNodePush(cctxt
, node
);
5689 cctxt
->inode
->isRoot
= 1;
5690 cctxt
->inode
->nsChanged
= 0;
5692 * Start with the naked dummy info for literal result elements.
5694 cctxt
->inode
->litResElemInfo
= cctxt
->inodeList
->litResElemInfo
;
5697 * In every case, we need to have
5698 * the in-scope namespaces of the element, where the
5699 * stylesheet is rooted at, regardless if it's an XSLT
5700 * instruction or a literal result instruction (or if
5701 * this is an embedded stylesheet).
5703 cctxt
->inode
->inScopeNs
=
5704 xsltCompilerBuildInScopeNsList(cctxt
, node
);
5707 * Process attributes of xsl:stylesheet/xsl:transform.
5708 * --------------------------------------------------
5711 * extension-element-prefixes = tokens
5712 * exclude-result-prefixes = tokens
5713 * version = number (mandatory)
5715 if (xsltParseAttrXSLTVersion(cctxt
, node
,
5716 XSLT_ELEMENT_CATEGORY_XSLT
) == 0)
5719 * Attribute "version".
5720 * XSLT 1.0: "An xsl:stylesheet element *must* have a version
5721 * attribute, indicating the version of XSLT that the
5722 * stylesheet requires".
5723 * The root element of a simplified stylesheet must also have
5726 #ifdef XSLT_REFACTORED_MANDATORY_VERSION
5728 xsltTransformError(NULL
, cctxt
->style
, node
,
5729 "The attribute 'version' is missing.\n");
5730 cctxt
->style
->errors
++;
5732 /* OLD behaviour. */
5733 xsltTransformError(NULL
, cctxt
->style
, node
,
5734 "xsl:version is missing: document may not be a stylesheet\n");
5735 cctxt
->style
->warnings
++;
5739 * The namespaces declared by the attributes
5740 * "extension-element-prefixes" and
5741 * "exclude-result-prefixes" are local to *this*
5742 * stylesheet tree; i.e., they are *not* visible to
5743 * other stylesheet-modules, whether imported or included.
5745 * Attribute "extension-element-prefixes".
5747 cctxt
->inode
->extElemNs
=
5748 xsltParseExtElemPrefixes(cctxt
, node
, NULL
,
5749 XSLT_ELEMENT_CATEGORY_XSLT
);
5751 * Attribute "exclude-result-prefixes".
5753 cctxt
->inode
->exclResultNs
=
5754 xsltParseExclResultPrefixes(cctxt
, node
, NULL
,
5755 XSLT_ELEMENT_CATEGORY_XSLT
);
5757 * Create/reuse info for the literal result element.
5759 if (cctxt
->inode
->nsChanged
)
5760 xsltLREInfoCreate(cctxt
, node
, 0);
5762 * Processed top-level elements:
5763 * ----------------------------
5764 * xsl:variable, xsl:param (QName, in-scope ns,
5765 * expression (vars allowed))
5766 * xsl:attribute-set (QName, in-scope ns)
5767 * xsl:strip-space, xsl:preserve-space (XPath NameTests,
5769 * I *think* global scope, merge with includes
5770 * xsl:output (QName, in-scope ns)
5771 * xsl:key (QName, in-scope ns, pattern,
5772 * expression (vars *not* allowed))
5773 * xsl:decimal-format (QName, needs in-scope ns)
5774 * xsl:namespace-alias (in-scope ns)
5775 * global scope, merge with includes
5776 * xsl:template (last, QName, pattern)
5778 * (whitespace-only text-nodes have *not* been removed
5779 * yet; this will be done in xsltParseSequenceConstructor)
5781 * Report misplaced child-nodes first.
5783 cur
= node
->children
;
5784 while (cur
!= NULL
) {
5785 if (cur
->type
== XML_TEXT_NODE
) {
5786 xsltTransformError(NULL
, style
, cur
,
5787 "Misplaced text node (content: '%s').\n",
5788 (cur
->content
!= NULL
) ? cur
->content
: BAD_CAST
"");
5790 } else if (cur
->type
!= XML_ELEMENT_NODE
) {
5791 xsltTransformError(NULL
, style
, cur
, "Misplaced node.\n");
5797 * Skip xsl:import elements; they have been processed
5800 cur
= node
->children
;
5801 while ((cur
!= NULL
) && xsltParseFindTopLevelElem(cctxt
, cur
,
5802 BAD_CAST
"import", XSLT_NAMESPACE
, 1, &cur
) == 1)
5809 * Process all top-level xsl:param elements.
5811 while ((cur
!= NULL
) &&
5812 xsltParseFindTopLevelElem(cctxt
, cur
,
5813 BAD_CAST
"param", XSLT_NAMESPACE
, 0, &cur
) == 1)
5815 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_PARAM
);
5819 * Process all top-level xsl:variable elements.
5822 while ((cur
!= NULL
) &&
5823 xsltParseFindTopLevelElem(cctxt
, cur
,
5824 BAD_CAST
"variable", XSLT_NAMESPACE
, 0, &cur
) == 1)
5826 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_VARIABLE
);
5830 * Process all the rest of top-level elements.
5833 while (cur
!= NULL
) {
5835 * Process element nodes.
5837 if (cur
->type
== XML_ELEMENT_NODE
) {
5838 if (cur
->ns
== NULL
) {
5839 xsltTransformError(NULL
, style
, cur
,
5840 "Unexpected top-level element in no namespace.\n");
5846 * Process all XSLT elements.
5848 if (IS_XSLT_ELEM_FAST(cur
)) {
5850 * xsl:import is only allowed at the beginning.
5852 if (IS_XSLT_NAME(cur
, "import")) {
5853 xsltTransformError(NULL
, style
, cur
,
5854 "Misplaced xsl:import element.\n");
5860 * TODO: Change the return type of the parsing functions
5863 if (IS_XSLT_NAME(cur
, "template")) {
5864 #ifdef WITH_XSLT_DEBUG_PARSING
5868 * TODO: Is the position of xsl:template in the
5869 * tree significant? If not it would be easier to
5870 * parse them at a later stage.
5872 xsltParseXSLTTemplate(cctxt
, cur
);
5873 } else if (IS_XSLT_NAME(cur
, "variable")) {
5874 /* NOP; done already */
5875 } else if (IS_XSLT_NAME(cur
, "param")) {
5876 /* NOP; done already */
5877 } else if (IS_XSLT_NAME(cur
, "include")) {
5878 if (cur
->psvi
!= NULL
)
5879 xsltParseXSLTStylesheetElemCore(cctxt
, cur
);
5881 xsltTransformError(NULL
, style
, cur
,
5883 "(xsltParseXSLTStylesheetElemCore) "
5884 "The xsl:include element was not compiled.\n");
5887 } else if (IS_XSLT_NAME(cur
, "strip-space")) {
5888 /* No node info needed. */
5889 xsltParseStylesheetStripSpace(style
, cur
);
5890 } else if (IS_XSLT_NAME(cur
, "preserve-space")) {
5891 /* No node info needed. */
5892 xsltParseStylesheetPreserveSpace(style
, cur
);
5893 } else if (IS_XSLT_NAME(cur
, "output")) {
5894 /* No node-info needed. */
5895 xsltParseStylesheetOutput(style
, cur
);
5896 } else if (IS_XSLT_NAME(cur
, "key")) {
5897 /* TODO: node-info needed for expressions ? */
5898 xsltParseStylesheetKey(style
, cur
);
5899 } else if (IS_XSLT_NAME(cur
, "decimal-format")) {
5900 /* No node-info needed. */
5901 xsltParseStylesheetDecimalFormat(style
, cur
);
5902 } else if (IS_XSLT_NAME(cur
, "attribute-set")) {
5903 xsltParseTopLevelXSLTElem(cctxt
, cur
,
5905 } else if (IS_XSLT_NAME(cur
, "namespace-alias")) {
5906 /* NOP; done already */
5908 if (cctxt
->inode
->forwardsCompat
) {
5910 * Forwards-compatible mode:
5912 * XSLT-1: "if it is a top-level element and
5913 * XSLT 1.0 does not allow such elements as top-level
5914 * elements, then the element must be ignored along
5915 * with its content;"
5918 * TODO: I don't think we should generate a warning.
5920 xsltTransformError(NULL
, style
, cur
,
5921 "Forwards-compatible mode: Ignoring unknown XSLT "
5922 "element '%s'.\n", cur
->name
);
5925 xsltTransformError(NULL
, style
, cur
,
5926 "Unknown XSLT element '%s'.\n", cur
->name
);
5931 xsltTopLevelFunction function
;
5934 * Process non-XSLT elements, which are in a
5935 * non-NULL namespace.
5938 * QUESTION: What does xsltExtModuleTopLevelLookup()
5941 function
= xsltExtModuleTopLevelLookup(cur
->name
,
5943 if (function
!= NULL
)
5944 function(style
, cur
);
5945 #ifdef WITH_XSLT_DEBUG_PARSING
5946 xsltGenericDebug(xsltGenericDebugContext
,
5947 "xsltParseXSLTStylesheetElemCore : User-defined "
5948 "data element '%s'.\n", cur
->name
);
5957 #ifdef WITH_XSLT_DEBUG_PARSING
5958 xsltGenericDebug(xsltGenericDebugContext
,
5959 "### END of parsing top-level elements of doc '%s'.\n",
5961 xsltGenericDebug(xsltGenericDebugContext
,
5962 "### Templates: %d\n", templates
);
5963 #ifdef XSLT_REFACTORED
5964 xsltGenericDebug(xsltGenericDebugContext
,
5965 "### Max inodes: %d\n", cctxt
->maxNodeInfos
);
5966 xsltGenericDebug(xsltGenericDebugContext
,
5967 "### Max LREs : %d\n", cctxt
->maxLREs
);
5968 #endif /* XSLT_REFACTORED */
5969 #endif /* WITH_XSLT_DEBUG_PARSING */
5971 xsltCompilerNodePop(cctxt
, node
);
5976 * xsltParseXSLTStylesheet:
5977 * @cctxt: the compiler context
5978 * @node: the xsl:stylesheet/xsl:transform element-node
5980 * Parses the xsl:stylesheet and xsl:transform element.
5984 * extension-element-prefixes = tokens
5985 * exclude-result-prefixes = tokens
5987 * <!-- Content: (xsl:import*, top-level-elements) -->
5990 * BIG TODO: The xsl:include stuff.
5992 * Called by xsltParseStylesheetTree()
5994 * Returns 0 on success, a positive result on errors and
5995 * -1 on API or internal errors.
5998 xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
6000 xmlNodePtr cur
, start
;
6002 if ((cctxt
== NULL
) || (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
6005 if (node
->children
== NULL
)
6009 * Process top-level elements:
6010 * xsl:import (must be first)
6011 * xsl:include (this is just a pre-processing)
6013 cur
= node
->children
;
6015 * Process xsl:import elements.
6016 * XSLT 1.0: "The xsl:import element children must precede all
6017 * other element children of an xsl:stylesheet element,
6018 * including any xsl:include element children."
6020 while ((cur
!= NULL
) &&
6021 xsltParseFindTopLevelElem(cctxt
, cur
,
6022 BAD_CAST
"import", XSLT_NAMESPACE
, 1, &cur
) == 1)
6024 if (xsltParseStylesheetImport(cctxt
->style
, cur
) != 0) {
6025 cctxt
->style
->errors
++;
6033 * Pre-process all xsl:include elements.
6036 while ((cur
!= NULL
) &&
6037 xsltParseFindTopLevelElem(cctxt
, cur
,
6038 BAD_CAST
"include", XSLT_NAMESPACE
, 0, &cur
) == 1)
6040 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_INCLUDE
);
6044 * Pre-process all xsl:namespace-alias elements.
6045 * URGENT TODO: This won't work correctly: the order of included
6046 * aliases and aliases defined here is significant.
6049 while ((cur
!= NULL
) &&
6050 xsltParseFindTopLevelElem(cctxt
, cur
,
6051 BAD_CAST
"namespace-alias", XSLT_NAMESPACE
, 0, &cur
) == 1)
6053 xsltNamespaceAlias(cctxt
->style
, cur
);
6057 if (cctxt
->isInclude
) {
6059 * If this stylesheet is intended for inclusion, then
6060 * we will process only imports and includes.
6065 * Now parse the rest of the top-level elements.
6067 xsltParseXSLTStylesheetElemCore(cctxt
, node
);
6073 #else /* XSLT_REFACTORED */
6076 * xsltParseStylesheetTop:
6077 * @style: the XSLT stylesheet
6078 * @top: the top level "stylesheet" or "transform" element
6080 * scan the top level elements of an XSL stylesheet
6083 xsltParseStylesheetTop(xsltStylesheetPtr style
, xmlNodePtr top
) {
6086 #ifdef WITH_XSLT_DEBUG_PARSING
6090 if ((top
== NULL
) || (top
->type
!= XML_ELEMENT_NODE
))
6093 prop
= xmlGetNsProp(top
, (const xmlChar
*)"version", NULL
);
6095 xsltTransformError(NULL
, style
, top
,
6096 "xsl:version is missing: document may not be a stylesheet\n");
6097 if (style
!= NULL
) style
->warnings
++;
6099 if ((!xmlStrEqual(prop
, (const xmlChar
*)"1.0")) &&
6100 (!xmlStrEqual(prop
, (const xmlChar
*)"1.1"))) {
6101 xsltTransformError(NULL
, style
, top
,
6102 "xsl:version: only 1.1 features are supported\n");
6103 if (style
!= NULL
) {
6104 style
->forwards_compatible
= 1;
6112 * process xsl:import elements
6114 cur
= top
->children
;
6115 while (cur
!= NULL
) {
6116 if (IS_BLANK_NODE(cur
)) {
6120 if (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "import")) {
6121 if (xsltParseStylesheetImport(style
, cur
) != 0)
6122 if (style
!= NULL
) style
->errors
++;
6129 * process other top-level elements
6131 while (cur
!= NULL
) {
6132 if (IS_BLANK_NODE(cur
)) {
6136 if (cur
->type
== XML_TEXT_NODE
) {
6137 if (cur
->content
!= NULL
) {
6138 xsltTransformError(NULL
, style
, cur
,
6139 "misplaced text node: '%s'\n", cur
->content
);
6141 if (style
!= NULL
) style
->errors
++;
6145 if ((cur
->type
== XML_ELEMENT_NODE
) && (cur
->ns
== NULL
)) {
6146 xsltGenericError(xsltGenericErrorContext
,
6147 "Found a top-level element %s with null namespace URI\n",
6149 if (style
!= NULL
) style
->errors
++;
6153 if ((cur
->type
== XML_ELEMENT_NODE
) && (!(IS_XSLT_ELEM(cur
)))) {
6154 xsltTopLevelFunction function
;
6156 function
= xsltExtModuleTopLevelLookup(cur
->name
,
6158 if (function
!= NULL
)
6159 function(style
, cur
);
6161 #ifdef WITH_XSLT_DEBUG_PARSING
6162 xsltGenericDebug(xsltGenericDebugContext
,
6163 "xsltParseStylesheetTop : found foreign element %s\n",
6169 if (IS_XSLT_NAME(cur
, "import")) {
6170 xsltTransformError(NULL
, style
, cur
,
6171 "xsltParseStylesheetTop: ignoring misplaced import element\n");
6172 if (style
!= NULL
) style
->errors
++;
6173 } else if (IS_XSLT_NAME(cur
, "include")) {
6174 if (xsltParseStylesheetInclude(style
, cur
) != 0)
6175 if (style
!= NULL
) style
->errors
++;
6176 } else if (IS_XSLT_NAME(cur
, "strip-space")) {
6177 xsltParseStylesheetStripSpace(style
, cur
);
6178 } else if (IS_XSLT_NAME(cur
, "preserve-space")) {
6179 xsltParseStylesheetPreserveSpace(style
, cur
);
6180 } else if (IS_XSLT_NAME(cur
, "output")) {
6181 xsltParseStylesheetOutput(style
, cur
);
6182 } else if (IS_XSLT_NAME(cur
, "key")) {
6183 xsltParseStylesheetKey(style
, cur
);
6184 } else if (IS_XSLT_NAME(cur
, "decimal-format")) {
6185 xsltParseStylesheetDecimalFormat(style
, cur
);
6186 } else if (IS_XSLT_NAME(cur
, "attribute-set")) {
6187 xsltParseStylesheetAttributeSet(style
, cur
);
6188 } else if (IS_XSLT_NAME(cur
, "variable")) {
6189 xsltParseGlobalVariable(style
, cur
);
6190 } else if (IS_XSLT_NAME(cur
, "param")) {
6191 xsltParseGlobalParam(style
, cur
);
6192 } else if (IS_XSLT_NAME(cur
, "template")) {
6193 #ifdef WITH_XSLT_DEBUG_PARSING
6196 xsltParseStylesheetTemplate(style
, cur
);
6197 } else if (IS_XSLT_NAME(cur
, "namespace-alias")) {
6198 xsltNamespaceAlias(style
, cur
);
6200 if ((style
!= NULL
) && (style
->forwards_compatible
== 0)) {
6201 xsltTransformError(NULL
, style
, cur
,
6202 "xsltParseStylesheetTop: unknown %s element\n",
6204 if (style
!= NULL
) style
->errors
++;
6209 #ifdef WITH_XSLT_DEBUG_PARSING
6210 xsltGenericDebug(xsltGenericDebugContext
,
6211 "parsed %d templates\n", templates
);
6215 #endif /* else of XSLT_REFACTORED */
6217 #ifdef XSLT_REFACTORED
6219 * xsltParseSimplifiedStylesheetTree:
6221 * @style: the stylesheet (TODO: Change this to the compiler context)
6222 * @doc: the document containing the stylesheet.
6223 * @node: the node where the stylesheet is rooted at
6225 * Returns 0 in case of success, a positive result if an error occurred
6226 * and -1 on API and internal errors.
6229 xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt
,
6233 xsltTemplatePtr templ
;
6235 if ((cctxt
== NULL
) || (node
== NULL
))
6238 if (xsltParseAttrXSLTVersion(cctxt
, node
, 0) == XSLT_ELEMENT_CATEGORY_LRE
)
6241 * TODO: Adjust report, since this might be an
6242 * embedded stylesheet.
6244 xsltTransformError(NULL
, cctxt
->style
, node
,
6245 "The attribute 'xsl:version' is missing; cannot identify "
6246 "this document as an XSLT stylesheet document.\n");
6247 cctxt
->style
->errors
++;
6251 #ifdef WITH_XSLT_DEBUG_PARSING
6252 xsltGenericDebug(xsltGenericDebugContext
,
6253 "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
6257 * Create and link the template
6259 templ
= xsltNewTemplate();
6260 if (templ
== NULL
) {
6263 templ
->next
= cctxt
->style
->templates
;
6264 cctxt
->style
->templates
= templ
;
6265 templ
->match
= xmlStrdup(BAD_CAST
"/");
6268 * Note that we push the document-node in this special case.
6270 xsltCompilerNodePush(cctxt
, (xmlNodePtr
) doc
);
6272 * In every case, we need to have
6273 * the in-scope namespaces of the element, where the
6274 * stylesheet is rooted at, regardless if it's an XSLT
6275 * instruction or a literal result instruction (or if
6276 * this is an embedded stylesheet).
6278 cctxt
->inode
->inScopeNs
=
6279 xsltCompilerBuildInScopeNsList(cctxt
, node
);
6281 * Parse the content and register the match-pattern.
6283 xsltParseSequenceConstructor(cctxt
, node
);
6284 xsltCompilerNodePop(cctxt
, (xmlNodePtr
) doc
);
6286 templ
->elem
= (xmlNodePtr
) doc
;
6287 templ
->content
= node
;
6288 xsltAddTemplate(cctxt
->style
, templ
, NULL
, NULL
);
6289 cctxt
->style
->literal_result
= 1;
6293 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6295 * xsltRestoreDocumentNamespaces:
6296 * @ns: map of namespaces
6297 * @doc: the document
6299 * Restore the namespaces for the document
6301 * Returns 0 in case of success, -1 in case of failure
6304 xsltRestoreDocumentNamespaces(xsltNsMapPtr ns
, xmlDocPtr doc
)
6309 * Revert the changes we have applied to the namespace-URIs of
6312 while (ns
!= NULL
) {
6313 if ((ns
->doc
== doc
) && (ns
->ns
!= NULL
)) {
6314 ns
->ns
->href
= ns
->origNsName
;
6315 ns
->origNsName
= NULL
;
6322 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
6325 * xsltParseStylesheetProcess:
6326 * @style: the XSLT stylesheet (the current stylesheet-level)
6327 * @doc: and xmlDoc parsed XML
6329 * Parses an XSLT stylesheet, adding the associated structures.
6331 * xsltParseStylesheetImportedDoc() (xslt.c)
6332 * xsltParseStylesheetInclude() (imports.c)
6334 * Returns the value of the @style parameter if everything
6335 * went right, NULL if something went amiss.
6338 xsltParseStylesheetProcess(xsltStylesheetPtr style
, xmlDocPtr doc
)
6340 xsltCompilerCtxtPtr cctxt
;
6342 int oldIsSimplifiedStylesheet
;
6346 if ((style
== NULL
) || (doc
== NULL
))
6349 cctxt
= XSLT_CCTXT(style
);
6351 cur
= xmlDocGetRootElement(doc
);
6353 xsltTransformError(NULL
, style
, (xmlNodePtr
) doc
,
6354 "xsltParseStylesheetProcess : empty stylesheet\n");
6357 oldIsSimplifiedStylesheet
= cctxt
->simplified
;
6359 if ((IS_XSLT_ELEM(cur
)) &&
6360 ((IS_XSLT_NAME(cur
, "stylesheet")) ||
6361 (IS_XSLT_NAME(cur
, "transform")))) {
6362 #ifdef WITH_XSLT_DEBUG_PARSING
6363 xsltGenericDebug(xsltGenericDebugContext
,
6364 "xsltParseStylesheetProcess : found stylesheet\n");
6366 cctxt
->simplified
= 0;
6367 style
->literal_result
= 0;
6369 cctxt
->simplified
= 1;
6370 style
->literal_result
= 1;
6373 * Pre-process the stylesheet if not already done before.
6374 * This will remove PIs and comments, merge adjacent
6375 * text nodes, internalize strings, etc.
6377 if (! style
->nopreproc
)
6378 xsltParsePreprocessStylesheetTree(cctxt
, cur
);
6380 * Parse and compile the stylesheet.
6382 if (style
->literal_result
== 0) {
6383 if (xsltParseXSLTStylesheetElem(cctxt
, cur
) != 0)
6386 if (xsltParseSimplifiedStylesheetTree(cctxt
, doc
, cur
) != 0)
6390 cctxt
->simplified
= oldIsSimplifiedStylesheet
;
6395 #else /* XSLT_REFACTORED */
6398 * xsltParseStylesheetProcess:
6399 * @ret: the XSLT stylesheet (the current stylesheet-level)
6400 * @doc: and xmlDoc parsed XML
6402 * Parses an XSLT stylesheet, adding the associated structures.
6404 * xsltParseStylesheetImportedDoc() (xslt.c)
6405 * xsltParseStylesheetInclude() (imports.c)
6407 * Returns the value of the @style parameter if everything
6408 * went right, NULL if something went amiss.
6411 xsltParseStylesheetProcess(xsltStylesheetPtr ret
, xmlDocPtr doc
) {
6422 * First steps, remove blank nodes,
6423 * locate the xsl:stylesheet element and the
6424 * namespace declaration.
6426 cur
= xmlDocGetRootElement(doc
);
6428 xsltTransformError(NULL
, ret
, (xmlNodePtr
) doc
,
6429 "xsltParseStylesheetProcess : empty stylesheet\n");
6433 if ((IS_XSLT_ELEM(cur
)) &&
6434 ((IS_XSLT_NAME(cur
, "stylesheet")) ||
6435 (IS_XSLT_NAME(cur
, "transform")))) {
6436 #ifdef WITH_XSLT_DEBUG_PARSING
6437 xsltGenericDebug(xsltGenericDebugContext
,
6438 "xsltParseStylesheetProcess : found stylesheet\n");
6440 ret
->literal_result
= 0;
6441 xsltParseStylesheetExcludePrefix(ret
, cur
, 1);
6442 xsltParseStylesheetExtPrefix(ret
, cur
, 1);
6444 xsltParseStylesheetExcludePrefix(ret
, cur
, 0);
6445 xsltParseStylesheetExtPrefix(ret
, cur
, 0);
6446 ret
->literal_result
= 1;
6448 if (!ret
->nopreproc
) {
6449 xsltPreprocessStylesheet(ret
, cur
);
6451 if (ret
->literal_result
== 0) {
6452 xsltParseStylesheetTop(ret
, cur
);
6455 xsltTemplatePtr
template;
6458 * the document itself might be the template, check xsl:version
6460 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"version", XSLT_NAMESPACE
);
6462 xsltTransformError(NULL
, ret
, cur
,
6463 "xsltParseStylesheetProcess : document is not a stylesheet\n");
6467 #ifdef WITH_XSLT_DEBUG_PARSING
6468 xsltGenericDebug(xsltGenericDebugContext
,
6469 "xsltParseStylesheetProcess : document is stylesheet\n");
6472 if ((!xmlStrEqual(prop
, (const xmlChar
*)"1.0")) &&
6473 (!xmlStrEqual(prop
, (const xmlChar
*)"1.1"))) {
6474 xsltTransformError(NULL
, ret
, cur
,
6475 "xsl:version: only 1.1 features are supported\n");
6476 ret
->forwards_compatible
= 1;
6482 * Create and link the template
6484 template = xsltNewTemplate();
6485 if (template == NULL
) {
6488 template->next
= ret
->templates
;
6489 ret
->templates
= template;
6490 template->match
= xmlStrdup((const xmlChar
*)"/");
6493 * parse the content and register the pattern
6495 xsltParseTemplateContent(ret
, (xmlNodePtr
) doc
);
6496 template->elem
= (xmlNodePtr
) doc
;
6497 template->content
= doc
->children
;
6498 xsltAddTemplate(ret
, template, NULL
, NULL
);
6499 ret
->literal_result
= 1;
6505 #endif /* else of XSLT_REFACTORED */
6508 * xsltParseStylesheetImportedDoc:
6509 * @doc: an xmlDoc parsed XML
6510 * @parentStyle: pointer to the parent stylesheet (if it exists)
6512 * parse an XSLT stylesheet building the associated structures
6513 * except the processing not needed for imported documents.
6515 * Returns a new XSLT stylesheet structure.
6519 xsltParseStylesheetImportedDoc(xmlDocPtr doc
,
6520 xsltStylesheetPtr parentStyle
) {
6521 xsltStylesheetPtr retStyle
;
6526 retStyle
= xsltNewStylesheetInternal(parentStyle
);
6527 if (retStyle
== NULL
)
6530 if (xsltParseStylesheetUser(retStyle
, doc
) != 0) {
6531 xsltFreeStylesheet(retStyle
);
6539 * xsltParseStylesheetUser:
6540 * @style: pointer to the stylesheet
6541 * @doc: an xmlDoc parsed XML
6543 * Parse an XSLT stylesheet with a user-provided stylesheet struct.
6545 * Returns 0 if successful, -1 in case of error.
6548 xsltParseStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
) {
6549 if ((style
== NULL
) || (doc
== NULL
))
6553 * Adjust the string dict.
6555 if (doc
->dict
!= NULL
) {
6556 xmlDictFree(style
->dict
);
6557 style
->dict
= doc
->dict
;
6558 #ifdef WITH_XSLT_DEBUG
6559 xsltGenericDebug(xsltGenericDebugContext
,
6560 "reusing dictionary from %s for stylesheet\n",
6563 xmlDictReference(style
->dict
);
6567 * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
6568 * the stylesheet to containt distinct namespace prefixes.
6570 xsltGatherNamespaces(style
);
6572 #ifdef XSLT_REFACTORED
6574 xsltCompilerCtxtPtr cctxt
;
6575 xsltStylesheetPtr oldCurSheet
;
6577 if (style
->parent
== NULL
) {
6578 xsltPrincipalStylesheetDataPtr principalData
;
6580 * Create extra data for the principal stylesheet.
6582 principalData
= xsltNewPrincipalStylesheetData();
6583 if (principalData
== NULL
) {
6586 style
->principalData
= principalData
;
6588 * Create the compilation context
6589 * ------------------------------
6590 * (only once; for the principal stylesheet).
6591 * This is currently the only function where the
6592 * compilation context is created.
6594 cctxt
= xsltCompilationCtxtCreate(style
);
6595 if (cctxt
== NULL
) {
6598 style
->compCtxt
= (void *) cctxt
;
6599 cctxt
->style
= style
;
6600 cctxt
->dict
= style
->dict
;
6601 cctxt
->psData
= principalData
;
6603 * Push initial dummy node info.
6606 xsltCompilerNodePush(cctxt
, (xmlNodePtr
) doc
);
6609 * Imported stylesheet.
6611 cctxt
= style
->parent
->compCtxt
;
6612 style
->compCtxt
= cctxt
;
6615 * Save the old and set the current stylesheet structure in the
6616 * compilation context.
6618 oldCurSheet
= cctxt
->style
;
6619 cctxt
->style
= style
;
6622 xsltParseStylesheetProcess(style
, doc
);
6624 cctxt
->style
= oldCurSheet
;
6625 if (style
->parent
== NULL
) {
6627 * Pop the initial dummy node info.
6629 xsltCompilerNodePop(cctxt
, (xmlNodePtr
) doc
);
6632 * Clear the compilation context of imported
6636 /* style->compCtxt = NULL; */
6639 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6640 if (style
->errors
!= 0) {
6642 * Restore all changes made to namespace URIs of ns-decls.
6644 if (cctxt
->psData
->nsMap
)
6645 xsltRestoreDocumentNamespaces(cctxt
->psData
->nsMap
, doc
);
6649 if (style
->parent
== NULL
) {
6650 xsltCompilationCtxtFree(style
->compCtxt
);
6651 style
->compCtxt
= NULL
;
6655 #else /* XSLT_REFACTORED */
6660 if (xsltParseStylesheetProcess(style
, doc
) == NULL
) {
6664 #endif /* else of XSLT_REFACTORED */
6666 if (style
->parent
== NULL
)
6667 xsltResolveStylesheetAttributeSet(style
);
6669 if (style
->errors
!= 0) {
6671 * Detach the doc from the stylesheet; otherwise the doc
6672 * will be freed in xsltFreeStylesheet().
6676 * Cleanup the doc if its the main stylesheet.
6678 if (style
->parent
== NULL
)
6679 xsltCleanupStylesheetTree(doc
, xmlDocGetRootElement(doc
));
6687 * xsltParseStylesheetDoc:
6688 * @doc: an xmlDoc parsed XML
6690 * parse an XSLT stylesheet, building the associated structures. doc
6691 * is kept as a reference within the returned stylesheet, so changes
6692 * to doc after the parsing will be reflected when the stylesheet
6693 * is applied, and the doc is automatically freed when the
6694 * stylesheet is closed.
6696 * Returns a new XSLT stylesheet structure.
6700 xsltParseStylesheetDoc(xmlDocPtr doc
) {
6703 return(xsltParseStylesheetImportedDoc(doc
, NULL
));
6707 * xsltParseStylesheetFile:
6708 * @filename: the filename/URL to the stylesheet
6710 * Load and parse an XSLT stylesheet
6712 * Returns a new XSLT stylesheet structure.
6716 xsltParseStylesheetFile(const xmlChar
* filename
) {
6717 xsltSecurityPrefsPtr sec
;
6718 xsltStylesheetPtr ret
;
6723 if (filename
== NULL
)
6726 #ifdef WITH_XSLT_DEBUG_PARSING
6727 xsltGenericDebug(xsltGenericDebugContext
,
6728 "xsltParseStylesheetFile : parse %s\n", filename
);
6732 * Security framework check
6734 sec
= xsltGetDefaultSecurityPrefs();
6738 res
= xsltCheckRead(sec
, NULL
, filename
);
6741 xsltTransformError(NULL
, NULL
, NULL
,
6742 "xsltParseStylesheetFile: read rights for %s denied\n",
6748 doc
= xsltDocDefaultLoader(filename
, NULL
, XSLT_PARSE_OPTIONS
,
6749 NULL
, XSLT_LOAD_START
);
6751 xsltTransformError(NULL
, NULL
, NULL
,
6752 "xsltParseStylesheetFile : cannot parse %s\n", filename
);
6755 ret
= xsltParseStylesheetDoc(doc
);
6764 /************************************************************************
6766 * Handling of Stylesheet PI *
6768 ************************************************************************/
6771 #define SKIP(val) cur += (val)
6772 #define NXT(val) cur[(val)]
6773 #define SKIP_BLANKS \
6774 while (IS_BLANK(CUR)) NEXT
6775 #define NEXT ((*cur) ? cur++ : cur)
6778 * xsltParseStylesheetPI:
6779 * @value: the value of the PI
6781 * This function checks that the type is text/xml and extracts
6782 * the URI-Reference for the stylesheet
6784 * Returns the URI-Reference for the stylesheet or NULL (it need to
6785 * be freed by the caller)
6788 xsltParseStylesheetPI(const xmlChar
*value
) {
6790 const xmlChar
*start
;
6793 xmlChar
*href
= NULL
;
6802 if ((CUR
== 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
6809 if ((CUR
!= '\'') && (CUR
!= '"'))
6814 while ((CUR
!= 0) && (CUR
!= tmp
))
6818 val
= xmlStrndup(start
, cur
- start
);
6822 if ((xmlStrcasecmp(val
, BAD_CAST
"text/xml")) &&
6823 (xmlStrcasecmp(val
, BAD_CAST
"text/xsl")) &&
6824 (xmlStrcasecmp(val
, BAD_CAST
"application/xslt+xml"))) {
6830 } else if ((CUR
== 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
6837 if ((CUR
!= '\'') && (CUR
!= '"'))
6842 while ((CUR
!= 0) && (CUR
!= tmp
))
6847 href
= xmlStrndup(start
, cur
- start
);
6850 while ((CUR
!= 0) && (!IS_BLANK(CUR
)))
6865 * xsltLoadStylesheetPI:
6866 * @doc: a document to process
6868 * This function tries to locate the stylesheet PI in the given document
6869 * If found, and if contained within the document, it will extract
6870 * that subtree to build the stylesheet to process @doc (doc itself will
6871 * be modified). If found but referencing an external document it will
6872 * attempt to load it and generate a stylesheet from it. In both cases,
6873 * the resulting stylesheet and the document need to be freed once the
6874 * transformation is done.
6876 * Returns a new XSLT stylesheet structure or NULL if not found.
6879 xsltLoadStylesheetPI(xmlDocPtr doc
) {
6881 xsltStylesheetPtr ret
= NULL
;
6882 xmlChar
*href
= NULL
;
6891 * Find the text/xml stylesheet PI id any before the root
6893 child
= doc
->children
;
6894 while ((child
!= NULL
) && (child
->type
!= XML_ELEMENT_NODE
)) {
6895 if ((child
->type
== XML_PI_NODE
) &&
6896 (xmlStrEqual(child
->name
, BAD_CAST
"xml-stylesheet"))) {
6897 href
= xsltParseStylesheetPI(child
->content
);
6901 child
= child
->next
;
6905 * If found check the href to select processing
6908 #ifdef WITH_XSLT_DEBUG_PARSING
6909 xsltGenericDebug(xsltGenericDebugContext
,
6910 "xsltLoadStylesheetPI : found PI href=%s\n", href
);
6912 URI
= xmlParseURI((const char *) href
);
6914 xsltTransformError(NULL
, NULL
, child
,
6915 "xml-stylesheet : href %s is not valid\n", href
);
6919 if ((URI
->fragment
!= NULL
) && (URI
->scheme
== NULL
) &&
6920 (URI
->opaque
== NULL
) && (URI
->authority
== NULL
) &&
6921 (URI
->server
== NULL
) && (URI
->user
== NULL
) &&
6922 (URI
->path
== NULL
) && (URI
->query
== NULL
)) {
6925 #ifdef WITH_XSLT_DEBUG_PARSING
6926 xsltGenericDebug(xsltGenericDebugContext
,
6927 "xsltLoadStylesheetPI : Reference to ID %s\n", href
);
6929 if (URI
->fragment
[0] == '#')
6930 ID
= xmlGetID(doc
, (const xmlChar
*) &(URI
->fragment
[1]));
6932 ID
= xmlGetID(doc
, (const xmlChar
*) URI
->fragment
);
6934 xsltTransformError(NULL
, NULL
, child
,
6935 "xml-stylesheet : no ID %s found\n", URI
->fragment
);
6938 xmlNodePtr subtree
, newtree
;
6941 #ifdef WITH_XSLT_DEBUG
6942 xsltGenericDebug(xsltGenericDebugContext
,
6943 "creating new document from %s for embedded stylesheet\n",
6947 * move the subtree in a new document passed to
6948 * the stylesheet analyzer
6950 subtree
= ID
->parent
;
6951 fake
= xmlNewDoc(NULL
);
6954 * Should the dictionary still be shared even though
6955 * the nodes are being copied rather than moved?
6957 fake
->dict
= doc
->dict
;
6958 xmlDictReference(doc
->dict
);
6959 #ifdef WITH_XSLT_DEBUG
6960 xsltGenericDebug(xsltGenericDebugContext
,
6961 "reusing dictionary from %s for embedded stylesheet\n",
6965 newtree
= xmlDocCopyNode(subtree
, fake
, 1);
6967 fake
->URL
= xmlNodeGetBase(doc
, subtree
->parent
);
6968 #ifdef WITH_XSLT_DEBUG
6969 xsltGenericDebug(xsltGenericDebugContext
,
6970 "set base URI for embedded stylesheet as %s\n",
6975 * Add all namespaces in scope of embedded stylesheet to
6976 * root element of newly created stylesheet document
6978 while ((subtree
= subtree
->parent
) != (xmlNodePtr
)doc
) {
6979 for (ns
= subtree
->ns
; ns
; ns
= ns
->next
) {
6980 xmlNewNs(newtree
, ns
->href
, ns
->prefix
);
6984 xmlAddChild((xmlNodePtr
)fake
, newtree
);
6985 ret
= xsltParseStylesheetDoc(fake
);
6991 xmlChar
*URL
, *base
;
6994 * Reference to an external stylesheet
6997 base
= xmlNodeGetBase(doc
, (xmlNodePtr
) doc
);
6998 URL
= xmlBuildURI(href
, base
);
7000 #ifdef WITH_XSLT_DEBUG_PARSING
7001 xsltGenericDebug(xsltGenericDebugContext
,
7002 "xsltLoadStylesheetPI : fetching %s\n", URL
);
7004 ret
= xsltParseStylesheetFile(URL
);
7007 #ifdef WITH_XSLT_DEBUG_PARSING
7008 xsltGenericDebug(xsltGenericDebugContext
,
7009 "xsltLoadStylesheetPI : fetching %s\n", href
);
7011 ret
= xsltParseStylesheetFile(href
);