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.
18 #ifdef WITH_XSLT_DEBUG
19 #define WITH_XSLT_DEBUG_PARSING
20 /* #define WITH_XSLT_DEBUG_BLANKS */
23 const char *xsltEngineVersion
= LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA
;
24 const int xsltLibxsltVersion
= LIBXSLT_VERSION
;
25 const int xsltLibxmlVersion
= LIBXML_VERSION
;
27 #ifdef XSLT_REFACTORED
29 const xmlChar
*xsltConstNamespaceNameXSLT
= (const xmlChar
*) XSLT_NAMESPACE
;
31 #define XSLT_ELEMENT_CATEGORY_XSLT 0
32 #define XSLT_ELEMENT_CATEGORY_EXTENSION 1
33 #define XSLT_ELEMENT_CATEGORY_LRE 2
36 * xsltLiteralResultMarker:
37 * Marker for Literal result elements, in order to avoid multiple attempts
38 * to recognize such elements in the stylesheet's tree.
39 * This marker is set on node->psvi during the initial traversal
40 * of a stylesheet's node tree.
42 const xmlChar *xsltLiteralResultMarker =
43 (const xmlChar *) "Literal Result Element";
48 * Marker for xsl:text elements. Used to recognize xsl:text elements
49 * for post-processing of the stylesheet's tree, where those
50 * elements are removed from the tree.
52 const xmlChar
*xsltXSLTTextMarker
= (const xmlChar
*) "XSLT Text Element";
56 * Marker for XSLT attribute on Literal Result Elements.
58 const xmlChar
*xsltXSLTAttrMarker
= (const xmlChar
*) "LRE XSLT Attr";
62 #ifdef XSLT_LOCALE_WINAPI
63 extern xmlRMutexPtr xsltLocaleMutex
;
66 * Harmless but avoiding a problem when compiling against a
67 * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
69 #ifndef LIBXML_DEBUG_ENABLED
70 double xmlXPathStringEvalNumber(const xmlChar
*str
);
79 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
85 #define IS_BLANK_NODE(n) \
86 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
89 * xsltParseContentError:
91 * @style: the stylesheet
92 * @node: the node where the error occured
94 * Compile-time error function.
97 xsltParseContentError(xsltStylesheetPtr style
,
100 if ((style
== NULL
) || (node
== NULL
))
103 if (IS_XSLT_ELEM(node
))
104 xsltTransformError(NULL
, style
, node
,
105 "The XSLT-element '%s' is not allowed at this position.\n",
108 xsltTransformError(NULL
, style
, node
,
109 "The element '%s' is not allowed at this position.\n",
114 #ifdef XSLT_REFACTORED
118 * @style: the transformation stylesheet
119 * @value: the excluded namespace name to push on the stack
121 * Push an excluded namespace name on the stack
123 * Returns the new index in the stack or -1 if already present or
127 exclPrefixPush(xsltStylesheetPtr style
, xmlChar
* value
)
131 if (style
->exclPrefixMax
== 0) {
132 style
->exclPrefixMax
= 4;
133 style
->exclPrefixTab
=
134 (xmlChar
* *)xmlMalloc(style
->exclPrefixMax
*
135 sizeof(style
->exclPrefixTab
[0]));
136 if (style
->exclPrefixTab
== NULL
) {
137 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
141 /* do not push duplicates */
142 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
143 if (xmlStrEqual(style
->exclPrefixTab
[i
], value
))
146 if (style
->exclPrefixNr
>= style
->exclPrefixMax
) {
147 style
->exclPrefixMax
*= 2;
148 style
->exclPrefixTab
=
149 (xmlChar
* *)xmlRealloc(style
->exclPrefixTab
,
150 style
->exclPrefixMax
*
151 sizeof(style
->exclPrefixTab
[0]));
152 if (style
->exclPrefixTab
== NULL
) {
153 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
157 style
->exclPrefixTab
[style
->exclPrefixNr
] = value
;
158 style
->exclPrefix
= value
;
159 return (style
->exclPrefixNr
++);
163 * @style: the transformation stylesheet
165 * Pop an excluded prefix value from the stack
167 * Returns the stored excluded prefix value
170 exclPrefixPop(xsltStylesheetPtr style
)
174 if (style
->exclPrefixNr
<= 0)
176 style
->exclPrefixNr
--;
177 if (style
->exclPrefixNr
> 0)
178 style
->exclPrefix
= style
->exclPrefixTab
[style
->exclPrefixNr
- 1];
180 style
->exclPrefix
= NULL
;
181 ret
= style
->exclPrefixTab
[style
->exclPrefixNr
];
182 style
->exclPrefixTab
[style
->exclPrefixNr
] = 0;
187 /************************************************************************
191 ************************************************************************/
193 static int initialized
= 0;
197 * Initializes the processor (e.g. registers built-in extensions,
202 if (initialized
== 0) {
204 #ifdef XSLT_LOCALE_WINAPI
205 xsltLocaleMutex
= xmlNewRMutex();
207 xsltRegisterAllExtras();
214 * Uninitializes the processor.
218 #ifdef XSLT_LOCALE_WINAPI
219 xmlFreeRMutex(xsltLocaleMutex
);
220 xsltLocaleMutex
= NULL
;
229 * Check if a string is ignorable
231 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
234 xsltIsBlank(xmlChar
*str
) {
238 if (!(IS_BLANK(*str
))) return(0);
244 /************************************************************************
246 * Routines to handle XSLT data structures *
248 ************************************************************************/
249 static xsltDecimalFormatPtr
250 xsltNewDecimalFormat(const xmlChar
*nsUri
, xmlChar
*name
)
252 xsltDecimalFormatPtr self
;
253 /* UTF-8 for 0x2030 */
254 static const xmlChar permille
[4] = {0xe2, 0x80, 0xb0, 0};
256 self
= xmlMalloc(sizeof(xsltDecimalFormat
));
263 self
->digit
= xmlStrdup(BAD_CAST("#"));
264 self
->patternSeparator
= xmlStrdup(BAD_CAST(";"));
265 self
->decimalPoint
= xmlStrdup(BAD_CAST("."));
266 self
->grouping
= xmlStrdup(BAD_CAST(","));
267 self
->percent
= xmlStrdup(BAD_CAST("%"));
268 self
->permille
= xmlStrdup(BAD_CAST(permille
));
269 self
->zeroDigit
= xmlStrdup(BAD_CAST("0"));
270 self
->minusSign
= xmlStrdup(BAD_CAST("-"));
271 self
->infinity
= xmlStrdup(BAD_CAST("Infinity"));
272 self
->noNumber
= xmlStrdup(BAD_CAST("NaN"));
278 xsltFreeDecimalFormat(xsltDecimalFormatPtr self
)
282 xmlFree(self
->digit
);
283 if (self
->patternSeparator
)
284 xmlFree(self
->patternSeparator
);
285 if (self
->decimalPoint
)
286 xmlFree(self
->decimalPoint
);
288 xmlFree(self
->grouping
);
290 xmlFree(self
->percent
);
292 xmlFree(self
->permille
);
294 xmlFree(self
->zeroDigit
);
296 xmlFree(self
->minusSign
);
298 xmlFree(self
->infinity
);
300 xmlFree(self
->noNumber
);
308 xsltFreeDecimalFormatList(xsltStylesheetPtr self
)
310 xsltDecimalFormatPtr iter
;
311 xsltDecimalFormatPtr tmp
;
316 iter
= self
->decimalFormat
;
317 while (iter
!= NULL
) {
319 xsltFreeDecimalFormat(iter
);
325 * xsltDecimalFormatGetByName:
326 * @style: the XSLT stylesheet
327 * @name: the decimal-format name to find
329 * Find decimal-format by name
331 * Returns the xsltDecimalFormatPtr
334 xsltDecimalFormatGetByName(xsltStylesheetPtr style
, xmlChar
*name
)
336 xsltDecimalFormatPtr result
= NULL
;
339 return style
->decimalFormat
;
341 while (style
!= NULL
) {
342 for (result
= style
->decimalFormat
->next
;
344 result
= result
->next
) {
345 if ((result
->nsUri
== NULL
) && xmlStrEqual(name
, result
->name
))
348 style
= xsltNextImport(style
);
354 * xsltDecimalFormatGetByQName:
355 * @style: the XSLT stylesheet
356 * @nsUri: the namespace URI of the QName
357 * @name: the local part of the QName
359 * Find decimal-format by QName
361 * Returns the xsltDecimalFormatPtr
364 xsltDecimalFormatGetByQName(xsltStylesheetPtr style
, const xmlChar
*nsUri
,
367 xsltDecimalFormatPtr result
= NULL
;
370 return style
->decimalFormat
;
372 while (style
!= NULL
) {
373 for (result
= style
->decimalFormat
->next
;
375 result
= result
->next
) {
376 if (xmlStrEqual(nsUri
, result
->nsUri
) &&
377 xmlStrEqual(name
, result
->name
))
380 style
= xsltNextImport(style
);
389 * Create a new XSLT Template
391 * Returns the newly allocated xsltTemplatePtr or NULL in case of error
393 static xsltTemplatePtr
394 xsltNewTemplate(void) {
397 cur
= (xsltTemplatePtr
) xmlMalloc(sizeof(xsltTemplate
));
399 xsltTransformError(NULL
, NULL
, NULL
,
400 "xsltNewTemplate : malloc failed\n");
403 memset(cur
, 0, sizeof(xsltTemplate
));
404 cur
->priority
= XSLT_PAT_NO_PRIORITY
;
410 * @template: an XSLT template
412 * Free up the memory allocated by @template
415 xsltFreeTemplate(xsltTemplatePtr
template) {
416 if (template == NULL
)
418 if (template->match
) xmlFree(template->match
);
420 * NOTE: @name and @nameURI are put into the string dict now.
421 * if (template->name) xmlFree(template->name);
422 * if (template->nameURI) xmlFree(template->nameURI);
425 if (template->mode) xmlFree(template->mode);
426 if (template->modeURI) xmlFree(template->modeURI);
428 if (template->inheritedNs
) xmlFree(template->inheritedNs
);
430 /* free profiling data */
431 if (template->templCalledTab
) xmlFree(template->templCalledTab
);
432 if (template->templCountTab
) xmlFree(template->templCountTab
);
434 memset(template, -1, sizeof(xsltTemplate
));
439 * xsltFreeTemplateList:
440 * @template: an XSLT template list
442 * Free up the memory allocated by all the elements of @template
445 xsltFreeTemplateList(xsltTemplatePtr
template) {
448 while (template != NULL
) {
450 template = template->next
;
451 xsltFreeTemplate(cur
);
455 #ifdef XSLT_REFACTORED
458 xsltFreeNsAliasList(xsltNsAliasPtr item
)
470 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
472 xsltFreeNamespaceMap(xsltNsMapPtr item
)
485 xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt
,
492 if ((cctxt
== NULL
) || (doc
== NULL
) || (ns
== NULL
))
495 ret
= (xsltNsMapPtr
) xmlMalloc(sizeof(xsltNsMap
));
497 xsltTransformError(NULL
, cctxt
->style
, elem
,
498 "Internal error: (xsltNewNamespaceMapItem) "
499 "memory allocation failed.\n");
502 memset(ret
, 0, sizeof(xsltNsMap
));
505 ret
->origNsName
= ns
->href
;
507 * Store the item at current stylesheet-level.
509 if (cctxt
->psData
->nsMap
!= NULL
)
510 ret
->next
= cctxt
->psData
->nsMap
;
511 cctxt
->psData
->nsMap
= ret
;
515 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
518 * xsltCompilerVarInfoFree:
519 * @cctxt: the compilation context
521 * Frees the list of information for vars/params.
524 xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt
)
526 xsltVarInfoPtr ivar
= cctxt
->ivars
, ivartmp
;
536 * xsltCompilerCtxtFree:
538 * Free an XSLT compiler context.
541 xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt
)
545 #ifdef WITH_XSLT_DEBUG_PARSING
546 xsltGenericDebug(xsltGenericDebugContext
,
547 "Freeing compilation context\n");
548 xsltGenericDebug(xsltGenericDebugContext
,
549 "### Max inodes: %d\n", cctxt
->maxNodeInfos
);
550 xsltGenericDebug(xsltGenericDebugContext
,
551 "### Max LREs : %d\n", cctxt
->maxLREs
);
556 if (cctxt
->inodeList
!= NULL
) {
557 xsltCompilerNodeInfoPtr tmp
, cur
= cctxt
->inodeList
;
558 while (cur
!= NULL
) {
564 if (cctxt
->tmpList
!= NULL
)
565 xsltPointerListFree(cctxt
->tmpList
);
566 #ifdef XSLT_REFACTORED_XPATHCOMP
567 if (cctxt
->xpathCtxt
!= NULL
)
568 xmlXPathFreeContext(cctxt
->xpathCtxt
);
570 if (cctxt
->nsAliases
!= NULL
)
571 xsltFreeNsAliasList(cctxt
->nsAliases
);
574 xsltCompilerVarInfoFree(cctxt
);
580 * xsltCompilerCreate:
582 * Creates an XSLT compiler context.
584 * Returns the pointer to the created xsltCompilerCtxt or
585 * NULL in case of an internal error.
587 static xsltCompilerCtxtPtr
588 xsltCompilationCtxtCreate(xsltStylesheetPtr style
) {
589 xsltCompilerCtxtPtr ret
;
591 ret
= (xsltCompilerCtxtPtr
) xmlMalloc(sizeof(xsltCompilerCtxt
));
593 xsltTransformError(NULL
, style
, NULL
,
594 "xsltCompilerCreate: allocation of compiler "
595 "context failed.\n");
598 memset(ret
, 0, sizeof(xsltCompilerCtxt
));
600 ret
->errSeverity
= XSLT_ERROR_SEVERITY_ERROR
;
601 ret
->tmpList
= xsltPointerListCreate(20);
602 if (ret
->tmpList
== NULL
) {
605 #ifdef XSLT_REFACTORED_XPATHCOMP
607 * Create the XPath compilation context in order
608 * to speed up precompilation of XPath expressions.
610 ret
->xpathCtxt
= xmlXPathNewContext(NULL
);
611 if (ret
->xpathCtxt
== NULL
)
618 xsltCompilationCtxtFree(ret
);
623 xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first
)
625 xsltEffectiveNsPtr tmp
;
627 while (first
!= NULL
) {
629 first
= first
->nextInStore
;
635 xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data
)
640 if (data
->inScopeNamespaces
!= NULL
) {
642 xsltNsListContainerPtr nsi
;
643 xsltPointerListPtr list
=
644 (xsltPointerListPtr
) data
->inScopeNamespaces
;
646 for (i
= 0; i
< list
->number
; i
++) {
648 * REVISIT TODO: Free info of in-scope namespaces.
650 nsi
= (xsltNsListContainerPtr
) list
->items
[i
];
651 if (nsi
->list
!= NULL
)
655 xsltPointerListFree(list
);
656 data
->inScopeNamespaces
= NULL
;
659 if (data
->exclResultNamespaces
!= NULL
) {
661 xsltPointerListPtr list
= (xsltPointerListPtr
)
662 data
->exclResultNamespaces
;
664 for (i
= 0; i
< list
->number
; i
++)
665 xsltPointerListFree((xsltPointerListPtr
) list
->items
[i
]);
667 xsltPointerListFree(list
);
668 data
->exclResultNamespaces
= NULL
;
671 if (data
->extElemNamespaces
!= NULL
) {
672 xsltPointerListPtr list
= (xsltPointerListPtr
)
673 data
->extElemNamespaces
;
676 for (i
= 0; i
< list
->number
; i
++)
677 xsltPointerListFree((xsltPointerListPtr
) list
->items
[i
]);
679 xsltPointerListFree(list
);
680 data
->extElemNamespaces
= NULL
;
682 if (data
->effectiveNs
) {
683 xsltLREEffectiveNsNodesFree(data
->effectiveNs
);
684 data
->effectiveNs
= NULL
;
686 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
687 xsltFreeNamespaceMap(data
->nsMap
);
692 static xsltPrincipalStylesheetDataPtr
693 xsltNewPrincipalStylesheetData(void)
695 xsltPrincipalStylesheetDataPtr ret
;
697 ret
= (xsltPrincipalStylesheetDataPtr
)
698 xmlMalloc(sizeof(xsltPrincipalStylesheetData
));
700 xsltTransformError(NULL
, NULL
, NULL
,
701 "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
704 memset(ret
, 0, sizeof(xsltPrincipalStylesheetData
));
707 * Global list of in-scope namespaces.
709 ret
->inScopeNamespaces
= xsltPointerListCreate(-1);
710 if (ret
->inScopeNamespaces
== NULL
)
713 * Global list of excluded result ns-decls.
715 ret
->exclResultNamespaces
= xsltPointerListCreate(-1);
716 if (ret
->exclResultNamespaces
== NULL
)
719 * Global list of extension instruction namespace names.
721 ret
->extElemNamespaces
= xsltPointerListCreate(-1);
722 if (ret
->extElemNamespaces
== NULL
)
737 * Create a new XSLT Stylesheet
739 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
742 xsltNewStylesheet(void) {
743 xsltStylesheetPtr ret
= NULL
;
745 ret
= (xsltStylesheetPtr
) xmlMalloc(sizeof(xsltStylesheet
));
747 xsltTransformError(NULL
, NULL
, NULL
,
748 "xsltNewStylesheet : malloc failed\n");
751 memset(ret
, 0, sizeof(xsltStylesheet
));
753 ret
->omitXmlDeclaration
= -1;
754 ret
->standalone
= -1;
755 ret
->decimalFormat
= xsltNewDecimalFormat(NULL
, NULL
);
759 ret
->exclPrefixNr
= 0;
760 ret
->exclPrefixMax
= 0;
761 ret
->exclPrefixTab
= NULL
;
762 ret
->extInfos
= NULL
;
764 ret
->internalized
= 1;
765 ret
->literal_result
= 0;
766 ret
->forwards_compatible
= 0;
767 ret
->dict
= xmlDictCreate();
768 #ifdef WITH_XSLT_DEBUG
769 xsltGenericDebug(xsltGenericDebugContext
,
770 "creating dictionary for stylesheet\n");
779 xsltFreeStylesheet(ret
);
785 * @style: an XSLT stylesheet
787 * Allocate an extra runtime information slot statically while compiling
788 * the stylesheet and return its number
790 * Returns the number of the slot
793 xsltAllocateExtra(xsltStylesheetPtr style
)
795 return(style
->extrasNr
++);
799 * xsltAllocateExtraCtxt:
800 * @ctxt: an XSLT transformation context
802 * Allocate an extra runtime information slot at run-time
803 * and return its number
804 * This make sure there is a slot ready in the transformation context
806 * Returns the number of the slot
809 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt
)
811 if (ctxt
->extrasNr
>= ctxt
->extrasMax
) {
813 if (ctxt
->extrasNr
== 0) {
814 ctxt
->extrasMax
= 20;
815 ctxt
->extras
= (xsltRuntimeExtraPtr
)
816 xmlMalloc(ctxt
->extrasMax
* sizeof(xsltRuntimeExtra
));
817 if (ctxt
->extras
== NULL
) {
818 xsltTransformError(ctxt
, NULL
, NULL
,
819 "xsltAllocateExtraCtxt: out of memory\n");
822 for (i
= 0;i
< ctxt
->extrasMax
;i
++) {
823 ctxt
->extras
[i
].info
= NULL
;
824 ctxt
->extras
[i
].deallocate
= NULL
;
825 ctxt
->extras
[i
].val
.ptr
= NULL
;
829 xsltRuntimeExtraPtr tmp
;
831 ctxt
->extrasMax
+= 100;
832 tmp
= (xsltRuntimeExtraPtr
) xmlRealloc(ctxt
->extras
,
833 ctxt
->extrasMax
* sizeof(xsltRuntimeExtra
));
835 xsltTransformError(ctxt
, NULL
, NULL
,
836 "xsltAllocateExtraCtxt: out of memory\n");
840 for (i
= ctxt
->extrasNr
;i
< ctxt
->extrasMax
;i
++) {
841 ctxt
->extras
[i
].info
= NULL
;
842 ctxt
->extras
[i
].deallocate
= NULL
;
843 ctxt
->extras
[i
].val
.ptr
= NULL
;
847 return(ctxt
->extrasNr
++);
851 * xsltFreeStylesheetList:
852 * @style: an XSLT stylesheet list
854 * Free up the memory allocated by the list @style
857 xsltFreeStylesheetList(xsltStylesheetPtr style
) {
858 xsltStylesheetPtr next
;
860 while (style
!= NULL
) {
862 xsltFreeStylesheet(style
);
868 * xsltCleanupStylesheetTree:
870 * @doc: the document-node
871 * @node: the element where the stylesheet is rooted at
873 * Actually @node need not be the document-element, but
874 * currently Libxslt does not support embedded stylesheets.
876 * Returns 0 if OK, -1 on API or internal errors.
879 xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED
,
880 xmlNodePtr rootElem ATTRIBUTE_UNUSED
)
882 #if 0 /* TODO: Currently disabled, since probably not needed. */
885 if ((doc
== NULL
) || (rootElem
== NULL
) ||
886 (rootElem
->type
!= XML_ELEMENT_NODE
) ||
887 (doc
!= rootElem
->doc
))
891 * Cleanup was suggested by Aleksey Sanin:
892 * Clear the PSVI field to avoid problems if the
893 * node-tree of the stylesheet is intended to be used for
894 * further processing by the user (e.g. for compiling it
895 * once again - although not recommended).
899 while (cur
!= NULL
) {
900 if (cur
->type
== XML_ELEMENT_NODE
) {
902 * Clear the PSVI field.
914 if (cur
->next
!= NULL
)
928 * xsltFreeStylesheet:
929 * @style: an XSLT stylesheet
931 * Free up the memory allocated by @style
934 xsltFreeStylesheet(xsltStylesheetPtr style
)
939 #ifdef XSLT_REFACTORED
941 * Start with a cleanup of the main stylesheet's doc.
943 if ((style
->principal
== style
) && (style
->doc
))
944 xsltCleanupStylesheetTree(style
->doc
,
945 xmlDocGetRootElement(style
->doc
));
946 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
948 * Restore changed ns-decls before freeing the document.
950 if ((style
->doc
!= NULL
) &&
951 XSLT_HAS_INTERNAL_NSMAP(style
))
953 xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style
),
956 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
959 * Start with a cleanup of the main stylesheet's doc.
961 if ((style
->parent
== NULL
) && (style
->doc
))
962 xsltCleanupStylesheetTree(style
->doc
,
963 xmlDocGetRootElement(style
->doc
));
964 #endif /* XSLT_REFACTORED */
968 xsltFreeTemplateHashes(style
);
969 xsltFreeDecimalFormatList(style
);
970 xsltFreeTemplateList(style
->templates
);
971 xsltFreeAttributeSetsHashes(style
);
972 xsltFreeNamespaceAliasHashes(style
);
973 xsltFreeStylePreComps(style
);
975 * Free documents of all included stylsheet modules of this
978 xsltFreeStyleDocuments(style
);
980 * TODO: Best time to shutdown extension stuff?
982 xsltShutdownExts(style
);
984 if (style
->variables
!= NULL
)
985 xsltFreeStackElemList(style
->variables
);
986 if (style
->cdataSection
!= NULL
)
987 xmlHashFree(style
->cdataSection
, NULL
);
988 if (style
->stripSpaces
!= NULL
)
989 xmlHashFree(style
->stripSpaces
, NULL
);
990 if (style
->nsHash
!= NULL
)
991 xmlHashFree(style
->nsHash
, NULL
);
992 if (style
->exclPrefixTab
!= NULL
)
993 xmlFree(style
->exclPrefixTab
);
994 if (style
->method
!= NULL
)
995 xmlFree(style
->method
);
996 if (style
->methodURI
!= NULL
)
997 xmlFree(style
->methodURI
);
998 if (style
->version
!= NULL
)
999 xmlFree(style
->version
);
1000 if (style
->encoding
!= NULL
)
1001 xmlFree(style
->encoding
);
1002 if (style
->doctypePublic
!= NULL
)
1003 xmlFree(style
->doctypePublic
);
1004 if (style
->doctypeSystem
!= NULL
)
1005 xmlFree(style
->doctypeSystem
);
1006 if (style
->mediaType
!= NULL
)
1007 xmlFree(style
->mediaType
);
1009 xsltFreeAVTList(style
->attVTs
);
1010 if (style
->imports
!= NULL
)
1011 xsltFreeStylesheetList(style
->imports
);
1013 #ifdef XSLT_REFACTORED
1015 * If this is the principal stylesheet, then
1016 * free its internal data.
1018 if (style
->principal
== style
) {
1019 if (style
->principalData
) {
1020 xsltFreePrincipalStylesheetData(style
->principalData
);
1021 style
->principalData
= NULL
;
1026 * Better to free the main document of this stylesheet level
1027 * at the end - so here.
1029 if (style
->doc
!= NULL
) {
1030 xmlFreeDoc(style
->doc
);
1033 #ifdef WITH_XSLT_DEBUG
1034 xsltGenericDebug(xsltGenericDebugContext
,
1035 "freeing dictionary from stylesheet\n");
1037 xmlDictFree(style
->dict
);
1039 memset(style
, -1, sizeof(xsltStylesheet
));
1043 /************************************************************************
1045 * Parsing of an XSLT Stylesheet *
1047 ************************************************************************/
1049 #ifdef XSLT_REFACTORED
1051 * This is now performed in an optimized way in xsltParseXSLTTemplate.
1055 * xsltGetInheritedNsList:
1056 * @style: the stylesheet
1057 * @template: the template
1058 * @node: the current node
1060 * Search all the namespace applying to a given element except the ones
1061 * from excluded output prefixes currently in scope. Initialize the
1062 * template inheritedNs list with it.
1064 * Returns the number of entries found
1067 xsltGetInheritedNsList(xsltStylesheetPtr style
,
1068 xsltTemplatePtr
template,
1072 xmlNsPtr
*ret
= NULL
;
1077 if ((style
== NULL
) || (template == NULL
) || (node
== NULL
) ||
1078 (template->inheritedNsNr
!= 0) || (template->inheritedNs
!= NULL
))
1080 while (node
!= NULL
) {
1081 if (node
->type
== XML_ELEMENT_NODE
) {
1083 while (cur
!= NULL
) {
1084 if (xmlStrEqual(cur
->href
, XSLT_NAMESPACE
))
1087 if ((cur
->prefix
!= NULL
) &&
1088 (xsltCheckExtPrefix(style
, cur
->prefix
)))
1091 * Check if this namespace was excluded.
1092 * Note that at this point only the exclusions defined
1093 * on the topmost stylesheet element are in the exclusion-list.
1095 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
1096 if (xmlStrEqual(cur
->href
, style
->exclPrefixTab
[i
]))
1101 (xmlNsPtr
*) xmlMalloc((maxns
+ 1) *
1104 xmlGenericError(xmlGenericErrorContext
,
1105 "xsltGetInheritedNsList : out of memory!\n");
1111 * Skip shadowed namespace bindings.
1113 for (i
= 0; i
< nbns
; i
++) {
1114 if ((cur
->prefix
== ret
[i
]->prefix
) ||
1115 (xmlStrEqual(cur
->prefix
, ret
[i
]->prefix
)))
1119 if (nbns
>= maxns
) {
1121 ret
= (xmlNsPtr
*) xmlRealloc(ret
,
1126 xmlGenericError(xmlGenericErrorContext
,
1127 "xsltGetInheritedNsList : realloc failed!\n");
1138 node
= node
->parent
;
1141 #ifdef WITH_XSLT_DEBUG_PARSING
1142 xsltGenericDebug(xsltGenericDebugContext
,
1143 "template has %d inherited namespaces\n", nbns
);
1145 template->inheritedNsNr
= nbns
;
1146 template->inheritedNs
= ret
;
1150 #endif /* else of XSLT_REFACTORED */
1153 * xsltParseStylesheetOutput:
1154 * @style: the XSLT stylesheet
1155 * @cur: the "output" element
1157 * parse an XSLT stylesheet output element and record
1158 * information related to the stylesheet output
1162 xsltParseStylesheetOutput(xsltStylesheetPtr style
, xmlNodePtr cur
)
1169 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1172 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "version", NULL
);
1174 if (style
->version
!= NULL
)
1175 xmlFree(style
->version
);
1176 style
->version
= prop
;
1179 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "encoding", NULL
);
1181 if (style
->encoding
!= NULL
)
1182 xmlFree(style
->encoding
);
1183 style
->encoding
= prop
;
1186 /* relaxed to support xt:document
1187 * TODO KB: What does "relaxed to support xt:document" mean?
1189 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "method", NULL
);
1193 if (style
->method
!= NULL
)
1194 xmlFree(style
->method
);
1195 style
->method
= NULL
;
1196 if (style
->methodURI
!= NULL
)
1197 xmlFree(style
->methodURI
);
1198 style
->methodURI
= NULL
;
1201 * TODO: Don't use xsltGetQNameURI().
1203 URI
= xsltGetQNameURI(cur
, &prop
);
1205 if (style
!= NULL
) style
->errors
++;
1206 } else if (URI
== NULL
) {
1207 if ((xmlStrEqual(prop
, (const xmlChar
*) "xml")) ||
1208 (xmlStrEqual(prop
, (const xmlChar
*) "html")) ||
1209 (xmlStrEqual(prop
, (const xmlChar
*) "text"))) {
1210 style
->method
= prop
;
1212 xsltTransformError(NULL
, style
, cur
,
1213 "invalid value for method: %s\n", prop
);
1214 if (style
!= NULL
) style
->warnings
++;
1218 style
->method
= prop
;
1219 style
->methodURI
= xmlStrdup(URI
);
1223 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "doctype-system", NULL
);
1225 if (style
->doctypeSystem
!= NULL
)
1226 xmlFree(style
->doctypeSystem
);
1227 style
->doctypeSystem
= prop
;
1230 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "doctype-public", NULL
);
1232 if (style
->doctypePublic
!= NULL
)
1233 xmlFree(style
->doctypePublic
);
1234 style
->doctypePublic
= prop
;
1237 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "standalone", NULL
);
1239 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1240 style
->standalone
= 1;
1241 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1242 style
->standalone
= 0;
1244 xsltTransformError(NULL
, style
, cur
,
1245 "invalid value for standalone: %s\n", prop
);
1251 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "indent", NULL
);
1253 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1255 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1258 xsltTransformError(NULL
, style
, cur
,
1259 "invalid value for indent: %s\n", prop
);
1265 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "omit-xml-declaration", NULL
);
1267 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
1268 style
->omitXmlDeclaration
= 1;
1269 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
1270 style
->omitXmlDeclaration
= 0;
1272 xsltTransformError(NULL
, style
, cur
,
1273 "invalid value for omit-xml-declaration: %s\n",
1280 elements
= xmlGetNsProp(cur
, (const xmlChar
*) "cdata-section-elements",
1282 if (elements
!= NULL
) {
1283 if (style
->cdataSection
== NULL
)
1284 style
->cdataSection
= xmlHashCreate(10);
1285 if (style
->cdataSection
== NULL
)
1289 while (*element
!= 0) {
1290 while (IS_BLANK(*element
))
1295 while ((*end
!= 0) && (!IS_BLANK(*end
)))
1297 element
= xmlStrndup(element
, end
- element
);
1299 #ifdef WITH_XSLT_DEBUG_PARSING
1300 xsltGenericDebug(xsltGenericDebugContext
,
1301 "add cdata section output element %s\n",
1304 if (xmlValidateQName(BAD_CAST element
, 0) != 0) {
1305 xsltTransformError(NULL
, style
, cur
,
1306 "Attribute 'cdata-section-elements': The value "
1307 "'%s' is not a valid QName.\n", element
);
1314 * TODO: Don't use xsltGetQNameURI().
1316 URI
= xsltGetQNameURI(cur
, &element
);
1317 if (element
== NULL
) {
1319 * TODO: We'll report additionally an error
1320 * via the stylesheet's error handling.
1322 xsltTransformError(NULL
, style
, cur
,
1323 "Attribute 'cdata-section-elements': The value "
1324 "'%s' is not a valid QName.\n", element
);
1330 * XSLT-1.0 "Each QName is expanded into an
1331 * expanded-name using the namespace declarations in
1332 * effect on the xsl:output element in which the QName
1333 * occurs; if there is a default namespace, it is used
1334 * for QNames that do not have a prefix"
1335 * NOTE: Fix of bug #339570.
1338 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1342 xmlHashAddEntry2(style
->cdataSection
, element
, URI
,
1353 prop
= xmlGetNsProp(cur
, (const xmlChar
*) "media-type", NULL
);
1355 if (style
->mediaType
)
1356 xmlFree(style
->mediaType
);
1357 style
->mediaType
= prop
;
1359 if (cur
->children
!= NULL
) {
1360 xsltParseContentError(style
, cur
->children
);
1365 * xsltParseStylesheetDecimalFormat:
1366 * @style: the XSLT stylesheet
1367 * @cur: the "decimal-format" element
1369 * <!-- Category: top-level-element -->
1370 * <xsl:decimal-format
1371 * name = qname, decimal-separator = char, grouping-separator = char,
1372 * infinity = string, minus-sign = char, NaN = string, percent = char
1373 * per-mille = char, zero-digit = char, digit = char,
1374 * pattern-separator = char />
1376 * parse an XSLT stylesheet decimal-format element and
1377 * and record the formatting characteristics
1380 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style
, xmlNodePtr cur
)
1383 xsltDecimalFormatPtr format
;
1384 xsltDecimalFormatPtr iter
;
1386 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1389 format
= style
->decimalFormat
;
1391 prop
= xmlGetNsProp(cur
, BAD_CAST("name"), NULL
);
1393 const xmlChar
*nsUri
;
1395 if (xmlValidateQName(prop
, 0) != 0) {
1396 xsltTransformError(NULL
, style
, cur
,
1397 "xsl:decimal-format: Invalid QName '%s'.\n", prop
);
1403 * TODO: Don't use xsltGetQNameURI().
1405 nsUri
= xsltGetQNameURI(cur
, &prop
);
1410 format
= xsltDecimalFormatGetByQName(style
, nsUri
, prop
);
1411 if (format
!= NULL
) {
1412 xsltTransformError(NULL
, style
, cur
,
1413 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop
);
1418 format
= xsltNewDecimalFormat(nsUri
, prop
);
1419 if (format
== NULL
) {
1420 xsltTransformError(NULL
, style
, cur
,
1421 "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
1426 /* Append new decimal-format structure */
1427 for (iter
= style
->decimalFormat
; iter
->next
; iter
= iter
->next
)
1430 iter
->next
= format
;
1433 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"decimal-separator", NULL
);
1435 if (format
->decimalPoint
!= NULL
) xmlFree(format
->decimalPoint
);
1436 format
->decimalPoint
= prop
;
1439 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"grouping-separator", NULL
);
1441 if (format
->grouping
!= NULL
) xmlFree(format
->grouping
);
1442 format
->grouping
= prop
;
1445 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"infinity", NULL
);
1447 if (format
->infinity
!= NULL
) xmlFree(format
->infinity
);
1448 format
->infinity
= prop
;
1451 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"minus-sign", NULL
);
1453 if (format
->minusSign
!= NULL
) xmlFree(format
->minusSign
);
1454 format
->minusSign
= prop
;
1457 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"NaN", NULL
);
1459 if (format
->noNumber
!= NULL
) xmlFree(format
->noNumber
);
1460 format
->noNumber
= prop
;
1463 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"percent", NULL
);
1465 if (format
->percent
!= NULL
) xmlFree(format
->percent
);
1466 format
->percent
= prop
;
1469 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"per-mille", NULL
);
1471 if (format
->permille
!= NULL
) xmlFree(format
->permille
);
1472 format
->permille
= prop
;
1475 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"zero-digit", NULL
);
1477 if (format
->zeroDigit
!= NULL
) xmlFree(format
->zeroDigit
);
1478 format
->zeroDigit
= prop
;
1481 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"digit", NULL
);
1483 if (format
->digit
!= NULL
) xmlFree(format
->digit
);
1484 format
->digit
= prop
;
1487 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"pattern-separator", NULL
);
1489 if (format
->patternSeparator
!= NULL
) xmlFree(format
->patternSeparator
);
1490 format
->patternSeparator
= prop
;
1492 if (cur
->children
!= NULL
) {
1493 xsltParseContentError(style
, cur
->children
);
1498 * xsltParseStylesheetPreserveSpace:
1499 * @style: the XSLT stylesheet
1500 * @cur: the "preserve-space" element
1502 * parse an XSLT stylesheet preserve-space element and record
1503 * elements needing preserving
1507 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style
, xmlNodePtr cur
) {
1509 xmlChar
*element
, *end
;
1511 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1514 elements
= xmlGetNsProp(cur
, (const xmlChar
*)"elements", NULL
);
1515 if (elements
== NULL
) {
1516 xsltTransformError(NULL
, style
, cur
,
1517 "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
1518 if (style
!= NULL
) style
->warnings
++;
1522 if (style
->stripSpaces
== NULL
)
1523 style
->stripSpaces
= xmlHashCreate(10);
1524 if (style
->stripSpaces
== NULL
)
1528 while (*element
!= 0) {
1529 while (IS_BLANK(*element
)) element
++;
1533 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1534 element
= xmlStrndup(element
, end
- element
);
1536 #ifdef WITH_XSLT_DEBUG_PARSING
1537 xsltGenericDebug(xsltGenericDebugContext
,
1538 "add preserved space element %s\n", element
);
1540 if (xmlStrEqual(element
, (const xmlChar
*)"*")) {
1541 style
->stripAll
= -1;
1546 * TODO: Don't use xsltGetQNameURI().
1548 URI
= xsltGetQNameURI(cur
, &element
);
1550 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
1551 (xmlChar
*) "preserve");
1558 if (cur
->children
!= NULL
) {
1559 xsltParseContentError(style
, cur
->children
);
1563 #ifdef XSLT_REFACTORED
1566 * xsltParseStylesheetExtPrefix:
1567 * @style: the XSLT stylesheet
1568 * @template: the "extension-element-prefixes" prefix
1570 * parse an XSLT stylesheet's "extension-element-prefix" attribute value
1571 * and register the namespaces of extension instruction.
1572 * SPEC "A namespace is designated as an extension namespace by using
1573 * an extension-element-prefixes attribute on:
1574 * 1) an xsl:stylesheet element
1575 * 2) an xsl:extension-element-prefixes attribute on a
1576 * literal result element
1577 * 3) an extension instruction."
1580 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style
, xmlNodePtr cur
,
1583 xmlChar
*prefix
, *end
;
1585 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1589 /* For xsl:stylesheet/xsl:transform. */
1590 prefixes
= xmlGetNsProp(cur
,
1591 (const xmlChar
*)"extension-element-prefixes", NULL
);
1593 /* For literal result elements and extension instructions. */
1594 prefixes
= xmlGetNsProp(cur
,
1595 (const xmlChar
*)"extension-element-prefixes", XSLT_NAMESPACE
);
1597 if (prefixes
== NULL
) {
1602 while (*prefix
!= 0) {
1603 while (IS_BLANK(*prefix
)) prefix
++;
1607 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1608 prefix
= xmlStrndup(prefix
, end
- prefix
);
1612 if (xmlStrEqual(prefix
, (const xmlChar
*)"#default"))
1613 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1615 ns
= xmlSearchNs(style
->doc
, cur
, prefix
);
1617 xsltTransformError(NULL
, style
, cur
,
1618 "xsl:extension-element-prefix : undefined namespace %s\n",
1620 if (style
!= NULL
) style
->warnings
++;
1622 #ifdef WITH_XSLT_DEBUG_PARSING
1623 xsltGenericDebug(xsltGenericDebugContext
,
1624 "add extension prefix %s\n", prefix
);
1626 xsltRegisterExtPrefix(style
, prefix
, ns
->href
);
1634 #endif /* else of XSLT_REFACTORED */
1637 * xsltParseStylesheetStripSpace:
1638 * @style: the XSLT stylesheet
1639 * @cur: the "strip-space" element
1641 * parse an XSLT stylesheet's strip-space element and record
1642 * the elements needing stripping
1646 xsltParseStylesheetStripSpace(xsltStylesheetPtr style
, xmlNodePtr cur
) {
1648 xmlChar
*element
, *end
;
1650 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1653 elements
= xmlGetNsProp(cur
, (const xmlChar
*)"elements", NULL
);
1654 if (elements
== NULL
) {
1655 xsltTransformError(NULL
, style
, cur
,
1656 "xsltParseStylesheetStripSpace: missing elements attribute\n");
1657 if (style
!= NULL
) style
->warnings
++;
1661 if (style
->stripSpaces
== NULL
)
1662 style
->stripSpaces
= xmlHashCreate(10);
1663 if (style
->stripSpaces
== NULL
)
1667 while (*element
!= 0) {
1668 while (IS_BLANK(*element
)) element
++;
1672 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1673 element
= xmlStrndup(element
, end
- element
);
1675 #ifdef WITH_XSLT_DEBUG_PARSING
1676 xsltGenericDebug(xsltGenericDebugContext
,
1677 "add stripped space element %s\n", element
);
1679 if (xmlStrEqual(element
, (const xmlChar
*)"*")) {
1680 style
->stripAll
= 1;
1685 * TODO: Don't use xsltGetQNameURI().
1687 URI
= xsltGetQNameURI(cur
, &element
);
1689 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
1690 (xmlChar
*) "strip");
1697 if (cur
->children
!= NULL
) {
1698 xsltParseContentError(style
, cur
->children
);
1702 #ifdef XSLT_REFACTORED
1705 * xsltParseStylesheetExcludePrefix:
1706 * @style: the XSLT stylesheet
1707 * @cur: the current point in the stylesheet
1709 * parse an XSLT stylesheet exclude prefix and record
1710 * namespaces needing stripping
1712 * Returns the number of Excluded prefixes added at that level
1716 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style
, xmlNodePtr cur
,
1721 xmlChar
*prefix
, *end
;
1723 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
1727 prefixes
= xmlGetNsProp(cur
,
1728 (const xmlChar
*)"exclude-result-prefixes", NULL
);
1730 prefixes
= xmlGetNsProp(cur
,
1731 (const xmlChar
*)"exclude-result-prefixes", XSLT_NAMESPACE
);
1733 if (prefixes
== NULL
) {
1738 while (*prefix
!= 0) {
1739 while (IS_BLANK(*prefix
)) prefix
++;
1743 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
1744 prefix
= xmlStrndup(prefix
, end
- prefix
);
1748 if (xmlStrEqual(prefix
, (const xmlChar
*)"#default"))
1749 ns
= xmlSearchNs(style
->doc
, cur
, NULL
);
1751 ns
= xmlSearchNs(style
->doc
, cur
, prefix
);
1753 xsltTransformError(NULL
, style
, cur
,
1754 "xsl:exclude-result-prefixes : undefined namespace %s\n",
1756 if (style
!= NULL
) style
->warnings
++;
1758 if (exclPrefixPush(style
, (xmlChar
*) ns
->href
) >= 0) {
1759 #ifdef WITH_XSLT_DEBUG_PARSING
1760 xsltGenericDebug(xsltGenericDebugContext
,
1761 "exclude result prefix %s\n", prefix
);
1773 #endif /* else of XSLT_REFACTORED */
1775 #ifdef XSLT_REFACTORED
1778 * xsltTreeEnsureXMLDecl:
1782 * This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
1783 * Ensures that there is an XML namespace declaration on the doc.
1785 * Returns the XML ns-struct or NULL on API and internal errors.
1788 xsltTreeEnsureXMLDecl(xmlDocPtr doc
)
1792 if (doc
->oldNs
!= NULL
)
1793 return (doc
->oldNs
);
1796 ns
= (xmlNsPtr
) xmlMalloc(sizeof(xmlNs
));
1798 xmlGenericError(xmlGenericErrorContext
,
1799 "xsltTreeEnsureXMLDecl: Failed to allocate "
1800 "the XML namespace.\n");
1803 memset(ns
, 0, sizeof(xmlNs
));
1804 ns
->type
= XML_LOCAL_NAMESPACE
;
1806 * URGENT TODO: revisit this.
1808 #ifdef LIBXML_NAMESPACE_DICT
1810 ns
->href
= xmlDictLookup(doc
->dict
, XML_XML_NAMESPACE
, -1);
1812 ns
->href
= xmlStrdup(XML_XML_NAMESPACE
);
1814 ns
->href
= xmlStrdup(XML_XML_NAMESPACE
);
1816 ns
->prefix
= xmlStrdup((const xmlChar
*)"xml");
1823 * xsltTreeAcquireStoredNs:
1825 * @nsName: the namespace name
1826 * @prefix: the prefix
1829 * This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
1830 * Creates or reuses an xmlNs struct on doc->oldNs with
1831 * the given prefix and namespace name.
1833 * Returns the aquired ns struct or NULL in case of an API
1834 * or internal error.
1837 xsltTreeAcquireStoredNs(xmlDocPtr doc
,
1838 const xmlChar
*nsName
,
1839 const xmlChar
*prefix
)
1845 if (doc
->oldNs
!= NULL
)
1848 ns
= xsltTreeEnsureXMLDecl(doc
);
1851 if (ns
->next
!= NULL
) {
1854 while (ns
!= NULL
) {
1855 if ((ns
->prefix
== NULL
) != (prefix
== NULL
)) {
1857 } else if (prefix
== NULL
) {
1858 if (xmlStrEqual(ns
->href
, nsName
))
1861 if ((ns
->prefix
[0] == prefix
[0]) &&
1862 xmlStrEqual(ns
->prefix
, prefix
) &&
1863 xmlStrEqual(ns
->href
, nsName
))
1867 if (ns
->next
== NULL
)
1873 ns
->next
= xmlNewNs(NULL
, nsName
, prefix
);
1878 * xsltLREBuildEffectiveNs:
1880 * Apply ns-aliasing on the namespace of the given @elem and
1884 xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt
,
1888 xsltNsAliasPtr alias
;
1890 if ((cctxt
== NULL
) || (elem
== NULL
))
1892 if ((cctxt
->nsAliases
== NULL
) || (! cctxt
->hasNsAliases
))
1895 alias
= cctxt
->nsAliases
;
1896 while (alias
!= NULL
) {
1897 if ( /* If both namespaces are NULL... */
1898 ( (elem
->ns
== NULL
) &&
1899 ((alias
->literalNs
== NULL
) ||
1900 (alias
->literalNs
->href
== NULL
)) ) ||
1901 /* ... or both namespace are equal */
1902 ( (elem
->ns
!= NULL
) &&
1903 (alias
->literalNs
!= NULL
) &&
1904 xmlStrEqual(elem
->ns
->href
, alias
->literalNs
->href
) ) )
1906 if ((alias
->targetNs
!= NULL
) &&
1907 (alias
->targetNs
->href
!= NULL
))
1910 * Convert namespace.
1912 if (elem
->doc
== alias
->docOfTargetNs
) {
1914 * This is the nice case: same docs.
1915 * This will eventually assign a ns-decl which
1916 * is shadowed, but this has no negative effect on
1917 * the generation of the result tree.
1919 elem
->ns
= alias
->targetNs
;
1922 * This target xmlNs originates from a different
1923 * stylesheet tree. Try to locate it in the
1924 * in-scope namespaces.
1925 * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
1927 ns
= xmlSearchNs(elem
->doc
, elem
,
1928 alias
->targetNs
->prefix
);
1930 * If no matching ns-decl found, then assign a
1931 * ns-decl stored in xmlDoc.
1934 (! xmlStrEqual(ns
->href
, alias
->targetNs
->href
)))
1937 * BIG NOTE: The use of xsltTreeAcquireStoredNs()
1938 * is not very efficient, but currently I don't
1939 * see an other way of *safely* changing a node's
1940 * namespace, since the xmlNs struct in
1941 * alias->targetNs might come from an other
1942 * stylesheet tree. So we need to anchor it in the
1943 * current document, without adding it to the tree,
1944 * which would otherwise change the in-scope-ns
1945 * semantic of the tree.
1947 ns
= xsltTreeAcquireStoredNs(elem
->doc
,
1948 alias
->targetNs
->href
,
1949 alias
->targetNs
->prefix
);
1952 xsltTransformError(NULL
, cctxt
->style
, elem
,
1953 "Internal error in "
1954 "xsltLREBuildEffectiveNs(): "
1955 "failed to acquire a stored "
1956 "ns-declaration.\n");
1957 cctxt
->style
->errors
++;
1966 * Move into or leave in the NULL namespace.
1972 alias
= alias
->next
;
1975 * Same with attributes of literal result elements.
1977 if (elem
->properties
!= NULL
) {
1978 xmlAttrPtr attr
= elem
->properties
;
1980 while (attr
!= NULL
) {
1981 if (attr
->ns
== NULL
) {
1985 alias
= cctxt
->nsAliases
;
1986 while (alias
!= NULL
) {
1987 if ( /* If both namespaces are NULL... */
1988 ( (elem
->ns
== NULL
) &&
1989 ((alias
->literalNs
== NULL
) ||
1990 (alias
->literalNs
->href
== NULL
)) ) ||
1991 /* ... or both namespace are equal */
1992 ( (elem
->ns
!= NULL
) &&
1993 (alias
->literalNs
!= NULL
) &&
1994 xmlStrEqual(elem
->ns
->href
, alias
->literalNs
->href
) ) )
1996 if ((alias
->targetNs
!= NULL
) &&
1997 (alias
->targetNs
->href
!= NULL
))
1999 if (elem
->doc
== alias
->docOfTargetNs
) {
2000 elem
->ns
= alias
->targetNs
;
2002 ns
= xmlSearchNs(elem
->doc
, elem
,
2003 alias
->targetNs
->prefix
);
2005 (! xmlStrEqual(ns
->href
, alias
->targetNs
->href
)))
2007 ns
= xsltTreeAcquireStoredNs(elem
->doc
,
2008 alias
->targetNs
->href
,
2009 alias
->targetNs
->prefix
);
2012 xsltTransformError(NULL
, cctxt
->style
, elem
,
2013 "Internal error in "
2014 "xsltLREBuildEffectiveNs(): "
2015 "failed to acquire a stored "
2016 "ns-declaration.\n");
2017 cctxt
->style
->errors
++;
2026 * Move into or leave in the NULL namespace.
2032 alias
= alias
->next
;
2042 * xsltLREBuildEffectiveNsNodes:
2044 * Computes the effective namespaces nodes for a literal result
2046 * @effectiveNs is the set of effective ns-nodes
2047 * on the literal result element, which will be added to the result
2048 * element if not already existing in the result tree.
2049 * This means that excluded namespaces (via exclude-result-prefixes,
2050 * extension-element-prefixes and the XSLT namespace) not added
2052 * Namespace-aliasing was applied on the @effectiveNs.
2055 xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt
,
2056 xsltStyleItemLRElementInfoPtr item
,
2061 xsltEffectiveNsPtr effNs
, lastEffNs
= NULL
;
2062 int i
, j
, holdByElem
;
2063 xsltPointerListPtr extElemNs
= cctxt
->inode
->extElemNs
;
2064 xsltPointerListPtr exclResultNs
= cctxt
->inode
->exclResultNs
;
2066 if ((cctxt
== NULL
) || (cctxt
->inode
== NULL
) || (elem
== NULL
) ||
2067 (item
== NULL
) || (item
->effectiveNs
!= NULL
))
2070 if (item
->inScopeNs
== NULL
)
2073 extElemNs
= cctxt
->inode
->extElemNs
;
2074 exclResultNs
= cctxt
->inode
->exclResultNs
;
2076 for (i
= 0; i
< item
->inScopeNs
->totalNumber
; i
++) {
2077 ns
= item
->inScopeNs
->list
[i
];
2079 * Skip namespaces designated as excluded namespaces
2080 * -------------------------------------------------
2082 * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
2083 * which are target namespaces of namespace-aliases
2084 * regardless if designated as excluded.
2086 * Exclude the XSLT namespace.
2088 if (xmlStrEqual(ns
->href
, XSLT_NAMESPACE
))
2092 * Apply namespace aliasing
2093 * ------------------------
2096 * "- A namespace node whose string value is a literal namespace
2097 * URI is not copied to the result tree.
2098 * - A namespace node whose string value is a target namespace URI
2099 * is copied to the result tree, whether or not the URI
2100 * identifies an excluded namespace."
2102 * NOTE: The ns-aliasing machanism is non-cascading.
2103 * (checked with Saxon, Xalan and MSXML .NET).
2104 * URGENT TODO: is style->nsAliases the effective list of
2105 * ns-aliases, or do we need to lookup the whole
2107 * TODO: Get rid of import-tree lookup.
2109 if (cctxt
->hasNsAliases
) {
2110 xsltNsAliasPtr alias
;
2112 * First check for being a target namespace.
2114 alias
= cctxt
->nsAliases
;
2117 * TODO: Is xmlns="" handled already?
2119 if ((alias
->targetNs
!= NULL
) &&
2120 (xmlStrEqual(alias
->targetNs
->href
, ns
->href
)))
2123 * Recognized as a target namespace; use it regardless
2124 * if excluded otherwise.
2126 goto add_effective_ns
;
2128 alias
= alias
->next
;
2129 } while (alias
!= NULL
);
2131 alias
= cctxt
->nsAliases
;
2134 * TODO: Is xmlns="" handled already?
2136 if ((alias
->literalNs
!= NULL
) &&
2137 (xmlStrEqual(alias
->literalNs
->href
, ns
->href
)))
2140 * Recognized as an namespace alias; do not use it.
2144 alias
= alias
->next
;
2145 } while (alias
!= NULL
);
2149 * Exclude excluded result namespaces.
2152 for (j
= 0; j
< exclResultNs
->number
; j
++)
2153 if (xmlStrEqual(ns
->href
, BAD_CAST exclResultNs
->items
[j
]))
2157 * Exclude extension-element namespaces.
2160 for (j
= 0; j
< extElemNs
->number
; j
++)
2161 if (xmlStrEqual(ns
->href
, BAD_CAST extElemNs
->items
[j
]))
2167 * OPTIMIZE TODO: This information may not be needed.
2169 if (isLRE
&& (elem
->nsDef
!= NULL
)) {
2171 tmpns
= elem
->nsDef
;
2177 tmpns
= tmpns
->next
;
2178 } while (tmpns
!= NULL
);
2184 * Add the effective namespace declaration.
2186 effNs
= (xsltEffectiveNsPtr
) xmlMalloc(sizeof(xsltEffectiveNs
));
2187 if (effNs
== NULL
) {
2188 xsltTransformError(NULL
, cctxt
->style
, elem
,
2189 "Internal error in xsltLREBuildEffectiveNs(): "
2190 "failed to allocate memory.\n");
2191 cctxt
->style
->errors
++;
2194 if (cctxt
->psData
->effectiveNs
== NULL
) {
2195 cctxt
->psData
->effectiveNs
= effNs
;
2196 effNs
->nextInStore
= NULL
;
2198 effNs
->nextInStore
= cctxt
->psData
->effectiveNs
;
2199 cctxt
->psData
->effectiveNs
= effNs
;
2203 effNs
->prefix
= ns
->prefix
;
2204 effNs
->nsName
= ns
->href
;
2205 effNs
->holdByElem
= holdByElem
;
2207 if (lastEffNs
== NULL
)
2208 item
->effectiveNs
= effNs
;
2210 lastEffNs
->next
= effNs
;
2221 * xsltLREInfoCreate:
2223 * @isLRE: indicates if the given @elem is a literal result element
2225 * Creates a new info for a literal result element.
2228 xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt
,
2232 xsltStyleItemLRElementInfoPtr item
;
2234 if ((cctxt
== NULL
) || (cctxt
->inode
== NULL
))
2237 item
= (xsltStyleItemLRElementInfoPtr
)
2238 xmlMalloc(sizeof(xsltStyleItemLRElementInfo
));
2240 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2241 "Internal error in xsltLREInfoCreate(): "
2242 "memory allocation failed.\n");
2243 cctxt
->style
->errors
++;
2246 memset(item
, 0, sizeof(xsltStyleItemLRElementInfo
));
2247 item
->type
= XSLT_FUNC_LITERAL_RESULT_ELEMENT
;
2249 * Store it in the stylesheet.
2251 item
->next
= cctxt
->style
->preComps
;
2252 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
2254 * @inScopeNs are used for execution of XPath expressions
2257 item
->inScopeNs
= cctxt
->inode
->inScopeNs
;
2260 xsltLREBuildEffectiveNsNodes(cctxt
, item
, elem
, isLRE
);
2262 cctxt
->inode
->litResElemInfo
= item
;
2263 cctxt
->inode
->nsChanged
= 0;
2269 * xsltCompilerVarInfoPush:
2270 * @cctxt: the compilation context
2272 * Pushes a new var/param info onto the stack.
2274 * Returns the acquired variable info.
2276 static xsltVarInfoPtr
2277 xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt
,
2279 const xmlChar
*name
,
2280 const xmlChar
*nsName
)
2282 xsltVarInfoPtr ivar
;
2284 if ((cctxt
->ivar
!= NULL
) && (cctxt
->ivar
->next
!= NULL
)) {
2285 ivar
= cctxt
->ivar
->next
;
2286 } else if ((cctxt
->ivar
== NULL
) && (cctxt
->ivars
!= NULL
)) {
2287 ivar
= cctxt
->ivars
;
2289 ivar
= (xsltVarInfoPtr
) xmlMalloc(sizeof(xsltVarInfo
));
2291 xsltTransformError(NULL
, cctxt
->style
, inst
,
2292 "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
2293 cctxt
->style
->errors
++;
2296 /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
2297 if (cctxt
->ivars
== NULL
) {
2298 cctxt
->ivars
= ivar
;
2301 cctxt
->ivar
->next
= ivar
;
2302 ivar
->prev
= cctxt
->ivar
;
2307 ivar
->depth
= cctxt
->depth
;
2309 ivar
->nsName
= nsName
;
2314 * xsltCompilerVarInfoPop:
2315 * @cctxt: the compilation context
2317 * Pops all var/param infos from the stack, which
2318 * have the current depth.
2321 xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt
)
2324 while ((cctxt
->ivar
!= NULL
) &&
2325 (cctxt
->ivar
->depth
> cctxt
->depth
))
2327 cctxt
->ivar
= cctxt
->ivar
->prev
;
2332 * xsltCompilerNodePush:
2334 * @cctxt: the compilation context
2335 * @node: the node to be pushed (this can also be the doc-node)
2339 * Returns the current node info structure or
2340 * NULL in case of an internal error.
2342 static xsltCompilerNodeInfoPtr
2343 xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2345 xsltCompilerNodeInfoPtr inode
, iprev
;
2347 if ((cctxt
->inode
!= NULL
) && (cctxt
->inode
->next
!= NULL
)) {
2348 inode
= cctxt
->inode
->next
;
2349 } else if ((cctxt
->inode
== NULL
) && (cctxt
->inodeList
!= NULL
)) {
2350 inode
= cctxt
->inodeList
;
2353 * Create a new node-info.
2355 inode
= (xsltCompilerNodeInfoPtr
)
2356 xmlMalloc(sizeof(xsltCompilerNodeInfo
));
2357 if (inode
== NULL
) {
2358 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2359 "xsltCompilerNodePush: malloc failed.\n");
2362 memset(inode
, 0, sizeof(xsltCompilerNodeInfo
));
2363 if (cctxt
->inodeList
== NULL
)
2364 cctxt
->inodeList
= inode
;
2366 cctxt
->inodeLast
->next
= inode
;
2367 inode
->prev
= cctxt
->inodeLast
;
2369 cctxt
->inodeLast
= inode
;
2370 cctxt
->maxNodeInfos
++;
2371 if (cctxt
->inode
== NULL
) {
2372 cctxt
->inode
= inode
;
2374 * Create an initial literal result element info for
2375 * the root of the stylesheet.
2377 xsltLREInfoCreate(cctxt
, NULL
, 0);
2381 cctxt
->inode
= inode
;
2383 * REVISIT TODO: Keep the reset always complete.
2384 * NOTE: Be carefull with the @node, since it might be
2388 inode
->depth
= cctxt
->depth
;
2389 inode
->templ
= NULL
;
2390 inode
->category
= XSLT_ELEMENT_CATEGORY_XSLT
;
2393 inode
->curChildType
= 0;
2394 inode
->extContentHandled
= 0;
2397 if (inode
->prev
!= NULL
) {
2398 iprev
= inode
->prev
;
2400 * Inherit the following information:
2401 * ---------------------------------
2403 * In-scope namespaces
2405 inode
->inScopeNs
= iprev
->inScopeNs
;
2407 * Info for literal result elements
2409 inode
->litResElemInfo
= iprev
->litResElemInfo
;
2410 inode
->nsChanged
= iprev
->nsChanged
;
2412 * Excluded result namespaces
2414 inode
->exclResultNs
= iprev
->exclResultNs
;
2416 * Extension instruction namespaces
2418 inode
->extElemNs
= iprev
->extElemNs
;
2420 * Whitespace preservation
2422 inode
->preserveWhitespace
= iprev
->preserveWhitespace
;
2424 * Forwards-compatible mode
2426 inode
->forwardsCompat
= iprev
->forwardsCompat
;
2428 inode
->inScopeNs
= NULL
;
2429 inode
->exclResultNs
= NULL
;
2430 inode
->extElemNs
= NULL
;
2431 inode
->preserveWhitespace
= 0;
2432 inode
->forwardsCompat
= 0;
2439 * xsltCompilerNodePop:
2441 * @cctxt: the compilation context
2442 * @node: the node to be pushed (this can also be the doc-node)
2444 * Pops the current node info.
2447 xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2449 if (cctxt
->inode
== NULL
) {
2450 xmlGenericError(xmlGenericErrorContext
,
2451 "xsltCompilerNodePop: Top-node mismatch.\n");
2455 * NOTE: Be carefull with the @node, since it might be
2458 if (cctxt
->inode
->node
!= node
) {
2459 xmlGenericError(xmlGenericErrorContext
,
2460 "xsltCompilerNodePop: Node mismatch.\n");
2463 if (cctxt
->inode
->depth
!= cctxt
->depth
) {
2464 xmlGenericError(xmlGenericErrorContext
,
2465 "xsltCompilerNodePop: Depth mismatch.\n");
2470 * Pop information of variables.
2472 if ((cctxt
->ivar
) && (cctxt
->ivar
->depth
> cctxt
->depth
))
2473 xsltCompilerVarInfoPop(cctxt
);
2475 cctxt
->inode
= cctxt
->inode
->prev
;
2476 if (cctxt
->inode
!= NULL
)
2477 cctxt
->inode
->curChildType
= 0;
2482 const xmlChar
*nsName
= NULL
, *name
= NULL
;
2483 const xmlChar
*infnsName
= NULL
, *infname
= NULL
;
2486 if (node
->type
== XML_ELEMENT_NODE
) {
2488 if (node
->ns
!= NULL
)
2489 nsName
= node
->ns
->href
;
2491 nsName
= BAD_CAST
"";
2493 name
= BAD_CAST
"#document";
2494 nsName
= BAD_CAST
"";
2497 name
= BAD_CAST
"Not given";
2499 if (cctxt
->inode
->node
) {
2500 if (node
->type
== XML_ELEMENT_NODE
) {
2501 infname
= cctxt
->inode
->node
->name
;
2502 if (cctxt
->inode
->node
->ns
!= NULL
)
2503 infnsName
= cctxt
->inode
->node
->ns
->href
;
2505 infnsName
= BAD_CAST
"";
2507 infname
= BAD_CAST
"#document";
2508 infnsName
= BAD_CAST
"";
2511 infname
= BAD_CAST
"Not given";
2514 xmlGenericError(xmlGenericErrorContext
,
2515 "xsltCompilerNodePop: Given : '%s' URI '%s'\n",
2517 xmlGenericError(xmlGenericErrorContext
,
2518 "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
2519 infname
, infnsName
);
2524 * xsltCompilerBuildInScopeNsList:
2526 * Create and store the list of in-scope namespaces for the given
2527 * node in the stylesheet. If there are no changes in the in-scope
2528 * namespaces then the last ns-info of the ancestor axis will be returned.
2529 * Compilation-time only.
2531 * Returns the ns-info or NULL if there are no namespaces in scope.
2533 static xsltNsListContainerPtr
2534 xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
2536 xsltNsListContainerPtr nsi
= NULL
;
2537 xmlNsPtr
*list
= NULL
, ns
;
2540 * Create a new ns-list for this position in the node-tree.
2541 * xmlGetNsList() will return NULL, if there are no ns-decls in the
2542 * tree. Note that the ns-decl for the XML namespace is not added
2543 * to the resulting list; the XPath module handles the XML namespace
2546 while (node
!= NULL
) {
2547 if (node
->type
== XML_ELEMENT_NODE
) {
2549 while (ns
!= NULL
) {
2551 nsi
= (xsltNsListContainerPtr
)
2552 xmlMalloc(sizeof(xsltNsListContainer
));
2554 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2555 "xsltCompilerBuildInScopeNsList: "
2556 "malloc failed!\n");
2559 memset(nsi
, 0, sizeof(xsltNsListContainer
));
2561 (xmlNsPtr
*) xmlMalloc(maxns
* sizeof(xmlNsPtr
));
2562 if (nsi
->list
== NULL
) {
2563 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2564 "xsltCompilerBuildInScopeNsList: "
2565 "malloc failed!\n");
2568 nsi
->list
[0] = NULL
;
2571 * Skip shadowed namespace bindings.
2573 for (i
= 0; i
< nsi
->totalNumber
; i
++) {
2574 if ((ns
->prefix
== nsi
->list
[i
]->prefix
) ||
2575 (xmlStrEqual(ns
->prefix
, nsi
->list
[i
]->prefix
)))
2578 if (i
>= nsi
->totalNumber
) {
2579 if (nsi
->totalNumber
+1 >= maxns
) {
2582 (xmlNsPtr
*) xmlRealloc(nsi
->list
,
2583 maxns
* sizeof(xmlNsPtr
));
2584 if (nsi
->list
== NULL
) {
2585 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2586 "xsltCompilerBuildInScopeNsList: "
2587 "realloc failed!\n");
2591 nsi
->list
[nsi
->totalNumber
++] = ns
;
2592 nsi
->list
[nsi
->totalNumber
] = NULL
;
2598 node
= node
->parent
;
2603 * Move the default namespace to last position.
2605 nsi
->xpathNumber
= nsi
->totalNumber
;
2606 for (i
= 0; i
< nsi
->totalNumber
; i
++) {
2607 if (nsi
->list
[i
]->prefix
== NULL
) {
2609 nsi
->list
[i
] = nsi
->list
[nsi
->totalNumber
-1];
2610 nsi
->list
[nsi
->totalNumber
-1] = ns
;
2616 * Store the ns-list in the stylesheet.
2618 if (xsltPointerListAddSize(
2619 (xsltPointerListPtr
)cctxt
->psData
->inScopeNamespaces
,
2620 (void *) nsi
, 5) == -1)
2624 xsltTransformError(NULL
, cctxt
->style
, NULL
,
2625 "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
2629 * Notify of change in status wrt namespaces.
2631 if (cctxt
->inode
!= NULL
)
2632 cctxt
->inode
->nsChanged
= 1;
2639 cctxt
->style
->errors
++;
2644 xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt
,
2645 xsltPointerListPtr list
,
2647 const xmlChar
*value
)
2652 if ((cctxt
== NULL
) || (value
== NULL
) || (list
== NULL
))
2657 cur
= (xmlChar
*) value
;
2659 while (IS_BLANK(*cur
)) cur
++;
2663 while ((*end
!= 0) && (!IS_BLANK(*end
))) end
++;
2664 cur
= xmlStrndup(cur
, end
- cur
);
2670 * TODO: Export and use xmlSearchNsByPrefixStrict()
2671 * in Libxml2, tree.c, since xmlSearchNs() is in most
2672 * cases not efficient and in some cases not correct.
2674 * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
2676 if ((cur
[0] == '#') &&
2677 xmlStrEqual(cur
, (const xmlChar
*)"#default"))
2678 ns
= xmlSearchNs(cctxt
->style
->doc
, node
, NULL
);
2680 ns
= xmlSearchNs(cctxt
->style
->doc
, node
, cur
);
2684 * TODO: Better to report the attr-node, otherwise
2685 * the user won't know which attribute was invalid.
2687 xsltTransformError(NULL
, cctxt
->style
, node
,
2688 "No namespace binding in scope for prefix '%s'.\n", cur
);
2690 * XSLT-1.0: "It is an error if there is no namespace
2691 * bound to the prefix on the element bearing the
2692 * exclude-result-prefixes or xsl:exclude-result-prefixes
2695 cctxt
->style
->errors
++;
2697 #ifdef WITH_XSLT_DEBUG_PARSING
2698 xsltGenericDebug(xsltGenericDebugContext
,
2699 "resolved prefix '%s'\n", cur
);
2702 * Note that we put the namespace name into the dict.
2704 if (xsltPointerListAddSize(list
,
2705 (void *) xmlDictLookup(cctxt
->style
->dict
,
2706 ns
->href
, -1), 5) == -1)
2719 cctxt
->style
->errors
++;
2724 * xsltCompilerUtilsCreateMergedList:
2725 * @dest: the destination list (optional)
2726 * @first: the first list
2727 * @second: the second list (optional)
2729 * Appends the content of @second to @first into @destination.
2730 * If @destination is NULL a new list will be created.
2732 * Returns the merged list of items or NULL if there's nothing to merge.
2734 static xsltPointerListPtr
2735 xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first
,
2736 xsltPointerListPtr second
)
2738 xsltPointerListPtr ret
;
2742 num
= first
->number
;
2746 num
+= second
->number
;
2749 ret
= xsltPointerListCreate(num
);
2755 if ((first
!= NULL
) && (first
->number
!= 0)) {
2756 memcpy(ret
->items
, first
->items
,
2757 first
->number
* sizeof(void *));
2758 if ((second
!= NULL
) && (second
->number
!= 0))
2759 memcpy(ret
->items
+ first
->number
, second
->items
,
2760 second
->number
* sizeof(void *));
2761 } else if ((second
!= NULL
) && (second
->number
!= 0))
2762 memcpy(ret
->items
, (void *) second
->items
,
2763 second
->number
* sizeof(void *));
2769 * xsltParseExclResultPrefixes:
2771 * Create and store the list of in-scope namespaces for the given
2772 * node in the stylesheet. If there are no changes in the in-scope
2773 * namespaces then the last ns-info of the ancestor axis will be returned.
2774 * Compilation-time only.
2776 * Returns the ns-info or NULL if there are no namespaces in scope.
2778 static xsltPointerListPtr
2779 xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2780 xsltPointerListPtr def
,
2783 xsltPointerListPtr list
= NULL
;
2787 if ((cctxt
== NULL
) || (node
== NULL
))
2790 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2791 attr
= xmlHasNsProp(node
, BAD_CAST
"exclude-result-prefixes", NULL
);
2793 attr
= xmlHasNsProp(node
, BAD_CAST
"exclude-result-prefixes",
2798 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
2800 * Mark the XSLT attr.
2802 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2805 if ((attr
->children
!= NULL
) &&
2806 (attr
->children
->content
!= NULL
))
2807 value
= attr
->children
->content
;
2809 xsltTransformError(NULL
, cctxt
->style
, node
,
2810 "Attribute 'exclude-result-prefixes': Invalid value.\n");
2811 cctxt
->style
->errors
++;
2815 if (xsltParseNsPrefixList(cctxt
, cctxt
->tmpList
, node
,
2816 BAD_CAST value
) != 0)
2818 if (cctxt
->tmpList
->number
== 0)
2821 * Merge the list with the inherited list.
2823 list
= xsltCompilerUtilsCreateMergedList(def
, cctxt
->tmpList
);
2827 * Store the list in the stylesheet/compiler context.
2829 if (xsltPointerListAddSize(
2830 cctxt
->psData
->exclResultNamespaces
, list
, 5) == -1)
2832 xsltPointerListFree(list
);
2837 * Notify of change in status wrt namespaces.
2839 if (cctxt
->inode
!= NULL
)
2840 cctxt
->inode
->nsChanged
= 1;
2850 * xsltParseExtElemPrefixes:
2852 * Create and store the list of in-scope namespaces for the given
2853 * node in the stylesheet. If there are no changes in the in-scope
2854 * namespaces then the last ns-info of the ancestor axis will be returned.
2855 * Compilation-time only.
2857 * Returns the ns-info or NULL if there are no namespaces in scope.
2859 static xsltPointerListPtr
2860 xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2861 xsltPointerListPtr def
,
2864 xsltPointerListPtr list
= NULL
;
2869 if ((cctxt
== NULL
) || (node
== NULL
))
2872 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2873 attr
= xmlHasNsProp(node
, BAD_CAST
"extension-element-prefixes", NULL
);
2875 attr
= xmlHasNsProp(node
, BAD_CAST
"extension-element-prefixes",
2880 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
2882 * Mark the XSLT attr.
2884 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2887 if ((attr
->children
!= NULL
) &&
2888 (attr
->children
->content
!= NULL
))
2889 value
= attr
->children
->content
;
2891 xsltTransformError(NULL
, cctxt
->style
, node
,
2892 "Attribute 'extension-element-prefixes': Invalid value.\n");
2893 cctxt
->style
->errors
++;
2898 if (xsltParseNsPrefixList(cctxt
, cctxt
->tmpList
, node
,
2899 BAD_CAST value
) != 0)
2902 if (cctxt
->tmpList
->number
== 0)
2905 * REVISIT: Register the extension namespaces.
2907 for (i
= 0; i
< cctxt
->tmpList
->number
; i
++)
2908 xsltRegisterExtPrefix(cctxt
->style
, NULL
,
2909 BAD_CAST cctxt
->tmpList
->items
[i
]);
2911 * Merge the list with the inherited list.
2913 list
= xsltCompilerUtilsCreateMergedList(def
, cctxt
->tmpList
);
2917 * Store the list in the stylesheet.
2919 if (xsltPointerListAddSize(
2920 cctxt
->psData
->extElemNamespaces
, list
, 5) == -1)
2922 xsltPointerListFree(list
);
2927 * Notify of change in status wrt namespaces.
2929 if (cctxt
->inode
!= NULL
)
2930 cctxt
->inode
->nsChanged
= 1;
2940 * xsltParseAttrXSLTVersion:
2942 * @cctxt: the compilation context
2943 * @node: the element-node
2944 * @isXsltElem: whether this is an XSLT element
2946 * Parses the attribute xsl:version.
2948 * Returns 1 if there was such an attribute, 0 if not and
2949 * -1 if an internal or API error occured.
2952 xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
,
2958 if ((cctxt
== NULL
) || (node
== NULL
))
2961 if (instrCategory
== XSLT_ELEMENT_CATEGORY_XSLT
)
2962 attr
= xmlHasNsProp(node
, BAD_CAST
"version", NULL
);
2964 attr
= xmlHasNsProp(node
, BAD_CAST
"version", XSLT_NAMESPACE
);
2969 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
2971 if ((attr
->children
!= NULL
) &&
2972 (attr
->children
->content
!= NULL
))
2973 value
= attr
->children
->content
;
2975 xsltTransformError(NULL
, cctxt
->style
, node
,
2976 "Attribute 'version': Invalid value.\n");
2977 cctxt
->style
->errors
++;
2981 if (! xmlStrEqual(value
, (const xmlChar
*)"1.0")) {
2982 cctxt
->inode
->forwardsCompat
= 1;
2984 * TODO: To what extent do we support the
2985 * forwards-compatible mode?
2988 * Report this only once per compilation episode.
2990 if (! cctxt
->hasForwardsCompat
) {
2991 cctxt
->hasForwardsCompat
= 1;
2992 cctxt
->errSeverity
= XSLT_ERROR_SEVERITY_WARNING
;
2993 xsltTransformError(NULL
, cctxt
->style
, node
,
2994 "Warning: the attribute xsl:version specifies a value "
2995 "different from '1.0'. Switching to forwards-compatible "
2996 "mode. Only features of XSLT 1.0 are supported by this "
2998 cctxt
->style
->warnings
++;
2999 cctxt
->errSeverity
= XSLT_ERROR_SEVERITY_ERROR
;
3002 cctxt
->inode
->forwardsCompat
= 0;
3005 if (attr
&& (instrCategory
== XSLT_ELEMENT_CATEGORY_LRE
)) {
3007 * Set a marker on XSLT attributes.
3009 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
3015 xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
3017 xmlNodePtr deleteNode
, cur
, txt
, textNode
= NULL
;
3019 xsltStylesheetPtr style
;
3020 int internalize
= 0, findSpaceAttr
;
3021 int xsltStylesheetElemDepth
;
3024 const xmlChar
*name
, *nsNameXSLT
= NULL
;
3025 int strictWhitespace
, inXSLText
= 0;
3026 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3027 xsltNsMapPtr nsMapItem
;
3030 if ((cctxt
== NULL
) || (cctxt
->style
== NULL
) ||
3031 (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
3038 style
= cctxt
->style
;
3039 if ((style
->dict
!= NULL
) && (doc
->dict
== style
->dict
))
3042 style
->internalized
= 0;
3045 * Init value of xml:space. Since this might be an embedded
3046 * stylesheet, this is needed to be performed on the element
3047 * where the stylesheet is rooted at, taking xml:space of
3048 * ancestors into account.
3050 if (! cctxt
->simplified
)
3051 xsltStylesheetElemDepth
= cctxt
->depth
+1;
3053 xsltStylesheetElemDepth
= 0;
3055 if (xmlNodeGetSpacePreserve(node
) != 1)
3056 cctxt
->inode
->preserveWhitespace
= 0;
3058 cctxt
->inode
->preserveWhitespace
= 1;
3061 * Eval if we should keep the old incorrect behaviour.
3063 strictWhitespace
= (cctxt
->strict
!= 0) ? 1 : 0;
3065 nsNameXSLT
= xsltConstNamespaceNameXSLT
;
3069 while (cur
!= NULL
) {
3070 if (deleteNode
!= NULL
) {
3072 #ifdef WITH_XSLT_DEBUG_BLANKS
3073 xsltGenericDebug(xsltGenericDebugContext
,
3074 "xsltParsePreprocessStylesheetTree: removing node\n");
3076 xmlUnlinkNode(deleteNode
);
3077 xmlFreeNode(deleteNode
);
3080 if (cur
->type
== XML_ELEMENT_NODE
) {
3083 * Clear the PSVI field.
3087 xsltCompilerNodePush(cctxt
, cur
);
3092 cctxt
->inode
->stripWhitespace
= 0;
3094 * TODO: I'd love to use a string pointer comparison here :-/
3096 if (IS_XSLT_ELEM(cur
)) {
3097 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3098 if (cur
->ns
->href
!= nsNameXSLT
) {
3099 nsMapItem
= xsltNewNamespaceMapItem(cctxt
,
3101 if (nsMapItem
== NULL
)
3103 cur
->ns
->href
= nsNameXSLT
;
3107 if (cur
->name
== NULL
)
3108 goto process_attributes
;
3110 * Mark the XSLT element for later recognition.
3111 * TODO: Using the marker is still too dangerous, since if
3112 * the parsing mechanism leaves out an XSLT element, then
3113 * this might hit the transformation-mechanism, which
3114 * will break if it doesn't expect such a marker.
3116 /* cur->psvi = (void *) xsltXSLTElemMarker; */
3119 * XSLT 2.0: "Any whitespace text node whose parent is
3120 * one of the following elements is removed from the "
3121 * tree, regardless of any xml:space attributes:..."
3122 * xsl:apply-imports,
3123 * xsl:apply-templates,
3124 * xsl:attribute-set,
3125 * xsl:call-template,
3127 * xsl:stylesheet, xsl:transform.
3128 * XSLT 2.0: xsl:analyze-string,
3129 * xsl:character-map,
3132 * TODO: I'd love to use a string pointer comparison here :-/
3137 if ((name
[0] == 't') && (name
[1] == 'e') &&
3138 (name
[2] == 'x') && (name
[3] == 't') &&
3142 * Process the xsl:text element.
3143 * ----------------------------
3144 * Mark it for later recognition.
3146 cur
->psvi
= (void *) xsltXSLTTextMarker
;
3148 * For stylesheets, the set of
3149 * whitespace-preserving element names
3150 * consists of just xsl:text.
3153 cctxt
->inode
->preserveWhitespace
= 1;
3158 if (xmlStrEqual(name
, BAD_CAST
"choose") ||
3159 xmlStrEqual(name
, BAD_CAST
"call-template"))
3160 cctxt
->inode
->stripWhitespace
= 1;
3163 if (xmlStrEqual(name
, BAD_CAST
"apply-templates") ||
3164 xmlStrEqual(name
, BAD_CAST
"apply-imports") ||
3165 xmlStrEqual(name
, BAD_CAST
"attribute-set"))
3167 cctxt
->inode
->stripWhitespace
= 1;
3170 if (xsltStylesheetElemDepth
== cctxt
->depth
) {
3172 * This is a xsl:stylesheet/xsl:transform.
3174 cctxt
->inode
->stripWhitespace
= 1;
3178 if ((cur
->prev
!= NULL
) &&
3179 (cur
->prev
->type
== XML_TEXT_NODE
))
3182 * XSLT 2.0 : "Any whitespace text node whose
3183 * following-sibling node is an xsl:param or
3184 * xsl:sort element is removed from the tree,
3185 * regardless of any xml:space attributes."
3187 if (((*name
== 'p') || (*name
== 's')) &&
3188 (xmlStrEqual(name
, BAD_CAST
"param") ||
3189 xmlStrEqual(name
, BAD_CAST
"sort")))
3192 if (IS_BLANK_NODE(cur
->prev
)) {
3198 * This will result in a content
3199 * error, when hitting the parsing
3204 } while (cur
->prev
);
3213 * Process attributes.
3214 * ------------------
3216 if (cur
->properties
!= NULL
) {
3217 if (cur
->children
== NULL
)
3219 attr
= cur
->properties
;
3221 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3222 if ((attr
->ns
) && (attr
->ns
->href
!= nsNameXSLT
) &&
3223 xmlStrEqual(attr
->ns
->href
, nsNameXSLT
))
3225 nsMapItem
= xsltNewNamespaceMapItem(cctxt
,
3226 doc
, attr
->ns
, cur
);
3227 if (nsMapItem
== NULL
)
3229 attr
->ns
->href
= nsNameXSLT
;
3234 * Internalize the attribute's value; the goal is to
3235 * speed up operations and minimize used space by
3236 * compiled stylesheets.
3238 txt
= attr
->children
;
3240 * NOTE that this assumes only one
3241 * text-node in the attribute's content.
3243 if ((txt
!= NULL
) && (txt
->content
!= NULL
) &&
3244 (!xmlDictOwns(style
->dict
, txt
->content
)))
3246 value
= (xmlChar
*) xmlDictLookup(style
->dict
,
3248 xmlNodeSetContent(txt
, NULL
);
3249 txt
->content
= value
;
3253 * Process xml:space attributes.
3254 * ----------------------------
3256 if ((findSpaceAttr
!= 0) &&
3257 (attr
->ns
!= NULL
) &&
3258 (attr
->name
!= NULL
) &&
3259 (attr
->name
[0] == 's') &&
3260 (attr
->ns
->prefix
!= NULL
) &&
3261 (attr
->ns
->prefix
[0] == 'x') &&
3262 (attr
->ns
->prefix
[1] == 'm') &&
3263 (attr
->ns
->prefix
[2] == 'l') &&
3264 (attr
->ns
->prefix
[3] == 0))
3266 value
= xmlGetNsProp(cur
, BAD_CAST
"space",
3268 if (value
!= NULL
) {
3269 if (xmlStrEqual(value
, BAD_CAST
"preserve")) {
3270 cctxt
->inode
->preserveWhitespace
= 1;
3271 } else if (xmlStrEqual(value
, BAD_CAST
"default")) {
3272 cctxt
->inode
->preserveWhitespace
= 0;
3274 /* Invalid value for xml:space. */
3275 xsltTransformError(NULL
, style
, cur
,
3276 "Attribute xml:space: Invalid value.\n");
3277 cctxt
->style
->warnings
++;
3285 } while (attr
!= NULL
);
3288 * We'll descend into the children of element nodes only.
3290 if (cur
->children
!= NULL
) {
3291 cur
= cur
->children
;
3294 } else if ((cur
->type
== XML_TEXT_NODE
) ||
3295 (cur
->type
== XML_CDATA_SECTION_NODE
))
3298 * Merge adjacent text/CDATA-section-nodes
3299 * ---------------------------------------
3300 * In order to avoid breaking of existing stylesheets,
3301 * if the old behaviour is wanted (strictWhitespace == 0),
3302 * then we *won't* merge adjacent text-nodes
3303 * (except in xsl:text); this will ensure that whitespace-only
3304 * text nodes are (incorrectly) not stripped in some cases.
3306 * Example: : <foo> <!-- bar -->zoo</foo>
3307 * Corrent (strict) result: <foo> zoo</foo>
3308 * Incorrect (old) result : <foo>zoo</foo>
3310 * NOTE that we *will* merge adjacent text-nodes if
3311 * they are in xsl:text.
3312 * Example, the following:
3313 * <xsl:text> <!-- bar -->zoo<xsl:text>
3314 * will result in both cases in:
3315 * <xsl:text> zoo<xsl:text>
3317 cur
->type
= XML_TEXT_NODE
;
3318 if ((strictWhitespace
!= 0) || (inXSLText
!= 0)) {
3320 * New behaviour; merge nodes.
3322 if (textNode
== NULL
)
3325 if (cur
->content
!= NULL
)
3326 xmlNodeAddContent(textNode
, cur
->content
);
3329 if ((cur
->next
== NULL
) ||
3330 (cur
->next
->type
== XML_ELEMENT_NODE
))
3338 if (textNode
== NULL
)
3342 } else if ((cur
->type
== XML_COMMENT_NODE
) ||
3343 (cur
->type
== XML_PI_NODE
))
3346 * Remove processing instructions and comments.
3349 if ((cur
->next
== NULL
) ||
3350 (cur
->next
->type
== XML_ELEMENT_NODE
))
3357 * Invalid node-type for this data-model.
3359 xsltTransformError(NULL
, style
, cur
,
3360 "Invalid type of node for the XSLT data model.\n");
3361 cctxt
->style
->errors
++;
3367 value
= textNode
->content
;
3369 * At this point all adjacent text/CDATA-section nodes
3372 * Strip whitespace-only text-nodes.
3373 * (cctxt->inode->stripWhitespace)
3375 if ((value
== NULL
) || (*value
== 0) ||
3376 (((cctxt
->inode
->stripWhitespace
) ||
3377 (! cctxt
->inode
->preserveWhitespace
)) &&
3379 xsltIsBlank(value
)))
3381 if (textNode
!= cur
) {
3382 xmlUnlinkNode(textNode
);
3383 xmlFreeNode(textNode
);
3385 deleteNode
= textNode
;
3390 * Convert CDATA-section nodes to text-nodes.
3391 * TODO: Can this produce problems?
3393 if (textNode
->type
!= XML_TEXT_NODE
) {
3394 textNode
->type
= XML_TEXT_NODE
;
3395 textNode
->name
= xmlStringText
;
3398 (textNode
->content
!= NULL
) &&
3399 (!xmlDictOwns(style
->dict
, textNode
->content
)))
3402 * Internalize the string.
3404 value
= (xmlChar
*) xmlDictLookup(style
->dict
,
3405 textNode
->content
, -1);
3406 xmlNodeSetContent(textNode
, NULL
);
3407 textNode
->content
= value
;
3411 * Note that "disable-output-escaping" of the xsl:text
3412 * element will be applied at a later level, when
3413 * XSLT elements are processed.
3418 if (cur
->type
== XML_ELEMENT_NODE
) {
3419 xsltCompilerNodePop(cctxt
, cur
);
3423 if (cur
->next
!= NULL
) {
3431 if (deleteNode
!= NULL
) {
3432 #ifdef WITH_XSLT_DEBUG_PARSING
3433 xsltGenericDebug(xsltGenericDebugContext
,
3434 "xsltParsePreprocessStylesheetTree: removing node\n");
3436 xmlUnlinkNode(deleteNode
);
3437 xmlFreeNode(deleteNode
);
3445 #endif /* XSLT_REFACTORED */
3447 #ifdef XSLT_REFACTORED
3450 xsltPreprocessStylesheet(xsltStylesheetPtr style
, xmlNodePtr cur
)
3452 xmlNodePtr deleteNode
, styleelem
;
3453 int internalize
= 0;
3455 if ((style
== NULL
) || (cur
== NULL
))
3458 if ((cur
->doc
!= NULL
) && (style
->dict
!= NULL
) &&
3459 (cur
->doc
->dict
== style
->dict
))
3462 style
->internalized
= 0;
3464 if ((cur
!= NULL
) && (IS_XSLT_ELEM(cur
)) &&
3465 (IS_XSLT_NAME(cur
, "stylesheet"))) {
3472 * This content comes from the stylesheet
3473 * For stylesheets, the set of whitespace-preserving
3474 * element names consists of just xsl:text.
3477 while (cur
!= NULL
) {
3478 if (deleteNode
!= NULL
) {
3479 #ifdef WITH_XSLT_DEBUG_BLANKS
3480 xsltGenericDebug(xsltGenericDebugContext
,
3481 "xsltPreprocessStylesheet: removing ignorable blank node\n");
3483 xmlUnlinkNode(deleteNode
);
3484 xmlFreeNode(deleteNode
);
3487 if (cur
->type
== XML_ELEMENT_NODE
) {
3490 * Internalize attributes values.
3492 if ((internalize
) && (cur
->properties
!= NULL
)) {
3493 xmlAttrPtr attr
= cur
->properties
;
3496 while (attr
!= NULL
) {
3497 txt
= attr
->children
;
3498 if ((txt
!= NULL
) && (txt
->type
== XML_TEXT_NODE
) &&
3499 (txt
->content
!= NULL
) &&
3500 (!xmlDictOwns(style
->dict
, txt
->content
)))
3505 * internalize the text string, goal is to speed
3506 * up operations and minimize used space by compiled
3509 tmp
= (xmlChar
*) xmlDictLookup(style
->dict
,
3511 if (tmp
!= txt
->content
) {
3512 xmlNodeSetContent(txt
, NULL
);
3519 if (IS_XSLT_ELEM(cur
)) {
3521 if (IS_XSLT_NAME(cur
, "text")) {
3522 for (;exclPrefixes
> 0;exclPrefixes
--)
3523 exclPrefixPop(style
);
3527 exclPrefixes
= xsltParseStylesheetExcludePrefix(style
, cur
, 0);
3530 if ((cur
->nsDef
!= NULL
) && (style
->exclPrefixNr
> 0)) {
3531 xmlNsPtr ns
= cur
->nsDef
, prev
= NULL
, next
;
3532 xmlNodePtr root
= NULL
;
3535 root
= xmlDocGetRootElement(cur
->doc
);
3536 if ((root
!= NULL
) && (root
!= cur
)) {
3537 while (ns
!= NULL
) {
3540 for (i
= 0;i
< style
->exclPrefixNr
;i
++) {
3541 if ((ns
->prefix
!= NULL
) &&
3542 (xmlStrEqual(ns
->href
,
3543 style
->exclPrefixTab
[i
]))) {
3545 * Move the namespace definition on the root
3546 * element to avoid duplicating it without
3550 cur
->nsDef
= ns
->next
;
3552 prev
->next
= ns
->next
;
3554 ns
->next
= root
->nsDef
;
3567 * If we have prefixes locally, recurse and pop them up when
3570 if (exclPrefixes
> 0) {
3571 xsltPreprocessStylesheet(style
, cur
->children
);
3572 for (;exclPrefixes
> 0;exclPrefixes
--)
3573 exclPrefixPop(style
);
3576 } else if (cur
->type
== XML_TEXT_NODE
) {
3577 if (IS_BLANK_NODE(cur
)) {
3578 if (xmlNodeGetSpacePreserve(cur
->parent
) != 1) {
3581 } else if ((cur
->content
!= NULL
) && (internalize
) &&
3582 (!xmlDictOwns(style
->dict
, cur
->content
))) {
3586 * internalize the text string, goal is to speed
3587 * up operations and minimize used space by compiled
3590 tmp
= (xmlChar
*) xmlDictLookup(style
->dict
, cur
->content
, -1);
3591 xmlNodeSetContent(cur
, NULL
);
3594 } else if ((cur
->type
!= XML_ELEMENT_NODE
) &&
3595 (cur
->type
!= XML_CDATA_SECTION_NODE
)) {
3601 * Skip to next node. In case of a namespaced element children of
3602 * the stylesheet and not in the XSLT namespace and not an extension
3603 * element, ignore its content.
3605 if ((cur
->type
== XML_ELEMENT_NODE
) && (cur
->ns
!= NULL
) &&
3606 (styleelem
!= NULL
) && (cur
->parent
== styleelem
) &&
3607 (!xmlStrEqual(cur
->ns
->href
, XSLT_NAMESPACE
)) &&
3608 (!xsltCheckExtURI(style
, cur
->ns
->href
))) {
3610 } else if (cur
->children
!= NULL
) {
3611 if ((cur
->children
->type
!= XML_ENTITY_DECL
) &&
3612 (cur
->children
->type
!= XML_ENTITY_REF_NODE
) &&
3613 (cur
->children
->type
!= XML_ENTITY_NODE
)) {
3614 cur
= cur
->children
;
3620 if (cur
->next
!= NULL
) {
3629 if (cur
== (xmlNodePtr
) style
->doc
) {
3633 if (cur
->next
!= NULL
) {
3637 } while (cur
!= NULL
);
3639 if (deleteNode
!= NULL
) {
3640 #ifdef WITH_XSLT_DEBUG_PARSING
3641 xsltGenericDebug(xsltGenericDebugContext
,
3642 "xsltPreprocessStylesheet: removing ignorable blank node\n");
3644 xmlUnlinkNode(deleteNode
);
3645 xmlFreeNode(deleteNode
);
3648 #endif /* end of else XSLT_REFACTORED */
3651 * xsltGatherNamespaces:
3652 * @style: the XSLT stylesheet
3654 * Browse the stylesheet and build the namspace hash table which
3655 * will be used for XPath interpretation. If needed do a bit of normalization
3659 xsltGatherNamespaces(xsltStylesheetPtr style
) {
3666 * TODO: basically if the stylesheet uses the same prefix for different
3667 * patterns, well they may be in problem, hopefully they will get
3671 * TODO: Eliminate the use of the hash for XPath expressions.
3672 * An expression should be evaluated in the context of the in-scope
3673 * namespaces; eliminate the restriction of an XML document to contain
3674 * no duplicate prefixes for different namespace names.
3677 cur
= xmlDocGetRootElement(style
->doc
);
3678 while (cur
!= NULL
) {
3679 if (cur
->type
== XML_ELEMENT_NODE
) {
3680 xmlNsPtr ns
= cur
->nsDef
;
3681 while (ns
!= NULL
) {
3682 if (ns
->prefix
!= NULL
) {
3683 if (style
->nsHash
== NULL
) {
3684 style
->nsHash
= xmlHashCreate(10);
3685 if (style
->nsHash
== NULL
) {
3686 xsltTransformError(NULL
, style
, cur
,
3687 "xsltGatherNamespaces: failed to create hash table\n");
3692 URI
= xmlHashLookup(style
->nsHash
, ns
->prefix
);
3693 if ((URI
!= NULL
) && (!xmlStrEqual(URI
, ns
->href
))) {
3694 xsltTransformError(NULL
, style
, cur
,
3695 "Namespaces prefix %s used for multiple namespaces\n",ns
->prefix
);
3697 } else if (URI
== NULL
) {
3698 xmlHashUpdateEntry(style
->nsHash
, ns
->prefix
,
3699 (void *) ns
->href
, (xmlHashDeallocator
)xmlFree
);
3701 #ifdef WITH_XSLT_DEBUG_PARSING
3702 xsltGenericDebug(xsltGenericDebugContext
,
3703 "Added namespace: %s mapped to %s\n", ns
->prefix
, ns
->href
);
3714 if (cur
->children
!= NULL
) {
3715 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
3716 cur
= cur
->children
;
3720 if (cur
->next
!= NULL
) {
3729 if (cur
== (xmlNodePtr
) style
->doc
) {
3733 if (cur
->next
!= NULL
) {
3737 } while (cur
!= NULL
);
3741 #ifdef XSLT_REFACTORED
3743 static xsltStyleType
3744 xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt
,
3747 if ((node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
) ||
3748 (node
->name
== NULL
))
3751 if (node
->name
[0] == 'a') {
3752 if (IS_XSLT_NAME(node
, "apply-templates"))
3753 return(XSLT_FUNC_APPLYTEMPLATES
);
3754 else if (IS_XSLT_NAME(node
, "attribute"))
3755 return(XSLT_FUNC_ATTRIBUTE
);
3756 else if (IS_XSLT_NAME(node
, "apply-imports"))
3757 return(XSLT_FUNC_APPLYIMPORTS
);
3758 else if (IS_XSLT_NAME(node
, "attribute-set"))
3761 } else if (node
->name
[0] == 'c') {
3762 if (IS_XSLT_NAME(node
, "choose"))
3763 return(XSLT_FUNC_CHOOSE
);
3764 else if (IS_XSLT_NAME(node
, "copy"))
3765 return(XSLT_FUNC_COPY
);
3766 else if (IS_XSLT_NAME(node
, "copy-of"))
3767 return(XSLT_FUNC_COPYOF
);
3768 else if (IS_XSLT_NAME(node
, "call-template"))
3769 return(XSLT_FUNC_CALLTEMPLATE
);
3770 else if (IS_XSLT_NAME(node
, "comment"))
3771 return(XSLT_FUNC_COMMENT
);
3773 } else if (node
->name
[0] == 'd') {
3774 if (IS_XSLT_NAME(node
, "document"))
3775 return(XSLT_FUNC_DOCUMENT
);
3776 else if (IS_XSLT_NAME(node
, "decimal-format"))
3779 } else if (node
->name
[0] == 'e') {
3780 if (IS_XSLT_NAME(node
, "element"))
3781 return(XSLT_FUNC_ELEMENT
);
3783 } else if (node
->name
[0] == 'f') {
3784 if (IS_XSLT_NAME(node
, "for-each"))
3785 return(XSLT_FUNC_FOREACH
);
3786 else if (IS_XSLT_NAME(node
, "fallback"))
3787 return(XSLT_FUNC_FALLBACK
);
3789 } else if (*(node
->name
) == 'i') {
3790 if (IS_XSLT_NAME(node
, "if"))
3791 return(XSLT_FUNC_IF
);
3792 else if (IS_XSLT_NAME(node
, "include"))
3794 else if (IS_XSLT_NAME(node
, "import"))
3797 } else if (*(node
->name
) == 'k') {
3798 if (IS_XSLT_NAME(node
, "key"))
3801 } else if (*(node
->name
) == 'm') {
3802 if (IS_XSLT_NAME(node
, "message"))
3803 return(XSLT_FUNC_MESSAGE
);
3805 } else if (*(node
->name
) == 'n') {
3806 if (IS_XSLT_NAME(node
, "number"))
3807 return(XSLT_FUNC_NUMBER
);
3808 else if (IS_XSLT_NAME(node
, "namespace-alias"))
3811 } else if (*(node
->name
) == 'o') {
3812 if (IS_XSLT_NAME(node
, "otherwise"))
3813 return(XSLT_FUNC_OTHERWISE
);
3814 else if (IS_XSLT_NAME(node
, "output"))
3817 } else if (*(node
->name
) == 'p') {
3818 if (IS_XSLT_NAME(node
, "param"))
3819 return(XSLT_FUNC_PARAM
);
3820 else if (IS_XSLT_NAME(node
, "processing-instruction"))
3821 return(XSLT_FUNC_PI
);
3822 else if (IS_XSLT_NAME(node
, "preserve-space"))
3825 } else if (*(node
->name
) == 's') {
3826 if (IS_XSLT_NAME(node
, "sort"))
3827 return(XSLT_FUNC_SORT
);
3828 else if (IS_XSLT_NAME(node
, "strip-space"))
3830 else if (IS_XSLT_NAME(node
, "stylesheet"))
3833 } else if (node
->name
[0] == 't') {
3834 if (IS_XSLT_NAME(node
, "text"))
3835 return(XSLT_FUNC_TEXT
);
3836 else if (IS_XSLT_NAME(node
, "template"))
3838 else if (IS_XSLT_NAME(node
, "transform"))
3841 } else if (*(node
->name
) == 'v') {
3842 if (IS_XSLT_NAME(node
, "value-of"))
3843 return(XSLT_FUNC_VALUEOF
);
3844 else if (IS_XSLT_NAME(node
, "variable"))
3845 return(XSLT_FUNC_VARIABLE
);
3847 } else if (*(node
->name
) == 'w') {
3848 if (IS_XSLT_NAME(node
, "when"))
3849 return(XSLT_FUNC_WHEN
);
3850 if (IS_XSLT_NAME(node
, "with-param"))
3851 return(XSLT_FUNC_WITHPARAM
);
3857 * xsltParseAnyXSLTElem:
3859 * @cctxt: the compilation context
3860 * @elem: the element node of the XSLT instruction
3862 * Parses, validates the content models and compiles XSLT instructions.
3864 * Returns 0 if everything's fine;
3865 * -1 on API or internal errors.
3868 xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr elem
)
3870 if ((cctxt
== NULL
) || (elem
== NULL
) ||
3871 (elem
->type
!= XML_ELEMENT_NODE
))
3876 if (! (IS_XSLT_ELEM_FAST(elem
)))
3879 * Detection of handled content of extension instructions.
3881 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
3882 cctxt
->inode
->extContentHandled
= 1;
3885 xsltCompilerNodePush(cctxt
, elem
);
3887 * URGENT TODO: Find a way to speed up this annoying redundant
3888 * textual node-name and namespace comparison.
3890 if (cctxt
->inode
->prev
->curChildType
!= 0)
3891 cctxt
->inode
->type
= cctxt
->inode
->prev
->curChildType
;
3893 cctxt
->inode
->type
= xsltGetXSLTElementTypeByNode(cctxt
, elem
);
3895 * Update the in-scope namespaces if needed.
3897 if (elem
->nsDef
!= NULL
)
3898 cctxt
->inode
->inScopeNs
=
3899 xsltCompilerBuildInScopeNsList(cctxt
, elem
);
3901 * xsltStylePreCompute():
3902 * This will compile the information found on the current
3903 * element's attributes. NOTE that this won't process the
3904 * children of the instruction.
3906 xsltStylePreCompute(cctxt
->style
, elem
);
3908 * TODO: How to react on errors in xsltStylePreCompute() ?
3912 * Validate the content model of the XSLT-element.
3914 switch (cctxt
->inode
->type
) {
3915 case XSLT_FUNC_APPLYIMPORTS
:
3918 case XSLT_FUNC_APPLYTEMPLATES
:
3919 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
3920 goto apply_templates
;
3921 case XSLT_FUNC_ATTRIBUTE
:
3922 /* <!-- Content: template --> */
3923 goto sequence_constructor
;
3924 case XSLT_FUNC_CALLTEMPLATE
:
3925 /* <!-- Content: xsl:with-param* --> */
3927 case XSLT_FUNC_CHOOSE
:
3928 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
3930 case XSLT_FUNC_COMMENT
:
3931 /* <!-- Content: template --> */
3932 goto sequence_constructor
;
3933 case XSLT_FUNC_COPY
:
3934 /* <!-- Content: template --> */
3935 goto sequence_constructor
;
3936 case XSLT_FUNC_COPYOF
:
3939 case XSLT_FUNC_DOCUMENT
: /* Extra one */
3940 /* ?? template ?? */
3941 goto sequence_constructor
;
3942 case XSLT_FUNC_ELEMENT
:
3943 /* <!-- Content: template --> */
3944 goto sequence_constructor
;
3945 case XSLT_FUNC_FALLBACK
:
3946 /* <!-- Content: template --> */
3947 goto sequence_constructor
;
3948 case XSLT_FUNC_FOREACH
:
3949 /* <!-- Content: (xsl:sort*, template) --> */
3952 /* <!-- Content: template --> */
3953 goto sequence_constructor
;
3954 case XSLT_FUNC_OTHERWISE
:
3955 /* <!-- Content: template --> */
3956 goto sequence_constructor
;
3957 case XSLT_FUNC_MESSAGE
:
3958 /* <!-- Content: template --> */
3959 goto sequence_constructor
;
3960 case XSLT_FUNC_NUMBER
:
3963 case XSLT_FUNC_PARAM
:
3965 * Check for redefinition.
3967 if ((elem
->psvi
!= NULL
) && (cctxt
->ivar
!= NULL
)) {
3968 xsltVarInfoPtr ivar
= cctxt
->ivar
;
3972 ((xsltStyleItemParamPtr
) elem
->psvi
)->name
) &&
3974 ((xsltStyleItemParamPtr
) elem
->psvi
)->ns
))
3977 xsltTransformError(NULL
, cctxt
->style
, elem
,
3978 "Redefinition of variable or parameter '%s'.\n",
3980 cctxt
->style
->errors
++;
3984 } while (ivar
!= NULL
);
3986 /* <!-- Content: template --> */
3987 goto sequence_constructor
;
3989 /* <!-- Content: template --> */
3990 goto sequence_constructor
;
3991 case XSLT_FUNC_SORT
:
3994 case XSLT_FUNC_TEXT
:
3995 /* <!-- Content: #PCDATA --> */
3997 case XSLT_FUNC_VALUEOF
:
4000 case XSLT_FUNC_VARIABLE
:
4002 * Check for redefinition.
4004 if ((elem
->psvi
!= NULL
) && (cctxt
->ivar
!= NULL
)) {
4005 xsltVarInfoPtr ivar
= cctxt
->ivar
;
4009 ((xsltStyleItemVariablePtr
) elem
->psvi
)->name
) &&
4011 ((xsltStyleItemVariablePtr
) elem
->psvi
)->ns
))
4014 xsltTransformError(NULL
, cctxt
->style
, elem
,
4015 "Redefinition of variable or parameter '%s'.\n",
4017 cctxt
->style
->errors
++;
4021 } while (ivar
!= NULL
);
4023 /* <!-- Content: template --> */
4024 goto sequence_constructor
;
4025 case XSLT_FUNC_WHEN
:
4026 /* <!-- Content: template --> */
4027 goto sequence_constructor
;
4028 case XSLT_FUNC_WITHPARAM
:
4029 /* <!-- Content: template --> */
4030 goto sequence_constructor
;
4032 #ifdef WITH_XSLT_DEBUG_PARSING
4033 xsltGenericDebug(xsltGenericDebugContext
,
4034 "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
4037 xsltTransformError(NULL
, cctxt
->style
, elem
,
4038 "xsltParseXSLTNode: Internal error; "
4039 "unhandled XSLT element '%s'.\n", elem
->name
);
4040 cctxt
->style
->errors
++;
4045 /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
4046 if (elem
->children
!= NULL
) {
4047 xmlNodePtr child
= elem
->children
;
4049 if (child
->type
== XML_ELEMENT_NODE
) {
4050 if (IS_XSLT_ELEM_FAST(child
)) {
4051 if (xmlStrEqual(child
->name
, BAD_CAST
"with-param")) {
4052 cctxt
->inode
->curChildType
= XSLT_FUNC_WITHPARAM
;
4053 xsltParseAnyXSLTElem(cctxt
, child
);
4054 } else if (xmlStrEqual(child
->name
, BAD_CAST
"sort")) {
4055 cctxt
->inode
->curChildType
= XSLT_FUNC_SORT
;
4056 xsltParseAnyXSLTElem(cctxt
, child
);
4058 xsltParseContentError(cctxt
->style
, child
);
4060 xsltParseContentError(cctxt
->style
, child
);
4062 child
= child
->next
;
4063 } while (child
!= NULL
);
4068 /* <!-- Content: 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
)) {
4076 type
= xsltGetXSLTElementTypeByNode(cctxt
, child
);
4077 if (type
== XSLT_FUNC_WITHPARAM
) {
4078 cctxt
->inode
->curChildType
= XSLT_FUNC_WITHPARAM
;
4079 xsltParseAnyXSLTElem(cctxt
, child
);
4081 xsltParseContentError(cctxt
->style
, child
);
4084 xsltParseContentError(cctxt
->style
, child
);
4086 child
= child
->next
;
4087 } while (child
!= NULL
);
4092 if (elem
->children
!= NULL
) {
4093 xmlNodePtr child
= elem
->children
;
4095 if ((child
->type
!= XML_TEXT_NODE
) &&
4096 (child
->type
!= XML_CDATA_SECTION_NODE
))
4098 xsltTransformError(NULL
, cctxt
->style
, elem
,
4099 "The XSLT 'text' element must have only character "
4100 "data as content.\n");
4102 child
= child
->next
;
4103 } while (child
!= NULL
);
4108 if (elem
->children
!= NULL
) {
4109 xmlNodePtr child
= elem
->children
;
4111 * Relaxed behaviour: we will allow whitespace-only text-nodes.
4114 if (((child
->type
!= XML_TEXT_NODE
) &&
4115 (child
->type
!= XML_CDATA_SECTION_NODE
)) ||
4116 (! IS_BLANK_NODE(child
)))
4118 xsltTransformError(NULL
, cctxt
->style
, elem
,
4119 "This XSLT element must have no content.\n");
4120 cctxt
->style
->errors
++;
4123 child
= child
->next
;
4124 } while (child
!= NULL
);
4129 /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
4131 * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
4132 * The old behaviour did not check this.
4133 * NOTE: In XSLT 2.0 they are stripped beforehand
4134 * if whitespace-only (regardless of xml:space).
4136 if (elem
->children
!= NULL
) {
4137 xmlNodePtr child
= elem
->children
;
4138 int nbWhen
= 0, nbOtherwise
= 0, err
= 0;
4140 if (child
->type
== XML_ELEMENT_NODE
) {
4141 if (IS_XSLT_ELEM_FAST(child
)) {
4144 type
= xsltGetXSLTElementTypeByNode(cctxt
, child
);
4145 if (type
== XSLT_FUNC_WHEN
) {
4148 xsltParseContentError(cctxt
->style
, child
);
4152 cctxt
->inode
->curChildType
= XSLT_FUNC_WHEN
;
4153 xsltParseAnyXSLTElem(cctxt
, child
);
4154 } else if (type
== XSLT_FUNC_OTHERWISE
) {
4156 xsltParseContentError(cctxt
->style
, child
);
4161 xsltTransformError(NULL
, cctxt
->style
, elem
,
4162 "The XSLT 'choose' element must not contain "
4163 "more than one XSLT 'otherwise' element.\n");
4164 cctxt
->style
->errors
++;
4169 cctxt
->inode
->curChildType
= XSLT_FUNC_OTHERWISE
;
4170 xsltParseAnyXSLTElem(cctxt
, child
);
4172 xsltParseContentError(cctxt
->style
, child
);
4174 xsltParseContentError(cctxt
->style
, child
);
4178 xsltParseContentError(cctxt, child);
4180 child
= child
->next
;
4181 } while (child
!= NULL
);
4182 if ((! err
) && (! nbWhen
)) {
4183 xsltTransformError(NULL
, cctxt
->style
, elem
,
4184 "The XSLT element 'choose' must contain at least one "
4185 "XSLT element 'when'.\n");
4186 cctxt
->style
->errors
++;
4192 /* <!-- Content: (xsl:sort*, template) --> */
4194 * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
4195 * The old behaviour did not allow this, but it catched this
4196 * only at transformation-time.
4197 * In XSLT 2.0 they are stripped beforehand if whitespace-only
4198 * (regardless of xml:space).
4200 if (elem
->children
!= NULL
) {
4201 xmlNodePtr child
= elem
->children
;
4203 * Parse xsl:sort first.
4206 if ((child
->type
== XML_ELEMENT_NODE
) &&
4207 IS_XSLT_ELEM_FAST(child
))
4209 if (xsltGetXSLTElementTypeByNode(cctxt
, child
) ==
4212 cctxt
->inode
->curChildType
= XSLT_FUNC_SORT
;
4213 xsltParseAnyXSLTElem(cctxt
, child
);
4218 child
= child
->next
;
4219 } while (child
!= NULL
);
4221 * Parse the sequece constructor.
4224 xsltParseSequenceConstructor(cctxt
, child
);
4228 sequence_constructor
:
4230 * Parse the sequence constructor.
4232 if (elem
->children
!= NULL
)
4233 xsltParseSequenceConstructor(cctxt
, elem
->children
);
4236 * Register information for vars/params. Only needed if there
4237 * are any following siblings.
4239 if ((elem
->next
!= NULL
) &&
4240 ((cctxt
->inode
->type
== XSLT_FUNC_VARIABLE
) ||
4241 (cctxt
->inode
->type
== XSLT_FUNC_PARAM
)))
4243 if ((elem
->psvi
!= NULL
) &&
4244 (((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->name
))
4246 xsltCompilerVarInfoPush(cctxt
, elem
,
4247 ((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->name
,
4248 ((xsltStyleBasicItemVariablePtr
) elem
->psvi
)->ns
);
4254 xsltCompilerNodePop(cctxt
, elem
);
4258 xsltCompilerNodePop(cctxt
, elem
);
4263 * xsltForwardsCompatUnkownItemCreate:
4265 * @cctxt: the compilation context
4267 * Creates a compiled representation of the unknown
4270 * Returns the compiled representation.
4272 static xsltStyleItemUknownPtr
4273 xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt
)
4275 xsltStyleItemUknownPtr item
;
4277 item
= (xsltStyleItemUknownPtr
) xmlMalloc(sizeof(xsltStyleItemUknown
));
4279 xsltTransformError(NULL
, cctxt
->style
, NULL
,
4280 "Internal error in xsltForwardsCompatUnkownItemCreate(): "
4281 "Failed to allocate memory.\n");
4282 cctxt
->style
->errors
++;
4285 memset(item
, 0, sizeof(xsltStyleItemUknown
));
4286 item
->type
= XSLT_FUNC_UNKOWN_FORWARDS_COMPAT
;
4288 * Store it in the stylesheet.
4290 item
->next
= cctxt
->style
->preComps
;
4291 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
4296 * xsltParseUnknownXSLTElem:
4298 * @cctxt: the compilation context
4299 * @node: the element of the unknown XSLT instruction
4301 * Parses an unknown XSLT element.
4302 * If forwards compatible mode is enabled this will allow
4303 * such an unknown XSLT and; otherwise it is rejected.
4305 * Returns 1 in the unknown XSLT instruction is rejected,
4306 * 0 if everything's fine and
4307 * -1 on API or internal errors.
4310 xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt
,
4313 if ((cctxt
== NULL
) || (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
4317 * Detection of handled content of extension instructions.
4319 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4320 cctxt
->inode
->extContentHandled
= 1;
4322 if (cctxt
->inode
->forwardsCompat
== 0) {
4324 * We are not in forwards-compatible mode, so raise an error.
4326 xsltTransformError(NULL
, cctxt
->style
, node
,
4327 "Unknown XSLT element '%s'.\n", node
->name
);
4328 cctxt
->style
->errors
++;
4332 * Forwards-compatible mode.
4333 * ------------------------
4335 * Parse/compile xsl:fallback elements.
4337 * QUESTION: Do we have to raise an error if there's no xsl:fallback?
4338 * ANSWER: No, since in the stylesheet the fallback behaviour might
4339 * also be provided by using the XSLT function "element-available".
4341 if (cctxt
->unknownItem
== NULL
) {
4343 * Create a singleton for all unknown XSLT instructions.
4345 cctxt
->unknownItem
= xsltForwardsCompatUnkownItemCreate(cctxt
);
4346 if (cctxt
->unknownItem
== NULL
) {
4351 node
->psvi
= cctxt
->unknownItem
;
4352 if (node
->children
== NULL
)
4355 xmlNodePtr child
= node
->children
;
4357 xsltCompilerNodePush(cctxt
, node
);
4359 * Update the in-scope namespaces if needed.
4361 if (node
->nsDef
!= NULL
)
4362 cctxt
->inode
->inScopeNs
=
4363 xsltCompilerBuildInScopeNsList(cctxt
, node
);
4365 * Parse all xsl:fallback children.
4368 if ((child
->type
== XML_ELEMENT_NODE
) &&
4369 IS_XSLT_ELEM_FAST(child
) &&
4370 IS_XSLT_NAME(child
, "fallback"))
4372 cctxt
->inode
->curChildType
= XSLT_FUNC_FALLBACK
;
4373 xsltParseAnyXSLTElem(cctxt
, child
);
4375 child
= child
->next
;
4376 } while (child
!= NULL
);
4378 xsltCompilerNodePop(cctxt
, node
);
4384 * xsltParseSequenceConstructor:
4386 * @cctxt: the compilation context
4387 * @cur: the start-node of the content to be parsed
4389 * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
4390 * This will additionally remove xsl:text elements from the tree.
4393 xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt
, xmlNodePtr cur
)
4396 xmlNodePtr deleteNode
= NULL
;
4398 if (cctxt
== NULL
) {
4399 xmlGenericError(xmlGenericErrorContext
,
4400 "xsltParseSequenceConstructor: Bad arguments\n");
4401 cctxt
->style
->errors
++;
4405 * Detection of handled content of extension instructions.
4407 if (cctxt
->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4408 cctxt
->inode
->extContentHandled
= 1;
4410 if ((cur
== NULL
) || (cur
->type
== XML_NAMESPACE_DECL
))
4413 * This is the content reffered to as a "template".
4414 * E.g. an xsl:element has such content model:
4417 * namespace = { uri-reference }
4418 * use-attribute-sets = qnames>
4419 * <!-- Content: template -->
4421 * NOTE that in XSLT-2 the term "template" was abandoned due to
4422 * confusion with xsl:template and the term "sequence constructor"
4423 * was introduced instead.
4425 * The following XSLT-instructions are allowed to appear:
4426 * xsl:apply-templates, xsl:call-template, xsl:apply-imports,
4427 * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
4428 * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
4429 * xsl:message, xsl:fallback,
4430 * xsl:processing-instruction, xsl:comment, xsl:element
4432 * Additional allowed content:
4433 * 1) extension instructions
4434 * 2) literal result elements
4437 * NOTE that this content model does *not* allow xsl:param.
4439 while (cur
!= NULL
) {
4440 if (deleteNode
!= NULL
) {
4441 #ifdef WITH_XSLT_DEBUG_BLANKS
4442 xsltGenericDebug(xsltGenericDebugContext
,
4443 "xsltParseSequenceConstructor: removing xsl:text element\n");
4445 xmlUnlinkNode(deleteNode
);
4446 xmlFreeNode(deleteNode
);
4449 if (cur
->type
== XML_ELEMENT_NODE
) {
4451 if (cur
->psvi
== xsltXSLTTextMarker
) {
4454 * --------------------------------------------------------
4460 * Mark the xsl:text element for later deletion.
4466 tmp
= cur
->children
;
4469 * We don't expect more than one text-node in the
4470 * content, since we already merged adjacent
4471 * text/CDATA-nodes and eliminated PI/comment-nodes.
4473 if ((tmp
->type
== XML_TEXT_NODE
) ||
4474 (tmp
->next
== NULL
))
4477 * Leave the contained text-node in the tree.
4480 xmlAddPrevSibling(cur
, tmp
);
4483 xsltTransformError(NULL
, cctxt
->style
, cur
,
4484 "Element 'xsl:text': Invalid type "
4485 "of node found in content.\n");
4486 cctxt
->style
->errors
++;
4489 if (cur
->properties
) {
4492 * TODO: We need to report errors for
4495 attr
= cur
->properties
;
4497 if ((attr
->ns
== NULL
) &&
4498 (attr
->name
!= NULL
) &&
4499 (attr
->name
[0] == 'd') &&
4500 xmlStrEqual(attr
->name
,
4501 BAD_CAST
"disable-output-escaping"))
4504 * Attr "disable-output-escaping".
4505 * XSLT-2: This attribute is deprecated.
4507 if ((attr
->children
!= NULL
) &&
4508 xmlStrEqual(attr
->children
->content
,
4512 * Disable output escaping for this
4516 tmp
->name
= xmlStringTextNoenc
;
4517 } else if ((attr
->children
== NULL
) ||
4518 (attr
->children
->content
== NULL
) ||
4519 (!xmlStrEqual(attr
->children
->content
,
4522 xsltTransformError(NULL
, cctxt
->style
,
4524 "Attribute 'disable-output-escaping': "
4525 "Invalid value. Expected is "
4526 "'yes' or 'no'.\n");
4527 cctxt
->style
->errors
++;
4532 } while (attr
!= NULL
);
4534 } else if (IS_XSLT_ELEM_FAST(cur
)) {
4536 * TODO: Using the XSLT-marker is still not stable yet.
4538 /* if (cur->psvi == xsltXSLTElemMarker) { */
4541 * --------------------------------------------------------
4544 type
= xsltGetXSLTElementTypeByNode(cctxt
, cur
);
4546 case XSLT_FUNC_APPLYIMPORTS
:
4547 case XSLT_FUNC_APPLYTEMPLATES
:
4548 case XSLT_FUNC_ATTRIBUTE
:
4549 case XSLT_FUNC_CALLTEMPLATE
:
4550 case XSLT_FUNC_CHOOSE
:
4551 case XSLT_FUNC_COMMENT
:
4552 case XSLT_FUNC_COPY
:
4553 case XSLT_FUNC_COPYOF
:
4554 case XSLT_FUNC_DOCUMENT
: /* Extra one */
4555 case XSLT_FUNC_ELEMENT
:
4556 case XSLT_FUNC_FALLBACK
:
4557 case XSLT_FUNC_FOREACH
:
4559 case XSLT_FUNC_MESSAGE
:
4560 case XSLT_FUNC_NUMBER
:
4562 case XSLT_FUNC_TEXT
:
4563 case XSLT_FUNC_VALUEOF
:
4564 case XSLT_FUNC_VARIABLE
:
4566 * Parse the XSLT element.
4568 cctxt
->inode
->curChildType
= type
;
4569 xsltParseAnyXSLTElem(cctxt
, cur
);
4572 xsltParseUnknownXSLTElem(cctxt
, cur
);
4581 xsltCompilerNodePush(cctxt
, cur
);
4583 * Update the in-scope namespaces if needed.
4585 if (cur
->nsDef
!= NULL
)
4586 cctxt
->inode
->inScopeNs
=
4587 xsltCompilerBuildInScopeNsList(cctxt
, cur
);
4589 * The current element is either a literal result element
4590 * or an extension instruction.
4592 * Process attr "xsl:extension-element-prefixes".
4593 * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
4594 * processed by the implementor of the extension function;
4595 * i.e., it won't be handled by the XSLT processor.
4598 * "exclude-result-prefixes" is only allowed on literal
4599 * result elements and "xsl:exclude-result-prefixes"
4600 * on xsl:stylesheet/xsl:transform.
4602 * "There are a number of standard attributes
4603 * that may appear on any XSLT element: specifically
4604 * version, exclude-result-prefixes,
4605 * extension-element-prefixes, xpath-default-namespace,
4606 * default-collation, and use-when."
4609 * For literal result elements:
4610 * "xsl:version, xsl:exclude-result-prefixes,
4611 * xsl:extension-element-prefixes,
4612 * xsl:xpath-default-namespace,
4613 * xsl:default-collation, or xsl:use-when."
4615 if (cur
->properties
)
4616 cctxt
->inode
->extElemNs
=
4617 xsltParseExtElemPrefixes(cctxt
,
4618 cur
, cctxt
->inode
->extElemNs
,
4619 XSLT_ELEMENT_CATEGORY_LRE
);
4621 * Eval if we have an extension instruction here.
4623 if ((cur
->ns
!= NULL
) &&
4624 (cctxt
->inode
->extElemNs
!= NULL
) &&
4625 (xsltCheckExtPrefix(cctxt
->style
, cur
->ns
->href
) == 1))
4628 * Extension instructions
4629 * ----------------------------------------------------
4630 * Mark the node information.
4632 cctxt
->inode
->category
= XSLT_ELEMENT_CATEGORY_EXTENSION
;
4633 cctxt
->inode
->extContentHandled
= 0;
4634 if (cur
->psvi
!= NULL
) {
4637 * TODO: Temporary sanity check.
4639 xsltTransformError(NULL
, cctxt
->style
, cur
,
4640 "Internal error in xsltParseSequenceConstructor(): "
4641 "Occupied PSVI field.\n");
4642 cctxt
->style
->errors
++;
4646 cur
->psvi
= (void *)
4647 xsltPreComputeExtModuleElement(cctxt
->style
, cur
);
4649 if (cur
->psvi
== NULL
) {
4651 * OLD COMMENT: "Unknown element, maybe registered
4652 * at the context level. Mark it for later
4654 * QUESTION: What does the xsltExtMarker mean?
4655 * ANSWER: It is used in
4656 * xsltApplySequenceConstructor() at
4657 * transformation-time to look out for extension
4658 * registered in the transformation context.
4660 cur
->psvi
= (void *) xsltExtMarker
;
4663 * BIG NOTE: Now the ugly part. In previous versions
4664 * of Libxslt (until 1.1.16), all the content of an
4665 * extension instruction was processed and compiled without
4666 * the need of the extension-author to explicitely call
4667 * such a processing;.We now need to mimic this old
4668 * behaviour in order to avoid breaking old code
4669 * on the extension-author's side.
4671 * 1) If the author does *not* set the
4672 * compile-time-flag @extContentHandled, then we'll
4673 * parse the content assuming that it's a "template"
4674 * (or "sequence constructor in XSLT 2.0 terms).
4675 * NOTE: If the extension is registered at
4676 * transformation-time only, then there's no way of
4677 * knowing that content shall be valid, and we'll
4678 * process the content the same way.
4679 * 2) If the author *does* set the flag, then we'll assume
4680 * that the author has handled the parsing him/herself
4681 * (e.g. called xsltParseSequenceConstructor(), etc.
4682 * explicitely in his/her code).
4684 if ((cur
->children
!= NULL
) &&
4685 (cctxt
->inode
->extContentHandled
== 0))
4688 * Default parsing of the content using the
4689 * sequence-constructor model.
4691 xsltParseSequenceConstructor(cctxt
, cur
->children
);
4695 * Literal result element
4696 * ----------------------------------------------------
4697 * Allowed XSLT attributes:
4698 * xsl:extension-element-prefixes CDATA #IMPLIED
4699 * xsl:exclude-result-prefixes CDATA #IMPLIED
4700 * TODO: xsl:use-attribute-sets %qnames; #IMPLIED
4701 * xsl:version NMTOKEN #IMPLIED
4704 cctxt
->inode
->category
= XSLT_ELEMENT_CATEGORY_LRE
;
4705 if (cur
->properties
!= NULL
) {
4706 xmlAttrPtr attr
= cur
->properties
;
4708 * Attribute "xsl:exclude-result-prefixes".
4710 cctxt
->inode
->exclResultNs
=
4711 xsltParseExclResultPrefixes(cctxt
, cur
,
4712 cctxt
->inode
->exclResultNs
,
4713 XSLT_ELEMENT_CATEGORY_LRE
);
4715 * Attribute "xsl:version".
4717 xsltParseAttrXSLTVersion(cctxt
, cur
,
4718 XSLT_ELEMENT_CATEGORY_LRE
);
4720 * Report invalid XSLT attributes.
4721 * For XSLT 1.0 only xsl:use-attribute-sets is allowed
4722 * next to xsl:version, xsl:exclude-result-prefixes and
4723 * xsl:extension-element-prefixes.
4725 * Mark all XSLT attributes, in order to skip such
4726 * attributes when instantiating the LRE.
4729 if ((attr
->psvi
!= xsltXSLTAttrMarker
) &&
4730 IS_XSLT_ATTR_FAST(attr
))
4732 if (! xmlStrEqual(attr
->name
,
4733 BAD_CAST
"use-attribute-sets"))
4735 xsltTransformError(NULL
, cctxt
->style
,
4737 "Unknown XSLT attribute '%s'.\n",
4739 cctxt
->style
->errors
++;
4744 attr
->psvi
= (void *) xsltXSLTAttrMarker
;
4748 } while (attr
!= NULL
);
4751 * Create/reuse info for the literal result element.
4753 if (cctxt
->inode
->nsChanged
)
4754 xsltLREInfoCreate(cctxt
, cur
, 1);
4755 cur
->psvi
= cctxt
->inode
->litResElemInfo
;
4757 * Apply ns-aliasing on the element and on its attributes.
4759 if (cctxt
->hasNsAliases
)
4760 xsltLREBuildEffectiveNs(cctxt
, cur
);
4762 * Compile attribute value templates (AVT).
4764 if (cur
->properties
) {
4765 xmlAttrPtr attr
= cur
->properties
;
4767 while (attr
!= NULL
) {
4768 xsltCompileAttr(cctxt
->style
, attr
);
4773 * Parse the content, which is defined to be a "template"
4774 * (or "sequence constructor" in XSLT 2.0 terms).
4776 if (cur
->children
!= NULL
) {
4777 xsltParseSequenceConstructor(cctxt
, cur
->children
);
4781 * Leave the non-XSLT element.
4783 xsltCompilerNodePop(cctxt
, cur
);
4788 if (deleteNode
!= NULL
) {
4789 #ifdef WITH_XSLT_DEBUG_BLANKS
4790 xsltGenericDebug(xsltGenericDebugContext
,
4791 "xsltParseSequenceConstructor: removing xsl:text element\n");
4793 xmlUnlinkNode(deleteNode
);
4794 xmlFreeNode(deleteNode
);
4800 * xsltParseTemplateContent:
4801 * @style: the XSLT stylesheet
4802 * @templ: the node containing the content to be parsed
4804 * Parses and compiles the content-model of an xsl:template element.
4805 * Note that this is *not* the "template" content model (or "sequence
4806 * constructor" in XSLT 2.0); it it allows addional xsl:param
4807 * elements as immediate children of @templ.
4810 * exsltFuncFunctionComp() (EXSLT, functions.c)
4811 * So this is intended to be called from extension functions.
4814 xsltParseTemplateContent(xsltStylesheetPtr style
, xmlNodePtr templ
) {
4815 if ((style
== NULL
) || (templ
== NULL
) ||
4816 (templ
->type
== XML_NAMESPACE_DECL
))
4820 * Detection of handled content of extension instructions.
4822 if (XSLT_CCTXT(style
)->inode
->category
== XSLT_ELEMENT_CATEGORY_EXTENSION
) {
4823 XSLT_CCTXT(style
)->inode
->extContentHandled
= 1;
4826 if (templ
->children
!= NULL
) {
4827 xmlNodePtr child
= templ
->children
;
4829 * Process xsl:param elements, which can only occur as the
4830 * immediate children of xsl:template (well, and of any
4831 * user-defined extension instruction if needed).
4834 if ((child
->type
== XML_ELEMENT_NODE
) &&
4835 IS_XSLT_ELEM_FAST(child
) &&
4836 IS_XSLT_NAME(child
, "param"))
4838 XSLT_CCTXT(style
)->inode
->curChildType
= XSLT_FUNC_PARAM
;
4839 xsltParseAnyXSLTElem(XSLT_CCTXT(style
), child
);
4842 child
= child
->next
;
4843 } while (child
!= NULL
);
4845 * Parse the content and register the pattern.
4847 xsltParseSequenceConstructor(XSLT_CCTXT(style
), child
);
4851 #else /* XSLT_REFACTORED */
4854 * xsltParseTemplateContent:
4855 * @style: the XSLT stylesheet
4856 * @templ: the container node (can be a document for literal results)
4858 * parse a template content-model
4859 * Clean-up the template content from unwanted ignorable blank nodes
4860 * and process xslt:text
4863 xsltParseTemplateContent(xsltStylesheetPtr style
, xmlNodePtr templ
) {
4864 xmlNodePtr cur
, delete;
4866 if ((style
== NULL
) || (templ
== NULL
) ||
4867 (templ
->type
== XML_NAMESPACE_DECL
)) return;
4870 * This content comes from the stylesheet
4871 * For stylesheets, the set of whitespace-preserving
4872 * element names consists of just xsl:text.
4874 cur
= templ
->children
;
4876 while (cur
!= NULL
) {
4877 if (delete != NULL
) {
4878 #ifdef WITH_XSLT_DEBUG_BLANKS
4879 xsltGenericDebug(xsltGenericDebugContext
,
4880 "xsltParseTemplateContent: removing text\n");
4882 xmlUnlinkNode(delete);
4883 xmlFreeNode(delete);
4886 if (IS_XSLT_ELEM(cur
)) {
4887 xsltStylePreCompute(style
, cur
);
4889 if (IS_XSLT_NAME(cur
, "text")) {
4891 * TODO: Processing of xsl:text should be moved to
4892 * xsltPreprocessStylesheet(), since otherwise this
4893 * will be performed for every multiply included
4894 * stylesheet; i.e. this here is not skipped with
4895 * the use of the style->nopreproc flag.
4897 if (cur
->children
!= NULL
) {
4899 xmlNodePtr text
= cur
->children
, next
;
4902 prop
= xmlGetNsProp(cur
,
4903 (const xmlChar
*)"disable-output-escaping",
4906 #ifdef WITH_XSLT_DEBUG_PARSING
4907 xsltGenericDebug(xsltGenericDebugContext
,
4908 "Disable escaping: %s\n", text
->content
);
4910 if (xmlStrEqual(prop
, (const xmlChar
*)"yes")) {
4912 } else if (!xmlStrEqual(prop
,
4913 (const xmlChar
*)"no")){
4914 xsltTransformError(NULL
, style
, cur
,
4915 "xsl:text: disable-output-escaping allows only yes or no\n");
4922 while (text
!= NULL
) {
4923 if (text
->type
== XML_COMMENT_NODE
) {
4927 if ((text
->type
!= XML_TEXT_NODE
) &&
4928 (text
->type
!= XML_CDATA_SECTION_NODE
)) {
4929 xsltTransformError(NULL
, style
, cur
,
4930 "xsltParseTemplateContent: xslt:text content problem\n");
4934 if ((noesc
) && (text
->type
!= XML_CDATA_SECTION_NODE
))
4935 text
->name
= xmlStringTextNoenc
;
4940 * replace xsl:text by the list of childs
4943 text
= cur
->children
;
4944 while (text
!= NULL
) {
4945 if ((style
->internalized
) &&
4946 (text
->content
!= NULL
) &&
4947 (!xmlDictOwns(style
->dict
, text
->content
))) {
4950 * internalize the text string
4952 if (text
->doc
->dict
!= NULL
) {
4955 tmp
= xmlDictLookup(text
->doc
->dict
,
4957 if (tmp
!= text
->content
) {
4958 xmlNodeSetContent(text
, NULL
);
4959 text
->content
= (xmlChar
*) tmp
;
4965 xmlUnlinkNode(text
);
4966 xmlAddPrevSibling(cur
, text
);
4975 else if ((cur
->ns
!= NULL
) && (style
->nsDefs
!= NULL
) &&
4976 (xsltCheckExtPrefix(style
, cur
->ns
->prefix
)))
4979 * okay this is an extension element compile it too
4981 xsltStylePreCompute(style
, cur
);
4983 else if (cur
->type
== XML_ELEMENT_NODE
)
4986 * This is an element which will be output as part of the
4987 * template exectution, precompile AVT if found.
4989 if ((cur
->ns
== NULL
) && (style
->defaultAlias
!= NULL
)) {
4990 cur
->ns
= xmlSearchNsByHref(cur
->doc
, cur
,
4991 style
->defaultAlias
);
4993 if (cur
->properties
!= NULL
) {
4994 xmlAttrPtr attr
= cur
->properties
;
4996 while (attr
!= NULL
) {
4997 xsltCompileAttr(style
, attr
);
5005 if (cur
->children
!= NULL
) {
5006 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
5007 cur
= cur
->children
;
5012 if (cur
->next
!= NULL
) {
5025 if (cur
->next
!= NULL
) {
5029 } while (cur
!= NULL
);
5031 if (delete != NULL
) {
5032 #ifdef WITH_XSLT_DEBUG_PARSING
5033 xsltGenericDebug(xsltGenericDebugContext
,
5034 "xsltParseTemplateContent: removing text\n");
5036 xmlUnlinkNode(delete);
5037 xmlFreeNode(delete);
5042 * Skip the first params
5044 cur
= templ
->children
;
5045 while (cur
!= NULL
) {
5046 if ((IS_XSLT_ELEM(cur
)) && (!(IS_XSLT_NAME(cur
, "param"))))
5052 * Browse the remainder of the template
5054 while (cur
!= NULL
) {
5055 if ((IS_XSLT_ELEM(cur
)) && (IS_XSLT_NAME(cur
, "param"))) {
5056 xmlNodePtr param
= cur
;
5058 xsltTransformError(NULL
, style
, cur
,
5059 "xsltParseTemplateContent: ignoring misplaced param element\n");
5060 if (style
!= NULL
) style
->warnings
++;
5062 xmlUnlinkNode(param
);
5069 #endif /* else XSLT_REFACTORED */
5072 * xsltParseStylesheetKey:
5073 * @style: the XSLT stylesheet
5074 * @key: the "key" element
5076 * <!-- Category: top-level-element -->
5077 * <xsl:key name = qname, match = pattern, use = expression />
5079 * parse an XSLT stylesheet key definition and register it
5083 xsltParseStylesheetKey(xsltStylesheetPtr style
, xmlNodePtr key
) {
5084 xmlChar
*prop
= NULL
;
5085 xmlChar
*use
= NULL
;
5086 xmlChar
*match
= NULL
;
5087 xmlChar
*name
= NULL
;
5088 xmlChar
*nameURI
= NULL
;
5090 if ((style
== NULL
) || (key
== NULL
) || (key
->type
!= XML_ELEMENT_NODE
))
5096 prop
= xmlGetNsProp(key
, (const xmlChar
*)"name", NULL
);
5101 * TODO: Don't use xsltGetQNameURI().
5103 URI
= xsltGetQNameURI(key
, &prop
);
5105 if (style
!= NULL
) style
->errors
++;
5110 nameURI
= xmlStrdup(URI
);
5112 #ifdef WITH_XSLT_DEBUG_PARSING
5113 xsltGenericDebug(xsltGenericDebugContext
,
5114 "xsltParseStylesheetKey: name %s\n", name
);
5117 xsltTransformError(NULL
, style
, key
,
5118 "xsl:key : error missing name\n");
5119 if (style
!= NULL
) style
->errors
++;
5123 match
= xmlGetNsProp(key
, (const xmlChar
*)"match", NULL
);
5124 if (match
== NULL
) {
5125 xsltTransformError(NULL
, style
, key
,
5126 "xsl:key : error missing match\n");
5127 if (style
!= NULL
) style
->errors
++;
5131 use
= xmlGetNsProp(key
, (const xmlChar
*)"use", NULL
);
5133 xsltTransformError(NULL
, style
, key
,
5134 "xsl:key : error missing use\n");
5135 if (style
!= NULL
) style
->errors
++;
5142 xsltAddKey(style
, name
, nameURI
, match
, use
, key
);
5152 if (nameURI
!= NULL
)
5155 if (key
->children
!= NULL
) {
5156 xsltParseContentError(style
, key
->children
);
5160 #ifdef XSLT_REFACTORED
5162 * xsltParseXSLTTemplate:
5163 * @style: the XSLT stylesheet
5164 * @template: the "template" element
5166 * parse an XSLT stylesheet template building the associated structures
5167 * TODO: Is @style ever expected to be NULL?
5170 * xsltParseXSLTStylesheet()
5171 * xsltParseStylesheetTop()
5175 xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt
, xmlNodePtr templNode
) {
5176 xsltTemplatePtr templ
;
5180 if ((cctxt
== NULL
) || (templNode
== NULL
) ||
5181 (templNode
->type
!= XML_ELEMENT_NODE
))
5185 * Create and link the structure
5187 templ
= xsltNewTemplate();
5191 xsltCompilerNodePush(cctxt
, templNode
);
5192 if (templNode
->nsDef
!= NULL
)
5193 cctxt
->inode
->inScopeNs
=
5194 xsltCompilerBuildInScopeNsList(cctxt
, templNode
);
5196 templ
->next
= cctxt
->style
->templates
;
5197 cctxt
->style
->templates
= templ
;
5198 templ
->style
= cctxt
->style
;
5203 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"mode", NULL
);
5205 const xmlChar
*modeURI
;
5208 * TODO: We need a standardized function for extraction
5209 * of namespace names and local names from QNames.
5210 * Don't use xsltGetQNameURI() as it cannot channe�
5211 * reports through the context.
5213 modeURI
= xsltGetQNameURI(templNode
, &prop
);
5215 cctxt
->style
->errors
++;
5218 templ
->mode
= xmlDictLookup(cctxt
->style
->dict
, prop
, -1);
5221 if (xmlValidateNCName(templ
->mode
, 0)) {
5222 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5223 "xsl:template: Attribute 'mode': The local part '%s' "
5224 "of the value is not a valid NCName.\n", templ
->name
);
5225 cctxt
->style
->errors
++;
5228 if (modeURI
!= NULL
)
5229 templ
->modeURI
= xmlDictLookup(cctxt
->style
->dict
, modeURI
, -1);
5230 #ifdef WITH_XSLT_DEBUG_PARSING
5231 xsltGenericDebug(xsltGenericDebugContext
,
5232 "xsltParseXSLTTemplate: mode %s\n", templ
->mode
);
5236 * Attribute "match".
5238 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"match", NULL
);
5240 templ
->match
= prop
;
5244 * Attribute "priority".
5246 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"priority", NULL
);
5248 priority
= xmlXPathStringEvalNumber(prop
);
5249 templ
->priority
= (float) priority
;
5256 prop
= xmlGetNsProp(templNode
, (const xmlChar
*)"name", NULL
);
5258 const xmlChar
*nameURI
;
5259 xsltTemplatePtr curTempl
;
5262 * TODO: Don't use xsltGetQNameURI().
5264 nameURI
= xsltGetQNameURI(templNode
, &prop
);
5266 cctxt
->style
->errors
++;
5269 templ
->name
= xmlDictLookup(cctxt
->style
->dict
, prop
, -1);
5272 if (xmlValidateNCName(templ
->name
, 0)) {
5273 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5274 "xsl:template: Attribute 'name': The local part '%s' of "
5275 "the value is not a valid NCName.\n", templ
->name
);
5276 cctxt
->style
->errors
++;
5279 if (nameURI
!= NULL
)
5280 templ
->nameURI
= xmlDictLookup(cctxt
->style
->dict
, nameURI
, -1);
5281 curTempl
= templ
->next
;
5282 while (curTempl
!= NULL
) {
5283 if ((nameURI
!= NULL
&& xmlStrEqual(curTempl
->name
, templ
->name
) &&
5284 xmlStrEqual(curTempl
->nameURI
, nameURI
) ) ||
5285 (nameURI
== NULL
&& curTempl
->nameURI
== NULL
&&
5286 xmlStrEqual(curTempl
->name
, templ
->name
)))
5288 xsltTransformError(NULL
, cctxt
->style
, templNode
,
5289 "xsl:template: error duplicate name '%s'\n", templ
->name
);
5290 cctxt
->style
->errors
++;
5293 curTempl
= curTempl
->next
;
5296 if (templNode
->children
!= NULL
) {
5297 xsltParseTemplateContent(cctxt
->style
, templNode
);
5299 * MAYBE TODO: Custom behaviour: In order to stay compatible with
5300 * Xalan and MSXML(.NET), we could allow whitespace
5301 * to appear before an xml:param element; this whitespace
5302 * will additionally become part of the "template".
5303 * NOTE that this is totally deviates from the spec, but
5304 * is the de facto behaviour of Xalan and MSXML(.NET).
5305 * Personally I wouldn't allow this, since if we have:
5306 * <xsl:template ...xml:space="preserve">
5307 * <xsl:param name="foo"/>
5308 * <xsl:param name="bar"/>
5309 * <xsl:param name="zoo"/>
5310 * ... the whitespace between every xsl:param would be
5311 * added to the result tree.
5315 templ
->elem
= templNode
;
5316 templ
->content
= templNode
->children
;
5317 xsltAddTemplate(cctxt
->style
, templ
, templ
->mode
, templ
->modeURI
);
5320 xsltCompilerNodePop(cctxt
, templNode
);
5324 #else /* XSLT_REFACTORED */
5327 * xsltParseStylesheetTemplate:
5328 * @style: the XSLT stylesheet
5329 * @template: the "template" element
5331 * parse an XSLT stylesheet template building the associated structures
5335 xsltParseStylesheetTemplate(xsltStylesheetPtr style
, xmlNodePtr
template) {
5336 xsltTemplatePtr ret
;
5338 xmlChar
*mode
= NULL
;
5339 xmlChar
*modeURI
= NULL
;
5342 if ((style
== NULL
) || (template == NULL
) ||
5343 (template->type
!= XML_ELEMENT_NODE
))
5347 * Create and link the structure
5349 ret
= xsltNewTemplate();
5352 ret
->next
= style
->templates
;
5353 style
->templates
= ret
;
5357 * Get inherited namespaces
5360 * TODO: Apply the optimized in-scope-namespace mechanism
5361 * as for the other XSLT instructions.
5363 xsltGetInheritedNsList(style
, ret
, template);
5368 prop
= xmlGetNsProp(template, (const xmlChar
*)"mode", NULL
);
5373 * TODO: Don't use xsltGetQNameURI().
5375 URI
= xsltGetQNameURI(template, &prop
);
5377 if (style
!= NULL
) style
->errors
++;
5382 modeURI
= xmlStrdup(URI
);
5384 ret
->mode
= xmlDictLookup(style
->dict
, mode
, -1);
5385 ret
->modeURI
= xmlDictLookup(style
->dict
, modeURI
, -1);
5386 #ifdef WITH_XSLT_DEBUG_PARSING
5387 xsltGenericDebug(xsltGenericDebugContext
,
5388 "xsltParseStylesheetTemplate: mode %s\n", mode
);
5390 if (mode
!= NULL
) xmlFree(mode
);
5391 if (modeURI
!= NULL
) xmlFree(modeURI
);
5393 prop
= xmlGetNsProp(template, (const xmlChar
*)"match", NULL
);
5395 if (ret
->match
!= NULL
) xmlFree(ret
->match
);
5399 prop
= xmlGetNsProp(template, (const xmlChar
*)"priority", NULL
);
5401 priority
= xmlXPathStringEvalNumber(prop
);
5402 ret
->priority
= (float) priority
;
5406 prop
= xmlGetNsProp(template, (const xmlChar
*)"name", NULL
);
5411 * TODO: Don't use xsltGetQNameURI().
5413 URI
= xsltGetQNameURI(template, &prop
);
5415 if (style
!= NULL
) style
->errors
++;
5418 if (xmlValidateNCName(prop
,0)) {
5419 xsltTransformError(NULL
, style
, template,
5420 "xsl:template : error invalid name '%s'\n", prop
);
5421 if (style
!= NULL
) style
->errors
++;
5425 ret
->name
= xmlDictLookup(style
->dict
, BAD_CAST prop
, -1);
5429 ret
->nameURI
= xmlDictLookup(style
->dict
, BAD_CAST URI
, -1);
5431 ret
->nameURI
= NULL
;
5436 * parse the content and register the pattern
5438 xsltParseTemplateContent(style
, template);
5439 ret
->elem
= template;
5440 ret
->content
= template->children
;
5441 xsltAddTemplate(style
, ret
, ret
->mode
, ret
->modeURI
);
5447 #endif /* else XSLT_REFACTORED */
5449 #ifdef XSLT_REFACTORED
5453 * @cctxt: the compilation contenxt
5454 * @node: the xsl:include node
5456 * Process the xslt include node on the source node
5458 static xsltStyleItemIncludePtr
5459 xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
) {
5460 xsltStyleItemIncludePtr item
;
5462 if ((cctxt
== NULL
) || (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
5466 item
= (xsltStyleItemIncludePtr
) xmlMalloc(sizeof(xsltStyleItemInclude
));
5468 xsltTransformError(NULL
, cctxt
->style
, node
,
5469 "xsltIncludeComp : malloc failed\n");
5470 cctxt
->style
->errors
++;
5473 memset(item
, 0, sizeof(xsltStyleItemInclude
));
5477 item
->type
= XSLT_FUNC_INCLUDE
;
5479 item
->next
= cctxt
->style
->preComps
;
5480 cctxt
->style
->preComps
= (xsltElemPreCompPtr
) item
;
5486 * xsltParseFindTopLevelElem:
5489 xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt
,
5491 const xmlChar
*name
,
5492 const xmlChar
*namespaceURI
,
5493 int breakOnOtherElem
,
5494 xmlNodePtr
*resultNode
)
5500 while (cur
!= NULL
) {
5501 if (cur
->type
== XML_ELEMENT_NODE
) {
5502 if ((cur
->ns
!= NULL
) && (cur
->name
!= NULL
)) {
5503 if ((*(cur
->name
) == *name
) &&
5504 xmlStrEqual(cur
->name
, name
) &&
5505 xmlStrEqual(cur
->ns
->href
, namespaceURI
))
5511 if (breakOnOtherElem
)
5521 xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt
,
5528 * TODO: The reason why this function exists:
5529 * due to historical reasons some of the
5530 * top-level declarations are processed by functions
5531 * in other files. Since we need still to set
5532 * up the node-info and generate information like
5533 * in-scope namespaces, this is a wrapper around
5534 * those old parsing functions.
5536 xsltCompilerNodePush(cctxt
, node
);
5537 if (node
->nsDef
!= NULL
)
5538 cctxt
->inode
->inScopeNs
=
5539 xsltCompilerBuildInScopeNsList(cctxt
, node
);
5540 cctxt
->inode
->type
= type
;
5543 case XSLT_FUNC_INCLUDE
:
5547 if (xsltCompileXSLTIncludeElem(cctxt
, node
) == NULL
)
5550 * Mark this stylesheet tree as being currently included.
5552 oldIsInclude
= cctxt
->isInclude
;
5553 cctxt
->isInclude
= 1;
5555 if (xsltParseStylesheetInclude(cctxt
->style
, node
) != 0) {
5556 cctxt
->style
->errors
++;
5558 cctxt
->isInclude
= oldIsInclude
;
5561 case XSLT_FUNC_PARAM
:
5562 xsltStylePreCompute(cctxt
->style
, node
);
5563 xsltParseGlobalParam(cctxt
->style
, node
);
5565 case XSLT_FUNC_VARIABLE
:
5566 xsltStylePreCompute(cctxt
->style
, node
);
5567 xsltParseGlobalVariable(cctxt
->style
, node
);
5569 case XSLT_FUNC_ATTRSET
:
5570 xsltParseStylesheetAttributeSet(cctxt
->style
, node
);
5573 xsltTransformError(NULL
, cctxt
->style
, node
,
5574 "Internal error: (xsltParseTopLevelXSLTElem) "
5575 "Cannot handle this top-level declaration.\n");
5576 cctxt
->style
->errors
++;
5581 xsltCompilerNodePop(cctxt
, node
);
5588 xsltParseRemoveWhitespace(xmlNodePtr node
)
5590 if ((node
== NULL
) || (node
->children
== NULL
))
5593 xmlNodePtr delNode
= NULL
, child
= node
->children
;
5597 xmlUnlinkNode(delNode
);
5598 xmlFreeNode(delNode
);
5601 if (((child
->type
== XML_TEXT_NODE
) ||
5602 (child
->type
== XML_CDATA_SECTION_NODE
)) &&
5603 (IS_BLANK_NODE(child
)))
5605 child
= child
->next
;
5606 } while (child
!= NULL
);
5608 xmlUnlinkNode(delNode
);
5609 xmlFreeNode(delNode
);
5618 xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
5620 #ifdef WITH_XSLT_DEBUG_PARSING
5623 xmlNodePtr cur
, start
= NULL
;
5624 xsltStylesheetPtr style
;
5626 if ((cctxt
== NULL
) || (node
== NULL
) ||
5627 (node
->type
!= XML_ELEMENT_NODE
))
5630 style
= cctxt
->style
;
5632 * At this stage all import declarations of all stylesheet modules
5633 * with the same stylesheet level have been processed.
5634 * Now we can safely parse the rest of the declarations.
5636 if (IS_XSLT_ELEM_FAST(node
) && IS_XSLT_NAME(node
, "include"))
5638 xsltDocumentPtr include
;
5640 * URGENT TODO: Make this work with simplified stylesheets!
5641 * I.e., when we won't find an xsl:stylesheet element.
5644 * This is as include declaration.
5646 include
= ((xsltStyleItemIncludePtr
) node
->psvi
)->include
;
5647 if (include
== NULL
) {
5648 /* TODO: raise error? */
5652 * TODO: Actually an xsl:include should locate an embedded
5653 * stylesheet as well; so the document-element won't always
5654 * be the element where the actual stylesheet is rooted at.
5655 * But such embedded stylesheets are not supported by Libxslt yet.
5657 node
= xmlDocGetRootElement(include
->doc
);
5663 if (node
->children
== NULL
)
5666 * Push the xsl:stylesheet/xsl:transform element.
5668 xsltCompilerNodePush(cctxt
, node
);
5669 cctxt
->inode
->isRoot
= 1;
5670 cctxt
->inode
->nsChanged
= 0;
5672 * Start with the naked dummy info for literal result elements.
5674 cctxt
->inode
->litResElemInfo
= cctxt
->inodeList
->litResElemInfo
;
5677 * In every case, we need to have
5678 * the in-scope namespaces of the element, where the
5679 * stylesheet is rooted at, regardless if it's an XSLT
5680 * instruction or a literal result instruction (or if
5681 * this is an embedded stylesheet).
5683 cctxt
->inode
->inScopeNs
=
5684 xsltCompilerBuildInScopeNsList(cctxt
, node
);
5687 * Process attributes of xsl:stylesheet/xsl:transform.
5688 * --------------------------------------------------
5691 * extension-element-prefixes = tokens
5692 * exclude-result-prefixes = tokens
5693 * version = number (mandatory)
5695 if (xsltParseAttrXSLTVersion(cctxt
, node
,
5696 XSLT_ELEMENT_CATEGORY_XSLT
) == 0)
5699 * Attribute "version".
5700 * XSLT 1.0: "An xsl:stylesheet element *must* have a version
5701 * attribute, indicating the version of XSLT that the
5702 * stylesheet requires".
5703 * The root element of a simplified stylesheet must also have
5706 #ifdef XSLT_REFACTORED_MANDATORY_VERSION
5708 xsltTransformError(NULL
, cctxt
->style
, node
,
5709 "The attribute 'version' is missing.\n");
5710 cctxt
->style
->errors
++;
5712 /* OLD behaviour. */
5713 xsltTransformError(NULL
, cctxt
->style
, node
,
5714 "xsl:version is missing: document may not be a stylesheet\n");
5715 cctxt
->style
->warnings
++;
5719 * The namespaces declared by the attributes
5720 * "extension-element-prefixes" and
5721 * "exclude-result-prefixes" are local to *this*
5722 * stylesheet tree; i.e., they are *not* visible to
5723 * other stylesheet-modules, whether imported or included.
5725 * Attribute "extension-element-prefixes".
5727 cctxt
->inode
->extElemNs
=
5728 xsltParseExtElemPrefixes(cctxt
, node
, NULL
,
5729 XSLT_ELEMENT_CATEGORY_XSLT
);
5731 * Attribute "exclude-result-prefixes".
5733 cctxt
->inode
->exclResultNs
=
5734 xsltParseExclResultPrefixes(cctxt
, node
, NULL
,
5735 XSLT_ELEMENT_CATEGORY_XSLT
);
5737 * Create/reuse info for the literal result element.
5739 if (cctxt
->inode
->nsChanged
)
5740 xsltLREInfoCreate(cctxt
, node
, 0);
5742 * Processed top-level elements:
5743 * ----------------------------
5744 * xsl:variable, xsl:param (QName, in-scope ns,
5745 * expression (vars allowed))
5746 * xsl:attribute-set (QName, in-scope ns)
5747 * xsl:strip-space, xsl:preserve-space (XPath NameTests,
5749 * I *think* global scope, merge with includes
5750 * xsl:output (QName, in-scope ns)
5751 * xsl:key (QName, in-scope ns, pattern,
5752 * expression (vars *not* allowed))
5753 * xsl:decimal-format (QName, needs in-scope ns)
5754 * xsl:namespace-alias (in-scope ns)
5755 * global scope, merge with includes
5756 * xsl:template (last, QName, pattern)
5758 * (whitespace-only text-nodes have *not* been removed
5759 * yet; this will be done in xsltParseSequenceConstructor)
5761 * Report misplaced child-nodes first.
5763 cur
= node
->children
;
5764 while (cur
!= NULL
) {
5765 if (cur
->type
== XML_TEXT_NODE
) {
5766 xsltTransformError(NULL
, style
, cur
,
5767 "Misplaced text node (content: '%s').\n",
5768 (cur
->content
!= NULL
) ? cur
->content
: BAD_CAST
"");
5770 } else if (cur
->type
!= XML_ELEMENT_NODE
) {
5771 xsltTransformError(NULL
, style
, cur
, "Misplaced node.\n");
5777 * Skip xsl:import elements; they have been processed
5780 cur
= node
->children
;
5781 while ((cur
!= NULL
) && xsltParseFindTopLevelElem(cctxt
, cur
,
5782 BAD_CAST
"import", XSLT_NAMESPACE
, 1, &cur
) == 1)
5789 * Process all top-level xsl:param elements.
5791 while ((cur
!= NULL
) &&
5792 xsltParseFindTopLevelElem(cctxt
, cur
,
5793 BAD_CAST
"param", XSLT_NAMESPACE
, 0, &cur
) == 1)
5795 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_PARAM
);
5799 * Process all top-level xsl:variable elements.
5802 while ((cur
!= NULL
) &&
5803 xsltParseFindTopLevelElem(cctxt
, cur
,
5804 BAD_CAST
"variable", XSLT_NAMESPACE
, 0, &cur
) == 1)
5806 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_VARIABLE
);
5810 * Process all the rest of top-level elements.
5813 while (cur
!= NULL
) {
5815 * Process element nodes.
5817 if (cur
->type
== XML_ELEMENT_NODE
) {
5818 if (cur
->ns
== NULL
) {
5819 xsltTransformError(NULL
, style
, cur
,
5820 "Unexpected top-level element in no namespace.\n");
5826 * Process all XSLT elements.
5828 if (IS_XSLT_ELEM_FAST(cur
)) {
5830 * xsl:import is only allowed at the beginning.
5832 if (IS_XSLT_NAME(cur
, "import")) {
5833 xsltTransformError(NULL
, style
, cur
,
5834 "Misplaced xsl:import element.\n");
5840 * TODO: Change the return type of the parsing functions
5843 if (IS_XSLT_NAME(cur
, "template")) {
5844 #ifdef WITH_XSLT_DEBUG_PARSING
5848 * TODO: Is the position of xsl:template in the
5849 * tree significant? If not it would be easier to
5850 * parse them at a later stage.
5852 xsltParseXSLTTemplate(cctxt
, cur
);
5853 } else if (IS_XSLT_NAME(cur
, "variable")) {
5854 /* NOP; done already */
5855 } else if (IS_XSLT_NAME(cur
, "param")) {
5856 /* NOP; done already */
5857 } else if (IS_XSLT_NAME(cur
, "include")) {
5858 if (cur
->psvi
!= NULL
)
5859 xsltParseXSLTStylesheetElemCore(cctxt
, cur
);
5861 xsltTransformError(NULL
, style
, cur
,
5863 "(xsltParseXSLTStylesheetElemCore) "
5864 "The xsl:include element was not compiled.\n");
5867 } else if (IS_XSLT_NAME(cur
, "strip-space")) {
5868 /* No node info needed. */
5869 xsltParseStylesheetStripSpace(style
, cur
);
5870 } else if (IS_XSLT_NAME(cur
, "preserve-space")) {
5871 /* No node info needed. */
5872 xsltParseStylesheetPreserveSpace(style
, cur
);
5873 } else if (IS_XSLT_NAME(cur
, "output")) {
5874 /* No node-info needed. */
5875 xsltParseStylesheetOutput(style
, cur
);
5876 } else if (IS_XSLT_NAME(cur
, "key")) {
5877 /* TODO: node-info needed for expressions ? */
5878 xsltParseStylesheetKey(style
, cur
);
5879 } else if (IS_XSLT_NAME(cur
, "decimal-format")) {
5880 /* No node-info needed. */
5881 xsltParseStylesheetDecimalFormat(style
, cur
);
5882 } else if (IS_XSLT_NAME(cur
, "attribute-set")) {
5883 xsltParseTopLevelXSLTElem(cctxt
, cur
,
5885 } else if (IS_XSLT_NAME(cur
, "namespace-alias")) {
5886 /* NOP; done already */
5888 if (cctxt
->inode
->forwardsCompat
) {
5890 * Forwards-compatible mode:
5892 * XSLT-1: "if it is a top-level element and
5893 * XSLT 1.0 does not allow such elements as top-level
5894 * elements, then the element must be ignored along
5895 * with its content;"
5898 * TODO: I don't think we should generate a warning.
5900 xsltTransformError(NULL
, style
, cur
,
5901 "Forwards-compatible mode: Ignoring unknown XSLT "
5902 "element '%s'.\n", cur
->name
);
5905 xsltTransformError(NULL
, style
, cur
,
5906 "Unknown XSLT element '%s'.\n", cur
->name
);
5911 xsltTopLevelFunction function
;
5914 * Process non-XSLT elements, which are in a
5915 * non-NULL namespace.
5918 * QUESTION: What does xsltExtModuleTopLevelLookup()
5921 function
= xsltExtModuleTopLevelLookup(cur
->name
,
5923 if (function
!= NULL
)
5924 function(style
, cur
);
5925 #ifdef WITH_XSLT_DEBUG_PARSING
5926 xsltGenericDebug(xsltGenericDebugContext
,
5927 "xsltParseXSLTStylesheetElemCore : User-defined "
5928 "data element '%s'.\n", cur
->name
);
5937 #ifdef WITH_XSLT_DEBUG_PARSING
5938 xsltGenericDebug(xsltGenericDebugContext
,
5939 "### END of parsing top-level elements of doc '%s'.\n",
5941 xsltGenericDebug(xsltGenericDebugContext
,
5942 "### Templates: %d\n", templates
);
5943 #ifdef XSLT_REFACTORED
5944 xsltGenericDebug(xsltGenericDebugContext
,
5945 "### Max inodes: %d\n", cctxt
->maxNodeInfos
);
5946 xsltGenericDebug(xsltGenericDebugContext
,
5947 "### Max LREs : %d\n", cctxt
->maxLREs
);
5948 #endif /* XSLT_REFACTORED */
5949 #endif /* WITH_XSLT_DEBUG_PARSING */
5951 xsltCompilerNodePop(cctxt
, node
);
5956 * xsltParseXSLTStylesheet:
5957 * @cctxt: the compiler context
5958 * @node: the xsl:stylesheet/xsl:transform element-node
5960 * Parses the xsl:stylesheet and xsl:transform element.
5964 * extension-element-prefixes = tokens
5965 * exclude-result-prefixes = tokens
5967 * <!-- Content: (xsl:import*, top-level-elements) -->
5970 * BIG TODO: The xsl:include stuff.
5972 * Called by xsltParseStylesheetTree()
5974 * Returns 0 on success, a positive result on errors and
5975 * -1 on API or internal errors.
5978 xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt
, xmlNodePtr node
)
5980 xmlNodePtr cur
, start
;
5982 if ((cctxt
== NULL
) || (node
== NULL
) || (node
->type
!= XML_ELEMENT_NODE
))
5985 if (node
->children
== NULL
)
5989 * Process top-level elements:
5990 * xsl:import (must be first)
5991 * xsl:include (this is just a pre-processing)
5993 cur
= node
->children
;
5995 * Process xsl:import elements.
5996 * XSLT 1.0: "The xsl:import element children must precede all
5997 * other element children of an xsl:stylesheet element,
5998 * including any xsl:include element children."
6000 while ((cur
!= NULL
) &&
6001 xsltParseFindTopLevelElem(cctxt
, cur
,
6002 BAD_CAST
"import", XSLT_NAMESPACE
, 1, &cur
) == 1)
6004 if (xsltParseStylesheetImport(cctxt
->style
, cur
) != 0) {
6005 cctxt
->style
->errors
++;
6013 * Pre-process all xsl:include elements.
6016 while ((cur
!= NULL
) &&
6017 xsltParseFindTopLevelElem(cctxt
, cur
,
6018 BAD_CAST
"include", XSLT_NAMESPACE
, 0, &cur
) == 1)
6020 xsltParseTopLevelXSLTElem(cctxt
, cur
, XSLT_FUNC_INCLUDE
);
6024 * Pre-process all xsl:namespace-alias elements.
6025 * URGENT TODO: This won't work correctly: the order of included
6026 * aliases and aliases defined here is significant.
6029 while ((cur
!= NULL
) &&
6030 xsltParseFindTopLevelElem(cctxt
, cur
,
6031 BAD_CAST
"namespace-alias", XSLT_NAMESPACE
, 0, &cur
) == 1)
6033 xsltNamespaceAlias(cctxt
->style
, cur
);
6037 if (cctxt
->isInclude
) {
6039 * If this stylesheet is intended for inclusion, then
6040 * we will process only imports and includes.
6045 * Now parse the rest of the top-level elements.
6047 xsltParseXSLTStylesheetElemCore(cctxt
, node
);
6053 #else /* XSLT_REFACTORED */
6056 * xsltParseStylesheetTop:
6057 * @style: the XSLT stylesheet
6058 * @top: the top level "stylesheet" or "transform" element
6060 * scan the top level elements of an XSL stylesheet
6063 xsltParseStylesheetTop(xsltStylesheetPtr style
, xmlNodePtr top
) {
6066 #ifdef WITH_XSLT_DEBUG_PARSING
6070 if ((top
== NULL
) || (top
->type
!= XML_ELEMENT_NODE
))
6073 prop
= xmlGetNsProp(top
, (const xmlChar
*)"version", NULL
);
6075 xsltTransformError(NULL
, style
, top
,
6076 "xsl:version is missing: document may not be a stylesheet\n");
6077 if (style
!= NULL
) style
->warnings
++;
6079 if ((!xmlStrEqual(prop
, (const xmlChar
*)"1.0")) &&
6080 (!xmlStrEqual(prop
, (const xmlChar
*)"1.1"))) {
6081 xsltTransformError(NULL
, style
, top
,
6082 "xsl:version: only 1.1 features are supported\n");
6083 if (style
!= NULL
) {
6084 style
->forwards_compatible
= 1;
6092 * process xsl:import elements
6094 cur
= top
->children
;
6095 while (cur
!= NULL
) {
6096 if (IS_BLANK_NODE(cur
)) {
6100 if (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "import")) {
6101 if (xsltParseStylesheetImport(style
, cur
) != 0)
6102 if (style
!= NULL
) style
->errors
++;
6109 * process other top-level elements
6111 while (cur
!= NULL
) {
6112 if (IS_BLANK_NODE(cur
)) {
6116 if (cur
->type
== XML_TEXT_NODE
) {
6117 if (cur
->content
!= NULL
) {
6118 xsltTransformError(NULL
, style
, cur
,
6119 "misplaced text node: '%s'\n", cur
->content
);
6121 if (style
!= NULL
) style
->errors
++;
6125 if ((cur
->type
== XML_ELEMENT_NODE
) && (cur
->ns
== NULL
)) {
6126 xsltGenericError(xsltGenericErrorContext
,
6127 "Found a top-level element %s with null namespace URI\n",
6129 if (style
!= NULL
) style
->errors
++;
6133 if ((cur
->type
== XML_ELEMENT_NODE
) && (!(IS_XSLT_ELEM(cur
)))) {
6134 xsltTopLevelFunction function
;
6136 function
= xsltExtModuleTopLevelLookup(cur
->name
,
6138 if (function
!= NULL
)
6139 function(style
, cur
);
6141 #ifdef WITH_XSLT_DEBUG_PARSING
6142 xsltGenericDebug(xsltGenericDebugContext
,
6143 "xsltParseStylesheetTop : found foreign element %s\n",
6149 if (IS_XSLT_NAME(cur
, "import")) {
6150 xsltTransformError(NULL
, style
, cur
,
6151 "xsltParseStylesheetTop: ignoring misplaced import element\n");
6152 if (style
!= NULL
) style
->errors
++;
6153 } else if (IS_XSLT_NAME(cur
, "include")) {
6154 if (xsltParseStylesheetInclude(style
, cur
) != 0)
6155 if (style
!= NULL
) style
->errors
++;
6156 } else if (IS_XSLT_NAME(cur
, "strip-space")) {
6157 xsltParseStylesheetStripSpace(style
, cur
);
6158 } else if (IS_XSLT_NAME(cur
, "preserve-space")) {
6159 xsltParseStylesheetPreserveSpace(style
, cur
);
6160 } else if (IS_XSLT_NAME(cur
, "output")) {
6161 xsltParseStylesheetOutput(style
, cur
);
6162 } else if (IS_XSLT_NAME(cur
, "key")) {
6163 xsltParseStylesheetKey(style
, cur
);
6164 } else if (IS_XSLT_NAME(cur
, "decimal-format")) {
6165 xsltParseStylesheetDecimalFormat(style
, cur
);
6166 } else if (IS_XSLT_NAME(cur
, "attribute-set")) {
6167 xsltParseStylesheetAttributeSet(style
, cur
);
6168 } else if (IS_XSLT_NAME(cur
, "variable")) {
6169 xsltParseGlobalVariable(style
, cur
);
6170 } else if (IS_XSLT_NAME(cur
, "param")) {
6171 xsltParseGlobalParam(style
, cur
);
6172 } else if (IS_XSLT_NAME(cur
, "template")) {
6173 #ifdef WITH_XSLT_DEBUG_PARSING
6176 xsltParseStylesheetTemplate(style
, cur
);
6177 } else if (IS_XSLT_NAME(cur
, "namespace-alias")) {
6178 xsltNamespaceAlias(style
, cur
);
6180 if ((style
!= NULL
) && (style
->forwards_compatible
== 0)) {
6181 xsltTransformError(NULL
, style
, cur
,
6182 "xsltParseStylesheetTop: unknown %s element\n",
6184 if (style
!= NULL
) style
->errors
++;
6189 #ifdef WITH_XSLT_DEBUG_PARSING
6190 xsltGenericDebug(xsltGenericDebugContext
,
6191 "parsed %d templates\n", templates
);
6195 #endif /* else of XSLT_REFACTORED */
6197 #ifdef XSLT_REFACTORED
6199 * xsltParseSimplifiedStylesheetTree:
6201 * @style: the stylesheet (TODO: Change this to the compiler context)
6202 * @doc: the document containing the stylesheet.
6203 * @node: the node where the stylesheet is rooted at
6205 * Returns 0 in case of success, a positive result if an error occurred
6206 * and -1 on API and internal errors.
6209 xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt
,
6213 xsltTemplatePtr templ
;
6215 if ((cctxt
== NULL
) || (node
== NULL
))
6218 if (xsltParseAttrXSLTVersion(cctxt
, node
, 0) == XSLT_ELEMENT_CATEGORY_LRE
)
6221 * TODO: Adjust report, since this might be an
6222 * embedded stylesheet.
6224 xsltTransformError(NULL
, cctxt
->style
, node
,
6225 "The attribute 'xsl:version' is missing; cannot identify "
6226 "this document as an XSLT stylesheet document.\n");
6227 cctxt
->style
->errors
++;
6231 #ifdef WITH_XSLT_DEBUG_PARSING
6232 xsltGenericDebug(xsltGenericDebugContext
,
6233 "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
6237 * Create and link the template
6239 templ
= xsltNewTemplate();
6240 if (templ
== NULL
) {
6243 templ
->next
= cctxt
->style
->templates
;
6244 cctxt
->style
->templates
= templ
;
6245 templ
->match
= xmlStrdup(BAD_CAST
"/");
6248 * Note that we push the document-node in this special case.
6250 xsltCompilerNodePush(cctxt
, (xmlNodePtr
) doc
);
6252 * In every case, we need to have
6253 * the in-scope namespaces of the element, where the
6254 * stylesheet is rooted at, regardless if it's an XSLT
6255 * instruction or a literal result instruction (or if
6256 * this is an embedded stylesheet).
6258 cctxt
->inode
->inScopeNs
=
6259 xsltCompilerBuildInScopeNsList(cctxt
, node
);
6261 * Parse the content and register the match-pattern.
6263 xsltParseSequenceConstructor(cctxt
, node
);
6264 xsltCompilerNodePop(cctxt
, (xmlNodePtr
) doc
);
6266 templ
->elem
= (xmlNodePtr
) doc
;
6267 templ
->content
= node
;
6268 xsltAddTemplate(cctxt
->style
, templ
, NULL
, NULL
);
6269 cctxt
->style
->literal_result
= 1;
6273 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6275 * xsltRestoreDocumentNamespaces:
6276 * @ns: map of namespaces
6277 * @doc: the document
6279 * Restore the namespaces for the document
6281 * Returns 0 in case of success, -1 in case of failure
6284 xsltRestoreDocumentNamespaces(xsltNsMapPtr ns
, xmlDocPtr doc
)
6289 * Revert the changes we have applied to the namespace-URIs of
6292 while (ns
!= NULL
) {
6293 if ((ns
->doc
== doc
) && (ns
->ns
!= NULL
)) {
6294 ns
->ns
->href
= ns
->origNsName
;
6295 ns
->origNsName
= NULL
;
6302 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
6305 * xsltParseStylesheetProcess:
6306 * @style: the XSLT stylesheet (the current stylesheet-level)
6307 * @doc: and xmlDoc parsed XML
6309 * Parses an XSLT stylesheet, adding the associated structures.
6311 * xsltParseStylesheetImportedDoc() (xslt.c)
6312 * xsltParseStylesheetInclude() (imports.c)
6314 * Returns the value of the @style parameter if everything
6315 * went right, NULL if something went amiss.
6318 xsltParseStylesheetProcess(xsltStylesheetPtr style
, xmlDocPtr doc
)
6320 xsltCompilerCtxtPtr cctxt
;
6322 int oldIsSimplifiedStylesheet
;
6326 if ((style
== NULL
) || (doc
== NULL
))
6329 cctxt
= XSLT_CCTXT(style
);
6331 cur
= xmlDocGetRootElement(doc
);
6333 xsltTransformError(NULL
, style
, (xmlNodePtr
) doc
,
6334 "xsltParseStylesheetProcess : empty stylesheet\n");
6337 oldIsSimplifiedStylesheet
= cctxt
->simplified
;
6339 if ((IS_XSLT_ELEM(cur
)) &&
6340 ((IS_XSLT_NAME(cur
, "stylesheet")) ||
6341 (IS_XSLT_NAME(cur
, "transform")))) {
6342 #ifdef WITH_XSLT_DEBUG_PARSING
6343 xsltGenericDebug(xsltGenericDebugContext
,
6344 "xsltParseStylesheetProcess : found stylesheet\n");
6346 cctxt
->simplified
= 0;
6347 style
->literal_result
= 0;
6349 cctxt
->simplified
= 1;
6350 style
->literal_result
= 1;
6353 * Pre-process the stylesheet if not already done before.
6354 * This will remove PIs and comments, merge adjacent
6355 * text nodes, internalize strings, etc.
6357 if (! style
->nopreproc
)
6358 xsltParsePreprocessStylesheetTree(cctxt
, cur
);
6360 * Parse and compile the stylesheet.
6362 if (style
->literal_result
== 0) {
6363 if (xsltParseXSLTStylesheetElem(cctxt
, cur
) != 0)
6366 if (xsltParseSimplifiedStylesheetTree(cctxt
, doc
, cur
) != 0)
6370 cctxt
->simplified
= oldIsSimplifiedStylesheet
;
6375 #else /* XSLT_REFACTORED */
6378 * xsltParseStylesheetProcess:
6379 * @ret: the XSLT stylesheet (the current stylesheet-level)
6380 * @doc: and xmlDoc parsed XML
6382 * Parses an XSLT stylesheet, adding the associated structures.
6384 * xsltParseStylesheetImportedDoc() (xslt.c)
6385 * xsltParseStylesheetInclude() (imports.c)
6387 * Returns the value of the @style parameter if everything
6388 * went right, NULL if something went amiss.
6391 xsltParseStylesheetProcess(xsltStylesheetPtr ret
, xmlDocPtr doc
) {
6402 * First steps, remove blank nodes,
6403 * locate the xsl:stylesheet element and the
6404 * namespace declaration.
6406 cur
= xmlDocGetRootElement(doc
);
6408 xsltTransformError(NULL
, ret
, (xmlNodePtr
) doc
,
6409 "xsltParseStylesheetProcess : empty stylesheet\n");
6413 if ((IS_XSLT_ELEM(cur
)) &&
6414 ((IS_XSLT_NAME(cur
, "stylesheet")) ||
6415 (IS_XSLT_NAME(cur
, "transform")))) {
6416 #ifdef WITH_XSLT_DEBUG_PARSING
6417 xsltGenericDebug(xsltGenericDebugContext
,
6418 "xsltParseStylesheetProcess : found stylesheet\n");
6420 ret
->literal_result
= 0;
6421 xsltParseStylesheetExcludePrefix(ret
, cur
, 1);
6422 xsltParseStylesheetExtPrefix(ret
, cur
, 1);
6424 xsltParseStylesheetExcludePrefix(ret
, cur
, 0);
6425 xsltParseStylesheetExtPrefix(ret
, cur
, 0);
6426 ret
->literal_result
= 1;
6428 if (!ret
->nopreproc
) {
6429 xsltPreprocessStylesheet(ret
, cur
);
6431 if (ret
->literal_result
== 0) {
6432 xsltParseStylesheetTop(ret
, cur
);
6435 xsltTemplatePtr
template;
6438 * the document itself might be the template, check xsl:version
6440 prop
= xmlGetNsProp(cur
, (const xmlChar
*)"version", XSLT_NAMESPACE
);
6442 xsltTransformError(NULL
, ret
, cur
,
6443 "xsltParseStylesheetProcess : document is not a stylesheet\n");
6447 #ifdef WITH_XSLT_DEBUG_PARSING
6448 xsltGenericDebug(xsltGenericDebugContext
,
6449 "xsltParseStylesheetProcess : document is stylesheet\n");
6452 if ((!xmlStrEqual(prop
, (const xmlChar
*)"1.0")) &&
6453 (!xmlStrEqual(prop
, (const xmlChar
*)"1.1"))) {
6454 xsltTransformError(NULL
, ret
, cur
,
6455 "xsl:version: only 1.1 features are supported\n");
6456 ret
->forwards_compatible
= 1;
6462 * Create and link the template
6464 template = xsltNewTemplate();
6465 if (template == NULL
) {
6468 template->next
= ret
->templates
;
6469 ret
->templates
= template;
6470 template->match
= xmlStrdup((const xmlChar
*)"/");
6473 * parse the content and register the pattern
6475 xsltParseTemplateContent(ret
, (xmlNodePtr
) doc
);
6476 template->elem
= (xmlNodePtr
) doc
;
6477 template->content
= doc
->children
;
6478 xsltAddTemplate(ret
, template, NULL
, NULL
);
6479 ret
->literal_result
= 1;
6485 #endif /* else of XSLT_REFACTORED */
6488 * xsltParseStylesheetImportedDoc:
6489 * @doc: an xmlDoc parsed XML
6490 * @parentStyle: pointer to the parent stylesheet (if it exists)
6492 * parse an XSLT stylesheet building the associated structures
6493 * except the processing not needed for imported documents.
6495 * Returns a new XSLT stylesheet structure.
6499 xsltParseStylesheetImportedDoc(xmlDocPtr doc
,
6500 xsltStylesheetPtr parentStyle
) {
6501 xsltStylesheetPtr retStyle
;
6506 retStyle
= xsltNewStylesheet();
6507 if (retStyle
== NULL
)
6510 * Set the importing stylesheet module; also used to detect recursion.
6512 retStyle
->parent
= parentStyle
;
6514 * Adjust the string dict.
6516 if (doc
->dict
!= NULL
) {
6517 xmlDictFree(retStyle
->dict
);
6518 retStyle
->dict
= doc
->dict
;
6519 #ifdef WITH_XSLT_DEBUG
6520 xsltGenericDebug(xsltGenericDebugContext
,
6521 "reusing dictionary from %s for stylesheet\n",
6524 xmlDictReference(retStyle
->dict
);
6528 * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
6529 * the stylesheet to containt distinct namespace prefixes.
6531 xsltGatherNamespaces(retStyle
);
6533 #ifdef XSLT_REFACTORED
6535 xsltCompilerCtxtPtr cctxt
;
6536 xsltStylesheetPtr oldCurSheet
;
6538 if (parentStyle
== NULL
) {
6539 xsltPrincipalStylesheetDataPtr principalData
;
6541 * Principal stylesheet
6542 * --------------------
6544 retStyle
->principal
= retStyle
;
6546 * Create extra data for the principal stylesheet.
6548 principalData
= xsltNewPrincipalStylesheetData();
6549 if (principalData
== NULL
) {
6550 xsltFreeStylesheet(retStyle
);
6553 retStyle
->principalData
= principalData
;
6555 * Create the compilation context
6556 * ------------------------------
6557 * (only once; for the principal stylesheet).
6558 * This is currently the only function where the
6559 * compilation context is created.
6561 cctxt
= xsltCompilationCtxtCreate(retStyle
);
6562 if (cctxt
== NULL
) {
6563 xsltFreeStylesheet(retStyle
);
6566 retStyle
->compCtxt
= (void *) cctxt
;
6567 cctxt
->style
= retStyle
;
6568 cctxt
->dict
= retStyle
->dict
;
6569 cctxt
->psData
= principalData
;
6571 * Push initial dummy node info.
6574 xsltCompilerNodePush(cctxt
, (xmlNodePtr
) doc
);
6577 * Imported stylesheet.
6579 retStyle
->principal
= parentStyle
->principal
;
6580 cctxt
= parentStyle
->compCtxt
;
6581 retStyle
->compCtxt
= cctxt
;
6584 * Save the old and set the current stylesheet structure in the
6585 * compilation context.
6587 oldCurSheet
= cctxt
->style
;
6588 cctxt
->style
= retStyle
;
6590 retStyle
->doc
= doc
;
6591 xsltParseStylesheetProcess(retStyle
, doc
);
6593 cctxt
->style
= oldCurSheet
;
6594 if (parentStyle
== NULL
) {
6596 * Pop the initial dummy node info.
6598 xsltCompilerNodePop(cctxt
, (xmlNodePtr
) doc
);
6601 * Clear the compilation context of imported
6605 /* retStyle->compCtxt = NULL; */
6608 * Free the stylesheet if there were errors.
6610 if (retStyle
!= NULL
) {
6611 if (retStyle
->errors
!= 0) {
6612 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6614 * Restore all changes made to namespace URIs of ns-decls.
6616 if (cctxt
->psData
->nsMap
)
6617 xsltRestoreDocumentNamespaces(cctxt
->psData
->nsMap
, doc
);
6620 * Detach the doc from the stylesheet; otherwise the doc
6621 * will be freed in xsltFreeStylesheet().
6623 retStyle
->doc
= NULL
;
6625 * Cleanup the doc if its the main stylesheet.
6627 if (parentStyle
== NULL
) {
6628 xsltCleanupStylesheetTree(doc
, xmlDocGetRootElement(doc
));
6629 if (retStyle
->compCtxt
!= NULL
) {
6630 xsltCompilationCtxtFree(retStyle
->compCtxt
);
6631 retStyle
->compCtxt
= NULL
;
6635 xsltFreeStylesheet(retStyle
);
6641 #else /* XSLT_REFACTORED */
6645 retStyle
->doc
= doc
;
6646 if (xsltParseStylesheetProcess(retStyle
, doc
) == NULL
) {
6647 retStyle
->doc
= NULL
;
6648 xsltFreeStylesheet(retStyle
);
6651 if (retStyle
!= NULL
) {
6652 if (retStyle
->errors
!= 0) {
6653 retStyle
->doc
= NULL
;
6654 if (parentStyle
== NULL
)
6655 xsltCleanupStylesheetTree(doc
,
6656 xmlDocGetRootElement(doc
));
6657 xsltFreeStylesheet(retStyle
);
6661 #endif /* else of XSLT_REFACTORED */
6667 * xsltParseStylesheetDoc:
6668 * @doc: and xmlDoc parsed XML
6670 * parse an XSLT stylesheet, building the associated structures. doc
6671 * is kept as a reference within the returned stylesheet, so changes
6672 * to doc after the parsing will be reflected when the stylesheet
6673 * is applied, and the doc is automatically freed when the
6674 * stylesheet is closed.
6676 * Returns a new XSLT stylesheet structure.
6680 xsltParseStylesheetDoc(xmlDocPtr doc
) {
6681 xsltStylesheetPtr ret
;
6685 ret
= xsltParseStylesheetImportedDoc(doc
, NULL
);
6689 xsltResolveStylesheetAttributeSet(ret
);
6690 #ifdef XSLT_REFACTORED
6692 * Free the compilation context.
6693 * TODO: Check if it's better to move this cleanup to
6694 * xsltParseStylesheetImportedDoc().
6696 if (ret
->compCtxt
!= NULL
) {
6697 xsltCompilationCtxtFree(XSLT_CCTXT(ret
));
6698 ret
->compCtxt
= NULL
;
6705 * xsltParseStylesheetFile:
6706 * @filename: the filename/URL to the stylesheet
6708 * Load and parse an XSLT stylesheet
6710 * Returns a new XSLT stylesheet structure.
6714 xsltParseStylesheetFile(const xmlChar
* filename
) {
6715 xsltSecurityPrefsPtr sec
;
6716 xsltStylesheetPtr ret
;
6721 if (filename
== NULL
)
6724 #ifdef WITH_XSLT_DEBUG_PARSING
6725 xsltGenericDebug(xsltGenericDebugContext
,
6726 "xsltParseStylesheetFile : parse %s\n", filename
);
6730 * Security framework check
6732 sec
= xsltGetDefaultSecurityPrefs();
6736 res
= xsltCheckRead(sec
, NULL
, filename
);
6738 xsltTransformError(NULL
, NULL
, NULL
,
6739 "xsltParseStylesheetFile: read rights for %s denied\n",
6745 doc
= xsltDocDefaultLoader(filename
, NULL
, XSLT_PARSE_OPTIONS
,
6746 NULL
, XSLT_LOAD_START
);
6748 xsltTransformError(NULL
, NULL
, NULL
,
6749 "xsltParseStylesheetFile : cannot parse %s\n", filename
);
6752 ret
= xsltParseStylesheetDoc(doc
);
6761 /************************************************************************
6763 * Handling of Stylesheet PI *
6765 ************************************************************************/
6768 #define SKIP(val) cur += (val)
6769 #define NXT(val) cur[(val)]
6770 #define SKIP_BLANKS \
6771 while (IS_BLANK(CUR)) NEXT
6772 #define NEXT ((*cur) ? cur++ : cur)
6775 * xsltParseStylesheetPI:
6776 * @value: the value of the PI
6778 * This function checks that the type is text/xml and extracts
6779 * the URI-Reference for the stylesheet
6781 * Returns the URI-Reference for the stylesheet or NULL (it need to
6782 * be freed by the caller)
6785 xsltParseStylesheetPI(const xmlChar
*value
) {
6787 const xmlChar
*start
;
6790 xmlChar
*href
= NULL
;
6799 if ((CUR
== 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
6806 if ((CUR
!= '\'') && (CUR
!= '"'))
6811 while ((CUR
!= 0) && (CUR
!= tmp
))
6815 val
= xmlStrndup(start
, cur
- start
);
6819 if ((xmlStrcasecmp(val
, BAD_CAST
"text/xml")) &&
6820 (xmlStrcasecmp(val
, BAD_CAST
"text/xsl"))) {
6826 } else if ((CUR
== 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
6833 if ((CUR
!= '\'') && (CUR
!= '"'))
6838 while ((CUR
!= 0) && (CUR
!= tmp
))
6843 href
= xmlStrndup(start
, cur
- start
);
6846 while ((CUR
!= 0) && (!IS_BLANK(CUR
)))
6861 * xsltLoadStylesheetPI:
6862 * @doc: a document to process
6864 * This function tries to locate the stylesheet PI in the given document
6865 * If found, and if contained within the document, it will extract
6866 * that subtree to build the stylesheet to process @doc (doc itself will
6867 * be modified). If found but referencing an external document it will
6868 * attempt to load it and generate a stylesheet from it. In both cases,
6869 * the resulting stylesheet and the document need to be freed once the
6870 * transformation is done.
6872 * Returns a new XSLT stylesheet structure or NULL if not found.
6875 xsltLoadStylesheetPI(xmlDocPtr doc
) {
6877 xsltStylesheetPtr ret
= NULL
;
6878 xmlChar
*href
= NULL
;
6887 * Find the text/xml stylesheet PI id any before the root
6889 child
= doc
->children
;
6890 while ((child
!= NULL
) && (child
->type
!= XML_ELEMENT_NODE
)) {
6891 if ((child
->type
== XML_PI_NODE
) &&
6892 (xmlStrEqual(child
->name
, BAD_CAST
"xml-stylesheet"))) {
6893 href
= xsltParseStylesheetPI(child
->content
);
6897 child
= child
->next
;
6901 * If found check the href to select processing
6904 #ifdef WITH_XSLT_DEBUG_PARSING
6905 xsltGenericDebug(xsltGenericDebugContext
,
6906 "xsltLoadStylesheetPI : found PI href=%s\n", href
);
6908 URI
= xmlParseURI((const char *) href
);
6910 xsltTransformError(NULL
, NULL
, child
,
6911 "xml-stylesheet : href %s is not valid\n", href
);
6915 if ((URI
->fragment
!= NULL
) && (URI
->scheme
== NULL
) &&
6916 (URI
->opaque
== NULL
) && (URI
->authority
== NULL
) &&
6917 (URI
->server
== NULL
) && (URI
->user
== NULL
) &&
6918 (URI
->path
== NULL
) && (URI
->query
== NULL
)) {
6921 #ifdef WITH_XSLT_DEBUG_PARSING
6922 xsltGenericDebug(xsltGenericDebugContext
,
6923 "xsltLoadStylesheetPI : Reference to ID %s\n", href
);
6925 if (URI
->fragment
[0] == '#')
6926 ID
= xmlGetID(doc
, (const xmlChar
*) &(URI
->fragment
[1]));
6928 ID
= xmlGetID(doc
, (const xmlChar
*) URI
->fragment
);
6930 xsltTransformError(NULL
, NULL
, child
,
6931 "xml-stylesheet : no ID %s found\n", URI
->fragment
);
6934 xmlNodePtr subtree
, newtree
;
6937 #ifdef WITH_XSLT_DEBUG
6938 xsltGenericDebug(xsltGenericDebugContext
,
6939 "creating new document from %s for embedded stylesheet\n",
6943 * move the subtree in a new document passed to
6944 * the stylesheet analyzer
6946 subtree
= ID
->parent
;
6947 fake
= xmlNewDoc(NULL
);
6950 * Should the dictionary still be shared even though
6951 * the nodes are being copied rather than moved?
6953 fake
->dict
= doc
->dict
;
6954 xmlDictReference(doc
->dict
);
6955 #ifdef WITH_XSLT_DEBUG
6956 xsltGenericDebug(xsltGenericDebugContext
,
6957 "reusing dictionary from %s for embedded stylesheet\n",
6961 newtree
= xmlDocCopyNode(subtree
, fake
, 1);
6963 fake
->URL
= xmlNodeGetBase(doc
, subtree
->parent
);
6964 #ifdef WITH_XSLT_DEBUG
6965 xsltGenericDebug(xsltGenericDebugContext
,
6966 "set base URI for embedded stylesheet as %s\n",
6971 * Add all namespaces in scope of embedded stylesheet to
6972 * root element of newly created stylesheet document
6974 while ((subtree
= subtree
->parent
) != (xmlNodePtr
)doc
) {
6975 for (ns
= subtree
->ns
; ns
; ns
= ns
->next
) {
6976 xmlNewNs(newtree
, ns
->href
, ns
->prefix
);
6980 xmlAddChild((xmlNodePtr
)fake
, newtree
);
6981 ret
= xsltParseStylesheetDoc(fake
);
6987 xmlChar
*URL
, *base
;
6990 * Reference to an external stylesheet
6993 base
= xmlNodeGetBase(doc
, (xmlNodePtr
) doc
);
6994 URL
= xmlBuildURI(href
, base
);
6996 #ifdef WITH_XSLT_DEBUG_PARSING
6997 xsltGenericDebug(xsltGenericDebugContext
,
6998 "xsltLoadStylesheetPI : fetching %s\n", URL
);
7000 ret
= xsltParseStylesheetFile(URL
);
7003 #ifdef WITH_XSLT_DEBUG_PARSING
7004 xsltGenericDebug(xsltGenericDebugContext
,
7005 "xsltLoadStylesheetPI : fetching %s\n", href
);
7007 ret
= xsltParseStylesheetFile(href
);