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.
27 #include <libxml/xmlmemory.h>
28 #include <libxml/parser.h>
29 #include <libxml/tree.h>
30 #include <libxml/valid.h>
31 #include <libxml/hash.h>
32 #include <libxml/encoding.h>
33 #include <libxml/xmlerror.h>
34 #include <libxml/xpath.h>
35 #include <libxml/parserInternals.h>
36 #include <libxml/xpathInternals.h>
37 #include <libxml/HTMLtree.h>
38 #include <libxml/debugXML.h>
39 #include <libxml/uri.h>
41 #include "xsltInternals.h"
42 #include "xsltutils.h"
43 #include "xsltlocale.h"
45 #include "transform.h"
46 #include "variables.h"
47 #include "numbersInternals.h"
48 #include "namespaces.h"
49 #include "attributes.h"
50 #include "templates.h"
53 #include "documents.h"
54 #include "extensions.h"
59 #ifdef WITH_XSLT_DEBUG
60 #define WITH_XSLT_DEBUG_EXTRA
61 #define WITH_XSLT_DEBUG_PROCESS
62 #define WITH_XSLT_DEBUG_VARIABLE
65 #define XSLT_GENERATE_HTML_DOCTYPE
66 #ifdef XSLT_GENERATE_HTML_DOCTYPE
67 static int xsltGetHTMLIDs(const xmlChar
*version
, const xmlChar
**publicID
,
68 const xmlChar
**systemID
);
71 int xsltMaxDepth
= 3000;
72 int xsltMaxVars
= 15000;
79 # define FALSE (0 == 1)
80 # define TRUE (!FALSE)
83 #define IS_BLANK_NODE(n) \
84 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
88 * Forward declarations
92 xsltCopyNamespaceListInternal(xmlNodePtr node
, xmlNsPtr cur
);
95 xsltCopyTree(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
96 xmlNodePtr node
, xmlNodePtr insert
, int isLRE
,
100 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt
,
101 xmlNodePtr contextNode
, xmlNodePtr list
,
102 xsltTemplatePtr templ
);
105 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt
,
106 xmlNodePtr contextNode
,
108 xsltTemplatePtr templ
,
109 xsltStackElemPtr withParams
);
113 * @ctxt: the transformation context
114 * @value: the template to push on the stack
116 * Push a template on the stack
118 * Returns the new index in the stack or 0 in case of error
121 templPush(xsltTransformContextPtr ctxt
, xsltTemplatePtr value
)
123 if (ctxt
->templNr
>= ctxt
->templMax
) {
124 xsltTemplatePtr
*tmp
;
125 int newMax
= ctxt
->templMax
== 0 ? 4 : ctxt
->templMax
* 2;
127 tmp
= (xsltTemplatePtr
*) xmlRealloc(ctxt
->templTab
,
128 newMax
* sizeof(*tmp
));
130 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
133 ctxt
->templTab
= tmp
;
134 ctxt
->templMax
= newMax
;
136 ctxt
->templTab
[ctxt
->templNr
] = value
;
138 return (ctxt
->templNr
++);
142 * @ctxt: the transformation context
144 * Pop a template value from the stack
146 * Returns the stored template value
148 static xsltTemplatePtr
149 templPop(xsltTransformContextPtr ctxt
)
153 if (ctxt
->templNr
<= 0)
156 if (ctxt
->templNr
> 0)
157 ctxt
->templ
= ctxt
->templTab
[ctxt
->templNr
- 1];
159 ctxt
->templ
= (xsltTemplatePtr
) 0;
160 ret
= ctxt
->templTab
[ctxt
->templNr
];
161 ctxt
->templTab
[ctxt
->templNr
] = 0;
166 * xsltLocalVariablePop:
167 * @ctxt: the transformation context
168 * @limitNr: number of variables which should remain
169 * @level: the depth in the xsl:template's tree
171 * Pops all variable values at the given @depth from the stack.
173 * Returns the stored variable value
175 * This is an internal routine and should not be called by users!
178 xsltLocalVariablePop(xsltTransformContextPtr ctxt
, int limitNr
, int level
)
180 xsltStackElemPtr variable
;
182 if (ctxt
->varsNr
<= 0)
186 if (ctxt
->varsNr
<= limitNr
)
188 variable
= ctxt
->varsTab
[ctxt
->varsNr
- 1];
189 if (variable
->level
<= level
)
191 if (variable
->level
>= 0)
192 xsltFreeStackElemList(variable
);
194 } while (ctxt
->varsNr
!= 0);
195 if (ctxt
->varsNr
> 0)
196 ctxt
->vars
= ctxt
->varsTab
[ctxt
->varsNr
- 1];
202 * xsltTemplateParamsCleanup:
204 * Removes xsl:param and xsl:with-param items from the
205 * variable-stack. Only xsl:with-param items are not freed.
208 xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt
)
210 xsltStackElemPtr param
;
212 for (; ctxt
->varsNr
> ctxt
->varsBase
; ctxt
->varsNr
--) {
213 param
= ctxt
->varsTab
[ctxt
->varsNr
-1];
215 * Free xsl:param items.
216 * xsl:with-param items will have a level of -1 or -2.
218 if (param
->level
>= 0) {
219 xsltFreeStackElemList(param
);
222 if (ctxt
->varsNr
> 0)
223 ctxt
->vars
= ctxt
->varsTab
[ctxt
->varsNr
- 1];
232 * @ctxt: the transformation context
233 * @value: the profiling value to push on the stack
235 * Push a profiling value on the stack
237 * Returns the new index in the stack or 0 in case of error
240 profPush(xsltTransformContextPtr ctxt
, long value
)
242 if (ctxt
->profMax
== 0) {
245 (long *) xmlMalloc(ctxt
->profMax
* sizeof(ctxt
->profTab
[0]));
246 if (ctxt
->profTab
== NULL
) {
247 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
251 else if (ctxt
->profNr
>= ctxt
->profMax
) {
254 (long *) xmlRealloc(ctxt
->profTab
,
255 ctxt
->profMax
* sizeof(ctxt
->profTab
[0]));
256 if (ctxt
->profTab
== NULL
) {
257 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
261 ctxt
->profTab
[ctxt
->profNr
] = value
;
263 return (ctxt
->profNr
++);
267 * @ctxt: the transformation context
269 * Pop a profiling value from the stack
271 * Returns the stored profiling value
274 profPop(xsltTransformContextPtr ctxt
)
278 if (ctxt
->profNr
<= 0)
281 if (ctxt
->profNr
> 0)
282 ctxt
->prof
= ctxt
->profTab
[ctxt
->profNr
- 1];
284 ctxt
->prof
= (long) 0;
285 ret
= ctxt
->profTab
[ctxt
->profNr
];
286 ctxt
->profTab
[ctxt
->profNr
] = 0;
291 profCallgraphAdd(xsltTemplatePtr templ
, xsltTemplatePtr parent
)
295 if (templ
->templMax
== 0) {
297 templ
->templCalledTab
=
298 (xsltTemplatePtr
*) xmlMalloc(templ
->templMax
*
299 sizeof(templ
->templCalledTab
[0]));
300 templ
->templCountTab
=
301 (int *) xmlMalloc(templ
->templMax
*
302 sizeof(templ
->templCountTab
[0]));
303 if (templ
->templCalledTab
== NULL
|| templ
->templCountTab
== NULL
) {
304 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
308 else if (templ
->templNr
>= templ
->templMax
) {
309 templ
->templMax
*= 2;
310 templ
->templCalledTab
=
311 (xsltTemplatePtr
*) xmlRealloc(templ
->templCalledTab
,
313 sizeof(templ
->templCalledTab
[0]));
314 templ
->templCountTab
=
315 (int *) xmlRealloc(templ
->templCountTab
,
317 sizeof(templ
->templCountTab
[0]));
318 if (templ
->templCalledTab
== NULL
|| templ
->templCountTab
== NULL
) {
319 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
324 for (i
= 0; i
< templ
->templNr
; i
++) {
325 if (templ
->templCalledTab
[i
] == parent
) {
326 templ
->templCountTab
[i
]++;
330 if (i
== templ
->templNr
) {
331 /* not found, add new one */
332 templ
->templCalledTab
[templ
->templNr
] = parent
;
333 templ
->templCountTab
[templ
->templNr
] = 1;
338 #endif /* WITH_PROFILER */
342 * @ctxt: transform context
343 * @node: context node
344 * @comp: precompiled expression
346 * Evaluate a precompiled XPath expression.
348 static xmlXPathObjectPtr
349 xsltPreCompEval(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
350 xsltStylePreCompPtr comp
) {
351 xmlXPathObjectPtr res
;
352 xmlXPathContextPtr xpctxt
;
353 xmlNodePtr oldXPContextNode
;
354 xmlNsPtr
*oldXPNamespaces
;
355 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
357 xpctxt
= ctxt
->xpathCtxt
;
358 oldXPContextNode
= xpctxt
->node
;
359 oldXPProximityPosition
= xpctxt
->proximityPosition
;
360 oldXPContextSize
= xpctxt
->contextSize
;
361 oldXPNsNr
= xpctxt
->nsNr
;
362 oldXPNamespaces
= xpctxt
->namespaces
;
365 #ifdef XSLT_REFACTORED
366 if (comp
->inScopeNs
!= NULL
) {
367 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
368 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
370 xpctxt
->namespaces
= NULL
;
374 xpctxt
->namespaces
= comp
->nsList
;
375 xpctxt
->nsNr
= comp
->nsNr
;
378 res
= xmlXPathCompiledEval(comp
->comp
, xpctxt
);
380 xpctxt
->node
= oldXPContextNode
;
381 xpctxt
->proximityPosition
= oldXPProximityPosition
;
382 xpctxt
->contextSize
= oldXPContextSize
;
383 xpctxt
->nsNr
= oldXPNsNr
;
384 xpctxt
->namespaces
= oldXPNamespaces
;
390 * xsltPreCompEvalToBoolean:
391 * @ctxt: transform context
392 * @node: context node
393 * @comp: precompiled expression
395 * Evaluate a precompiled XPath expression as boolean.
398 xsltPreCompEvalToBoolean(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
399 xsltStylePreCompPtr comp
) {
401 xmlXPathContextPtr xpctxt
;
402 xmlNodePtr oldXPContextNode
;
403 xmlNsPtr
*oldXPNamespaces
;
404 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
406 xpctxt
= ctxt
->xpathCtxt
;
407 oldXPContextNode
= xpctxt
->node
;
408 oldXPProximityPosition
= xpctxt
->proximityPosition
;
409 oldXPContextSize
= xpctxt
->contextSize
;
410 oldXPNsNr
= xpctxt
->nsNr
;
411 oldXPNamespaces
= xpctxt
->namespaces
;
414 #ifdef XSLT_REFACTORED
415 if (comp
->inScopeNs
!= NULL
) {
416 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
417 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
419 xpctxt
->namespaces
= NULL
;
423 xpctxt
->namespaces
= comp
->nsList
;
424 xpctxt
->nsNr
= comp
->nsNr
;
427 res
= xmlXPathCompiledEvalToBoolean(comp
->comp
, xpctxt
);
429 xpctxt
->node
= oldXPContextNode
;
430 xpctxt
->proximityPosition
= oldXPProximityPosition
;
431 xpctxt
->contextSize
= oldXPContextSize
;
432 xpctxt
->nsNr
= oldXPNsNr
;
433 xpctxt
->namespaces
= oldXPNamespaces
;
438 /************************************************************************
440 * XInclude default settings *
442 ************************************************************************/
444 static int xsltDoXIncludeDefault
= 0;
447 * xsltSetXIncludeDefault:
448 * @xinclude: whether to do XInclude processing
450 * Set whether XInclude should be processed on document being loaded by default
453 xsltSetXIncludeDefault(int xinclude
) {
454 xsltDoXIncludeDefault
= (xinclude
!= 0);
458 * xsltGetXIncludeDefault:
460 * Provides the default state for XInclude processing
462 * Returns 0 if there is no processing 1 otherwise
465 xsltGetXIncludeDefault(void) {
466 return(xsltDoXIncludeDefault
);
469 static unsigned long xsltDefaultTrace
= (unsigned long) XSLT_TRACE_ALL
;
472 * xsltDebugSetDefaultTrace:
473 * @val: tracing level mask
475 * Set the default debug tracing level mask
477 void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val
) {
478 xsltDefaultTrace
= val
;
482 * xsltDebugGetDefaultTrace:
484 * Get the current default debug tracing level mask
486 * Returns the current default debug tracing level mask
488 xsltDebugTraceCodes
xsltDebugGetDefaultTrace(void) {
489 return xsltDefaultTrace
;
492 /************************************************************************
494 * Handling of Transformation Contexts *
496 ************************************************************************/
498 static xsltTransformCachePtr
499 xsltTransformCacheCreate(void)
501 xsltTransformCachePtr ret
;
503 ret
= (xsltTransformCachePtr
) xmlMalloc(sizeof(xsltTransformCache
));
505 xsltTransformError(NULL
, NULL
, NULL
,
506 "xsltTransformCacheCreate : malloc failed\n");
509 memset(ret
, 0, sizeof(xsltTransformCache
));
514 xsltTransformCacheFree(xsltTransformCachePtr cache
)
519 * Free tree fragments.
522 xmlDocPtr tmp
, cur
= cache
->RVT
;
525 cur
= (xmlDocPtr
) cur
->next
;
526 if (tmp
->_private
!= NULL
) {
528 * Tree the document info.
530 xsltFreeDocumentKeys((xsltDocumentPtr
) tmp
->_private
);
531 xmlFree(tmp
->_private
);
539 if (cache
->stackItems
) {
540 xsltStackElemPtr tmp
, cur
= cache
->stackItems
;
545 * REVISIT TODO: Should be call a destruction-function
555 * xsltNewTransformContext:
556 * @style: a parsed XSLT stylesheet
557 * @doc: the input document
559 * Create a new XSLT TransformContext
561 * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
563 xsltTransformContextPtr
564 xsltNewTransformContext(xsltStylesheetPtr style
, xmlDocPtr doc
) {
565 xsltTransformContextPtr cur
;
566 xsltDocumentPtr docu
;
571 cur
= (xsltTransformContextPtr
) xmlMalloc(sizeof(xsltTransformContext
));
573 xsltTransformError(NULL
, NULL
, (xmlNodePtr
)doc
,
574 "xsltNewTransformContext : malloc failed\n");
577 memset(cur
, 0, sizeof(xsltTransformContext
));
579 cur
->cache
= xsltTransformCacheCreate();
580 if (cur
->cache
== NULL
)
583 * setup of the dictionary must be done early as some of the
584 * processing later like key handling may need it.
586 cur
->dict
= xmlDictCreateSub(style
->dict
);
587 cur
->internalized
= ((style
->internalized
) && (cur
->dict
!= NULL
));
588 #ifdef WITH_XSLT_DEBUG
589 xsltGenericDebug(xsltGenericDebugContext
,
590 "Creating sub-dictionary from stylesheet for transformation\n");
594 * initialize the template stack
596 cur
->templTab
= (xsltTemplatePtr
*)
597 xmlMalloc(10 * sizeof(xsltTemplatePtr
));
598 if (cur
->templTab
== NULL
) {
599 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
600 "xsltNewTransformContext: out of memory\n");
606 cur
->maxTemplateDepth
= xsltMaxDepth
;
609 * initialize the variables stack
611 cur
->varsTab
= (xsltStackElemPtr
*)
612 xmlMalloc(10 * sizeof(xsltStackElemPtr
));
613 if (cur
->varsTab
== NULL
) {
614 xmlGenericError(xmlGenericErrorContext
,
615 "xsltNewTransformContext: out of memory\n");
622 cur
->maxTemplateVars
= xsltMaxVars
;
625 * the profiling stack is not initialized by default
633 cur
->xpathCtxt
= xmlXPathNewContext(doc
);
634 if (cur
->xpathCtxt
== NULL
) {
635 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
636 "xsltNewTransformContext : xmlXPathNewContext failed\n");
640 * Create an XPath cache.
642 if (xmlXPathContextSetCache(cur
->xpathCtxt
, 1, -1, 0) == -1)
645 * Initialize the extras array
647 if (style
->extrasNr
!= 0) {
648 cur
->extrasMax
= style
->extrasNr
+ 20;
649 cur
->extras
= (xsltRuntimeExtraPtr
)
650 xmlMalloc(cur
->extrasMax
* sizeof(xsltRuntimeExtra
));
651 if (cur
->extras
== NULL
) {
652 xmlGenericError(xmlGenericErrorContext
,
653 "xsltNewTransformContext: out of memory\n");
656 cur
->extrasNr
= style
->extrasNr
;
657 for (i
= 0;i
< cur
->extrasMax
;i
++) {
658 cur
->extras
[i
].info
= NULL
;
659 cur
->extras
[i
].deallocate
= NULL
;
660 cur
->extras
[i
].val
.ptr
= NULL
;
668 XSLT_REGISTER_VARIABLE_LOOKUP(cur
);
669 XSLT_REGISTER_FUNCTION_LOOKUP(cur
);
670 cur
->xpathCtxt
->nsHash
= style
->nsHash
;
672 * Initialize the registered external modules
674 xsltInitCtxtExts(cur
);
676 * Setup document element ordering for later efficiencies
679 if (xslDebugStatus
== XSLT_DEBUG_NONE
)
680 xmlXPathOrderDocElems(doc
);
682 * Must set parserOptions before calling xsltNewDocument
685 cur
->parserOptions
= XSLT_PARSE_OPTIONS
;
686 docu
= xsltNewDocument(cur
, doc
);
688 xsltTransformError(cur
, NULL
, (xmlNodePtr
)doc
,
689 "xsltNewTransformContext : xsltNewDocument failed\n");
693 cur
->document
= docu
;
695 cur
->outputFile
= NULL
;
696 cur
->sec
= xsltGetDefaultSecurityPrefs();
697 cur
->debugStatus
= xslDebugStatus
;
698 cur
->traceCode
= (unsigned long*) &xsltDefaultTrace
;
699 cur
->xinclude
= xsltGetXIncludeDefault();
700 cur
->keyInitLevel
= 0;
702 cur
->newLocale
= xsltNewLocale
;
703 cur
->freeLocale
= xsltFreeLocale
;
704 cur
->genSortKey
= xsltStrxfrm
;
710 xsltFreeTransformContext(cur
);
715 * xsltFreeTransformContext:
716 * @ctxt: an XSLT transform context
718 * Free up the memory allocated by @ctxt
721 xsltFreeTransformContext(xsltTransformContextPtr ctxt
) {
726 * Shutdown the extension modules associated to the stylesheet
729 xsltShutdownCtxtExts(ctxt
);
731 if (ctxt
->xpathCtxt
!= NULL
) {
732 ctxt
->xpathCtxt
->nsHash
= NULL
;
733 xmlXPathFreeContext(ctxt
->xpathCtxt
);
735 if (ctxt
->templTab
!= NULL
)
736 xmlFree(ctxt
->templTab
);
737 if (ctxt
->varsTab
!= NULL
)
738 xmlFree(ctxt
->varsTab
);
739 if (ctxt
->profTab
!= NULL
)
740 xmlFree(ctxt
->profTab
);
741 if ((ctxt
->extrasNr
> 0) && (ctxt
->extras
!= NULL
)) {
744 for (i
= 0;i
< ctxt
->extrasNr
;i
++) {
745 if ((ctxt
->extras
[i
].deallocate
!= NULL
) &&
746 (ctxt
->extras
[i
].info
!= NULL
))
747 ctxt
->extras
[i
].deallocate(ctxt
->extras
[i
].info
);
749 xmlFree(ctxt
->extras
);
751 xsltFreeGlobalVariables(ctxt
);
752 xsltFreeDocuments(ctxt
);
753 xsltFreeCtxtExts(ctxt
);
755 xsltTransformCacheFree(ctxt
->cache
);
756 xmlDictFree(ctxt
->dict
);
757 #ifdef WITH_XSLT_DEBUG
758 xsltGenericDebug(xsltGenericDebugContext
,
759 "freeing transformation dictionary\n");
761 memset(ctxt
, -1, sizeof(xsltTransformContext
));
765 /************************************************************************
767 * Copy of Nodes in an XSLT fashion *
769 ************************************************************************/
773 * @parent: the parent node
774 * @cur: the child node
776 * Wrapper version of xmlAddChild with a more consistent behaviour on
777 * error. One expect the use to be child = xsltAddChild(parent, child);
778 * and the routine will take care of not leaking on errors or node merge
780 * Returns the child is successfully attached or NULL if merged or freed
783 xsltAddChild(xmlNodePtr parent
, xmlNodePtr cur
) {
788 if (parent
== NULL
) {
792 ret
= xmlAddChild(parent
, cur
);
799 * @ctxt: a XSLT process context
800 * @target: the text node where the text will be attached
801 * @string: the text string
802 * @len: the string length in byte
804 * Extend the current text node with the new string, it handles coalescing
806 * Returns: the text node
809 xsltAddTextString(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
810 const xmlChar
*string
, int len
) {
814 if ((len
<= 0) || (string
== NULL
) || (target
== NULL
))
817 if (ctxt
->lasttext
== target
->content
) {
820 /* Check for integer overflow accounting for NUL terminator. */
821 if (len
>= INT_MAX
- ctxt
->lasttuse
) {
822 xsltTransformError(ctxt
, NULL
, target
,
823 "xsltCopyText: text allocation failed\n");
826 minSize
= ctxt
->lasttuse
+ len
+ 1;
828 if (ctxt
->lasttsize
< minSize
) {
833 /* Double buffer size but increase by at least 100 bytes. */
834 extra
= minSize
< 100 ? 100 : minSize
;
836 /* Check for integer overflow. */
837 if (extra
> INT_MAX
- ctxt
->lasttsize
) {
841 size
= ctxt
->lasttsize
+ extra
;
844 newbuf
= (xmlChar
*) xmlRealloc(target
->content
,size
);
845 if (newbuf
== NULL
) {
846 xsltTransformError(ctxt
, NULL
, target
,
847 "xsltCopyText: text allocation failed\n");
850 ctxt
->lasttsize
= size
;
851 ctxt
->lasttext
= newbuf
;
852 target
->content
= newbuf
;
854 memcpy(&(target
->content
[ctxt
->lasttuse
]), string
, len
);
855 ctxt
->lasttuse
+= len
;
856 target
->content
[ctxt
->lasttuse
] = 0;
858 xmlNodeAddContent(target
, string
);
859 ctxt
->lasttext
= target
->content
;
860 len
= xmlStrlen(target
->content
);
861 ctxt
->lasttsize
= len
;
862 ctxt
->lasttuse
= len
;
868 * xsltCopyTextString:
869 * @ctxt: a XSLT process context
870 * @target: the element where the text will be attached
871 * @string: the text string
872 * @noescape: should disable-escaping be activated for this text node.
874 * Adds @string to a newly created or an existent text node child of
877 * Returns: the text node, where the text content of @cur is copied to.
878 * NULL in case of API or internal errors.
881 xsltCopyTextString(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
882 const xmlChar
*string
, int noescape
)
890 #ifdef WITH_XSLT_DEBUG_PROCESS
891 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
892 "xsltCopyTextString: copy text %s\n",
897 * Play safe and reset the merging mechanism for every new
900 if ((target
== NULL
) || (target
->children
== NULL
)) {
901 ctxt
->lasttext
= NULL
;
904 /* handle coalescing of text nodes here */
905 len
= xmlStrlen(string
);
906 if ((ctxt
->type
== XSLT_OUTPUT_XML
) &&
907 (ctxt
->style
->cdataSection
!= NULL
) &&
909 (target
->type
== XML_ELEMENT_NODE
) &&
910 (((target
->ns
== NULL
) &&
911 (xmlHashLookup2(ctxt
->style
->cdataSection
,
912 target
->name
, NULL
) != NULL
)) ||
913 ((target
->ns
!= NULL
) &&
914 (xmlHashLookup2(ctxt
->style
->cdataSection
,
915 target
->name
, target
->ns
->href
) != NULL
))))
918 * Process "cdata-section-elements".
920 if ((target
->last
!= NULL
) &&
921 (target
->last
->type
== XML_CDATA_SECTION_NODE
))
923 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
925 copy
= xmlNewCDataBlock(ctxt
->output
, string
, len
);
926 } else if (noescape
) {
928 * Process "disable-output-escaping".
930 if ((target
!= NULL
) && (target
->last
!= NULL
) &&
931 (target
->last
->type
== XML_TEXT_NODE
) &&
932 (target
->last
->name
== xmlStringTextNoenc
))
934 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
936 copy
= xmlNewTextLen(string
, len
);
938 copy
->name
= xmlStringTextNoenc
;
941 * Default processing.
943 if ((target
!= NULL
) && (target
->last
!= NULL
) &&
944 (target
->last
->type
== XML_TEXT_NODE
) &&
945 (target
->last
->name
== xmlStringText
)) {
946 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
948 copy
= xmlNewTextLen(string
, len
);
950 if (copy
!= NULL
&& target
!= NULL
)
951 copy
= xsltAddChild(target
, copy
);
953 ctxt
->lasttext
= copy
->content
;
954 ctxt
->lasttsize
= len
;
955 ctxt
->lasttuse
= len
;
957 xsltTransformError(ctxt
, NULL
, target
,
958 "xsltCopyTextString: text copy failed\n");
959 ctxt
->lasttext
= NULL
;
966 * @ctxt: a XSLT process context
967 * @target: the element where the text will be attached
968 * @cur: the text or CDATA node
969 * @interned: the string is in the target doc dictionary
971 * Copy the text content of @cur and append it to @target's children.
973 * Returns: the text node, where the text content of @cur is copied to.
974 * NULL in case of API or internal errors.
977 xsltCopyText(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
978 xmlNodePtr cur
, int interned
)
982 if ((cur
->type
!= XML_TEXT_NODE
) &&
983 (cur
->type
!= XML_CDATA_SECTION_NODE
))
985 if (cur
->content
== NULL
)
988 #ifdef WITH_XSLT_DEBUG_PROCESS
989 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
990 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
991 "xsltCopyText: copy CDATA text %s\n",
993 } else if (cur
->name
== xmlStringTextNoenc
) {
994 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
995 "xsltCopyText: copy unescaped text %s\n",
998 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
999 "xsltCopyText: copy text %s\n",
1005 * Play save and reset the merging mechanism for every new
1008 if ((target
== NULL
) || (target
->children
== NULL
)) {
1009 ctxt
->lasttext
= NULL
;
1012 if ((ctxt
->style
->cdataSection
!= NULL
) &&
1013 (ctxt
->type
== XSLT_OUTPUT_XML
) &&
1015 (target
->type
== XML_ELEMENT_NODE
) &&
1016 (((target
->ns
== NULL
) &&
1017 (xmlHashLookup2(ctxt
->style
->cdataSection
,
1018 target
->name
, NULL
) != NULL
)) ||
1019 ((target
->ns
!= NULL
) &&
1020 (xmlHashLookup2(ctxt
->style
->cdataSection
,
1021 target
->name
, target
->ns
->href
) != NULL
))))
1024 * Process "cdata-section-elements".
1027 * OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
1030 * TODO: Since this doesn't merge adjacent CDATA-section nodes,
1031 * we'll get: <![CDATA[x]]><!CDATA[y]]>.
1032 * TODO: Reported in #321505.
1034 if ((target
->last
!= NULL
) &&
1035 (target
->last
->type
== XML_CDATA_SECTION_NODE
))
1038 * Append to existing CDATA-section node.
1040 copy
= xsltAddTextString(ctxt
, target
->last
, cur
->content
,
1041 xmlStrlen(cur
->content
));
1046 len
= xmlStrlen(cur
->content
);
1047 copy
= xmlNewCDataBlock(ctxt
->output
, cur
->content
, len
);
1050 ctxt
->lasttext
= copy
->content
;
1051 ctxt
->lasttsize
= len
;
1052 ctxt
->lasttuse
= len
;
1054 } else if ((target
!= NULL
) &&
1055 (target
->last
!= NULL
) &&
1056 /* both escaped or both non-escaped text-nodes */
1057 (((target
->last
->type
== XML_TEXT_NODE
) &&
1058 (target
->last
->name
== cur
->name
)) ||
1059 /* non-escaped text nodes and CDATA-section nodes */
1060 (((target
->last
->type
== XML_CDATA_SECTION_NODE
) &&
1061 (cur
->name
== xmlStringTextNoenc
)))))
1064 * we are appending to an existing text node
1066 copy
= xsltAddTextString(ctxt
, target
->last
, cur
->content
,
1067 xmlStrlen(cur
->content
));
1069 } else if ((interned
) && (target
!= NULL
) &&
1070 (target
->doc
!= NULL
) &&
1071 (target
->doc
->dict
== ctxt
->dict
))
1074 * TODO: DO we want to use this also for "text" output?
1076 copy
= xmlNewTextLen(NULL
, 0);
1079 if (cur
->name
== xmlStringTextNoenc
)
1080 copy
->name
= xmlStringTextNoenc
;
1083 * Must confirm that content is in dict (bug 302821)
1084 * TODO: This check should be not needed for text coming
1085 * from the stylesheets
1087 if (xmlDictOwns(ctxt
->dict
, cur
->content
))
1088 copy
->content
= cur
->content
;
1090 if ((copy
->content
= xmlStrdup(cur
->content
)) == NULL
) {
1096 ctxt
->lasttext
= NULL
;
1099 * normal processing. keep counters to extend the text node
1100 * in xsltAddTextString if needed.
1104 len
= xmlStrlen(cur
->content
);
1105 copy
= xmlNewTextLen(cur
->content
, len
);
1108 if (cur
->name
== xmlStringTextNoenc
)
1109 copy
->name
= xmlStringTextNoenc
;
1110 ctxt
->lasttext
= copy
->content
;
1111 ctxt
->lasttsize
= len
;
1112 ctxt
->lasttuse
= len
;
1115 if (target
!= NULL
) {
1116 copy
->doc
= target
->doc
;
1118 * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
1119 * to ensure that the optimized text-merging mechanism
1120 * won't interfere with normal node-merging in any case.
1122 copy
= xsltAddChild(target
, copy
);
1125 xsltTransformError(ctxt
, NULL
, target
,
1126 "xsltCopyText: text copy failed\n");
1130 if ((copy
== NULL
) || (copy
->content
== NULL
)) {
1131 xsltTransformError(ctxt
, NULL
, target
,
1132 "Internal error in xsltCopyText(): "
1133 "Failed to copy the string.\n");
1134 ctxt
->state
= XSLT_STATE_STOPPED
;
1140 * xsltShallowCopyAttr:
1141 * @ctxt: a XSLT process context
1142 * @invocNode: responsible node in the stylesheet; used for error reports
1143 * @target: the element where the attribute will be grafted
1144 * @attr: the attribute to be copied
1146 * Do a copy of an attribute.
1152 * Returns: a new xmlAttrPtr, or NULL in case of error.
1155 xsltShallowCopyAttr(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1156 xmlNodePtr target
, xmlAttrPtr attr
)
1164 if (target
->type
!= XML_ELEMENT_NODE
) {
1165 xsltTransformError(ctxt
, NULL
, invocNode
,
1166 "Cannot add an attribute node to a non-element node.\n");
1170 if (target
->children
!= NULL
) {
1171 xsltTransformError(ctxt
, NULL
, invocNode
,
1172 "Attribute nodes must be added before "
1173 "any child nodes to an element.\n");
1177 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1178 if (attr
->ns
!= NULL
) {
1181 ns
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1182 attr
->ns
->href
, attr
->ns
->prefix
, target
);
1184 xsltTransformError(ctxt
, NULL
, invocNode
,
1185 "Namespace fixup error: Failed to acquire an in-scope "
1186 "namespace binding of the copied attribute '{%s}%s'.\n",
1187 attr
->ns
->href
, attr
->name
);
1189 * TODO: Should we just stop here?
1193 * Note that xmlSetNsProp() will take care of duplicates
1194 * and assigns the new namespace even to a duplicate.
1196 copy
= xmlSetNsProp(target
, ns
, attr
->name
, value
);
1198 copy
= xmlSetNsProp(target
, NULL
, attr
->name
, value
);
1208 * NOTE: This was optimized according to bug #342695.
1209 * TODO: Can this further be optimized, if source and target
1210 * share the same dict and attr->children is just 1 text node
1211 * which is in the dict? How probable is such a case?
1214 * TODO: Do we need to create an empty text node if the value
1215 * is the empty string?
1217 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1218 if (value
!= NULL
) {
1219 txtNode
= xmlNewDocText(target
->doc
, NULL
);
1220 if (txtNode
== NULL
)
1222 if ((target
->doc
!= NULL
) &&
1223 (target
->doc
->dict
!= NULL
))
1226 (xmlChar
*) xmlDictLookup(target
->doc
->dict
,
1227 BAD_CAST value
, -1);
1230 txtNode
->content
= value
;
1231 copy
->children
= txtNode
;
1239 * xsltCopyAttrListNoOverwrite:
1240 * @ctxt: a XSLT process context
1241 * @invocNode: responsible node in the stylesheet; used for error reports
1242 * @target: the element where the new attributes will be grafted
1243 * @attr: the first attribute in the list to be copied
1245 * Copies a list of attribute nodes, starting with @attr, over to the
1246 * @target element node.
1251 * Returns 0 on success and -1 on errors and internal errors.
1254 xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt
,
1255 xmlNodePtr invocNode
,
1256 xmlNodePtr target
, xmlAttrPtr attr
)
1259 xmlNsPtr origNs
= NULL
, copyNs
= NULL
;
1263 * Don't use xmlCopyProp() here, since it will try to
1264 * reconciliate namespaces.
1266 while (attr
!= NULL
) {
1268 * Find a namespace node in the tree of @target.
1269 * Avoid searching for the same ns.
1271 if (attr
->ns
!= origNs
) {
1273 if (attr
->ns
!= NULL
) {
1274 copyNs
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1275 attr
->ns
->href
, attr
->ns
->prefix
, target
);
1282 * If attribute has a value, we need to copy it (watching out
1283 * for possible entities)
1285 if ((attr
->children
) && (attr
->children
->type
== XML_TEXT_NODE
) &&
1286 (attr
->children
->next
== NULL
)) {
1287 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
,
1288 attr
->children
->content
);
1289 } else if (attr
->children
!= NULL
) {
1290 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1291 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
, BAD_CAST value
);
1294 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
, NULL
);
1306 * xsltShallowCopyElem:
1307 * @ctxt: the XSLT process context
1308 * @node: the element node in the source tree
1309 * or the Literal Result Element
1310 * @insert: the parent in the result tree
1311 * @isLRE: if @node is a Literal Result Element
1313 * Make a copy of the element node @node
1314 * and insert it as last child of @insert.
1316 * URGENT TODO: The problem with this one (for the non-refactored code)
1317 * is that it is used for both, Literal Result Elements *and*
1318 * copying input nodes.
1320 * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
1323 * xsltApplySequenceConstructor()
1324 * (for Literal Result Elements - which is a problem)
1325 * xsltCopy() (for shallow-copying elements via xsl:copy)
1327 * Returns a pointer to the new node, or NULL in case of error
1330 xsltShallowCopyElem(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1331 xmlNodePtr insert
, int isLRE
)
1335 if ((node
->type
== XML_DTD_NODE
) || (insert
== NULL
))
1337 if ((node
->type
== XML_TEXT_NODE
) ||
1338 (node
->type
== XML_CDATA_SECTION_NODE
))
1339 return(xsltCopyText(ctxt
, insert
, node
, 0));
1341 copy
= xmlDocCopyNode(node
, insert
->doc
, 0);
1343 copy
->doc
= ctxt
->output
;
1344 copy
= xsltAddChild(insert
, copy
);
1346 xsltTransformError(ctxt
, NULL
, node
,
1347 "xsltShallowCopyElem: copy failed\n");
1351 if (node
->type
== XML_ELEMENT_NODE
) {
1353 * Add namespaces as they are needed
1355 if (node
->nsDef
!= NULL
) {
1357 * TODO: Remove the LRE case in the refactored code
1361 xsltCopyNamespaceList(ctxt
, copy
, node
->nsDef
);
1363 xsltCopyNamespaceListInternal(copy
, node
->nsDef
);
1367 * URGENT TODO: The problem with this is that it does not
1368 * copy over all namespace nodes in scope.
1369 * The damn thing about this is, that we would need to
1370 * use the xmlGetNsList(), for every single node; this is
1371 * also done in xsltCopyTree(), but only for the top node.
1373 if (node
->ns
!= NULL
) {
1376 * REVISIT TODO: Since the non-refactored code still does
1377 * ns-aliasing, we need to call xsltGetNamespace() here.
1378 * Remove this when ready.
1380 copy
->ns
= xsltGetNamespace(ctxt
, node
, node
->ns
, copy
);
1382 copy
->ns
= xsltGetSpecialNamespace(ctxt
,
1383 node
, node
->ns
->href
, node
->ns
->prefix
, copy
);
1386 } else if ((insert
->type
== XML_ELEMENT_NODE
) &&
1387 (insert
->ns
!= NULL
))
1390 * "Undeclare" the default namespace.
1392 xsltGetSpecialNamespace(ctxt
, node
, NULL
, NULL
, copy
);
1396 xsltTransformError(ctxt
, NULL
, node
,
1397 "xsltShallowCopyElem: copy %s failed\n", node
->name
);
1404 * @ctxt: a XSLT process context
1405 * @invocNode: responsible node in the stylesheet; used for error reports
1406 * @list: the list of element nodes in the source tree.
1407 * @insert: the parent in the result tree.
1408 * @isLRE: is this a literal result element list
1409 * @topElemVisited: indicates if a top-most element was already processed
1411 * Make a copy of the full list of tree @list
1412 * and insert it as last children of @insert
1414 * NOTE: Not to be used for Literal Result Elements.
1419 * Returns a pointer to the new list, or NULL in case of error
1422 xsltCopyTreeList(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1424 xmlNodePtr insert
, int isLRE
, int topElemVisited
)
1426 xmlNodePtr copy
, ret
= NULL
;
1428 while (list
!= NULL
) {
1429 copy
= xsltCopyTree(ctxt
, invocNode
,
1430 list
, insert
, isLRE
, topElemVisited
);
1442 * xsltCopyNamespaceListInternal:
1443 * @node: the target node
1444 * @cur: the first namespace
1446 * Do a copy of a namespace list. If @node is non-NULL the
1447 * new namespaces are added automatically.
1451 * QUESTION: What is the exact difference between this function
1452 * and xsltCopyNamespaceList() in "namespaces.c"?
1453 * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
1455 * Returns: a new xmlNsPtr, or NULL in case of error.
1458 xsltCopyNamespaceListInternal(xmlNodePtr elem
, xmlNsPtr ns
) {
1459 xmlNsPtr ret
= NULL
;
1460 xmlNsPtr p
= NULL
, q
, luNs
;
1465 * One can add namespaces only on element nodes
1467 if ((elem
!= NULL
) && (elem
->type
!= XML_ELEMENT_NODE
))
1471 if (ns
->type
!= XML_NAMESPACE_DECL
)
1474 * Avoid duplicating namespace declarations on the tree.
1477 if ((elem
->ns
!= NULL
) &&
1478 xmlStrEqual(elem
->ns
->prefix
, ns
->prefix
) &&
1479 xmlStrEqual(elem
->ns
->href
, ns
->href
))
1484 luNs
= xmlSearchNs(elem
->doc
, elem
, ns
->prefix
);
1485 if ((luNs
!= NULL
) && (xmlStrEqual(luNs
->href
, ns
->href
)))
1491 q
= xmlNewNs(elem
, ns
->href
, ns
->prefix
);
1494 } else if (q
!= NULL
) {
1499 } while (ns
!= NULL
);
1504 * xsltShallowCopyNsNode:
1505 * @ctxt: the XSLT transformation context
1506 * @invocNode: responsible node in the stylesheet; used for error reports
1507 * @insert: the target element node in the result tree
1508 * @ns: the namespace node
1510 * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
1512 * Returns a new/existing ns-node, or NULL.
1515 xsltShallowCopyNsNode(xsltTransformContextPtr ctxt
,
1516 xmlNodePtr invocNode
,
1521 * TODO: Contrary to header comments, this is declared as int.
1522 * be modified to return a node pointer, or NULL if any error
1526 if ((insert
== NULL
) || (insert
->type
!= XML_ELEMENT_NODE
))
1529 if (insert
->children
!= NULL
) {
1530 xsltTransformError(ctxt
, NULL
, invocNode
,
1531 "Namespace nodes must be added before "
1532 "any child nodes are added to an element.\n");
1536 * BIG NOTE: Xalan-J simply overwrites any ns-decls with
1537 * an equal prefix. We definitively won't do that.
1539 * MSXML 4.0 and the .NET ignores ns-decls for which an
1540 * equal prefix is already in use.
1542 * Saxon raises an error like:
1543 * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
1544 * nodes with the same name".
1546 * NOTE: We'll currently follow MSXML here.
1547 * REVISIT TODO: Check if it's better to follow Saxon here.
1549 if (ns
->prefix
== NULL
) {
1551 * If we are adding ns-nodes to an element using e.g.
1552 * <xsl:copy-of select="/foo/namespace::*">, then we need
1553 * to ensure that we don't incorrectly declare a default
1554 * namespace on an element in no namespace, which otherwise
1555 * would move the element incorrectly into a namespace, if
1556 * the node tree is serialized.
1558 if (insert
->ns
== NULL
)
1560 } else if ((ns
->prefix
[0] == 'x') &&
1561 xmlStrEqual(ns
->prefix
, BAD_CAST
"xml"))
1564 * The XML namespace is built in.
1569 if (insert
->nsDef
!= NULL
) {
1570 tmpns
= insert
->nsDef
;
1572 if ((tmpns
->prefix
== NULL
) == (ns
->prefix
== NULL
)) {
1573 if ((tmpns
->prefix
== ns
->prefix
) ||
1574 xmlStrEqual(tmpns
->prefix
, ns
->prefix
))
1579 if (xmlStrEqual(tmpns
->href
, ns
->href
))
1584 tmpns
= tmpns
->next
;
1585 } while (tmpns
!= NULL
);
1587 tmpns
= xmlSearchNs(insert
->doc
, insert
, ns
->prefix
);
1588 if ((tmpns
!= NULL
) && xmlStrEqual(tmpns
->href
, ns
->href
))
1591 * Declare a new namespace.
1592 * TODO: The problem (wrt efficiency) with this xmlNewNs() is
1593 * that it will again search the already declared namespaces
1594 * for a duplicate :-/
1596 return(xmlNewNs(insert
, ns
->href
, ns
->prefix
));
1600 * TODO: We could as well raise an error here (like Saxon does),
1601 * or at least generate a warning.
1608 * @ctxt: the XSLT transformation context
1609 * @invocNode: responsible node in the stylesheet; used for error reports
1610 * @node: the element node in the source tree
1611 * @insert: the parent in the result tree
1612 * @isLRE: indicates if @node is a Literal Result Element
1613 * @topElemVisited: indicates if a top-most element was already processed
1615 * Make a copy of the full tree under the element node @node
1616 * and insert it as last child of @insert
1618 * NOTE: Not to be used for Literal Result Elements.
1623 * Returns a pointer to the new tree, or NULL in case of error
1626 xsltCopyTree(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1627 xmlNodePtr node
, xmlNodePtr insert
, int isLRE
,
1634 switch (node
->type
) {
1635 case XML_ELEMENT_NODE
:
1636 case XML_ENTITY_REF_NODE
:
1637 case XML_ENTITY_NODE
:
1639 case XML_COMMENT_NODE
:
1640 case XML_DOCUMENT_NODE
:
1641 case XML_HTML_DOCUMENT_NODE
:
1642 #ifdef LIBXML_DOCB_ENABLED
1643 case XML_DOCB_DOCUMENT_NODE
:
1646 case XML_TEXT_NODE
: {
1647 int noenc
= (node
->name
== xmlStringTextNoenc
);
1648 return(xsltCopyTextString(ctxt
, insert
, node
->content
, noenc
));
1650 case XML_CDATA_SECTION_NODE
:
1651 return(xsltCopyTextString(ctxt
, insert
, node
->content
, 0));
1652 case XML_ATTRIBUTE_NODE
:
1654 xsltShallowCopyAttr(ctxt
, invocNode
, insert
, (xmlAttrPtr
) node
));
1655 case XML_NAMESPACE_DECL
:
1656 return((xmlNodePtr
) xsltShallowCopyNsNode(ctxt
, invocNode
,
1657 insert
, (xmlNsPtr
) node
));
1659 case XML_DOCUMENT_TYPE_NODE
:
1660 case XML_DOCUMENT_FRAG_NODE
:
1661 case XML_NOTATION_NODE
:
1663 case XML_ELEMENT_DECL
:
1664 case XML_ATTRIBUTE_DECL
:
1665 case XML_ENTITY_DECL
:
1666 case XML_XINCLUDE_START
:
1667 case XML_XINCLUDE_END
:
1670 if (XSLT_IS_RES_TREE_FRAG(node
)) {
1671 if (node
->children
!= NULL
)
1672 copy
= xsltCopyTreeList(ctxt
, invocNode
,
1673 node
->children
, insert
, 0, 0);
1678 copy
= xmlDocCopyNode(node
, insert
->doc
, 0);
1680 copy
->doc
= ctxt
->output
;
1681 copy
= xsltAddChild(insert
, copy
);
1683 xsltTransformError(ctxt
, NULL
, invocNode
,
1684 "xsltCopyTree: Copying of '%s' failed.\n", node
->name
);
1688 * The node may have been coalesced into another text node.
1690 if (insert
->last
!= copy
)
1691 return(insert
->last
);
1694 if (node
->type
== XML_ELEMENT_NODE
) {
1696 * Copy in-scope namespace nodes.
1698 * REVISIT: Since we try to reuse existing in-scope ns-decls by
1699 * using xmlSearchNsByHref(), this will eventually change
1700 * the prefix of an original ns-binding; thus it might
1701 * break QNames in element/attribute content.
1702 * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
1703 * context, plus a ns-lookup function, which writes directly
1704 * to a given list, then we wouldn't need to create/free the
1705 * nsList every time.
1707 if ((topElemVisited
== 0) &&
1708 (node
->parent
!= NULL
) &&
1709 (node
->parent
->type
!= XML_DOCUMENT_NODE
) &&
1710 (node
->parent
->type
!= XML_HTML_DOCUMENT_NODE
))
1712 xmlNsPtr
*nsList
, *curns
, ns
;
1715 * If this is a top-most element in a tree to be
1716 * copied, then we need to ensure that all in-scope
1717 * namespaces are copied over. For nodes deeper in the
1718 * tree, it is sufficient to reconcile only the ns-decls
1719 * (node->nsDef entries).
1722 nsList
= xmlGetNsList(node
->doc
, node
);
1723 if (nsList
!= NULL
) {
1727 * Search by prefix first in order to break as less
1728 * QNames in element/attribute content as possible.
1730 ns
= xmlSearchNs(insert
->doc
, insert
,
1734 (! xmlStrEqual(ns
->href
, (*curns
)->href
)))
1738 * Search by namespace name.
1739 * REVISIT TODO: Currently disabled.
1742 ns
= xmlSearchNsByHref(insert
->doc
,
1743 insert
, (*curns
)->href
);
1748 * Declare a new namespace on the copied element.
1750 ns
= xmlNewNs(copy
, (*curns
)->href
,
1752 /* TODO: Handle errors */
1754 if (node
->ns
== *curns
) {
1756 * If this was the original's namespace then set
1757 * the generated counterpart on the copy.
1762 } while (*curns
!= NULL
);
1765 } else if (node
->nsDef
!= NULL
) {
1767 * Copy over all namespace declaration attributes.
1769 if (node
->nsDef
!= NULL
) {
1771 xsltCopyNamespaceList(ctxt
, copy
, node
->nsDef
);
1773 xsltCopyNamespaceListInternal(copy
, node
->nsDef
);
1777 * Set the namespace.
1779 if (node
->ns
!= NULL
) {
1780 if (copy
->ns
== NULL
) {
1782 * This will map copy->ns to one of the newly created
1783 * in-scope ns-decls, OR create a new ns-decl on @copy.
1785 copy
->ns
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1786 node
->ns
->href
, node
->ns
->prefix
, copy
);
1788 } else if ((insert
->type
== XML_ELEMENT_NODE
) &&
1789 (insert
->ns
!= NULL
))
1792 * "Undeclare" the default namespace on @copy with xmlns="".
1794 xsltGetSpecialNamespace(ctxt
, invocNode
, NULL
, NULL
, copy
);
1797 * Copy attribute nodes.
1799 if (node
->properties
!= NULL
) {
1800 xsltCopyAttrListNoOverwrite(ctxt
, invocNode
,
1801 copy
, node
->properties
);
1803 if (topElemVisited
== 0)
1809 if (node
->children
!= NULL
) {
1810 xsltCopyTreeList(ctxt
, invocNode
,
1811 node
->children
, copy
, isLRE
, topElemVisited
);
1814 xsltTransformError(ctxt
, NULL
, invocNode
,
1815 "xsltCopyTree: Copying of '%s' failed.\n", node
->name
);
1820 /************************************************************************
1822 * Error/fallback processing *
1824 ************************************************************************/
1827 * xsltApplyFallbacks:
1828 * @ctxt: a XSLT process context
1829 * @node: the node in the source tree.
1830 * @inst: the node generating the error
1832 * Process possible xsl:fallback nodes present under @inst
1834 * Returns the number of xsl:fallback element found and processed
1837 xsltApplyFallbacks(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1843 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) ||
1844 (inst
->children
== NULL
))
1847 child
= inst
->children
;
1848 while (child
!= NULL
) {
1849 if ((IS_XSLT_ELEM(child
)) &&
1850 (xmlStrEqual(child
->name
, BAD_CAST
"fallback"))) {
1851 #ifdef WITH_XSLT_DEBUG_PARSING
1852 xsltGenericDebug(xsltGenericDebugContext
,
1853 "applying xsl:fallback\n");
1856 xsltApplySequenceConstructor(ctxt
, node
, child
->children
,
1859 child
= child
->next
;
1864 /************************************************************************
1866 * Default processing *
1868 ************************************************************************/
1871 * xsltDefaultProcessOneNode:
1872 * @ctxt: a XSLT process context
1873 * @node: the node in the source tree.
1874 * @params: extra parameters passed to the template if any
1876 * Process the source node with the default built-in template rule:
1877 * <xsl:template match="*|/">
1878 * <xsl:apply-templates/>
1883 * <xsl:template match="text()|@*">
1884 * <xsl:value-of select="."/>
1887 * Note also that namespace declarations are copied directly:
1889 * the built-in template rule is the only template rule that is applied
1890 * for namespace nodes.
1893 xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1894 xsltStackElemPtr params
) {
1897 int nbchild
= 0, oldSize
;
1898 int childno
= 0, oldPos
;
1899 xsltTemplatePtr
template;
1903 * Handling of leaves
1905 switch (node
->type
) {
1906 case XML_DOCUMENT_NODE
:
1907 case XML_HTML_DOCUMENT_NODE
:
1908 case XML_ELEMENT_NODE
:
1910 case XML_CDATA_SECTION_NODE
:
1911 #ifdef WITH_XSLT_DEBUG_PROCESS
1912 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1913 "xsltDefaultProcessOneNode: copy CDATA %s\n",
1916 copy
= xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
1918 xsltTransformError(ctxt
, NULL
, node
,
1919 "xsltDefaultProcessOneNode: cdata copy failed\n");
1923 #ifdef WITH_XSLT_DEBUG_PROCESS
1924 if (node
->content
== NULL
) {
1925 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1926 "xsltDefaultProcessOneNode: copy empty text\n"));
1929 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1930 "xsltDefaultProcessOneNode: copy text %s\n",
1934 copy
= xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
1936 xsltTransformError(ctxt
, NULL
, node
,
1937 "xsltDefaultProcessOneNode: text copy failed\n");
1940 case XML_ATTRIBUTE_NODE
:
1941 cur
= node
->children
;
1942 while ((cur
!= NULL
) && (cur
->type
!= XML_TEXT_NODE
))
1945 xsltTransformError(ctxt
, NULL
, node
,
1946 "xsltDefaultProcessOneNode: no text for attribute\n");
1948 #ifdef WITH_XSLT_DEBUG_PROCESS
1949 if (cur
->content
== NULL
) {
1950 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1951 "xsltDefaultProcessOneNode: copy empty text\n"));
1953 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1954 "xsltDefaultProcessOneNode: copy text %s\n",
1958 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
1960 xsltTransformError(ctxt
, NULL
, node
,
1961 "xsltDefaultProcessOneNode: text copy failed\n");
1969 * Handling of Elements: first pass, counting
1971 cur
= node
->children
;
1972 while (cur
!= NULL
) {
1973 if (IS_XSLT_REAL_NODE(cur
))
1979 * Handling of Elements: second pass, actual processing
1981 * Note that params are passed to the next template. This matches
1982 * XSLT 2.0 behavior but doesn't conform to XSLT 1.0.
1984 oldSize
= ctxt
->xpathCtxt
->contextSize
;
1985 oldPos
= ctxt
->xpathCtxt
->proximityPosition
;
1986 cur
= node
->children
;
1987 while (cur
!= NULL
) {
1989 switch (cur
->type
) {
1990 case XML_DOCUMENT_NODE
:
1991 case XML_HTML_DOCUMENT_NODE
:
1992 case XML_ELEMENT_NODE
:
1993 ctxt
->xpathCtxt
->contextSize
= nbchild
;
1994 ctxt
->xpathCtxt
->proximityPosition
= childno
;
1995 xsltProcessOneNode(ctxt
, cur
, params
);
1997 case XML_CDATA_SECTION_NODE
:
1998 template = xsltGetTemplate(ctxt
, cur
, NULL
);
2000 #ifdef WITH_XSLT_DEBUG_PROCESS
2001 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2002 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
2006 * Instantiate the xsl:template.
2008 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
2010 } else /* if (ctxt->mode == NULL) */ {
2011 #ifdef WITH_XSLT_DEBUG_PROCESS
2012 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2013 "xsltDefaultProcessOneNode: copy CDATA %s\n",
2016 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
2018 xsltTransformError(ctxt
, NULL
, cur
,
2019 "xsltDefaultProcessOneNode: cdata copy failed\n");
2024 template = xsltGetTemplate(ctxt
, cur
, NULL
);
2026 #ifdef WITH_XSLT_DEBUG_PROCESS
2027 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2028 "xsltDefaultProcessOneNode: applying template for text %s\n",
2031 ctxt
->xpathCtxt
->contextSize
= nbchild
;
2032 ctxt
->xpathCtxt
->proximityPosition
= childno
;
2034 * Instantiate the xsl:template.
2036 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
2038 } else /* if (ctxt->mode == NULL) */ {
2039 #ifdef WITH_XSLT_DEBUG_PROCESS
2040 if (cur
->content
== NULL
) {
2041 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2042 "xsltDefaultProcessOneNode: copy empty text\n"));
2044 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2045 "xsltDefaultProcessOneNode: copy text %s\n",
2049 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
2051 xsltTransformError(ctxt
, NULL
, cur
,
2052 "xsltDefaultProcessOneNode: text copy failed\n");
2057 case XML_COMMENT_NODE
:
2058 template = xsltGetTemplate(ctxt
, cur
, NULL
);
2060 #ifdef WITH_XSLT_DEBUG_PROCESS
2061 if (cur
->type
== XML_PI_NODE
) {
2062 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2063 "xsltDefaultProcessOneNode: template found for PI %s\n",
2065 } else if (cur
->type
== XML_COMMENT_NODE
) {
2066 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2067 "xsltDefaultProcessOneNode: template found for comment\n"));
2070 ctxt
->xpathCtxt
->contextSize
= nbchild
;
2071 ctxt
->xpathCtxt
->proximityPosition
= childno
;
2073 * Instantiate the xsl:template.
2075 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
2084 ctxt
->xpathCtxt
->contextSize
= oldSize
;
2085 ctxt
->xpathCtxt
->proximityPosition
= oldPos
;
2089 * xsltProcessOneNode:
2090 * @ctxt: a XSLT process context
2091 * @contextNode: the "current node" in the source tree
2092 * @withParams: extra parameters (e.g. xsl:with-param) passed to the
2095 * Process the source node.
2098 xsltProcessOneNode(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
2099 xsltStackElemPtr withParams
)
2101 xsltTemplatePtr templ
;
2104 templ
= xsltGetTemplate(ctxt
, contextNode
, NULL
);
2106 * If no template is found, apply the default rule.
2108 if (templ
== NULL
) {
2109 #ifdef WITH_XSLT_DEBUG_PROCESS
2110 if (contextNode
->type
== XML_DOCUMENT_NODE
) {
2111 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2112 "xsltProcessOneNode: no template found for /\n"));
2113 } else if (contextNode
->type
== XML_CDATA_SECTION_NODE
) {
2114 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2115 "xsltProcessOneNode: no template found for CDATA\n"));
2116 } else if (contextNode
->type
== XML_ATTRIBUTE_NODE
) {
2117 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2118 "xsltProcessOneNode: no template found for attribute %s\n",
2119 ((xmlAttrPtr
) contextNode
)->name
));
2121 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2122 "xsltProcessOneNode: no template found for %s\n", contextNode
->name
));
2125 oldNode
= ctxt
->node
;
2126 ctxt
->node
= contextNode
;
2127 xsltDefaultProcessOneNode(ctxt
, contextNode
, withParams
);
2128 ctxt
->node
= oldNode
;
2132 if (contextNode
->type
== XML_ATTRIBUTE_NODE
) {
2133 xsltTemplatePtr oldCurTempRule
= ctxt
->currentTemplateRule
;
2135 * Set the "current template rule".
2137 ctxt
->currentTemplateRule
= templ
;
2139 #ifdef WITH_XSLT_DEBUG_PROCESS
2140 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2141 "xsltProcessOneNode: applying template '%s' for attribute %s\n",
2142 templ
->match
, contextNode
->name
));
2144 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
, templ
, withParams
);
2146 ctxt
->currentTemplateRule
= oldCurTempRule
;
2148 xsltTemplatePtr oldCurTempRule
= ctxt
->currentTemplateRule
;
2150 * Set the "current template rule".
2152 ctxt
->currentTemplateRule
= templ
;
2154 #ifdef WITH_XSLT_DEBUG_PROCESS
2155 if (contextNode
->type
== XML_DOCUMENT_NODE
) {
2156 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2157 "xsltProcessOneNode: applying template '%s' for /\n",
2160 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2161 "xsltProcessOneNode: applying template '%s' for %s\n",
2162 templ
->match
, contextNode
->name
));
2165 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
, templ
, withParams
);
2167 ctxt
->currentTemplateRule
= oldCurTempRule
;
2171 #ifdef WITH_DEBUGGER
2173 xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt
,
2174 xmlNodePtr contextNode
,
2176 xsltTemplatePtr templ
,
2179 xmlNodePtr debugedNode
= NULL
;
2181 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2183 *addCallResult
= xslAddCall(templ
, templ
->elem
);
2185 *addCallResult
= xslAddCall(NULL
, list
);
2187 switch (ctxt
->debugStatus
) {
2188 case XSLT_DEBUG_RUN_RESTART
:
2189 case XSLT_DEBUG_QUIT
:
2195 xslHandleDebugger(templ
->elem
, contextNode
, templ
, ctxt
);
2196 debugedNode
= templ
->elem
;
2198 xslHandleDebugger(list
, contextNode
, templ
, ctxt
);
2200 } else if (ctxt
->inst
) {
2201 xslHandleDebugger(ctxt
->inst
, contextNode
, templ
, ctxt
);
2202 debugedNode
= ctxt
->inst
;
2205 return(debugedNode
);
2207 #endif /* WITH_DEBUGGER */
2210 * xsltLocalVariablePush:
2211 * @ctxt: the transformation context
2212 * @variable: variable to be pushed to the variable stack
2213 * @level: new value for variable's level
2215 * Places the variable onto the local variable stack
2217 * Returns: 0 for success, -1 for any error
2219 * This is an internal routine and should not be called by users!
2222 xsltLocalVariablePush(xsltTransformContextPtr ctxt
,
2223 xsltStackElemPtr variable
,
2226 if (ctxt
->varsNr
>= ctxt
->varsMax
) {
2227 xsltStackElemPtr
*tmp
;
2228 int newMax
= ctxt
->varsMax
== 0 ? 10 : 2 * ctxt
->varsMax
;
2230 tmp
= (xsltStackElemPtr
*) xmlRealloc(ctxt
->varsTab
,
2231 newMax
* sizeof(*tmp
));
2233 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
2236 ctxt
->varsTab
= tmp
;
2237 ctxt
->varsMax
= newMax
;
2239 ctxt
->varsTab
[ctxt
->varsNr
++] = variable
;
2240 ctxt
->vars
= variable
;
2241 variable
->level
= level
;
2246 * xsltReleaseLocalRVTs:
2248 * Fragments which are results of extension instructions
2249 * are preserved; all other fragments are freed/cached.
2252 xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt
, xmlDocPtr base
)
2254 xmlDocPtr cur
= ctxt
->localRVT
, tmp
;
2258 if (cur
->prev
!= NULL
)
2259 xsltTransformError(ctxt
, NULL
, NULL
, "localRVT not head of list\n");
2261 /* Reset localRVT early because some RVTs might be registered again. */
2262 ctxt
->localRVT
= base
;
2268 cur
= (xmlDocPtr
) cur
->next
;
2269 if (tmp
->compression
== XSLT_RVT_LOCAL
) {
2270 xsltReleaseRVT(ctxt
, tmp
);
2271 } else if (tmp
->compression
== XSLT_RVT_GLOBAL
) {
2272 xsltRegisterPersistRVT(ctxt
, tmp
);
2273 } else if (tmp
->compression
== XSLT_RVT_FUNC_RESULT
) {
2275 * This will either register the RVT again or move it to the
2278 xsltRegisterLocalRVT(ctxt
, tmp
);
2279 tmp
->compression
= XSLT_RVT_FUNC_RESULT
;
2281 xmlGenericError(xmlGenericErrorContext
,
2282 "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
2285 } while (cur
!= base
);
2289 * xsltApplySequenceConstructor:
2290 * @ctxt: a XSLT process context
2291 * @contextNode: the "current node" in the source tree
2292 * @list: the nodes of a sequence constructor;
2293 * (plus leading xsl:param elements)
2294 * @templ: the compiled xsl:template (optional)
2296 * Processes a sequence constructor.
2298 * NOTE: ctxt->currentTemplateRule was introduced to reflect the
2299 * semantics of "current template rule". I.e. the field ctxt->templ
2300 * is not intended to reflect this, thus always pushed onto the
2304 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt
,
2305 xmlNodePtr contextNode
, xmlNodePtr list
,
2306 xsltTemplatePtr templ
)
2308 xmlNodePtr oldInsert
, oldInst
, oldCurInst
, oldContextNode
;
2309 xmlNodePtr cur
, insert
, copy
= NULL
;
2310 int level
= 0, oldVarsNr
;
2311 xmlDocPtr oldLocalFragmentTop
;
2313 #ifdef XSLT_REFACTORED
2314 xsltStylePreCompPtr info
;
2317 #ifdef WITH_DEBUGGER
2318 int addCallResult
= 0;
2319 xmlNodePtr debuggedNode
= NULL
;
2325 #ifdef WITH_DEBUGGER
2326 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2328 xsltDebuggerStartSequenceConstructor(ctxt
, contextNode
,
2329 list
, templ
, &addCallResult
);
2330 if (debuggedNode
== NULL
)
2340 * Check for infinite recursion: stop if the maximum of nested templates
2341 * is excceeded. Adjust xsltMaxDepth if you need more.
2343 if (ctxt
->depth
>= ctxt
->maxTemplateDepth
) {
2344 xsltTransformError(ctxt
, NULL
, list
,
2345 "xsltApplySequenceConstructor: A potential infinite template "
2346 "recursion was detected.\n"
2347 "You can adjust xsltMaxDepth (--maxdepth) in order to "
2348 "raise the maximum number of nested template calls and "
2349 "variables/params (currently set to %d).\n",
2350 ctxt
->maxTemplateDepth
);
2351 xsltDebug(ctxt
, contextNode
, list
, NULL
);
2352 ctxt
->state
= XSLT_STATE_STOPPED
;
2357 oldLocalFragmentTop
= ctxt
->localRVT
;
2358 oldInsert
= insert
= ctxt
->insert
;
2359 oldInst
= oldCurInst
= ctxt
->inst
;
2360 oldContextNode
= ctxt
->node
;
2362 * Save current number of variables on the stack; new vars are popped when
2365 oldVarsNr
= ctxt
->varsNr
;
2367 * Process the sequence constructor.
2370 while (cur
!= NULL
) {
2371 if (ctxt
->opLimit
!= 0) {
2372 if (ctxt
->opCount
>= ctxt
->opLimit
) {
2373 xsltTransformError(ctxt
, NULL
, cur
,
2374 "xsltApplySequenceConstructor: "
2375 "Operation limit exceeded\n");
2376 ctxt
->state
= XSLT_STATE_STOPPED
;
2384 #ifdef WITH_DEBUGGER
2385 switch (ctxt
->debugStatus
) {
2386 case XSLT_DEBUG_RUN_RESTART
:
2387 case XSLT_DEBUG_QUIT
:
2393 * Test; we must have a valid insertion point.
2395 if (insert
== NULL
) {
2397 #ifdef WITH_XSLT_DEBUG_PROCESS
2398 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2399 "xsltApplySequenceConstructor: insert == NULL !\n"));
2404 #ifdef WITH_DEBUGGER
2405 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (debuggedNode
!= cur
))
2406 xslHandleDebugger(cur
, contextNode
, templ
, ctxt
);
2409 #ifdef XSLT_REFACTORED
2410 if (cur
->type
== XML_ELEMENT_NODE
) {
2411 info
= (xsltStylePreCompPtr
) cur
->psvi
;
2413 * We expect a compiled representation on:
2414 * 1) XSLT instructions of this XSLT version (1.0)
2415 * (with a few exceptions)
2416 * 2) Literal result elements
2417 * 3) Extension instructions
2418 * 4) XSLT instructions of future XSLT versions
2419 * (forwards-compatible mode).
2423 * Handle the rare cases where we don't expect a compiled
2424 * representation on an XSLT element.
2426 if (IS_XSLT_ELEM_FAST(cur
) && IS_XSLT_NAME(cur
, "message")) {
2427 xsltMessage(ctxt
, contextNode
, cur
);
2431 * Something really went wrong:
2433 xsltTransformError(ctxt
, NULL
, cur
,
2434 "Internal error in xsltApplySequenceConstructor(): "
2435 "The element '%s' in the stylesheet has no compiled "
2436 "representation.\n",
2441 if (info
->type
== XSLT_FUNC_LITERAL_RESULT_ELEMENT
) {
2442 xsltStyleItemLRElementInfoPtr lrInfo
=
2443 (xsltStyleItemLRElementInfoPtr
) info
;
2445 * Literal result elements
2446 * --------------------------------------------------------
2448 #ifdef WITH_XSLT_DEBUG_PROCESS
2449 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2450 xsltGenericDebug(xsltGenericDebugContext
,
2451 "xsltApplySequenceConstructor: copy literal result "
2452 "element '%s'\n", cur
->name
));
2455 * Copy the raw element-node.
2456 * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2460 copy
= xmlDocCopyNode(cur
, insert
->doc
, 0);
2462 xsltTransformError(ctxt
, NULL
, cur
,
2463 "Internal error in xsltApplySequenceConstructor(): "
2464 "Failed to copy literal result element '%s'.\n",
2469 * Add the element-node to the result tree.
2471 copy
->doc
= ctxt
->output
;
2472 copy
= xsltAddChild(insert
, copy
);
2474 * Create effective namespaces declarations.
2475 * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2477 if (lrInfo
->effectiveNs
!= NULL
) {
2478 xsltEffectiveNsPtr effNs
= lrInfo
->effectiveNs
;
2479 xmlNsPtr ns
, lastns
= NULL
;
2481 while (effNs
!= NULL
) {
2483 * Avoid generating redundant namespace
2484 * declarations; thus lookup if there is already
2485 * such a ns-decl in the result.
2487 ns
= xmlSearchNs(copy
->doc
, copy
, effNs
->prefix
);
2489 (xmlStrEqual(ns
->href
, effNs
->nsName
)))
2491 effNs
= effNs
->next
;
2494 ns
= xmlNewNs(copy
, effNs
->nsName
, effNs
->prefix
);
2496 xsltTransformError(ctxt
, NULL
, cur
,
2497 "Internal error in "
2498 "xsltApplySequenceConstructor(): "
2499 "Failed to copy a namespace "
2510 effNs
= effNs
->next
;
2515 * NOTE that we don't need to apply ns-alising: this was
2516 * already done at compile-time.
2518 if (cur
->ns
!= NULL
) {
2520 * If there's no such ns-decl in the result tree,
2521 * then xsltGetSpecialNamespace() will
2522 * create a ns-decl on the copied node.
2524 copy
->ns
= xsltGetSpecialNamespace(ctxt
, cur
,
2525 cur
->ns
->href
, cur
->ns
->prefix
, copy
);
2528 * Undeclare the default namespace if needed.
2529 * This can be skipped, if the result element has
2530 * no ns-decls, in which case the result element
2531 * obviously does not declare a default namespace;
2532 * AND there's either no parent, or the parent
2533 * element is in no namespace; this means there's no
2534 * default namespace is scope to care about.
2536 * REVISIT: This might result in massive
2537 * generation of ns-decls if nodes in a default
2538 * namespaces are mixed with nodes in no namespace.
2542 ((insert
!= NULL
) &&
2543 (insert
->type
== XML_ELEMENT_NODE
) &&
2544 (insert
->ns
!= NULL
)))
2546 xsltGetSpecialNamespace(ctxt
, cur
,
2552 * SPEC XSLT 2.0 "Each attribute of the literal result
2553 * element, other than an attribute in the XSLT namespace,
2554 * is processed to produce an attribute for the element in
2556 * NOTE: See bug #341325.
2558 if (cur
->properties
!= NULL
) {
2559 xsltAttrListTemplateProcess(ctxt
, copy
, cur
->properties
);
2561 } else if (IS_XSLT_ELEM_FAST(cur
)) {
2564 * --------------------------------------------------------
2566 if (info
->type
== XSLT_FUNC_UNKOWN_FORWARDS_COMPAT
) {
2568 * We hit an unknown XSLT element.
2569 * Try to apply one of the fallback cases.
2571 ctxt
->insert
= insert
;
2572 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2573 xsltTransformError(ctxt
, NULL
, cur
,
2574 "The is no fallback behaviour defined for "
2575 "the unknown XSLT element '%s'.\n",
2578 ctxt
->insert
= oldInsert
;
2579 } else if (info
->func
!= NULL
) {
2581 * Execute the XSLT instruction.
2583 ctxt
->insert
= insert
;
2585 info
->func(ctxt
, contextNode
, cur
,
2586 (xsltElemPreCompPtr
) info
);
2589 * Cleanup temporary tree fragments.
2591 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2592 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2594 ctxt
->insert
= oldInsert
;
2595 } else if (info
->type
== XSLT_FUNC_VARIABLE
) {
2596 xsltStackElemPtr tmpvar
= ctxt
->vars
;
2598 xsltParseStylesheetVariable(ctxt
, cur
);
2600 if (tmpvar
!= ctxt
->vars
) {
2602 * TODO: Using a @tmpvar is an annoying workaround, but
2603 * the current mechanisms do not provide any other way
2604 * of knowing if the var was really pushed onto the
2607 ctxt
->vars
->level
= level
;
2609 } else if (info
->type
== XSLT_FUNC_MESSAGE
) {
2611 * TODO: Won't be hit, since we don't compile xsl:message.
2613 xsltMessage(ctxt
, contextNode
, cur
);
2615 xsltTransformError(ctxt
, NULL
, cur
,
2616 "Unexpected XSLT element '%s'.\n", cur
->name
);
2621 xsltTransformFunction func
;
2623 * Extension intructions (elements)
2624 * --------------------------------------------------------
2626 if (cur
->psvi
== xsltExtMarker
) {
2628 * The xsltExtMarker was set during the compilation
2629 * of extension instructions if there was no registered
2630 * handler for this specific extension function at
2632 * Libxslt will now lookup if a handler is
2633 * registered in the context of this transformation.
2635 func
= xsltExtElementLookup(ctxt
, cur
->name
,
2638 func
= ((xsltElemPreCompPtr
) cur
->psvi
)->func
;
2642 * No handler available.
2643 * Try to execute fallback behaviour via xsl:fallback.
2645 #ifdef WITH_XSLT_DEBUG_PROCESS
2646 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2647 xsltGenericDebug(xsltGenericDebugContext
,
2648 "xsltApplySequenceConstructor: unknown extension %s\n",
2651 ctxt
->insert
= insert
;
2652 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2653 xsltTransformError(ctxt
, NULL
, cur
,
2654 "Unknown extension instruction '{%s}%s'.\n",
2655 cur
->ns
->href
, cur
->name
);
2657 ctxt
->insert
= oldInsert
;
2660 * Execute the handler-callback.
2662 #ifdef WITH_XSLT_DEBUG_PROCESS
2663 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2664 "xsltApplySequenceConstructor: extension construct %s\n",
2668 * Disable the xsltCopyTextString optimization for
2669 * extension elements. Extensions could append text using
2670 * xmlAddChild which will free the buffer pointed to by
2671 * 'lasttext'. This buffer could later be reallocated with
2672 * a different size than recorded in 'lasttsize'. See bug
2675 if (cur
->psvi
== xsltExtMarker
) {
2676 ctxt
->lasttext
= NULL
;
2679 ctxt
->insert
= insert
;
2681 func(ctxt
, contextNode
, cur
, cur
->psvi
);
2684 * Cleanup temporary tree fragments.
2686 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2687 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2689 ctxt
->insert
= oldInsert
;
2694 } else if (XSLT_IS_TEXT_NODE(cur
)) {
2697 * ------------------------------------------------------------
2699 #ifdef WITH_XSLT_DEBUG_PROCESS
2700 if (cur
->name
== xmlStringTextNoenc
) {
2701 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2702 xsltGenericDebug(xsltGenericDebugContext
,
2703 "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2706 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2707 xsltGenericDebug(xsltGenericDebugContext
,
2708 "xsltApplySequenceConstructor: copy text '%s'\n",
2712 if (xsltCopyText(ctxt
, insert
, cur
, ctxt
->internalized
) == NULL
)
2716 #else /* XSLT_REFACTORED */
2718 if (IS_XSLT_ELEM(cur
)) {
2720 * This is an XSLT node
2722 xsltStylePreCompPtr info
= (xsltStylePreCompPtr
) cur
->psvi
;
2725 if (IS_XSLT_NAME(cur
, "message")) {
2726 xsltMessage(ctxt
, contextNode
, cur
);
2729 * That's an error try to apply one of the fallback cases
2731 ctxt
->insert
= insert
;
2732 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2733 xsltGenericError(xsltGenericErrorContext
,
2734 "xsltApplySequenceConstructor: %s was not compiled\n",
2737 ctxt
->insert
= oldInsert
;
2742 if (info
->func
!= NULL
) {
2743 oldCurInst
= ctxt
->inst
;
2745 ctxt
->insert
= insert
;
2747 info
->func(ctxt
, contextNode
, cur
, (xsltElemPreCompPtr
) info
);
2750 * Cleanup temporary tree fragments.
2752 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2753 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2755 ctxt
->insert
= oldInsert
;
2756 ctxt
->inst
= oldCurInst
;
2760 if (IS_XSLT_NAME(cur
, "variable")) {
2761 xsltStackElemPtr tmpvar
= ctxt
->vars
;
2763 oldCurInst
= ctxt
->inst
;
2766 xsltParseStylesheetVariable(ctxt
, cur
);
2768 ctxt
->inst
= oldCurInst
;
2770 if (tmpvar
!= ctxt
->vars
) {
2772 * TODO: Using a @tmpvar is an annoying workaround, but
2773 * the current mechanisms do not provide any other way
2774 * of knowing if the var was really pushed onto the
2777 ctxt
->vars
->level
= level
;
2779 } else if (IS_XSLT_NAME(cur
, "message")) {
2780 xsltMessage(ctxt
, contextNode
, cur
);
2782 xsltTransformError(ctxt
, NULL
, cur
,
2783 "Unexpected XSLT element '%s'.\n", cur
->name
);
2786 } else if ((cur
->type
== XML_TEXT_NODE
) ||
2787 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
2790 * This text comes from the stylesheet
2791 * For stylesheets, the set of whitespace-preserving
2792 * element names consists of just xsl:text.
2794 #ifdef WITH_XSLT_DEBUG_PROCESS
2795 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
2796 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2797 "xsltApplySequenceConstructor: copy CDATA text %s\n",
2799 } else if (cur
->name
== xmlStringTextNoenc
) {
2800 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2801 "xsltApplySequenceConstructor: copy unescaped text %s\n",
2804 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2805 "xsltApplySequenceConstructor: copy text %s\n",
2809 if (xsltCopyText(ctxt
, insert
, cur
, ctxt
->internalized
) == NULL
)
2811 } else if ((cur
->type
== XML_ELEMENT_NODE
) &&
2812 (cur
->ns
!= NULL
) && (cur
->psvi
!= NULL
)) {
2813 xsltTransformFunction function
;
2815 oldCurInst
= ctxt
->inst
;
2818 * Flagged as an extension element
2820 if (cur
->psvi
== xsltExtMarker
)
2821 function
= xsltExtElementLookup(ctxt
, cur
->name
,
2824 function
= ((xsltElemPreCompPtr
) cur
->psvi
)->func
;
2826 if (function
== NULL
) {
2830 #ifdef WITH_XSLT_DEBUG_PROCESS
2831 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2832 "xsltApplySequenceConstructor: unknown extension %s\n",
2836 * Search if there are fallbacks
2838 ctxt
->insert
= insert
;
2839 child
= cur
->children
;
2840 while (child
!= NULL
) {
2841 if ((IS_XSLT_ELEM(child
)) &&
2842 (IS_XSLT_NAME(child
, "fallback")))
2845 xsltApplySequenceConstructor(ctxt
, contextNode
,
2846 child
->children
, NULL
);
2848 child
= child
->next
;
2850 ctxt
->insert
= oldInsert
;
2853 xsltTransformError(ctxt
, NULL
, cur
,
2854 "xsltApplySequenceConstructor: failed to find extension %s\n",
2858 #ifdef WITH_XSLT_DEBUG_PROCESS
2859 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2860 "xsltApplySequenceConstructor: extension construct %s\n",
2865 * Disable the xsltCopyTextString optimization for
2866 * extension elements. Extensions could append text using
2867 * xmlAddChild which will free the buffer pointed to by
2868 * 'lasttext'. This buffer could later be reallocated with
2869 * a different size than recorded in 'lasttsize'. See bug
2872 if (cur
->psvi
== xsltExtMarker
) {
2873 ctxt
->lasttext
= NULL
;
2876 ctxt
->insert
= insert
;
2878 function(ctxt
, contextNode
, cur
, cur
->psvi
);
2880 * Cleanup temporary tree fragments.
2882 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2883 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2885 ctxt
->insert
= oldInsert
;
2888 ctxt
->inst
= oldCurInst
;
2890 } else if (cur
->type
== XML_ELEMENT_NODE
) {
2891 #ifdef WITH_XSLT_DEBUG_PROCESS
2892 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2893 "xsltApplySequenceConstructor: copy node %s\n",
2896 oldCurInst
= ctxt
->inst
;
2899 if ((copy
= xsltShallowCopyElem(ctxt
, cur
, insert
, 1)) == NULL
)
2902 * Add extra namespaces inherited from the current template
2903 * if we are in the first level children and this is a
2906 if ((templ
!= NULL
) && (oldInsert
== insert
) &&
2907 (ctxt
->templ
!= NULL
) && (ctxt
->templ
->inheritedNs
!= NULL
)) {
2911 for (i
= 0; i
< ctxt
->templ
->inheritedNsNr
; i
++) {
2912 const xmlChar
*URI
= NULL
;
2913 xsltStylesheetPtr style
;
2914 ns
= ctxt
->templ
->inheritedNs
[i
];
2916 /* Note that the XSLT namespace was already excluded
2917 * in xsltGetInheritedNsList().
2920 if (xmlStrEqual(ns
->href
, XSLT_NAMESPACE
))
2923 style
= ctxt
->style
;
2924 while (style
!= NULL
) {
2925 if (style
->nsAliases
!= NULL
)
2926 URI
= (const xmlChar
*)
2927 xmlHashLookup(style
->nsAliases
, ns
->href
);
2931 style
= xsltNextImport(style
);
2933 if (URI
== UNDEFINED_DEFAULT_NS
)
2938 * TODO: The following will still be buggy for the
2939 * non-refactored code.
2941 ret
= xmlSearchNs(copy
->doc
, copy
, ns
->prefix
);
2942 if ((ret
== NULL
) || (!xmlStrEqual(ret
->href
, URI
)))
2944 xmlNewNs(copy
, URI
, ns
->prefix
);
2947 if (copy
->ns
!= NULL
) {
2949 * Fix the node namespace if needed
2951 copy
->ns
= xsltGetNamespace(ctxt
, cur
, copy
->ns
, copy
);
2955 * all the attributes are directly inherited
2957 if (cur
->properties
!= NULL
) {
2958 xsltAttrListTemplateProcess(ctxt
, copy
, cur
->properties
);
2960 ctxt
->inst
= oldCurInst
;
2962 #endif /* else of XSLT_REFACTORED */
2965 * Descend into content in document order.
2967 if (cur
->children
!= NULL
) {
2968 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
2969 cur
= cur
->children
;
2979 * If xslt:message was just processed, we might have hit a
2980 * terminate='yes'; if so, then break the loop and clean up.
2981 * TODO: Do we need to check this also before trying to descend
2984 if (ctxt
->state
== XSLT_STATE_STOPPED
)
2986 if (cur
->next
!= NULL
) {
2995 * Pop variables/params (xsl:variable and xsl:param).
2997 if ((ctxt
->varsNr
> oldVarsNr
) && (ctxt
->vars
->level
> level
)) {
2998 xsltLocalVariablePop(ctxt
, oldVarsNr
, level
);
3001 insert
= insert
->parent
;
3004 if (cur
== list
->parent
) {
3008 if (cur
->next
!= NULL
) {
3012 } while (cur
!= NULL
);
3017 * In case of errors: pop remaining variables.
3019 if (ctxt
->varsNr
> oldVarsNr
)
3020 xsltLocalVariablePop(ctxt
, oldVarsNr
, -1);
3022 ctxt
->node
= oldContextNode
;
3023 ctxt
->inst
= oldInst
;
3024 ctxt
->insert
= oldInsert
;
3028 #ifdef WITH_DEBUGGER
3029 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (addCallResult
)) {
3036 * xsltApplyXSLTTemplate:
3037 * @ctxt: a XSLT transformation context
3038 * @contextNode: the node in the source tree.
3039 * @list: the nodes of a sequence constructor;
3040 * (plus leading xsl:param elements)
3041 * @templ: the compiled xsl:template declaration;
3042 * NULL if a sequence constructor
3043 * @withParams: a set of caller-parameters (xsl:with-param) or NULL
3046 * - xsltApplyImports()
3047 * - xsltCallTemplate()
3048 * - xsltDefaultProcessOneNode()
3049 * - xsltProcessOneNode()
3052 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt
,
3053 xmlNodePtr contextNode
,
3055 xsltTemplatePtr templ
,
3056 xsltStackElemPtr withParams
)
3058 int oldVarsBase
= 0;
3060 xsltStackElemPtr tmpParam
= NULL
;
3061 xmlDocPtr oldUserFragmentTop
;
3062 #ifdef WITH_PROFILER
3066 #ifdef XSLT_REFACTORED
3067 xsltStyleItemParamPtr iparam
;
3069 xsltStylePreCompPtr iparam
;
3072 #ifdef WITH_DEBUGGER
3073 int addCallResult
= 0;
3078 if (templ
== NULL
) {
3079 xsltTransformError(ctxt
, NULL
, list
,
3080 "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
3084 #ifdef WITH_DEBUGGER
3085 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
3086 if (xsltDebuggerStartSequenceConstructor(ctxt
, contextNode
,
3087 list
, templ
, &addCallResult
) == NULL
)
3096 if (ctxt
->varsNr
>= ctxt
->maxTemplateVars
)
3098 xsltTransformError(ctxt
, NULL
, list
,
3099 "xsltApplyXSLTTemplate: A potential infinite template recursion "
3101 "You can adjust maxTemplateVars (--maxvars) in order to "
3102 "raise the maximum number of variables/params (currently set to %d).\n",
3103 ctxt
->maxTemplateVars
);
3104 xsltDebug(ctxt
, contextNode
, list
, NULL
);
3105 ctxt
->state
= XSLT_STATE_STOPPED
;
3109 oldUserFragmentTop
= ctxt
->tmpRVT
;
3110 ctxt
->tmpRVT
= NULL
;
3113 * Initiate a distinct scope of local params/variables.
3115 oldVarsBase
= ctxt
->varsBase
;
3116 ctxt
->varsBase
= ctxt
->varsNr
;
3118 ctxt
->node
= contextNode
;
3120 #ifdef WITH_PROFILER
3121 if (ctxt
->profile
) {
3123 start
= xsltTimestamp();
3125 profCallgraphAdd(templ
, ctxt
->templ
);
3130 * Push the xsl:template declaration onto the stack.
3132 templPush(ctxt
, templ
);
3134 #ifdef WITH_XSLT_DEBUG_PROCESS
3135 if (templ
->name
!= NULL
)
3136 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
3137 "applying xsl:template '%s'\n", templ
->name
));
3140 * Process xsl:param instructions and skip those elements for
3141 * further processing.
3145 if (cur
->type
== XML_TEXT_NODE
) {
3149 if ((cur
->type
!= XML_ELEMENT_NODE
) ||
3150 (cur
->name
[0] != 'p') ||
3151 (cur
->psvi
== NULL
) ||
3152 (! xmlStrEqual(cur
->name
, BAD_CAST
"param")) ||
3153 (! IS_XSLT_ELEM(cur
)))
3160 #ifdef XSLT_REFACTORED
3161 iparam
= (xsltStyleItemParamPtr
) cur
->psvi
;
3163 iparam
= (xsltStylePreCompPtr
) cur
->psvi
;
3167 * Substitute xsl:param for a given xsl:with-param.
3168 * Since the XPath expression will reference the params/vars
3169 * by index, we need to slot the xsl:with-params in the
3170 * order of encountered xsl:params to keep the sequence of
3171 * params/variables in the stack exactly as it was at
3176 tmpParam
= withParams
;
3178 if ((tmpParam
->name
== (iparam
->name
)) &&
3179 (tmpParam
->nameURI
== (iparam
->ns
)))
3182 * Push the caller-parameter.
3184 xsltLocalVariablePush(ctxt
, tmpParam
, -1);
3187 tmpParam
= tmpParam
->next
;
3188 } while (tmpParam
!= NULL
);
3191 * Push the xsl:param.
3193 if (tmpParam
== NULL
) {
3195 * Note that we must assume that the added parameter
3196 * has a @depth of 0.
3198 xsltParseStylesheetParam(ctxt
, cur
);
3201 } while (cur
!= NULL
);
3203 * Process the sequence constructor.
3205 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3208 * Remove remaining xsl:param and xsl:with-param items from
3209 * the stack. Don't free xsl:with-param items.
3211 if (ctxt
->varsNr
> ctxt
->varsBase
)
3212 xsltTemplateParamsCleanup(ctxt
);
3213 ctxt
->varsBase
= oldVarsBase
;
3216 * Release user-created fragments stored in the scope
3217 * of xsl:template. Note that this mechanism is deprecated:
3218 * user code should now use xsltRegisterLocalRVT() instead
3219 * of the obsolete xsltRegisterTmpRVT().
3222 xmlDocPtr curdoc
= ctxt
->tmpRVT
, tmp
;
3224 while (curdoc
!= NULL
) {
3226 curdoc
= (xmlDocPtr
) curdoc
->next
;
3227 xsltReleaseRVT(ctxt
, tmp
);
3230 ctxt
->tmpRVT
= oldUserFragmentTop
;
3233 * Pop the xsl:template declaration from the stack.
3237 #ifdef WITH_PROFILER
3238 if (ctxt
->profile
) {
3239 long spent
, child
, total
, end
;
3241 end
= xsltTimestamp();
3242 child
= profPop(ctxt
);
3243 total
= end
- start
;
3244 spent
= total
- child
;
3247 * Not possible unless the original calibration failed
3248 * we can try to correct it on the fly.
3250 xsltCalibrateAdjust(spent
);
3254 templ
->time
+= spent
;
3255 if (ctxt
->profNr
> 0)
3256 ctxt
->profTab
[ctxt
->profNr
- 1] += total
;
3260 #ifdef WITH_DEBUGGER
3261 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (addCallResult
)) {
3269 * xsltApplyOneTemplate:
3270 * @ctxt: a XSLT process context
3271 * @contextNode: the node in the source tree.
3272 * @list: the nodes of a sequence constructor
3274 * @params: a set of parameters (xsl:param) or NULL
3276 * Processes a sequence constructor on the current node in the source tree.
3278 * @params are the already computed variable stack items; this function
3279 * pushes them on the variable stack, and pops them before exiting; it's
3280 * left to the caller to free or reuse @params afterwards. The initial
3281 * states of the variable stack will always be restored before this
3283 * NOTE that this does *not* initiate a new distinct variable scope; i.e.
3284 * variables already on the stack are visible to the process. The caller's
3285 * side needs to start a new variable scope if needed (e.g. in exsl:function).
3287 * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
3288 * provide a @templ); a non-NULL @templ might raise an error in the future.
3290 * BIG NOTE: This function is not intended to process the content of an
3291 * xsl:template; it does not expect xsl:param instructions in @list and
3292 * will report errors if found.
3295 * - xsltEvalVariable() (variables.c)
3296 * - exsltFuncFunctionFunction() (libexsl/functions.c)
3299 xsltApplyOneTemplate(xsltTransformContextPtr ctxt
,
3300 xmlNodePtr contextNode
,
3302 xsltTemplatePtr templ ATTRIBUTE_UNUSED
,
3303 xsltStackElemPtr params
)
3305 if ((ctxt
== NULL
) || (list
== NULL
))
3311 * This code should be obsolete - was previously used
3312 * by libexslt/functions.c, but due to bug 381319 the
3313 * logic there was changed.
3315 int oldVarsNr
= ctxt
->varsNr
;
3318 * Push the given xsl:param(s) onto the variable stack.
3320 while (params
!= NULL
) {
3321 xsltLocalVariablePush(ctxt
, params
, -1);
3322 params
= params
->next
;
3324 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3326 * Pop the given xsl:param(s) from the stack but don't free them.
3328 xsltLocalVariablePop(ctxt
, oldVarsNr
, -2);
3330 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3333 /************************************************************************
3335 * XSLT-1.1 extensions *
3337 ************************************************************************/
3341 * @ctxt: an XSLT processing context
3342 * @node: The current node
3343 * @inst: the instruction in the stylesheet
3344 * @castedComp: precomputed information
3346 * Process an EXSLT/XSLT-1.1 document element
3349 xsltDocumentElem(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3350 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
3352 #ifdef XSLT_REFACTORED
3353 xsltStyleItemDocumentPtr comp
= (xsltStyleItemDocumentPtr
) castedComp
;
3355 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
3357 xsltStylesheetPtr style
= NULL
;
3359 xmlChar
*filename
= NULL
, *prop
, *elements
;
3360 xmlChar
*element
, *end
;
3361 xmlDocPtr res
= NULL
;
3362 xmlDocPtr oldOutput
;
3363 xmlNodePtr oldInsert
, root
;
3364 const char *oldOutputFile
;
3365 xsltOutputType oldType
;
3366 xmlChar
*URL
= NULL
;
3367 const xmlChar
*method
;
3368 const xmlChar
*doctypePublic
;
3369 const xmlChar
*doctypeSystem
;
3370 const xmlChar
*version
;
3371 const xmlChar
*encoding
;
3372 int redirect_write_append
= 0;
3374 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
3377 if (comp
->filename
== NULL
) {
3379 if (xmlStrEqual(inst
->name
, (const xmlChar
*) "output")) {
3381 * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
3382 * (http://icl.com/saxon)
3383 * The @file is in no namespace.
3385 #ifdef WITH_XSLT_DEBUG_EXTRA
3386 xsltGenericDebug(xsltGenericDebugContext
,
3387 "Found saxon:output extension\n");
3389 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3390 (const xmlChar
*) "file",
3391 XSLT_SAXON_NAMESPACE
);
3394 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3395 (const xmlChar
*) "href",
3396 XSLT_SAXON_NAMESPACE
);
3397 } else if (xmlStrEqual(inst
->name
, (const xmlChar
*) "write")) {
3398 #ifdef WITH_XSLT_DEBUG_EXTRA
3399 xsltGenericDebug(xsltGenericDebugContext
,
3400 "Found xalan:write extension\n");
3402 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3405 XSLT_XALAN_NAMESPACE
);
3407 xmlXPathCompExprPtr cmp
;
3411 * Trying to handle bug #59212
3412 * The value of the "select" attribute is an
3414 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
3416 cmp
= xmlXPathCtxtCompile(ctxt
->xpathCtxt
, URL
);
3417 val
= xsltEvalXPathString(ctxt
, cmp
);
3418 xmlXPathFreeCompExpr(cmp
);
3423 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3426 XSLT_XALAN_NAMESPACE
);
3428 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3431 XSLT_XALAN_NAMESPACE
);
3432 } else if (xmlStrEqual(inst
->name
, (const xmlChar
*) "document")) {
3433 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3434 (const xmlChar
*) "href",
3439 URL
= xmlStrdup(comp
->filename
);
3443 xsltTransformError(ctxt
, NULL
, inst
,
3444 "xsltDocumentElem: href/URI-Reference not found\n");
3449 * If the computation failed, it's likely that the URL wasn't escaped
3451 filename
= xmlBuildURI(URL
, (const xmlChar
*) ctxt
->outputFile
);
3452 if (filename
== NULL
) {
3455 escURL
=xmlURIEscapeStr(URL
, BAD_CAST
":/.?,");
3456 if (escURL
!= NULL
) {
3457 filename
= xmlBuildURI(escURL
, (const xmlChar
*) ctxt
->outputFile
);
3462 if (filename
== NULL
) {
3463 xsltTransformError(ctxt
, NULL
, inst
,
3464 "xsltDocumentElem: URL computation failed for %s\n",
3471 * Security checking: can we write to this resource
3473 if (ctxt
->sec
!= NULL
) {
3474 ret
= xsltCheckWrite(ctxt
->sec
, ctxt
, filename
);
3477 xsltTransformError(ctxt
, NULL
, inst
,
3478 "xsltDocumentElem: write rights for %s denied\n",
3486 oldOutputFile
= ctxt
->outputFile
;
3487 oldOutput
= ctxt
->output
;
3488 oldInsert
= ctxt
->insert
;
3489 oldType
= ctxt
->type
;
3490 ctxt
->outputFile
= (const char *) filename
;
3492 style
= xsltNewStylesheet();
3493 if (style
== NULL
) {
3494 xsltTransformError(ctxt
, NULL
, inst
,
3495 "xsltDocumentElem: out of memory\n");
3500 * Version described in 1.1 draft allows full parameterization
3503 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3504 (const xmlChar
*) "version",
3507 if (style
->version
!= NULL
)
3508 xmlFree(style
->version
);
3509 style
->version
= prop
;
3511 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3512 (const xmlChar
*) "encoding",
3515 if (style
->encoding
!= NULL
)
3516 xmlFree(style
->encoding
);
3517 style
->encoding
= prop
;
3519 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3520 (const xmlChar
*) "method",
3525 if (style
->method
!= NULL
)
3526 xmlFree(style
->method
);
3527 style
->method
= NULL
;
3528 if (style
->methodURI
!= NULL
)
3529 xmlFree(style
->methodURI
);
3530 style
->methodURI
= NULL
;
3532 URI
= xsltGetQNameURI(inst
, &prop
);
3534 if (style
!= NULL
) style
->errors
++;
3535 } else if (URI
== NULL
) {
3536 if ((xmlStrEqual(prop
, (const xmlChar
*) "xml")) ||
3537 (xmlStrEqual(prop
, (const xmlChar
*) "html")) ||
3538 (xmlStrEqual(prop
, (const xmlChar
*) "text"))) {
3539 style
->method
= prop
;
3541 xsltTransformError(ctxt
, NULL
, inst
,
3542 "invalid value for method: %s\n", prop
);
3543 if (style
!= NULL
) style
->warnings
++;
3546 style
->method
= prop
;
3547 style
->methodURI
= xmlStrdup(URI
);
3550 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3552 "doctype-system", NULL
);
3554 if (style
->doctypeSystem
!= NULL
)
3555 xmlFree(style
->doctypeSystem
);
3556 style
->doctypeSystem
= prop
;
3558 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3560 "doctype-public", NULL
);
3562 if (style
->doctypePublic
!= NULL
)
3563 xmlFree(style
->doctypePublic
);
3564 style
->doctypePublic
= prop
;
3566 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3567 (const xmlChar
*) "standalone",
3570 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3571 style
->standalone
= 1;
3572 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3573 style
->standalone
= 0;
3575 xsltTransformError(ctxt
, NULL
, inst
,
3576 "invalid value for standalone: %s\n",
3578 if (style
!= NULL
) style
->warnings
++;
3583 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3584 (const xmlChar
*) "indent",
3587 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3589 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3592 xsltTransformError(ctxt
, NULL
, inst
,
3593 "invalid value for indent: %s\n", prop
);
3594 if (style
!= NULL
) style
->warnings
++;
3599 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3601 "omit-xml-declaration",
3604 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3605 style
->omitXmlDeclaration
= 1;
3606 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3607 style
->omitXmlDeclaration
= 0;
3609 xsltTransformError(ctxt
, NULL
, inst
,
3610 "invalid value for omit-xml-declaration: %s\n",
3612 if (style
!= NULL
) style
->warnings
++;
3617 elements
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3619 "cdata-section-elements",
3621 if (elements
!= NULL
) {
3622 if (style
->stripSpaces
== NULL
)
3623 style
->stripSpaces
= xmlHashCreate(10);
3624 if (style
->stripSpaces
== NULL
) {
3630 while (*element
!= 0) {
3631 while (xmlIsBlank_ch(*element
))
3636 while ((*end
!= 0) && (!xmlIsBlank_ch(*end
)))
3638 element
= xmlStrndup(element
, end
- element
);
3642 #ifdef WITH_XSLT_DEBUG_PARSING
3643 xsltGenericDebug(xsltGenericDebugContext
,
3644 "add cdata section output element %s\n",
3647 URI
= xsltGetQNameURI(inst
, &element
);
3649 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
3650 (xmlChar
*) "cdata");
3659 * Create a new document tree and process the element template
3661 XSLT_GET_IMPORT_PTR(method
, style
, method
)
3662 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
3663 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
3664 XSLT_GET_IMPORT_PTR(version
, style
, version
)
3665 XSLT_GET_IMPORT_PTR(encoding
, style
, encoding
)
3667 if ((method
!= NULL
) &&
3668 (!xmlStrEqual(method
, (const xmlChar
*) "xml"))) {
3669 if (xmlStrEqual(method
, (const xmlChar
*) "html")) {
3670 ctxt
->type
= XSLT_OUTPUT_HTML
;
3671 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3672 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
3674 if (version
!= NULL
) {
3675 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3676 xsltGetHTMLIDs(version
, &doctypePublic
, &doctypeSystem
);
3679 res
= htmlNewDocNoDtD(doctypeSystem
, doctypePublic
);
3683 res
->dict
= ctxt
->dict
;
3684 xmlDictReference(res
->dict
);
3685 } else if (xmlStrEqual(method
, (const xmlChar
*) "xhtml")) {
3686 xsltTransformError(ctxt
, NULL
, inst
,
3687 "xsltDocumentElem: unsupported method xhtml\n");
3688 ctxt
->type
= XSLT_OUTPUT_HTML
;
3689 res
= htmlNewDocNoDtD(doctypeSystem
, doctypePublic
);
3692 res
->dict
= ctxt
->dict
;
3693 xmlDictReference(res
->dict
);
3694 } else if (xmlStrEqual(method
, (const xmlChar
*) "text")) {
3695 ctxt
->type
= XSLT_OUTPUT_TEXT
;
3696 res
= xmlNewDoc(style
->version
);
3699 res
->dict
= ctxt
->dict
;
3700 xmlDictReference(res
->dict
);
3701 #ifdef WITH_XSLT_DEBUG
3702 xsltGenericDebug(xsltGenericDebugContext
,
3703 "reusing transformation dict for output\n");
3706 xsltTransformError(ctxt
, NULL
, inst
,
3707 "xsltDocumentElem: unsupported method (%s)\n",
3712 ctxt
->type
= XSLT_OUTPUT_XML
;
3713 res
= xmlNewDoc(style
->version
);
3716 res
->dict
= ctxt
->dict
;
3717 xmlDictReference(res
->dict
);
3718 #ifdef WITH_XSLT_DEBUG
3719 xsltGenericDebug(xsltGenericDebugContext
,
3720 "reusing transformation dict for output\n");
3723 res
->charset
= XML_CHAR_ENCODING_UTF8
;
3724 if (encoding
!= NULL
)
3725 res
->encoding
= xmlStrdup(encoding
);
3727 ctxt
->insert
= (xmlNodePtr
) res
;
3728 xsltApplySequenceConstructor(ctxt
, node
, inst
->children
, NULL
);
3731 * Do some post processing work depending on the generated output
3733 root
= xmlDocGetRootElement(res
);
3735 const xmlChar
*doctype
= NULL
;
3737 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
))
3738 doctype
= xmlDictQLookup(ctxt
->dict
, root
->ns
->prefix
, root
->name
);
3739 if (doctype
== NULL
)
3740 doctype
= root
->name
;
3743 * Apply the default selection of the method
3745 if ((method
== NULL
) &&
3746 (root
->ns
== NULL
) &&
3747 (!xmlStrcasecmp(root
->name
, (const xmlChar
*) "html"))) {
3750 tmp
= res
->children
;
3751 while ((tmp
!= NULL
) && (tmp
!= root
)) {
3752 if (tmp
->type
== XML_ELEMENT_NODE
)
3754 if ((tmp
->type
== XML_TEXT_NODE
) && (!xmlIsBlankNode(tmp
)))
3759 ctxt
->type
= XSLT_OUTPUT_HTML
;
3760 res
->type
= XML_HTML_DOCUMENT_NODE
;
3761 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
3762 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
3765 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3766 } else if (version
!= NULL
) {
3767 xsltGetHTMLIDs(version
, &doctypePublic
,
3769 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3771 xmlCreateIntSubset(res
, doctype
,
3779 if (ctxt
->type
== XSLT_OUTPUT_XML
) {
3780 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
3781 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
3782 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3783 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
3790 * Calls to redirect:write also take an optional attribute append.
3791 * Attribute append="true|yes" which will attempt to simply append
3792 * to an existing file instead of always opening a new file. The
3793 * default behavior of always overwriting the file still happens
3794 * if we do not specify append.
3795 * Note that append use will forbid use of remote URI target.
3797 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
, (const xmlChar
*)"append",
3800 if (xmlStrEqual(prop
, (const xmlChar
*) "true") ||
3801 xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3802 style
->omitXmlDeclaration
= 1;
3803 redirect_write_append
= 1;
3805 style
->omitXmlDeclaration
= 0;
3809 if (redirect_write_append
) {
3812 f
= fopen((const char *) filename
, "ab");
3816 ret
= xsltSaveResultToFile(f
, res
, style
);
3820 ret
= xsltSaveResultToFilename((const char *) filename
, res
, style
, 0);
3823 xsltTransformError(ctxt
, NULL
, inst
,
3824 "xsltDocumentElem: unable to save to %s\n",
3826 #ifdef WITH_XSLT_DEBUG_EXTRA
3828 xsltGenericDebug(xsltGenericDebugContext
,
3829 "Wrote %d bytes to %s\n", ret
, filename
);
3834 ctxt
->output
= oldOutput
;
3835 ctxt
->insert
= oldInsert
;
3836 ctxt
->type
= oldType
;
3837 ctxt
->outputFile
= oldOutputFile
;
3840 if (filename
!= NULL
)
3843 xsltFreeStylesheet(style
);
3848 /************************************************************************
3850 * Most of the XSLT-1.0 transformations *
3852 ************************************************************************/
3856 * @ctxt: a XSLT process context
3857 * @node: the node in the source tree.
3858 * @inst: the xslt sort node
3859 * @comp: precomputed information
3861 * function attached to xsl:sort nodes, but this should not be
3865 xsltSort(xsltTransformContextPtr ctxt
,
3866 xmlNodePtr node ATTRIBUTE_UNUSED
, xmlNodePtr inst
,
3867 xsltElemPreCompPtr comp
) {
3869 xsltTransformError(ctxt
, NULL
, inst
,
3870 "xsl:sort : compilation failed\n");
3873 xsltTransformError(ctxt
, NULL
, inst
,
3874 "xsl:sort : improper use this should not be reached\n");
3879 * @ctxt: an XSLT process context
3880 * @node: the node in the source tree
3881 * @inst: the element node of the XSLT-copy instruction
3882 * @castedComp: computed information of the XSLT-copy instruction
3884 * Execute the XSLT-copy instruction on the source node.
3887 xsltCopy(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3888 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
3890 #ifdef XSLT_REFACTORED
3891 xsltStyleItemCopyPtr comp
= (xsltStyleItemCopyPtr
) castedComp
;
3893 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
3895 xmlNodePtr copy
, oldInsert
;
3897 oldInsert
= ctxt
->insert
;
3898 if (ctxt
->insert
!= NULL
) {
3899 switch (node
->type
) {
3901 case XML_CDATA_SECTION_NODE
:
3903 * This text comes from the stylesheet
3904 * For stylesheets, the set of whitespace-preserving
3905 * element names consists of just xsl:text.
3907 #ifdef WITH_XSLT_DEBUG_PROCESS
3908 if (node
->type
== XML_CDATA_SECTION_NODE
) {
3909 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3910 "xsltCopy: CDATA text %s\n", node
->content
));
3912 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3913 "xsltCopy: text %s\n", node
->content
));
3916 xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
3918 case XML_DOCUMENT_NODE
:
3919 case XML_HTML_DOCUMENT_NODE
:
3921 case XML_ELEMENT_NODE
:
3923 * REVISIT NOTE: The "fake" is a doc-node, not an element node.
3925 * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3929 #ifdef WITH_XSLT_DEBUG_PROCESS
3930 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3931 "xsltCopy: node %s\n", node
->name
));
3933 copy
= xsltShallowCopyElem(ctxt
, node
, ctxt
->insert
, 0);
3934 ctxt
->insert
= copy
;
3935 if (comp
->use
!= NULL
) {
3936 xsltApplyAttributeSet(ctxt
, node
, inst
, comp
->use
);
3939 case XML_ATTRIBUTE_NODE
: {
3940 #ifdef WITH_XSLT_DEBUG_PROCESS
3941 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3942 "xsltCopy: attribute %s\n", node
->name
));
3945 * REVISIT: We could also raise an error if the parent is not
3947 * OPTIMIZE TODO: Can we set the value/children of the
3948 * attribute without an intermediate copy of the string value?
3950 xsltShallowCopyAttr(ctxt
, inst
, ctxt
->insert
, (xmlAttrPtr
) node
);
3954 #ifdef WITH_XSLT_DEBUG_PROCESS
3955 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3956 "xsltCopy: PI %s\n", node
->name
));
3958 copy
= xmlNewDocPI(ctxt
->insert
->doc
, node
->name
,
3960 copy
= xsltAddChild(ctxt
->insert
, copy
);
3962 case XML_COMMENT_NODE
:
3963 #ifdef WITH_XSLT_DEBUG_PROCESS
3964 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3965 "xsltCopy: comment\n"));
3967 copy
= xmlNewComment(node
->content
);
3968 copy
= xsltAddChild(ctxt
->insert
, copy
);
3970 case XML_NAMESPACE_DECL
:
3971 #ifdef WITH_XSLT_DEBUG_PROCESS
3972 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3973 "xsltCopy: namespace declaration\n"));
3975 xsltShallowCopyNsNode(ctxt
, inst
, ctxt
->insert
, (xmlNsPtr
)node
);
3983 switch (node
->type
) {
3984 case XML_DOCUMENT_NODE
:
3985 case XML_HTML_DOCUMENT_NODE
:
3986 case XML_ELEMENT_NODE
:
3987 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, inst
->children
,
3993 ctxt
->insert
= oldInsert
;
3998 * @ctxt: a XSLT process context
3999 * @node: the node in the source tree.
4000 * @inst: the xslt text node
4001 * @comp: precomputed information
4003 * Process the xslt text node on the source node
4006 xsltText(xsltTransformContextPtr ctxt
, xmlNodePtr node ATTRIBUTE_UNUSED
,
4007 xmlNodePtr inst
, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
) {
4008 if ((inst
->children
!= NULL
) && (comp
!= NULL
)) {
4009 xmlNodePtr text
= inst
->children
;
4012 while (text
!= NULL
) {
4013 if ((text
->type
!= XML_TEXT_NODE
) &&
4014 (text
->type
!= XML_CDATA_SECTION_NODE
)) {
4015 xsltTransformError(ctxt
, NULL
, inst
,
4016 "xsl:text content problem\n");
4019 copy
= xmlNewDocText(ctxt
->output
, text
->content
);
4020 if (text
->type
!= XML_CDATA_SECTION_NODE
) {
4021 #ifdef WITH_XSLT_DEBUG_PARSING
4022 xsltGenericDebug(xsltGenericDebugContext
,
4023 "Disable escaping: %s\n", text
->content
);
4025 copy
->name
= xmlStringTextNoenc
;
4027 copy
= xsltAddChild(ctxt
->insert
, copy
);
4035 * @ctxt: a XSLT process context
4036 * @node: the node in the source tree.
4037 * @inst: the xslt element node
4038 * @castedComp: precomputed information
4040 * Process the xslt element node on the source node
4043 xsltElement(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4044 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
) {
4045 #ifdef XSLT_REFACTORED
4046 xsltStyleItemElementPtr comp
= (xsltStyleItemElementPtr
) castedComp
;
4048 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4050 xmlChar
*prop
= NULL
;
4051 const xmlChar
*name
, *prefix
= NULL
, *nsName
= NULL
;
4053 xmlNodePtr oldInsert
;
4055 if (ctxt
->insert
== NULL
)
4059 * A comp->has_name == 0 indicates that we need to skip this instruction,
4060 * since it was evaluated to be invalid already during compilation.
4062 if (!comp
->has_name
)
4068 oldInsert
= ctxt
->insert
;
4070 if (comp
->name
== NULL
) {
4071 /* TODO: fix attr acquisition wrt to the XSLT namespace */
4072 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4073 (const xmlChar
*) "name", XSLT_NAMESPACE
);
4075 xsltTransformError(ctxt
, NULL
, inst
,
4076 "xsl:element: The attribute 'name' is missing.\n");
4079 if (xmlValidateQName(prop
, 0)) {
4080 xsltTransformError(ctxt
, NULL
, inst
,
4081 "xsl:element: The effective name '%s' is not a "
4082 "valid QName.\n", prop
);
4083 /* we fall through to catch any further errors, if possible */
4085 name
= xsltSplitQName(ctxt
->dict
, prop
, &prefix
);
4089 * The "name" value was static.
4091 #ifdef XSLT_REFACTORED
4092 prefix
= comp
->nsPrefix
;
4095 name
= xsltSplitQName(ctxt
->dict
, comp
->name
, &prefix
);
4100 * Create the new element
4102 if (ctxt
->output
->dict
== ctxt
->dict
) {
4103 copy
= xmlNewDocNodeEatName(ctxt
->output
, NULL
, (xmlChar
*)name
, NULL
);
4105 copy
= xmlNewDocNode(ctxt
->output
, NULL
, (xmlChar
*)name
, NULL
);
4108 xsltTransformError(ctxt
, NULL
, inst
,
4109 "xsl:element : creation of %s failed\n", name
);
4112 copy
= xsltAddChild(ctxt
->insert
, copy
);
4114 xsltTransformError(ctxt
, NULL
, inst
,
4115 "xsl:element : xsltAddChild failed\n");
4124 if (comp
->ns
!= NULL
) {
4126 * No AVT; just plain text for the namespace name.
4128 if (comp
->ns
[0] != 0)
4135 /* TODO: check attr acquisition wrt to the XSLT namespace */
4136 tmpNsName
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4137 (const xmlChar
*) "namespace", XSLT_NAMESPACE
);
4140 * "If the string is empty, then the expanded-name of the
4141 * attribute has a null namespace URI."
4143 if ((tmpNsName
!= NULL
) && (tmpNsName
[0] != 0))
4144 nsName
= xmlDictLookup(ctxt
->dict
, BAD_CAST tmpNsName
, -1);
4148 if (xmlStrEqual(nsName
, BAD_CAST
"http://www.w3.org/2000/xmlns/")) {
4149 xsltTransformError(ctxt
, NULL
, inst
,
4150 "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
4154 if (xmlStrEqual(nsName
, XML_XML_NAMESPACE
)) {
4155 prefix
= BAD_CAST
"xml";
4156 } else if (xmlStrEqual(prefix
, BAD_CAST
"xml")) {
4163 * "If the namespace attribute is not present, then the QName is
4164 * expanded into an expanded-name using the namespace declarations
4165 * in effect for the xsl:element element, including any default
4166 * namespace declaration.
4168 ns
= xmlSearchNs(inst
->doc
, inst
, prefix
);
4171 * TODO: Check this in the compilation layer in case it's a
4174 if (prefix
!= NULL
) {
4175 xsltTransformError(ctxt
, NULL
, inst
,
4176 "xsl:element: The QName '%s:%s' has no "
4177 "namespace binding in scope in the stylesheet; "
4178 "this is an error, since the namespace was not "
4179 "specified by the instruction itself.\n", prefix
, name
);
4185 * Find/create a matching ns-decl in the result tree.
4187 if (nsName
!= NULL
) {
4188 if (xmlStrEqual(prefix
, BAD_CAST
"xmlns")) {
4189 /* Don't use a prefix of "xmlns" */
4190 xmlChar
*pref
= xmlStrdup(BAD_CAST
"ns_1");
4192 copy
->ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, pref
, copy
);
4196 copy
->ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, prefix
,
4199 } else if ((copy
->parent
!= NULL
) &&
4200 (copy
->parent
->type
== XML_ELEMENT_NODE
) &&
4201 (copy
->parent
->ns
!= NULL
))
4204 * "Undeclare" the default namespace.
4206 xsltGetSpecialNamespace(ctxt
, inst
, NULL
, NULL
, copy
);
4209 ctxt
->insert
= copy
;
4211 if (comp
->has_use
) {
4212 if (comp
->use
!= NULL
) {
4213 xsltApplyAttributeSet(ctxt
, node
, inst
, comp
->use
);
4215 xmlChar
*attrSets
= NULL
;
4217 * BUG TODO: use-attribute-sets is not a value template.
4218 * use-attribute-sets = qnames
4220 attrSets
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4221 (const xmlChar
*)"use-attribute-sets", NULL
);
4222 if (attrSets
!= NULL
) {
4223 xsltApplyAttributeSet(ctxt
, node
, inst
, attrSets
);
4229 * Instantiate the sequence constructor.
4231 if (inst
->children
!= NULL
)
4232 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, inst
->children
,
4236 ctxt
->insert
= oldInsert
;
4243 * @ctxt: a XSLT process context
4244 * @node: the node in the source tree.
4245 * @inst: the xslt comment node
4246 * @comp: precomputed information
4248 * Process the xslt comment node on the source node
4251 xsltComment(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4252 xmlNodePtr inst
, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
) {
4253 xmlChar
*value
= NULL
;
4254 xmlNodePtr commentNode
;
4257 value
= xsltEvalTemplateString(ctxt
, node
, inst
);
4258 /* TODO: use or generate the compiled form */
4259 len
= xmlStrlen(value
);
4261 if ((value
[len
-1] == '-') ||
4262 (xmlStrstr(value
, BAD_CAST
"--"))) {
4263 xsltTransformError(ctxt
, NULL
, inst
,
4264 "xsl:comment : '--' or ending '-' not allowed in comment\n");
4265 /* fall through to try to catch further errors */
4268 #ifdef WITH_XSLT_DEBUG_PROCESS
4269 if (value
== NULL
) {
4270 XSLT_TRACE(ctxt
,XSLT_TRACE_COMMENT
,xsltGenericDebug(xsltGenericDebugContext
,
4271 "xsltComment: empty\n"));
4273 XSLT_TRACE(ctxt
,XSLT_TRACE_COMMENT
,xsltGenericDebug(xsltGenericDebugContext
,
4274 "xsltComment: content %s\n", value
));
4278 commentNode
= xmlNewComment(value
);
4279 commentNode
= xsltAddChild(ctxt
->insert
, commentNode
);
4286 * xsltProcessingInstruction:
4287 * @ctxt: a XSLT process context
4288 * @node: the node in the source tree.
4289 * @inst: the xslt processing-instruction node
4290 * @castedComp: precomputed information
4292 * Process the xslt processing-instruction node on the source node
4295 xsltProcessingInstruction(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4296 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
) {
4297 #ifdef XSLT_REFACTORED
4298 xsltStyleItemPIPtr comp
= (xsltStyleItemPIPtr
) castedComp
;
4300 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4302 const xmlChar
*name
;
4303 xmlChar
*value
= NULL
;
4307 if (ctxt
->insert
== NULL
)
4309 if (comp
->has_name
== 0)
4311 if (comp
->name
== NULL
) {
4312 name
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4313 (const xmlChar
*)"name", NULL
);
4315 xsltTransformError(ctxt
, NULL
, inst
,
4316 "xsl:processing-instruction : name is missing\n");
4322 /* TODO: check that it's both an an NCName and a PITarget. */
4325 value
= xsltEvalTemplateString(ctxt
, node
, inst
);
4326 if (xmlStrstr(value
, BAD_CAST
"?>") != NULL
) {
4327 xsltTransformError(ctxt
, NULL
, inst
,
4328 "xsl:processing-instruction: '?>' not allowed within PI content\n");
4331 #ifdef WITH_XSLT_DEBUG_PROCESS
4332 if (value
== NULL
) {
4333 XSLT_TRACE(ctxt
,XSLT_TRACE_PI
,xsltGenericDebug(xsltGenericDebugContext
,
4334 "xsltProcessingInstruction: %s empty\n", name
));
4336 XSLT_TRACE(ctxt
,XSLT_TRACE_PI
,xsltGenericDebug(xsltGenericDebugContext
,
4337 "xsltProcessingInstruction: %s content %s\n", name
, value
));
4341 pi
= xmlNewDocPI(ctxt
->insert
->doc
, name
, value
);
4342 pi
= xsltAddChild(ctxt
->insert
, pi
);
4345 if ((name
!= NULL
) && (name
!= comp
->name
))
4346 xmlFree((xmlChar
*) name
);
4353 * @ctxt: an XSLT transformation context
4354 * @node: the current node in the source tree
4355 * @inst: the element node of the XSLT copy-of instruction
4356 * @castedComp: precomputed information of the XSLT copy-of instruction
4358 * Process the XSLT copy-of instruction.
4361 xsltCopyOf(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4362 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
) {
4363 #ifdef XSLT_REFACTORED
4364 xsltStyleItemCopyOfPtr comp
= (xsltStyleItemCopyOfPtr
) castedComp
;
4366 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4368 xmlXPathObjectPtr res
= NULL
;
4369 xmlNodeSetPtr list
= NULL
;
4372 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
))
4374 if ((comp
== NULL
) || (comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
4375 xsltTransformError(ctxt
, NULL
, inst
,
4376 "xsl:copy-of : compilation failed\n");
4382 * "The xsl:copy-of element can be used to insert a result tree
4383 * fragment into the result tree, without first converting it to
4384 * a string as xsl:value-of does (see [7.6.1 Generating Text with
4385 * xsl:value-of]). The required select attribute contains an
4386 * expression. When the result of evaluating the expression is a
4387 * result tree fragment, the complete fragment is copied into the
4388 * result tree. When the result is a node-set, all the nodes in the
4389 * set are copied in document order into the result tree; copying
4390 * an element node copies the attribute nodes, namespace nodes and
4391 * children of the element node as well as the element node itself;
4392 * a root node is copied by copying its children. When the result
4393 * is neither a node-set nor a result tree fragment, the result is
4394 * converted to a string and then inserted into the result tree,
4395 * as with xsl:value-of.
4398 #ifdef WITH_XSLT_DEBUG_PROCESS
4399 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4400 "xsltCopyOf: select %s\n", comp
->select
));
4404 * Evaluate the "select" expression.
4406 res
= xsltPreCompEval(ctxt
, node
, comp
);
4409 if (res
->type
== XPATH_NODESET
) {
4414 #ifdef WITH_XSLT_DEBUG_PROCESS
4415 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4416 "xsltCopyOf: result is a node set\n"));
4418 list
= res
->nodesetval
;
4422 * The list is already sorted in document order by XPath.
4423 * Append everything in this order under ctxt->insert.
4425 for (i
= 0;i
< list
->nodeNr
;i
++) {
4426 cur
= list
->nodeTab
[i
];
4429 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
4430 (cur
->type
== XML_HTML_DOCUMENT_NODE
))
4432 xsltCopyTreeList(ctxt
, inst
,
4433 cur
->children
, ctxt
->insert
, 0, 0);
4434 } else if (cur
->type
== XML_ATTRIBUTE_NODE
) {
4435 xsltShallowCopyAttr(ctxt
, inst
,
4436 ctxt
->insert
, (xmlAttrPtr
) cur
);
4438 xsltCopyTree(ctxt
, inst
, cur
, ctxt
->insert
, 0, 0);
4442 } else if (res
->type
== XPATH_XSLT_TREE
) {
4444 * Result tree fragment
4445 * --------------------
4446 * E.g. via <xsl:variable ...><foo/></xsl:variable>
4447 * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4449 #ifdef WITH_XSLT_DEBUG_PROCESS
4450 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4451 "xsltCopyOf: result is a result tree fragment\n"));
4453 list
= res
->nodesetval
;
4454 if ((list
!= NULL
) && (list
->nodeTab
!= NULL
) &&
4455 (list
->nodeTab
[0] != NULL
) &&
4456 (IS_XSLT_REAL_NODE(list
->nodeTab
[0])))
4458 xsltCopyTreeList(ctxt
, inst
,
4459 list
->nodeTab
[0]->children
, ctxt
->insert
, 0, 0);
4462 xmlChar
*value
= NULL
;
4464 * Convert to a string.
4466 value
= xmlXPathCastToString(res
);
4467 if (value
== NULL
) {
4468 xsltTransformError(ctxt
, NULL
, inst
,
4469 "Internal error in xsltCopyOf(): "
4470 "failed to cast an XPath object to string.\n");
4471 ctxt
->state
= XSLT_STATE_STOPPED
;
4473 if (value
[0] != 0) {
4475 * Append content as text node.
4477 xsltCopyTextString(ctxt
, ctxt
->insert
, value
, 0);
4481 #ifdef WITH_XSLT_DEBUG_PROCESS
4482 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4483 "xsltCopyOf: result %s\n", res
->stringval
));
4488 ctxt
->state
= XSLT_STATE_STOPPED
;
4492 xmlXPathFreeObject(res
);
4497 * @ctxt: a XSLT process context
4498 * @node: the node in the source tree.
4499 * @inst: the xslt value-of node
4500 * @castedComp: precomputed information
4502 * Process the xslt value-of node on the source node
4505 xsltValueOf(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4506 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
4508 #ifdef XSLT_REFACTORED
4509 xsltStyleItemValueOfPtr comp
= (xsltStyleItemValueOfPtr
) castedComp
;
4511 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4513 xmlXPathObjectPtr res
= NULL
;
4514 xmlChar
*value
= NULL
;
4516 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
))
4519 if ((comp
== NULL
) || (comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
4520 xsltTransformError(ctxt
, NULL
, inst
,
4521 "Internal error in xsltValueOf(): "
4522 "The XSLT 'value-of' instruction was not compiled.\n");
4526 #ifdef WITH_XSLT_DEBUG_PROCESS
4527 XSLT_TRACE(ctxt
,XSLT_TRACE_VALUE_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4528 "xsltValueOf: select %s\n", comp
->select
));
4531 res
= xsltPreCompEval(ctxt
, node
, comp
);
4534 * Cast the XPath object to string.
4537 value
= xmlXPathCastToString(res
);
4538 if (value
== NULL
) {
4539 xsltTransformError(ctxt
, NULL
, inst
,
4540 "Internal error in xsltValueOf(): "
4541 "failed to cast an XPath object to string.\n");
4542 ctxt
->state
= XSLT_STATE_STOPPED
;
4545 if (value
[0] != 0) {
4546 xsltCopyTextString(ctxt
, ctxt
->insert
, value
, comp
->noescape
);
4549 xsltTransformError(ctxt
, NULL
, inst
,
4550 "XPath evaluation returned no result.\n");
4551 ctxt
->state
= XSLT_STATE_STOPPED
;
4555 #ifdef WITH_XSLT_DEBUG_PROCESS
4557 XSLT_TRACE(ctxt
,XSLT_TRACE_VALUE_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4558 "xsltValueOf: result '%s'\n", value
));
4566 xmlXPathFreeObject(res
);
4571 * @ctxt: a XSLT process context
4572 * @node: the node in the source tree.
4573 * @inst: the xslt number node
4574 * @castedComp: precomputed information
4576 * Process the xslt number node on the source node
4579 xsltNumber(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4580 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
4582 #ifdef XSLT_REFACTORED
4583 xsltStyleItemNumberPtr comp
= (xsltStyleItemNumberPtr
) castedComp
;
4585 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4587 xmlXPathContextPtr xpctxt
;
4588 xmlNsPtr
*oldXPNamespaces
;
4592 xsltTransformError(ctxt
, NULL
, inst
,
4593 "xsl:number : compilation failed\n");
4597 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
4600 comp
->numdata
.doc
= inst
->doc
;
4601 comp
->numdata
.node
= inst
;
4603 xpctxt
= ctxt
->xpathCtxt
;
4604 oldXPNsNr
= xpctxt
->nsNr
;
4605 oldXPNamespaces
= xpctxt
->namespaces
;
4607 #ifdef XSLT_REFACTORED
4608 if (comp
->inScopeNs
!= NULL
) {
4609 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
4610 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
4612 xpctxt
->namespaces
= NULL
;
4616 xpctxt
->namespaces
= comp
->nsList
;
4617 xpctxt
->nsNr
= comp
->nsNr
;
4620 xsltNumberFormat(ctxt
, &comp
->numdata
, node
);
4622 xpctxt
->nsNr
= oldXPNsNr
;
4623 xpctxt
->namespaces
= oldXPNamespaces
;
4628 * @ctxt: an XSLT transformation context
4629 * @contextNode: the current node in the source tree.
4630 * @inst: the element node of the XSLT 'apply-imports' instruction
4631 * @comp: the compiled instruction
4633 * Process the XSLT apply-imports element.
4636 xsltApplyImports(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
4638 xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
)
4640 xsltTemplatePtr templ
;
4642 if ((ctxt
== NULL
) || (inst
== NULL
))
4646 xsltTransformError(ctxt
, NULL
, inst
,
4647 "Internal error in xsltApplyImports(): "
4648 "The XSLT 'apply-imports' instruction was not compiled.\n");
4652 * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4653 * same; the former is the "Current Template Rule" as defined by the
4654 * XSLT spec, the latter is simply the template struct being
4655 * currently processed.
4657 if (ctxt
->currentTemplateRule
== NULL
) {
4660 * "[ERR XTDE0560] It is a non-recoverable dynamic error if
4661 * xsl:apply-imports or xsl:next-match is evaluated when the
4662 * current template rule is null."
4664 xsltTransformError(ctxt
, NULL
, inst
,
4665 "It is an error to call 'apply-imports' "
4666 "when there's no current template rule.\n");
4670 * TODO: Check if this is correct.
4672 templ
= xsltGetTemplate(ctxt
, contextNode
,
4673 ctxt
->currentTemplateRule
->style
);
4675 if (templ
!= NULL
) {
4676 xsltTemplatePtr oldCurTemplRule
= ctxt
->currentTemplateRule
;
4678 * Set the current template rule.
4680 ctxt
->currentTemplateRule
= templ
;
4682 * URGENT TODO: Need xsl:with-param be handled somehow here?
4684 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
,
4687 ctxt
->currentTemplateRule
= oldCurTemplRule
;
4690 /* Use built-in templates. */
4691 xsltDefaultProcessOneNode(ctxt
, contextNode
, NULL
);
4697 * @ctxt: a XSLT transformation context
4698 * @node: the "current node" in the source tree
4699 * @inst: the XSLT 'call-template' instruction
4700 * @castedComp: the compiled information of the instruction
4702 * Processes the XSLT call-template instruction on the source node.
4705 xsltCallTemplate(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4706 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
4708 #ifdef XSLT_REFACTORED
4709 xsltStyleItemCallTemplatePtr comp
=
4710 (xsltStyleItemCallTemplatePtr
) castedComp
;
4712 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4714 xsltStackElemPtr withParams
= NULL
;
4716 if (ctxt
->insert
== NULL
)
4719 xsltTransformError(ctxt
, NULL
, inst
,
4720 "The XSLT 'call-template' instruction was not compiled.\n");
4725 * The template must have been precomputed
4727 if (comp
->templ
== NULL
) {
4728 comp
->templ
= xsltFindTemplate(ctxt
, comp
->name
, comp
->ns
);
4729 if (comp
->templ
== NULL
) {
4730 if (comp
->ns
!= NULL
) {
4731 xsltTransformError(ctxt
, NULL
, inst
,
4732 "The called template '{%s}%s' was not found.\n",
4733 comp
->ns
, comp
->name
);
4735 xsltTransformError(ctxt
, NULL
, inst
,
4736 "The called template '%s' was not found.\n",
4743 #ifdef WITH_XSLT_DEBUG_PROCESS
4744 if ((comp
!= NULL
) && (comp
->name
!= NULL
))
4745 XSLT_TRACE(ctxt
,XSLT_TRACE_CALL_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
4746 "call-template: name %s\n", comp
->name
));
4749 if (inst
->children
) {
4751 xsltStackElemPtr param
;
4753 cur
= inst
->children
;
4754 while (cur
!= NULL
) {
4755 #ifdef WITH_DEBUGGER
4756 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
4757 xslHandleDebugger(cur
, node
, comp
->templ
, ctxt
);
4759 if (ctxt
->state
== XSLT_STATE_STOPPED
) break;
4761 * TODO: The "with-param"s could be part of the "call-template"
4762 * structure. Avoid to "search" for params dynamically
4763 * in the XML tree every time.
4765 if (IS_XSLT_ELEM(cur
)) {
4766 if (IS_XSLT_NAME(cur
, "with-param")) {
4767 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
4768 if (param
!= NULL
) {
4769 param
->next
= withParams
;
4773 xsltGenericError(xsltGenericErrorContext
,
4774 "xsl:call-template: misplaced xsl:%s\n", cur
->name
);
4777 xsltGenericError(xsltGenericErrorContext
,
4778 "xsl:call-template: misplaced %s element\n", cur
->name
);
4784 * Create a new frame using the params first
4786 xsltApplyXSLTTemplate(ctxt
, node
, comp
->templ
->content
, comp
->templ
,
4788 if (withParams
!= NULL
)
4789 xsltFreeStackElemList(withParams
);
4791 #ifdef WITH_XSLT_DEBUG_PROCESS
4792 if ((comp
!= NULL
) && (comp
->name
!= NULL
))
4793 XSLT_TRACE(ctxt
,XSLT_TRACE_CALL_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
4794 "call-template returned: name %s\n", comp
->name
));
4799 * xsltApplyTemplates:
4800 * @ctxt: a XSLT transformation context
4801 * @node: the 'current node' in the source tree
4802 * @inst: the element node of an XSLT 'apply-templates' instruction
4803 * @castedComp: the compiled instruction
4805 * Processes the XSLT 'apply-templates' instruction on the current node.
4808 xsltApplyTemplates(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4809 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
4811 #ifdef XSLT_REFACTORED
4812 xsltStyleItemApplyTemplatesPtr comp
=
4813 (xsltStyleItemApplyTemplatesPtr
) castedComp
;
4815 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4818 xmlNodePtr cur
, oldContextNode
;
4819 xmlNodeSetPtr list
= NULL
, oldList
;
4820 xsltStackElemPtr withParams
= NULL
;
4821 int oldXPProximityPosition
, oldXPContextSize
;
4822 const xmlChar
*oldMode
, *oldModeURI
;
4824 xsltDocumentPtr oldDocInfo
;
4825 xmlXPathContextPtr xpctxt
;
4828 xsltTransformError(ctxt
, NULL
, inst
,
4829 "xsl:apply-templates : compilation failed\n");
4832 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
4835 #ifdef WITH_XSLT_DEBUG_PROCESS
4836 if ((node
!= NULL
) && (node
->name
!= NULL
))
4837 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4838 "xsltApplyTemplates: node: '%s'\n", node
->name
));
4841 xpctxt
= ctxt
->xpathCtxt
;
4843 * Save context states.
4845 oldContextNode
= ctxt
->node
;
4846 oldMode
= ctxt
->mode
;
4847 oldModeURI
= ctxt
->modeURI
;
4848 oldDocInfo
= ctxt
->document
;
4849 oldList
= ctxt
->nodeList
;
4852 * The xpath context size and proximity position, as
4853 * well as the xpath and context documents, may be changed
4854 * so we save their initial state and will restore on exit
4856 oldXPContextSize
= xpctxt
->contextSize
;
4857 oldXPProximityPosition
= xpctxt
->proximityPosition
;
4858 oldXPDoc
= xpctxt
->doc
;
4863 ctxt
->mode
= comp
->mode
;
4864 ctxt
->modeURI
= comp
->modeURI
;
4866 if (comp
->select
!= NULL
) {
4867 xmlXPathObjectPtr res
= NULL
;
4869 if (comp
->comp
== NULL
) {
4870 xsltTransformError(ctxt
, NULL
, inst
,
4871 "xsl:apply-templates : compilation failed\n");
4874 #ifdef WITH_XSLT_DEBUG_PROCESS
4875 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4876 "xsltApplyTemplates: select %s\n", comp
->select
));
4879 res
= xsltPreCompEval(ctxt
, node
, comp
);
4882 if (res
->type
== XPATH_NODESET
) {
4883 list
= res
->nodesetval
; /* consume the node set */
4884 res
->nodesetval
= NULL
;
4886 xsltTransformError(ctxt
, NULL
, inst
,
4887 "The 'select' expression did not evaluate to a "
4889 ctxt
->state
= XSLT_STATE_STOPPED
;
4890 xmlXPathFreeObject(res
);
4893 xmlXPathFreeObject(res
);
4895 * Note: An xsl:apply-templates with a 'select' attribute,
4896 * can change the current source doc.
4899 xsltTransformError(ctxt
, NULL
, inst
,
4900 "Failed to evaluate the 'select' expression.\n");
4901 ctxt
->state
= XSLT_STATE_STOPPED
;
4905 #ifdef WITH_XSLT_DEBUG_PROCESS
4906 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4907 "xsltApplyTemplates: select didn't evaluate to a node list\n"));
4913 * NOTE: Previously a document info (xsltDocument) was
4914 * created and attached to the Result Tree Fragment.
4915 * But such a document info is created on demand in
4916 * xsltKeyFunction() (functions.c), so we need to create
4917 * it here beforehand.
4918 * In order to take care of potential keys we need to
4919 * do some extra work for the case when a Result Tree Fragment
4920 * is converted into a nodeset (e.g. exslt:node-set()) :
4921 * We attach a "pseudo-doc" (xsltDocument) to _private.
4922 * This xsltDocument, together with the keyset, will be freed
4923 * when the Result Tree Fragment is freed.
4927 if ((ctxt
->nbKeys
> 0) &&
4928 (list
->nodeNr
!= 0) &&
4929 (list
->nodeTab
[0]->doc
!= NULL
) &&
4930 XSLT_IS_RES_TREE_FRAG(list
->nodeTab
[0]->doc
))
4933 * NOTE that it's also OK if @effectiveDocInfo will be
4937 effectiveDocInfo
= list
->nodeTab
[0]->doc
->_private
;
4942 * Build an XPath node set with the children
4944 list
= xmlXPathNodeSetCreate(NULL
);
4947 if (node
->type
!= XML_NAMESPACE_DECL
)
4948 cur
= node
->children
;
4951 while (cur
!= NULL
) {
4952 if (IS_XSLT_REAL_NODE(cur
))
4953 xmlXPathNodeSetAddUnique(list
, cur
);
4958 #ifdef WITH_XSLT_DEBUG_PROCESS
4960 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4961 "xsltApplyTemplates: list of %d nodes\n", list
->nodeNr
));
4964 if ((list
== NULL
) || (list
->nodeNr
== 0))
4968 * Set the context's node set and size; this is also needed for
4969 * for xsltDoSortFunction().
4971 ctxt
->nodeList
= list
;
4973 * Process xsl:with-param and xsl:sort instructions.
4974 * (The code became so verbose just to avoid the
4975 * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
4976 * BUG TODO: We are not using namespaced potentially defined on the
4977 * xsl:sort or xsl:with-param elements; XPath expression might fail.
4979 if (inst
->children
) {
4980 xsltStackElemPtr param
;
4982 cur
= inst
->children
;
4985 #ifdef WITH_DEBUGGER
4986 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
4987 xslHandleDebugger(cur
, node
, NULL
, ctxt
);
4989 if (ctxt
->state
== XSLT_STATE_STOPPED
)
4991 if (cur
->type
== XML_TEXT_NODE
) {
4995 if (! IS_XSLT_ELEM(cur
))
4997 if (IS_XSLT_NAME(cur
, "with-param")) {
4998 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
4999 if (param
!= NULL
) {
5000 param
->next
= withParams
;
5004 if (IS_XSLT_NAME(cur
, "sort")) {
5005 xsltTemplatePtr oldCurTempRule
=
5006 ctxt
->currentTemplateRule
;
5008 xmlNodePtr sorts
[XSLT_MAX_SORT
];
5010 sorts
[nbsorts
++] = cur
;
5015 #ifdef WITH_DEBUGGER
5016 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
5017 xslHandleDebugger(cur
, node
, NULL
, ctxt
);
5019 if (ctxt
->state
== XSLT_STATE_STOPPED
)
5022 if (cur
->type
== XML_TEXT_NODE
) {
5027 if (! IS_XSLT_ELEM(cur
))
5029 if (IS_XSLT_NAME(cur
, "with-param")) {
5030 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
5031 if (param
!= NULL
) {
5032 param
->next
= withParams
;
5036 if (IS_XSLT_NAME(cur
, "sort")) {
5037 if (nbsorts
>= XSLT_MAX_SORT
) {
5038 xsltTransformError(ctxt
, NULL
, cur
,
5039 "The number (%d) of xsl:sort instructions exceeds the "
5040 "maximum allowed by this processor's settings.\n",
5042 ctxt
->state
= XSLT_STATE_STOPPED
;
5045 sorts
[nbsorts
++] = cur
;
5051 * The "current template rule" is cleared for xsl:sort.
5053 ctxt
->currentTemplateRule
= NULL
;
5057 xsltDoSortFunction(ctxt
, sorts
, nbsorts
);
5058 ctxt
->currentTemplateRule
= oldCurTempRule
;
5064 xpctxt
->contextSize
= list
->nodeNr
;
5066 * Apply templates for all selected source nodes.
5068 for (i
= 0; i
< list
->nodeNr
; i
++) {
5069 cur
= list
->nodeTab
[i
];
5071 * The node becomes the "current node".
5075 * An xsl:apply-templates can change the current context doc.
5076 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5078 if ((cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->doc
!= NULL
))
5079 xpctxt
->doc
= cur
->doc
;
5081 xpctxt
->proximityPosition
= i
+ 1;
5083 * Find and apply a template for this node.
5085 xsltProcessOneNode(ctxt
, cur
, withParams
);
5091 * Free the parameter list.
5093 if (withParams
!= NULL
)
5094 xsltFreeStackElemList(withParams
);
5096 xmlXPathFreeNodeSet(list
);
5098 * Restore context states.
5100 xpctxt
->doc
= oldXPDoc
;
5101 xpctxt
->contextSize
= oldXPContextSize
;
5102 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5104 ctxt
->document
= oldDocInfo
;
5105 ctxt
->nodeList
= oldList
;
5106 ctxt
->node
= oldContextNode
;
5107 ctxt
->mode
= oldMode
;
5108 ctxt
->modeURI
= oldModeURI
;
5114 * @ctxt: a XSLT process context
5115 * @contextNode: the current node in the source tree
5116 * @inst: the xsl:choose instruction
5117 * @comp: compiled information of the instruction
5119 * Processes the xsl:choose instruction on the source node.
5122 xsltChoose(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5123 xmlNodePtr inst
, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
)
5127 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
))
5131 * TODO: Content model checks should be done only at compilation
5134 cur
= inst
->children
;
5136 xsltTransformError(ctxt
, NULL
, inst
,
5137 "xsl:choose: The instruction has no content.\n");
5141 #ifdef XSLT_REFACTORED
5143 * We don't check the content model during transformation.
5146 if ((! IS_XSLT_ELEM(cur
)) || (! IS_XSLT_NAME(cur
, "when"))) {
5147 xsltTransformError(ctxt
, NULL
, inst
,
5148 "xsl:choose: xsl:when expected first\n");
5154 int testRes
= 0, res
= 0;
5156 #ifdef XSLT_REFACTORED
5157 xsltStyleItemWhenPtr wcomp
= NULL
;
5159 xsltStylePreCompPtr wcomp
= NULL
;
5163 * Process xsl:when ---------------------------------------------------
5165 while (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "when")) {
5168 if ((wcomp
== NULL
) || (wcomp
->test
== NULL
) ||
5169 (wcomp
->comp
== NULL
))
5171 xsltTransformError(ctxt
, NULL
, cur
,
5172 "Internal error in xsltChoose(): "
5173 "The XSLT 'when' instruction was not compiled.\n");
5178 #ifdef WITH_DEBUGGER
5179 if (xslDebugStatus
!= XSLT_DEBUG_NONE
) {
5181 * TODO: Isn't comp->templ always NULL for xsl:choose?
5183 xslHandleDebugger(cur
, contextNode
, NULL
, ctxt
);
5186 #ifdef WITH_XSLT_DEBUG_PROCESS
5187 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5188 "xsltChoose: test %s\n", wcomp
->test
));
5192 res
= xsltPreCompEvalToBoolean(ctxt
, contextNode
, wcomp
);
5195 ctxt
->state
= XSLT_STATE_STOPPED
;
5198 testRes
= (res
== 1) ? 1 : 0;
5200 #else /* XSLT_FAST_IF */
5202 res
= xsltPreCompEval(ctxt
, cotextNode
, wcomp
);
5205 if (res
->type
!= XPATH_BOOLEAN
)
5206 res
= xmlXPathConvertBoolean(res
);
5207 if (res
->type
== XPATH_BOOLEAN
)
5208 testRes
= res
->boolval
;
5210 #ifdef WITH_XSLT_DEBUG_PROCESS
5211 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5212 "xsltChoose: test didn't evaluate to a boolean\n"));
5216 xmlXPathFreeObject(res
);
5219 ctxt
->state
= XSLT_STATE_STOPPED
;
5223 #endif /* else of XSLT_FAST_IF */
5225 #ifdef WITH_XSLT_DEBUG_PROCESS
5226 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5227 "xsltChoose: test evaluate to %d\n", testRes
));
5236 * Process xsl:otherwise ----------------------------------------------
5238 if (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "otherwise")) {
5240 #ifdef WITH_DEBUGGER
5241 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5242 xslHandleDebugger(cur
, contextNode
, NULL
, ctxt
);
5245 #ifdef WITH_XSLT_DEBUG_PROCESS
5246 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5247 "evaluating xsl:otherwise\n"));
5255 goto process_sequence
;
5261 * Instantiate the sequence constructor.
5263 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, cur
->children
,
5273 * @ctxt: a XSLT process context
5274 * @contextNode: the current node in the source tree
5275 * @inst: the xsl:if instruction
5276 * @castedComp: compiled information of the instruction
5278 * Processes the xsl:if instruction on the source node.
5281 xsltIf(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5282 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
5286 #ifdef XSLT_REFACTORED
5287 xsltStyleItemIfPtr comp
= (xsltStyleItemIfPtr
) castedComp
;
5289 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
5292 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
))
5294 if ((comp
== NULL
) || (comp
->test
== NULL
) || (comp
->comp
== NULL
)) {
5295 xsltTransformError(ctxt
, NULL
, inst
,
5296 "Internal error in xsltIf(): "
5297 "The XSLT 'if' instruction was not compiled.\n");
5301 #ifdef WITH_XSLT_DEBUG_PROCESS
5302 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5303 "xsltIf: test %s\n", comp
->test
));
5308 xmlDocPtr oldLocalFragmentTop
= ctxt
->localRVT
;
5310 res
= xsltPreCompEvalToBoolean(ctxt
, contextNode
, comp
);
5313 * Cleanup fragments created during evaluation of the
5314 * "select" expression.
5316 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
5317 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
5320 #ifdef WITH_XSLT_DEBUG_PROCESS
5321 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5322 "xsltIf: test evaluate to %d\n", res
));
5326 ctxt
->state
= XSLT_STATE_STOPPED
;
5331 * Instantiate the sequence constructor of xsl:if.
5333 xsltApplySequenceConstructor(ctxt
,
5334 contextNode
, inst
->children
, NULL
);
5337 #else /* XSLT_FAST_IF */
5342 xmlXPathObjectPtr xpobj
= xsltPreCompEval(ctxt
, contextNode
, comp
);
5343 if (xpobj
!= NULL
) {
5344 if (xpobj
->type
!= XPATH_BOOLEAN
)
5345 xpobj
= xmlXPathConvertBoolean(xpobj
);
5346 if (xpobj
->type
== XPATH_BOOLEAN
) {
5347 res
= xpobj
->boolval
;
5349 #ifdef WITH_XSLT_DEBUG_PROCESS
5350 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5351 "xsltIf: test evaluate to %d\n", res
));
5354 xsltApplySequenceConstructor(ctxt
,
5355 contextNode
, inst
->children
, NULL
);
5359 #ifdef WITH_XSLT_DEBUG_PROCESS
5360 XSLT_TRACE(ctxt
, XSLT_TRACE_IF
,
5361 xsltGenericDebug(xsltGenericDebugContext
,
5362 "xsltIf: test didn't evaluate to a boolean\n"));
5364 ctxt
->state
= XSLT_STATE_STOPPED
;
5366 xmlXPathFreeObject(xpobj
);
5368 ctxt
->state
= XSLT_STATE_STOPPED
;
5371 #endif /* else of XSLT_FAST_IF */
5379 * @ctxt: an XSLT transformation context
5380 * @contextNode: the "current node" in the source tree
5381 * @inst: the element node of the xsl:for-each instruction
5382 * @castedComp: the compiled information of the instruction
5384 * Process the xslt for-each node on the source node
5387 xsltForEach(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5388 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
5390 #ifdef XSLT_REFACTORED
5391 xsltStyleItemForEachPtr comp
= (xsltStyleItemForEachPtr
) castedComp
;
5393 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
5396 xmlXPathObjectPtr res
= NULL
;
5397 xmlNodePtr cur
, curInst
;
5398 xmlNodeSetPtr list
= NULL
;
5399 xmlNodeSetPtr oldList
;
5400 int oldXPProximityPosition
, oldXPContextSize
;
5401 xmlNodePtr oldContextNode
;
5402 xsltTemplatePtr oldCurTemplRule
;
5404 xsltDocumentPtr oldDocInfo
;
5405 xmlXPathContextPtr xpctxt
;
5407 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
)) {
5408 xsltGenericError(xsltGenericErrorContext
,
5409 "xsltForEach(): Bad arguments.\n");
5414 xsltTransformError(ctxt
, NULL
, inst
,
5415 "Internal error in xsltForEach(): "
5416 "The XSLT 'for-each' instruction was not compiled.\n");
5419 if ((comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
5420 xsltTransformError(ctxt
, NULL
, inst
,
5421 "Internal error in xsltForEach(): "
5422 "The selecting expression of the XSLT 'for-each' "
5423 "instruction was not compiled correctly.\n");
5426 xpctxt
= ctxt
->xpathCtxt
;
5428 #ifdef WITH_XSLT_DEBUG_PROCESS
5429 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5430 "xsltForEach: select %s\n", comp
->select
));
5434 * Save context states.
5436 oldDocInfo
= ctxt
->document
;
5437 oldList
= ctxt
->nodeList
;
5438 oldContextNode
= ctxt
->node
;
5440 * The "current template rule" is cleared for the instantiation of
5443 oldCurTemplRule
= ctxt
->currentTemplateRule
;
5444 ctxt
->currentTemplateRule
= NULL
;
5446 oldXPDoc
= xpctxt
->doc
;
5447 oldXPProximityPosition
= xpctxt
->proximityPosition
;
5448 oldXPContextSize
= xpctxt
->contextSize
;
5451 * Evaluate the 'select' expression.
5453 res
= xsltPreCompEval(ctxt
, contextNode
, comp
);
5456 if (res
->type
== XPATH_NODESET
)
5457 list
= res
->nodesetval
;
5459 xsltTransformError(ctxt
, NULL
, inst
,
5460 "The 'select' expression does not evaluate to a node set.\n");
5462 #ifdef WITH_XSLT_DEBUG_PROCESS
5463 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5464 "xsltForEach: select didn't evaluate to a node list\n"));
5469 xsltTransformError(ctxt
, NULL
, inst
,
5470 "Failed to evaluate the 'select' expression.\n");
5471 ctxt
->state
= XSLT_STATE_STOPPED
;
5475 if ((list
== NULL
) || (list
->nodeNr
<= 0))
5478 #ifdef WITH_XSLT_DEBUG_PROCESS
5479 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5480 "xsltForEach: select evaluates to %d nodes\n", list
->nodeNr
));
5484 * Set the list; this has to be done already here for xsltDoSortFunction().
5486 ctxt
->nodeList
= list
;
5488 * Handle xsl:sort instructions and skip them for further processing.
5489 * BUG TODO: We are not using namespaced potentially defined on the
5490 * xsl:sort element; XPath expression might fail.
5492 curInst
= inst
->children
;
5493 if (IS_XSLT_ELEM(curInst
) && IS_XSLT_NAME(curInst
, "sort")) {
5495 xmlNodePtr sorts
[XSLT_MAX_SORT
];
5497 sorts
[nbsorts
++] = curInst
;
5499 #ifdef WITH_DEBUGGER
5500 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5501 xslHandleDebugger(curInst
, contextNode
, NULL
, ctxt
);
5504 curInst
= curInst
->next
;
5505 while (IS_XSLT_ELEM(curInst
) && IS_XSLT_NAME(curInst
, "sort")) {
5506 if (nbsorts
>= XSLT_MAX_SORT
) {
5507 xsltTransformError(ctxt
, NULL
, curInst
,
5508 "The number of xsl:sort instructions exceeds the "
5509 "maximum (%d) allowed by this processor.\n",
5513 sorts
[nbsorts
++] = curInst
;
5516 #ifdef WITH_DEBUGGER
5517 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5518 xslHandleDebugger(curInst
, contextNode
, NULL
, ctxt
);
5520 curInst
= curInst
->next
;
5522 xsltDoSortFunction(ctxt
, sorts
, nbsorts
);
5524 xpctxt
->contextSize
= list
->nodeNr
;
5526 * Instantiate the sequence constructor for each selected node.
5528 for (i
= 0; i
< list
->nodeNr
; i
++) {
5529 cur
= list
->nodeTab
[i
];
5531 * The selected node becomes the "current node".
5535 * An xsl:for-each can change the current context doc.
5536 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5538 if ((cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->doc
!= NULL
))
5539 xpctxt
->doc
= cur
->doc
;
5541 xpctxt
->proximityPosition
= i
+ 1;
5543 xsltApplySequenceConstructor(ctxt
, cur
, curInst
, NULL
);
5549 xmlXPathFreeObject(res
);
5551 * Restore old states.
5553 ctxt
->document
= oldDocInfo
;
5554 ctxt
->nodeList
= oldList
;
5555 ctxt
->node
= oldContextNode
;
5556 ctxt
->currentTemplateRule
= oldCurTemplRule
;
5558 xpctxt
->doc
= oldXPDoc
;
5559 xpctxt
->contextSize
= oldXPContextSize
;
5560 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5563 /************************************************************************
5565 * Generic interface *
5567 ************************************************************************/
5569 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5570 typedef struct xsltHTMLVersion
{
5571 const char *version
;
5576 static xsltHTMLVersion xsltHTMLVersions
[] = {
5577 { "5", NULL
, "about:legacy-compat" },
5578 { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5579 "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
5580 { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
5581 "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
5582 { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5583 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5584 { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
5585 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5586 { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
5587 "http://www.w3.org/TR/html4/strict.dtd"},
5588 { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5589 "http://www.w3.org/TR/html4/loose.dtd"},
5590 { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5591 "http://www.w3.org/TR/html4/frameset.dtd"},
5592 { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
5593 "http://www.w3.org/TR/html4/loose.dtd"},
5594 { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL
}
5599 * @version: the version string
5600 * @publicID: used to return the public ID
5601 * @systemID: used to return the system ID
5603 * Returns -1 if not found, 0 otherwise and the system and public
5604 * Identifier for this given verion of HTML
5607 xsltGetHTMLIDs(const xmlChar
*version
, const xmlChar
**publicID
,
5608 const xmlChar
**systemID
) {
5610 if (version
== NULL
)
5612 for (i
= 0;i
< (sizeof(xsltHTMLVersions
)/sizeof(xsltHTMLVersions
[1]));
5614 if (!xmlStrcasecmp(version
,
5615 (const xmlChar
*) xsltHTMLVersions
[i
].version
)) {
5616 if (publicID
!= NULL
)
5617 *publicID
= (const xmlChar
*) xsltHTMLVersions
[i
].public;
5618 if (systemID
!= NULL
)
5619 *systemID
= (const xmlChar
*) xsltHTMLVersions
[i
].system
;
5628 * xsltApplyStripSpaces:
5629 * @ctxt: a XSLT process context
5630 * @node: the root of the XML tree
5632 * Strip the unwanted ignorable spaces from the input tree
5635 xsltApplyStripSpaces(xsltTransformContextPtr ctxt
, xmlNodePtr node
) {
5637 #ifdef WITH_XSLT_DEBUG_PROCESS
5643 while (current
!= NULL
) {
5645 * Cleanup children empty nodes if asked for
5647 if ((IS_XSLT_REAL_NODE(current
)) &&
5648 (current
->children
!= NULL
) &&
5649 (xsltFindElemSpaceHandling(ctxt
, current
))) {
5650 xmlNodePtr
delete = NULL
, cur
= current
->children
;
5652 while (cur
!= NULL
) {
5653 if (IS_BLANK_NODE(cur
))
5657 if (delete != NULL
) {
5658 xmlUnlinkNode(delete);
5659 xmlFreeNode(delete);
5661 #ifdef WITH_XSLT_DEBUG_PROCESS
5669 * Skip to next node in document order.
5671 if (node
->type
== XML_ENTITY_REF_NODE
) {
5672 /* process deep in entities */
5673 xsltApplyStripSpaces(ctxt
, node
->children
);
5675 if ((current
->children
!= NULL
) &&
5676 (current
->type
!= XML_ENTITY_REF_NODE
)) {
5677 current
= current
->children
;
5678 } else if (current
->next
!= NULL
) {
5679 current
= current
->next
;
5682 current
= current
->parent
;
5683 if (current
== NULL
)
5685 if (current
== node
)
5687 if (current
->next
!= NULL
) {
5688 current
= current
->next
;
5691 } while (current
!= NULL
);
5696 #ifdef WITH_XSLT_DEBUG_PROCESS
5697 XSLT_TRACE(ctxt
,XSLT_TRACE_STRIP_SPACES
,xsltGenericDebug(xsltGenericDebugContext
,
5698 "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb
));
5704 xsltCountKeys(xsltTransformContextPtr ctxt
)
5706 xsltStylesheetPtr style
;
5713 * Do we have those nastly templates with a key() in the match pattern?
5715 ctxt
->hasTemplKeyPatterns
= 0;
5716 style
= ctxt
->style
;
5717 while (style
!= NULL
) {
5718 if (style
->keyMatch
!= NULL
) {
5719 ctxt
->hasTemplKeyPatterns
= 1;
5722 style
= xsltNextImport(style
);
5725 * Count number of key declarations.
5728 style
= ctxt
->style
;
5729 while (style
!= NULL
) {
5735 style
= xsltNextImport(style
);
5737 return(ctxt
->nbKeys
);
5741 * xsltCleanupSourceDoc:
5744 * Resets source node flags and ids stored in 'psvi' member.
5747 xsltCleanupSourceDoc(xmlDocPtr doc
) {
5748 xmlNodePtr cur
= (xmlNodePtr
) doc
;
5752 xsltClearSourceNodeFlags(cur
, XSLT_SOURCE_NODE_MASK
);
5753 psviPtr
= xsltGetPSVIPtr(cur
);
5757 if (cur
->type
== XML_ELEMENT_NODE
) {
5758 xmlAttrPtr prop
= cur
->properties
;
5761 prop
->atype
&= ~(XSLT_SOURCE_NODE_MASK
<< 27);
5767 if (cur
->children
!= NULL
&& cur
->type
!= XML_ENTITY_REF_NODE
) {
5768 cur
= cur
->children
;
5770 if (cur
== (xmlNodePtr
) doc
)
5772 while (cur
->next
== NULL
) {
5774 if (cur
== (xmlNodePtr
) doc
)
5784 * xsltApplyStylesheetInternal:
5785 * @style: a parsed XSLT stylesheet
5786 * @doc: a parsed XML document
5787 * @params: a NULL terminated array of parameters names/values tuples
5788 * @output: the targetted output
5789 * @profile: profile FILE * output or NULL
5790 * @user: user provided parameter
5792 * Apply the stylesheet to the document
5793 * NOTE: This may lead to a non-wellformed output XML wise !
5795 * Returns the result document or NULL in case of error
5798 xsltApplyStylesheetInternal(xsltStylesheetPtr style
, xmlDocPtr doc
,
5799 const char **params
, const char *output
,
5800 FILE * profile
, xsltTransformContextPtr userCtxt
)
5802 xmlDocPtr res
= NULL
;
5803 xsltTransformContextPtr ctxt
= NULL
;
5804 xmlNodePtr root
, node
;
5805 const xmlChar
*method
;
5806 const xmlChar
*doctypePublic
;
5807 const xmlChar
*doctypeSystem
;
5808 const xmlChar
*version
;
5809 const xmlChar
*encoding
;
5810 xsltStackElemPtr variables
;
5811 xsltStackElemPtr vptr
;
5815 if ((style
== NULL
) || (doc
== NULL
))
5818 if (style
->internalized
== 0) {
5819 #ifdef WITH_XSLT_DEBUG
5820 xsltGenericDebug(xsltGenericDebugContext
,
5821 "Stylesheet was not fully internalized !\n");
5824 if (doc
->intSubset
!= NULL
) {
5826 * Avoid hitting the DTD when scanning nodes
5827 * but keep it linked as doc->intSubset
5829 xmlNodePtr cur
= (xmlNodePtr
) doc
->intSubset
;
5830 if (cur
->next
!= NULL
)
5831 cur
->next
->prev
= cur
->prev
;
5832 if (cur
->prev
!= NULL
)
5833 cur
->prev
->next
= cur
->next
;
5834 if (doc
->children
== cur
)
5835 doc
->children
= cur
->next
;
5836 if (doc
->last
== cur
)
5837 doc
->last
= cur
->prev
;
5838 cur
->prev
= cur
->next
= NULL
;
5842 * Check for XPath document order availability
5844 root
= xmlDocGetRootElement(doc
);
5846 if (((ptrdiff_t) root
->content
>= 0) &&
5847 (xslDebugStatus
== XSLT_DEBUG_NONE
))
5848 xmlXPathOrderDocElems(doc
);
5851 if (userCtxt
!= NULL
)
5854 ctxt
= xsltNewTransformContext(style
, doc
);
5859 ctxt
->initialContextDoc
= doc
;
5860 ctxt
->initialContextNode
= (xmlNodePtr
) doc
;
5862 if (profile
!= NULL
) {
5863 #ifdef WITH_PROFILER
5866 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
5867 "xsltApplyStylesheetInternal: "
5868 "libxslt compiled without profiler\n");
5874 ctxt
->outputFile
= output
;
5876 ctxt
->outputFile
= NULL
;
5879 * internalize the modes if needed
5881 if (ctxt
->dict
!= NULL
) {
5882 if (ctxt
->mode
!= NULL
)
5883 ctxt
->mode
= xmlDictLookup(ctxt
->dict
, ctxt
->mode
, -1);
5884 if (ctxt
->modeURI
!= NULL
)
5885 ctxt
->modeURI
= xmlDictLookup(ctxt
->dict
, ctxt
->modeURI
, -1);
5888 XSLT_GET_IMPORT_PTR(method
, style
, method
)
5889 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
5890 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
5891 XSLT_GET_IMPORT_PTR(version
, style
, version
)
5892 XSLT_GET_IMPORT_PTR(encoding
, style
, encoding
)
5894 if ((method
!= NULL
) &&
5895 (!xmlStrEqual(method
, (const xmlChar
*) "xml")))
5897 if (xmlStrEqual(method
, (const xmlChar
*) "html")) {
5898 ctxt
->type
= XSLT_OUTPUT_HTML
;
5899 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
5900 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5902 if (version
== NULL
) {
5905 res
= htmlNewDoc(NULL
, NULL
);
5907 * Make sure no DTD node is generated in this case
5910 dtd
= xmlGetIntSubset(res
);
5912 xmlUnlinkNode((xmlNodePtr
) dtd
);
5915 res
->intSubset
= NULL
;
5916 res
->extSubset
= NULL
;
5920 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5921 xsltGetHTMLIDs(version
, &doctypePublic
, &doctypeSystem
);
5923 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5928 res
->dict
= ctxt
->dict
;
5929 xmlDictReference(res
->dict
);
5931 #ifdef WITH_XSLT_DEBUG
5932 xsltGenericDebug(xsltGenericDebugContext
,
5933 "reusing transformation dict for output\n");
5935 } else if (xmlStrEqual(method
, (const xmlChar
*) "xhtml")) {
5936 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
5937 "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n");
5938 ctxt
->type
= XSLT_OUTPUT_HTML
;
5939 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5942 res
->dict
= ctxt
->dict
;
5943 xmlDictReference(res
->dict
);
5945 #ifdef WITH_XSLT_DEBUG
5946 xsltGenericDebug(xsltGenericDebugContext
,
5947 "reusing transformation dict for output\n");
5949 } else if (xmlStrEqual(method
, (const xmlChar
*) "text")) {
5950 ctxt
->type
= XSLT_OUTPUT_TEXT
;
5951 res
= xmlNewDoc(style
->version
);
5954 res
->dict
= ctxt
->dict
;
5955 xmlDictReference(res
->dict
);
5957 #ifdef WITH_XSLT_DEBUG
5958 xsltGenericDebug(xsltGenericDebugContext
,
5959 "reusing transformation dict for output\n");
5962 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
5963 "xsltApplyStylesheetInternal: unsupported method (%s)\n",
5968 ctxt
->type
= XSLT_OUTPUT_XML
;
5969 res
= xmlNewDoc(style
->version
);
5972 res
->dict
= ctxt
->dict
;
5973 xmlDictReference(ctxt
->dict
);
5974 #ifdef WITH_XSLT_DEBUG
5975 xsltGenericDebug(xsltGenericDebugContext
,
5976 "reusing transformation dict for output\n");
5979 res
->charset
= XML_CHAR_ENCODING_UTF8
;
5980 if (encoding
!= NULL
)
5981 res
->encoding
= xmlStrdup(encoding
);
5982 variables
= style
->variables
;
5984 ctxt
->node
= (xmlNodePtr
) doc
;
5987 ctxt
->xpathCtxt
->contextSize
= 1;
5988 ctxt
->xpathCtxt
->proximityPosition
= 1;
5989 ctxt
->xpathCtxt
->node
= NULL
; /* TODO: Set the context node here? */
5992 * Start the evaluation, evaluate the params, the stylesheets globals
5993 * and start by processing the top node.
5995 if (xsltNeedElemSpaceHandling(ctxt
))
5996 xsltApplyStripSpaces(ctxt
, xmlDocGetRootElement(doc
));
5998 * Evaluate global params and user-provided params.
6000 if (ctxt
->globalVars
== NULL
)
6001 ctxt
->globalVars
= xmlHashCreate(20);
6002 if (params
!= NULL
) {
6003 xsltEvalUserParams(ctxt
, params
);
6006 /* need to be called before evaluating global variables */
6007 xsltCountKeys(ctxt
);
6009 xsltEvalGlobalVariables(ctxt
);
6011 /* Clean up any unused RVTs. */
6012 xsltReleaseLocalRVTs(ctxt
, NULL
);
6014 ctxt
->insert
= (xmlNodePtr
) res
;
6015 ctxt
->varsBase
= ctxt
->varsNr
- 1;
6018 * Start processing the source tree -----------------------------------
6020 xsltProcessOneNode(ctxt
, ctxt
->node
, NULL
);
6022 * Remove all remaining vars from the stack.
6024 xsltLocalVariablePop(ctxt
, 0, -2);
6025 xsltShutdownCtxtExts(ctxt
);
6027 xsltCleanupTemplates(style
); /* TODO: <- style should be read only */
6030 * Now cleanup our variables so stylesheet can be re-used
6032 * TODO: this is not needed anymore global variables are copied
6033 * and not evaluated directly anymore, keep this as a check
6035 if (style
->variables
!= variables
) {
6036 vptr
= style
->variables
;
6037 while (vptr
->next
!= variables
)
6040 xsltFreeStackElemList(style
->variables
);
6041 style
->variables
= variables
;
6043 vptr
= style
->variables
;
6044 while (vptr
!= NULL
) {
6045 if (vptr
->computed
) {
6046 if (vptr
->value
!= NULL
) {
6047 xmlXPathFreeObject(vptr
->value
);
6056 * code disabled by wmb; awaiting kb's review
6057 * problem is that global variable(s) may contain xpath objects
6058 * from doc associated with RVT, so can't be freed at this point.
6059 * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
6060 * I assume this shouldn't be required at this point.
6063 * Free all remaining tree fragments.
6068 * Do some post processing work depending on the generated output
6070 root
= xmlDocGetRootElement(res
);
6072 const xmlChar
*doctype
= NULL
;
6074 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
))
6075 doctype
= xmlDictQLookup(ctxt
->dict
, root
->ns
->prefix
, root
->name
);
6076 if (doctype
== NULL
)
6077 doctype
= root
->name
;
6080 * Apply the default selection of the method
6082 if ((method
== NULL
) &&
6083 (root
->ns
== NULL
) &&
6084 (!xmlStrcasecmp(root
->name
, (const xmlChar
*) "html"))) {
6087 tmp
= res
->children
;
6088 while ((tmp
!= NULL
) && (tmp
!= root
)) {
6089 if (tmp
->type
== XML_ELEMENT_NODE
)
6091 if ((tmp
->type
== XML_TEXT_NODE
) && (!xmlIsBlankNode(tmp
)))
6096 ctxt
->type
= XSLT_OUTPUT_HTML
;
6098 * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
6099 * transformation on the doc, but functions like
6101 res
->type
= XML_HTML_DOCUMENT_NODE
;
6102 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
6103 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
6106 #ifdef XSLT_GENERATE_HTML_DOCTYPE
6107 } else if (version
!= NULL
) {
6108 xsltGetHTMLIDs(version
, &doctypePublic
,
6110 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
6112 xmlCreateIntSubset(res
, doctype
,
6120 if (ctxt
->type
== XSLT_OUTPUT_XML
) {
6121 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
6122 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
6123 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
6125 /* Need a small "hack" here to assure DTD comes before
6126 possible comment nodes */
6127 node
= res
->children
;
6129 res
->children
= NULL
;
6131 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
6134 if (res
->children
!= NULL
) {
6135 res
->children
->next
= node
;
6136 node
->prev
= res
->children
;
6139 res
->children
= node
;
6145 xmlXPathFreeNodeSet(ctxt
->nodeList
);
6147 #ifdef WITH_PROFILER
6148 if (profile
!= NULL
) {
6149 xsltSaveProfiling(ctxt
, profile
);
6156 if ((ctxt
!= NULL
) && (ctxt
->state
!= XSLT_STATE_OK
)) {
6160 if ((res
!= NULL
) && (ctxt
!= NULL
) && (output
!= NULL
)) {
6163 ret
= xsltCheckWrite(ctxt
->sec
, ctxt
, (const xmlChar
*) output
);
6165 xsltTransformError(ctxt
, NULL
, NULL
,
6166 "xsltApplyStylesheet: forbidden to save to %s\n",
6168 } else if (ret
< 0) {
6169 xsltTransformError(ctxt
, NULL
, NULL
,
6170 "xsltApplyStylesheet: saving to %s may not be possible\n",
6175 #ifdef XSLT_DEBUG_PROFILE_CACHE
6176 printf("# Cache:\n");
6177 printf("# Reused tree fragments: %d\n", ctxt
->cache
->dbgReusedRVTs
);
6178 printf("# Reused variables : %d\n", ctxt
->cache
->dbgReusedVars
);
6181 if (ctxt
->sourceDocDirty
)
6182 xsltCleanupSourceDoc(doc
);
6184 if ((ctxt
!= NULL
) && (userCtxt
== NULL
))
6185 xsltFreeTransformContext(ctxt
);
6193 #ifdef XSLT_DEBUG_PROFILE_CACHE
6194 printf("# Cache:\n");
6195 printf("# Reused tree fragments: %d\n", ctxt
->cache
->dbgReusedRVTs
);
6196 printf("# Reused variables : %d\n", ctxt
->cache
->dbgReusedVars
);
6199 if ((ctxt
!= NULL
) && (userCtxt
== NULL
))
6200 xsltFreeTransformContext(ctxt
);
6205 * xsltApplyStylesheet:
6206 * @style: a parsed XSLT stylesheet
6207 * @doc: a parsed XML document
6208 * @params: a NULL terminated arry of parameters names/values tuples
6210 * Apply the stylesheet to the document
6211 * NOTE: This may lead to a non-wellformed output XML wise !
6213 * Returns the result document or NULL in case of error
6216 xsltApplyStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6217 const char **params
)
6219 return (xsltApplyStylesheetInternal(style
, doc
, params
, NULL
, NULL
, NULL
));
6223 * xsltProfileStylesheet:
6224 * @style: a parsed XSLT stylesheet
6225 * @doc: a parsed XML document
6226 * @params: a NULL terminated arry of parameters names/values tuples
6227 * @output: a FILE * for the profiling output
6229 * Apply the stylesheet to the document and dump the profiling to
6232 * Returns the result document or NULL in case of error
6235 xsltProfileStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6236 const char **params
, FILE * output
)
6240 res
= xsltApplyStylesheetInternal(style
, doc
, params
, NULL
, output
, NULL
);
6245 * xsltApplyStylesheetUser:
6246 * @style: a parsed XSLT stylesheet
6247 * @doc: a parsed XML document
6248 * @params: a NULL terminated array of parameters names/values tuples
6249 * @output: the targetted output
6250 * @profile: profile FILE * output or NULL
6251 * @userCtxt: user provided transform context
6253 * Apply the stylesheet to the document and allow the user to provide
6254 * its own transformation context.
6256 * Returns the result document or NULL in case of error
6259 xsltApplyStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
,
6260 const char **params
, const char *output
,
6261 FILE * profile
, xsltTransformContextPtr userCtxt
)
6265 res
= xsltApplyStylesheetInternal(style
, doc
, params
, output
,
6271 * xsltRunStylesheetUser:
6272 * @style: a parsed XSLT stylesheet
6273 * @doc: a parsed XML document
6274 * @params: a NULL terminated array of parameters names/values tuples
6275 * @output: the URL/filename ot the generated resource if available
6276 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6277 * @IObuf: an output buffer for progressive output (not implemented yet)
6278 * @profile: profile FILE * output or NULL
6279 * @userCtxt: user provided transform context
6281 * Apply the stylesheet to the document and generate the output according
6282 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6284 * NOTE: This may lead to a non-wellformed output XML wise !
6285 * NOTE: This may also result in multiple files being generated
6286 * NOTE: using IObuf, the result encoding used will be the one used for
6287 * creating the output buffer, use the following macro to read it
6288 * from the stylesheet
6289 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6290 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6291 * since the interface uses only UTF8
6293 * Returns the number of by written to the main resource or -1 in case of
6297 xsltRunStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
,
6298 const char **params
, const char *output
,
6299 xmlSAXHandlerPtr SAX
, xmlOutputBufferPtr IObuf
,
6300 FILE * profile
, xsltTransformContextPtr userCtxt
)
6305 if ((output
== NULL
) && (SAX
== NULL
) && (IObuf
== NULL
))
6307 if ((SAX
!= NULL
) && (IObuf
!= NULL
))
6310 /* unsupported yet */
6312 XSLT_TODO
/* xsltRunStylesheet xmlSAXHandlerPtr SAX */
6316 tmp
= xsltApplyStylesheetInternal(style
, doc
, params
, output
, profile
,
6319 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
6320 "xsltRunStylesheet : run failed\n");
6323 if (IObuf
!= NULL
) {
6324 /* TODO: incomplete, IObuf output not progressive */
6325 ret
= xsltSaveResultTo(IObuf
, tmp
, style
);
6327 ret
= xsltSaveResultToFilename(output
, tmp
, style
, 0);
6334 * xsltRunStylesheet:
6335 * @style: a parsed XSLT stylesheet
6336 * @doc: a parsed XML document
6337 * @params: a NULL terminated array of parameters names/values tuples
6338 * @output: the URL/filename ot the generated resource if available
6339 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6340 * @IObuf: an output buffer for progressive output (not implemented yet)
6342 * Apply the stylesheet to the document and generate the output according
6343 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6345 * NOTE: This may lead to a non-wellformed output XML wise !
6346 * NOTE: This may also result in multiple files being generated
6347 * NOTE: using IObuf, the result encoding used will be the one used for
6348 * creating the output buffer, use the following macro to read it
6349 * from the stylesheet
6350 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6351 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6352 * since the interface uses only UTF8
6354 * Returns the number of bytes written to the main resource or -1 in case of
6358 xsltRunStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6359 const char **params
, const char *output
,
6360 xmlSAXHandlerPtr SAX
, xmlOutputBufferPtr IObuf
)
6362 return(xsltRunStylesheetUser(style
, doc
, params
, output
, SAX
, IObuf
,
6367 xsltMessageWrapper(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
6368 xmlNodePtr inst
, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
) {
6369 xsltMessage(ctxt
, node
, inst
);
6373 * xsltRegisterAllElement:
6374 * @ctxt: the XPath context
6376 * Registers all default XSLT elements in this context
6379 xsltRegisterAllElement(xsltTransformContextPtr ctxt
)
6381 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "apply-templates",
6383 xsltApplyTemplates
);
6384 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "apply-imports",
6387 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "call-template",
6390 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "element",
6393 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "attribute",
6396 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "text",
6399 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "processing-instruction",
6401 xsltProcessingInstruction
);
6402 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "comment",
6405 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "copy",
6408 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "value-of",
6411 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "number",
6414 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "for-each",
6417 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "if",
6420 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "choose",
6423 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "sort",
6426 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "copy-of",
6429 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "message",
6431 xsltMessageWrapper
);
6434 * Those don't have callable entry points but are registered anyway
6436 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "variable",
6439 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "param",
6442 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "with-param",
6445 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "decimal-format",
6448 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "when",
6451 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "otherwise",
6454 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "fallback",