2 * transform.c: Implementation of the XSL Transformation 1.0 engine
3 * transform part, i.e. applying a Stylesheet to a document
6 * http://www.w3.org/TR/1999/REC-xslt-19991116
8 * Michael Kay "XSLT Programmer's Reference" pp 637-643
9 * Writing Multiple Output Files
11 * XSLT-1.1 Working Draft
12 * http://www.w3.org/TR/xslt11#multiple-output
14 * See Copyright for the status of this software.
24 #include <libxml/xmlmemory.h>
25 #include <libxml/parser.h>
26 #include <libxml/tree.h>
27 #include <libxml/valid.h>
28 #include <libxml/hash.h>
29 #include <libxml/encoding.h>
30 #include <libxml/xmlerror.h>
31 #include <libxml/xpath.h>
32 #include <libxml/parserInternals.h>
33 #include <libxml/xpathInternals.h>
34 #include <libxml/HTMLtree.h>
35 #include <libxml/debugXML.h>
36 #include <libxml/uri.h>
38 #include "xsltInternals.h"
39 #include "xsltutils.h"
41 #include "transform.h"
42 #include "variables.h"
43 #include "numbersInternals.h"
44 #include "namespaces.h"
45 #include "attributes.h"
46 #include "templates.h"
49 #include "documents.h"
50 #include "extensions.h"
55 #ifdef WITH_XSLT_DEBUG
56 #define WITH_XSLT_DEBUG_EXTRA
57 #define WITH_XSLT_DEBUG_PROCESS
60 #define XSLT_GENERATE_HTML_DOCTYPE
61 #ifdef XSLT_GENERATE_HTML_DOCTYPE
62 static int xsltGetHTMLIDs(const xmlChar
*version
, const xmlChar
**publicID
,
63 const xmlChar
**systemID
);
66 int xsltMaxDepth
= 3000;
73 # define FALSE (0 == 1)
74 # define TRUE (!FALSE)
77 #define IS_BLANK_NODE(n) \
78 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
82 * Forward declarations
86 xsltCopyNamespaceListInternal(xmlNodePtr node
, xmlNsPtr cur
);
89 xsltCopyTreeInternal(xsltTransformContextPtr ctxt
,
92 xmlNodePtr insert
, int isLRE
, int topElemVisited
);
95 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt
,
96 xmlNodePtr contextNode
, xmlNodePtr list
,
97 xsltTemplatePtr templ
);
100 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt
,
101 xmlNodePtr contextNode
,
103 xsltTemplatePtr templ
,
104 xsltStackElemPtr withParams
);
108 * @ctxt: the transformation context
109 * @value: the template to push on the stack
111 * Push a template on the stack
113 * Returns the new index in the stack or 0 in case of error
116 templPush(xsltTransformContextPtr ctxt
, xsltTemplatePtr value
)
118 if (ctxt
->templMax
== 0) {
121 (xsltTemplatePtr
*) xmlMalloc(ctxt
->templMax
*
122 sizeof(ctxt
->templTab
[0]));
123 if (ctxt
->templTab
== NULL
) {
124 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
128 if (ctxt
->templNr
>= ctxt
->templMax
) {
131 (xsltTemplatePtr
*) xmlRealloc(ctxt
->templTab
,
133 sizeof(ctxt
->templTab
[0]));
134 if (ctxt
->templTab
== NULL
) {
135 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
139 ctxt
->templTab
[ctxt
->templNr
] = value
;
141 return (ctxt
->templNr
++);
145 * @ctxt: the transformation context
147 * Pop a template value from the stack
149 * Returns the stored template value
151 static xsltTemplatePtr
152 templPop(xsltTransformContextPtr ctxt
)
156 if (ctxt
->templNr
<= 0)
159 if (ctxt
->templNr
> 0)
160 ctxt
->templ
= ctxt
->templTab
[ctxt
->templNr
- 1];
162 ctxt
->templ
= (xsltTemplatePtr
) 0;
163 ret
= ctxt
->templTab
[ctxt
->templNr
];
164 ctxt
->templTab
[ctxt
->templNr
] = 0;
169 * xsltLocalVariablePop:
170 * @ctxt: the transformation context
171 * @limitNr: number of variables which should remain
172 * @level: the depth in the xsl:template's tree
174 * Pops all variable values at the given @depth from the stack.
176 * Returns the stored variable value
178 * This is an internal routine and should not be called by users!
181 xsltLocalVariablePop(xsltTransformContextPtr ctxt
, int limitNr
, int level
)
183 xsltStackElemPtr variable
;
185 if (ctxt
->varsNr
<= 0)
189 if (ctxt
->varsNr
<= limitNr
)
191 variable
= ctxt
->varsTab
[ctxt
->varsNr
- 1];
192 if (variable
->level
<= level
)
194 if (variable
->level
>= 0)
195 xsltFreeStackElemList(variable
);
197 } while (ctxt
->varsNr
!= 0);
198 if (ctxt
->varsNr
> 0)
199 ctxt
->vars
= ctxt
->varsTab
[ctxt
->varsNr
- 1];
205 * xsltTemplateParamsCleanup:
207 * Removes xsl:param and xsl:with-param items from the
208 * variable-stack. Only xsl:with-param items are not freed.
211 xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt
)
213 xsltStackElemPtr param
;
215 for (; ctxt
->varsNr
> ctxt
->varsBase
; ctxt
->varsNr
--) {
216 param
= ctxt
->varsTab
[ctxt
->varsNr
-1];
218 * Free xsl:param items.
219 * xsl:with-param items will have a level of -1 or -2.
221 if (param
->level
>= 0) {
222 xsltFreeStackElemList(param
);
225 if (ctxt
->varsNr
> 0)
226 ctxt
->vars
= ctxt
->varsTab
[ctxt
->varsNr
- 1];
233 * @ctxt: the transformation context
234 * @value: the profiling value to push on the stack
236 * Push a profiling value on the stack
238 * Returns the new index in the stack or 0 in case of error
241 profPush(xsltTransformContextPtr ctxt
, long value
)
243 if (ctxt
->profMax
== 0) {
246 (long *) xmlMalloc(ctxt
->profMax
* sizeof(ctxt
->profTab
[0]));
247 if (ctxt
->profTab
== NULL
) {
248 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
252 if (ctxt
->profNr
>= ctxt
->profMax
) {
255 (long *) xmlRealloc(ctxt
->profTab
,
256 ctxt
->profMax
* sizeof(ctxt
->profTab
[0]));
257 if (ctxt
->profTab
== NULL
) {
258 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
262 ctxt
->profTab
[ctxt
->profNr
] = value
;
264 return (ctxt
->profNr
++);
268 * @ctxt: the transformation context
270 * Pop a profiling value from the stack
272 * Returns the stored profiling value
275 profPop(xsltTransformContextPtr ctxt
)
279 if (ctxt
->profNr
<= 0)
282 if (ctxt
->profNr
> 0)
283 ctxt
->prof
= ctxt
->profTab
[ctxt
->profNr
- 1];
285 ctxt
->prof
= (long) 0;
286 ret
= ctxt
->profTab
[ctxt
->profNr
];
287 ctxt
->profTab
[ctxt
->profNr
] = 0;
291 /************************************************************************
293 * XInclude default settings *
295 ************************************************************************/
297 static int xsltDoXIncludeDefault
= 0;
300 * xsltSetXIncludeDefault:
301 * @xinclude: whether to do XInclude processing
303 * Set whether XInclude should be processed on document being loaded by default
306 xsltSetXIncludeDefault(int xinclude
) {
307 xsltDoXIncludeDefault
= (xinclude
!= 0);
311 * xsltGetXIncludeDefault:
313 * Provides the default state for XInclude processing
315 * Returns 0 if there is no processing 1 otherwise
318 xsltGetXIncludeDefault(void) {
319 return(xsltDoXIncludeDefault
);
322 unsigned long xsltDefaultTrace
= (unsigned long) XSLT_TRACE_ALL
;
325 * xsltDebugSetDefaultTrace:
326 * @val: tracing level mask
328 * Set the default debug tracing level mask
330 void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val
) {
331 xsltDefaultTrace
= val
;
335 * xsltDebugGetDefaultTrace:
337 * Get the current default debug tracing level mask
339 * Returns the current default debug tracing level mask
341 xsltDebugTraceCodes
xsltDebugGetDefaultTrace() {
342 return xsltDefaultTrace
;
345 /************************************************************************
347 * Handling of Transformation Contexts *
349 ************************************************************************/
351 static xsltTransformCachePtr
352 xsltTransformCacheCreate(void)
354 xsltTransformCachePtr ret
;
356 ret
= (xsltTransformCachePtr
) xmlMalloc(sizeof(xsltTransformCache
));
358 xsltTransformError(NULL
, NULL
, NULL
,
359 "xsltTransformCacheCreate : malloc failed\n");
362 memset(ret
, 0, sizeof(xsltTransformCache
));
367 xsltTransformCacheFree(xsltTransformCachePtr cache
)
372 * Free tree fragments.
375 xmlDocPtr tmp
, cur
= cache
->RVT
;
378 cur
= (xmlDocPtr
) cur
->next
;
379 if (tmp
->_private
!= NULL
) {
381 * Tree the document info.
383 xsltFreeDocumentKeys((xsltDocumentPtr
) tmp
->_private
);
384 xmlFree(tmp
->_private
);
392 if (cache
->stackItems
) {
393 xsltStackElemPtr tmp
, cur
= cache
->stackItems
;
398 * REVISIT TODO: Should be call a destruction-function
408 * xsltNewTransformContext:
409 * @style: a parsed XSLT stylesheet
410 * @doc: the input document
412 * Create a new XSLT TransformContext
414 * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
416 xsltTransformContextPtr
417 xsltNewTransformContext(xsltStylesheetPtr style
, xmlDocPtr doc
) {
418 xsltTransformContextPtr cur
;
419 xsltDocumentPtr docu
;
424 cur
= (xsltTransformContextPtr
) xmlMalloc(sizeof(xsltTransformContext
));
426 xsltTransformError(NULL
, NULL
, (xmlNodePtr
)doc
,
427 "xsltNewTransformContext : malloc failed\n");
430 memset(cur
, 0, sizeof(xsltTransformContext
));
432 cur
->cache
= xsltTransformCacheCreate();
433 if (cur
->cache
== NULL
)
436 * setup of the dictionary must be done early as some of the
437 * processing later like key handling may need it.
439 cur
->dict
= xmlDictCreateSub(style
->dict
);
440 cur
->internalized
= ((style
->internalized
) && (cur
->dict
!= NULL
));
441 #ifdef WITH_XSLT_DEBUG
442 xsltGenericDebug(xsltGenericDebugContext
,
443 "Creating sub-dictionary from stylesheet for transformation\n");
447 * initialize the template stack
449 cur
->templTab
= (xsltTemplatePtr
*)
450 xmlMalloc(10 * sizeof(xsltTemplatePtr
));
451 if (cur
->templTab
== NULL
) {
452 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
453 "xsltNewTransformContext: out of memory\n");
461 * initialize the variables stack
463 cur
->varsTab
= (xsltStackElemPtr
*)
464 xmlMalloc(10 * sizeof(xsltStackElemPtr
));
465 if (cur
->varsTab
== NULL
) {
466 xmlGenericError(xmlGenericErrorContext
,
467 "xsltNewTransformContext: out of memory\n");
476 * the profiling stack is not initialized by default
485 cur
->xpathCtxt
= xmlXPathNewContext(doc
);
486 if (cur
->xpathCtxt
== NULL
) {
487 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
488 "xsltNewTransformContext : xmlXPathNewContext failed\n");
492 * Create an XPath cache.
494 if (xmlXPathContextSetCache(cur
->xpathCtxt
, 1, -1, 0) == -1)
497 * Initialize the extras array
499 if (style
->extrasNr
!= 0) {
500 cur
->extrasMax
= style
->extrasNr
+ 20;
501 cur
->extras
= (xsltRuntimeExtraPtr
)
502 xmlMalloc(cur
->extrasMax
* sizeof(xsltRuntimeExtra
));
503 if (cur
->extras
== NULL
) {
504 xmlGenericError(xmlGenericErrorContext
,
505 "xsltNewTransformContext: out of memory\n");
508 cur
->extrasNr
= style
->extrasNr
;
509 for (i
= 0;i
< cur
->extrasMax
;i
++) {
510 cur
->extras
[i
].info
= NULL
;
511 cur
->extras
[i
].deallocate
= NULL
;
512 cur
->extras
[i
].val
.ptr
= NULL
;
520 XSLT_REGISTER_VARIABLE_LOOKUP(cur
);
521 XSLT_REGISTER_FUNCTION_LOOKUP(cur
);
522 cur
->xpathCtxt
->nsHash
= style
->nsHash
;
524 * Initialize the registered external modules
526 xsltInitCtxtExts(cur
);
528 * Setup document element ordering for later efficiencies
531 if (xslDebugStatus
== XSLT_DEBUG_NONE
)
532 xmlXPathOrderDocElems(doc
);
534 * Must set parserOptions before calling xsltNewDocument
537 cur
->parserOptions
= XSLT_PARSE_OPTIONS
;
538 docu
= xsltNewDocument(cur
, doc
);
540 xsltTransformError(cur
, NULL
, (xmlNodePtr
)doc
,
541 "xsltNewTransformContext : xsltNewDocument failed\n");
545 cur
->document
= docu
;
547 cur
->outputFile
= NULL
;
548 cur
->sec
= xsltGetDefaultSecurityPrefs();
549 cur
->debugStatus
= xslDebugStatus
;
550 cur
->traceCode
= (unsigned long*) &xsltDefaultTrace
;
551 cur
->xinclude
= xsltGetXIncludeDefault();
552 cur
->keyInitLevel
= 0;
558 xsltFreeTransformContext(cur
);
563 * xsltFreeTransformContext:
564 * @ctxt: an XSLT parser context
566 * Free up the memory allocated by @ctxt
569 xsltFreeTransformContext(xsltTransformContextPtr ctxt
) {
574 * Shutdown the extension modules associated to the stylesheet
577 xsltShutdownCtxtExts(ctxt
);
579 if (ctxt
->xpathCtxt
!= NULL
) {
580 ctxt
->xpathCtxt
->nsHash
= NULL
;
581 xmlXPathFreeContext(ctxt
->xpathCtxt
);
583 if (ctxt
->templTab
!= NULL
)
584 xmlFree(ctxt
->templTab
);
585 if (ctxt
->varsTab
!= NULL
)
586 xmlFree(ctxt
->varsTab
);
587 if (ctxt
->profTab
!= NULL
)
588 xmlFree(ctxt
->profTab
);
589 if ((ctxt
->extrasNr
> 0) && (ctxt
->extras
!= NULL
)) {
592 for (i
= 0;i
< ctxt
->extrasNr
;i
++) {
593 if ((ctxt
->extras
[i
].deallocate
!= NULL
) &&
594 (ctxt
->extras
[i
].info
!= NULL
))
595 ctxt
->extras
[i
].deallocate(ctxt
->extras
[i
].info
);
597 xmlFree(ctxt
->extras
);
599 xsltFreeGlobalVariables(ctxt
);
600 xsltFreeDocuments(ctxt
);
601 xsltFreeCtxtExts(ctxt
);
603 xsltTransformCacheFree(ctxt
->cache
);
604 xmlDictFree(ctxt
->dict
);
605 #ifdef WITH_XSLT_DEBUG
606 xsltGenericDebug(xsltGenericDebugContext
,
607 "freeing transformation dictionary\n");
609 memset(ctxt
, -1, sizeof(xsltTransformContext
));
613 /************************************************************************
615 * Copy of Nodes in an XSLT fashion *
617 ************************************************************************/
619 xmlNodePtr
xsltCopyTree(xsltTransformContextPtr ctxt
,
620 xmlNodePtr node
, xmlNodePtr insert
, int literal
);
624 * @parent: the parent node
625 * @cur: the child node
627 * Wrapper version of xmlAddChild with a more consistent behaviour on
628 * error. One expect the use to be child = xsltAddChild(parent, child);
629 * and the routine will take care of not leaking on errors or node merge
631 * Returns the child is successfully attached or NULL if merged or freed
634 xsltAddChild(xmlNodePtr parent
, xmlNodePtr cur
) {
637 if ((cur
== NULL
) || (parent
== NULL
))
639 if (parent
== NULL
) {
643 ret
= xmlAddChild(parent
, cur
);
650 * @ctxt: a XSLT process context
651 * @target: the text node where the text will be attached
652 * @string: the text string
653 * @len: the string length in byte
655 * Extend the current text node with the new string, it handles coalescing
657 * Returns: the text node
660 xsltAddTextString(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
661 const xmlChar
*string
, int len
) {
665 if ((len
<= 0) || (string
== NULL
) || (target
== NULL
))
668 if (ctxt
->lasttext
== target
->content
) {
670 if (ctxt
->lasttuse
+ len
>= ctxt
->lasttsize
) {
674 size
= ctxt
->lasttsize
+ len
+ 100;
676 newbuf
= (xmlChar
*) xmlRealloc(target
->content
,size
);
677 if (newbuf
== NULL
) {
678 xsltTransformError(ctxt
, NULL
, target
,
679 "xsltCopyText: text allocation failed\n");
682 ctxt
->lasttsize
= size
;
683 ctxt
->lasttext
= newbuf
;
684 target
->content
= newbuf
;
686 memcpy(&(target
->content
[ctxt
->lasttuse
]), string
, len
);
687 ctxt
->lasttuse
+= len
;
688 target
->content
[ctxt
->lasttuse
] = 0;
690 xmlNodeAddContent(target
, string
);
691 ctxt
->lasttext
= target
->content
;
692 len
= xmlStrlen(target
->content
);
693 ctxt
->lasttsize
= len
;
694 ctxt
->lasttuse
= len
;
700 * xsltCopyTextString:
701 * @ctxt: a XSLT process context
702 * @target: the element where the text will be attached
703 * @string: the text string
704 * @noescape: should disable-escaping be activated for this text node.
706 * Adds @string to a newly created or an existent text node child of
709 * Returns: the text node, where the text content of @cur is copied to.
710 * NULL in case of API or internal errors.
713 xsltCopyTextString(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
714 const xmlChar
*string
, int noescape
)
722 #ifdef WITH_XSLT_DEBUG_PROCESS
723 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
724 "xsltCopyTextString: copy text %s\n",
729 * Play save and reset the merging mechanism for every new
732 if ((target
== NULL
) || (target
->children
== NULL
)) {
733 ctxt
->lasttext
= NULL
;
736 /* handle coalescing of text nodes here */
737 len
= xmlStrlen(string
);
738 if ((ctxt
->type
== XSLT_OUTPUT_XML
) &&
739 (ctxt
->style
->cdataSection
!= NULL
) &&
741 (target
->type
== XML_ELEMENT_NODE
) &&
742 (((target
->ns
== NULL
) &&
743 (xmlHashLookup2(ctxt
->style
->cdataSection
,
744 target
->name
, NULL
) != NULL
)) ||
745 ((target
->ns
!= NULL
) &&
746 (xmlHashLookup2(ctxt
->style
->cdataSection
,
747 target
->name
, target
->ns
->href
) != NULL
))))
750 * Process "cdata-section-elements".
752 if ((target
->last
!= NULL
) &&
753 (target
->last
->type
== XML_CDATA_SECTION_NODE
))
755 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
757 copy
= xmlNewCDataBlock(ctxt
->output
, string
, len
);
758 } else if (noescape
) {
760 * Process "disable-output-escaping".
762 if ((target
!= NULL
) && (target
->last
!= NULL
) &&
763 (target
->last
->type
== XML_TEXT_NODE
) &&
764 (target
->last
->name
== xmlStringTextNoenc
))
766 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
768 copy
= xmlNewTextLen(string
, len
);
770 copy
->name
= xmlStringTextNoenc
;
773 * Default processing.
775 if ((target
!= NULL
) && (target
->last
!= NULL
) &&
776 (target
->last
->type
== XML_TEXT_NODE
) &&
777 (target
->last
->name
== xmlStringText
)) {
778 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
780 copy
= xmlNewTextLen(string
, len
);
784 copy
= xsltAddChild(target
, copy
);
785 ctxt
->lasttext
= copy
->content
;
786 ctxt
->lasttsize
= len
;
787 ctxt
->lasttuse
= len
;
789 xsltTransformError(ctxt
, NULL
, target
,
790 "xsltCopyTextString: text copy failed\n");
791 ctxt
->lasttext
= NULL
;
798 * @ctxt: a XSLT process context
799 * @target: the element where the text will be attached
800 * @cur: the text or CDATA node
801 * @interned: the string is in the target doc dictionary
803 * Copy the text content of @cur and append it to @target's children.
805 * Returns: the text node, where the text content of @cur is copied to.
806 * NULL in case of API or internal errors.
809 xsltCopyText(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
810 xmlNodePtr cur
, int interned
)
814 if ((cur
->type
!= XML_TEXT_NODE
) &&
815 (cur
->type
!= XML_CDATA_SECTION_NODE
))
817 if (cur
->content
== NULL
)
820 #ifdef WITH_XSLT_DEBUG_PROCESS
821 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
822 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
823 "xsltCopyText: copy CDATA text %s\n",
825 } else if (cur
->name
== xmlStringTextNoenc
) {
826 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
827 "xsltCopyText: copy unescaped text %s\n",
830 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
831 "xsltCopyText: copy text %s\n",
837 * Play save and reset the merging mechanism for every new
840 if ((target
== NULL
) || (target
->children
== NULL
)) {
841 ctxt
->lasttext
= NULL
;
844 if ((ctxt
->style
->cdataSection
!= NULL
) &&
845 (ctxt
->type
== XSLT_OUTPUT_XML
) &&
847 (target
->type
== XML_ELEMENT_NODE
) &&
848 (((target
->ns
== NULL
) &&
849 (xmlHashLookup2(ctxt
->style
->cdataSection
,
850 target
->name
, NULL
) != NULL
)) ||
851 ((target
->ns
!= NULL
) &&
852 (xmlHashLookup2(ctxt
->style
->cdataSection
,
853 target
->name
, target
->ns
->href
) != NULL
))))
856 * Process "cdata-section-elements".
859 * OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
862 * TODO: Since this doesn't merge adjacent CDATA-section nodes,
863 * we'll get: <![CDATA[x]]><!CDATA[y]]>.
864 * TODO: Reported in #321505.
866 if ((target
->last
!= NULL
) &&
867 (target
->last
->type
== XML_CDATA_SECTION_NODE
))
870 * Append to existing CDATA-section node.
872 copy
= xsltAddTextString(ctxt
, target
->last
, cur
->content
,
873 xmlStrlen(cur
->content
));
878 len
= xmlStrlen(cur
->content
);
879 copy
= xmlNewCDataBlock(ctxt
->output
, cur
->content
, len
);
882 ctxt
->lasttext
= copy
->content
;
883 ctxt
->lasttsize
= len
;
884 ctxt
->lasttuse
= len
;
886 } else if ((target
!= NULL
) &&
887 (target
->last
!= NULL
) &&
888 /* both escaped or both non-escaped text-nodes */
889 (((target
->last
->type
== XML_TEXT_NODE
) &&
890 (target
->last
->name
== cur
->name
)) ||
891 /* non-escaped text nodes and CDATA-section nodes */
892 (((target
->last
->type
== XML_CDATA_SECTION_NODE
) &&
893 (cur
->name
== xmlStringTextNoenc
)))))
896 * we are appending to an existing text node
898 copy
= xsltAddTextString(ctxt
, target
->last
, cur
->content
,
899 xmlStrlen(cur
->content
));
901 } else if ((interned
) && (target
!= NULL
) &&
902 (target
->doc
!= NULL
) &&
903 (target
->doc
->dict
== ctxt
->dict
))
906 * TODO: DO we want to use this also for "text" output?
908 copy
= xmlNewTextLen(NULL
, 0);
911 if (cur
->name
== xmlStringTextNoenc
)
912 copy
->name
= xmlStringTextNoenc
;
915 * Must confirm that content is in dict (bug 302821)
916 * TODO: This check should be not needed for text coming
917 * from the stylesheets
919 if (xmlDictOwns(ctxt
->dict
, cur
->content
))
920 copy
->content
= cur
->content
;
922 if ((copy
->content
= xmlStrdup(cur
->content
)) == NULL
)
927 * normal processing. keep counters to extend the text node
928 * in xsltAddTextString if needed.
932 len
= xmlStrlen(cur
->content
);
933 copy
= xmlNewTextLen(cur
->content
, len
);
936 if (cur
->name
== xmlStringTextNoenc
)
937 copy
->name
= xmlStringTextNoenc
;
938 ctxt
->lasttext
= copy
->content
;
939 ctxt
->lasttsize
= len
;
940 ctxt
->lasttuse
= len
;
943 if (target
!= NULL
) {
944 copy
->doc
= target
->doc
;
946 * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
947 * to ensure that the optimized text-merging mechanism
948 * won't interfere with normal node-merging in any case.
950 copy
= xsltAddChild(target
, copy
);
953 xsltTransformError(ctxt
, NULL
, target
,
954 "xsltCopyText: text copy failed\n");
958 if ((copy
== NULL
) || (copy
->content
== NULL
)) {
959 xsltTransformError(ctxt
, NULL
, target
,
960 "Internal error in xsltCopyText(): "
961 "Failed to copy the string.\n");
962 ctxt
->state
= XSLT_STATE_STOPPED
;
968 * xsltShallowCopyAttr:
969 * @ctxt: a XSLT process context
970 * @invocNode: responsible node in the stylesheet; used for error reports
971 * @target: the element where the attribute will be grafted
972 * @attr: the attribute to be copied
974 * Do a copy of an attribute.
976 * - xsltCopyTreeInternal()
980 * Returns: a new xmlAttrPtr, or NULL in case of error.
983 xsltShallowCopyAttr(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
984 xmlNodePtr target
, xmlAttrPtr attr
)
992 if (target
->type
!= XML_ELEMENT_NODE
) {
993 xsltTransformError(ctxt
, NULL
, invocNode
,
994 "Cannot add an attribute node to a non-element node.\n");
998 if (target
->children
!= NULL
) {
999 xsltTransformError(ctxt
, NULL
, invocNode
,
1000 "Attribute nodes must be added before "
1001 "any child nodes to an element.\n");
1005 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1006 if (attr
->ns
!= NULL
) {
1009 ns
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1010 attr
->ns
->href
, attr
->ns
->prefix
, target
);
1012 xsltTransformError(ctxt
, NULL
, invocNode
,
1013 "Namespace fixup error: Failed to acquire an in-scope "
1014 "namespace binding of the copied attribute '{%s}%s'.\n",
1015 attr
->ns
->href
, attr
->name
);
1017 * TODO: Should we just stop here?
1021 * Note that xmlSetNsProp() will take care of duplicates
1022 * and assigns the new namespace even to a duplicate.
1024 copy
= xmlSetNsProp(target
, ns
, attr
->name
, value
);
1026 copy
= xmlSetNsProp(target
, NULL
, attr
->name
, value
);
1036 * NOTE: This was optimized according to bug #342695.
1037 * TODO: Can this further be optimized, if source and target
1038 * share the same dict and attr->children is just 1 text node
1039 * which is in the dict? How probable is such a case?
1042 * TODO: Do we need to create an empty text node if the value
1043 * is the empty string?
1045 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1046 if (value
!= NULL
) {
1047 txtNode
= xmlNewDocText(target
->doc
, NULL
);
1048 if (txtNode
== NULL
)
1050 if ((target
->doc
!= NULL
) &&
1051 (target
->doc
->dict
!= NULL
))
1054 (xmlChar
*) xmlDictLookup(target
->doc
->dict
,
1055 BAD_CAST value
, -1);
1058 txtNode
->content
= value
;
1059 copy
->children
= txtNode
;
1067 * xsltCopyAttrListNoOverwrite:
1068 * @ctxt: a XSLT process context
1069 * @invocNode: responsible node in the stylesheet; used for error reports
1070 * @target: the element where the new attributes will be grafted
1071 * @attr: the first attribute in the list to be copied
1073 * Copies a list of attribute nodes, starting with @attr, over to the
1074 * @target element node.
1077 * - xsltCopyTreeInternal()
1079 * Returns 0 on success and -1 on errors and internal errors.
1082 xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt
,
1083 xmlNodePtr invocNode
,
1084 xmlNodePtr target
, xmlAttrPtr attr
)
1087 xmlNsPtr origNs
= NULL
, copyNs
= NULL
;
1091 * Don't use xmlCopyProp() here, since it will try to
1092 * reconciliate namespaces.
1094 while (attr
!= NULL
) {
1096 * Find a namespace node in the tree of @target.
1097 * Avoid searching for the same ns.
1099 if (attr
->ns
!= origNs
) {
1101 if (attr
->ns
!= NULL
) {
1102 copyNs
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1103 attr
->ns
->href
, attr
->ns
->prefix
, target
);
1110 * If attribute has a value, we need to copy it (watching out
1111 * for possible entities)
1113 if ((attr
->children
) && (attr
->children
->type
== XML_TEXT_NODE
) &&
1114 (attr
->children
->next
== NULL
)) {
1115 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
,
1116 attr
->children
->content
);
1117 } else if (attr
->children
!= NULL
) {
1118 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1119 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
, BAD_CAST value
);
1122 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
, NULL
);
1134 * xsltShallowCopyElem:
1135 * @ctxt: the XSLT process context
1136 * @node: the element node in the source tree
1137 * or the Literal Result Element
1138 * @insert: the parent in the result tree
1139 * @isLRE: if @node is a Literal Result Element
1141 * Make a copy of the element node @node
1142 * and insert it as last child of @insert.
1144 * URGENT TODO: The problem with this one (for the non-refactored code)
1145 * is that it is used for both, Literal Result Elements *and*
1146 * copying input nodes.
1148 * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
1151 * xsltApplySequenceConstructor()
1152 * (for Literal Result Elements - which is a problem)
1153 * xsltCopy() (for shallow-copying elements via xsl:copy)
1155 * Returns a pointer to the new node, or NULL in case of error
1158 xsltShallowCopyElem(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1159 xmlNodePtr insert
, int isLRE
)
1163 if ((node
->type
== XML_DTD_NODE
) || (insert
== NULL
))
1165 if ((node
->type
== XML_TEXT_NODE
) ||
1166 (node
->type
== XML_CDATA_SECTION_NODE
))
1167 return(xsltCopyText(ctxt
, insert
, node
, 0));
1169 copy
= xmlDocCopyNode(node
, insert
->doc
, 0);
1171 copy
->doc
= ctxt
->output
;
1172 copy
= xsltAddChild(insert
, copy
);
1174 if (node
->type
== XML_ELEMENT_NODE
) {
1176 * Add namespaces as they are needed
1178 if (node
->nsDef
!= NULL
) {
1180 * TODO: Remove the LRE case in the refactored code
1184 xsltCopyNamespaceList(ctxt
, copy
, node
->nsDef
);
1186 xsltCopyNamespaceListInternal(copy
, node
->nsDef
);
1190 * URGENT TODO: The problem with this is that it does not
1191 * copy over all namespace nodes in scope.
1192 * The damn thing about this is, that we would need to
1193 * use the xmlGetNsList(), for every single node; this is
1194 * also done in xsltCopyTreeInternal(), but only for the top node.
1196 if (node
->ns
!= NULL
) {
1199 * REVISIT TODO: Since the non-refactored code still does
1200 * ns-aliasing, we need to call xsltGetNamespace() here.
1201 * Remove this when ready.
1203 copy
->ns
= xsltGetNamespace(ctxt
, node
, node
->ns
, copy
);
1205 copy
->ns
= xsltGetSpecialNamespace(ctxt
,
1206 node
, node
->ns
->href
, node
->ns
->prefix
, copy
);
1209 } else if ((insert
->type
== XML_ELEMENT_NODE
) &&
1210 (insert
->ns
!= NULL
))
1213 * "Undeclare" the default namespace.
1215 xsltGetSpecialNamespace(ctxt
, node
, NULL
, NULL
, copy
);
1219 xsltTransformError(ctxt
, NULL
, node
,
1220 "xsltShallowCopyElem: copy %s failed\n", node
->name
);
1227 * @ctxt: a XSLT process context
1228 * @invocNode: responsible node in the stylesheet; used for error reports
1229 * @list: the list of element nodes in the source tree.
1230 * @insert: the parent in the result tree.
1231 * @isLRE: is this a literal result element list
1232 * @topElemVisited: indicates if a top-most element was already processed
1234 * Make a copy of the full list of tree @list
1235 * and insert it as last children of @insert
1237 * NOTE: Not to be used for Literal Result Elements.
1242 * Returns a pointer to the new list, or NULL in case of error
1245 xsltCopyTreeList(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1247 xmlNodePtr insert
, int isLRE
, int topElemVisited
)
1249 xmlNodePtr copy
, ret
= NULL
;
1251 while (list
!= NULL
) {
1252 copy
= xsltCopyTreeInternal(ctxt
, invocNode
,
1253 list
, insert
, isLRE
, topElemVisited
);
1265 * xsltCopyNamespaceListInternal:
1266 * @node: the target node
1267 * @cur: the first namespace
1269 * Do a copy of a namespace list. If @node is non-NULL the
1270 * new namespaces are added automatically.
1272 * xsltCopyTreeInternal()
1274 * QUESTION: What is the exact difference between this function
1275 * and xsltCopyNamespaceList() in "namespaces.c"?
1276 * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
1278 * Returns: a new xmlNsPtr, or NULL in case of error.
1281 xsltCopyNamespaceListInternal(xmlNodePtr elem
, xmlNsPtr ns
) {
1282 xmlNsPtr ret
= NULL
;
1283 xmlNsPtr p
= NULL
, q
, luNs
;
1288 * One can add namespaces only on element nodes
1290 if ((elem
!= NULL
) && (elem
->type
!= XML_ELEMENT_NODE
))
1294 if (ns
->type
!= XML_NAMESPACE_DECL
)
1297 * Avoid duplicating namespace declarations on the tree.
1300 if ((elem
->ns
!= NULL
) &&
1301 xmlStrEqual(elem
->ns
->prefix
, ns
->prefix
) &&
1302 xmlStrEqual(elem
->ns
->href
, ns
->href
))
1307 luNs
= xmlSearchNs(elem
->doc
, elem
, ns
->prefix
);
1308 if ((luNs
!= NULL
) && (xmlStrEqual(luNs
->href
, ns
->href
)))
1314 q
= xmlNewNs(elem
, ns
->href
, ns
->prefix
);
1317 } else if (q
!= NULL
) {
1322 } while (ns
!= NULL
);
1327 * xsltShallowCopyNsNode:
1328 * @ctxt: the XSLT transformation context
1329 * @invocNode: responsible node in the stylesheet; used for error reports
1330 * @insert: the target element node in the result tree
1331 * @ns: the namespace node
1333 * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
1335 * Returns a new/existing ns-node, or NULL.
1338 xsltShallowCopyNsNode(xsltTransformContextPtr ctxt
,
1339 xmlNodePtr invocNode
,
1344 * TODO: Contrary to header comments, this is declared as int.
1345 * be modified to return a node pointer, or NULL if any error
1349 if ((insert
== NULL
) || (insert
->type
!= XML_ELEMENT_NODE
))
1352 if (insert
->children
!= NULL
) {
1353 xsltTransformError(ctxt
, NULL
, invocNode
,
1354 "Namespace nodes must be added before "
1355 "any child nodes are added to an element.\n");
1359 * BIG NOTE: Xalan-J simply overwrites any ns-decls with
1360 * an equal prefix. We definitively won't do that.
1362 * MSXML 4.0 and the .NET ignores ns-decls for which an
1363 * equal prefix is already in use.
1365 * Saxon raises an error like:
1366 * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
1367 * nodes with the same name".
1369 * NOTE: We'll currently follow MSXML here.
1370 * REVISIT TODO: Check if it's better to follow Saxon here.
1372 if (ns
->prefix
== NULL
) {
1374 * If we are adding ns-nodes to an element using e.g.
1375 * <xsl:copy-of select="/foo/namespace::*">, then we need
1376 * to ensure that we don't incorrectly declare a default
1377 * namespace on an element in no namespace, which otherwise
1378 * would move the element incorrectly into a namespace, if
1379 * the node tree is serialized.
1381 if (insert
->ns
== NULL
)
1383 } else if ((ns
->prefix
[0] == 'x') &&
1384 xmlStrEqual(ns
->prefix
, BAD_CAST
"xml"))
1387 * The XML namespace is built in.
1392 if (insert
->nsDef
!= NULL
) {
1393 tmpns
= insert
->nsDef
;
1395 if ((tmpns
->prefix
== NULL
) == (ns
->prefix
== NULL
)) {
1396 if ((tmpns
->prefix
== ns
->prefix
) ||
1397 xmlStrEqual(tmpns
->prefix
, ns
->prefix
))
1402 if (xmlStrEqual(tmpns
->href
, ns
->href
))
1407 tmpns
= tmpns
->next
;
1408 } while (tmpns
!= NULL
);
1410 tmpns
= xmlSearchNs(insert
->doc
, insert
, ns
->prefix
);
1411 if ((tmpns
!= NULL
) && xmlStrEqual(tmpns
->href
, ns
->href
))
1414 * Declare a new namespace.
1415 * TODO: The problem (wrt efficiency) with this xmlNewNs() is
1416 * that it will again search the already declared namespaces
1417 * for a duplicate :-/
1419 return(xmlNewNs(insert
, ns
->href
, ns
->prefix
));
1423 * TODO: We could as well raise an error here (like Saxon does),
1424 * or at least generate a warning.
1430 * xsltCopyTreeInternal:
1431 * @ctxt: the XSLT transformation context
1432 * @invocNode: responsible node in the stylesheet; used for error reports
1433 * @node: the element node in the source tree
1434 * @insert: the parent in the result tree
1435 * @isLRE: indicates if @node is a Literal Result Element
1436 * @topElemVisited: indicates if a top-most element was already processed
1438 * Make a copy of the full tree under the element node @node
1439 * and insert it as last child of @insert
1441 * NOTE: Not to be used for Literal Result Elements.
1446 * Returns a pointer to the new tree, or NULL in case of error
1449 xsltCopyTreeInternal(xsltTransformContextPtr ctxt
,
1450 xmlNodePtr invocNode
,
1452 xmlNodePtr insert
, int isLRE
, int topElemVisited
)
1458 switch (node
->type
) {
1459 case XML_ELEMENT_NODE
:
1460 case XML_ENTITY_REF_NODE
:
1461 case XML_ENTITY_NODE
:
1463 case XML_COMMENT_NODE
:
1464 case XML_DOCUMENT_NODE
:
1465 case XML_HTML_DOCUMENT_NODE
:
1466 #ifdef LIBXML_DOCB_ENABLED
1467 case XML_DOCB_DOCUMENT_NODE
:
1470 case XML_TEXT_NODE
: {
1471 int noenc
= (node
->name
== xmlStringTextNoenc
);
1472 return(xsltCopyTextString(ctxt
, insert
, node
->content
, noenc
));
1474 case XML_CDATA_SECTION_NODE
:
1475 return(xsltCopyTextString(ctxt
, insert
, node
->content
, 0));
1476 case XML_ATTRIBUTE_NODE
:
1478 xsltShallowCopyAttr(ctxt
, invocNode
, insert
, (xmlAttrPtr
) node
));
1479 case XML_NAMESPACE_DECL
:
1480 return((xmlNodePtr
) xsltShallowCopyNsNode(ctxt
, invocNode
,
1481 insert
, (xmlNsPtr
) node
));
1483 case XML_DOCUMENT_TYPE_NODE
:
1484 case XML_DOCUMENT_FRAG_NODE
:
1485 case XML_NOTATION_NODE
:
1487 case XML_ELEMENT_DECL
:
1488 case XML_ATTRIBUTE_DECL
:
1489 case XML_ENTITY_DECL
:
1490 case XML_XINCLUDE_START
:
1491 case XML_XINCLUDE_END
:
1494 if (XSLT_IS_RES_TREE_FRAG(node
)) {
1495 if (node
->children
!= NULL
)
1496 copy
= xsltCopyTreeList(ctxt
, invocNode
,
1497 node
->children
, insert
, 0, 0);
1502 copy
= xmlDocCopyNode(node
, insert
->doc
, 0);
1504 copy
->doc
= ctxt
->output
;
1505 copy
= xsltAddChild(insert
, copy
);
1507 * The node may have been coalesced into another text node.
1509 if (insert
->last
!= copy
)
1510 return(insert
->last
);
1513 if (node
->type
== XML_ELEMENT_NODE
) {
1515 * Copy in-scope namespace nodes.
1517 * REVISIT: Since we try to reuse existing in-scope ns-decls by
1518 * using xmlSearchNsByHref(), this will eventually change
1519 * the prefix of an original ns-binding; thus it might
1520 * break QNames in element/attribute content.
1521 * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
1522 * context, plus a ns-lookup function, which writes directly
1523 * to a given list, then we wouldn't need to create/free the
1524 * nsList every time.
1526 if ((topElemVisited
== 0) &&
1527 (node
->parent
!= NULL
) &&
1528 (node
->parent
->type
!= XML_DOCUMENT_NODE
) &&
1529 (node
->parent
->type
!= XML_HTML_DOCUMENT_NODE
))
1531 xmlNsPtr
*nsList
, *curns
, ns
;
1534 * If this is a top-most element in a tree to be
1535 * copied, then we need to ensure that all in-scope
1536 * namespaces are copied over. For nodes deeper in the
1537 * tree, it is sufficient to reconcile only the ns-decls
1538 * (node->nsDef entries).
1541 nsList
= xmlGetNsList(node
->doc
, node
);
1542 if (nsList
!= NULL
) {
1546 * Search by prefix first in order to break as less
1547 * QNames in element/attribute content as possible.
1549 ns
= xmlSearchNs(insert
->doc
, insert
,
1553 (! xmlStrEqual(ns
->href
, (*curns
)->href
)))
1557 * Search by namespace name.
1558 * REVISIT TODO: Currently disabled.
1561 ns
= xmlSearchNsByHref(insert
->doc
,
1562 insert
, (*curns
)->href
);
1567 * Declare a new namespace on the copied element.
1569 ns
= xmlNewNs(copy
, (*curns
)->href
,
1571 /* TODO: Handle errors */
1573 if (node
->ns
== *curns
) {
1575 * If this was the original's namespace then set
1576 * the generated counterpart on the copy.
1581 } while (*curns
!= NULL
);
1584 } else if (node
->nsDef
!= NULL
) {
1586 * Copy over all namespace declaration attributes.
1588 if (node
->nsDef
!= NULL
) {
1590 xsltCopyNamespaceList(ctxt
, copy
, node
->nsDef
);
1592 xsltCopyNamespaceListInternal(copy
, node
->nsDef
);
1596 * Set the namespace.
1598 if (node
->ns
!= NULL
) {
1599 if (copy
->ns
== NULL
) {
1601 * This will map copy->ns to one of the newly created
1602 * in-scope ns-decls, OR create a new ns-decl on @copy.
1604 copy
->ns
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1605 node
->ns
->href
, node
->ns
->prefix
, copy
);
1607 } else if ((insert
->type
== XML_ELEMENT_NODE
) &&
1608 (insert
->ns
!= NULL
))
1611 * "Undeclare" the default namespace on @copy with xmlns="".
1613 xsltGetSpecialNamespace(ctxt
, invocNode
, NULL
, NULL
, copy
);
1616 * Copy attribute nodes.
1618 if (node
->properties
!= NULL
) {
1619 xsltCopyAttrListNoOverwrite(ctxt
, invocNode
,
1620 copy
, node
->properties
);
1622 if (topElemVisited
== 0)
1628 if (node
->children
!= NULL
) {
1629 xsltCopyTreeList(ctxt
, invocNode
,
1630 node
->children
, copy
, isLRE
, topElemVisited
);
1633 xsltTransformError(ctxt
, NULL
, invocNode
,
1634 "xsltCopyTreeInternal: Copying of '%s' failed.\n", node
->name
);
1641 * @ctxt: the XSLT transformation context
1642 * @node: the element node in the source tree
1643 * @insert: the parent in the result tree
1644 * @literal: indicates if @node is a Literal Result Element
1646 * Make a copy of the full tree under the element node @node
1647 * and insert it as last child of @insert
1648 * For literal result element, some of the namespaces may not be copied
1649 * over according to section 7.1.
1650 * TODO: Why is this a public function?
1652 * Returns a pointer to the new tree, or NULL in case of error
1655 xsltCopyTree(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1656 xmlNodePtr insert
, int literal
)
1658 return(xsltCopyTreeInternal(ctxt
, node
, node
, insert
, literal
, 0));
1662 /************************************************************************
1664 * Error/fallback processing *
1666 ************************************************************************/
1669 * xsltApplyFallbacks:
1670 * @ctxt: a XSLT process context
1671 * @node: the node in the source tree.
1672 * @inst: the node generating the error
1674 * Process possible xsl:fallback nodes present under @inst
1676 * Returns the number of xsl:fallback element found and processed
1679 xsltApplyFallbacks(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1685 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) ||
1686 (inst
->children
== NULL
))
1689 child
= inst
->children
;
1690 while (child
!= NULL
) {
1691 if ((IS_XSLT_ELEM(child
)) &&
1692 (xmlStrEqual(child
->name
, BAD_CAST
"fallback"))) {
1693 #ifdef WITH_XSLT_DEBUG_PARSING
1694 xsltGenericDebug(xsltGenericDebugContext
,
1695 "applying xsl:fallback\n");
1698 xsltApplySequenceConstructor(ctxt
, node
, child
->children
,
1701 child
= child
->next
;
1706 /************************************************************************
1708 * Default processing *
1710 ************************************************************************/
1713 * xsltDefaultProcessOneNode:
1714 * @ctxt: a XSLT process context
1715 * @node: the node in the source tree.
1716 * @params: extra parameters passed to the template if any
1718 * Process the source node with the default built-in template rule:
1719 * <xsl:template match="*|/">
1720 * <xsl:apply-templates/>
1725 * <xsl:template match="text()|@*">
1726 * <xsl:value-of select="."/>
1729 * Note also that namespace declarations are copied directly:
1731 * the built-in template rule is the only template rule that is applied
1732 * for namespace nodes.
1735 xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1736 xsltStackElemPtr params
) {
1738 xmlNodePtr
delete = NULL
, cur
;
1739 int nbchild
= 0, oldSize
;
1740 int childno
= 0, oldPos
;
1741 xsltTemplatePtr
template;
1745 * Handling of leaves
1747 switch (node
->type
) {
1748 case XML_DOCUMENT_NODE
:
1749 case XML_HTML_DOCUMENT_NODE
:
1750 case XML_ELEMENT_NODE
:
1752 case XML_CDATA_SECTION_NODE
:
1753 #ifdef WITH_XSLT_DEBUG_PROCESS
1754 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1755 "xsltDefaultProcessOneNode: copy CDATA %s\n",
1758 copy
= xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
1760 xsltTransformError(ctxt
, NULL
, node
,
1761 "xsltDefaultProcessOneNode: cdata copy failed\n");
1765 #ifdef WITH_XSLT_DEBUG_PROCESS
1766 if (node
->content
== NULL
) {
1767 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1768 "xsltDefaultProcessOneNode: copy empty text\n"));
1771 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1772 "xsltDefaultProcessOneNode: copy text %s\n",
1776 copy
= xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
1778 xsltTransformError(ctxt
, NULL
, node
,
1779 "xsltDefaultProcessOneNode: text copy failed\n");
1782 case XML_ATTRIBUTE_NODE
:
1783 cur
= node
->children
;
1784 while ((cur
!= NULL
) && (cur
->type
!= XML_TEXT_NODE
))
1787 xsltTransformError(ctxt
, NULL
, node
,
1788 "xsltDefaultProcessOneNode: no text for attribute\n");
1790 #ifdef WITH_XSLT_DEBUG_PROCESS
1791 if (cur
->content
== NULL
) {
1792 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1793 "xsltDefaultProcessOneNode: copy empty text\n"));
1795 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1796 "xsltDefaultProcessOneNode: copy text %s\n",
1800 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
1802 xsltTransformError(ctxt
, NULL
, node
,
1803 "xsltDefaultProcessOneNode: text copy failed\n");
1811 * Handling of Elements: first pass, cleanup and counting
1813 cur
= node
->children
;
1814 while (cur
!= NULL
) {
1815 switch (cur
->type
) {
1817 case XML_CDATA_SECTION_NODE
:
1818 case XML_DOCUMENT_NODE
:
1819 case XML_HTML_DOCUMENT_NODE
:
1820 case XML_ELEMENT_NODE
:
1822 case XML_COMMENT_NODE
:
1826 /* Unlink the DTD, it's still reachable using doc->intSubset */
1827 if (cur
->next
!= NULL
)
1828 cur
->next
->prev
= cur
->prev
;
1829 if (cur
->prev
!= NULL
)
1830 cur
->prev
->next
= cur
->next
;
1833 #ifdef WITH_XSLT_DEBUG_PROCESS
1834 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1835 "xsltDefaultProcessOneNode: skipping node type %d\n",
1841 if (delete != NULL
) {
1842 #ifdef WITH_XSLT_DEBUG_PROCESS
1843 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1844 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1846 xmlUnlinkNode(delete);
1847 xmlFreeNode(delete);
1851 if (delete != NULL
) {
1852 #ifdef WITH_XSLT_DEBUG_PROCESS
1853 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1854 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1856 xmlUnlinkNode(delete);
1857 xmlFreeNode(delete);
1862 * Handling of Elements: second pass, actual processing
1864 oldSize
= ctxt
->xpathCtxt
->contextSize
;
1865 oldPos
= ctxt
->xpathCtxt
->proximityPosition
;
1866 cur
= node
->children
;
1867 while (cur
!= NULL
) {
1869 switch (cur
->type
) {
1870 case XML_DOCUMENT_NODE
:
1871 case XML_HTML_DOCUMENT_NODE
:
1872 case XML_ELEMENT_NODE
:
1873 ctxt
->xpathCtxt
->contextSize
= nbchild
;
1874 ctxt
->xpathCtxt
->proximityPosition
= childno
;
1875 xsltProcessOneNode(ctxt
, cur
, params
);
1877 case XML_CDATA_SECTION_NODE
:
1878 template = xsltGetTemplate(ctxt
, cur
, NULL
);
1880 #ifdef WITH_XSLT_DEBUG_PROCESS
1881 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1882 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
1886 * Instantiate the xsl:template.
1888 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
1890 } else /* if (ctxt->mode == NULL) */ {
1891 #ifdef WITH_XSLT_DEBUG_PROCESS
1892 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1893 "xsltDefaultProcessOneNode: copy CDATA %s\n",
1896 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
1898 xsltTransformError(ctxt
, NULL
, cur
,
1899 "xsltDefaultProcessOneNode: cdata copy failed\n");
1904 template = xsltGetTemplate(ctxt
, cur
, NULL
);
1906 #ifdef WITH_XSLT_DEBUG_PROCESS
1907 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1908 "xsltDefaultProcessOneNode: applying template for text %s\n",
1911 ctxt
->xpathCtxt
->contextSize
= nbchild
;
1912 ctxt
->xpathCtxt
->proximityPosition
= childno
;
1914 * Instantiate the xsl:template.
1916 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
1918 } else /* if (ctxt->mode == NULL) */ {
1919 #ifdef WITH_XSLT_DEBUG_PROCESS
1920 if (cur
->content
== NULL
) {
1921 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1922 "xsltDefaultProcessOneNode: copy empty text\n"));
1924 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1925 "xsltDefaultProcessOneNode: copy text %s\n",
1929 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
1931 xsltTransformError(ctxt
, NULL
, cur
,
1932 "xsltDefaultProcessOneNode: text copy failed\n");
1937 case XML_COMMENT_NODE
:
1938 template = xsltGetTemplate(ctxt
, cur
, NULL
);
1940 #ifdef WITH_XSLT_DEBUG_PROCESS
1941 if (cur
->type
== XML_PI_NODE
) {
1942 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1943 "xsltDefaultProcessOneNode: template found for PI %s\n",
1945 } else if (cur
->type
== XML_COMMENT_NODE
) {
1946 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1947 "xsltDefaultProcessOneNode: template found for comment\n"));
1950 ctxt
->xpathCtxt
->contextSize
= nbchild
;
1951 ctxt
->xpathCtxt
->proximityPosition
= childno
;
1953 * Instantiate the xsl:template.
1955 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
1964 ctxt
->xpathCtxt
->contextSize
= oldSize
;
1965 ctxt
->xpathCtxt
->proximityPosition
= oldPos
;
1969 * xsltProcessOneNode:
1970 * @ctxt: a XSLT process context
1971 * @contextNode: the "current node" in the source tree
1972 * @withParams: extra parameters (e.g. xsl:with-param) passed to the
1975 * Process the source node.
1978 xsltProcessOneNode(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
1979 xsltStackElemPtr withParams
)
1981 xsltTemplatePtr templ
;
1984 templ
= xsltGetTemplate(ctxt
, contextNode
, NULL
);
1986 * If no template is found, apply the default rule.
1988 if (templ
== NULL
) {
1989 #ifdef WITH_XSLT_DEBUG_PROCESS
1990 if (contextNode
->type
== XML_DOCUMENT_NODE
) {
1991 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1992 "xsltProcessOneNode: no template found for /\n"));
1993 } else if (contextNode
->type
== XML_CDATA_SECTION_NODE
) {
1994 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1995 "xsltProcessOneNode: no template found for CDATA\n"));
1996 } else if (contextNode
->type
== XML_ATTRIBUTE_NODE
) {
1997 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1998 "xsltProcessOneNode: no template found for attribute %s\n",
1999 ((xmlAttrPtr
) contextNode
)->name
));
2001 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2002 "xsltProcessOneNode: no template found for %s\n", contextNode
->name
));
2005 oldNode
= ctxt
->node
;
2006 ctxt
->node
= contextNode
;
2007 xsltDefaultProcessOneNode(ctxt
, contextNode
, withParams
);
2008 ctxt
->node
= oldNode
;
2012 if (contextNode
->type
== XML_ATTRIBUTE_NODE
) {
2013 xsltTemplatePtr oldCurTempRule
= ctxt
->currentTemplateRule
;
2015 * Set the "current template rule".
2017 ctxt
->currentTemplateRule
= templ
;
2019 #ifdef WITH_XSLT_DEBUG_PROCESS
2020 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2021 "xsltProcessOneNode: applying template '%s' for attribute %s\n",
2022 templ
->match
, contextNode
->name
));
2024 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
, templ
, withParams
);
2026 ctxt
->currentTemplateRule
= oldCurTempRule
;
2028 xsltTemplatePtr oldCurTempRule
= ctxt
->currentTemplateRule
;
2030 * Set the "current template rule".
2032 ctxt
->currentTemplateRule
= templ
;
2034 #ifdef WITH_XSLT_DEBUG_PROCESS
2035 if (contextNode
->type
== XML_DOCUMENT_NODE
) {
2036 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2037 "xsltProcessOneNode: applying template '%s' for /\n",
2040 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2041 "xsltProcessOneNode: applying template '%s' for %s\n",
2042 templ
->match
, contextNode
->name
));
2045 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
, templ
, withParams
);
2047 ctxt
->currentTemplateRule
= oldCurTempRule
;
2052 xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt
,
2053 xmlNodePtr contextNode
,
2055 xsltTemplatePtr templ
,
2058 xmlNodePtr debugedNode
= NULL
;
2060 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2062 *addCallResult
= xslAddCall(templ
, templ
->elem
);
2064 *addCallResult
= xslAddCall(NULL
, list
);
2066 switch (ctxt
->debugStatus
) {
2067 case XSLT_DEBUG_RUN_RESTART
:
2068 case XSLT_DEBUG_QUIT
:
2074 xslHandleDebugger(templ
->elem
, contextNode
, templ
, ctxt
);
2075 debugedNode
= templ
->elem
;
2077 xslHandleDebugger(list
, contextNode
, templ
, ctxt
);
2079 } else if (ctxt
->inst
) {
2080 xslHandleDebugger(ctxt
->inst
, contextNode
, templ
, ctxt
);
2081 debugedNode
= ctxt
->inst
;
2084 return(debugedNode
);
2088 * xsltLocalVariablePush:
2089 * @ctxt: the transformation context
2090 * @variable: variable to be pushed to the variable stack
2091 * @level: new value for variable's level
2093 * Places the variable onto the local variable stack
2095 * Returns: 0 for success, -1 for any error
2097 * This is an internal routine and should not be called by users!
2100 xsltLocalVariablePush(xsltTransformContextPtr ctxt
,
2101 xsltStackElemPtr variable
,
2104 if (ctxt
->varsMax
== 0) {
2107 (xsltStackElemPtr
*) xmlMalloc(ctxt
->varsMax
*
2108 sizeof(ctxt
->varsTab
[0]));
2109 if (ctxt
->varsTab
== NULL
) {
2110 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
2114 if (ctxt
->varsNr
>= ctxt
->varsMax
) {
2117 (xsltStackElemPtr
*) xmlRealloc(ctxt
->varsTab
,
2119 sizeof(ctxt
->varsTab
[0]));
2120 if (ctxt
->varsTab
== NULL
) {
2121 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
2125 ctxt
->varsTab
[ctxt
->varsNr
++] = variable
;
2126 ctxt
->vars
= variable
;
2127 variable
->level
= level
;
2132 * xsltReleaseLocalRVTs:
2134 * Fragments which are results of extension instructions
2135 * are preserved; all other fragments are freed/cached.
2138 xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt
, xmlDocPtr base
)
2140 xmlDocPtr cur
= ctxt
->localRVT
, tmp
;
2142 while ((cur
!= NULL
) && (cur
!= base
)) {
2143 if (cur
->psvi
== (void *) ((long) 1)) {
2144 cur
= (xmlDocPtr
) cur
->next
;
2147 cur
= (xmlDocPtr
) cur
->next
;
2149 if (tmp
== ctxt
->localRVT
)
2150 ctxt
->localRVT
= cur
;
2153 * We need ctxt->localRVTBase for extension instructions
2154 * which return values (like EXSLT's function).
2156 if (tmp
== ctxt
->localRVTBase
)
2157 ctxt
->localRVTBase
= cur
;
2160 tmp
->prev
->next
= (xmlNodePtr
) cur
;
2162 cur
->prev
= tmp
->prev
;
2163 xsltReleaseRVT(ctxt
, tmp
);
2169 * xsltApplySequenceConstructor:
2170 * @ctxt: a XSLT process context
2171 * @contextNode: the "current node" in the source tree
2172 * @list: the nodes of a sequence constructor;
2173 * (plus leading xsl:param elements)
2174 * @templ: the compiled xsl:template (optional)
2176 * Processes a sequence constructor.
2178 * NOTE: ctxt->currentTemplateRule was introduced to reflect the
2179 * semantics of "current template rule". I.e. the field ctxt->templ
2180 * is not intended to reflect this, thus always pushed onto the
2184 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt
,
2185 xmlNodePtr contextNode
, xmlNodePtr list
,
2186 xsltTemplatePtr templ
)
2188 xmlNodePtr oldInsert
, oldInst
, oldCurInst
, oldContextNode
;
2189 xmlNodePtr cur
, insert
, copy
= NULL
;
2190 int level
= 0, oldVarsNr
;
2191 xmlDocPtr oldLocalFragmentTop
, oldLocalFragmentBase
;
2193 #ifdef XSLT_REFACTORED
2194 xsltStylePreCompPtr info
;
2197 #ifdef WITH_DEBUGGER
2198 int addCallResult
= 0;
2199 xmlNodePtr debuggedNode
= NULL
;
2205 #ifdef WITH_DEBUGGER
2206 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2208 xsltDebuggerStartSequenceConstructor(ctxt
, contextNode
,
2209 list
, templ
, &addCallResult
);
2210 if (debuggedNode
== NULL
)
2219 oldLocalFragmentTop
= ctxt
->localRVT
;
2220 oldInsert
= insert
= ctxt
->insert
;
2221 oldInst
= oldCurInst
= ctxt
->inst
;
2222 oldContextNode
= ctxt
->node
;
2224 * Save current number of variables on the stack; new vars are popped when
2227 oldVarsNr
= ctxt
->varsNr
;
2229 * Process the sequence constructor.
2232 while (cur
!= NULL
) {
2235 #ifdef WITH_DEBUGGER
2236 switch (ctxt
->debugStatus
) {
2237 case XSLT_DEBUG_RUN_RESTART
:
2238 case XSLT_DEBUG_QUIT
:
2244 * Test; we must have a valid insertion point.
2246 if (insert
== NULL
) {
2248 #ifdef WITH_XSLT_DEBUG_PROCESS
2249 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2250 "xsltApplySequenceConstructor: insert == NULL !\n"));
2255 #ifdef WITH_DEBUGGER
2256 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (debuggedNode
!= cur
))
2257 xslHandleDebugger(cur
, contextNode
, templ
, ctxt
);
2260 #ifdef XSLT_REFACTORED
2261 if (cur
->type
== XML_ELEMENT_NODE
) {
2262 info
= (xsltStylePreCompPtr
) cur
->psvi
;
2264 * We expect a compiled representation on:
2265 * 1) XSLT instructions of this XSLT version (1.0)
2266 * (with a few exceptions)
2267 * 2) Literal result elements
2268 * 3) Extension instructions
2269 * 4) XSLT instructions of future XSLT versions
2270 * (forwards-compatible mode).
2274 * Handle the rare cases where we don't expect a compiled
2275 * representation on an XSLT element.
2277 if (IS_XSLT_ELEM_FAST(cur
) && IS_XSLT_NAME(cur
, "message")) {
2278 xsltMessage(ctxt
, contextNode
, cur
);
2282 * Something really went wrong:
2284 xsltTransformError(ctxt
, NULL
, cur
,
2285 "Internal error in xsltApplySequenceConstructor(): "
2286 "The element '%s' in the stylesheet has no compiled "
2287 "representation.\n",
2292 if (info
->type
== XSLT_FUNC_LITERAL_RESULT_ELEMENT
) {
2293 xsltStyleItemLRElementInfoPtr lrInfo
=
2294 (xsltStyleItemLRElementInfoPtr
) info
;
2296 * Literal result elements
2297 * --------------------------------------------------------
2299 #ifdef WITH_XSLT_DEBUG_PROCESS
2300 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2301 xsltGenericDebug(xsltGenericDebugContext
,
2302 "xsltApplySequenceConstructor: copy literal result "
2303 "element '%s'\n", cur
->name
));
2306 * Copy the raw element-node.
2307 * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2311 copy
= xmlDocCopyNode(cur
, insert
->doc
, 0);
2313 xsltTransformError(ctxt
, NULL
, cur
,
2314 "Internal error in xsltApplySequenceConstructor(): "
2315 "Failed to copy literal result element '%s'.\n",
2320 * Add the element-node to the result tree.
2322 copy
->doc
= ctxt
->output
;
2323 copy
= xsltAddChild(insert
, copy
);
2325 * Create effective namespaces declarations.
2326 * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2328 if (lrInfo
->effectiveNs
!= NULL
) {
2329 xsltEffectiveNsPtr effNs
= lrInfo
->effectiveNs
;
2330 xmlNsPtr ns
, lastns
= NULL
;
2332 while (effNs
!= NULL
) {
2334 * Avoid generating redundant namespace
2335 * declarations; thus lookup if there is already
2336 * such a ns-decl in the result.
2338 ns
= xmlSearchNs(copy
->doc
, copy
, effNs
->prefix
);
2340 (xmlStrEqual(ns
->href
, effNs
->nsName
)))
2342 effNs
= effNs
->next
;
2345 ns
= xmlNewNs(copy
, effNs
->nsName
, effNs
->prefix
);
2347 xsltTransformError(ctxt
, NULL
, cur
,
2348 "Internal error in "
2349 "xsltApplySequenceConstructor(): "
2350 "Failed to copy a namespace "
2361 effNs
= effNs
->next
;
2366 * NOTE that we don't need to apply ns-alising: this was
2367 * already done at compile-time.
2369 if (cur
->ns
!= NULL
) {
2371 * If there's no such ns-decl in the result tree,
2372 * then xsltGetSpecialNamespace() will
2373 * create a ns-decl on the copied node.
2375 copy
->ns
= xsltGetSpecialNamespace(ctxt
, cur
,
2376 cur
->ns
->href
, cur
->ns
->prefix
, copy
);
2379 * Undeclare the default namespace if needed.
2380 * This can be skipped, if the result element has
2381 * no ns-decls, in which case the result element
2382 * obviously does not declare a default namespace;
2383 * AND there's either no parent, or the parent
2384 * element is in no namespace; this means there's no
2385 * default namespace is scope to care about.
2387 * REVISIT: This might result in massive
2388 * generation of ns-decls if nodes in a default
2389 * namespaces are mixed with nodes in no namespace.
2393 ((insert
!= NULL
) &&
2394 (insert
->type
== XML_ELEMENT_NODE
) &&
2395 (insert
->ns
!= NULL
)))
2397 xsltGetSpecialNamespace(ctxt
, cur
,
2403 * SPEC XSLT 2.0 "Each attribute of the literal result
2404 * element, other than an attribute in the XSLT namespace,
2405 * is processed to produce an attribute for the element in
2407 * NOTE: See bug #341325.
2409 if (cur
->properties
!= NULL
) {
2410 xsltAttrListTemplateProcess(ctxt
, copy
, cur
->properties
);
2412 } else if (IS_XSLT_ELEM_FAST(cur
)) {
2415 * --------------------------------------------------------
2417 if (info
->type
== XSLT_FUNC_UNKOWN_FORWARDS_COMPAT
) {
2419 * We hit an unknown XSLT element.
2420 * Try to apply one of the fallback cases.
2422 ctxt
->insert
= insert
;
2423 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2424 xsltTransformError(ctxt
, NULL
, cur
,
2425 "The is no fallback behaviour defined for "
2426 "the unknown XSLT element '%s'.\n",
2429 ctxt
->insert
= oldInsert
;
2430 } else if (info
->func
!= NULL
) {
2432 * Execute the XSLT instruction.
2434 ctxt
->insert
= insert
;
2436 info
->func(ctxt
, contextNode
, cur
,
2437 (xsltElemPreCompPtr
) info
);
2440 * Cleanup temporary tree fragments.
2442 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2443 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2445 ctxt
->insert
= oldInsert
;
2446 } else if (info
->type
== XSLT_FUNC_VARIABLE
) {
2447 xsltStackElemPtr tmpvar
= ctxt
->vars
;
2449 xsltParseStylesheetVariable(ctxt
, cur
);
2451 if (tmpvar
!= ctxt
->vars
) {
2453 * TODO: Using a @tmpvar is an annoying workaround, but
2454 * the current mechanisms do not provide any other way
2455 * of knowing if the var was really pushed onto the
2458 ctxt
->vars
->level
= level
;
2460 } else if (info
->type
== XSLT_FUNC_MESSAGE
) {
2462 * TODO: Won't be hit, since we don't compile xsl:message.
2464 xsltMessage(ctxt
, contextNode
, cur
);
2466 xsltTransformError(ctxt
, NULL
, cur
,
2467 "Unexpected XSLT element '%s'.\n", cur
->name
);
2472 xsltTransformFunction func
;
2474 * Extension intructions (elements)
2475 * --------------------------------------------------------
2477 if (cur
->psvi
== xsltExtMarker
) {
2479 * The xsltExtMarker was set during the compilation
2480 * of extension instructions if there was no registered
2481 * handler for this specific extension function at
2483 * Libxslt will now lookup if a handler is
2484 * registered in the context of this transformation.
2486 func
= (xsltTransformFunction
)
2487 xsltExtElementLookup(ctxt
, cur
->name
, cur
->ns
->href
);
2489 func
= ((xsltElemPreCompPtr
) cur
->psvi
)->func
;
2493 * No handler available.
2494 * Try to execute fallback behaviour via xsl:fallback.
2496 #ifdef WITH_XSLT_DEBUG_PROCESS
2497 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2498 xsltGenericDebug(xsltGenericDebugContext
,
2499 "xsltApplySequenceConstructor: unknown extension %s\n",
2502 ctxt
->insert
= insert
;
2503 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2504 xsltTransformError(ctxt
, NULL
, cur
,
2505 "Unknown extension instruction '{%s}%s'.\n",
2506 cur
->ns
->href
, cur
->name
);
2508 ctxt
->insert
= oldInsert
;
2511 * Execute the handler-callback.
2513 #ifdef WITH_XSLT_DEBUG_PROCESS
2514 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2515 "xsltApplySequenceConstructor: extension construct %s\n",
2518 ctxt
->insert
= insert
;
2520 * We need the fragment base for extension instructions
2521 * which return values (like EXSLT's function).
2523 oldLocalFragmentBase
= ctxt
->localRVTBase
;
2524 ctxt
->localRVTBase
= NULL
;
2526 func(ctxt
, contextNode
, cur
, cur
->psvi
);
2528 ctxt
->localRVTBase
= oldLocalFragmentBase
;
2530 * Cleanup temporary tree fragments.
2532 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2533 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2535 ctxt
->insert
= oldInsert
;
2540 } else if (XSLT_IS_TEXT_NODE(cur
)) {
2543 * ------------------------------------------------------------
2545 #ifdef WITH_XSLT_DEBUG_PROCESS
2546 if (cur
->name
== xmlStringTextNoenc
) {
2547 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2548 xsltGenericDebug(xsltGenericDebugContext
,
2549 "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2552 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2553 xsltGenericDebug(xsltGenericDebugContext
,
2554 "xsltApplySequenceConstructor: copy text '%s'\n",
2558 if (xsltCopyText(ctxt
, insert
, cur
, ctxt
->internalized
) == NULL
)
2562 #else /* XSLT_REFACTORED */
2564 if (IS_XSLT_ELEM(cur
)) {
2566 * This is an XSLT node
2568 xsltStylePreCompPtr info
= (xsltStylePreCompPtr
) cur
->psvi
;
2571 if (IS_XSLT_NAME(cur
, "message")) {
2572 xsltMessage(ctxt
, contextNode
, cur
);
2575 * That's an error try to apply one of the fallback cases
2577 ctxt
->insert
= insert
;
2578 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2579 xsltGenericError(xsltGenericErrorContext
,
2580 "xsltApplySequenceConstructor: %s was not compiled\n",
2583 ctxt
->insert
= oldInsert
;
2588 if (info
->func
!= NULL
) {
2589 oldCurInst
= ctxt
->inst
;
2591 ctxt
->insert
= insert
;
2592 oldLocalFragmentBase
= ctxt
->localRVTBase
;
2593 ctxt
->localRVTBase
= NULL
;
2595 info
->func(ctxt
, contextNode
, cur
, (xsltElemPreCompPtr
) info
);
2597 ctxt
->localRVTBase
= oldLocalFragmentBase
;
2599 * Cleanup temporary tree fragments.
2601 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2602 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2604 ctxt
->insert
= oldInsert
;
2605 ctxt
->inst
= oldCurInst
;
2609 if (IS_XSLT_NAME(cur
, "variable")) {
2610 xsltStackElemPtr tmpvar
= ctxt
->vars
;
2612 oldCurInst
= ctxt
->inst
;
2615 xsltParseStylesheetVariable(ctxt
, cur
);
2617 ctxt
->inst
= oldCurInst
;
2619 if (tmpvar
!= ctxt
->vars
) {
2621 * TODO: Using a @tmpvar is an annoying workaround, but
2622 * the current mechanisms do not provide any other way
2623 * of knowing if the var was really pushed onto the
2626 ctxt
->vars
->level
= level
;
2628 } else if (IS_XSLT_NAME(cur
, "message")) {
2629 xsltMessage(ctxt
, contextNode
, cur
);
2631 xsltTransformError(ctxt
, NULL
, cur
,
2632 "Unexpected XSLT element '%s'.\n", cur
->name
);
2635 } else if ((cur
->type
== XML_TEXT_NODE
) ||
2636 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
2639 * This text comes from the stylesheet
2640 * For stylesheets, the set of whitespace-preserving
2641 * element names consists of just xsl:text.
2643 #ifdef WITH_XSLT_DEBUG_PROCESS
2644 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
2645 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2646 "xsltApplySequenceConstructor: copy CDATA text %s\n",
2648 } else if (cur
->name
== xmlStringTextNoenc
) {
2649 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2650 "xsltApplySequenceConstructor: copy unescaped text %s\n",
2653 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2654 "xsltApplySequenceConstructor: copy text %s\n",
2658 if (xsltCopyText(ctxt
, insert
, cur
, ctxt
->internalized
) == NULL
)
2660 } else if ((cur
->type
== XML_ELEMENT_NODE
) &&
2661 (cur
->ns
!= NULL
) && (cur
->psvi
!= NULL
)) {
2662 xsltTransformFunction function
;
2664 oldCurInst
= ctxt
->inst
;
2667 * Flagged as an extension element
2669 if (cur
->psvi
== xsltExtMarker
)
2670 function
= (xsltTransformFunction
)
2671 xsltExtElementLookup(ctxt
, cur
->name
, cur
->ns
->href
);
2673 function
= ((xsltElemPreCompPtr
) cur
->psvi
)->func
;
2675 if (function
== NULL
) {
2679 #ifdef WITH_XSLT_DEBUG_PROCESS
2680 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2681 "xsltApplySequenceConstructor: unknown extension %s\n",
2685 * Search if there are fallbacks
2687 child
= cur
->children
;
2688 while (child
!= NULL
) {
2689 if ((IS_XSLT_ELEM(child
)) &&
2690 (IS_XSLT_NAME(child
, "fallback")))
2693 xsltApplySequenceConstructor(ctxt
, contextNode
,
2694 child
->children
, NULL
);
2696 child
= child
->next
;
2700 xsltTransformError(ctxt
, NULL
, cur
,
2701 "xsltApplySequenceConstructor: failed to find extension %s\n",
2705 #ifdef WITH_XSLT_DEBUG_PROCESS
2706 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2707 "xsltApplySequenceConstructor: extension construct %s\n",
2711 ctxt
->insert
= insert
;
2713 * We need the fragment base for extension instructions
2714 * which return values (like EXSLT's function).
2716 oldLocalFragmentBase
= ctxt
->localRVTBase
;
2717 ctxt
->localRVTBase
= NULL
;
2719 function(ctxt
, contextNode
, cur
, cur
->psvi
);
2721 * Cleanup temporary tree fragments.
2723 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2724 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2726 ctxt
->localRVTBase
= oldLocalFragmentBase
;
2727 ctxt
->insert
= oldInsert
;
2730 ctxt
->inst
= oldCurInst
;
2732 } else if (cur
->type
== XML_ELEMENT_NODE
) {
2733 #ifdef WITH_XSLT_DEBUG_PROCESS
2734 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2735 "xsltApplySequenceConstructor: copy node %s\n",
2738 oldCurInst
= ctxt
->inst
;
2741 if ((copy
= xsltShallowCopyElem(ctxt
, cur
, insert
, 1)) == NULL
)
2744 * Add extra namespaces inherited from the current template
2745 * if we are in the first level children and this is a
2748 if ((templ
!= NULL
) && (oldInsert
== insert
) &&
2749 (ctxt
->templ
!= NULL
) && (ctxt
->templ
->inheritedNs
!= NULL
)) {
2753 for (i
= 0; i
< ctxt
->templ
->inheritedNsNr
; i
++) {
2754 const xmlChar
*URI
= NULL
;
2755 xsltStylesheetPtr style
;
2756 ns
= ctxt
->templ
->inheritedNs
[i
];
2758 /* Note that the XSLT namespace was already excluded
2759 * in xsltGetInheritedNsList().
2762 if (xmlStrEqual(ns
->href
, XSLT_NAMESPACE
))
2765 style
= ctxt
->style
;
2766 while (style
!= NULL
) {
2767 if (style
->nsAliases
!= NULL
)
2768 URI
= (const xmlChar
*)
2769 xmlHashLookup(style
->nsAliases
, ns
->href
);
2773 style
= xsltNextImport(style
);
2775 if (URI
== UNDEFINED_DEFAULT_NS
)
2780 * TODO: The following will still be buggy for the
2781 * non-refactored code.
2783 ret
= xmlSearchNs(copy
->doc
, copy
, ns
->prefix
);
2784 if ((ret
== NULL
) || (!xmlStrEqual(ret
->href
, URI
)))
2786 xmlNewNs(copy
, URI
, ns
->prefix
);
2789 if (copy
->ns
!= NULL
) {
2791 * Fix the node namespace if needed
2793 copy
->ns
= xsltGetNamespace(ctxt
, cur
, copy
->ns
, copy
);
2797 * all the attributes are directly inherited
2799 if (cur
->properties
!= NULL
) {
2800 xsltAttrListTemplateProcess(ctxt
, copy
, cur
->properties
);
2802 ctxt
->inst
= oldCurInst
;
2804 #endif /* else of XSLT_REFACTORED */
2807 * Descend into content in document order.
2809 if (cur
->children
!= NULL
) {
2810 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
2811 cur
= cur
->children
;
2821 * If xslt:message was just processed, we might have hit a
2822 * terminate='yes'; if so, then break the loop and clean up.
2823 * TODO: Do we need to check this also before trying to descend
2826 if (ctxt
->state
== XSLT_STATE_STOPPED
)
2828 if (cur
->next
!= NULL
) {
2837 * Pop variables/params (xsl:variable and xsl:param).
2839 if ((ctxt
->varsNr
> oldVarsNr
) && (ctxt
->vars
->level
> level
)) {
2840 xsltLocalVariablePop(ctxt
, oldVarsNr
, level
);
2843 insert
= insert
->parent
;
2846 if (cur
== list
->parent
) {
2850 if (cur
->next
!= NULL
) {
2854 } while (cur
!= NULL
);
2859 * In case of errors: pop remaining variables.
2861 if (ctxt
->varsNr
> oldVarsNr
)
2862 xsltLocalVariablePop(ctxt
, oldVarsNr
, -1);
2864 ctxt
->node
= oldContextNode
;
2865 ctxt
->inst
= oldInst
;
2866 ctxt
->insert
= oldInsert
;
2868 #ifdef WITH_DEBUGGER
2869 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (addCallResult
)) {
2876 * xsltApplyXSLTTemplate:
2877 * @ctxt: a XSLT transformation context
2878 * @contextNode: the node in the source tree.
2879 * @list: the nodes of a sequence constructor;
2880 * (plus leading xsl:param elements)
2881 * @templ: the compiled xsl:template declaration;
2882 * NULL if a sequence constructor
2883 * @withParams: a set of caller-parameters (xsl:with-param) or NULL
2886 * - xsltApplyImports()
2887 * - xsltCallTemplate()
2888 * - xsltDefaultProcessOneNode()
2889 * - xsltProcessOneNode()
2892 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt
,
2893 xmlNodePtr contextNode
,
2895 xsltTemplatePtr templ
,
2896 xsltStackElemPtr withParams
)
2898 int oldVarsBase
= 0;
2901 xsltStackElemPtr tmpParam
= NULL
;
2902 xmlDocPtr oldUserFragmentTop
, oldLocalFragmentTop
;
2904 #ifdef XSLT_REFACTORED
2905 xsltStyleItemParamPtr iparam
;
2907 xsltStylePreCompPtr iparam
;
2910 #ifdef WITH_DEBUGGER
2911 int addCallResult
= 0;
2916 if (templ
== NULL
) {
2917 xsltTransformError(ctxt
, NULL
, list
,
2918 "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
2922 #ifdef WITH_DEBUGGER
2923 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2924 if (xsltDebuggerStartSequenceConstructor(ctxt
, contextNode
,
2925 list
, templ
, &addCallResult
) == NULL
)
2935 * Check for infinite recursion: stop if the maximum of nested templates
2936 * is excceeded. Adjust xsltMaxDepth if you need more.
2938 if (((ctxt
->templNr
>= xsltMaxDepth
) ||
2939 (ctxt
->varsNr
>= 5 * xsltMaxDepth
)))
2941 xsltTransformError(ctxt
, NULL
, list
,
2942 "xsltApplyXSLTTemplate: A potential infinite template recursion "
2944 "You can adjust xsltMaxDepth (--maxdepth) in order to "
2945 "raise the maximum number of nested template calls and "
2946 "variables/params (currently set to %d).\n",
2948 xsltDebug(ctxt
, contextNode
, list
, NULL
);
2952 oldUserFragmentTop
= ctxt
->tmpRVT
;
2953 ctxt
->tmpRVT
= NULL
;
2954 oldLocalFragmentTop
= ctxt
->localRVT
;
2957 * Initiate a distinct scope of local params/variables.
2959 oldVarsBase
= ctxt
->varsBase
;
2960 ctxt
->varsBase
= ctxt
->varsNr
;
2962 ctxt
->node
= contextNode
;
2963 if (ctxt
->profile
) {
2965 start
= xsltTimestamp();
2969 * Push the xsl:template declaration onto the stack.
2971 templPush(ctxt
, templ
);
2973 #ifdef WITH_XSLT_DEBUG_PROCESS
2974 if (templ
->name
!= NULL
)
2975 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2976 "applying xsl:template '%s'\n", templ
->name
));
2979 * Process xsl:param instructions and skip those elements for
2980 * further processing.
2984 if (cur
->type
== XML_TEXT_NODE
) {
2988 if ((cur
->type
!= XML_ELEMENT_NODE
) ||
2989 (cur
->name
[0] != 'p') ||
2990 (cur
->psvi
== NULL
) ||
2991 (! xmlStrEqual(cur
->name
, BAD_CAST
"param")) ||
2992 (! IS_XSLT_ELEM(cur
)))
2999 #ifdef XSLT_REFACTORED
3000 iparam
= (xsltStyleItemParamPtr
) cur
->psvi
;
3002 iparam
= (xsltStylePreCompPtr
) cur
->psvi
;
3006 * Substitute xsl:param for a given xsl:with-param.
3007 * Since the XPath expression will reference the params/vars
3008 * by index, we need to slot the xsl:with-params in the
3009 * order of encountered xsl:params to keep the sequence of
3010 * params/variables in the stack exactly as it was at
3015 tmpParam
= withParams
;
3017 if ((tmpParam
->name
== (iparam
->name
)) &&
3018 (tmpParam
->nameURI
== (iparam
->ns
)))
3021 * Push the caller-parameter.
3023 xsltLocalVariablePush(ctxt
, tmpParam
, -1);
3026 tmpParam
= tmpParam
->next
;
3027 } while (tmpParam
!= NULL
);
3030 * Push the xsl:param.
3032 if (tmpParam
== NULL
) {
3034 * Note that we must assume that the added parameter
3035 * has a @depth of 0.
3037 xsltParseStylesheetParam(ctxt
, cur
);
3040 } while (cur
!= NULL
);
3042 * Process the sequence constructor.
3044 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3047 * Remove remaining xsl:param and xsl:with-param items from
3048 * the stack. Don't free xsl:with-param items.
3050 if (ctxt
->varsNr
> ctxt
->varsBase
)
3051 xsltTemplateParamsCleanup(ctxt
);
3052 ctxt
->varsBase
= oldVarsBase
;
3055 * Clean up remaining local tree fragments.
3056 * This also frees fragments which are the result of
3057 * extension instructions. Should normally not be hit; but
3058 * just for the case xsltExtensionInstructionResultFinalize()
3059 * was not called by the extension author.
3061 if (oldLocalFragmentTop
!= ctxt
->localRVT
) {
3062 xmlDocPtr curdoc
= ctxt
->localRVT
, tmp
;
3066 curdoc
= (xmlDocPtr
) curdoc
->next
;
3067 /* Need to housekeep localRVTBase */
3068 if (tmp
== ctxt
->localRVTBase
)
3069 ctxt
->localRVTBase
= curdoc
;
3071 tmp
->prev
->next
= (xmlNodePtr
) curdoc
;
3073 curdoc
->prev
= tmp
->prev
;
3074 xsltReleaseRVT(ctxt
, tmp
);
3075 } while (curdoc
!= oldLocalFragmentTop
);
3077 ctxt
->localRVT
= oldLocalFragmentTop
;
3080 * Release user-created fragments stored in the scope
3081 * of xsl:template. Note that this mechanism is deprecated:
3082 * user code should now use xsltRegisterLocalRVT() instead
3083 * of the obsolete xsltRegisterTmpRVT().
3086 xmlDocPtr curdoc
= ctxt
->tmpRVT
, tmp
;
3088 while (curdoc
!= NULL
) {
3090 curdoc
= (xmlDocPtr
) curdoc
->next
;
3091 xsltReleaseRVT(ctxt
, tmp
);
3094 ctxt
->tmpRVT
= oldUserFragmentTop
;
3097 * Pop the xsl:template declaration from the stack.
3100 if (ctxt
->profile
) {
3101 long spent
, child
, total
, end
;
3103 end
= xsltTimestamp();
3104 child
= profPop(ctxt
);
3105 total
= end
- start
;
3106 spent
= total
- child
;
3109 * Not possible unless the original calibration failed
3110 * we can try to correct it on the fly.
3112 xsltCalibrateAdjust(spent
);
3116 templ
->time
+= spent
;
3117 if (ctxt
->profNr
> 0)
3118 ctxt
->profTab
[ctxt
->profNr
- 1] += total
;
3121 #ifdef WITH_DEBUGGER
3122 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (addCallResult
)) {
3130 * xsltApplyOneTemplate:
3131 * @ctxt: a XSLT process context
3132 * @contextNode: the node in the source tree.
3133 * @list: the nodes of a sequence constructor
3135 * @params: a set of parameters (xsl:param) or NULL
3137 * Processes a sequence constructor on the current node in the source tree.
3139 * @params are the already computed variable stack items; this function
3140 * pushes them on the variable stack, and pops them before exiting; it's
3141 * left to the caller to free or reuse @params afterwards. The initial
3142 * states of the variable stack will always be restored before this
3144 * NOTE that this does *not* initiate a new distinct variable scope; i.e.
3145 * variables already on the stack are visible to the process. The caller's
3146 * side needs to start a new variable scope if needed (e.g. in exsl:function).
3148 * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
3149 * provide a @templ); a non-NULL @templ might raise an error in the future.
3151 * BIG NOTE: This function is not intended to process the content of an
3152 * xsl:template; it does not expect xsl:param instructions in @list and
3153 * will report errors if found.
3156 * - xsltEvalVariable() (variables.c)
3157 * - exsltFuncFunctionFunction() (libexsl/functions.c)
3160 xsltApplyOneTemplate(xsltTransformContextPtr ctxt
,
3161 xmlNodePtr contextNode
,
3163 xsltTemplatePtr templ ATTRIBUTE_UNUSED
,
3164 xsltStackElemPtr params
)
3166 if ((ctxt
== NULL
) || (list
== NULL
))
3172 * This code should be obsolete - was previously used
3173 * by libexslt/functions.c, but due to bug 381319 the
3174 * logic there was changed.
3176 int oldVarsNr
= ctxt
->varsNr
;
3179 * Push the given xsl:param(s) onto the variable stack.
3181 while (params
!= NULL
) {
3182 xsltLocalVariablePush(ctxt
, params
, -1);
3183 params
= params
->next
;
3185 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3187 * Pop the given xsl:param(s) from the stack but don't free them.
3189 xsltLocalVariablePop(ctxt
, oldVarsNr
, -2);
3191 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3194 /************************************************************************
3196 * XSLT-1.1 extensions *
3198 ************************************************************************/
3202 * @ctxt: an XSLT processing context
3203 * @node: The current node
3204 * @inst: the instruction in the stylesheet
3205 * @castedComp: precomputed information
3207 * Process an EXSLT/XSLT-1.1 document element
3210 xsltDocumentElem(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3211 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
3213 #ifdef XSLT_REFACTORED
3214 xsltStyleItemDocumentPtr comp
= (xsltStyleItemDocumentPtr
) castedComp
;
3216 xsltStylePreCompPtr comp
= castedComp
;
3218 xsltStylesheetPtr style
= NULL
;
3220 xmlChar
*filename
= NULL
, *prop
, *elements
;
3221 xmlChar
*element
, *end
;
3222 xmlDocPtr res
= NULL
;
3223 xmlDocPtr oldOutput
;
3224 xmlNodePtr oldInsert
, root
;
3225 const char *oldOutputFile
;
3226 xsltOutputType oldType
;
3227 xmlChar
*URL
= NULL
;
3228 const xmlChar
*method
;
3229 const xmlChar
*doctypePublic
;
3230 const xmlChar
*doctypeSystem
;
3231 const xmlChar
*version
;
3232 const xmlChar
*encoding
;
3234 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
3237 if (comp
->filename
== NULL
) {
3239 if (xmlStrEqual(inst
->name
, (const xmlChar
*) "output")) {
3241 * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
3242 * (http://icl.com/saxon)
3243 * The @file is in no namespace.
3245 #ifdef WITH_XSLT_DEBUG_EXTRA
3246 xsltGenericDebug(xsltGenericDebugContext
,
3247 "Found saxon:output extension\n");
3249 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3250 (const xmlChar
*) "file",
3251 XSLT_SAXON_NAMESPACE
);
3254 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3255 (const xmlChar
*) "href",
3256 XSLT_SAXON_NAMESPACE
);
3257 } else if (xmlStrEqual(inst
->name
, (const xmlChar
*) "write")) {
3258 #ifdef WITH_XSLT_DEBUG_EXTRA
3259 xsltGenericDebug(xsltGenericDebugContext
,
3260 "Found xalan:write extension\n");
3262 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3265 XSLT_XALAN_NAMESPACE
);
3267 xmlXPathCompExprPtr cmp
;
3271 * Trying to handle bug #59212
3272 * The value of the "select" attribute is an
3274 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
3276 cmp
= xmlXPathCompile(URL
);
3277 val
= xsltEvalXPathString(ctxt
, cmp
);
3278 xmlXPathFreeCompExpr(cmp
);
3283 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3286 XSLT_XALAN_NAMESPACE
);
3288 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3291 XSLT_XALAN_NAMESPACE
);
3292 } else if (xmlStrEqual(inst
->name
, (const xmlChar
*) "document")) {
3293 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3294 (const xmlChar
*) "href",
3299 URL
= xmlStrdup(comp
->filename
);
3303 xsltTransformError(ctxt
, NULL
, inst
,
3304 "xsltDocumentElem: href/URI-Reference not found\n");
3309 * If the computation failed, it's likely that the URL wasn't escaped
3311 filename
= xmlBuildURI(URL
, (const xmlChar
*) ctxt
->outputFile
);
3312 if (filename
== NULL
) {
3315 escURL
=xmlURIEscapeStr(URL
, BAD_CAST
":/.?,");
3316 if (escURL
!= NULL
) {
3317 filename
= xmlBuildURI(escURL
, (const xmlChar
*) ctxt
->outputFile
);
3322 if (filename
== NULL
) {
3323 xsltTransformError(ctxt
, NULL
, inst
,
3324 "xsltDocumentElem: URL computation failed for %s\n",
3331 * Security checking: can we write to this resource
3333 if (ctxt
->sec
!= NULL
) {
3334 ret
= xsltCheckWrite(ctxt
->sec
, ctxt
, filename
);
3336 xsltTransformError(ctxt
, NULL
, inst
,
3337 "xsltDocumentElem: write rights for %s denied\n",
3345 oldOutputFile
= ctxt
->outputFile
;
3346 oldOutput
= ctxt
->output
;
3347 oldInsert
= ctxt
->insert
;
3348 oldType
= ctxt
->type
;
3349 ctxt
->outputFile
= (const char *) filename
;
3351 style
= xsltNewStylesheet();
3352 if (style
== NULL
) {
3353 xsltTransformError(ctxt
, NULL
, inst
,
3354 "xsltDocumentElem: out of memory\n");
3359 * Version described in 1.1 draft allows full parameterization
3362 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3363 (const xmlChar
*) "version",
3366 if (style
->version
!= NULL
)
3367 xmlFree(style
->version
);
3368 style
->version
= prop
;
3370 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3371 (const xmlChar
*) "encoding",
3374 if (style
->encoding
!= NULL
)
3375 xmlFree(style
->encoding
);
3376 style
->encoding
= prop
;
3378 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3379 (const xmlChar
*) "method",
3384 if (style
->method
!= NULL
)
3385 xmlFree(style
->method
);
3386 style
->method
= NULL
;
3387 if (style
->methodURI
!= NULL
)
3388 xmlFree(style
->methodURI
);
3389 style
->methodURI
= NULL
;
3391 URI
= xsltGetQNameURI(inst
, &prop
);
3393 if (style
!= NULL
) style
->errors
++;
3394 } else if (URI
== NULL
) {
3395 if ((xmlStrEqual(prop
, (const xmlChar
*) "xml")) ||
3396 (xmlStrEqual(prop
, (const xmlChar
*) "html")) ||
3397 (xmlStrEqual(prop
, (const xmlChar
*) "text"))) {
3398 style
->method
= prop
;
3400 xsltTransformError(ctxt
, NULL
, inst
,
3401 "invalid value for method: %s\n", prop
);
3402 if (style
!= NULL
) style
->warnings
++;
3405 style
->method
= prop
;
3406 style
->methodURI
= xmlStrdup(URI
);
3409 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3411 "doctype-system", NULL
);
3413 if (style
->doctypeSystem
!= NULL
)
3414 xmlFree(style
->doctypeSystem
);
3415 style
->doctypeSystem
= prop
;
3417 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3419 "doctype-public", NULL
);
3421 if (style
->doctypePublic
!= NULL
)
3422 xmlFree(style
->doctypePublic
);
3423 style
->doctypePublic
= prop
;
3425 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3426 (const xmlChar
*) "standalone",
3429 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3430 style
->standalone
= 1;
3431 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3432 style
->standalone
= 0;
3434 xsltTransformError(ctxt
, NULL
, inst
,
3435 "invalid value for standalone: %s\n",
3437 if (style
!= NULL
) style
->warnings
++;
3442 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3443 (const xmlChar
*) "indent",
3446 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3448 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3451 xsltTransformError(ctxt
, NULL
, inst
,
3452 "invalid value for indent: %s\n", prop
);
3453 if (style
!= NULL
) style
->warnings
++;
3458 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3460 "omit-xml-declaration",
3463 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3464 style
->omitXmlDeclaration
= 1;
3465 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3466 style
->omitXmlDeclaration
= 0;
3468 xsltTransformError(ctxt
, NULL
, inst
,
3469 "invalid value for omit-xml-declaration: %s\n",
3471 if (style
!= NULL
) style
->warnings
++;
3476 elements
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3478 "cdata-section-elements",
3480 if (elements
!= NULL
) {
3481 if (style
->stripSpaces
== NULL
)
3482 style
->stripSpaces
= xmlHashCreate(10);
3483 if (style
->stripSpaces
== NULL
)
3487 while (*element
!= 0) {
3488 while (IS_BLANK_CH(*element
))
3493 while ((*end
!= 0) && (!IS_BLANK_CH(*end
)))
3495 element
= xmlStrndup(element
, end
- element
);
3499 #ifdef WITH_XSLT_DEBUG_PARSING
3500 xsltGenericDebug(xsltGenericDebugContext
,
3501 "add cdata section output element %s\n",
3504 URI
= xsltGetQNameURI(inst
, &element
);
3506 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
3507 (xmlChar
*) "cdata");
3516 * Create a new document tree and process the element template
3518 XSLT_GET_IMPORT_PTR(method
, style
, method
)
3519 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
3520 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
3521 XSLT_GET_IMPORT_PTR(version
, style
, version
)
3522 XSLT_GET_IMPORT_PTR(encoding
, style
, encoding
)
3524 if ((method
!= NULL
) &&
3525 (!xmlStrEqual(method
, (const xmlChar
*) "xml"))) {
3526 if (xmlStrEqual(method
, (const xmlChar
*) "html")) {
3527 ctxt
->type
= XSLT_OUTPUT_HTML
;
3528 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3529 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
3531 if (version
!= NULL
) {
3532 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3533 xsltGetHTMLIDs(version
, &doctypePublic
, &doctypeSystem
);
3536 res
= htmlNewDocNoDtD(doctypeSystem
, doctypePublic
);
3540 res
->dict
= ctxt
->dict
;
3541 xmlDictReference(res
->dict
);
3542 } else if (xmlStrEqual(method
, (const xmlChar
*) "xhtml")) {
3543 xsltTransformError(ctxt
, NULL
, inst
,
3544 "xsltDocumentElem: unsupported method xhtml\n",
3546 ctxt
->type
= XSLT_OUTPUT_HTML
;
3547 res
= htmlNewDocNoDtD(doctypeSystem
, doctypePublic
);
3550 res
->dict
= ctxt
->dict
;
3551 xmlDictReference(res
->dict
);
3552 } else if (xmlStrEqual(method
, (const xmlChar
*) "text")) {
3553 ctxt
->type
= XSLT_OUTPUT_TEXT
;
3554 res
= xmlNewDoc(style
->version
);
3557 res
->dict
= ctxt
->dict
;
3558 xmlDictReference(res
->dict
);
3559 #ifdef WITH_XSLT_DEBUG
3560 xsltGenericDebug(xsltGenericDebugContext
,
3561 "reusing transformation dict for output\n");
3564 xsltTransformError(ctxt
, NULL
, inst
,
3565 "xsltDocumentElem: unsupported method %s\n",
3570 ctxt
->type
= XSLT_OUTPUT_XML
;
3571 res
= xmlNewDoc(style
->version
);
3574 res
->dict
= ctxt
->dict
;
3575 xmlDictReference(res
->dict
);
3576 #ifdef WITH_XSLT_DEBUG
3577 xsltGenericDebug(xsltGenericDebugContext
,
3578 "reusing transformation dict for output\n");
3581 res
->charset
= XML_CHAR_ENCODING_UTF8
;
3582 if (encoding
!= NULL
)
3583 res
->encoding
= xmlStrdup(encoding
);
3585 ctxt
->insert
= (xmlNodePtr
) res
;
3586 xsltApplySequenceConstructor(ctxt
, node
, inst
->children
, NULL
);
3589 * Do some post processing work depending on the generated output
3591 root
= xmlDocGetRootElement(res
);
3593 const xmlChar
*doctype
= NULL
;
3595 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
))
3596 doctype
= xmlDictQLookup(ctxt
->dict
, root
->ns
->prefix
, root
->name
);
3597 if (doctype
== NULL
)
3598 doctype
= root
->name
;
3601 * Apply the default selection of the method
3603 if ((method
== NULL
) &&
3604 (root
->ns
== NULL
) &&
3605 (!xmlStrcasecmp(root
->name
, (const xmlChar
*) "html"))) {
3608 tmp
= res
->children
;
3609 while ((tmp
!= NULL
) && (tmp
!= root
)) {
3610 if (tmp
->type
== XML_ELEMENT_NODE
)
3612 if ((tmp
->type
== XML_TEXT_NODE
) && (!xmlIsBlankNode(tmp
)))
3617 ctxt
->type
= XSLT_OUTPUT_HTML
;
3618 res
->type
= XML_HTML_DOCUMENT_NODE
;
3619 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
3620 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
3623 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3624 } else if (version
!= NULL
) {
3625 xsltGetHTMLIDs(version
, &doctypePublic
,
3627 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3629 xmlCreateIntSubset(res
, doctype
,
3637 if (ctxt
->type
== XSLT_OUTPUT_XML
) {
3638 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
3639 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
3640 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3641 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
3650 ret
= xsltSaveResultToFilename((const char *) filename
,
3653 xsltTransformError(ctxt
, NULL
, inst
,
3654 "xsltDocumentElem: unable to save to %s\n",
3656 ctxt
->state
= XSLT_STATE_ERROR
;
3657 #ifdef WITH_XSLT_DEBUG_EXTRA
3659 xsltGenericDebug(xsltGenericDebugContext
,
3660 "Wrote %d bytes to %s\n", ret
, filename
);
3665 ctxt
->output
= oldOutput
;
3666 ctxt
->insert
= oldInsert
;
3667 ctxt
->type
= oldType
;
3668 ctxt
->outputFile
= oldOutputFile
;
3671 if (filename
!= NULL
)
3674 xsltFreeStylesheet(style
);
3679 /************************************************************************
3681 * Most of the XSLT-1.0 transformations *
3683 ************************************************************************/
3687 * @ctxt: a XSLT process context
3688 * @node: the node in the source tree.
3689 * @inst: the xslt sort node
3690 * @comp: precomputed information
3692 * function attached to xsl:sort nodes, but this should not be
3696 xsltSort(xsltTransformContextPtr ctxt
,
3697 xmlNodePtr node ATTRIBUTE_UNUSED
, xmlNodePtr inst
,
3698 xsltStylePreCompPtr comp
) {
3700 xsltTransformError(ctxt
, NULL
, inst
,
3701 "xsl:sort : compilation failed\n");
3704 xsltTransformError(ctxt
, NULL
, inst
,
3705 "xsl:sort : improper use this should not be reached\n");
3710 * @ctxt: an XSLT process context
3711 * @node: the node in the source tree
3712 * @inst: the element node of the XSLT-copy instruction
3713 * @castedComp: computed information of the XSLT-copy instruction
3715 * Execute the XSLT-copy instruction on the source node.
3718 xsltCopy(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3719 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
3721 #ifdef XSLT_REFACTORED
3722 xsltStyleItemCopyPtr comp
= (xsltStyleItemCopyPtr
) castedComp
;
3724 xsltStylePreCompPtr comp
= castedComp
;
3726 xmlNodePtr copy
, oldInsert
;
3728 oldInsert
= ctxt
->insert
;
3729 if (ctxt
->insert
!= NULL
) {
3730 switch (node
->type
) {
3732 case XML_CDATA_SECTION_NODE
:
3734 * This text comes from the stylesheet
3735 * For stylesheets, the set of whitespace-preserving
3736 * element names consists of just xsl:text.
3738 #ifdef WITH_XSLT_DEBUG_PROCESS
3739 if (node
->type
== XML_CDATA_SECTION_NODE
) {
3740 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3741 "xsltCopy: CDATA text %s\n", node
->content
));
3743 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3744 "xsltCopy: text %s\n", node
->content
));
3747 xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
3749 case XML_DOCUMENT_NODE
:
3750 case XML_HTML_DOCUMENT_NODE
:
3752 case XML_ELEMENT_NODE
:
3754 * REVISIT NOTE: The "fake" is a doc-node, not an element node.
3756 * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3760 #ifdef WITH_XSLT_DEBUG_PROCESS
3761 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3762 "xsltCopy: node %s\n", node
->name
));
3764 copy
= xsltShallowCopyElem(ctxt
, node
, ctxt
->insert
, 0);
3765 ctxt
->insert
= copy
;
3766 if (comp
->use
!= NULL
) {
3767 xsltApplyAttributeSet(ctxt
, node
, inst
, comp
->use
);
3770 case XML_ATTRIBUTE_NODE
: {
3771 #ifdef WITH_XSLT_DEBUG_PROCESS
3772 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3773 "xsltCopy: attribute %s\n", node
->name
));
3776 * REVISIT: We could also raise an error if the parent is not
3778 * OPTIMIZE TODO: Can we set the value/children of the
3779 * attribute without an intermediate copy of the string value?
3781 xsltShallowCopyAttr(ctxt
, inst
, ctxt
->insert
, (xmlAttrPtr
) node
);
3785 #ifdef WITH_XSLT_DEBUG_PROCESS
3786 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3787 "xsltCopy: PI %s\n", node
->name
));
3789 copy
= xmlNewDocPI(ctxt
->insert
->doc
, node
->name
,
3791 copy
= xsltAddChild(ctxt
->insert
, copy
);
3793 case XML_COMMENT_NODE
:
3794 #ifdef WITH_XSLT_DEBUG_PROCESS
3795 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3796 "xsltCopy: comment\n"));
3798 copy
= xmlNewComment(node
->content
);
3799 copy
= xsltAddChild(ctxt
->insert
, copy
);
3801 case XML_NAMESPACE_DECL
:
3802 #ifdef WITH_XSLT_DEBUG_PROCESS
3803 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3804 "xsltCopy: namespace declaration\n"));
3806 xsltShallowCopyNsNode(ctxt
, inst
, ctxt
->insert
, (xmlNsPtr
)node
);
3814 switch (node
->type
) {
3815 case XML_DOCUMENT_NODE
:
3816 case XML_HTML_DOCUMENT_NODE
:
3817 case XML_ELEMENT_NODE
:
3818 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, inst
->children
,
3824 ctxt
->insert
= oldInsert
;
3829 * @ctxt: a XSLT process context
3830 * @node: the node in the source tree.
3831 * @inst: the xslt text node
3832 * @comp: precomputed information
3834 * Process the xslt text node on the source node
3837 xsltText(xsltTransformContextPtr ctxt
, xmlNodePtr node ATTRIBUTE_UNUSED
,
3838 xmlNodePtr inst
, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED
) {
3839 if ((inst
->children
!= NULL
) && (comp
!= NULL
)) {
3840 xmlNodePtr text
= inst
->children
;
3843 while (text
!= NULL
) {
3844 if ((text
->type
!= XML_TEXT_NODE
) &&
3845 (text
->type
!= XML_CDATA_SECTION_NODE
)) {
3846 xsltTransformError(ctxt
, NULL
, inst
,
3847 "xsl:text content problem\n");
3850 copy
= xmlNewDocText(ctxt
->output
, text
->content
);
3851 if (text
->type
!= XML_CDATA_SECTION_NODE
) {
3852 #ifdef WITH_XSLT_DEBUG_PARSING
3853 xsltGenericDebug(xsltGenericDebugContext
,
3854 "Disable escaping: %s\n", text
->content
);
3856 copy
->name
= xmlStringTextNoenc
;
3858 copy
= xsltAddChild(ctxt
->insert
, copy
);
3866 * @ctxt: a XSLT process context
3867 * @node: the node in the source tree.
3868 * @inst: the xslt element node
3869 * @castedComp: precomputed information
3871 * Process the xslt element node on the source node
3874 xsltElement(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3875 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
) {
3876 #ifdef XSLT_REFACTORED
3877 xsltStyleItemElementPtr comp
= (xsltStyleItemElementPtr
) castedComp
;
3879 xsltStylePreCompPtr comp
= castedComp
;
3881 xmlChar
*prop
= NULL
;
3882 const xmlChar
*name
, *prefix
= NULL
, *nsName
= NULL
;
3884 xmlNodePtr oldInsert
;
3886 if (ctxt
->insert
== NULL
)
3890 * A comp->has_name == 0 indicates that we need to skip this instruction,
3891 * since it was evaluated to be invalid already during compilation.
3893 if (!comp
->has_name
)
3899 oldInsert
= ctxt
->insert
;
3901 if (comp
->name
== NULL
) {
3902 /* TODO: fix attr acquisition wrt to the XSLT namespace */
3903 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3904 (const xmlChar
*) "name", XSLT_NAMESPACE
);
3906 xsltTransformError(ctxt
, NULL
, inst
,
3907 "xsl:element: The attribute 'name' is missing.\n");
3910 if (xmlValidateQName(prop
, 0)) {
3911 xsltTransformError(ctxt
, NULL
, inst
,
3912 "xsl:element: The effective name '%s' is not a "
3913 "valid QName.\n", prop
);
3914 /* we fall through to catch any further errors, if possible */
3916 name
= xsltSplitQName(ctxt
->dict
, prop
, &prefix
);
3918 if ((prefix
!= NULL
) &&
3919 (!xmlStrncasecmp(prefix
, (xmlChar
*)"xml", 3)))
3922 * TODO: Should we really disallow an "xml" prefix?
3928 * The "name" value was static.
3930 #ifdef XSLT_REFACTORED
3931 prefix
= comp
->nsPrefix
;
3934 name
= xsltSplitQName(ctxt
->dict
, comp
->name
, &prefix
);
3939 * Create the new element
3941 if (ctxt
->output
->dict
== ctxt
->dict
) {
3942 copy
= xmlNewDocNodeEatName(ctxt
->output
, NULL
, (xmlChar
*)name
, NULL
);
3944 copy
= xmlNewDocNode(ctxt
->output
, NULL
, (xmlChar
*)name
, NULL
);
3947 xsltTransformError(ctxt
, NULL
, inst
,
3948 "xsl:element : creation of %s failed\n", name
);
3951 copy
= xsltAddChild(ctxt
->insert
, copy
);
3958 if (comp
->ns
!= NULL
) {
3960 * No AVT; just plain text for the namespace name.
3962 if (comp
->ns
[0] != 0)
3969 /* TODO: check attr acquisition wrt to the XSLT namespace */
3970 tmpNsName
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3971 (const xmlChar
*) "namespace", XSLT_NAMESPACE
);
3974 * "If the string is empty, then the expanded-name of the
3975 * attribute has a null namespace URI."
3977 if ((tmpNsName
!= NULL
) && (tmpNsName
[0] != 0))
3978 nsName
= xmlDictLookup(ctxt
->dict
, BAD_CAST tmpNsName
, -1);
3985 * "If the namespace attribute is not present, then the QName is
3986 * expanded into an expanded-name using the namespace declarations
3987 * in effect for the xsl:element element, including any default
3988 * namespace declaration.
3990 ns
= xmlSearchNs(inst
->doc
, inst
, prefix
);
3993 * TODO: Check this in the compilation layer in case it's a
3996 if (prefix
!= NULL
) {
3997 xsltTransformError(ctxt
, NULL
, inst
,
3998 "xsl:element: The QName '%s:%s' has no "
3999 "namespace binding in scope in the stylesheet; "
4000 "this is an error, since the namespace was not "
4001 "specified by the instruction itself.\n", prefix
, name
);
4007 * Find/create a matching ns-decl in the result tree.
4009 if (nsName
!= NULL
) {
4010 copy
->ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, prefix
, copy
);
4011 } else if ((copy
->parent
!= NULL
) &&
4012 (copy
->parent
->type
== XML_ELEMENT_NODE
) &&
4013 (copy
->parent
->ns
!= NULL
))
4016 * "Undeclare" the default namespace.
4018 xsltGetSpecialNamespace(ctxt
, inst
, NULL
, NULL
, copy
);
4021 ctxt
->insert
= copy
;
4023 if (comp
->has_use
) {
4024 if (comp
->use
!= NULL
) {
4025 xsltApplyAttributeSet(ctxt
, node
, inst
, comp
->use
);
4027 xmlChar
*attrSets
= NULL
;
4029 * BUG TODO: use-attribute-sets is not a value template.
4030 * use-attribute-sets = qnames
4032 attrSets
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4033 (const xmlChar
*)"use-attribute-sets", NULL
);
4034 if (attrSets
!= NULL
) {
4035 xsltApplyAttributeSet(ctxt
, node
, inst
, attrSets
);
4041 * Instantiate the sequence constructor.
4043 if (inst
->children
!= NULL
)
4044 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, inst
->children
,
4048 ctxt
->insert
= oldInsert
;
4055 * @ctxt: a XSLT process context
4056 * @node: the node in the source tree.
4057 * @inst: the xslt comment node
4058 * @comp: precomputed information
4060 * Process the xslt comment node on the source node
4063 xsltComment(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4064 xmlNodePtr inst
, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED
) {
4065 xmlChar
*value
= NULL
;
4066 xmlNodePtr commentNode
;
4069 value
= xsltEvalTemplateString(ctxt
, node
, inst
);
4070 /* TODO: use or generate the compiled form */
4071 len
= xmlStrlen(value
);
4073 if ((value
[len
-1] == '-') ||
4074 (xmlStrstr(value
, BAD_CAST
"--"))) {
4075 xsltTransformError(ctxt
, NULL
, inst
,
4076 "xsl:comment : '--' or ending '-' not allowed in comment\n");
4077 /* fall through to try to catch further errors */
4080 #ifdef WITH_XSLT_DEBUG_PROCESS
4081 if (value
== NULL
) {
4082 XSLT_TRACE(ctxt
,XSLT_TRACE_COMMENT
,xsltGenericDebug(xsltGenericDebugContext
,
4083 "xsltComment: empty\n"));
4085 XSLT_TRACE(ctxt
,XSLT_TRACE_COMMENT
,xsltGenericDebug(xsltGenericDebugContext
,
4086 "xsltComment: content %s\n", value
));
4090 commentNode
= xmlNewComment(value
);
4091 commentNode
= xsltAddChild(ctxt
->insert
, commentNode
);
4098 * xsltProcessingInstruction:
4099 * @ctxt: a XSLT process context
4100 * @node: the node in the source tree.
4101 * @inst: the xslt processing-instruction node
4102 * @castedComp: precomputed information
4104 * Process the xslt processing-instruction node on the source node
4107 xsltProcessingInstruction(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4108 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
) {
4109 #ifdef XSLT_REFACTORED
4110 xsltStyleItemPIPtr comp
= (xsltStyleItemPIPtr
) castedComp
;
4112 xsltStylePreCompPtr comp
= castedComp
;
4114 const xmlChar
*name
;
4115 xmlChar
*value
= NULL
;
4119 if (ctxt
->insert
== NULL
)
4121 if (comp
->has_name
== 0)
4123 if (comp
->name
== NULL
) {
4124 name
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4125 (const xmlChar
*)"name", NULL
);
4127 xsltTransformError(ctxt
, NULL
, inst
,
4128 "xsl:processing-instruction : name is missing\n");
4134 /* TODO: check that it's both an an NCName and a PITarget. */
4137 value
= xsltEvalTemplateString(ctxt
, node
, inst
);
4138 if (xmlStrstr(value
, BAD_CAST
"?>") != NULL
) {
4139 xsltTransformError(ctxt
, NULL
, inst
,
4140 "xsl:processing-instruction: '?>' not allowed within PI content\n");
4143 #ifdef WITH_XSLT_DEBUG_PROCESS
4144 if (value
== NULL
) {
4145 XSLT_TRACE(ctxt
,XSLT_TRACE_PI
,xsltGenericDebug(xsltGenericDebugContext
,
4146 "xsltProcessingInstruction: %s empty\n", name
));
4148 XSLT_TRACE(ctxt
,XSLT_TRACE_PI
,xsltGenericDebug(xsltGenericDebugContext
,
4149 "xsltProcessingInstruction: %s content %s\n", name
, value
));
4153 pi
= xmlNewDocPI(ctxt
->insert
->doc
, name
, value
);
4154 pi
= xsltAddChild(ctxt
->insert
, pi
);
4157 if ((name
!= NULL
) && (name
!= comp
->name
))
4158 xmlFree((xmlChar
*) name
);
4165 * @ctxt: an XSLT transformation context
4166 * @node: the current node in the source tree
4167 * @inst: the element node of the XSLT copy-of instruction
4168 * @castedComp: precomputed information of the XSLT copy-of instruction
4170 * Process the XSLT copy-of instruction.
4173 xsltCopyOf(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4174 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
) {
4175 #ifdef XSLT_REFACTORED
4176 xsltStyleItemCopyOfPtr comp
= (xsltStyleItemCopyOfPtr
) castedComp
;
4178 xsltStylePreCompPtr comp
= castedComp
;
4180 xmlXPathObjectPtr res
= NULL
;
4181 xmlNodeSetPtr list
= NULL
;
4183 xmlDocPtr oldXPContextDoc
;
4184 xmlNsPtr
*oldXPNamespaces
;
4185 xmlNodePtr oldXPContextNode
;
4186 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
4187 xmlXPathContextPtr xpctxt
;
4189 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
))
4191 if ((comp
== NULL
) || (comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
4192 xsltTransformError(ctxt
, NULL
, inst
,
4193 "xsl:copy-of : compilation failed\n");
4199 * "The xsl:copy-of element can be used to insert a result tree
4200 * fragment into the result tree, without first converting it to
4201 * a string as xsl:value-of does (see [7.6.1 Generating Text with
4202 * xsl:value-of]). The required select attribute contains an
4203 * expression. When the result of evaluating the expression is a
4204 * result tree fragment, the complete fragment is copied into the
4205 * result tree. When the result is a node-set, all the nodes in the
4206 * set are copied in document order into the result tree; copying
4207 * an element node copies the attribute nodes, namespace nodes and
4208 * children of the element node as well as the element node itself;
4209 * a root node is copied by copying its children. When the result
4210 * is neither a node-set nor a result tree fragment, the result is
4211 * converted to a string and then inserted into the result tree,
4212 * as with xsl:value-of.
4215 #ifdef WITH_XSLT_DEBUG_PROCESS
4216 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4217 "xsltCopyOf: select %s\n", comp
->select
));
4221 * Evaluate the "select" expression.
4223 xpctxt
= ctxt
->xpathCtxt
;
4224 oldXPContextDoc
= xpctxt
->doc
;
4225 oldXPContextNode
= xpctxt
->node
;
4226 oldXPProximityPosition
= xpctxt
->proximityPosition
;
4227 oldXPContextSize
= xpctxt
->contextSize
;
4228 oldXPNsNr
= xpctxt
->nsNr
;
4229 oldXPNamespaces
= xpctxt
->namespaces
;
4231 xpctxt
->node
= node
;
4234 #ifdef XSLT_REFACTORED
4235 if (comp
->inScopeNs
!= NULL
) {
4236 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
4237 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
4239 xpctxt
->namespaces
= NULL
;
4243 xpctxt
->namespaces
= comp
->nsList
;
4244 xpctxt
->nsNr
= comp
->nsNr
;
4247 xpctxt
->namespaces
= NULL
;
4251 res
= xmlXPathCompiledEval(comp
->comp
, xpctxt
);
4253 xpctxt
->doc
= oldXPContextDoc
;
4254 xpctxt
->node
= oldXPContextNode
;
4255 xpctxt
->contextSize
= oldXPContextSize
;
4256 xpctxt
->proximityPosition
= oldXPProximityPosition
;
4257 xpctxt
->nsNr
= oldXPNsNr
;
4258 xpctxt
->namespaces
= oldXPNamespaces
;
4261 if (res
->type
== XPATH_NODESET
) {
4266 #ifdef WITH_XSLT_DEBUG_PROCESS
4267 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4268 "xsltCopyOf: result is a node set\n"));
4270 list
= res
->nodesetval
;
4274 * The list is already sorted in document order by XPath.
4275 * Append everything in this order under ctxt->insert.
4277 for (i
= 0;i
< list
->nodeNr
;i
++) {
4278 cur
= list
->nodeTab
[i
];
4281 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
4282 (cur
->type
== XML_HTML_DOCUMENT_NODE
))
4284 xsltCopyTreeList(ctxt
, inst
,
4285 cur
->children
, ctxt
->insert
, 0, 0);
4286 } else if (cur
->type
== XML_ATTRIBUTE_NODE
) {
4287 xsltShallowCopyAttr(ctxt
, inst
,
4288 ctxt
->insert
, (xmlAttrPtr
) cur
);
4290 xsltCopyTreeInternal(ctxt
, inst
,
4291 cur
, ctxt
->insert
, 0, 0);
4295 } else if (res
->type
== XPATH_XSLT_TREE
) {
4297 * Result tree fragment
4298 * --------------------
4299 * E.g. via <xsl:variable ...><foo/></xsl:variable>
4300 * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4302 #ifdef WITH_XSLT_DEBUG_PROCESS
4303 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4304 "xsltCopyOf: result is a result tree fragment\n"));
4306 list
= res
->nodesetval
;
4307 if ((list
!= NULL
) && (list
->nodeTab
!= NULL
) &&
4308 (list
->nodeTab
[0] != NULL
) &&
4309 (IS_XSLT_REAL_NODE(list
->nodeTab
[0])))
4311 xsltCopyTreeList(ctxt
, inst
,
4312 list
->nodeTab
[0]->children
, ctxt
->insert
, 0, 0);
4315 xmlChar
*value
= NULL
;
4317 * Convert to a string.
4319 value
= xmlXPathCastToString(res
);
4320 if (value
== NULL
) {
4321 xsltTransformError(ctxt
, NULL
, inst
,
4322 "Internal error in xsltCopyOf(): "
4323 "failed to cast an XPath object to string.\n");
4324 ctxt
->state
= XSLT_STATE_STOPPED
;
4326 if (value
[0] != 0) {
4328 * Append content as text node.
4330 xsltCopyTextString(ctxt
, ctxt
->insert
, value
, 0);
4334 #ifdef WITH_XSLT_DEBUG_PROCESS
4335 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4336 "xsltCopyOf: result %s\n", res
->stringval
));
4341 ctxt
->state
= XSLT_STATE_STOPPED
;
4345 xmlXPathFreeObject(res
);
4350 * @ctxt: a XSLT process context
4351 * @node: the node in the source tree.
4352 * @inst: the xslt value-of node
4353 * @castedComp: precomputed information
4355 * Process the xslt value-of node on the source node
4358 xsltValueOf(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4359 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
4361 #ifdef XSLT_REFACTORED
4362 xsltStyleItemValueOfPtr comp
= (xsltStyleItemValueOfPtr
) castedComp
;
4364 xsltStylePreCompPtr comp
= castedComp
;
4366 xmlXPathObjectPtr res
= NULL
;
4367 xmlNodePtr copy
= NULL
;
4368 xmlChar
*value
= NULL
;
4369 xmlDocPtr oldXPContextDoc
;
4370 xmlNsPtr
*oldXPNamespaces
;
4371 xmlNodePtr oldXPContextNode
;
4372 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
4373 xmlXPathContextPtr xpctxt
;
4375 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
))
4378 if ((comp
== NULL
) || (comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
4379 xsltTransformError(ctxt
, NULL
, inst
,
4380 "Internal error in xsltValueOf(): "
4381 "The XSLT 'value-of' instruction was not compiled.\n");
4385 #ifdef WITH_XSLT_DEBUG_PROCESS
4386 XSLT_TRACE(ctxt
,XSLT_TRACE_VALUE_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4387 "xsltValueOf: select %s\n", comp
->select
));
4390 xpctxt
= ctxt
->xpathCtxt
;
4391 oldXPContextDoc
= xpctxt
->doc
;
4392 oldXPContextNode
= xpctxt
->node
;
4393 oldXPProximityPosition
= xpctxt
->proximityPosition
;
4394 oldXPContextSize
= xpctxt
->contextSize
;
4395 oldXPNsNr
= xpctxt
->nsNr
;
4396 oldXPNamespaces
= xpctxt
->namespaces
;
4398 xpctxt
->node
= node
;
4401 #ifdef XSLT_REFACTORED
4402 if (comp
->inScopeNs
!= NULL
) {
4403 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
4404 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
4406 xpctxt
->namespaces
= NULL
;
4410 xpctxt
->namespaces
= comp
->nsList
;
4411 xpctxt
->nsNr
= comp
->nsNr
;
4414 xpctxt
->namespaces
= NULL
;
4418 res
= xmlXPathCompiledEval(comp
->comp
, xpctxt
);
4420 xpctxt
->doc
= oldXPContextDoc
;
4421 xpctxt
->node
= oldXPContextNode
;
4422 xpctxt
->contextSize
= oldXPContextSize
;
4423 xpctxt
->proximityPosition
= oldXPProximityPosition
;
4424 xpctxt
->nsNr
= oldXPNsNr
;
4425 xpctxt
->namespaces
= oldXPNamespaces
;
4428 * Cast the XPath object to string.
4431 value
= xmlXPathCastToString(res
);
4432 if (value
== NULL
) {
4433 xsltTransformError(ctxt
, NULL
, inst
,
4434 "Internal error in xsltValueOf(): "
4435 "failed to cast an XPath object to string.\n");
4436 ctxt
->state
= XSLT_STATE_STOPPED
;
4439 if (value
[0] != 0) {
4440 copy
= xsltCopyTextString(ctxt
,
4441 ctxt
->insert
, value
, comp
->noescape
);
4444 xsltTransformError(ctxt
, NULL
, inst
,
4445 "XPath evaluation returned no result.\n");
4446 ctxt
->state
= XSLT_STATE_STOPPED
;
4450 #ifdef WITH_XSLT_DEBUG_PROCESS
4452 XSLT_TRACE(ctxt
,XSLT_TRACE_VALUE_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4453 "xsltValueOf: result '%s'\n", value
));
4461 xmlXPathFreeObject(res
);
4466 * @ctxt: a XSLT process context
4467 * @node: the node in the source tree.
4468 * @inst: the xslt number node
4469 * @castedComp: precomputed information
4471 * Process the xslt number node on the source node
4474 xsltNumber(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4475 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
4477 #ifdef XSLT_REFACTORED
4478 xsltStyleItemNumberPtr comp
= (xsltStyleItemNumberPtr
) castedComp
;
4480 xsltStylePreCompPtr comp
= castedComp
;
4483 xsltTransformError(ctxt
, NULL
, inst
,
4484 "xsl:number : compilation failed\n");
4488 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
4491 comp
->numdata
.doc
= inst
->doc
;
4492 comp
->numdata
.node
= inst
;
4494 xsltNumberFormat(ctxt
, &comp
->numdata
, node
);
4499 * @ctxt: an XSLT transformation context
4500 * @contextNode: the current node in the source tree.
4501 * @inst: the element node of the XSLT 'apply-imports' instruction
4502 * @comp: the compiled instruction
4504 * Process the XSLT apply-imports element.
4507 xsltApplyImports(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
4509 xsltStylePreCompPtr comp ATTRIBUTE_UNUSED
)
4511 xsltTemplatePtr templ
;
4513 if ((ctxt
== NULL
) || (inst
== NULL
))
4517 xsltTransformError(ctxt
, NULL
, inst
,
4518 "Internal error in xsltApplyImports(): "
4519 "The XSLT 'apply-imports' instruction was not compiled.\n");
4523 * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4524 * same; the former is the "Current Template Rule" as defined by the
4525 * XSLT spec, the latter is simply the template struct being
4526 * currently processed.
4528 if (ctxt
->currentTemplateRule
== NULL
) {
4531 * "[ERR XTDE0560] It is a non-recoverable dynamic error if
4532 * xsl:apply-imports or xsl:next-match is evaluated when the
4533 * current template rule is null."
4535 xsltTransformError(ctxt
, NULL
, inst
,
4536 "It is an error to call 'apply-imports' "
4537 "when there's no current template rule.\n");
4541 * TODO: Check if this is correct.
4543 templ
= xsltGetTemplate(ctxt
, contextNode
,
4544 ctxt
->currentTemplateRule
->style
);
4546 if (templ
!= NULL
) {
4547 xsltTemplatePtr oldCurTemplRule
= ctxt
->currentTemplateRule
;
4549 * Set the current template rule.
4551 ctxt
->currentTemplateRule
= templ
;
4553 * URGENT TODO: Need xsl:with-param be handled somehow here?
4555 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
,
4558 ctxt
->currentTemplateRule
= oldCurTemplRule
;
4564 * @ctxt: a XSLT transformation context
4565 * @node: the "current node" in the source tree
4566 * @inst: the XSLT 'call-template' instruction
4567 * @castedComp: the compiled information of the instruction
4569 * Processes the XSLT call-template instruction on the source node.
4572 xsltCallTemplate(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4573 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
4575 #ifdef XSLT_REFACTORED
4576 xsltStyleItemCallTemplatePtr comp
=
4577 (xsltStyleItemCallTemplatePtr
) castedComp
;
4579 xsltStylePreCompPtr comp
= castedComp
;
4581 xsltStackElemPtr withParams
= NULL
;
4583 if (ctxt
->insert
== NULL
)
4586 xsltTransformError(ctxt
, NULL
, inst
,
4587 "The XSLT 'call-template' instruction was not compiled.\n");
4592 * The template must have been precomputed
4594 if (comp
->templ
== NULL
) {
4595 comp
->templ
= xsltFindTemplate(ctxt
, comp
->name
, comp
->ns
);
4596 if (comp
->templ
== NULL
) {
4597 if (comp
->ns
!= NULL
) {
4598 xsltTransformError(ctxt
, NULL
, inst
,
4599 "The called template '{%s}%s' was not found.\n",
4600 comp
->ns
, comp
->name
);
4602 xsltTransformError(ctxt
, NULL
, inst
,
4603 "The called template '%s' was not found.\n",
4610 #ifdef WITH_XSLT_DEBUG_PROCESS
4611 if ((comp
!= NULL
) && (comp
->name
!= NULL
))
4612 XSLT_TRACE(ctxt
,XSLT_TRACE_CALL_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
4613 "call-template: name %s\n", comp
->name
));
4616 if (inst
->children
) {
4618 xsltStackElemPtr param
;
4620 cur
= inst
->children
;
4621 while (cur
!= NULL
) {
4622 #ifdef WITH_DEBUGGER
4623 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
4624 xslHandleDebugger(cur
, node
, comp
->templ
, ctxt
);
4626 if (ctxt
->state
== XSLT_STATE_STOPPED
) break;
4628 * TODO: The "with-param"s could be part of the "call-template"
4629 * structure. Avoid to "search" for params dynamically
4630 * in the XML tree every time.
4632 if (IS_XSLT_ELEM(cur
)) {
4633 if (IS_XSLT_NAME(cur
, "with-param")) {
4634 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
4635 if (param
!= NULL
) {
4636 param
->next
= withParams
;
4640 xsltGenericError(xsltGenericErrorContext
,
4641 "xsl:call-template: misplaced xsl:%s\n", cur
->name
);
4644 xsltGenericError(xsltGenericErrorContext
,
4645 "xsl:call-template: misplaced %s element\n", cur
->name
);
4651 * Create a new frame using the params first
4653 xsltApplyXSLTTemplate(ctxt
, node
, comp
->templ
->content
, comp
->templ
,
4655 if (withParams
!= NULL
)
4656 xsltFreeStackElemList(withParams
);
4658 #ifdef WITH_XSLT_DEBUG_PROCESS
4659 if ((comp
!= NULL
) && (comp
->name
!= NULL
))
4660 XSLT_TRACE(ctxt
,XSLT_TRACE_CALL_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
4661 "call-template returned: name %s\n", comp
->name
));
4666 * xsltApplyTemplates:
4667 * @ctxt: a XSLT transformation context
4668 * @node: the 'current node' in the source tree
4669 * @inst: the element node of an XSLT 'apply-templates' instruction
4670 * @castedComp: the compiled instruction
4672 * Processes the XSLT 'apply-templates' instruction on the current node.
4675 xsltApplyTemplates(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4676 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
4678 #ifdef XSLT_REFACTORED
4679 xsltStyleItemApplyTemplatesPtr comp
=
4680 (xsltStyleItemApplyTemplatesPtr
) castedComp
;
4682 xsltStylePreCompPtr comp
= castedComp
;
4685 xmlNodePtr cur
, delNode
= NULL
, oldContextNode
;
4686 xmlNodeSetPtr list
= NULL
, oldList
;
4687 xsltStackElemPtr withParams
= NULL
;
4688 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
4689 const xmlChar
*oldMode
, *oldModeURI
;
4691 xsltDocumentPtr oldDocInfo
;
4692 xmlXPathContextPtr xpctxt
;
4693 xmlNsPtr
*oldXPNamespaces
;
4696 xsltTransformError(ctxt
, NULL
, inst
,
4697 "xsl:apply-templates : compilation failed\n");
4700 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
4703 #ifdef WITH_XSLT_DEBUG_PROCESS
4704 if ((node
!= NULL
) && (node
->name
!= NULL
))
4705 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4706 "xsltApplyTemplates: node: '%s'\n", node
->name
));
4709 xpctxt
= ctxt
->xpathCtxt
;
4711 * Save context states.
4713 oldContextNode
= ctxt
->node
;
4714 oldMode
= ctxt
->mode
;
4715 oldModeURI
= ctxt
->modeURI
;
4716 oldDocInfo
= ctxt
->document
;
4717 oldList
= ctxt
->nodeList
;
4720 * The xpath context size and proximity position, as
4721 * well as the xpath and context documents, may be changed
4722 * so we save their initial state and will restore on exit
4724 oldXPContextSize
= xpctxt
->contextSize
;
4725 oldXPProximityPosition
= xpctxt
->proximityPosition
;
4726 oldXPDoc
= xpctxt
->doc
;
4727 oldXPNsNr
= xpctxt
->nsNr
;
4728 oldXPNamespaces
= xpctxt
->namespaces
;
4733 ctxt
->mode
= comp
->mode
;
4734 ctxt
->modeURI
= comp
->modeURI
;
4736 if (comp
->select
!= NULL
) {
4737 xmlXPathObjectPtr res
= NULL
;
4739 if (comp
->comp
== NULL
) {
4740 xsltTransformError(ctxt
, NULL
, inst
,
4741 "xsl:apply-templates : compilation failed\n");
4744 #ifdef WITH_XSLT_DEBUG_PROCESS
4745 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4746 "xsltApplyTemplates: select %s\n", comp
->select
));
4752 xpctxt
->node
= node
; /* Set the "context node" */
4753 #ifdef XSLT_REFACTORED
4754 if (comp
->inScopeNs
!= NULL
) {
4755 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
4756 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
4758 xpctxt
->namespaces
= NULL
;
4762 xpctxt
->namespaces
= comp
->nsList
;
4763 xpctxt
->nsNr
= comp
->nsNr
;
4765 res
= xmlXPathCompiledEval(comp
->comp
, xpctxt
);
4767 xpctxt
->contextSize
= oldXPContextSize
;
4768 xpctxt
->proximityPosition
= oldXPProximityPosition
;
4770 if (res
->type
== XPATH_NODESET
) {
4771 list
= res
->nodesetval
; /* consume the node set */
4772 res
->nodesetval
= NULL
;
4774 xsltTransformError(ctxt
, NULL
, inst
,
4775 "The 'select' expression did not evaluate to a "
4777 ctxt
->state
= XSLT_STATE_STOPPED
;
4778 xmlXPathFreeObject(res
);
4781 xmlXPathFreeObject(res
);
4783 * Note: An xsl:apply-templates with a 'select' attribute,
4784 * can change the current source doc.
4787 xsltTransformError(ctxt
, NULL
, inst
,
4788 "Failed to evaluate the 'select' expression.\n");
4789 ctxt
->state
= XSLT_STATE_STOPPED
;
4793 #ifdef WITH_XSLT_DEBUG_PROCESS
4794 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4795 "xsltApplyTemplates: select didn't evaluate to a node list\n"));
4801 * NOTE: Previously a document info (xsltDocument) was
4802 * created and attached to the Result Tree Fragment.
4803 * But such a document info is created on demand in
4804 * xsltKeyFunction() (functions.c), so we need to create
4805 * it here beforehand.
4806 * In order to take care of potential keys we need to
4807 * do some extra work for the case when a Result Tree Fragment
4808 * is converted into a nodeset (e.g. exslt:node-set()) :
4809 * We attach a "pseudo-doc" (xsltDocument) to _private.
4810 * This xsltDocument, together with the keyset, will be freed
4811 * when the Result Tree Fragment is freed.
4815 if ((ctxt
->nbKeys
> 0) &&
4816 (list
->nodeNr
!= 0) &&
4817 (list
->nodeTab
[0]->doc
!= NULL
) &&
4818 XSLT_IS_RES_TREE_FRAG(list
->nodeTab
[0]->doc
))
4821 * NOTE that it's also OK if @effectiveDocInfo will be
4825 effectiveDocInfo
= list
->nodeTab
[0]->doc
->_private
;
4830 * Build an XPath node set with the children
4832 list
= xmlXPathNodeSetCreate(NULL
);
4835 cur
= node
->children
;
4836 while (cur
!= NULL
) {
4837 switch (cur
->type
) {
4839 if ((IS_BLANK_NODE(cur
)) &&
4840 (cur
->parent
!= NULL
) &&
4841 (cur
->parent
->type
== XML_ELEMENT_NODE
) &&
4842 (ctxt
->style
->stripSpaces
!= NULL
)) {
4845 if (cur
->parent
->ns
!= NULL
) {
4846 val
= (const xmlChar
*)
4847 xmlHashLookup2(ctxt
->style
->stripSpaces
,
4849 cur
->parent
->ns
->href
);
4851 val
= (const xmlChar
*)
4852 xmlHashLookup2(ctxt
->style
->stripSpaces
,
4854 cur
->parent
->ns
->href
);
4857 val
= (const xmlChar
*)
4858 xmlHashLookup2(ctxt
->style
->stripSpaces
,
4859 cur
->parent
->name
, NULL
);
4861 if ((val
!= NULL
) &&
4862 (xmlStrEqual(val
, (xmlChar
*) "strip"))) {
4867 /* no break on purpose */
4868 case XML_ELEMENT_NODE
:
4869 case XML_DOCUMENT_NODE
:
4870 case XML_HTML_DOCUMENT_NODE
:
4871 case XML_CDATA_SECTION_NODE
:
4873 case XML_COMMENT_NODE
:
4874 xmlXPathNodeSetAddUnique(list
, cur
);
4877 /* Unlink the DTD, it's still reachable
4878 * using doc->intSubset */
4879 if (cur
->next
!= NULL
)
4880 cur
->next
->prev
= cur
->prev
;
4881 if (cur
->prev
!= NULL
)
4882 cur
->prev
->next
= cur
->next
;
4885 #ifdef WITH_XSLT_DEBUG_PROCESS
4886 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4887 "xsltApplyTemplates: skipping cur type %d\n",
4893 if (delNode
!= NULL
) {
4894 #ifdef WITH_XSLT_DEBUG_PROCESS
4895 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4896 "xsltApplyTemplates: removing ignorable blank cur\n"));
4898 xmlUnlinkNode(delNode
);
4899 xmlFreeNode(delNode
);
4905 #ifdef WITH_XSLT_DEBUG_PROCESS
4907 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4908 "xsltApplyTemplates: list of %d nodes\n", list
->nodeNr
));
4911 if ((list
== NULL
) || (list
->nodeNr
== 0))
4915 * Set the context's node set and size; this is also needed for
4916 * for xsltDoSortFunction().
4918 ctxt
->nodeList
= list
;
4920 * Process xsl:with-param and xsl:sort instructions.
4921 * (The code became so verbose just to avoid the
4922 * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
4923 * BUG TODO: We are not using namespaced potentially defined on the
4924 * xsl:sort or xsl:with-param elements; XPath expression might fail.
4926 if (inst
->children
) {
4927 xsltStackElemPtr param
;
4929 cur
= inst
->children
;
4932 #ifdef WITH_DEBUGGER
4933 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
4934 xslHandleDebugger(cur
, node
, NULL
, ctxt
);
4936 if (ctxt
->state
== XSLT_STATE_STOPPED
)
4938 if (cur
->type
== XML_TEXT_NODE
) {
4942 if (! IS_XSLT_ELEM(cur
))
4944 if (IS_XSLT_NAME(cur
, "with-param")) {
4945 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
4946 if (param
!= NULL
) {
4947 param
->next
= withParams
;
4951 if (IS_XSLT_NAME(cur
, "sort")) {
4952 xsltTemplatePtr oldCurTempRule
=
4953 ctxt
->currentTemplateRule
;
4955 xmlNodePtr sorts
[XSLT_MAX_SORT
];
4957 sorts
[nbsorts
++] = cur
;
4961 #ifdef WITH_DEBUGGER
4962 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
4963 xslHandleDebugger(cur
, node
, NULL
, ctxt
);
4965 if (ctxt
->state
== XSLT_STATE_STOPPED
)
4968 if (cur
->type
== XML_TEXT_NODE
) {
4973 if (! IS_XSLT_ELEM(cur
))
4975 if (IS_XSLT_NAME(cur
, "with-param")) {
4976 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
4977 if (param
!= NULL
) {
4978 param
->next
= withParams
;
4982 if (IS_XSLT_NAME(cur
, "sort")) {
4983 if (nbsorts
>= XSLT_MAX_SORT
) {
4984 xsltTransformError(ctxt
, NULL
, cur
,
4985 "The number (%d) of xsl:sort instructions exceeds the "
4986 "maximum allowed by this processor's settings.\n",
4988 ctxt
->state
= XSLT_STATE_STOPPED
;
4991 sorts
[nbsorts
++] = cur
;
4997 * The "current template rule" is cleared for xsl:sort.
4999 ctxt
->currentTemplateRule
= NULL
;
5003 xsltDoSortFunction(ctxt
, sorts
, nbsorts
);
5004 ctxt
->currentTemplateRule
= oldCurTempRule
;
5010 xpctxt
->contextSize
= list
->nodeNr
;
5012 * Apply templates for all selected source nodes.
5014 for (i
= 0; i
< list
->nodeNr
; i
++) {
5015 cur
= list
->nodeTab
[i
];
5017 * The node becomes the "current node".
5021 * An xsl:apply-templates can change the current context doc.
5022 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5024 if ((cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->doc
!= NULL
))
5025 xpctxt
->doc
= cur
->doc
;
5027 xpctxt
->proximityPosition
= i
+ 1;
5029 * Find and apply a template for this node.
5031 xsltProcessOneNode(ctxt
, cur
, withParams
);
5037 * Free the parameter list.
5039 if (withParams
!= NULL
)
5040 xsltFreeStackElemList(withParams
);
5042 xmlXPathFreeNodeSet(list
);
5044 * Restore context states.
5046 xpctxt
->nsNr
= oldXPNsNr
;
5047 xpctxt
->namespaces
= oldXPNamespaces
;
5048 xpctxt
->doc
= oldXPDoc
;
5049 xpctxt
->contextSize
= oldXPContextSize
;
5050 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5052 ctxt
->document
= oldDocInfo
;
5053 ctxt
->nodeList
= oldList
;
5054 ctxt
->node
= oldContextNode
;
5055 ctxt
->mode
= oldMode
;
5056 ctxt
->modeURI
= oldModeURI
;
5062 * @ctxt: a XSLT process context
5063 * @contextNode: the current node in the source tree
5064 * @inst: the xsl:choose instruction
5065 * @comp: compiled information of the instruction
5067 * Processes the xsl:choose instruction on the source node.
5070 xsltChoose(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5071 xmlNodePtr inst
, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED
)
5075 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
))
5079 * TODO: Content model checks should be done only at compilation
5082 cur
= inst
->children
;
5084 xsltTransformError(ctxt
, NULL
, inst
,
5085 "xsl:choose: The instruction has no content.\n");
5089 #ifdef XSLT_REFACTORED
5091 * We don't check the content model during transformation.
5094 if ((! IS_XSLT_ELEM(cur
)) || (! IS_XSLT_NAME(cur
, "when"))) {
5095 xsltTransformError(ctxt
, NULL
, inst
,
5096 "xsl:choose: xsl:when expected first\n");
5102 int testRes
= 0, res
= 0;
5103 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
5104 xmlDocPtr oldXPContextDoc
= xpctxt
->doc
;
5105 int oldXPProximityPosition
= xpctxt
->proximityPosition
;
5106 int oldXPContextSize
= xpctxt
->contextSize
;
5107 xmlNsPtr
*oldXPNamespaces
= xpctxt
->namespaces
;
5108 int oldXPNsNr
= xpctxt
->nsNr
;
5110 #ifdef XSLT_REFACTORED
5111 xsltStyleItemWhenPtr wcomp
= NULL
;
5113 xsltStylePreCompPtr wcomp
= NULL
;
5117 * Process xsl:when ---------------------------------------------------
5119 while (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "when")) {
5122 if ((wcomp
== NULL
) || (wcomp
->test
== NULL
) ||
5123 (wcomp
->comp
== NULL
))
5125 xsltTransformError(ctxt
, NULL
, cur
,
5126 "Internal error in xsltChoose(): "
5127 "The XSLT 'when' instruction was not compiled.\n");
5132 #ifdef WITH_DEBUGGER
5133 if (xslDebugStatus
!= XSLT_DEBUG_NONE
) {
5135 * TODO: Isn't comp->templ always NULL for xsl:choose?
5137 xslHandleDebugger(cur
, contextNode
, NULL
, ctxt
);
5140 #ifdef WITH_XSLT_DEBUG_PROCESS
5141 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5142 "xsltChoose: test %s\n", wcomp
->test
));
5145 xpctxt
->node
= contextNode
;
5146 xpctxt
->doc
= oldXPContextDoc
;
5147 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5148 xpctxt
->contextSize
= oldXPContextSize
;
5150 #ifdef XSLT_REFACTORED
5151 if (wcomp
->inScopeNs
!= NULL
) {
5152 xpctxt
->namespaces
= wcomp
->inScopeNs
->list
;
5153 xpctxt
->nsNr
= wcomp
->inScopeNs
->xpathNumber
;
5155 xpctxt
->namespaces
= NULL
;
5159 xpctxt
->namespaces
= wcomp
->nsList
;
5160 xpctxt
->nsNr
= wcomp
->nsNr
;
5165 res
= xmlXPathCompiledEvalToBoolean(wcomp
->comp
, xpctxt
);
5168 ctxt
->state
= XSLT_STATE_STOPPED
;
5171 testRes
= (res
== 1) ? 1 : 0;
5173 #else /* XSLT_FAST_IF */
5175 res
= xmlXPathCompiledEval(wcomp
->comp
, xpctxt
);
5178 if (res
->type
!= XPATH_BOOLEAN
)
5179 res
= xmlXPathConvertBoolean(res
);
5180 if (res
->type
== XPATH_BOOLEAN
)
5181 testRes
= res
->boolval
;
5183 #ifdef WITH_XSLT_DEBUG_PROCESS
5184 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5185 "xsltChoose: test didn't evaluate to a boolean\n"));
5189 xmlXPathFreeObject(res
);
5192 ctxt
->state
= XSLT_STATE_STOPPED
;
5196 #endif /* else of XSLT_FAST_IF */
5198 #ifdef WITH_XSLT_DEBUG_PROCESS
5199 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5200 "xsltChoose: test evaluate to %d\n", testRes
));
5209 * Process xsl:otherwise ----------------------------------------------
5211 if (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "otherwise")) {
5213 #ifdef WITH_DEBUGGER
5214 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5215 xslHandleDebugger(cur
, contextNode
, NULL
, ctxt
);
5218 #ifdef WITH_XSLT_DEBUG_PROCESS
5219 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5220 "evaluating xsl:otherwise\n"));
5224 xpctxt
->node
= contextNode
;
5225 xpctxt
->doc
= oldXPContextDoc
;
5226 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5227 xpctxt
->contextSize
= oldXPContextSize
;
5228 xpctxt
->namespaces
= oldXPNamespaces
;
5229 xpctxt
->nsNr
= oldXPNsNr
;
5234 xpctxt
->node
= contextNode
;
5235 xpctxt
->doc
= oldXPContextDoc
;
5236 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5237 xpctxt
->contextSize
= oldXPContextSize
;
5238 xpctxt
->namespaces
= oldXPNamespaces
;
5239 xpctxt
->nsNr
= oldXPNsNr
;
5240 goto process_sequence
;
5246 * Instantiate the sequence constructor.
5248 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, cur
->children
,
5258 * @ctxt: a XSLT process context
5259 * @contextNode: the current node in the source tree
5260 * @inst: the xsl:if instruction
5261 * @castedComp: compiled information of the instruction
5263 * Processes the xsl:if instruction on the source node.
5266 xsltIf(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5267 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
5271 #ifdef XSLT_REFACTORED
5272 xsltStyleItemIfPtr comp
= (xsltStyleItemIfPtr
) castedComp
;
5274 xsltStylePreCompPtr comp
= castedComp
;
5277 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
))
5279 if ((comp
== NULL
) || (comp
->test
== NULL
) || (comp
->comp
== NULL
)) {
5280 xsltTransformError(ctxt
, NULL
, inst
,
5281 "Internal error in xsltIf(): "
5282 "The XSLT 'if' instruction was not compiled.\n");
5286 #ifdef WITH_XSLT_DEBUG_PROCESS
5287 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5288 "xsltIf: test %s\n", comp
->test
));
5293 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
5294 xmlDocPtr oldXPContextDoc
= xpctxt
->doc
;
5295 xmlNsPtr
*oldXPNamespaces
= xpctxt
->namespaces
;
5296 xmlNodePtr oldXPContextNode
= xpctxt
->node
;
5297 int oldXPProximityPosition
= xpctxt
->proximityPosition
;
5298 int oldXPContextSize
= xpctxt
->contextSize
;
5299 int oldXPNsNr
= xpctxt
->nsNr
;
5300 xmlDocPtr oldLocalFragmentTop
= ctxt
->localRVT
;
5302 xpctxt
->node
= contextNode
;
5305 #ifdef XSLT_REFACTORED
5306 if (comp
->inScopeNs
!= NULL
) {
5307 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
5308 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
5310 xpctxt
->namespaces
= NULL
;
5314 xpctxt
->namespaces
= comp
->nsList
;
5315 xpctxt
->nsNr
= comp
->nsNr
;
5318 xpctxt
->namespaces
= NULL
;
5322 * This XPath function is optimized for boolean results.
5324 res
= xmlXPathCompiledEvalToBoolean(comp
->comp
, xpctxt
);
5327 * Cleanup fragments created during evaluation of the
5328 * "select" expression.
5330 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
5331 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
5333 xpctxt
->doc
= oldXPContextDoc
;
5334 xpctxt
->node
= oldXPContextNode
;
5335 xpctxt
->contextSize
= oldXPContextSize
;
5336 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5337 xpctxt
->nsNr
= oldXPNsNr
;
5338 xpctxt
->namespaces
= oldXPNamespaces
;
5341 #ifdef WITH_XSLT_DEBUG_PROCESS
5342 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5343 "xsltIf: test evaluate to %d\n", res
));
5347 ctxt
->state
= XSLT_STATE_STOPPED
;
5352 * Instantiate the sequence constructor of xsl:if.
5354 xsltApplySequenceConstructor(ctxt
,
5355 contextNode
, inst
->children
, NULL
);
5358 #else /* XSLT_FAST_IF */
5360 xmlXPathObjectPtr xpobj
= NULL
;
5365 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
5366 xmlDocPtr oldXPContextDoc
= xpctxt
->doc
;
5367 xmlNsPtr
*oldXPNamespaces
= xpctxt
->namespaces
;
5368 xmlNodePtr oldXPContextNode
= xpctxt
->node
;
5369 int oldXPProximityPosition
= xpctxt
->proximityPosition
;
5370 int oldXPContextSize
= xpctxt
->contextSize
;
5371 int oldXPNsNr
= xpctxt
->nsNr
;
5373 xpctxt
->node
= contextNode
;
5376 #ifdef XSLT_REFACTORED
5377 if (comp
->inScopeNs
!= NULL
) {
5378 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
5379 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
5381 xpctxt
->namespaces
= NULL
;
5385 xpctxt
->namespaces
= comp
->nsList
;
5386 xpctxt
->nsNr
= comp
->nsNr
;
5389 xpctxt
->namespaces
= NULL
;
5394 * This XPath function is optimized for boolean results.
5396 xpobj
= xmlXPathCompiledEval(comp
->comp
, xpctxt
);
5398 xpctxt
->doc
= oldXPContextDoc
;
5399 xpctxt
->node
= oldXPContextNode
;
5400 xpctxt
->contextSize
= oldXPContextSize
;
5401 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5402 xpctxt
->nsNr
= oldXPNsNr
;
5403 xpctxt
->namespaces
= oldXPNamespaces
;
5405 if (xpobj
!= NULL
) {
5406 if (xpobj
->type
!= XPATH_BOOLEAN
)
5407 xpobj
= xmlXPathConvertBoolean(xpobj
);
5408 if (xpobj
->type
== XPATH_BOOLEAN
) {
5409 res
= xpobj
->boolval
;
5411 #ifdef WITH_XSLT_DEBUG_PROCESS
5412 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5413 "xsltIf: test evaluate to %d\n", res
));
5416 xsltApplySequenceConstructor(ctxt
,
5417 contextNode
, inst
->children
, NULL
);
5421 #ifdef WITH_XSLT_DEBUG_PROCESS
5422 XSLT_TRACE(ctxt
, XSLT_TRACE_IF
,
5423 xsltGenericDebug(xsltGenericDebugContext
,
5424 "xsltIf: test didn't evaluate to a boolean\n"));
5426 ctxt
->state
= XSLT_STATE_STOPPED
;
5428 xmlXPathFreeObject(xpobj
);
5430 ctxt
->state
= XSLT_STATE_STOPPED
;
5433 #endif /* else of XSLT_FAST_IF */
5441 * @ctxt: an XSLT transformation context
5442 * @contextNode: the "current node" in the source tree
5443 * @inst: the element node of the xsl:for-each instruction
5444 * @castedComp: the compiled information of the instruction
5446 * Process the xslt for-each node on the source node
5449 xsltForEach(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5450 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
5452 #ifdef XSLT_REFACTORED
5453 xsltStyleItemForEachPtr comp
= (xsltStyleItemForEachPtr
) castedComp
;
5455 xsltStylePreCompPtr comp
= castedComp
;
5458 xmlXPathObjectPtr res
= NULL
;
5459 xmlNodePtr cur
, curInst
;
5460 xmlNodeSetPtr list
= NULL
;
5461 xmlNodeSetPtr oldList
;
5462 int oldXPProximityPosition
, oldXPContextSize
;
5463 xmlNodePtr oldContextNode
;
5464 xsltTemplatePtr oldCurTemplRule
;
5466 xsltDocumentPtr oldDocInfo
;
5467 xmlXPathContextPtr xpctxt
;
5469 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
)) {
5470 xsltGenericError(xsltGenericErrorContext
,
5471 "xsltForEach(): Bad arguments.\n");
5476 xsltTransformError(ctxt
, NULL
, inst
,
5477 "Internal error in xsltForEach(): "
5478 "The XSLT 'for-each' instruction was not compiled.\n");
5481 if ((comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
5482 xsltTransformError(ctxt
, NULL
, inst
,
5483 "Internal error in xsltForEach(): "
5484 "The selecting expression of the XSLT 'for-each' "
5485 "instruction was not compiled correctly.\n");
5488 xpctxt
= ctxt
->xpathCtxt
;
5490 #ifdef WITH_XSLT_DEBUG_PROCESS
5491 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5492 "xsltForEach: select %s\n", comp
->select
));
5496 * Save context states.
5498 oldDocInfo
= ctxt
->document
;
5499 oldList
= ctxt
->nodeList
;
5500 oldContextNode
= ctxt
->node
;
5502 * The "current template rule" is cleared for the instantiation of
5505 oldCurTemplRule
= ctxt
->currentTemplateRule
;
5506 ctxt
->currentTemplateRule
= NULL
;
5508 oldXPDoc
= xpctxt
->doc
;
5509 oldXPProximityPosition
= xpctxt
->proximityPosition
;
5510 oldXPContextSize
= xpctxt
->contextSize
;
5514 xpctxt
->node
= contextNode
;
5515 #ifdef XSLT_REFACTORED
5516 if (comp
->inScopeNs
!= NULL
) {
5517 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
5518 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
5520 xpctxt
->namespaces
= NULL
;
5524 xpctxt
->namespaces
= comp
->nsList
;
5525 xpctxt
->nsNr
= comp
->nsNr
;
5529 * Evaluate the 'select' expression.
5531 res
= xmlXPathCompiledEval(comp
->comp
, ctxt
->xpathCtxt
);
5534 if (res
->type
== XPATH_NODESET
)
5535 list
= res
->nodesetval
;
5537 xsltTransformError(ctxt
, NULL
, inst
,
5538 "The 'select' expression does not evaluate to a node set.\n");
5540 #ifdef WITH_XSLT_DEBUG_PROCESS
5541 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5542 "xsltForEach: select didn't evaluate to a node list\n"));
5547 xsltTransformError(ctxt
, NULL
, inst
,
5548 "Failed to evaluate the 'select' expression.\n");
5549 ctxt
->state
= XSLT_STATE_STOPPED
;
5553 if ((list
== NULL
) || (list
->nodeNr
<= 0))
5556 #ifdef WITH_XSLT_DEBUG_PROCESS
5557 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5558 "xsltForEach: select evaluates to %d nodes\n", list
->nodeNr
));
5562 * Restore XPath states for the "current node".
5564 xpctxt
->contextSize
= oldXPContextSize
;
5565 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5566 xpctxt
->node
= contextNode
;
5569 * Set the list; this has to be done already here for xsltDoSortFunction().
5571 ctxt
->nodeList
= list
;
5573 * Handle xsl:sort instructions and skip them for further processing.
5574 * BUG TODO: We are not using namespaced potentially defined on the
5575 * xsl:sort element; XPath expression might fail.
5577 curInst
= inst
->children
;
5578 if (IS_XSLT_ELEM(curInst
) && IS_XSLT_NAME(curInst
, "sort")) {
5580 xmlNodePtr sorts
[XSLT_MAX_SORT
];
5582 sorts
[nbsorts
++] = curInst
;
5584 #ifdef WITH_DEBUGGER
5585 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5586 xslHandleDebugger(curInst
, contextNode
, NULL
, ctxt
);
5589 curInst
= curInst
->next
;
5590 while (IS_XSLT_ELEM(curInst
) && IS_XSLT_NAME(curInst
, "sort")) {
5591 if (nbsorts
>= XSLT_MAX_SORT
) {
5592 xsltTransformError(ctxt
, NULL
, curInst
,
5593 "The number of xsl:sort instructions exceeds the "
5594 "maximum (%d) allowed by this processor.\n",
5598 sorts
[nbsorts
++] = curInst
;
5601 #ifdef WITH_DEBUGGER
5602 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5603 xslHandleDebugger(curInst
, contextNode
, NULL
, ctxt
);
5605 curInst
= curInst
->next
;
5607 xsltDoSortFunction(ctxt
, sorts
, nbsorts
);
5609 xpctxt
->contextSize
= list
->nodeNr
;
5611 * Instantiate the sequence constructor for each selected node.
5613 for (i
= 0; i
< list
->nodeNr
; i
++) {
5614 cur
= list
->nodeTab
[i
];
5616 * The selected node becomes the "current node".
5620 * An xsl:for-each can change the current context doc.
5621 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5623 if ((cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->doc
!= NULL
))
5624 xpctxt
->doc
= cur
->doc
;
5626 xpctxt
->proximityPosition
= i
+ 1;
5628 xsltApplySequenceConstructor(ctxt
, cur
, curInst
, NULL
);
5634 xmlXPathFreeObject(res
);
5636 * Restore old states.
5638 ctxt
->document
= oldDocInfo
;
5639 ctxt
->nodeList
= oldList
;
5640 ctxt
->node
= oldContextNode
;
5641 ctxt
->currentTemplateRule
= oldCurTemplRule
;
5643 xpctxt
->doc
= oldXPDoc
;
5644 xpctxt
->contextSize
= oldXPContextSize
;
5645 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5648 /************************************************************************
5650 * Generic interface *
5652 ************************************************************************/
5654 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5655 typedef struct xsltHTMLVersion
{
5656 const char *version
;
5661 static xsltHTMLVersion xsltHTMLVersions
[] = {
5662 { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5663 "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
5664 { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
5665 "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
5666 { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5667 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5668 { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
5669 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5670 { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
5671 "http://www.w3.org/TR/html4/strict.dtd"},
5672 { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5673 "http://www.w3.org/TR/html4/loose.dtd"},
5674 { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5675 "http://www.w3.org/TR/html4/frameset.dtd"},
5676 { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
5677 "http://www.w3.org/TR/html4/loose.dtd"},
5678 { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL
}
5683 * @version: the version string
5684 * @publicID: used to return the public ID
5685 * @systemID: used to return the system ID
5687 * Returns -1 if not found, 0 otherwise and the system and public
5688 * Identifier for this given verion of HTML
5691 xsltGetHTMLIDs(const xmlChar
*version
, const xmlChar
**publicID
,
5692 const xmlChar
**systemID
) {
5694 if (version
== NULL
)
5696 for (i
= 0;i
< (sizeof(xsltHTMLVersions
)/sizeof(xsltHTMLVersions
[1]));
5698 if (!xmlStrcasecmp(version
,
5699 (const xmlChar
*) xsltHTMLVersions
[i
].version
)) {
5700 if (publicID
!= NULL
)
5701 *publicID
= (const xmlChar
*) xsltHTMLVersions
[i
].public;
5702 if (systemID
!= NULL
)
5703 *systemID
= (const xmlChar
*) xsltHTMLVersions
[i
].system
;
5712 * xsltApplyStripSpaces:
5713 * @ctxt: a XSLT process context
5714 * @node: the root of the XML tree
5716 * Strip the unwanted ignorable spaces from the input tree
5719 xsltApplyStripSpaces(xsltTransformContextPtr ctxt
, xmlNodePtr node
) {
5721 #ifdef WITH_XSLT_DEBUG_PROCESS
5727 while (current
!= NULL
) {
5729 * Cleanup children empty nodes if asked for
5731 if ((IS_XSLT_REAL_NODE(current
)) &&
5732 (current
->children
!= NULL
) &&
5733 (xsltFindElemSpaceHandling(ctxt
, current
))) {
5734 xmlNodePtr
delete = NULL
, cur
= current
->children
;
5736 while (cur
!= NULL
) {
5737 if (IS_BLANK_NODE(cur
))
5741 if (delete != NULL
) {
5742 xmlUnlinkNode(delete);
5743 xmlFreeNode(delete);
5745 #ifdef WITH_XSLT_DEBUG_PROCESS
5753 * Skip to next node in document order.
5755 if (node
->type
== XML_ENTITY_REF_NODE
) {
5756 /* process deep in entities */
5757 xsltApplyStripSpaces(ctxt
, node
->children
);
5759 if ((current
->children
!= NULL
) &&
5760 (current
->type
!= XML_ENTITY_REF_NODE
)) {
5761 current
= current
->children
;
5762 } else if (current
->next
!= NULL
) {
5763 current
= current
->next
;
5766 current
= current
->parent
;
5767 if (current
== NULL
)
5769 if (current
== node
)
5771 if (current
->next
!= NULL
) {
5772 current
= current
->next
;
5775 } while (current
!= NULL
);
5780 #ifdef WITH_XSLT_DEBUG_PROCESS
5781 XSLT_TRACE(ctxt
,XSLT_TRACE_STRIP_SPACES
,xsltGenericDebug(xsltGenericDebugContext
,
5782 "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb
));
5788 xsltCountKeys(xsltTransformContextPtr ctxt
)
5790 xsltStylesheetPtr style
;
5797 * Do we have those nastly templates with a key() in the match pattern?
5799 ctxt
->hasTemplKeyPatterns
= 0;
5800 style
= ctxt
->style
;
5801 while (style
!= NULL
) {
5802 if (style
->keyMatch
!= NULL
) {
5803 ctxt
->hasTemplKeyPatterns
= 1;
5806 style
= xsltNextImport(style
);
5809 * Count number of key declarations.
5812 style
= ctxt
->style
;
5813 while (style
!= NULL
) {
5819 style
= xsltNextImport(style
);
5821 return(ctxt
->nbKeys
);
5825 * xsltApplyStylesheetInternal:
5826 * @style: a parsed XSLT stylesheet
5827 * @doc: a parsed XML document
5828 * @params: a NULL terminated array of parameters names/values tuples
5829 * @output: the targetted output
5830 * @profile: profile FILE * output or NULL
5831 * @user: user provided parameter
5833 * Apply the stylesheet to the document
5834 * NOTE: This may lead to a non-wellformed output XML wise !
5836 * Returns the result document or NULL in case of error
5839 xsltApplyStylesheetInternal(xsltStylesheetPtr style
, xmlDocPtr doc
,
5840 const char **params
, const char *output
,
5841 FILE * profile
, xsltTransformContextPtr userCtxt
)
5843 xmlDocPtr res
= NULL
;
5844 xsltTransformContextPtr ctxt
= NULL
;
5845 xmlNodePtr root
, node
;
5846 const xmlChar
*method
;
5847 const xmlChar
*doctypePublic
;
5848 const xmlChar
*doctypeSystem
;
5849 const xmlChar
*version
;
5850 const xmlChar
*encoding
;
5851 xsltStackElemPtr variables
;
5852 xsltStackElemPtr vptr
;
5856 if ((style
== NULL
) || (doc
== NULL
))
5859 if (style
->internalized
== 0) {
5860 #ifdef WITH_XSLT_DEBUG
5861 xsltGenericDebug(xsltGenericDebugContext
,
5862 "Stylesheet was not fully internalized !\n");
5865 if (doc
->intSubset
!= NULL
) {
5867 * Avoid hitting the DTD when scanning nodes
5868 * but keep it linked as doc->intSubset
5870 xmlNodePtr cur
= (xmlNodePtr
) doc
->intSubset
;
5871 if (cur
->next
!= NULL
)
5872 cur
->next
->prev
= cur
->prev
;
5873 if (cur
->prev
!= NULL
)
5874 cur
->prev
->next
= cur
->next
;
5875 if (doc
->children
== cur
)
5876 doc
->children
= cur
->next
;
5877 if (doc
->last
== cur
)
5878 doc
->last
= cur
->prev
;
5879 cur
->prev
= cur
->next
= NULL
;
5883 * Check for XPath document order availability
5885 root
= xmlDocGetRootElement(doc
);
5887 if (((long) root
->content
) >= 0 && (xslDebugStatus
== XSLT_DEBUG_NONE
))
5888 xmlXPathOrderDocElems(doc
);
5891 if (userCtxt
!= NULL
)
5894 ctxt
= xsltNewTransformContext(style
, doc
);
5899 ctxt
->initialContextDoc
= doc
;
5900 ctxt
->initialContextNode
= (xmlNodePtr
) doc
;
5902 if (profile
!= NULL
)
5906 ctxt
->outputFile
= output
;
5908 ctxt
->outputFile
= NULL
;
5911 * internalize the modes if needed
5913 if (ctxt
->dict
!= NULL
) {
5914 if (ctxt
->mode
!= NULL
)
5915 ctxt
->mode
= xmlDictLookup(ctxt
->dict
, ctxt
->mode
, -1);
5916 if (ctxt
->modeURI
!= NULL
)
5917 ctxt
->modeURI
= xmlDictLookup(ctxt
->dict
, ctxt
->modeURI
, -1);
5920 XSLT_GET_IMPORT_PTR(method
, style
, method
)
5921 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
5922 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
5923 XSLT_GET_IMPORT_PTR(version
, style
, version
)
5924 XSLT_GET_IMPORT_PTR(encoding
, style
, encoding
)
5926 if ((method
!= NULL
) &&
5927 (!xmlStrEqual(method
, (const xmlChar
*) "xml")))
5929 if (xmlStrEqual(method
, (const xmlChar
*) "html")) {
5930 ctxt
->type
= XSLT_OUTPUT_HTML
;
5931 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
5932 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5934 if (version
== NULL
) {
5937 res
= htmlNewDoc(NULL
, NULL
);
5939 * Make sure no DTD node is generated in this case
5942 dtd
= xmlGetIntSubset(res
);
5944 xmlUnlinkNode((xmlNodePtr
) dtd
);
5947 res
->intSubset
= NULL
;
5948 res
->extSubset
= NULL
;
5952 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5953 xsltGetHTMLIDs(version
, &doctypePublic
, &doctypeSystem
);
5955 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5960 res
->dict
= ctxt
->dict
;
5961 xmlDictReference(res
->dict
);
5963 #ifdef WITH_XSLT_DEBUG
5964 xsltGenericDebug(xsltGenericDebugContext
,
5965 "reusing transformation dict for output\n");
5967 } else if (xmlStrEqual(method
, (const xmlChar
*) "xhtml")) {
5968 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
5969 "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n",
5971 ctxt
->type
= XSLT_OUTPUT_HTML
;
5972 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5975 res
->dict
= ctxt
->dict
;
5976 xmlDictReference(res
->dict
);
5978 #ifdef WITH_XSLT_DEBUG
5979 xsltGenericDebug(xsltGenericDebugContext
,
5980 "reusing transformation dict for output\n");
5982 } else if (xmlStrEqual(method
, (const xmlChar
*) "text")) {
5983 ctxt
->type
= XSLT_OUTPUT_TEXT
;
5984 res
= xmlNewDoc(style
->version
);
5987 res
->dict
= ctxt
->dict
;
5988 xmlDictReference(res
->dict
);
5990 #ifdef WITH_XSLT_DEBUG
5991 xsltGenericDebug(xsltGenericDebugContext
,
5992 "reusing transformation dict for output\n");
5995 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
5996 "xsltApplyStylesheetInternal: unsupported method %s\n",
6001 ctxt
->type
= XSLT_OUTPUT_XML
;
6002 res
= xmlNewDoc(style
->version
);
6005 res
->dict
= ctxt
->dict
;
6006 xmlDictReference(ctxt
->dict
);
6007 #ifdef WITH_XSLT_DEBUG
6008 xsltGenericDebug(xsltGenericDebugContext
,
6009 "reusing transformation dict for output\n");
6012 res
->charset
= XML_CHAR_ENCODING_UTF8
;
6013 if (encoding
!= NULL
)
6014 res
->encoding
= xmlStrdup(encoding
);
6015 variables
= style
->variables
;
6018 * Start the evaluation, evaluate the params, the stylesheets globals
6019 * and start by processing the top node.
6021 if (xsltNeedElemSpaceHandling(ctxt
))
6022 xsltApplyStripSpaces(ctxt
, xmlDocGetRootElement(doc
));
6024 * Evaluate global params and user-provided params.
6026 ctxt
->node
= (xmlNodePtr
) doc
;
6027 if (ctxt
->globalVars
== NULL
)
6028 ctxt
->globalVars
= xmlHashCreate(20);
6029 if (params
!= NULL
) {
6030 xsltEvalUserParams(ctxt
, params
);
6033 /* need to be called before evaluating global variables */
6034 xsltCountKeys(ctxt
);
6036 xsltEvalGlobalVariables(ctxt
);
6038 ctxt
->node
= (xmlNodePtr
) doc
;
6040 ctxt
->insert
= (xmlNodePtr
) res
;
6041 ctxt
->varsBase
= ctxt
->varsNr
- 1;
6043 ctxt
->xpathCtxt
->contextSize
= 1;
6044 ctxt
->xpathCtxt
->proximityPosition
= 1;
6045 ctxt
->xpathCtxt
->node
= NULL
; /* TODO: Set the context node here? */
6047 * Start processing the source tree -----------------------------------
6049 xsltProcessOneNode(ctxt
, ctxt
->node
, NULL
);
6051 * Remove all remaining vars from the stack.
6053 xsltLocalVariablePop(ctxt
, 0, -2);
6054 xsltShutdownCtxtExts(ctxt
);
6056 xsltCleanupTemplates(style
); /* TODO: <- style should be read only */
6059 * Now cleanup our variables so stylesheet can be re-used
6061 * TODO: this is not needed anymore global variables are copied
6062 * and not evaluated directly anymore, keep this as a check
6064 if (style
->variables
!= variables
) {
6065 vptr
= style
->variables
;
6066 while (vptr
->next
!= variables
)
6069 xsltFreeStackElemList(style
->variables
);
6070 style
->variables
= variables
;
6072 vptr
= style
->variables
;
6073 while (vptr
!= NULL
) {
6074 if (vptr
->computed
) {
6075 if (vptr
->value
!= NULL
) {
6076 xmlXPathFreeObject(vptr
->value
);
6085 * code disabled by wmb; awaiting kb's review
6086 * problem is that global variable(s) may contain xpath objects
6087 * from doc associated with RVT, so can't be freed at this point.
6088 * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
6089 * I assume this shouldn't be required at this point.
6092 * Free all remaining tree fragments.
6097 * Do some post processing work depending on the generated output
6099 root
= xmlDocGetRootElement(res
);
6101 const xmlChar
*doctype
= NULL
;
6103 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
))
6104 doctype
= xmlDictQLookup(ctxt
->dict
, root
->ns
->prefix
, root
->name
);
6105 if (doctype
== NULL
)
6106 doctype
= root
->name
;
6109 * Apply the default selection of the method
6111 if ((method
== NULL
) &&
6112 (root
->ns
== NULL
) &&
6113 (!xmlStrcasecmp(root
->name
, (const xmlChar
*) "html"))) {
6116 tmp
= res
->children
;
6117 while ((tmp
!= NULL
) && (tmp
!= root
)) {
6118 if (tmp
->type
== XML_ELEMENT_NODE
)
6120 if ((tmp
->type
== XML_TEXT_NODE
) && (!xmlIsBlankNode(tmp
)))
6125 ctxt
->type
= XSLT_OUTPUT_HTML
;
6127 * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
6128 * transformation on the doc, but functions like
6130 res
->type
= XML_HTML_DOCUMENT_NODE
;
6131 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
6132 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
6135 #ifdef XSLT_GENERATE_HTML_DOCTYPE
6136 } else if (version
!= NULL
) {
6137 xsltGetHTMLIDs(version
, &doctypePublic
,
6139 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
6141 xmlCreateIntSubset(res
, doctype
,
6149 if (ctxt
->type
== XSLT_OUTPUT_XML
) {
6150 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
6151 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
6152 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
6154 /* Need a small "hack" here to assure DTD comes before
6155 possible comment nodes */
6156 node
= res
->children
;
6158 res
->children
= NULL
;
6160 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
6163 if (res
->children
!= NULL
) {
6164 res
->children
->next
= node
;
6165 node
->prev
= res
->children
;
6168 res
->children
= node
;
6174 xmlXPathFreeNodeSet(ctxt
->nodeList
);
6175 if (profile
!= NULL
) {
6176 xsltSaveProfiling(ctxt
, profile
);
6182 if ((ctxt
!= NULL
) && (ctxt
->state
== XSLT_STATE_ERROR
)) {
6186 if ((res
!= NULL
) && (ctxt
!= NULL
) && (output
!= NULL
)) {
6189 ret
= xsltCheckWrite(ctxt
->sec
, ctxt
, (const xmlChar
*) output
);
6191 xsltTransformError(ctxt
, NULL
, NULL
,
6192 "xsltApplyStylesheet: forbidden to save to %s\n",
6194 } else if (ret
< 0) {
6195 xsltTransformError(ctxt
, NULL
, NULL
,
6196 "xsltApplyStylesheet: saving to %s may not be possible\n",
6201 #ifdef XSLT_DEBUG_PROFILE_CACHE
6202 printf("# Cache:\n");
6203 printf("# Reused tree fragments: %d\n", ctxt
->cache
->dbgReusedRVTs
);
6204 printf("# Reused variables : %d\n", ctxt
->cache
->dbgReusedVars
);
6207 if ((ctxt
!= NULL
) && (userCtxt
== NULL
))
6208 xsltFreeTransformContext(ctxt
);
6216 #ifdef XSLT_DEBUG_PROFILE_CACHE
6217 printf("# Cache:\n");
6218 printf("# Reused tree fragments: %d\n", ctxt
->cache
->dbgReusedRVTs
);
6219 printf("# Reused variables : %d\n", ctxt
->cache
->dbgReusedVars
);
6222 if ((ctxt
!= NULL
) && (userCtxt
== NULL
))
6223 xsltFreeTransformContext(ctxt
);
6228 * xsltApplyStylesheet:
6229 * @style: a parsed XSLT stylesheet
6230 * @doc: a parsed XML document
6231 * @params: a NULL terminated arry of parameters names/values tuples
6233 * Apply the stylesheet to the document
6234 * NOTE: This may lead to a non-wellformed output XML wise !
6236 * Returns the result document or NULL in case of error
6239 xsltApplyStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6240 const char **params
)
6242 return (xsltApplyStylesheetInternal(style
, doc
, params
, NULL
, NULL
, NULL
));
6246 * xsltProfileStylesheet:
6247 * @style: a parsed XSLT stylesheet
6248 * @doc: a parsed XML document
6249 * @params: a NULL terminated arry of parameters names/values tuples
6250 * @output: a FILE * for the profiling output
6252 * Apply the stylesheet to the document and dump the profiling to
6255 * Returns the result document or NULL in case of error
6258 xsltProfileStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6259 const char **params
, FILE * output
)
6263 res
= xsltApplyStylesheetInternal(style
, doc
, params
, NULL
, output
, NULL
);
6268 * xsltApplyStylesheetUser:
6269 * @style: a parsed XSLT stylesheet
6270 * @doc: a parsed XML document
6271 * @params: a NULL terminated array of parameters names/values tuples
6272 * @output: the targetted output
6273 * @profile: profile FILE * output or NULL
6274 * @userCtxt: user provided transform context
6276 * Apply the stylesheet to the document and allow the user to provide
6277 * its own transformation context.
6279 * Returns the result document or NULL in case of error
6282 xsltApplyStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
,
6283 const char **params
, const char *output
,
6284 FILE * profile
, xsltTransformContextPtr userCtxt
)
6288 res
= xsltApplyStylesheetInternal(style
, doc
, params
, output
,
6294 * xsltRunStylesheetUser:
6295 * @style: a parsed XSLT stylesheet
6296 * @doc: a parsed XML document
6297 * @params: a NULL terminated array of parameters names/values tuples
6298 * @output: the URL/filename ot the generated resource if available
6299 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6300 * @IObuf: an output buffer for progressive output (not implemented yet)
6301 * @profile: profile FILE * output or NULL
6302 * @userCtxt: user provided transform context
6304 * Apply the stylesheet to the document and generate the output according
6305 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6307 * NOTE: This may lead to a non-wellformed output XML wise !
6308 * NOTE: This may also result in multiple files being generated
6309 * NOTE: using IObuf, the result encoding used will be the one used for
6310 * creating the output buffer, use the following macro to read it
6311 * from the stylesheet
6312 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6313 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6314 * since the interface uses only UTF8
6316 * Returns the number of by written to the main resource or -1 in case of
6320 xsltRunStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
,
6321 const char **params
, const char *output
,
6322 xmlSAXHandlerPtr SAX
, xmlOutputBufferPtr IObuf
,
6323 FILE * profile
, xsltTransformContextPtr userCtxt
)
6328 if ((output
== NULL
) && (SAX
== NULL
) && (IObuf
== NULL
))
6330 if ((SAX
!= NULL
) && (IObuf
!= NULL
))
6333 /* unsupported yet */
6335 XSLT_TODO
/* xsltRunStylesheet xmlSAXHandlerPtr SAX */
6339 tmp
= xsltApplyStylesheetInternal(style
, doc
, params
, output
, profile
,
6342 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
6343 "xsltRunStylesheet : run failed\n");
6346 if (IObuf
!= NULL
) {
6347 /* TODO: incomplete, IObuf output not progressive */
6348 ret
= xsltSaveResultTo(IObuf
, tmp
, style
);
6350 ret
= xsltSaveResultToFilename(output
, tmp
, style
, 0);
6357 * xsltRunStylesheet:
6358 * @style: a parsed XSLT stylesheet
6359 * @doc: a parsed XML document
6360 * @params: a NULL terminated array of parameters names/values tuples
6361 * @output: the URL/filename ot the generated resource if available
6362 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6363 * @IObuf: an output buffer for progressive output (not implemented yet)
6365 * Apply the stylesheet to the document and generate the output according
6366 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6368 * NOTE: This may lead to a non-wellformed output XML wise !
6369 * NOTE: This may also result in multiple files being generated
6370 * NOTE: using IObuf, the result encoding used will be the one used for
6371 * creating the output buffer, use the following macro to read it
6372 * from the stylesheet
6373 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6374 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6375 * since the interface uses only UTF8
6377 * Returns the number of bytes written to the main resource or -1 in case of
6381 xsltRunStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6382 const char **params
, const char *output
,
6383 xmlSAXHandlerPtr SAX
, xmlOutputBufferPtr IObuf
)
6385 return(xsltRunStylesheetUser(style
, doc
, params
, output
, SAX
, IObuf
,
6390 * xsltRegisterAllElement:
6391 * @ctxt: the XPath context
6393 * Registers all default XSLT elements in this context
6396 xsltRegisterAllElement(xsltTransformContextPtr ctxt
)
6398 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "apply-templates",
6400 (xsltTransformFunction
) xsltApplyTemplates
);
6401 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "apply-imports",
6403 (xsltTransformFunction
) xsltApplyImports
);
6404 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "call-template",
6406 (xsltTransformFunction
) xsltCallTemplate
);
6407 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "element",
6409 (xsltTransformFunction
) xsltElement
);
6410 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "attribute",
6412 (xsltTransformFunction
) xsltAttribute
);
6413 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "text",
6415 (xsltTransformFunction
) xsltText
);
6416 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "processing-instruction",
6418 (xsltTransformFunction
) xsltProcessingInstruction
);
6419 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "comment",
6421 (xsltTransformFunction
) xsltComment
);
6422 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "copy",
6424 (xsltTransformFunction
) xsltCopy
);
6425 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "value-of",
6427 (xsltTransformFunction
) xsltValueOf
);
6428 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "number",
6430 (xsltTransformFunction
) xsltNumber
);
6431 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "for-each",
6433 (xsltTransformFunction
) xsltForEach
);
6434 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "if",
6436 (xsltTransformFunction
) xsltIf
);
6437 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "choose",
6439 (xsltTransformFunction
) xsltChoose
);
6440 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "sort",
6442 (xsltTransformFunction
) xsltSort
);
6443 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "copy-of",
6445 (xsltTransformFunction
) xsltCopyOf
);
6446 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "message",
6448 (xsltTransformFunction
) xsltMessage
);
6451 * Those don't have callable entry points but are registered anyway
6453 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "variable",
6455 (xsltTransformFunction
) xsltDebug
);
6456 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "param",
6458 (xsltTransformFunction
) xsltDebug
);
6459 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "with-param",
6461 (xsltTransformFunction
) xsltDebug
);
6462 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "decimal-format",
6464 (xsltTransformFunction
) xsltDebug
);
6465 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "when",
6467 (xsltTransformFunction
) xsltDebug
);
6468 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "otherwise",
6470 (xsltTransformFunction
) xsltDebug
);
6471 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "fallback",
6473 (xsltTransformFunction
) xsltDebug
);