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.
21 #include <libxml/debugXML.h>
23 #ifdef WITH_XSLT_DEBUG
24 #define WITH_XSLT_DEBUG_EXTRA
25 #define WITH_XSLT_DEBUG_PROCESS
26 #define WITH_XSLT_DEBUG_VARIABLE
29 #define XSLT_GENERATE_HTML_DOCTYPE
30 #ifdef XSLT_GENERATE_HTML_DOCTYPE
31 static int xsltGetHTMLIDs(const xmlChar
*version
, const xmlChar
**publicID
,
32 const xmlChar
**systemID
);
35 int xsltMaxDepth
= 3000;
36 int xsltMaxVars
= 15000;
43 # define FALSE (0 == 1)
44 # define TRUE (!FALSE)
47 #define IS_BLANK_NODE(n) \
48 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
52 * Forward declarations
56 xsltCopyNamespaceListInternal(xmlNodePtr node
, xmlNsPtr cur
);
59 xsltCopyTree(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
60 xmlNodePtr node
, xmlNodePtr insert
, int isLRE
,
64 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt
,
65 xmlNodePtr contextNode
, xmlNodePtr list
,
66 xsltTemplatePtr templ
);
69 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt
,
70 xmlNodePtr contextNode
,
72 xsltTemplatePtr templ
,
73 xsltStackElemPtr withParams
);
77 * @ctxt: the transformation context
78 * @value: the template to push on the stack
80 * Push a template on the stack
82 * Returns the new index in the stack or 0 in case of error
85 templPush(xsltTransformContextPtr ctxt
, xsltTemplatePtr value
)
87 if (ctxt
->templMax
== 0) {
90 (xsltTemplatePtr
*) xmlMalloc(ctxt
->templMax
*
91 sizeof(ctxt
->templTab
[0]));
92 if (ctxt
->templTab
== NULL
) {
93 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
97 else if (ctxt
->templNr
>= ctxt
->templMax
) {
100 (xsltTemplatePtr
*) xmlRealloc(ctxt
->templTab
,
102 sizeof(ctxt
->templTab
[0]));
103 if (ctxt
->templTab
== NULL
) {
104 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
108 ctxt
->templTab
[ctxt
->templNr
] = value
;
110 return (ctxt
->templNr
++);
114 * @ctxt: the transformation context
116 * Pop a template value from the stack
118 * Returns the stored template value
120 static xsltTemplatePtr
121 templPop(xsltTransformContextPtr ctxt
)
125 if (ctxt
->templNr
<= 0)
128 if (ctxt
->templNr
> 0)
129 ctxt
->templ
= ctxt
->templTab
[ctxt
->templNr
- 1];
131 ctxt
->templ
= (xsltTemplatePtr
) 0;
132 ret
= ctxt
->templTab
[ctxt
->templNr
];
133 ctxt
->templTab
[ctxt
->templNr
] = 0;
138 * xsltLocalVariablePop:
139 * @ctxt: the transformation context
140 * @limitNr: number of variables which should remain
141 * @level: the depth in the xsl:template's tree
143 * Pops all variable values at the given @depth from the stack.
145 * Returns the stored variable value
147 * This is an internal routine and should not be called by users!
150 xsltLocalVariablePop(xsltTransformContextPtr ctxt
, int limitNr
, int level
)
152 xsltStackElemPtr variable
;
154 if (ctxt
->varsNr
<= 0)
158 if (ctxt
->varsNr
<= limitNr
)
160 variable
= ctxt
->varsTab
[ctxt
->varsNr
- 1];
161 if (variable
->level
<= level
)
163 if (variable
->level
>= 0)
164 xsltFreeStackElemList(variable
);
166 } while (ctxt
->varsNr
!= 0);
167 if (ctxt
->varsNr
> 0)
168 ctxt
->vars
= ctxt
->varsTab
[ctxt
->varsNr
- 1];
174 * xsltTemplateParamsCleanup:
176 * Removes xsl:param and xsl:with-param items from the
177 * variable-stack. Only xsl:with-param items are not freed.
180 xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt
)
182 xsltStackElemPtr param
;
184 for (; ctxt
->varsNr
> ctxt
->varsBase
; ctxt
->varsNr
--) {
185 param
= ctxt
->varsTab
[ctxt
->varsNr
-1];
187 * Free xsl:param items.
188 * xsl:with-param items will have a level of -1 or -2.
190 if (param
->level
>= 0) {
191 xsltFreeStackElemList(param
);
194 if (ctxt
->varsNr
> 0)
195 ctxt
->vars
= ctxt
->varsTab
[ctxt
->varsNr
- 1];
204 * @ctxt: the transformation context
205 * @value: the profiling value to push on the stack
207 * Push a profiling value on the stack
209 * Returns the new index in the stack or 0 in case of error
212 profPush(xsltTransformContextPtr ctxt
, long value
)
214 if (ctxt
->profMax
== 0) {
217 (long *) xmlMalloc(ctxt
->profMax
* sizeof(ctxt
->profTab
[0]));
218 if (ctxt
->profTab
== NULL
) {
219 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
223 else if (ctxt
->profNr
>= ctxt
->profMax
) {
226 (long *) xmlRealloc(ctxt
->profTab
,
227 ctxt
->profMax
* sizeof(ctxt
->profTab
[0]));
228 if (ctxt
->profTab
== NULL
) {
229 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
233 ctxt
->profTab
[ctxt
->profNr
] = value
;
235 return (ctxt
->profNr
++);
239 * @ctxt: the transformation context
241 * Pop a profiling value from the stack
243 * Returns the stored profiling value
246 profPop(xsltTransformContextPtr ctxt
)
250 if (ctxt
->profNr
<= 0)
253 if (ctxt
->profNr
> 0)
254 ctxt
->prof
= ctxt
->profTab
[ctxt
->profNr
- 1];
256 ctxt
->prof
= (long) 0;
257 ret
= ctxt
->profTab
[ctxt
->profNr
];
258 ctxt
->profTab
[ctxt
->profNr
] = 0;
263 profCallgraphAdd(xsltTemplatePtr templ
, xsltTemplatePtr parent
)
267 if (templ
->templMax
== 0) {
269 templ
->templCalledTab
=
270 (xsltTemplatePtr
*) xmlMalloc(templ
->templMax
*
271 sizeof(templ
->templCalledTab
[0]));
272 templ
->templCountTab
=
273 (int *) xmlMalloc(templ
->templMax
*
274 sizeof(templ
->templCountTab
[0]));
275 if (templ
->templCalledTab
== NULL
|| templ
->templCountTab
== NULL
) {
276 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
280 else if (templ
->templNr
>= templ
->templMax
) {
281 templ
->templMax
*= 2;
282 templ
->templCalledTab
=
283 (xsltTemplatePtr
*) xmlRealloc(templ
->templCalledTab
,
285 sizeof(templ
->templCalledTab
[0]));
286 templ
->templCountTab
=
287 (int *) xmlRealloc(templ
->templCountTab
,
289 sizeof(templ
->templCountTab
[0]));
290 if (templ
->templCalledTab
== NULL
|| templ
->templCountTab
== NULL
) {
291 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
296 for (i
= 0; i
< templ
->templNr
; i
++) {
297 if (templ
->templCalledTab
[i
] == parent
) {
298 templ
->templCountTab
[i
]++;
302 if (i
== templ
->templNr
) {
303 /* not found, add new one */
304 templ
->templCalledTab
[templ
->templNr
] = parent
;
305 templ
->templCountTab
[templ
->templNr
] = 1;
310 #endif /* WITH_PROFILER */
314 * @ctxt: transform context
315 * @node: context node
316 * @comp: precompiled expression
318 * Evaluate a precompiled XPath expression.
320 static xmlXPathObjectPtr
321 xsltPreCompEval(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
322 xsltStylePreCompPtr comp
) {
323 xmlXPathObjectPtr res
;
324 xmlXPathContextPtr xpctxt
;
325 xmlNodePtr oldXPContextNode
;
326 xmlNsPtr
*oldXPNamespaces
;
327 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
329 xpctxt
= ctxt
->xpathCtxt
;
330 oldXPContextNode
= xpctxt
->node
;
331 oldXPProximityPosition
= xpctxt
->proximityPosition
;
332 oldXPContextSize
= xpctxt
->contextSize
;
333 oldXPNsNr
= xpctxt
->nsNr
;
334 oldXPNamespaces
= xpctxt
->namespaces
;
337 #ifdef XSLT_REFACTORED
338 if (comp
->inScopeNs
!= NULL
) {
339 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
340 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
342 xpctxt
->namespaces
= NULL
;
346 xpctxt
->namespaces
= comp
->nsList
;
347 xpctxt
->nsNr
= comp
->nsNr
;
350 res
= xmlXPathCompiledEval(comp
->comp
, xpctxt
);
352 xpctxt
->node
= oldXPContextNode
;
353 xpctxt
->proximityPosition
= oldXPProximityPosition
;
354 xpctxt
->contextSize
= oldXPContextSize
;
355 xpctxt
->nsNr
= oldXPNsNr
;
356 xpctxt
->namespaces
= oldXPNamespaces
;
362 * xsltPreCompEvalToBoolean:
363 * @ctxt: transform context
364 * @node: context node
365 * @comp: precompiled expression
367 * Evaluate a precompiled XPath expression as boolean.
370 xsltPreCompEvalToBoolean(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
371 xsltStylePreCompPtr comp
) {
373 xmlXPathContextPtr xpctxt
;
374 xmlNodePtr oldXPContextNode
;
375 xmlNsPtr
*oldXPNamespaces
;
376 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
378 xpctxt
= ctxt
->xpathCtxt
;
379 oldXPContextNode
= xpctxt
->node
;
380 oldXPProximityPosition
= xpctxt
->proximityPosition
;
381 oldXPContextSize
= xpctxt
->contextSize
;
382 oldXPNsNr
= xpctxt
->nsNr
;
383 oldXPNamespaces
= xpctxt
->namespaces
;
386 #ifdef XSLT_REFACTORED
387 if (comp
->inScopeNs
!= NULL
) {
388 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
389 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
391 xpctxt
->namespaces
= NULL
;
395 xpctxt
->namespaces
= comp
->nsList
;
396 xpctxt
->nsNr
= comp
->nsNr
;
399 res
= xmlXPathCompiledEvalToBoolean(comp
->comp
, xpctxt
);
401 xpctxt
->node
= oldXPContextNode
;
402 xpctxt
->proximityPosition
= oldXPProximityPosition
;
403 xpctxt
->contextSize
= oldXPContextSize
;
404 xpctxt
->nsNr
= oldXPNsNr
;
405 xpctxt
->namespaces
= oldXPNamespaces
;
410 /************************************************************************
412 * XInclude default settings *
414 ************************************************************************/
416 static int xsltDoXIncludeDefault
= 0;
419 * xsltSetXIncludeDefault:
420 * @xinclude: whether to do XInclude processing
422 * Set whether XInclude should be processed on document being loaded by default
425 xsltSetXIncludeDefault(int xinclude
) {
426 xsltDoXIncludeDefault
= (xinclude
!= 0);
430 * xsltGetXIncludeDefault:
432 * Provides the default state for XInclude processing
434 * Returns 0 if there is no processing 1 otherwise
437 xsltGetXIncludeDefault(void) {
438 return(xsltDoXIncludeDefault
);
441 static unsigned long xsltDefaultTrace
= (unsigned long) XSLT_TRACE_ALL
;
444 * xsltDebugSetDefaultTrace:
445 * @val: tracing level mask
447 * Set the default debug tracing level mask
449 void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val
) {
450 xsltDefaultTrace
= val
;
454 * xsltDebugGetDefaultTrace:
456 * Get the current default debug tracing level mask
458 * Returns the current default debug tracing level mask
460 xsltDebugTraceCodes
xsltDebugGetDefaultTrace() {
461 return xsltDefaultTrace
;
464 /************************************************************************
466 * Handling of Transformation Contexts *
468 ************************************************************************/
470 static xsltTransformCachePtr
471 xsltTransformCacheCreate(void)
473 xsltTransformCachePtr ret
;
475 ret
= (xsltTransformCachePtr
) xmlMalloc(sizeof(xsltTransformCache
));
477 xsltTransformError(NULL
, NULL
, NULL
,
478 "xsltTransformCacheCreate : malloc failed\n");
481 memset(ret
, 0, sizeof(xsltTransformCache
));
486 xsltTransformCacheFree(xsltTransformCachePtr cache
)
491 * Free tree fragments.
494 xmlDocPtr tmp
, cur
= cache
->RVT
;
497 cur
= (xmlDocPtr
) cur
->next
;
498 if (tmp
->_private
!= NULL
) {
500 * Tree the document info.
502 xsltFreeDocumentKeys((xsltDocumentPtr
) tmp
->_private
);
503 xmlFree(tmp
->_private
);
511 if (cache
->stackItems
) {
512 xsltStackElemPtr tmp
, cur
= cache
->stackItems
;
517 * REVISIT TODO: Should be call a destruction-function
527 * xsltNewTransformContext:
528 * @style: a parsed XSLT stylesheet
529 * @doc: the input document
531 * Create a new XSLT TransformContext
533 * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
535 xsltTransformContextPtr
536 xsltNewTransformContext(xsltStylesheetPtr style
, xmlDocPtr doc
) {
537 xsltTransformContextPtr cur
;
538 xsltDocumentPtr docu
;
543 cur
= (xsltTransformContextPtr
) xmlMalloc(sizeof(xsltTransformContext
));
545 xsltTransformError(NULL
, NULL
, (xmlNodePtr
)doc
,
546 "xsltNewTransformContext : malloc failed\n");
549 memset(cur
, 0, sizeof(xsltTransformContext
));
551 cur
->cache
= xsltTransformCacheCreate();
552 if (cur
->cache
== NULL
)
555 * setup of the dictionary must be done early as some of the
556 * processing later like key handling may need it.
558 cur
->dict
= xmlDictCreateSub(style
->dict
);
559 cur
->internalized
= ((style
->internalized
) && (cur
->dict
!= NULL
));
560 #ifdef WITH_XSLT_DEBUG
561 xsltGenericDebug(xsltGenericDebugContext
,
562 "Creating sub-dictionary from stylesheet for transformation\n");
566 * initialize the template stack
568 cur
->templTab
= (xsltTemplatePtr
*)
569 xmlMalloc(10 * sizeof(xsltTemplatePtr
));
570 if (cur
->templTab
== NULL
) {
571 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
572 "xsltNewTransformContext: out of memory\n");
578 cur
->maxTemplateDepth
= xsltMaxDepth
;
581 * initialize the variables stack
583 cur
->varsTab
= (xsltStackElemPtr
*)
584 xmlMalloc(10 * sizeof(xsltStackElemPtr
));
585 if (cur
->varsTab
== NULL
) {
586 xmlGenericError(xmlGenericErrorContext
,
587 "xsltNewTransformContext: out of memory\n");
594 cur
->maxTemplateVars
= xsltMaxVars
;
597 * the profiling stack is not initialized by default
605 cur
->xpathCtxt
= xmlXPathNewContext(doc
);
606 if (cur
->xpathCtxt
== NULL
) {
607 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
608 "xsltNewTransformContext : xmlXPathNewContext failed\n");
612 * Create an XPath cache.
614 if (xmlXPathContextSetCache(cur
->xpathCtxt
, 1, -1, 0) == -1)
617 * Initialize the extras array
619 if (style
->extrasNr
!= 0) {
620 cur
->extrasMax
= style
->extrasNr
+ 20;
621 cur
->extras
= (xsltRuntimeExtraPtr
)
622 xmlMalloc(cur
->extrasMax
* sizeof(xsltRuntimeExtra
));
623 if (cur
->extras
== NULL
) {
624 xmlGenericError(xmlGenericErrorContext
,
625 "xsltNewTransformContext: out of memory\n");
628 cur
->extrasNr
= style
->extrasNr
;
629 for (i
= 0;i
< cur
->extrasMax
;i
++) {
630 cur
->extras
[i
].info
= NULL
;
631 cur
->extras
[i
].deallocate
= NULL
;
632 cur
->extras
[i
].val
.ptr
= NULL
;
640 XSLT_REGISTER_VARIABLE_LOOKUP(cur
);
641 XSLT_REGISTER_FUNCTION_LOOKUP(cur
);
642 cur
->xpathCtxt
->nsHash
= style
->nsHash
;
644 * Initialize the registered external modules
646 xsltInitCtxtExts(cur
);
648 * Setup document element ordering for later efficiencies
651 if (xslDebugStatus
== XSLT_DEBUG_NONE
)
652 xmlXPathOrderDocElems(doc
);
654 * Must set parserOptions before calling xsltNewDocument
657 cur
->parserOptions
= XSLT_PARSE_OPTIONS
;
658 docu
= xsltNewDocument(cur
, doc
);
660 xsltTransformError(cur
, NULL
, (xmlNodePtr
)doc
,
661 "xsltNewTransformContext : xsltNewDocument failed\n");
665 cur
->document
= docu
;
667 cur
->outputFile
= NULL
;
668 cur
->sec
= xsltGetDefaultSecurityPrefs();
669 cur
->debugStatus
= xslDebugStatus
;
670 cur
->traceCode
= (unsigned long*) &xsltDefaultTrace
;
671 cur
->xinclude
= xsltGetXIncludeDefault();
672 cur
->keyInitLevel
= 0;
678 xsltFreeTransformContext(cur
);
683 * xsltFreeTransformContext:
684 * @ctxt: an XSLT parser context
686 * Free up the memory allocated by @ctxt
689 xsltFreeTransformContext(xsltTransformContextPtr ctxt
) {
694 * Shutdown the extension modules associated to the stylesheet
697 xsltShutdownCtxtExts(ctxt
);
699 if (ctxt
->xpathCtxt
!= NULL
) {
700 ctxt
->xpathCtxt
->nsHash
= NULL
;
701 xmlXPathFreeContext(ctxt
->xpathCtxt
);
703 if (ctxt
->templTab
!= NULL
)
704 xmlFree(ctxt
->templTab
);
705 if (ctxt
->varsTab
!= NULL
)
706 xmlFree(ctxt
->varsTab
);
707 if (ctxt
->profTab
!= NULL
)
708 xmlFree(ctxt
->profTab
);
709 if ((ctxt
->extrasNr
> 0) && (ctxt
->extras
!= NULL
)) {
712 for (i
= 0;i
< ctxt
->extrasNr
;i
++) {
713 if ((ctxt
->extras
[i
].deallocate
!= NULL
) &&
714 (ctxt
->extras
[i
].info
!= NULL
))
715 ctxt
->extras
[i
].deallocate(ctxt
->extras
[i
].info
);
717 xmlFree(ctxt
->extras
);
719 xsltFreeGlobalVariables(ctxt
);
720 xsltFreeDocuments(ctxt
);
721 xsltFreeCtxtExts(ctxt
);
723 xsltTransformCacheFree(ctxt
->cache
);
724 xmlDictFree(ctxt
->dict
);
725 #ifdef WITH_XSLT_DEBUG
726 xsltGenericDebug(xsltGenericDebugContext
,
727 "freeing transformation dictionary\n");
729 memset(ctxt
, -1, sizeof(xsltTransformContext
));
733 /************************************************************************
735 * Copy of Nodes in an XSLT fashion *
737 ************************************************************************/
741 * @parent: the parent node
742 * @cur: the child node
744 * Wrapper version of xmlAddChild with a more consistent behaviour on
745 * error. One expect the use to be child = xsltAddChild(parent, child);
746 * and the routine will take care of not leaking on errors or node merge
748 * Returns the child is successfully attached or NULL if merged or freed
751 xsltAddChild(xmlNodePtr parent
, xmlNodePtr cur
) {
756 if (parent
== NULL
) {
760 ret
= xmlAddChild(parent
, cur
);
767 * @ctxt: a XSLT process context
768 * @target: the text node where the text will be attached
769 * @string: the text string
770 * @len: the string length in byte
772 * Extend the current text node with the new string, it handles coalescing
774 * Returns: the text node
777 xsltAddTextString(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
778 const xmlChar
*string
, int len
) {
782 if ((len
<= 0) || (string
== NULL
) || (target
== NULL
))
785 if (ctxt
->lasttext
== target
->content
) {
788 /* Check for integer overflow accounting for NUL terminator. */
789 if (len
>= INT_MAX
- ctxt
->lasttuse
) {
790 xsltTransformError(ctxt
, NULL
, target
,
791 "xsltCopyText: text allocation failed\n");
794 minSize
= ctxt
->lasttuse
+ len
+ 1;
796 if (ctxt
->lasttsize
< minSize
) {
801 /* Double buffer size but increase by at least 100 bytes. */
802 extra
= minSize
< 100 ? 100 : minSize
;
804 /* Check for integer overflow. */
805 if (extra
> INT_MAX
- ctxt
->lasttsize
) {
809 size
= ctxt
->lasttsize
+ extra
;
812 newbuf
= (xmlChar
*) xmlRealloc(target
->content
,size
);
813 if (newbuf
== NULL
) {
814 xsltTransformError(ctxt
, NULL
, target
,
815 "xsltCopyText: text allocation failed\n");
818 ctxt
->lasttsize
= size
;
819 ctxt
->lasttext
= newbuf
;
820 target
->content
= newbuf
;
822 memcpy(&(target
->content
[ctxt
->lasttuse
]), string
, len
);
823 ctxt
->lasttuse
+= len
;
824 target
->content
[ctxt
->lasttuse
] = 0;
826 xmlNodeAddContent(target
, string
);
827 ctxt
->lasttext
= target
->content
;
828 len
= xmlStrlen(target
->content
);
829 ctxt
->lasttsize
= len
;
830 ctxt
->lasttuse
= len
;
836 * xsltCopyTextString:
837 * @ctxt: a XSLT process context
838 * @target: the element where the text will be attached
839 * @string: the text string
840 * @noescape: should disable-escaping be activated for this text node.
842 * Adds @string to a newly created or an existent text node child of
845 * Returns: the text node, where the text content of @cur is copied to.
846 * NULL in case of API or internal errors.
849 xsltCopyTextString(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
850 const xmlChar
*string
, int noescape
)
858 #ifdef WITH_XSLT_DEBUG_PROCESS
859 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
860 "xsltCopyTextString: copy text %s\n",
865 * Play safe and reset the merging mechanism for every new
868 if ((target
== NULL
) || (target
->children
== NULL
)) {
869 ctxt
->lasttext
= NULL
;
872 /* handle coalescing of text nodes here */
873 len
= xmlStrlen(string
);
874 if ((ctxt
->type
== XSLT_OUTPUT_XML
) &&
875 (ctxt
->style
->cdataSection
!= NULL
) &&
877 (target
->type
== XML_ELEMENT_NODE
) &&
878 (((target
->ns
== NULL
) &&
879 (xmlHashLookup2(ctxt
->style
->cdataSection
,
880 target
->name
, NULL
) != NULL
)) ||
881 ((target
->ns
!= NULL
) &&
882 (xmlHashLookup2(ctxt
->style
->cdataSection
,
883 target
->name
, target
->ns
->href
) != NULL
))))
886 * Process "cdata-section-elements".
888 if ((target
->last
!= NULL
) &&
889 (target
->last
->type
== XML_CDATA_SECTION_NODE
))
891 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
893 copy
= xmlNewCDataBlock(ctxt
->output
, string
, len
);
894 } else if (noescape
) {
896 * Process "disable-output-escaping".
898 if ((target
!= NULL
) && (target
->last
!= NULL
) &&
899 (target
->last
->type
== XML_TEXT_NODE
) &&
900 (target
->last
->name
== xmlStringTextNoenc
))
902 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
904 copy
= xmlNewTextLen(string
, len
);
906 copy
->name
= xmlStringTextNoenc
;
909 * Default processing.
911 if ((target
!= NULL
) && (target
->last
!= NULL
) &&
912 (target
->last
->type
== XML_TEXT_NODE
) &&
913 (target
->last
->name
== xmlStringText
)) {
914 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
916 copy
= xmlNewTextLen(string
, len
);
918 if (copy
!= NULL
&& target
!= NULL
)
919 copy
= xsltAddChild(target
, copy
);
921 ctxt
->lasttext
= copy
->content
;
922 ctxt
->lasttsize
= len
;
923 ctxt
->lasttuse
= len
;
925 xsltTransformError(ctxt
, NULL
, target
,
926 "xsltCopyTextString: text copy failed\n");
927 ctxt
->lasttext
= NULL
;
934 * @ctxt: a XSLT process context
935 * @target: the element where the text will be attached
936 * @cur: the text or CDATA node
937 * @interned: the string is in the target doc dictionary
939 * Copy the text content of @cur and append it to @target's children.
941 * Returns: the text node, where the text content of @cur is copied to.
942 * NULL in case of API or internal errors.
945 xsltCopyText(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
946 xmlNodePtr cur
, int interned
)
950 if ((cur
->type
!= XML_TEXT_NODE
) &&
951 (cur
->type
!= XML_CDATA_SECTION_NODE
))
953 if (cur
->content
== NULL
)
956 #ifdef WITH_XSLT_DEBUG_PROCESS
957 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
958 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
959 "xsltCopyText: copy CDATA text %s\n",
961 } else if (cur
->name
== xmlStringTextNoenc
) {
962 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
963 "xsltCopyText: copy unescaped text %s\n",
966 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
967 "xsltCopyText: copy text %s\n",
973 * Play save and reset the merging mechanism for every new
976 if ((target
== NULL
) || (target
->children
== NULL
)) {
977 ctxt
->lasttext
= NULL
;
980 if ((ctxt
->style
->cdataSection
!= NULL
) &&
981 (ctxt
->type
== XSLT_OUTPUT_XML
) &&
983 (target
->type
== XML_ELEMENT_NODE
) &&
984 (((target
->ns
== NULL
) &&
985 (xmlHashLookup2(ctxt
->style
->cdataSection
,
986 target
->name
, NULL
) != NULL
)) ||
987 ((target
->ns
!= NULL
) &&
988 (xmlHashLookup2(ctxt
->style
->cdataSection
,
989 target
->name
, target
->ns
->href
) != NULL
))))
992 * Process "cdata-section-elements".
995 * OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
998 * TODO: Since this doesn't merge adjacent CDATA-section nodes,
999 * we'll get: <![CDATA[x]]><!CDATA[y]]>.
1000 * TODO: Reported in #321505.
1002 if ((target
->last
!= NULL
) &&
1003 (target
->last
->type
== XML_CDATA_SECTION_NODE
))
1006 * Append to existing CDATA-section node.
1008 copy
= xsltAddTextString(ctxt
, target
->last
, cur
->content
,
1009 xmlStrlen(cur
->content
));
1014 len
= xmlStrlen(cur
->content
);
1015 copy
= xmlNewCDataBlock(ctxt
->output
, cur
->content
, len
);
1018 ctxt
->lasttext
= copy
->content
;
1019 ctxt
->lasttsize
= len
;
1020 ctxt
->lasttuse
= len
;
1022 } else if ((target
!= NULL
) &&
1023 (target
->last
!= NULL
) &&
1024 /* both escaped or both non-escaped text-nodes */
1025 (((target
->last
->type
== XML_TEXT_NODE
) &&
1026 (target
->last
->name
== cur
->name
)) ||
1027 /* non-escaped text nodes and CDATA-section nodes */
1028 (((target
->last
->type
== XML_CDATA_SECTION_NODE
) &&
1029 (cur
->name
== xmlStringTextNoenc
)))))
1032 * we are appending to an existing text node
1034 copy
= xsltAddTextString(ctxt
, target
->last
, cur
->content
,
1035 xmlStrlen(cur
->content
));
1037 } else if ((interned
) && (target
!= NULL
) &&
1038 (target
->doc
!= NULL
) &&
1039 (target
->doc
->dict
== ctxt
->dict
))
1042 * TODO: DO we want to use this also for "text" output?
1044 copy
= xmlNewTextLen(NULL
, 0);
1047 if (cur
->name
== xmlStringTextNoenc
)
1048 copy
->name
= xmlStringTextNoenc
;
1051 * Must confirm that content is in dict (bug 302821)
1052 * TODO: This check should be not needed for text coming
1053 * from the stylesheets
1055 if (xmlDictOwns(ctxt
->dict
, cur
->content
))
1056 copy
->content
= cur
->content
;
1058 if ((copy
->content
= xmlStrdup(cur
->content
)) == NULL
)
1062 ctxt
->lasttext
= NULL
;
1065 * normal processing. keep counters to extend the text node
1066 * in xsltAddTextString if needed.
1070 len
= xmlStrlen(cur
->content
);
1071 copy
= xmlNewTextLen(cur
->content
, len
);
1074 if (cur
->name
== xmlStringTextNoenc
)
1075 copy
->name
= xmlStringTextNoenc
;
1076 ctxt
->lasttext
= copy
->content
;
1077 ctxt
->lasttsize
= len
;
1078 ctxt
->lasttuse
= len
;
1081 if (target
!= NULL
) {
1082 copy
->doc
= target
->doc
;
1084 * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
1085 * to ensure that the optimized text-merging mechanism
1086 * won't interfere with normal node-merging in any case.
1088 copy
= xsltAddChild(target
, copy
);
1091 xsltTransformError(ctxt
, NULL
, target
,
1092 "xsltCopyText: text copy failed\n");
1096 if ((copy
== NULL
) || (copy
->content
== NULL
)) {
1097 xsltTransformError(ctxt
, NULL
, target
,
1098 "Internal error in xsltCopyText(): "
1099 "Failed to copy the string.\n");
1100 ctxt
->state
= XSLT_STATE_STOPPED
;
1106 * xsltShallowCopyAttr:
1107 * @ctxt: a XSLT process context
1108 * @invocNode: responsible node in the stylesheet; used for error reports
1109 * @target: the element where the attribute will be grafted
1110 * @attr: the attribute to be copied
1112 * Do a copy of an attribute.
1118 * Returns: a new xmlAttrPtr, or NULL in case of error.
1121 xsltShallowCopyAttr(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1122 xmlNodePtr target
, xmlAttrPtr attr
)
1130 if (target
->type
!= XML_ELEMENT_NODE
) {
1131 xsltTransformError(ctxt
, NULL
, invocNode
,
1132 "Cannot add an attribute node to a non-element node.\n");
1136 if (target
->children
!= NULL
) {
1137 xsltTransformError(ctxt
, NULL
, invocNode
,
1138 "Attribute nodes must be added before "
1139 "any child nodes to an element.\n");
1143 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1144 if (attr
->ns
!= NULL
) {
1147 ns
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1148 attr
->ns
->href
, attr
->ns
->prefix
, target
);
1150 xsltTransformError(ctxt
, NULL
, invocNode
,
1151 "Namespace fixup error: Failed to acquire an in-scope "
1152 "namespace binding of the copied attribute '{%s}%s'.\n",
1153 attr
->ns
->href
, attr
->name
);
1155 * TODO: Should we just stop here?
1159 * Note that xmlSetNsProp() will take care of duplicates
1160 * and assigns the new namespace even to a duplicate.
1162 copy
= xmlSetNsProp(target
, ns
, attr
->name
, value
);
1164 copy
= xmlSetNsProp(target
, NULL
, attr
->name
, value
);
1174 * NOTE: This was optimized according to bug #342695.
1175 * TODO: Can this further be optimized, if source and target
1176 * share the same dict and attr->children is just 1 text node
1177 * which is in the dict? How probable is such a case?
1180 * TODO: Do we need to create an empty text node if the value
1181 * is the empty string?
1183 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1184 if (value
!= NULL
) {
1185 txtNode
= xmlNewDocText(target
->doc
, NULL
);
1186 if (txtNode
== NULL
)
1188 if ((target
->doc
!= NULL
) &&
1189 (target
->doc
->dict
!= NULL
))
1192 (xmlChar
*) xmlDictLookup(target
->doc
->dict
,
1193 BAD_CAST value
, -1);
1196 txtNode
->content
= value
;
1197 copy
->children
= txtNode
;
1205 * xsltCopyAttrListNoOverwrite:
1206 * @ctxt: a XSLT process context
1207 * @invocNode: responsible node in the stylesheet; used for error reports
1208 * @target: the element where the new attributes will be grafted
1209 * @attr: the first attribute in the list to be copied
1211 * Copies a list of attribute nodes, starting with @attr, over to the
1212 * @target element node.
1217 * Returns 0 on success and -1 on errors and internal errors.
1220 xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt
,
1221 xmlNodePtr invocNode
,
1222 xmlNodePtr target
, xmlAttrPtr attr
)
1225 xmlNsPtr origNs
= NULL
, copyNs
= NULL
;
1229 * Don't use xmlCopyProp() here, since it will try to
1230 * reconciliate namespaces.
1232 while (attr
!= NULL
) {
1234 * Find a namespace node in the tree of @target.
1235 * Avoid searching for the same ns.
1237 if (attr
->ns
!= origNs
) {
1239 if (attr
->ns
!= NULL
) {
1240 copyNs
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1241 attr
->ns
->href
, attr
->ns
->prefix
, target
);
1248 * If attribute has a value, we need to copy it (watching out
1249 * for possible entities)
1251 if ((attr
->children
) && (attr
->children
->type
== XML_TEXT_NODE
) &&
1252 (attr
->children
->next
== NULL
)) {
1253 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
,
1254 attr
->children
->content
);
1255 } else if (attr
->children
!= NULL
) {
1256 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1257 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
, BAD_CAST value
);
1260 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
, NULL
);
1272 * xsltShallowCopyElem:
1273 * @ctxt: the XSLT process context
1274 * @node: the element node in the source tree
1275 * or the Literal Result Element
1276 * @insert: the parent in the result tree
1277 * @isLRE: if @node is a Literal Result Element
1279 * Make a copy of the element node @node
1280 * and insert it as last child of @insert.
1282 * URGENT TODO: The problem with this one (for the non-refactored code)
1283 * is that it is used for both, Literal Result Elements *and*
1284 * copying input nodes.
1286 * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
1289 * xsltApplySequenceConstructor()
1290 * (for Literal Result Elements - which is a problem)
1291 * xsltCopy() (for shallow-copying elements via xsl:copy)
1293 * Returns a pointer to the new node, or NULL in case of error
1296 xsltShallowCopyElem(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1297 xmlNodePtr insert
, int isLRE
)
1301 if ((node
->type
== XML_DTD_NODE
) || (insert
== NULL
))
1303 if ((node
->type
== XML_TEXT_NODE
) ||
1304 (node
->type
== XML_CDATA_SECTION_NODE
))
1305 return(xsltCopyText(ctxt
, insert
, node
, 0));
1307 copy
= xmlDocCopyNode(node
, insert
->doc
, 0);
1309 copy
->doc
= ctxt
->output
;
1310 copy
= xsltAddChild(insert
, copy
);
1312 xsltTransformError(ctxt
, NULL
, node
,
1313 "xsltShallowCopyElem: copy failed\n");
1317 if (node
->type
== XML_ELEMENT_NODE
) {
1319 * Add namespaces as they are needed
1321 if (node
->nsDef
!= NULL
) {
1323 * TODO: Remove the LRE case in the refactored code
1327 xsltCopyNamespaceList(ctxt
, copy
, node
->nsDef
);
1329 xsltCopyNamespaceListInternal(copy
, node
->nsDef
);
1333 * URGENT TODO: The problem with this is that it does not
1334 * copy over all namespace nodes in scope.
1335 * The damn thing about this is, that we would need to
1336 * use the xmlGetNsList(), for every single node; this is
1337 * also done in xsltCopyTree(), but only for the top node.
1339 if (node
->ns
!= NULL
) {
1342 * REVISIT TODO: Since the non-refactored code still does
1343 * ns-aliasing, we need to call xsltGetNamespace() here.
1344 * Remove this when ready.
1346 copy
->ns
= xsltGetNamespace(ctxt
, node
, node
->ns
, copy
);
1348 copy
->ns
= xsltGetSpecialNamespace(ctxt
,
1349 node
, node
->ns
->href
, node
->ns
->prefix
, copy
);
1352 } else if ((insert
->type
== XML_ELEMENT_NODE
) &&
1353 (insert
->ns
!= NULL
))
1356 * "Undeclare" the default namespace.
1358 xsltGetSpecialNamespace(ctxt
, node
, NULL
, NULL
, copy
);
1362 xsltTransformError(ctxt
, NULL
, node
,
1363 "xsltShallowCopyElem: copy %s failed\n", node
->name
);
1370 * @ctxt: a XSLT process context
1371 * @invocNode: responsible node in the stylesheet; used for error reports
1372 * @list: the list of element nodes in the source tree.
1373 * @insert: the parent in the result tree.
1374 * @isLRE: is this a literal result element list
1375 * @topElemVisited: indicates if a top-most element was already processed
1377 * Make a copy of the full list of tree @list
1378 * and insert it as last children of @insert
1380 * NOTE: Not to be used for Literal Result Elements.
1385 * Returns a pointer to the new list, or NULL in case of error
1388 xsltCopyTreeList(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1390 xmlNodePtr insert
, int isLRE
, int topElemVisited
)
1392 xmlNodePtr copy
, ret
= NULL
;
1394 while (list
!= NULL
) {
1395 copy
= xsltCopyTree(ctxt
, invocNode
,
1396 list
, insert
, isLRE
, topElemVisited
);
1408 * xsltCopyNamespaceListInternal:
1409 * @node: the target node
1410 * @cur: the first namespace
1412 * Do a copy of a namespace list. If @node is non-NULL the
1413 * new namespaces are added automatically.
1417 * QUESTION: What is the exact difference between this function
1418 * and xsltCopyNamespaceList() in "namespaces.c"?
1419 * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
1421 * Returns: a new xmlNsPtr, or NULL in case of error.
1424 xsltCopyNamespaceListInternal(xmlNodePtr elem
, xmlNsPtr ns
) {
1425 xmlNsPtr ret
= NULL
;
1426 xmlNsPtr p
= NULL
, q
, luNs
;
1431 * One can add namespaces only on element nodes
1433 if ((elem
!= NULL
) && (elem
->type
!= XML_ELEMENT_NODE
))
1437 if (ns
->type
!= XML_NAMESPACE_DECL
)
1440 * Avoid duplicating namespace declarations on the tree.
1443 if ((elem
->ns
!= NULL
) &&
1444 xmlStrEqual(elem
->ns
->prefix
, ns
->prefix
) &&
1445 xmlStrEqual(elem
->ns
->href
, ns
->href
))
1450 luNs
= xmlSearchNs(elem
->doc
, elem
, ns
->prefix
);
1451 if ((luNs
!= NULL
) && (xmlStrEqual(luNs
->href
, ns
->href
)))
1457 q
= xmlNewNs(elem
, ns
->href
, ns
->prefix
);
1460 } else if (q
!= NULL
) {
1465 } while (ns
!= NULL
);
1470 * xsltShallowCopyNsNode:
1471 * @ctxt: the XSLT transformation context
1472 * @invocNode: responsible node in the stylesheet; used for error reports
1473 * @insert: the target element node in the result tree
1474 * @ns: the namespace node
1476 * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
1478 * Returns a new/existing ns-node, or NULL.
1481 xsltShallowCopyNsNode(xsltTransformContextPtr ctxt
,
1482 xmlNodePtr invocNode
,
1487 * TODO: Contrary to header comments, this is declared as int.
1488 * be modified to return a node pointer, or NULL if any error
1492 if ((insert
== NULL
) || (insert
->type
!= XML_ELEMENT_NODE
))
1495 if (insert
->children
!= NULL
) {
1496 xsltTransformError(ctxt
, NULL
, invocNode
,
1497 "Namespace nodes must be added before "
1498 "any child nodes are added to an element.\n");
1502 * BIG NOTE: Xalan-J simply overwrites any ns-decls with
1503 * an equal prefix. We definitively won't do that.
1505 * MSXML 4.0 and the .NET ignores ns-decls for which an
1506 * equal prefix is already in use.
1508 * Saxon raises an error like:
1509 * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
1510 * nodes with the same name".
1512 * NOTE: We'll currently follow MSXML here.
1513 * REVISIT TODO: Check if it's better to follow Saxon here.
1515 if (ns
->prefix
== NULL
) {
1517 * If we are adding ns-nodes to an element using e.g.
1518 * <xsl:copy-of select="/foo/namespace::*">, then we need
1519 * to ensure that we don't incorrectly declare a default
1520 * namespace on an element in no namespace, which otherwise
1521 * would move the element incorrectly into a namespace, if
1522 * the node tree is serialized.
1524 if (insert
->ns
== NULL
)
1526 } else if ((ns
->prefix
[0] == 'x') &&
1527 xmlStrEqual(ns
->prefix
, BAD_CAST
"xml"))
1530 * The XML namespace is built in.
1535 if (insert
->nsDef
!= NULL
) {
1536 tmpns
= insert
->nsDef
;
1538 if ((tmpns
->prefix
== NULL
) == (ns
->prefix
== NULL
)) {
1539 if ((tmpns
->prefix
== ns
->prefix
) ||
1540 xmlStrEqual(tmpns
->prefix
, ns
->prefix
))
1545 if (xmlStrEqual(tmpns
->href
, ns
->href
))
1550 tmpns
= tmpns
->next
;
1551 } while (tmpns
!= NULL
);
1553 tmpns
= xmlSearchNs(insert
->doc
, insert
, ns
->prefix
);
1554 if ((tmpns
!= NULL
) && xmlStrEqual(tmpns
->href
, ns
->href
))
1557 * Declare a new namespace.
1558 * TODO: The problem (wrt efficiency) with this xmlNewNs() is
1559 * that it will again search the already declared namespaces
1560 * for a duplicate :-/
1562 return(xmlNewNs(insert
, ns
->href
, ns
->prefix
));
1566 * TODO: We could as well raise an error here (like Saxon does),
1567 * or at least generate a warning.
1574 * @ctxt: the XSLT transformation context
1575 * @invocNode: responsible node in the stylesheet; used for error reports
1576 * @node: the element node in the source tree
1577 * @insert: the parent in the result tree
1578 * @isLRE: indicates if @node is a Literal Result Element
1579 * @topElemVisited: indicates if a top-most element was already processed
1581 * Make a copy of the full tree under the element node @node
1582 * and insert it as last child of @insert
1584 * NOTE: Not to be used for Literal Result Elements.
1589 * Returns a pointer to the new tree, or NULL in case of error
1592 xsltCopyTree(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1593 xmlNodePtr node
, xmlNodePtr insert
, int isLRE
,
1600 switch (node
->type
) {
1601 case XML_ELEMENT_NODE
:
1602 case XML_ENTITY_REF_NODE
:
1603 case XML_ENTITY_NODE
:
1605 case XML_COMMENT_NODE
:
1606 case XML_DOCUMENT_NODE
:
1607 case XML_HTML_DOCUMENT_NODE
:
1608 #ifdef LIBXML_DOCB_ENABLED
1609 case XML_DOCB_DOCUMENT_NODE
:
1612 case XML_TEXT_NODE
: {
1613 int noenc
= (node
->name
== xmlStringTextNoenc
);
1614 return(xsltCopyTextString(ctxt
, insert
, node
->content
, noenc
));
1616 case XML_CDATA_SECTION_NODE
:
1617 return(xsltCopyTextString(ctxt
, insert
, node
->content
, 0));
1618 case XML_ATTRIBUTE_NODE
:
1620 xsltShallowCopyAttr(ctxt
, invocNode
, insert
, (xmlAttrPtr
) node
));
1621 case XML_NAMESPACE_DECL
:
1622 return((xmlNodePtr
) xsltShallowCopyNsNode(ctxt
, invocNode
,
1623 insert
, (xmlNsPtr
) node
));
1625 case XML_DOCUMENT_TYPE_NODE
:
1626 case XML_DOCUMENT_FRAG_NODE
:
1627 case XML_NOTATION_NODE
:
1629 case XML_ELEMENT_DECL
:
1630 case XML_ATTRIBUTE_DECL
:
1631 case XML_ENTITY_DECL
:
1632 case XML_XINCLUDE_START
:
1633 case XML_XINCLUDE_END
:
1636 if (XSLT_IS_RES_TREE_FRAG(node
)) {
1637 if (node
->children
!= NULL
)
1638 copy
= xsltCopyTreeList(ctxt
, invocNode
,
1639 node
->children
, insert
, 0, 0);
1644 copy
= xmlDocCopyNode(node
, insert
->doc
, 0);
1646 copy
->doc
= ctxt
->output
;
1647 copy
= xsltAddChild(insert
, copy
);
1649 xsltTransformError(ctxt
, NULL
, invocNode
,
1650 "xsltCopyTree: Copying of '%s' failed.\n", node
->name
);
1654 * The node may have been coalesced into another text node.
1656 if (insert
->last
!= copy
)
1657 return(insert
->last
);
1660 if (node
->type
== XML_ELEMENT_NODE
) {
1662 * Copy in-scope namespace nodes.
1664 * REVISIT: Since we try to reuse existing in-scope ns-decls by
1665 * using xmlSearchNsByHref(), this will eventually change
1666 * the prefix of an original ns-binding; thus it might
1667 * break QNames in element/attribute content.
1668 * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
1669 * context, plus a ns-lookup function, which writes directly
1670 * to a given list, then we wouldn't need to create/free the
1671 * nsList every time.
1673 if ((topElemVisited
== 0) &&
1674 (node
->parent
!= NULL
) &&
1675 (node
->parent
->type
!= XML_DOCUMENT_NODE
) &&
1676 (node
->parent
->type
!= XML_HTML_DOCUMENT_NODE
))
1678 xmlNsPtr
*nsList
, *curns
, ns
;
1681 * If this is a top-most element in a tree to be
1682 * copied, then we need to ensure that all in-scope
1683 * namespaces are copied over. For nodes deeper in the
1684 * tree, it is sufficient to reconcile only the ns-decls
1685 * (node->nsDef entries).
1688 nsList
= xmlGetNsList(node
->doc
, node
);
1689 if (nsList
!= NULL
) {
1693 * Search by prefix first in order to break as less
1694 * QNames in element/attribute content as possible.
1696 ns
= xmlSearchNs(insert
->doc
, insert
,
1700 (! xmlStrEqual(ns
->href
, (*curns
)->href
)))
1704 * Search by namespace name.
1705 * REVISIT TODO: Currently disabled.
1708 ns
= xmlSearchNsByHref(insert
->doc
,
1709 insert
, (*curns
)->href
);
1714 * Declare a new namespace on the copied element.
1716 ns
= xmlNewNs(copy
, (*curns
)->href
,
1718 /* TODO: Handle errors */
1720 if (node
->ns
== *curns
) {
1722 * If this was the original's namespace then set
1723 * the generated counterpart on the copy.
1728 } while (*curns
!= NULL
);
1731 } else if (node
->nsDef
!= NULL
) {
1733 * Copy over all namespace declaration attributes.
1735 if (node
->nsDef
!= NULL
) {
1737 xsltCopyNamespaceList(ctxt
, copy
, node
->nsDef
);
1739 xsltCopyNamespaceListInternal(copy
, node
->nsDef
);
1743 * Set the namespace.
1745 if (node
->ns
!= NULL
) {
1746 if (copy
->ns
== NULL
) {
1748 * This will map copy->ns to one of the newly created
1749 * in-scope ns-decls, OR create a new ns-decl on @copy.
1751 copy
->ns
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1752 node
->ns
->href
, node
->ns
->prefix
, copy
);
1754 } else if ((insert
->type
== XML_ELEMENT_NODE
) &&
1755 (insert
->ns
!= NULL
))
1758 * "Undeclare" the default namespace on @copy with xmlns="".
1760 xsltGetSpecialNamespace(ctxt
, invocNode
, NULL
, NULL
, copy
);
1763 * Copy attribute nodes.
1765 if (node
->properties
!= NULL
) {
1766 xsltCopyAttrListNoOverwrite(ctxt
, invocNode
,
1767 copy
, node
->properties
);
1769 if (topElemVisited
== 0)
1775 if (node
->children
!= NULL
) {
1776 xsltCopyTreeList(ctxt
, invocNode
,
1777 node
->children
, copy
, isLRE
, topElemVisited
);
1780 xsltTransformError(ctxt
, NULL
, invocNode
,
1781 "xsltCopyTree: Copying of '%s' failed.\n", node
->name
);
1786 /************************************************************************
1788 * Error/fallback processing *
1790 ************************************************************************/
1793 * xsltApplyFallbacks:
1794 * @ctxt: a XSLT process context
1795 * @node: the node in the source tree.
1796 * @inst: the node generating the error
1798 * Process possible xsl:fallback nodes present under @inst
1800 * Returns the number of xsl:fallback element found and processed
1803 xsltApplyFallbacks(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1809 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) ||
1810 (inst
->children
== NULL
))
1813 child
= inst
->children
;
1814 while (child
!= NULL
) {
1815 if ((IS_XSLT_ELEM(child
)) &&
1816 (xmlStrEqual(child
->name
, BAD_CAST
"fallback"))) {
1817 #ifdef WITH_XSLT_DEBUG_PARSING
1818 xsltGenericDebug(xsltGenericDebugContext
,
1819 "applying xsl:fallback\n");
1822 xsltApplySequenceConstructor(ctxt
, node
, child
->children
,
1825 child
= child
->next
;
1830 /************************************************************************
1832 * Default processing *
1834 ************************************************************************/
1837 * xsltDefaultProcessOneNode:
1838 * @ctxt: a XSLT process context
1839 * @node: the node in the source tree.
1840 * @params: extra parameters passed to the template if any
1842 * Process the source node with the default built-in template rule:
1843 * <xsl:template match="*|/">
1844 * <xsl:apply-templates/>
1849 * <xsl:template match="text()|@*">
1850 * <xsl:value-of select="."/>
1853 * Note also that namespace declarations are copied directly:
1855 * the built-in template rule is the only template rule that is applied
1856 * for namespace nodes.
1859 xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1860 xsltStackElemPtr params
) {
1863 int nbchild
= 0, oldSize
;
1864 int childno
= 0, oldPos
;
1865 xsltTemplatePtr
template;
1869 * Handling of leaves
1871 switch (node
->type
) {
1872 case XML_DOCUMENT_NODE
:
1873 case XML_HTML_DOCUMENT_NODE
:
1874 case XML_ELEMENT_NODE
:
1876 case XML_CDATA_SECTION_NODE
:
1877 #ifdef WITH_XSLT_DEBUG_PROCESS
1878 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1879 "xsltDefaultProcessOneNode: copy CDATA %s\n",
1882 copy
= xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
1884 xsltTransformError(ctxt
, NULL
, node
,
1885 "xsltDefaultProcessOneNode: cdata copy failed\n");
1889 #ifdef WITH_XSLT_DEBUG_PROCESS
1890 if (node
->content
== NULL
) {
1891 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1892 "xsltDefaultProcessOneNode: copy empty text\n"));
1895 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1896 "xsltDefaultProcessOneNode: copy text %s\n",
1900 copy
= xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
1902 xsltTransformError(ctxt
, NULL
, node
,
1903 "xsltDefaultProcessOneNode: text copy failed\n");
1906 case XML_ATTRIBUTE_NODE
:
1907 cur
= node
->children
;
1908 while ((cur
!= NULL
) && (cur
->type
!= XML_TEXT_NODE
))
1911 xsltTransformError(ctxt
, NULL
, node
,
1912 "xsltDefaultProcessOneNode: no text for attribute\n");
1914 #ifdef WITH_XSLT_DEBUG_PROCESS
1915 if (cur
->content
== NULL
) {
1916 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1917 "xsltDefaultProcessOneNode: copy empty text\n"));
1919 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1920 "xsltDefaultProcessOneNode: copy text %s\n",
1924 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
1926 xsltTransformError(ctxt
, NULL
, node
,
1927 "xsltDefaultProcessOneNode: text copy failed\n");
1935 * Handling of Elements: first pass, counting
1937 cur
= node
->children
;
1938 while (cur
!= NULL
) {
1939 if (IS_XSLT_REAL_NODE(cur
))
1945 * Handling of Elements: second pass, actual processing
1947 * Note that params are passed to the next template. This matches
1948 * XSLT 2.0 behavior but doesn't conform to XSLT 1.0.
1950 oldSize
= ctxt
->xpathCtxt
->contextSize
;
1951 oldPos
= ctxt
->xpathCtxt
->proximityPosition
;
1952 cur
= node
->children
;
1953 while (cur
!= NULL
) {
1955 switch (cur
->type
) {
1956 case XML_DOCUMENT_NODE
:
1957 case XML_HTML_DOCUMENT_NODE
:
1958 case XML_ELEMENT_NODE
:
1959 ctxt
->xpathCtxt
->contextSize
= nbchild
;
1960 ctxt
->xpathCtxt
->proximityPosition
= childno
;
1961 xsltProcessOneNode(ctxt
, cur
, params
);
1963 case XML_CDATA_SECTION_NODE
:
1964 template = xsltGetTemplate(ctxt
, cur
, NULL
);
1966 #ifdef WITH_XSLT_DEBUG_PROCESS
1967 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1968 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
1972 * Instantiate the xsl:template.
1974 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
1976 } else /* if (ctxt->mode == NULL) */ {
1977 #ifdef WITH_XSLT_DEBUG_PROCESS
1978 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1979 "xsltDefaultProcessOneNode: copy CDATA %s\n",
1982 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
1984 xsltTransformError(ctxt
, NULL
, cur
,
1985 "xsltDefaultProcessOneNode: cdata copy failed\n");
1990 template = xsltGetTemplate(ctxt
, cur
, NULL
);
1992 #ifdef WITH_XSLT_DEBUG_PROCESS
1993 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1994 "xsltDefaultProcessOneNode: applying template for text %s\n",
1997 ctxt
->xpathCtxt
->contextSize
= nbchild
;
1998 ctxt
->xpathCtxt
->proximityPosition
= childno
;
2000 * Instantiate the xsl:template.
2002 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
2004 } else /* if (ctxt->mode == NULL) */ {
2005 #ifdef WITH_XSLT_DEBUG_PROCESS
2006 if (cur
->content
== NULL
) {
2007 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2008 "xsltDefaultProcessOneNode: copy empty text\n"));
2010 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2011 "xsltDefaultProcessOneNode: copy text %s\n",
2015 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
2017 xsltTransformError(ctxt
, NULL
, cur
,
2018 "xsltDefaultProcessOneNode: text copy failed\n");
2023 case XML_COMMENT_NODE
:
2024 template = xsltGetTemplate(ctxt
, cur
, NULL
);
2026 #ifdef WITH_XSLT_DEBUG_PROCESS
2027 if (cur
->type
== XML_PI_NODE
) {
2028 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2029 "xsltDefaultProcessOneNode: template found for PI %s\n",
2031 } else if (cur
->type
== XML_COMMENT_NODE
) {
2032 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2033 "xsltDefaultProcessOneNode: template found for comment\n"));
2036 ctxt
->xpathCtxt
->contextSize
= nbchild
;
2037 ctxt
->xpathCtxt
->proximityPosition
= childno
;
2039 * Instantiate the xsl:template.
2041 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
2050 ctxt
->xpathCtxt
->contextSize
= oldSize
;
2051 ctxt
->xpathCtxt
->proximityPosition
= oldPos
;
2055 * xsltProcessOneNode:
2056 * @ctxt: a XSLT process context
2057 * @contextNode: the "current node" in the source tree
2058 * @withParams: extra parameters (e.g. xsl:with-param) passed to the
2061 * Process the source node.
2064 xsltProcessOneNode(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
2065 xsltStackElemPtr withParams
)
2067 xsltTemplatePtr templ
;
2070 templ
= xsltGetTemplate(ctxt
, contextNode
, NULL
);
2072 * If no template is found, apply the default rule.
2074 if (templ
== NULL
) {
2075 #ifdef WITH_XSLT_DEBUG_PROCESS
2076 if (contextNode
->type
== XML_DOCUMENT_NODE
) {
2077 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2078 "xsltProcessOneNode: no template found for /\n"));
2079 } else if (contextNode
->type
== XML_CDATA_SECTION_NODE
) {
2080 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2081 "xsltProcessOneNode: no template found for CDATA\n"));
2082 } else if (contextNode
->type
== XML_ATTRIBUTE_NODE
) {
2083 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2084 "xsltProcessOneNode: no template found for attribute %s\n",
2085 ((xmlAttrPtr
) contextNode
)->name
));
2087 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2088 "xsltProcessOneNode: no template found for %s\n", contextNode
->name
));
2091 oldNode
= ctxt
->node
;
2092 ctxt
->node
= contextNode
;
2093 xsltDefaultProcessOneNode(ctxt
, contextNode
, withParams
);
2094 ctxt
->node
= oldNode
;
2098 if (contextNode
->type
== XML_ATTRIBUTE_NODE
) {
2099 xsltTemplatePtr oldCurTempRule
= ctxt
->currentTemplateRule
;
2101 * Set the "current template rule".
2103 ctxt
->currentTemplateRule
= templ
;
2105 #ifdef WITH_XSLT_DEBUG_PROCESS
2106 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2107 "xsltProcessOneNode: applying template '%s' for attribute %s\n",
2108 templ
->match
, contextNode
->name
));
2110 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
, templ
, withParams
);
2112 ctxt
->currentTemplateRule
= oldCurTempRule
;
2114 xsltTemplatePtr oldCurTempRule
= ctxt
->currentTemplateRule
;
2116 * Set the "current template rule".
2118 ctxt
->currentTemplateRule
= templ
;
2120 #ifdef WITH_XSLT_DEBUG_PROCESS
2121 if (contextNode
->type
== XML_DOCUMENT_NODE
) {
2122 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2123 "xsltProcessOneNode: applying template '%s' for /\n",
2126 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2127 "xsltProcessOneNode: applying template '%s' for %s\n",
2128 templ
->match
, contextNode
->name
));
2131 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
, templ
, withParams
);
2133 ctxt
->currentTemplateRule
= oldCurTempRule
;
2137 #ifdef WITH_DEBUGGER
2139 xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt
,
2140 xmlNodePtr contextNode
,
2142 xsltTemplatePtr templ
,
2145 xmlNodePtr debugedNode
= NULL
;
2147 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2149 *addCallResult
= xslAddCall(templ
, templ
->elem
);
2151 *addCallResult
= xslAddCall(NULL
, list
);
2153 switch (ctxt
->debugStatus
) {
2154 case XSLT_DEBUG_RUN_RESTART
:
2155 case XSLT_DEBUG_QUIT
:
2161 xslHandleDebugger(templ
->elem
, contextNode
, templ
, ctxt
);
2162 debugedNode
= templ
->elem
;
2164 xslHandleDebugger(list
, contextNode
, templ
, ctxt
);
2166 } else if (ctxt
->inst
) {
2167 xslHandleDebugger(ctxt
->inst
, contextNode
, templ
, ctxt
);
2168 debugedNode
= ctxt
->inst
;
2171 return(debugedNode
);
2173 #endif /* WITH_DEBUGGER */
2176 * xsltLocalVariablePush:
2177 * @ctxt: the transformation context
2178 * @variable: variable to be pushed to the variable stack
2179 * @level: new value for variable's level
2181 * Places the variable onto the local variable stack
2183 * Returns: 0 for success, -1 for any error
2185 * This is an internal routine and should not be called by users!
2188 xsltLocalVariablePush(xsltTransformContextPtr ctxt
,
2189 xsltStackElemPtr variable
,
2192 if (ctxt
->varsMax
== 0) {
2195 (xsltStackElemPtr
*) xmlMalloc(ctxt
->varsMax
*
2196 sizeof(ctxt
->varsTab
[0]));
2197 if (ctxt
->varsTab
== NULL
) {
2198 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
2202 if (ctxt
->varsNr
>= ctxt
->varsMax
) {
2205 (xsltStackElemPtr
*) xmlRealloc(ctxt
->varsTab
,
2207 sizeof(ctxt
->varsTab
[0]));
2208 if (ctxt
->varsTab
== NULL
) {
2209 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
2213 ctxt
->varsTab
[ctxt
->varsNr
++] = variable
;
2214 ctxt
->vars
= variable
;
2215 variable
->level
= level
;
2220 * xsltReleaseLocalRVTs:
2222 * Fragments which are results of extension instructions
2223 * are preserved; all other fragments are freed/cached.
2226 xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt
, xmlDocPtr base
)
2228 xmlDocPtr cur
= ctxt
->localRVT
, tmp
;
2232 if (cur
->prev
!= NULL
)
2233 xsltTransformError(ctxt
, NULL
, NULL
, "localRVT not head of list\n");
2235 /* Reset localRVT early because some RVTs might be registered again. */
2236 ctxt
->localRVT
= base
;
2242 cur
= (xmlDocPtr
) cur
->next
;
2243 if (tmp
->psvi
== XSLT_RVT_LOCAL
) {
2244 xsltReleaseRVT(ctxt
, tmp
);
2245 } else if (tmp
->psvi
== XSLT_RVT_GLOBAL
) {
2246 xsltRegisterPersistRVT(ctxt
, tmp
);
2247 } else if (tmp
->psvi
== XSLT_RVT_FUNC_RESULT
) {
2249 * This will either register the RVT again or move it to the
2252 xsltRegisterLocalRVT(ctxt
, tmp
);
2253 tmp
->psvi
= XSLT_RVT_FUNC_RESULT
;
2255 xmlGenericError(xmlGenericErrorContext
,
2256 "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
2259 } while (cur
!= base
);
2263 * xsltApplySequenceConstructor:
2264 * @ctxt: a XSLT process context
2265 * @contextNode: the "current node" in the source tree
2266 * @list: the nodes of a sequence constructor;
2267 * (plus leading xsl:param elements)
2268 * @templ: the compiled xsl:template (optional)
2270 * Processes a sequence constructor.
2272 * NOTE: ctxt->currentTemplateRule was introduced to reflect the
2273 * semantics of "current template rule". I.e. the field ctxt->templ
2274 * is not intended to reflect this, thus always pushed onto the
2278 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt
,
2279 xmlNodePtr contextNode
, xmlNodePtr list
,
2280 xsltTemplatePtr templ
)
2282 xmlNodePtr oldInsert
, oldInst
, oldCurInst
, oldContextNode
;
2283 xmlNodePtr cur
, insert
, copy
= NULL
;
2284 int level
= 0, oldVarsNr
;
2285 xmlDocPtr oldLocalFragmentTop
;
2287 #ifdef XSLT_REFACTORED
2288 xsltStylePreCompPtr info
;
2291 #ifdef WITH_DEBUGGER
2292 int addCallResult
= 0;
2293 xmlNodePtr debuggedNode
= NULL
;
2299 #ifdef WITH_DEBUGGER
2300 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2302 xsltDebuggerStartSequenceConstructor(ctxt
, contextNode
,
2303 list
, templ
, &addCallResult
);
2304 if (debuggedNode
== NULL
)
2314 * Check for infinite recursion: stop if the maximum of nested templates
2315 * is excceeded. Adjust xsltMaxDepth if you need more.
2317 if (ctxt
->depth
>= ctxt
->maxTemplateDepth
) {
2318 xsltTransformError(ctxt
, NULL
, list
,
2319 "xsltApplySequenceConstructor: A potential infinite template "
2320 "recursion was detected.\n"
2321 "You can adjust xsltMaxDepth (--maxdepth) in order to "
2322 "raise the maximum number of nested template calls and "
2323 "variables/params (currently set to %d).\n",
2324 ctxt
->maxTemplateDepth
);
2325 xsltDebug(ctxt
, contextNode
, list
, NULL
);
2326 ctxt
->state
= XSLT_STATE_STOPPED
;
2331 oldLocalFragmentTop
= ctxt
->localRVT
;
2332 oldInsert
= insert
= ctxt
->insert
;
2333 oldInst
= oldCurInst
= ctxt
->inst
;
2334 oldContextNode
= ctxt
->node
;
2336 * Save current number of variables on the stack; new vars are popped when
2339 oldVarsNr
= ctxt
->varsNr
;
2341 * Process the sequence constructor.
2344 while (cur
!= NULL
) {
2345 if (ctxt
->opLimit
!= 0) {
2346 if (ctxt
->opCount
>= ctxt
->opLimit
) {
2347 xsltTransformError(ctxt
, NULL
, cur
,
2348 "xsltApplySequenceConstructor: "
2349 "Operation limit exceeded\n");
2350 ctxt
->state
= XSLT_STATE_STOPPED
;
2358 #ifdef WITH_DEBUGGER
2359 switch (ctxt
->debugStatus
) {
2360 case XSLT_DEBUG_RUN_RESTART
:
2361 case XSLT_DEBUG_QUIT
:
2367 * Test; we must have a valid insertion point.
2369 if (insert
== NULL
) {
2371 #ifdef WITH_XSLT_DEBUG_PROCESS
2372 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2373 "xsltApplySequenceConstructor: insert == NULL !\n"));
2378 #ifdef WITH_DEBUGGER
2379 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (debuggedNode
!= cur
))
2380 xslHandleDebugger(cur
, contextNode
, templ
, ctxt
);
2383 #ifdef XSLT_REFACTORED
2384 if (cur
->type
== XML_ELEMENT_NODE
) {
2385 info
= (xsltStylePreCompPtr
) cur
->psvi
;
2387 * We expect a compiled representation on:
2388 * 1) XSLT instructions of this XSLT version (1.0)
2389 * (with a few exceptions)
2390 * 2) Literal result elements
2391 * 3) Extension instructions
2392 * 4) XSLT instructions of future XSLT versions
2393 * (forwards-compatible mode).
2397 * Handle the rare cases where we don't expect a compiled
2398 * representation on an XSLT element.
2400 if (IS_XSLT_ELEM_FAST(cur
) && IS_XSLT_NAME(cur
, "message")) {
2401 xsltMessage(ctxt
, contextNode
, cur
);
2405 * Something really went wrong:
2407 xsltTransformError(ctxt
, NULL
, cur
,
2408 "Internal error in xsltApplySequenceConstructor(): "
2409 "The element '%s' in the stylesheet has no compiled "
2410 "representation.\n",
2415 if (info
->type
== XSLT_FUNC_LITERAL_RESULT_ELEMENT
) {
2416 xsltStyleItemLRElementInfoPtr lrInfo
=
2417 (xsltStyleItemLRElementInfoPtr
) info
;
2419 * Literal result elements
2420 * --------------------------------------------------------
2422 #ifdef WITH_XSLT_DEBUG_PROCESS
2423 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2424 xsltGenericDebug(xsltGenericDebugContext
,
2425 "xsltApplySequenceConstructor: copy literal result "
2426 "element '%s'\n", cur
->name
));
2429 * Copy the raw element-node.
2430 * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2434 copy
= xmlDocCopyNode(cur
, insert
->doc
, 0);
2436 xsltTransformError(ctxt
, NULL
, cur
,
2437 "Internal error in xsltApplySequenceConstructor(): "
2438 "Failed to copy literal result element '%s'.\n",
2443 * Add the element-node to the result tree.
2445 copy
->doc
= ctxt
->output
;
2446 copy
= xsltAddChild(insert
, copy
);
2448 * Create effective namespaces declarations.
2449 * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2451 if (lrInfo
->effectiveNs
!= NULL
) {
2452 xsltEffectiveNsPtr effNs
= lrInfo
->effectiveNs
;
2453 xmlNsPtr ns
, lastns
= NULL
;
2455 while (effNs
!= NULL
) {
2457 * Avoid generating redundant namespace
2458 * declarations; thus lookup if there is already
2459 * such a ns-decl in the result.
2461 ns
= xmlSearchNs(copy
->doc
, copy
, effNs
->prefix
);
2463 (xmlStrEqual(ns
->href
, effNs
->nsName
)))
2465 effNs
= effNs
->next
;
2468 ns
= xmlNewNs(copy
, effNs
->nsName
, effNs
->prefix
);
2470 xsltTransformError(ctxt
, NULL
, cur
,
2471 "Internal error in "
2472 "xsltApplySequenceConstructor(): "
2473 "Failed to copy a namespace "
2484 effNs
= effNs
->next
;
2489 * NOTE that we don't need to apply ns-alising: this was
2490 * already done at compile-time.
2492 if (cur
->ns
!= NULL
) {
2494 * If there's no such ns-decl in the result tree,
2495 * then xsltGetSpecialNamespace() will
2496 * create a ns-decl on the copied node.
2498 copy
->ns
= xsltGetSpecialNamespace(ctxt
, cur
,
2499 cur
->ns
->href
, cur
->ns
->prefix
, copy
);
2502 * Undeclare the default namespace if needed.
2503 * This can be skipped, if the result element has
2504 * no ns-decls, in which case the result element
2505 * obviously does not declare a default namespace;
2506 * AND there's either no parent, or the parent
2507 * element is in no namespace; this means there's no
2508 * default namespace is scope to care about.
2510 * REVISIT: This might result in massive
2511 * generation of ns-decls if nodes in a default
2512 * namespaces are mixed with nodes in no namespace.
2516 ((insert
!= NULL
) &&
2517 (insert
->type
== XML_ELEMENT_NODE
) &&
2518 (insert
->ns
!= NULL
)))
2520 xsltGetSpecialNamespace(ctxt
, cur
,
2526 * SPEC XSLT 2.0 "Each attribute of the literal result
2527 * element, other than an attribute in the XSLT namespace,
2528 * is processed to produce an attribute for the element in
2530 * NOTE: See bug #341325.
2532 if (cur
->properties
!= NULL
) {
2533 xsltAttrListTemplateProcess(ctxt
, copy
, cur
->properties
);
2535 } else if (IS_XSLT_ELEM_FAST(cur
)) {
2538 * --------------------------------------------------------
2540 if (info
->type
== XSLT_FUNC_UNKOWN_FORWARDS_COMPAT
) {
2542 * We hit an unknown XSLT element.
2543 * Try to apply one of the fallback cases.
2545 ctxt
->insert
= insert
;
2546 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2547 xsltTransformError(ctxt
, NULL
, cur
,
2548 "The is no fallback behaviour defined for "
2549 "the unknown XSLT element '%s'.\n",
2552 ctxt
->insert
= oldInsert
;
2553 } else if (info
->func
!= NULL
) {
2555 * Execute the XSLT instruction.
2557 ctxt
->insert
= insert
;
2559 info
->func(ctxt
, contextNode
, cur
,
2560 (xsltElemPreCompPtr
) info
);
2563 * Cleanup temporary tree fragments.
2565 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2566 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2568 ctxt
->insert
= oldInsert
;
2569 } else if (info
->type
== XSLT_FUNC_VARIABLE
) {
2570 xsltStackElemPtr tmpvar
= ctxt
->vars
;
2572 xsltParseStylesheetVariable(ctxt
, cur
);
2574 if (tmpvar
!= ctxt
->vars
) {
2576 * TODO: Using a @tmpvar is an annoying workaround, but
2577 * the current mechanisms do not provide any other way
2578 * of knowing if the var was really pushed onto the
2581 ctxt
->vars
->level
= level
;
2583 } else if (info
->type
== XSLT_FUNC_MESSAGE
) {
2585 * TODO: Won't be hit, since we don't compile xsl:message.
2587 xsltMessage(ctxt
, contextNode
, cur
);
2589 xsltTransformError(ctxt
, NULL
, cur
,
2590 "Unexpected XSLT element '%s'.\n", cur
->name
);
2595 xsltTransformFunction func
;
2597 * Extension intructions (elements)
2598 * --------------------------------------------------------
2600 if (cur
->psvi
== xsltExtMarker
) {
2602 * The xsltExtMarker was set during the compilation
2603 * of extension instructions if there was no registered
2604 * handler for this specific extension function at
2606 * Libxslt will now lookup if a handler is
2607 * registered in the context of this transformation.
2609 func
= xsltExtElementLookup(ctxt
, cur
->name
,
2612 func
= ((xsltElemPreCompPtr
) cur
->psvi
)->func
;
2616 * No handler available.
2617 * Try to execute fallback behaviour via xsl:fallback.
2619 #ifdef WITH_XSLT_DEBUG_PROCESS
2620 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2621 xsltGenericDebug(xsltGenericDebugContext
,
2622 "xsltApplySequenceConstructor: unknown extension %s\n",
2625 ctxt
->insert
= insert
;
2626 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2627 xsltTransformError(ctxt
, NULL
, cur
,
2628 "Unknown extension instruction '{%s}%s'.\n",
2629 cur
->ns
->href
, cur
->name
);
2631 ctxt
->insert
= oldInsert
;
2634 * Execute the handler-callback.
2636 #ifdef WITH_XSLT_DEBUG_PROCESS
2637 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2638 "xsltApplySequenceConstructor: extension construct %s\n",
2642 * Disable the xsltCopyTextString optimization for
2643 * extension elements. Extensions could append text using
2644 * xmlAddChild which will free the buffer pointed to by
2645 * 'lasttext'. This buffer could later be reallocated with
2646 * a different size than recorded in 'lasttsize'. See bug
2649 if (cur
->psvi
== xsltExtMarker
) {
2650 ctxt
->lasttext
= NULL
;
2653 ctxt
->insert
= insert
;
2655 func(ctxt
, contextNode
, cur
, cur
->psvi
);
2658 * Cleanup temporary tree fragments.
2660 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2661 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2663 ctxt
->insert
= oldInsert
;
2668 } else if (XSLT_IS_TEXT_NODE(cur
)) {
2671 * ------------------------------------------------------------
2673 #ifdef WITH_XSLT_DEBUG_PROCESS
2674 if (cur
->name
== xmlStringTextNoenc
) {
2675 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2676 xsltGenericDebug(xsltGenericDebugContext
,
2677 "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2680 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2681 xsltGenericDebug(xsltGenericDebugContext
,
2682 "xsltApplySequenceConstructor: copy text '%s'\n",
2686 if (xsltCopyText(ctxt
, insert
, cur
, ctxt
->internalized
) == NULL
)
2690 #else /* XSLT_REFACTORED */
2692 if (IS_XSLT_ELEM(cur
)) {
2694 * This is an XSLT node
2696 xsltStylePreCompPtr info
= (xsltStylePreCompPtr
) cur
->psvi
;
2699 if (IS_XSLT_NAME(cur
, "message")) {
2700 xsltMessage(ctxt
, contextNode
, cur
);
2703 * That's an error try to apply one of the fallback cases
2705 ctxt
->insert
= insert
;
2706 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2707 xsltGenericError(xsltGenericErrorContext
,
2708 "xsltApplySequenceConstructor: %s was not compiled\n",
2711 ctxt
->insert
= oldInsert
;
2716 if (info
->func
!= NULL
) {
2717 oldCurInst
= ctxt
->inst
;
2719 ctxt
->insert
= insert
;
2721 info
->func(ctxt
, contextNode
, cur
, (xsltElemPreCompPtr
) info
);
2724 * Cleanup temporary tree fragments.
2726 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2727 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2729 ctxt
->insert
= oldInsert
;
2730 ctxt
->inst
= oldCurInst
;
2734 if (IS_XSLT_NAME(cur
, "variable")) {
2735 xsltStackElemPtr tmpvar
= ctxt
->vars
;
2737 oldCurInst
= ctxt
->inst
;
2740 xsltParseStylesheetVariable(ctxt
, cur
);
2742 ctxt
->inst
= oldCurInst
;
2744 if (tmpvar
!= ctxt
->vars
) {
2746 * TODO: Using a @tmpvar is an annoying workaround, but
2747 * the current mechanisms do not provide any other way
2748 * of knowing if the var was really pushed onto the
2751 ctxt
->vars
->level
= level
;
2753 } else if (IS_XSLT_NAME(cur
, "message")) {
2754 xsltMessage(ctxt
, contextNode
, cur
);
2756 xsltTransformError(ctxt
, NULL
, cur
,
2757 "Unexpected XSLT element '%s'.\n", cur
->name
);
2760 } else if ((cur
->type
== XML_TEXT_NODE
) ||
2761 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
2764 * This text comes from the stylesheet
2765 * For stylesheets, the set of whitespace-preserving
2766 * element names consists of just xsl:text.
2768 #ifdef WITH_XSLT_DEBUG_PROCESS
2769 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
2770 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2771 "xsltApplySequenceConstructor: copy CDATA text %s\n",
2773 } else if (cur
->name
== xmlStringTextNoenc
) {
2774 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2775 "xsltApplySequenceConstructor: copy unescaped text %s\n",
2778 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2779 "xsltApplySequenceConstructor: copy text %s\n",
2783 if (xsltCopyText(ctxt
, insert
, cur
, ctxt
->internalized
) == NULL
)
2785 } else if ((cur
->type
== XML_ELEMENT_NODE
) &&
2786 (cur
->ns
!= NULL
) && (cur
->psvi
!= NULL
)) {
2787 xsltTransformFunction function
;
2789 oldCurInst
= ctxt
->inst
;
2792 * Flagged as an extension element
2794 if (cur
->psvi
== xsltExtMarker
)
2795 function
= xsltExtElementLookup(ctxt
, cur
->name
,
2798 function
= ((xsltElemPreCompPtr
) cur
->psvi
)->func
;
2800 if (function
== NULL
) {
2804 #ifdef WITH_XSLT_DEBUG_PROCESS
2805 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2806 "xsltApplySequenceConstructor: unknown extension %s\n",
2810 * Search if there are fallbacks
2812 ctxt
->insert
= insert
;
2813 child
= cur
->children
;
2814 while (child
!= NULL
) {
2815 if ((IS_XSLT_ELEM(child
)) &&
2816 (IS_XSLT_NAME(child
, "fallback")))
2819 xsltApplySequenceConstructor(ctxt
, contextNode
,
2820 child
->children
, NULL
);
2822 child
= child
->next
;
2824 ctxt
->insert
= oldInsert
;
2827 xsltTransformError(ctxt
, NULL
, cur
,
2828 "xsltApplySequenceConstructor: failed to find extension %s\n",
2832 #ifdef WITH_XSLT_DEBUG_PROCESS
2833 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2834 "xsltApplySequenceConstructor: extension construct %s\n",
2839 * Disable the xsltCopyTextString optimization for
2840 * extension elements. Extensions could append text using
2841 * xmlAddChild which will free the buffer pointed to by
2842 * 'lasttext'. This buffer could later be reallocated with
2843 * a different size than recorded in 'lasttsize'. See bug
2846 if (cur
->psvi
== xsltExtMarker
) {
2847 ctxt
->lasttext
= NULL
;
2850 ctxt
->insert
= insert
;
2852 function(ctxt
, contextNode
, cur
, cur
->psvi
);
2854 * Cleanup temporary tree fragments.
2856 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2857 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2859 ctxt
->insert
= oldInsert
;
2862 ctxt
->inst
= oldCurInst
;
2864 } else if (cur
->type
== XML_ELEMENT_NODE
) {
2865 #ifdef WITH_XSLT_DEBUG_PROCESS
2866 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2867 "xsltApplySequenceConstructor: copy node %s\n",
2870 oldCurInst
= ctxt
->inst
;
2873 if ((copy
= xsltShallowCopyElem(ctxt
, cur
, insert
, 1)) == NULL
)
2876 * Add extra namespaces inherited from the current template
2877 * if we are in the first level children and this is a
2880 if ((templ
!= NULL
) && (oldInsert
== insert
) &&
2881 (ctxt
->templ
!= NULL
) && (ctxt
->templ
->inheritedNs
!= NULL
)) {
2885 for (i
= 0; i
< ctxt
->templ
->inheritedNsNr
; i
++) {
2886 const xmlChar
*URI
= NULL
;
2887 xsltStylesheetPtr style
;
2888 ns
= ctxt
->templ
->inheritedNs
[i
];
2890 /* Note that the XSLT namespace was already excluded
2891 * in xsltGetInheritedNsList().
2894 if (xmlStrEqual(ns
->href
, XSLT_NAMESPACE
))
2897 style
= ctxt
->style
;
2898 while (style
!= NULL
) {
2899 if (style
->nsAliases
!= NULL
)
2900 URI
= (const xmlChar
*)
2901 xmlHashLookup(style
->nsAliases
, ns
->href
);
2905 style
= xsltNextImport(style
);
2907 if (URI
== UNDEFINED_DEFAULT_NS
)
2912 * TODO: The following will still be buggy for the
2913 * non-refactored code.
2915 ret
= xmlSearchNs(copy
->doc
, copy
, ns
->prefix
);
2916 if ((ret
== NULL
) || (!xmlStrEqual(ret
->href
, URI
)))
2918 xmlNewNs(copy
, URI
, ns
->prefix
);
2921 if (copy
->ns
!= NULL
) {
2923 * Fix the node namespace if needed
2925 copy
->ns
= xsltGetNamespace(ctxt
, cur
, copy
->ns
, copy
);
2929 * all the attributes are directly inherited
2931 if (cur
->properties
!= NULL
) {
2932 xsltAttrListTemplateProcess(ctxt
, copy
, cur
->properties
);
2934 ctxt
->inst
= oldCurInst
;
2936 #endif /* else of XSLT_REFACTORED */
2939 * Descend into content in document order.
2941 if (cur
->children
!= NULL
) {
2942 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
2943 cur
= cur
->children
;
2953 * If xslt:message was just processed, we might have hit a
2954 * terminate='yes'; if so, then break the loop and clean up.
2955 * TODO: Do we need to check this also before trying to descend
2958 if (ctxt
->state
== XSLT_STATE_STOPPED
)
2960 if (cur
->next
!= NULL
) {
2969 * Pop variables/params (xsl:variable and xsl:param).
2971 if ((ctxt
->varsNr
> oldVarsNr
) && (ctxt
->vars
->level
> level
)) {
2972 xsltLocalVariablePop(ctxt
, oldVarsNr
, level
);
2975 insert
= insert
->parent
;
2978 if (cur
== list
->parent
) {
2982 if (cur
->next
!= NULL
) {
2986 } while (cur
!= NULL
);
2991 * In case of errors: pop remaining variables.
2993 if (ctxt
->varsNr
> oldVarsNr
)
2994 xsltLocalVariablePop(ctxt
, oldVarsNr
, -1);
2996 ctxt
->node
= oldContextNode
;
2997 ctxt
->inst
= oldInst
;
2998 ctxt
->insert
= oldInsert
;
3002 #ifdef WITH_DEBUGGER
3003 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (addCallResult
)) {
3010 * xsltApplyXSLTTemplate:
3011 * @ctxt: a XSLT transformation context
3012 * @contextNode: the node in the source tree.
3013 * @list: the nodes of a sequence constructor;
3014 * (plus leading xsl:param elements)
3015 * @templ: the compiled xsl:template declaration;
3016 * NULL if a sequence constructor
3017 * @withParams: a set of caller-parameters (xsl:with-param) or NULL
3020 * - xsltApplyImports()
3021 * - xsltCallTemplate()
3022 * - xsltDefaultProcessOneNode()
3023 * - xsltProcessOneNode()
3026 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt
,
3027 xmlNodePtr contextNode
,
3029 xsltTemplatePtr templ
,
3030 xsltStackElemPtr withParams
)
3032 int oldVarsBase
= 0;
3034 xsltStackElemPtr tmpParam
= NULL
;
3035 xmlDocPtr oldUserFragmentTop
;
3036 #ifdef WITH_PROFILER
3040 #ifdef XSLT_REFACTORED
3041 xsltStyleItemParamPtr iparam
;
3043 xsltStylePreCompPtr iparam
;
3046 #ifdef WITH_DEBUGGER
3047 int addCallResult
= 0;
3052 if (templ
== NULL
) {
3053 xsltTransformError(ctxt
, NULL
, list
,
3054 "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
3058 #ifdef WITH_DEBUGGER
3059 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
3060 if (xsltDebuggerStartSequenceConstructor(ctxt
, contextNode
,
3061 list
, templ
, &addCallResult
) == NULL
)
3070 if (ctxt
->varsNr
>= ctxt
->maxTemplateVars
)
3072 xsltTransformError(ctxt
, NULL
, list
,
3073 "xsltApplyXSLTTemplate: A potential infinite template recursion "
3075 "You can adjust maxTemplateVars (--maxvars) in order to "
3076 "raise the maximum number of variables/params (currently set to %d).\n",
3077 ctxt
->maxTemplateVars
);
3078 xsltDebug(ctxt
, contextNode
, list
, NULL
);
3079 ctxt
->state
= XSLT_STATE_STOPPED
;
3083 oldUserFragmentTop
= ctxt
->tmpRVT
;
3084 ctxt
->tmpRVT
= NULL
;
3087 * Initiate a distinct scope of local params/variables.
3089 oldVarsBase
= ctxt
->varsBase
;
3090 ctxt
->varsBase
= ctxt
->varsNr
;
3092 ctxt
->node
= contextNode
;
3094 #ifdef WITH_PROFILER
3095 if (ctxt
->profile
) {
3097 start
= xsltTimestamp();
3099 profCallgraphAdd(templ
, ctxt
->templ
);
3104 * Push the xsl:template declaration onto the stack.
3106 templPush(ctxt
, templ
);
3108 #ifdef WITH_XSLT_DEBUG_PROCESS
3109 if (templ
->name
!= NULL
)
3110 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
3111 "applying xsl:template '%s'\n", templ
->name
));
3114 * Process xsl:param instructions and skip those elements for
3115 * further processing.
3119 if (cur
->type
== XML_TEXT_NODE
) {
3123 if ((cur
->type
!= XML_ELEMENT_NODE
) ||
3124 (cur
->name
[0] != 'p') ||
3125 (cur
->psvi
== NULL
) ||
3126 (! xmlStrEqual(cur
->name
, BAD_CAST
"param")) ||
3127 (! IS_XSLT_ELEM(cur
)))
3134 #ifdef XSLT_REFACTORED
3135 iparam
= (xsltStyleItemParamPtr
) cur
->psvi
;
3137 iparam
= (xsltStylePreCompPtr
) cur
->psvi
;
3141 * Substitute xsl:param for a given xsl:with-param.
3142 * Since the XPath expression will reference the params/vars
3143 * by index, we need to slot the xsl:with-params in the
3144 * order of encountered xsl:params to keep the sequence of
3145 * params/variables in the stack exactly as it was at
3150 tmpParam
= withParams
;
3152 if ((tmpParam
->name
== (iparam
->name
)) &&
3153 (tmpParam
->nameURI
== (iparam
->ns
)))
3156 * Push the caller-parameter.
3158 xsltLocalVariablePush(ctxt
, tmpParam
, -1);
3161 tmpParam
= tmpParam
->next
;
3162 } while (tmpParam
!= NULL
);
3165 * Push the xsl:param.
3167 if (tmpParam
== NULL
) {
3169 * Note that we must assume that the added parameter
3170 * has a @depth of 0.
3172 xsltParseStylesheetParam(ctxt
, cur
);
3175 } while (cur
!= NULL
);
3177 * Process the sequence constructor.
3179 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3182 * Remove remaining xsl:param and xsl:with-param items from
3183 * the stack. Don't free xsl:with-param items.
3185 if (ctxt
->varsNr
> ctxt
->varsBase
)
3186 xsltTemplateParamsCleanup(ctxt
);
3187 ctxt
->varsBase
= oldVarsBase
;
3190 * Release user-created fragments stored in the scope
3191 * of xsl:template. Note that this mechanism is deprecated:
3192 * user code should now use xsltRegisterLocalRVT() instead
3193 * of the obsolete xsltRegisterTmpRVT().
3196 xmlDocPtr curdoc
= ctxt
->tmpRVT
, tmp
;
3198 while (curdoc
!= NULL
) {
3200 curdoc
= (xmlDocPtr
) curdoc
->next
;
3201 xsltReleaseRVT(ctxt
, tmp
);
3204 ctxt
->tmpRVT
= oldUserFragmentTop
;
3207 * Pop the xsl:template declaration from the stack.
3211 #ifdef WITH_PROFILER
3212 if (ctxt
->profile
) {
3213 long spent
, child
, total
, end
;
3215 end
= xsltTimestamp();
3216 child
= profPop(ctxt
);
3217 total
= end
- start
;
3218 spent
= total
- child
;
3221 * Not possible unless the original calibration failed
3222 * we can try to correct it on the fly.
3224 xsltCalibrateAdjust(spent
);
3228 templ
->time
+= spent
;
3229 if (ctxt
->profNr
> 0)
3230 ctxt
->profTab
[ctxt
->profNr
- 1] += total
;
3234 #ifdef WITH_DEBUGGER
3235 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (addCallResult
)) {
3243 * xsltApplyOneTemplate:
3244 * @ctxt: a XSLT process context
3245 * @contextNode: the node in the source tree.
3246 * @list: the nodes of a sequence constructor
3248 * @params: a set of parameters (xsl:param) or NULL
3250 * Processes a sequence constructor on the current node in the source tree.
3252 * @params are the already computed variable stack items; this function
3253 * pushes them on the variable stack, and pops them before exiting; it's
3254 * left to the caller to free or reuse @params afterwards. The initial
3255 * states of the variable stack will always be restored before this
3257 * NOTE that this does *not* initiate a new distinct variable scope; i.e.
3258 * variables already on the stack are visible to the process. The caller's
3259 * side needs to start a new variable scope if needed (e.g. in exsl:function).
3261 * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
3262 * provide a @templ); a non-NULL @templ might raise an error in the future.
3264 * BIG NOTE: This function is not intended to process the content of an
3265 * xsl:template; it does not expect xsl:param instructions in @list and
3266 * will report errors if found.
3269 * - xsltEvalVariable() (variables.c)
3270 * - exsltFuncFunctionFunction() (libexsl/functions.c)
3273 xsltApplyOneTemplate(xsltTransformContextPtr ctxt
,
3274 xmlNodePtr contextNode
,
3276 xsltTemplatePtr templ ATTRIBUTE_UNUSED
,
3277 xsltStackElemPtr params
)
3279 if ((ctxt
== NULL
) || (list
== NULL
))
3285 * This code should be obsolete - was previously used
3286 * by libexslt/functions.c, but due to bug 381319 the
3287 * logic there was changed.
3289 int oldVarsNr
= ctxt
->varsNr
;
3292 * Push the given xsl:param(s) onto the variable stack.
3294 while (params
!= NULL
) {
3295 xsltLocalVariablePush(ctxt
, params
, -1);
3296 params
= params
->next
;
3298 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3300 * Pop the given xsl:param(s) from the stack but don't free them.
3302 xsltLocalVariablePop(ctxt
, oldVarsNr
, -2);
3304 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3307 /************************************************************************
3309 * XSLT-1.1 extensions *
3311 ************************************************************************/
3315 * @ctxt: an XSLT processing context
3316 * @node: The current node
3317 * @inst: the instruction in the stylesheet
3318 * @castedComp: precomputed information
3320 * Process an EXSLT/XSLT-1.1 document element
3323 xsltDocumentElem(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3324 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
3326 #ifdef XSLT_REFACTORED
3327 xsltStyleItemDocumentPtr comp
= (xsltStyleItemDocumentPtr
) castedComp
;
3329 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
3331 xsltStylesheetPtr style
= NULL
;
3333 xmlChar
*filename
= NULL
, *prop
, *elements
;
3334 xmlChar
*element
, *end
;
3335 xmlDocPtr res
= NULL
;
3336 xmlDocPtr oldOutput
;
3337 xmlNodePtr oldInsert
, root
;
3338 const char *oldOutputFile
;
3339 xsltOutputType oldType
;
3340 xmlChar
*URL
= NULL
;
3341 const xmlChar
*method
;
3342 const xmlChar
*doctypePublic
;
3343 const xmlChar
*doctypeSystem
;
3344 const xmlChar
*version
;
3345 const xmlChar
*encoding
;
3346 int redirect_write_append
= 0;
3348 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
3351 if (comp
->filename
== NULL
) {
3353 if (xmlStrEqual(inst
->name
, (const xmlChar
*) "output")) {
3355 * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
3356 * (http://icl.com/saxon)
3357 * The @file is in no namespace.
3359 #ifdef WITH_XSLT_DEBUG_EXTRA
3360 xsltGenericDebug(xsltGenericDebugContext
,
3361 "Found saxon:output extension\n");
3363 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3364 (const xmlChar
*) "file",
3365 XSLT_SAXON_NAMESPACE
);
3368 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3369 (const xmlChar
*) "href",
3370 XSLT_SAXON_NAMESPACE
);
3371 } else if (xmlStrEqual(inst
->name
, (const xmlChar
*) "write")) {
3372 #ifdef WITH_XSLT_DEBUG_EXTRA
3373 xsltGenericDebug(xsltGenericDebugContext
,
3374 "Found xalan:write extension\n");
3376 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3379 XSLT_XALAN_NAMESPACE
);
3381 xmlXPathCompExprPtr cmp
;
3385 * Trying to handle bug #59212
3386 * The value of the "select" attribute is an
3388 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
3390 cmp
= xmlXPathCtxtCompile(ctxt
->xpathCtxt
, URL
);
3391 val
= xsltEvalXPathString(ctxt
, cmp
);
3392 xmlXPathFreeCompExpr(cmp
);
3397 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3400 XSLT_XALAN_NAMESPACE
);
3402 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3405 XSLT_XALAN_NAMESPACE
);
3406 } else if (xmlStrEqual(inst
->name
, (const xmlChar
*) "document")) {
3407 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3408 (const xmlChar
*) "href",
3413 URL
= xmlStrdup(comp
->filename
);
3417 xsltTransformError(ctxt
, NULL
, inst
,
3418 "xsltDocumentElem: href/URI-Reference not found\n");
3423 * If the computation failed, it's likely that the URL wasn't escaped
3425 filename
= xmlBuildURI(URL
, (const xmlChar
*) ctxt
->outputFile
);
3426 if (filename
== NULL
) {
3429 escURL
=xmlURIEscapeStr(URL
, BAD_CAST
":/.?,");
3430 if (escURL
!= NULL
) {
3431 filename
= xmlBuildURI(escURL
, (const xmlChar
*) ctxt
->outputFile
);
3436 if (filename
== NULL
) {
3437 xsltTransformError(ctxt
, NULL
, inst
,
3438 "xsltDocumentElem: URL computation failed for %s\n",
3445 * Security checking: can we write to this resource
3447 if (ctxt
->sec
!= NULL
) {
3448 ret
= xsltCheckWrite(ctxt
->sec
, ctxt
, filename
);
3451 xsltTransformError(ctxt
, NULL
, inst
,
3452 "xsltDocumentElem: write rights for %s denied\n",
3460 oldOutputFile
= ctxt
->outputFile
;
3461 oldOutput
= ctxt
->output
;
3462 oldInsert
= ctxt
->insert
;
3463 oldType
= ctxt
->type
;
3464 ctxt
->outputFile
= (const char *) filename
;
3466 style
= xsltNewStylesheet();
3467 if (style
== NULL
) {
3468 xsltTransformError(ctxt
, NULL
, inst
,
3469 "xsltDocumentElem: out of memory\n");
3474 * Version described in 1.1 draft allows full parameterization
3477 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3478 (const xmlChar
*) "version",
3481 if (style
->version
!= NULL
)
3482 xmlFree(style
->version
);
3483 style
->version
= prop
;
3485 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3486 (const xmlChar
*) "encoding",
3489 if (style
->encoding
!= NULL
)
3490 xmlFree(style
->encoding
);
3491 style
->encoding
= prop
;
3493 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3494 (const xmlChar
*) "method",
3499 if (style
->method
!= NULL
)
3500 xmlFree(style
->method
);
3501 style
->method
= NULL
;
3502 if (style
->methodURI
!= NULL
)
3503 xmlFree(style
->methodURI
);
3504 style
->methodURI
= NULL
;
3506 URI
= xsltGetQNameURI(inst
, &prop
);
3508 if (style
!= NULL
) style
->errors
++;
3509 } else if (URI
== NULL
) {
3510 if ((xmlStrEqual(prop
, (const xmlChar
*) "xml")) ||
3511 (xmlStrEqual(prop
, (const xmlChar
*) "html")) ||
3512 (xmlStrEqual(prop
, (const xmlChar
*) "text"))) {
3513 style
->method
= prop
;
3515 xsltTransformError(ctxt
, NULL
, inst
,
3516 "invalid value for method: %s\n", prop
);
3517 if (style
!= NULL
) style
->warnings
++;
3520 style
->method
= prop
;
3521 style
->methodURI
= xmlStrdup(URI
);
3524 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3526 "doctype-system", NULL
);
3528 if (style
->doctypeSystem
!= NULL
)
3529 xmlFree(style
->doctypeSystem
);
3530 style
->doctypeSystem
= prop
;
3532 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3534 "doctype-public", NULL
);
3536 if (style
->doctypePublic
!= NULL
)
3537 xmlFree(style
->doctypePublic
);
3538 style
->doctypePublic
= prop
;
3540 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3541 (const xmlChar
*) "standalone",
3544 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3545 style
->standalone
= 1;
3546 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3547 style
->standalone
= 0;
3549 xsltTransformError(ctxt
, NULL
, inst
,
3550 "invalid value for standalone: %s\n",
3552 if (style
!= NULL
) style
->warnings
++;
3557 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3558 (const xmlChar
*) "indent",
3561 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3563 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3566 xsltTransformError(ctxt
, NULL
, inst
,
3567 "invalid value for indent: %s\n", prop
);
3568 if (style
!= NULL
) style
->warnings
++;
3573 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3575 "omit-xml-declaration",
3578 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3579 style
->omitXmlDeclaration
= 1;
3580 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3581 style
->omitXmlDeclaration
= 0;
3583 xsltTransformError(ctxt
, NULL
, inst
,
3584 "invalid value for omit-xml-declaration: %s\n",
3586 if (style
!= NULL
) style
->warnings
++;
3591 elements
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3593 "cdata-section-elements",
3595 if (elements
!= NULL
) {
3596 if (style
->stripSpaces
== NULL
)
3597 style
->stripSpaces
= xmlHashCreate(10);
3598 if (style
->stripSpaces
== NULL
) {
3604 while (*element
!= 0) {
3605 while (xmlIsBlank_ch(*element
))
3610 while ((*end
!= 0) && (!xmlIsBlank_ch(*end
)))
3612 element
= xmlStrndup(element
, end
- element
);
3616 #ifdef WITH_XSLT_DEBUG_PARSING
3617 xsltGenericDebug(xsltGenericDebugContext
,
3618 "add cdata section output element %s\n",
3621 URI
= xsltGetQNameURI(inst
, &element
);
3623 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
3624 (xmlChar
*) "cdata");
3633 * Create a new document tree and process the element template
3635 XSLT_GET_IMPORT_PTR(method
, style
, method
)
3636 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
3637 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
3638 XSLT_GET_IMPORT_PTR(version
, style
, version
)
3639 XSLT_GET_IMPORT_PTR(encoding
, style
, encoding
)
3641 if ((method
!= NULL
) &&
3642 (!xmlStrEqual(method
, (const xmlChar
*) "xml"))) {
3643 if (xmlStrEqual(method
, (const xmlChar
*) "html")) {
3644 ctxt
->type
= XSLT_OUTPUT_HTML
;
3645 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3646 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
3648 if (version
!= NULL
) {
3649 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3650 xsltGetHTMLIDs(version
, &doctypePublic
, &doctypeSystem
);
3653 res
= htmlNewDocNoDtD(doctypeSystem
, doctypePublic
);
3657 res
->dict
= ctxt
->dict
;
3658 xmlDictReference(res
->dict
);
3659 } else if (xmlStrEqual(method
, (const xmlChar
*) "xhtml")) {
3660 xsltTransformError(ctxt
, NULL
, inst
,
3661 "xsltDocumentElem: unsupported method xhtml\n");
3662 ctxt
->type
= XSLT_OUTPUT_HTML
;
3663 res
= htmlNewDocNoDtD(doctypeSystem
, doctypePublic
);
3666 res
->dict
= ctxt
->dict
;
3667 xmlDictReference(res
->dict
);
3668 } else if (xmlStrEqual(method
, (const xmlChar
*) "text")) {
3669 ctxt
->type
= XSLT_OUTPUT_TEXT
;
3670 res
= xmlNewDoc(style
->version
);
3673 res
->dict
= ctxt
->dict
;
3674 xmlDictReference(res
->dict
);
3675 #ifdef WITH_XSLT_DEBUG
3676 xsltGenericDebug(xsltGenericDebugContext
,
3677 "reusing transformation dict for output\n");
3680 xsltTransformError(ctxt
, NULL
, inst
,
3681 "xsltDocumentElem: unsupported method (%s)\n",
3686 ctxt
->type
= XSLT_OUTPUT_XML
;
3687 res
= xmlNewDoc(style
->version
);
3690 res
->dict
= ctxt
->dict
;
3691 xmlDictReference(res
->dict
);
3692 #ifdef WITH_XSLT_DEBUG
3693 xsltGenericDebug(xsltGenericDebugContext
,
3694 "reusing transformation dict for output\n");
3697 res
->charset
= XML_CHAR_ENCODING_UTF8
;
3698 if (encoding
!= NULL
)
3699 res
->encoding
= xmlStrdup(encoding
);
3701 ctxt
->insert
= (xmlNodePtr
) res
;
3702 xsltApplySequenceConstructor(ctxt
, node
, inst
->children
, NULL
);
3705 * Do some post processing work depending on the generated output
3707 root
= xmlDocGetRootElement(res
);
3709 const xmlChar
*doctype
= NULL
;
3711 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
))
3712 doctype
= xmlDictQLookup(ctxt
->dict
, root
->ns
->prefix
, root
->name
);
3713 if (doctype
== NULL
)
3714 doctype
= root
->name
;
3717 * Apply the default selection of the method
3719 if ((method
== NULL
) &&
3720 (root
->ns
== NULL
) &&
3721 (!xmlStrcasecmp(root
->name
, (const xmlChar
*) "html"))) {
3724 tmp
= res
->children
;
3725 while ((tmp
!= NULL
) && (tmp
!= root
)) {
3726 if (tmp
->type
== XML_ELEMENT_NODE
)
3728 if ((tmp
->type
== XML_TEXT_NODE
) && (!xmlIsBlankNode(tmp
)))
3733 ctxt
->type
= XSLT_OUTPUT_HTML
;
3734 res
->type
= XML_HTML_DOCUMENT_NODE
;
3735 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
3736 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
3739 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3740 } else if (version
!= NULL
) {
3741 xsltGetHTMLIDs(version
, &doctypePublic
,
3743 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3745 xmlCreateIntSubset(res
, doctype
,
3753 if (ctxt
->type
== XSLT_OUTPUT_XML
) {
3754 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
3755 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
3756 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3757 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
3764 * Calls to redirect:write also take an optional attribute append.
3765 * Attribute append="true|yes" which will attempt to simply append
3766 * to an existing file instead of always opening a new file. The
3767 * default behavior of always overwriting the file still happens
3768 * if we do not specify append.
3769 * Note that append use will forbid use of remote URI target.
3771 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
, (const xmlChar
*)"append",
3774 if (xmlStrEqual(prop
, (const xmlChar
*) "true") ||
3775 xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3776 style
->omitXmlDeclaration
= 1;
3777 redirect_write_append
= 1;
3779 style
->omitXmlDeclaration
= 0;
3783 if (redirect_write_append
) {
3786 f
= fopen((const char *) filename
, "ab");
3790 ret
= xsltSaveResultToFile(f
, res
, style
);
3794 ret
= xsltSaveResultToFilename((const char *) filename
, res
, style
, 0);
3797 xsltTransformError(ctxt
, NULL
, inst
,
3798 "xsltDocumentElem: unable to save to %s\n",
3800 #ifdef WITH_XSLT_DEBUG_EXTRA
3802 xsltGenericDebug(xsltGenericDebugContext
,
3803 "Wrote %d bytes to %s\n", ret
, filename
);
3808 ctxt
->output
= oldOutput
;
3809 ctxt
->insert
= oldInsert
;
3810 ctxt
->type
= oldType
;
3811 ctxt
->outputFile
= oldOutputFile
;
3814 if (filename
!= NULL
)
3817 xsltFreeStylesheet(style
);
3822 /************************************************************************
3824 * Most of the XSLT-1.0 transformations *
3826 ************************************************************************/
3830 * @ctxt: a XSLT process context
3831 * @node: the node in the source tree.
3832 * @inst: the xslt sort node
3833 * @comp: precomputed information
3835 * function attached to xsl:sort nodes, but this should not be
3839 xsltSort(xsltTransformContextPtr ctxt
,
3840 xmlNodePtr node ATTRIBUTE_UNUSED
, xmlNodePtr inst
,
3841 xsltElemPreCompPtr comp
) {
3843 xsltTransformError(ctxt
, NULL
, inst
,
3844 "xsl:sort : compilation failed\n");
3847 xsltTransformError(ctxt
, NULL
, inst
,
3848 "xsl:sort : improper use this should not be reached\n");
3853 * @ctxt: an XSLT process context
3854 * @node: the node in the source tree
3855 * @inst: the element node of the XSLT-copy instruction
3856 * @castedComp: computed information of the XSLT-copy instruction
3858 * Execute the XSLT-copy instruction on the source node.
3861 xsltCopy(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3862 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
3864 #ifdef XSLT_REFACTORED
3865 xsltStyleItemCopyPtr comp
= (xsltStyleItemCopyPtr
) castedComp
;
3867 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
3869 xmlNodePtr copy
, oldInsert
;
3871 oldInsert
= ctxt
->insert
;
3872 if (ctxt
->insert
!= NULL
) {
3873 switch (node
->type
) {
3875 case XML_CDATA_SECTION_NODE
:
3877 * This text comes from the stylesheet
3878 * For stylesheets, the set of whitespace-preserving
3879 * element names consists of just xsl:text.
3881 #ifdef WITH_XSLT_DEBUG_PROCESS
3882 if (node
->type
== XML_CDATA_SECTION_NODE
) {
3883 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3884 "xsltCopy: CDATA text %s\n", node
->content
));
3886 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3887 "xsltCopy: text %s\n", node
->content
));
3890 xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
3892 case XML_DOCUMENT_NODE
:
3893 case XML_HTML_DOCUMENT_NODE
:
3895 case XML_ELEMENT_NODE
:
3897 * REVISIT NOTE: The "fake" is a doc-node, not an element node.
3899 * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3903 #ifdef WITH_XSLT_DEBUG_PROCESS
3904 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3905 "xsltCopy: node %s\n", node
->name
));
3907 copy
= xsltShallowCopyElem(ctxt
, node
, ctxt
->insert
, 0);
3908 ctxt
->insert
= copy
;
3909 if (comp
->use
!= NULL
) {
3910 xsltApplyAttributeSet(ctxt
, node
, inst
, comp
->use
);
3913 case XML_ATTRIBUTE_NODE
: {
3914 #ifdef WITH_XSLT_DEBUG_PROCESS
3915 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3916 "xsltCopy: attribute %s\n", node
->name
));
3919 * REVISIT: We could also raise an error if the parent is not
3921 * OPTIMIZE TODO: Can we set the value/children of the
3922 * attribute without an intermediate copy of the string value?
3924 xsltShallowCopyAttr(ctxt
, inst
, ctxt
->insert
, (xmlAttrPtr
) node
);
3928 #ifdef WITH_XSLT_DEBUG_PROCESS
3929 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3930 "xsltCopy: PI %s\n", node
->name
));
3932 copy
= xmlNewDocPI(ctxt
->insert
->doc
, node
->name
,
3934 copy
= xsltAddChild(ctxt
->insert
, copy
);
3936 case XML_COMMENT_NODE
:
3937 #ifdef WITH_XSLT_DEBUG_PROCESS
3938 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3939 "xsltCopy: comment\n"));
3941 copy
= xmlNewComment(node
->content
);
3942 copy
= xsltAddChild(ctxt
->insert
, copy
);
3944 case XML_NAMESPACE_DECL
:
3945 #ifdef WITH_XSLT_DEBUG_PROCESS
3946 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3947 "xsltCopy: namespace declaration\n"));
3949 xsltShallowCopyNsNode(ctxt
, inst
, ctxt
->insert
, (xmlNsPtr
)node
);
3957 switch (node
->type
) {
3958 case XML_DOCUMENT_NODE
:
3959 case XML_HTML_DOCUMENT_NODE
:
3960 case XML_ELEMENT_NODE
:
3961 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, inst
->children
,
3967 ctxt
->insert
= oldInsert
;
3972 * @ctxt: a XSLT process context
3973 * @node: the node in the source tree.
3974 * @inst: the xslt text node
3975 * @comp: precomputed information
3977 * Process the xslt text node on the source node
3980 xsltText(xsltTransformContextPtr ctxt
, xmlNodePtr node ATTRIBUTE_UNUSED
,
3981 xmlNodePtr inst
, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
) {
3982 if ((inst
->children
!= NULL
) && (comp
!= NULL
)) {
3983 xmlNodePtr text
= inst
->children
;
3986 while (text
!= NULL
) {
3987 if ((text
->type
!= XML_TEXT_NODE
) &&
3988 (text
->type
!= XML_CDATA_SECTION_NODE
)) {
3989 xsltTransformError(ctxt
, NULL
, inst
,
3990 "xsl:text content problem\n");
3993 copy
= xmlNewDocText(ctxt
->output
, text
->content
);
3994 if (text
->type
!= XML_CDATA_SECTION_NODE
) {
3995 #ifdef WITH_XSLT_DEBUG_PARSING
3996 xsltGenericDebug(xsltGenericDebugContext
,
3997 "Disable escaping: %s\n", text
->content
);
3999 copy
->name
= xmlStringTextNoenc
;
4001 copy
= xsltAddChild(ctxt
->insert
, copy
);
4009 * @ctxt: a XSLT process context
4010 * @node: the node in the source tree.
4011 * @inst: the xslt element node
4012 * @castedComp: precomputed information
4014 * Process the xslt element node on the source node
4017 xsltElement(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4018 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
) {
4019 #ifdef XSLT_REFACTORED
4020 xsltStyleItemElementPtr comp
= (xsltStyleItemElementPtr
) castedComp
;
4022 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4024 xmlChar
*prop
= NULL
;
4025 const xmlChar
*name
, *prefix
= NULL
, *nsName
= NULL
;
4027 xmlNodePtr oldInsert
;
4029 if (ctxt
->insert
== NULL
)
4033 * A comp->has_name == 0 indicates that we need to skip this instruction,
4034 * since it was evaluated to be invalid already during compilation.
4036 if (!comp
->has_name
)
4042 oldInsert
= ctxt
->insert
;
4044 if (comp
->name
== NULL
) {
4045 /* TODO: fix attr acquisition wrt to the XSLT namespace */
4046 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4047 (const xmlChar
*) "name", XSLT_NAMESPACE
);
4049 xsltTransformError(ctxt
, NULL
, inst
,
4050 "xsl:element: The attribute 'name' is missing.\n");
4053 if (xmlValidateQName(prop
, 0)) {
4054 xsltTransformError(ctxt
, NULL
, inst
,
4055 "xsl:element: The effective name '%s' is not a "
4056 "valid QName.\n", prop
);
4057 /* we fall through to catch any further errors, if possible */
4059 name
= xsltSplitQName(ctxt
->dict
, prop
, &prefix
);
4063 * The "name" value was static.
4065 #ifdef XSLT_REFACTORED
4066 prefix
= comp
->nsPrefix
;
4069 name
= xsltSplitQName(ctxt
->dict
, comp
->name
, &prefix
);
4074 * Create the new element
4076 if (ctxt
->output
->dict
== ctxt
->dict
) {
4077 copy
= xmlNewDocNodeEatName(ctxt
->output
, NULL
, (xmlChar
*)name
, NULL
);
4079 copy
= xmlNewDocNode(ctxt
->output
, NULL
, (xmlChar
*)name
, NULL
);
4082 xsltTransformError(ctxt
, NULL
, inst
,
4083 "xsl:element : creation of %s failed\n", name
);
4086 copy
= xsltAddChild(ctxt
->insert
, copy
);
4088 xsltTransformError(ctxt
, NULL
, inst
,
4089 "xsl:element : xsltAddChild failed\n");
4098 if (comp
->ns
!= NULL
) {
4100 * No AVT; just plain text for the namespace name.
4102 if (comp
->ns
[0] != 0)
4109 /* TODO: check attr acquisition wrt to the XSLT namespace */
4110 tmpNsName
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4111 (const xmlChar
*) "namespace", XSLT_NAMESPACE
);
4114 * "If the string is empty, then the expanded-name of the
4115 * attribute has a null namespace URI."
4117 if ((tmpNsName
!= NULL
) && (tmpNsName
[0] != 0))
4118 nsName
= xmlDictLookup(ctxt
->dict
, BAD_CAST tmpNsName
, -1);
4122 if (xmlStrEqual(nsName
, BAD_CAST
"http://www.w3.org/2000/xmlns/")) {
4123 xsltTransformError(ctxt
, NULL
, inst
,
4124 "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
4128 if (xmlStrEqual(nsName
, XML_XML_NAMESPACE
)) {
4129 prefix
= BAD_CAST
"xml";
4130 } else if (xmlStrEqual(prefix
, BAD_CAST
"xml")) {
4137 * "If the namespace attribute is not present, then the QName is
4138 * expanded into an expanded-name using the namespace declarations
4139 * in effect for the xsl:element element, including any default
4140 * namespace declaration.
4142 ns
= xmlSearchNs(inst
->doc
, inst
, prefix
);
4145 * TODO: Check this in the compilation layer in case it's a
4148 if (prefix
!= NULL
) {
4149 xsltTransformError(ctxt
, NULL
, inst
,
4150 "xsl:element: The QName '%s:%s' has no "
4151 "namespace binding in scope in the stylesheet; "
4152 "this is an error, since the namespace was not "
4153 "specified by the instruction itself.\n", prefix
, name
);
4159 * Find/create a matching ns-decl in the result tree.
4161 if (nsName
!= NULL
) {
4162 if (xmlStrEqual(prefix
, BAD_CAST
"xmlns")) {
4163 /* Don't use a prefix of "xmlns" */
4164 xmlChar
*pref
= xmlStrdup(BAD_CAST
"ns_1");
4166 copy
->ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, pref
, copy
);
4170 copy
->ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, prefix
,
4173 } else if ((copy
->parent
!= NULL
) &&
4174 (copy
->parent
->type
== XML_ELEMENT_NODE
) &&
4175 (copy
->parent
->ns
!= NULL
))
4178 * "Undeclare" the default namespace.
4180 xsltGetSpecialNamespace(ctxt
, inst
, NULL
, NULL
, copy
);
4183 ctxt
->insert
= copy
;
4185 if (comp
->has_use
) {
4186 if (comp
->use
!= NULL
) {
4187 xsltApplyAttributeSet(ctxt
, node
, inst
, comp
->use
);
4189 xmlChar
*attrSets
= NULL
;
4191 * BUG TODO: use-attribute-sets is not a value template.
4192 * use-attribute-sets = qnames
4194 attrSets
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4195 (const xmlChar
*)"use-attribute-sets", NULL
);
4196 if (attrSets
!= NULL
) {
4197 xsltApplyAttributeSet(ctxt
, node
, inst
, attrSets
);
4203 * Instantiate the sequence constructor.
4205 if (inst
->children
!= NULL
)
4206 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, inst
->children
,
4210 ctxt
->insert
= oldInsert
;
4217 * @ctxt: a XSLT process context
4218 * @node: the node in the source tree.
4219 * @inst: the xslt comment node
4220 * @comp: precomputed information
4222 * Process the xslt comment node on the source node
4225 xsltComment(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4226 xmlNodePtr inst
, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
) {
4227 xmlChar
*value
= NULL
;
4228 xmlNodePtr commentNode
;
4231 value
= xsltEvalTemplateString(ctxt
, node
, inst
);
4232 /* TODO: use or generate the compiled form */
4233 len
= xmlStrlen(value
);
4235 if ((value
[len
-1] == '-') ||
4236 (xmlStrstr(value
, BAD_CAST
"--"))) {
4237 xsltTransformError(ctxt
, NULL
, inst
,
4238 "xsl:comment : '--' or ending '-' not allowed in comment\n");
4239 /* fall through to try to catch further errors */
4242 #ifdef WITH_XSLT_DEBUG_PROCESS
4243 if (value
== NULL
) {
4244 XSLT_TRACE(ctxt
,XSLT_TRACE_COMMENT
,xsltGenericDebug(xsltGenericDebugContext
,
4245 "xsltComment: empty\n"));
4247 XSLT_TRACE(ctxt
,XSLT_TRACE_COMMENT
,xsltGenericDebug(xsltGenericDebugContext
,
4248 "xsltComment: content %s\n", value
));
4252 commentNode
= xmlNewComment(value
);
4253 commentNode
= xsltAddChild(ctxt
->insert
, commentNode
);
4260 * xsltProcessingInstruction:
4261 * @ctxt: a XSLT process context
4262 * @node: the node in the source tree.
4263 * @inst: the xslt processing-instruction node
4264 * @castedComp: precomputed information
4266 * Process the xslt processing-instruction node on the source node
4269 xsltProcessingInstruction(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4270 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
) {
4271 #ifdef XSLT_REFACTORED
4272 xsltStyleItemPIPtr comp
= (xsltStyleItemPIPtr
) castedComp
;
4274 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4276 const xmlChar
*name
;
4277 xmlChar
*value
= NULL
;
4281 if (ctxt
->insert
== NULL
)
4283 if (comp
->has_name
== 0)
4285 if (comp
->name
== NULL
) {
4286 name
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4287 (const xmlChar
*)"name", NULL
);
4289 xsltTransformError(ctxt
, NULL
, inst
,
4290 "xsl:processing-instruction : name is missing\n");
4296 /* TODO: check that it's both an an NCName and a PITarget. */
4299 value
= xsltEvalTemplateString(ctxt
, node
, inst
);
4300 if (xmlStrstr(value
, BAD_CAST
"?>") != NULL
) {
4301 xsltTransformError(ctxt
, NULL
, inst
,
4302 "xsl:processing-instruction: '?>' not allowed within PI content\n");
4305 #ifdef WITH_XSLT_DEBUG_PROCESS
4306 if (value
== NULL
) {
4307 XSLT_TRACE(ctxt
,XSLT_TRACE_PI
,xsltGenericDebug(xsltGenericDebugContext
,
4308 "xsltProcessingInstruction: %s empty\n", name
));
4310 XSLT_TRACE(ctxt
,XSLT_TRACE_PI
,xsltGenericDebug(xsltGenericDebugContext
,
4311 "xsltProcessingInstruction: %s content %s\n", name
, value
));
4315 pi
= xmlNewDocPI(ctxt
->insert
->doc
, name
, value
);
4316 pi
= xsltAddChild(ctxt
->insert
, pi
);
4319 if ((name
!= NULL
) && (name
!= comp
->name
))
4320 xmlFree((xmlChar
*) name
);
4327 * @ctxt: an XSLT transformation context
4328 * @node: the current node in the source tree
4329 * @inst: the element node of the XSLT copy-of instruction
4330 * @castedComp: precomputed information of the XSLT copy-of instruction
4332 * Process the XSLT copy-of instruction.
4335 xsltCopyOf(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4336 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
) {
4337 #ifdef XSLT_REFACTORED
4338 xsltStyleItemCopyOfPtr comp
= (xsltStyleItemCopyOfPtr
) castedComp
;
4340 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4342 xmlXPathObjectPtr res
= NULL
;
4343 xmlNodeSetPtr list
= NULL
;
4346 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
))
4348 if ((comp
== NULL
) || (comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
4349 xsltTransformError(ctxt
, NULL
, inst
,
4350 "xsl:copy-of : compilation failed\n");
4356 * "The xsl:copy-of element can be used to insert a result tree
4357 * fragment into the result tree, without first converting it to
4358 * a string as xsl:value-of does (see [7.6.1 Generating Text with
4359 * xsl:value-of]). The required select attribute contains an
4360 * expression. When the result of evaluating the expression is a
4361 * result tree fragment, the complete fragment is copied into the
4362 * result tree. When the result is a node-set, all the nodes in the
4363 * set are copied in document order into the result tree; copying
4364 * an element node copies the attribute nodes, namespace nodes and
4365 * children of the element node as well as the element node itself;
4366 * a root node is copied by copying its children. When the result
4367 * is neither a node-set nor a result tree fragment, the result is
4368 * converted to a string and then inserted into the result tree,
4369 * as with xsl:value-of.
4372 #ifdef WITH_XSLT_DEBUG_PROCESS
4373 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4374 "xsltCopyOf: select %s\n", comp
->select
));
4378 * Evaluate the "select" expression.
4380 res
= xsltPreCompEval(ctxt
, node
, comp
);
4383 if (res
->type
== XPATH_NODESET
) {
4388 #ifdef WITH_XSLT_DEBUG_PROCESS
4389 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4390 "xsltCopyOf: result is a node set\n"));
4392 list
= res
->nodesetval
;
4396 * The list is already sorted in document order by XPath.
4397 * Append everything in this order under ctxt->insert.
4399 for (i
= 0;i
< list
->nodeNr
;i
++) {
4400 cur
= list
->nodeTab
[i
];
4403 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
4404 (cur
->type
== XML_HTML_DOCUMENT_NODE
))
4406 xsltCopyTreeList(ctxt
, inst
,
4407 cur
->children
, ctxt
->insert
, 0, 0);
4408 } else if (cur
->type
== XML_ATTRIBUTE_NODE
) {
4409 xsltShallowCopyAttr(ctxt
, inst
,
4410 ctxt
->insert
, (xmlAttrPtr
) cur
);
4412 xsltCopyTree(ctxt
, inst
, cur
, ctxt
->insert
, 0, 0);
4416 } else if (res
->type
== XPATH_XSLT_TREE
) {
4418 * Result tree fragment
4419 * --------------------
4420 * E.g. via <xsl:variable ...><foo/></xsl:variable>
4421 * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4423 #ifdef WITH_XSLT_DEBUG_PROCESS
4424 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4425 "xsltCopyOf: result is a result tree fragment\n"));
4427 list
= res
->nodesetval
;
4428 if ((list
!= NULL
) && (list
->nodeTab
!= NULL
) &&
4429 (list
->nodeTab
[0] != NULL
) &&
4430 (IS_XSLT_REAL_NODE(list
->nodeTab
[0])))
4432 xsltCopyTreeList(ctxt
, inst
,
4433 list
->nodeTab
[0]->children
, ctxt
->insert
, 0, 0);
4436 xmlChar
*value
= NULL
;
4438 * Convert to a string.
4440 value
= xmlXPathCastToString(res
);
4441 if (value
== NULL
) {
4442 xsltTransformError(ctxt
, NULL
, inst
,
4443 "Internal error in xsltCopyOf(): "
4444 "failed to cast an XPath object to string.\n");
4445 ctxt
->state
= XSLT_STATE_STOPPED
;
4447 if (value
[0] != 0) {
4449 * Append content as text node.
4451 xsltCopyTextString(ctxt
, ctxt
->insert
, value
, 0);
4455 #ifdef WITH_XSLT_DEBUG_PROCESS
4456 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4457 "xsltCopyOf: result %s\n", res
->stringval
));
4462 ctxt
->state
= XSLT_STATE_STOPPED
;
4466 xmlXPathFreeObject(res
);
4471 * @ctxt: a XSLT process context
4472 * @node: the node in the source tree.
4473 * @inst: the xslt value-of node
4474 * @castedComp: precomputed information
4476 * Process the xslt value-of node on the source node
4479 xsltValueOf(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4480 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
4482 #ifdef XSLT_REFACTORED
4483 xsltStyleItemValueOfPtr comp
= (xsltStyleItemValueOfPtr
) castedComp
;
4485 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4487 xmlXPathObjectPtr res
= NULL
;
4488 xmlChar
*value
= NULL
;
4490 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
))
4493 if ((comp
== NULL
) || (comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
4494 xsltTransformError(ctxt
, NULL
, inst
,
4495 "Internal error in xsltValueOf(): "
4496 "The XSLT 'value-of' instruction was not compiled.\n");
4500 #ifdef WITH_XSLT_DEBUG_PROCESS
4501 XSLT_TRACE(ctxt
,XSLT_TRACE_VALUE_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4502 "xsltValueOf: select %s\n", comp
->select
));
4505 res
= xsltPreCompEval(ctxt
, node
, comp
);
4508 * Cast the XPath object to string.
4511 value
= xmlXPathCastToString(res
);
4512 if (value
== NULL
) {
4513 xsltTransformError(ctxt
, NULL
, inst
,
4514 "Internal error in xsltValueOf(): "
4515 "failed to cast an XPath object to string.\n");
4516 ctxt
->state
= XSLT_STATE_STOPPED
;
4519 if (value
[0] != 0) {
4520 xsltCopyTextString(ctxt
, ctxt
->insert
, value
, comp
->noescape
);
4523 xsltTransformError(ctxt
, NULL
, inst
,
4524 "XPath evaluation returned no result.\n");
4525 ctxt
->state
= XSLT_STATE_STOPPED
;
4529 #ifdef WITH_XSLT_DEBUG_PROCESS
4531 XSLT_TRACE(ctxt
,XSLT_TRACE_VALUE_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4532 "xsltValueOf: result '%s'\n", value
));
4540 xmlXPathFreeObject(res
);
4545 * @ctxt: a XSLT process context
4546 * @node: the node in the source tree.
4547 * @inst: the xslt number node
4548 * @castedComp: precomputed information
4550 * Process the xslt number node on the source node
4553 xsltNumber(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4554 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
4556 #ifdef XSLT_REFACTORED
4557 xsltStyleItemNumberPtr comp
= (xsltStyleItemNumberPtr
) castedComp
;
4559 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4561 xmlXPathContextPtr xpctxt
;
4562 xmlNsPtr
*oldXPNamespaces
;
4566 xsltTransformError(ctxt
, NULL
, inst
,
4567 "xsl:number : compilation failed\n");
4571 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
4574 comp
->numdata
.doc
= inst
->doc
;
4575 comp
->numdata
.node
= inst
;
4577 xpctxt
= ctxt
->xpathCtxt
;
4578 oldXPNsNr
= xpctxt
->nsNr
;
4579 oldXPNamespaces
= xpctxt
->namespaces
;
4581 #ifdef XSLT_REFACTORED
4582 if (comp
->inScopeNs
!= NULL
) {
4583 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
4584 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
4586 xpctxt
->namespaces
= NULL
;
4590 xpctxt
->namespaces
= comp
->nsList
;
4591 xpctxt
->nsNr
= comp
->nsNr
;
4594 xsltNumberFormat(ctxt
, &comp
->numdata
, node
);
4596 xpctxt
->nsNr
= oldXPNsNr
;
4597 xpctxt
->namespaces
= oldXPNamespaces
;
4602 * @ctxt: an XSLT transformation context
4603 * @contextNode: the current node in the source tree.
4604 * @inst: the element node of the XSLT 'apply-imports' instruction
4605 * @comp: the compiled instruction
4607 * Process the XSLT apply-imports element.
4610 xsltApplyImports(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
4612 xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
)
4614 xsltTemplatePtr templ
;
4616 if ((ctxt
== NULL
) || (inst
== NULL
))
4620 xsltTransformError(ctxt
, NULL
, inst
,
4621 "Internal error in xsltApplyImports(): "
4622 "The XSLT 'apply-imports' instruction was not compiled.\n");
4626 * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4627 * same; the former is the "Current Template Rule" as defined by the
4628 * XSLT spec, the latter is simply the template struct being
4629 * currently processed.
4631 if (ctxt
->currentTemplateRule
== NULL
) {
4634 * "[ERR XTDE0560] It is a non-recoverable dynamic error if
4635 * xsl:apply-imports or xsl:next-match is evaluated when the
4636 * current template rule is null."
4638 xsltTransformError(ctxt
, NULL
, inst
,
4639 "It is an error to call 'apply-imports' "
4640 "when there's no current template rule.\n");
4644 * TODO: Check if this is correct.
4646 templ
= xsltGetTemplate(ctxt
, contextNode
,
4647 ctxt
->currentTemplateRule
->style
);
4649 if (templ
!= NULL
) {
4650 xsltTemplatePtr oldCurTemplRule
= ctxt
->currentTemplateRule
;
4652 * Set the current template rule.
4654 ctxt
->currentTemplateRule
= templ
;
4656 * URGENT TODO: Need xsl:with-param be handled somehow here?
4658 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
,
4661 ctxt
->currentTemplateRule
= oldCurTemplRule
;
4664 /* Use built-in templates. */
4665 xsltDefaultProcessOneNode(ctxt
, contextNode
, NULL
);
4671 * @ctxt: a XSLT transformation context
4672 * @node: the "current node" in the source tree
4673 * @inst: the XSLT 'call-template' instruction
4674 * @castedComp: the compiled information of the instruction
4676 * Processes the XSLT call-template instruction on the source node.
4679 xsltCallTemplate(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4680 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
4682 #ifdef XSLT_REFACTORED
4683 xsltStyleItemCallTemplatePtr comp
=
4684 (xsltStyleItemCallTemplatePtr
) castedComp
;
4686 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4688 xsltStackElemPtr withParams
= NULL
;
4690 if (ctxt
->insert
== NULL
)
4693 xsltTransformError(ctxt
, NULL
, inst
,
4694 "The XSLT 'call-template' instruction was not compiled.\n");
4699 * The template must have been precomputed
4701 if (comp
->templ
== NULL
) {
4702 comp
->templ
= xsltFindTemplate(ctxt
, comp
->name
, comp
->ns
);
4703 if (comp
->templ
== NULL
) {
4704 if (comp
->ns
!= NULL
) {
4705 xsltTransformError(ctxt
, NULL
, inst
,
4706 "The called template '{%s}%s' was not found.\n",
4707 comp
->ns
, comp
->name
);
4709 xsltTransformError(ctxt
, NULL
, inst
,
4710 "The called template '%s' was not found.\n",
4717 #ifdef WITH_XSLT_DEBUG_PROCESS
4718 if ((comp
!= NULL
) && (comp
->name
!= NULL
))
4719 XSLT_TRACE(ctxt
,XSLT_TRACE_CALL_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
4720 "call-template: name %s\n", comp
->name
));
4723 if (inst
->children
) {
4725 xsltStackElemPtr param
;
4727 cur
= inst
->children
;
4728 while (cur
!= NULL
) {
4729 #ifdef WITH_DEBUGGER
4730 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
4731 xslHandleDebugger(cur
, node
, comp
->templ
, ctxt
);
4733 if (ctxt
->state
== XSLT_STATE_STOPPED
) break;
4735 * TODO: The "with-param"s could be part of the "call-template"
4736 * structure. Avoid to "search" for params dynamically
4737 * in the XML tree every time.
4739 if (IS_XSLT_ELEM(cur
)) {
4740 if (IS_XSLT_NAME(cur
, "with-param")) {
4741 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
4742 if (param
!= NULL
) {
4743 param
->next
= withParams
;
4747 xsltGenericError(xsltGenericErrorContext
,
4748 "xsl:call-template: misplaced xsl:%s\n", cur
->name
);
4751 xsltGenericError(xsltGenericErrorContext
,
4752 "xsl:call-template: misplaced %s element\n", cur
->name
);
4758 * Create a new frame using the params first
4760 xsltApplyXSLTTemplate(ctxt
, node
, comp
->templ
->content
, comp
->templ
,
4762 if (withParams
!= NULL
)
4763 xsltFreeStackElemList(withParams
);
4765 #ifdef WITH_XSLT_DEBUG_PROCESS
4766 if ((comp
!= NULL
) && (comp
->name
!= NULL
))
4767 XSLT_TRACE(ctxt
,XSLT_TRACE_CALL_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
4768 "call-template returned: name %s\n", comp
->name
));
4773 * xsltApplyTemplates:
4774 * @ctxt: a XSLT transformation context
4775 * @node: the 'current node' in the source tree
4776 * @inst: the element node of an XSLT 'apply-templates' instruction
4777 * @castedComp: the compiled instruction
4779 * Processes the XSLT 'apply-templates' instruction on the current node.
4782 xsltApplyTemplates(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4783 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
4785 #ifdef XSLT_REFACTORED
4786 xsltStyleItemApplyTemplatesPtr comp
=
4787 (xsltStyleItemApplyTemplatesPtr
) castedComp
;
4789 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4792 xmlNodePtr cur
, oldContextNode
;
4793 xmlNodeSetPtr list
= NULL
, oldList
;
4794 xsltStackElemPtr withParams
= NULL
;
4795 int oldXPProximityPosition
, oldXPContextSize
;
4796 const xmlChar
*oldMode
, *oldModeURI
;
4798 xsltDocumentPtr oldDocInfo
;
4799 xmlXPathContextPtr xpctxt
;
4802 xsltTransformError(ctxt
, NULL
, inst
,
4803 "xsl:apply-templates : compilation failed\n");
4806 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
4809 #ifdef WITH_XSLT_DEBUG_PROCESS
4810 if ((node
!= NULL
) && (node
->name
!= NULL
))
4811 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4812 "xsltApplyTemplates: node: '%s'\n", node
->name
));
4815 xpctxt
= ctxt
->xpathCtxt
;
4817 * Save context states.
4819 oldContextNode
= ctxt
->node
;
4820 oldMode
= ctxt
->mode
;
4821 oldModeURI
= ctxt
->modeURI
;
4822 oldDocInfo
= ctxt
->document
;
4823 oldList
= ctxt
->nodeList
;
4826 * The xpath context size and proximity position, as
4827 * well as the xpath and context documents, may be changed
4828 * so we save their initial state and will restore on exit
4830 oldXPContextSize
= xpctxt
->contextSize
;
4831 oldXPProximityPosition
= xpctxt
->proximityPosition
;
4832 oldXPDoc
= xpctxt
->doc
;
4837 ctxt
->mode
= comp
->mode
;
4838 ctxt
->modeURI
= comp
->modeURI
;
4840 if (comp
->select
!= NULL
) {
4841 xmlXPathObjectPtr res
= NULL
;
4843 if (comp
->comp
== NULL
) {
4844 xsltTransformError(ctxt
, NULL
, inst
,
4845 "xsl:apply-templates : compilation failed\n");
4848 #ifdef WITH_XSLT_DEBUG_PROCESS
4849 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4850 "xsltApplyTemplates: select %s\n", comp
->select
));
4853 res
= xsltPreCompEval(ctxt
, node
, comp
);
4856 if (res
->type
== XPATH_NODESET
) {
4857 list
= res
->nodesetval
; /* consume the node set */
4858 res
->nodesetval
= NULL
;
4860 xsltTransformError(ctxt
, NULL
, inst
,
4861 "The 'select' expression did not evaluate to a "
4863 ctxt
->state
= XSLT_STATE_STOPPED
;
4864 xmlXPathFreeObject(res
);
4867 xmlXPathFreeObject(res
);
4869 * Note: An xsl:apply-templates with a 'select' attribute,
4870 * can change the current source doc.
4873 xsltTransformError(ctxt
, NULL
, inst
,
4874 "Failed to evaluate the 'select' expression.\n");
4875 ctxt
->state
= XSLT_STATE_STOPPED
;
4879 #ifdef WITH_XSLT_DEBUG_PROCESS
4880 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4881 "xsltApplyTemplates: select didn't evaluate to a node list\n"));
4887 * NOTE: Previously a document info (xsltDocument) was
4888 * created and attached to the Result Tree Fragment.
4889 * But such a document info is created on demand in
4890 * xsltKeyFunction() (functions.c), so we need to create
4891 * it here beforehand.
4892 * In order to take care of potential keys we need to
4893 * do some extra work for the case when a Result Tree Fragment
4894 * is converted into a nodeset (e.g. exslt:node-set()) :
4895 * We attach a "pseudo-doc" (xsltDocument) to _private.
4896 * This xsltDocument, together with the keyset, will be freed
4897 * when the Result Tree Fragment is freed.
4901 if ((ctxt
->nbKeys
> 0) &&
4902 (list
->nodeNr
!= 0) &&
4903 (list
->nodeTab
[0]->doc
!= NULL
) &&
4904 XSLT_IS_RES_TREE_FRAG(list
->nodeTab
[0]->doc
))
4907 * NOTE that it's also OK if @effectiveDocInfo will be
4911 effectiveDocInfo
= list
->nodeTab
[0]->doc
->_private
;
4916 * Build an XPath node set with the children
4918 list
= xmlXPathNodeSetCreate(NULL
);
4921 if (node
->type
!= XML_NAMESPACE_DECL
)
4922 cur
= node
->children
;
4925 while (cur
!= NULL
) {
4926 if (IS_XSLT_REAL_NODE(cur
))
4927 xmlXPathNodeSetAddUnique(list
, cur
);
4932 #ifdef WITH_XSLT_DEBUG_PROCESS
4934 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4935 "xsltApplyTemplates: list of %d nodes\n", list
->nodeNr
));
4938 if ((list
== NULL
) || (list
->nodeNr
== 0))
4942 * Set the context's node set and size; this is also needed for
4943 * for xsltDoSortFunction().
4945 ctxt
->nodeList
= list
;
4947 * Process xsl:with-param and xsl:sort instructions.
4948 * (The code became so verbose just to avoid the
4949 * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
4950 * BUG TODO: We are not using namespaced potentially defined on the
4951 * xsl:sort or xsl:with-param elements; XPath expression might fail.
4953 if (inst
->children
) {
4954 xsltStackElemPtr param
;
4956 cur
= inst
->children
;
4959 #ifdef WITH_DEBUGGER
4960 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
4961 xslHandleDebugger(cur
, node
, NULL
, ctxt
);
4963 if (ctxt
->state
== XSLT_STATE_STOPPED
)
4965 if (cur
->type
== XML_TEXT_NODE
) {
4969 if (! IS_XSLT_ELEM(cur
))
4971 if (IS_XSLT_NAME(cur
, "with-param")) {
4972 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
4973 if (param
!= NULL
) {
4974 param
->next
= withParams
;
4978 if (IS_XSLT_NAME(cur
, "sort")) {
4979 xsltTemplatePtr oldCurTempRule
=
4980 ctxt
->currentTemplateRule
;
4982 xmlNodePtr sorts
[XSLT_MAX_SORT
];
4984 sorts
[nbsorts
++] = cur
;
4989 #ifdef WITH_DEBUGGER
4990 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
4991 xslHandleDebugger(cur
, node
, NULL
, ctxt
);
4993 if (ctxt
->state
== XSLT_STATE_STOPPED
)
4996 if (cur
->type
== XML_TEXT_NODE
) {
5001 if (! IS_XSLT_ELEM(cur
))
5003 if (IS_XSLT_NAME(cur
, "with-param")) {
5004 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
5005 if (param
!= NULL
) {
5006 param
->next
= withParams
;
5010 if (IS_XSLT_NAME(cur
, "sort")) {
5011 if (nbsorts
>= XSLT_MAX_SORT
) {
5012 xsltTransformError(ctxt
, NULL
, cur
,
5013 "The number (%d) of xsl:sort instructions exceeds the "
5014 "maximum allowed by this processor's settings.\n",
5016 ctxt
->state
= XSLT_STATE_STOPPED
;
5019 sorts
[nbsorts
++] = cur
;
5025 * The "current template rule" is cleared for xsl:sort.
5027 ctxt
->currentTemplateRule
= NULL
;
5031 xsltDoSortFunction(ctxt
, sorts
, nbsorts
);
5032 ctxt
->currentTemplateRule
= oldCurTempRule
;
5038 xpctxt
->contextSize
= list
->nodeNr
;
5040 * Apply templates for all selected source nodes.
5042 for (i
= 0; i
< list
->nodeNr
; i
++) {
5043 cur
= list
->nodeTab
[i
];
5045 * The node becomes the "current node".
5049 * An xsl:apply-templates can change the current context doc.
5050 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5052 if ((cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->doc
!= NULL
))
5053 xpctxt
->doc
= cur
->doc
;
5055 xpctxt
->proximityPosition
= i
+ 1;
5057 * Find and apply a template for this node.
5059 xsltProcessOneNode(ctxt
, cur
, withParams
);
5065 * Free the parameter list.
5067 if (withParams
!= NULL
)
5068 xsltFreeStackElemList(withParams
);
5070 xmlXPathFreeNodeSet(list
);
5072 * Restore context states.
5074 xpctxt
->doc
= oldXPDoc
;
5075 xpctxt
->contextSize
= oldXPContextSize
;
5076 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5078 ctxt
->document
= oldDocInfo
;
5079 ctxt
->nodeList
= oldList
;
5080 ctxt
->node
= oldContextNode
;
5081 ctxt
->mode
= oldMode
;
5082 ctxt
->modeURI
= oldModeURI
;
5088 * @ctxt: a XSLT process context
5089 * @contextNode: the current node in the source tree
5090 * @inst: the xsl:choose instruction
5091 * @comp: compiled information of the instruction
5093 * Processes the xsl:choose instruction on the source node.
5096 xsltChoose(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5097 xmlNodePtr inst
, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
)
5101 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
))
5105 * TODO: Content model checks should be done only at compilation
5108 cur
= inst
->children
;
5110 xsltTransformError(ctxt
, NULL
, inst
,
5111 "xsl:choose: The instruction has no content.\n");
5115 #ifdef XSLT_REFACTORED
5117 * We don't check the content model during transformation.
5120 if ((! IS_XSLT_ELEM(cur
)) || (! IS_XSLT_NAME(cur
, "when"))) {
5121 xsltTransformError(ctxt
, NULL
, inst
,
5122 "xsl:choose: xsl:when expected first\n");
5128 int testRes
= 0, res
= 0;
5130 #ifdef XSLT_REFACTORED
5131 xsltStyleItemWhenPtr wcomp
= NULL
;
5133 xsltStylePreCompPtr wcomp
= NULL
;
5137 * Process xsl:when ---------------------------------------------------
5139 while (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "when")) {
5142 if ((wcomp
== NULL
) || (wcomp
->test
== NULL
) ||
5143 (wcomp
->comp
== NULL
))
5145 xsltTransformError(ctxt
, NULL
, cur
,
5146 "Internal error in xsltChoose(): "
5147 "The XSLT 'when' instruction was not compiled.\n");
5152 #ifdef WITH_DEBUGGER
5153 if (xslDebugStatus
!= XSLT_DEBUG_NONE
) {
5155 * TODO: Isn't comp->templ always NULL for xsl:choose?
5157 xslHandleDebugger(cur
, contextNode
, NULL
, ctxt
);
5160 #ifdef WITH_XSLT_DEBUG_PROCESS
5161 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5162 "xsltChoose: test %s\n", wcomp
->test
));
5166 res
= xsltPreCompEvalToBoolean(ctxt
, contextNode
, wcomp
);
5169 ctxt
->state
= XSLT_STATE_STOPPED
;
5172 testRes
= (res
== 1) ? 1 : 0;
5174 #else /* XSLT_FAST_IF */
5176 res
= xsltPreCompEval(ctxt
, cotextNode
, wcomp
);
5179 if (res
->type
!= XPATH_BOOLEAN
)
5180 res
= xmlXPathConvertBoolean(res
);
5181 if (res
->type
== XPATH_BOOLEAN
)
5182 testRes
= res
->boolval
;
5184 #ifdef WITH_XSLT_DEBUG_PROCESS
5185 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5186 "xsltChoose: test didn't evaluate to a boolean\n"));
5190 xmlXPathFreeObject(res
);
5193 ctxt
->state
= XSLT_STATE_STOPPED
;
5197 #endif /* else of XSLT_FAST_IF */
5199 #ifdef WITH_XSLT_DEBUG_PROCESS
5200 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5201 "xsltChoose: test evaluate to %d\n", testRes
));
5210 * Process xsl:otherwise ----------------------------------------------
5212 if (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "otherwise")) {
5214 #ifdef WITH_DEBUGGER
5215 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5216 xslHandleDebugger(cur
, contextNode
, NULL
, ctxt
);
5219 #ifdef WITH_XSLT_DEBUG_PROCESS
5220 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5221 "evaluating xsl:otherwise\n"));
5229 goto process_sequence
;
5235 * Instantiate the sequence constructor.
5237 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, cur
->children
,
5247 * @ctxt: a XSLT process context
5248 * @contextNode: the current node in the source tree
5249 * @inst: the xsl:if instruction
5250 * @castedComp: compiled information of the instruction
5252 * Processes the xsl:if instruction on the source node.
5255 xsltIf(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5256 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
5260 #ifdef XSLT_REFACTORED
5261 xsltStyleItemIfPtr comp
= (xsltStyleItemIfPtr
) castedComp
;
5263 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
5266 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
))
5268 if ((comp
== NULL
) || (comp
->test
== NULL
) || (comp
->comp
== NULL
)) {
5269 xsltTransformError(ctxt
, NULL
, inst
,
5270 "Internal error in xsltIf(): "
5271 "The XSLT 'if' instruction was not compiled.\n");
5275 #ifdef WITH_XSLT_DEBUG_PROCESS
5276 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5277 "xsltIf: test %s\n", comp
->test
));
5282 xmlDocPtr oldLocalFragmentTop
= ctxt
->localRVT
;
5284 res
= xsltPreCompEvalToBoolean(ctxt
, contextNode
, comp
);
5287 * Cleanup fragments created during evaluation of the
5288 * "select" expression.
5290 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
5291 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
5294 #ifdef WITH_XSLT_DEBUG_PROCESS
5295 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5296 "xsltIf: test evaluate to %d\n", res
));
5300 ctxt
->state
= XSLT_STATE_STOPPED
;
5305 * Instantiate the sequence constructor of xsl:if.
5307 xsltApplySequenceConstructor(ctxt
,
5308 contextNode
, inst
->children
, NULL
);
5311 #else /* XSLT_FAST_IF */
5316 xmlXPathObjectPtr xpobj
= xsltPreCompEval(ctxt
, contextNode
, comp
);
5317 if (xpobj
!= NULL
) {
5318 if (xpobj
->type
!= XPATH_BOOLEAN
)
5319 xpobj
= xmlXPathConvertBoolean(xpobj
);
5320 if (xpobj
->type
== XPATH_BOOLEAN
) {
5321 res
= xpobj
->boolval
;
5323 #ifdef WITH_XSLT_DEBUG_PROCESS
5324 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5325 "xsltIf: test evaluate to %d\n", res
));
5328 xsltApplySequenceConstructor(ctxt
,
5329 contextNode
, inst
->children
, NULL
);
5333 #ifdef WITH_XSLT_DEBUG_PROCESS
5334 XSLT_TRACE(ctxt
, XSLT_TRACE_IF
,
5335 xsltGenericDebug(xsltGenericDebugContext
,
5336 "xsltIf: test didn't evaluate to a boolean\n"));
5338 ctxt
->state
= XSLT_STATE_STOPPED
;
5340 xmlXPathFreeObject(xpobj
);
5342 ctxt
->state
= XSLT_STATE_STOPPED
;
5345 #endif /* else of XSLT_FAST_IF */
5353 * @ctxt: an XSLT transformation context
5354 * @contextNode: the "current node" in the source tree
5355 * @inst: the element node of the xsl:for-each instruction
5356 * @castedComp: the compiled information of the instruction
5358 * Process the xslt for-each node on the source node
5361 xsltForEach(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5362 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
5364 #ifdef XSLT_REFACTORED
5365 xsltStyleItemForEachPtr comp
= (xsltStyleItemForEachPtr
) castedComp
;
5367 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
5370 xmlXPathObjectPtr res
= NULL
;
5371 xmlNodePtr cur
, curInst
;
5372 xmlNodeSetPtr list
= NULL
;
5373 xmlNodeSetPtr oldList
;
5374 int oldXPProximityPosition
, oldXPContextSize
;
5375 xmlNodePtr oldContextNode
;
5376 xsltTemplatePtr oldCurTemplRule
;
5378 xsltDocumentPtr oldDocInfo
;
5379 xmlXPathContextPtr xpctxt
;
5381 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
)) {
5382 xsltGenericError(xsltGenericErrorContext
,
5383 "xsltForEach(): Bad arguments.\n");
5388 xsltTransformError(ctxt
, NULL
, inst
,
5389 "Internal error in xsltForEach(): "
5390 "The XSLT 'for-each' instruction was not compiled.\n");
5393 if ((comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
5394 xsltTransformError(ctxt
, NULL
, inst
,
5395 "Internal error in xsltForEach(): "
5396 "The selecting expression of the XSLT 'for-each' "
5397 "instruction was not compiled correctly.\n");
5400 xpctxt
= ctxt
->xpathCtxt
;
5402 #ifdef WITH_XSLT_DEBUG_PROCESS
5403 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5404 "xsltForEach: select %s\n", comp
->select
));
5408 * Save context states.
5410 oldDocInfo
= ctxt
->document
;
5411 oldList
= ctxt
->nodeList
;
5412 oldContextNode
= ctxt
->node
;
5414 * The "current template rule" is cleared for the instantiation of
5417 oldCurTemplRule
= ctxt
->currentTemplateRule
;
5418 ctxt
->currentTemplateRule
= NULL
;
5420 oldXPDoc
= xpctxt
->doc
;
5421 oldXPProximityPosition
= xpctxt
->proximityPosition
;
5422 oldXPContextSize
= xpctxt
->contextSize
;
5425 * Evaluate the 'select' expression.
5427 res
= xsltPreCompEval(ctxt
, contextNode
, comp
);
5430 if (res
->type
== XPATH_NODESET
)
5431 list
= res
->nodesetval
;
5433 xsltTransformError(ctxt
, NULL
, inst
,
5434 "The 'select' expression does not evaluate to a node set.\n");
5436 #ifdef WITH_XSLT_DEBUG_PROCESS
5437 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5438 "xsltForEach: select didn't evaluate to a node list\n"));
5443 xsltTransformError(ctxt
, NULL
, inst
,
5444 "Failed to evaluate the 'select' expression.\n");
5445 ctxt
->state
= XSLT_STATE_STOPPED
;
5449 if ((list
== NULL
) || (list
->nodeNr
<= 0))
5452 #ifdef WITH_XSLT_DEBUG_PROCESS
5453 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5454 "xsltForEach: select evaluates to %d nodes\n", list
->nodeNr
));
5458 * Set the list; this has to be done already here for xsltDoSortFunction().
5460 ctxt
->nodeList
= list
;
5462 * Handle xsl:sort instructions and skip them for further processing.
5463 * BUG TODO: We are not using namespaced potentially defined on the
5464 * xsl:sort element; XPath expression might fail.
5466 curInst
= inst
->children
;
5467 if (IS_XSLT_ELEM(curInst
) && IS_XSLT_NAME(curInst
, "sort")) {
5469 xmlNodePtr sorts
[XSLT_MAX_SORT
];
5471 sorts
[nbsorts
++] = curInst
;
5473 #ifdef WITH_DEBUGGER
5474 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5475 xslHandleDebugger(curInst
, contextNode
, NULL
, ctxt
);
5478 curInst
= curInst
->next
;
5479 while (IS_XSLT_ELEM(curInst
) && IS_XSLT_NAME(curInst
, "sort")) {
5480 if (nbsorts
>= XSLT_MAX_SORT
) {
5481 xsltTransformError(ctxt
, NULL
, curInst
,
5482 "The number of xsl:sort instructions exceeds the "
5483 "maximum (%d) allowed by this processor.\n",
5487 sorts
[nbsorts
++] = curInst
;
5490 #ifdef WITH_DEBUGGER
5491 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5492 xslHandleDebugger(curInst
, contextNode
, NULL
, ctxt
);
5494 curInst
= curInst
->next
;
5496 xsltDoSortFunction(ctxt
, sorts
, nbsorts
);
5498 xpctxt
->contextSize
= list
->nodeNr
;
5500 * Instantiate the sequence constructor for each selected node.
5502 for (i
= 0; i
< list
->nodeNr
; i
++) {
5503 cur
= list
->nodeTab
[i
];
5505 * The selected node becomes the "current node".
5509 * An xsl:for-each can change the current context doc.
5510 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5512 if ((cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->doc
!= NULL
))
5513 xpctxt
->doc
= cur
->doc
;
5515 xpctxt
->proximityPosition
= i
+ 1;
5517 xsltApplySequenceConstructor(ctxt
, cur
, curInst
, NULL
);
5523 xmlXPathFreeObject(res
);
5525 * Restore old states.
5527 ctxt
->document
= oldDocInfo
;
5528 ctxt
->nodeList
= oldList
;
5529 ctxt
->node
= oldContextNode
;
5530 ctxt
->currentTemplateRule
= oldCurTemplRule
;
5532 xpctxt
->doc
= oldXPDoc
;
5533 xpctxt
->contextSize
= oldXPContextSize
;
5534 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5537 /************************************************************************
5539 * Generic interface *
5541 ************************************************************************/
5543 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5544 typedef struct xsltHTMLVersion
{
5545 const char *version
;
5550 static xsltHTMLVersion xsltHTMLVersions
[] = {
5551 { "5", NULL
, "about:legacy-compat" },
5552 { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5553 "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
5554 { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
5555 "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
5556 { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5557 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5558 { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
5559 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5560 { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
5561 "http://www.w3.org/TR/html4/strict.dtd"},
5562 { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5563 "http://www.w3.org/TR/html4/loose.dtd"},
5564 { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5565 "http://www.w3.org/TR/html4/frameset.dtd"},
5566 { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
5567 "http://www.w3.org/TR/html4/loose.dtd"},
5568 { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL
}
5573 * @version: the version string
5574 * @publicID: used to return the public ID
5575 * @systemID: used to return the system ID
5577 * Returns -1 if not found, 0 otherwise and the system and public
5578 * Identifier for this given verion of HTML
5581 xsltGetHTMLIDs(const xmlChar
*version
, const xmlChar
**publicID
,
5582 const xmlChar
**systemID
) {
5584 if (version
== NULL
)
5586 for (i
= 0;i
< (sizeof(xsltHTMLVersions
)/sizeof(xsltHTMLVersions
[1]));
5588 if (!xmlStrcasecmp(version
,
5589 (const xmlChar
*) xsltHTMLVersions
[i
].version
)) {
5590 if (publicID
!= NULL
)
5591 *publicID
= (const xmlChar
*) xsltHTMLVersions
[i
].public;
5592 if (systemID
!= NULL
)
5593 *systemID
= (const xmlChar
*) xsltHTMLVersions
[i
].system
;
5602 * xsltApplyStripSpaces:
5603 * @ctxt: a XSLT process context
5604 * @node: the root of the XML tree
5606 * Strip the unwanted ignorable spaces from the input tree
5609 xsltApplyStripSpaces(xsltTransformContextPtr ctxt
, xmlNodePtr node
) {
5611 #ifdef WITH_XSLT_DEBUG_PROCESS
5617 while (current
!= NULL
) {
5619 * Cleanup children empty nodes if asked for
5621 if ((IS_XSLT_REAL_NODE(current
)) &&
5622 (current
->children
!= NULL
) &&
5623 (xsltFindElemSpaceHandling(ctxt
, current
))) {
5624 xmlNodePtr
delete = NULL
, cur
= current
->children
;
5626 while (cur
!= NULL
) {
5627 if (IS_BLANK_NODE(cur
))
5631 if (delete != NULL
) {
5632 xmlUnlinkNode(delete);
5633 xmlFreeNode(delete);
5635 #ifdef WITH_XSLT_DEBUG_PROCESS
5643 * Skip to next node in document order.
5645 if (node
->type
== XML_ENTITY_REF_NODE
) {
5646 /* process deep in entities */
5647 xsltApplyStripSpaces(ctxt
, node
->children
);
5649 if ((current
->children
!= NULL
) &&
5650 (current
->type
!= XML_ENTITY_REF_NODE
)) {
5651 current
= current
->children
;
5652 } else if (current
->next
!= NULL
) {
5653 current
= current
->next
;
5656 current
= current
->parent
;
5657 if (current
== NULL
)
5659 if (current
== node
)
5661 if (current
->next
!= NULL
) {
5662 current
= current
->next
;
5665 } while (current
!= NULL
);
5670 #ifdef WITH_XSLT_DEBUG_PROCESS
5671 XSLT_TRACE(ctxt
,XSLT_TRACE_STRIP_SPACES
,xsltGenericDebug(xsltGenericDebugContext
,
5672 "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb
));
5678 xsltCountKeys(xsltTransformContextPtr ctxt
)
5680 xsltStylesheetPtr style
;
5687 * Do we have those nastly templates with a key() in the match pattern?
5689 ctxt
->hasTemplKeyPatterns
= 0;
5690 style
= ctxt
->style
;
5691 while (style
!= NULL
) {
5692 if (style
->keyMatch
!= NULL
) {
5693 ctxt
->hasTemplKeyPatterns
= 1;
5696 style
= xsltNextImport(style
);
5699 * Count number of key declarations.
5702 style
= ctxt
->style
;
5703 while (style
!= NULL
) {
5709 style
= xsltNextImport(style
);
5711 return(ctxt
->nbKeys
);
5715 * xsltApplyStylesheetInternal:
5716 * @style: a parsed XSLT stylesheet
5717 * @doc: a parsed XML document
5718 * @params: a NULL terminated array of parameters names/values tuples
5719 * @output: the targetted output
5720 * @profile: profile FILE * output or NULL
5721 * @user: user provided parameter
5723 * Apply the stylesheet to the document
5724 * NOTE: This may lead to a non-wellformed output XML wise !
5726 * Returns the result document or NULL in case of error
5729 xsltApplyStylesheetInternal(xsltStylesheetPtr style
, xmlDocPtr doc
,
5730 const char **params
, const char *output
,
5731 FILE * profile
, xsltTransformContextPtr userCtxt
)
5733 xmlDocPtr res
= NULL
;
5734 xsltTransformContextPtr ctxt
= NULL
;
5735 xmlNodePtr root
, node
;
5736 const xmlChar
*method
;
5737 const xmlChar
*doctypePublic
;
5738 const xmlChar
*doctypeSystem
;
5739 const xmlChar
*version
;
5740 const xmlChar
*encoding
;
5741 xsltStackElemPtr variables
;
5742 xsltStackElemPtr vptr
;
5746 if ((style
== NULL
) || (doc
== NULL
))
5749 if (style
->internalized
== 0) {
5750 #ifdef WITH_XSLT_DEBUG
5751 xsltGenericDebug(xsltGenericDebugContext
,
5752 "Stylesheet was not fully internalized !\n");
5755 if (doc
->intSubset
!= NULL
) {
5757 * Avoid hitting the DTD when scanning nodes
5758 * but keep it linked as doc->intSubset
5760 xmlNodePtr cur
= (xmlNodePtr
) doc
->intSubset
;
5761 if (cur
->next
!= NULL
)
5762 cur
->next
->prev
= cur
->prev
;
5763 if (cur
->prev
!= NULL
)
5764 cur
->prev
->next
= cur
->next
;
5765 if (doc
->children
== cur
)
5766 doc
->children
= cur
->next
;
5767 if (doc
->last
== cur
)
5768 doc
->last
= cur
->prev
;
5769 cur
->prev
= cur
->next
= NULL
;
5773 * Check for XPath document order availability
5775 root
= xmlDocGetRootElement(doc
);
5777 if (((ptrdiff_t) root
->content
>= 0) &&
5778 (xslDebugStatus
== XSLT_DEBUG_NONE
))
5779 xmlXPathOrderDocElems(doc
);
5782 if (userCtxt
!= NULL
)
5785 ctxt
= xsltNewTransformContext(style
, doc
);
5790 ctxt
->initialContextDoc
= doc
;
5791 ctxt
->initialContextNode
= (xmlNodePtr
) doc
;
5793 if (profile
!= NULL
) {
5794 #ifdef WITH_PROFILER
5797 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
5798 "xsltApplyStylesheetInternal: "
5799 "libxslt compiled without profiler\n");
5805 ctxt
->outputFile
= output
;
5807 ctxt
->outputFile
= NULL
;
5810 * internalize the modes if needed
5812 if (ctxt
->dict
!= NULL
) {
5813 if (ctxt
->mode
!= NULL
)
5814 ctxt
->mode
= xmlDictLookup(ctxt
->dict
, ctxt
->mode
, -1);
5815 if (ctxt
->modeURI
!= NULL
)
5816 ctxt
->modeURI
= xmlDictLookup(ctxt
->dict
, ctxt
->modeURI
, -1);
5819 XSLT_GET_IMPORT_PTR(method
, style
, method
)
5820 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
5821 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
5822 XSLT_GET_IMPORT_PTR(version
, style
, version
)
5823 XSLT_GET_IMPORT_PTR(encoding
, style
, encoding
)
5825 if ((method
!= NULL
) &&
5826 (!xmlStrEqual(method
, (const xmlChar
*) "xml")))
5828 if (xmlStrEqual(method
, (const xmlChar
*) "html")) {
5829 ctxt
->type
= XSLT_OUTPUT_HTML
;
5830 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
5831 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5833 if (version
== NULL
) {
5836 res
= htmlNewDoc(NULL
, NULL
);
5838 * Make sure no DTD node is generated in this case
5841 dtd
= xmlGetIntSubset(res
);
5843 xmlUnlinkNode((xmlNodePtr
) dtd
);
5846 res
->intSubset
= NULL
;
5847 res
->extSubset
= NULL
;
5851 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5852 xsltGetHTMLIDs(version
, &doctypePublic
, &doctypeSystem
);
5854 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5859 res
->dict
= ctxt
->dict
;
5860 xmlDictReference(res
->dict
);
5862 #ifdef WITH_XSLT_DEBUG
5863 xsltGenericDebug(xsltGenericDebugContext
,
5864 "reusing transformation dict for output\n");
5866 } else if (xmlStrEqual(method
, (const xmlChar
*) "xhtml")) {
5867 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
5868 "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n");
5869 ctxt
->type
= XSLT_OUTPUT_HTML
;
5870 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5873 res
->dict
= ctxt
->dict
;
5874 xmlDictReference(res
->dict
);
5876 #ifdef WITH_XSLT_DEBUG
5877 xsltGenericDebug(xsltGenericDebugContext
,
5878 "reusing transformation dict for output\n");
5880 } else if (xmlStrEqual(method
, (const xmlChar
*) "text")) {
5881 ctxt
->type
= XSLT_OUTPUT_TEXT
;
5882 res
= xmlNewDoc(style
->version
);
5885 res
->dict
= ctxt
->dict
;
5886 xmlDictReference(res
->dict
);
5888 #ifdef WITH_XSLT_DEBUG
5889 xsltGenericDebug(xsltGenericDebugContext
,
5890 "reusing transformation dict for output\n");
5893 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
5894 "xsltApplyStylesheetInternal: unsupported method (%s)\n",
5899 ctxt
->type
= XSLT_OUTPUT_XML
;
5900 res
= xmlNewDoc(style
->version
);
5903 res
->dict
= ctxt
->dict
;
5904 xmlDictReference(ctxt
->dict
);
5905 #ifdef WITH_XSLT_DEBUG
5906 xsltGenericDebug(xsltGenericDebugContext
,
5907 "reusing transformation dict for output\n");
5910 res
->charset
= XML_CHAR_ENCODING_UTF8
;
5911 if (encoding
!= NULL
)
5912 res
->encoding
= xmlStrdup(encoding
);
5913 variables
= style
->variables
;
5915 ctxt
->node
= (xmlNodePtr
) doc
;
5918 ctxt
->xpathCtxt
->contextSize
= 1;
5919 ctxt
->xpathCtxt
->proximityPosition
= 1;
5920 ctxt
->xpathCtxt
->node
= NULL
; /* TODO: Set the context node here? */
5923 * Start the evaluation, evaluate the params, the stylesheets globals
5924 * and start by processing the top node.
5926 if (xsltNeedElemSpaceHandling(ctxt
))
5927 xsltApplyStripSpaces(ctxt
, xmlDocGetRootElement(doc
));
5929 * Evaluate global params and user-provided params.
5931 if (ctxt
->globalVars
== NULL
)
5932 ctxt
->globalVars
= xmlHashCreate(20);
5933 if (params
!= NULL
) {
5934 xsltEvalUserParams(ctxt
, params
);
5937 /* need to be called before evaluating global variables */
5938 xsltCountKeys(ctxt
);
5940 xsltEvalGlobalVariables(ctxt
);
5942 /* Clean up any unused RVTs. */
5943 xsltReleaseLocalRVTs(ctxt
, NULL
);
5945 ctxt
->insert
= (xmlNodePtr
) res
;
5946 ctxt
->varsBase
= ctxt
->varsNr
- 1;
5949 * Start processing the source tree -----------------------------------
5951 xsltProcessOneNode(ctxt
, ctxt
->node
, NULL
);
5953 * Remove all remaining vars from the stack.
5955 xsltLocalVariablePop(ctxt
, 0, -2);
5956 xsltShutdownCtxtExts(ctxt
);
5958 xsltCleanupTemplates(style
); /* TODO: <- style should be read only */
5961 * Now cleanup our variables so stylesheet can be re-used
5963 * TODO: this is not needed anymore global variables are copied
5964 * and not evaluated directly anymore, keep this as a check
5966 if (style
->variables
!= variables
) {
5967 vptr
= style
->variables
;
5968 while (vptr
->next
!= variables
)
5971 xsltFreeStackElemList(style
->variables
);
5972 style
->variables
= variables
;
5974 vptr
= style
->variables
;
5975 while (vptr
!= NULL
) {
5976 if (vptr
->computed
) {
5977 if (vptr
->value
!= NULL
) {
5978 xmlXPathFreeObject(vptr
->value
);
5987 * code disabled by wmb; awaiting kb's review
5988 * problem is that global variable(s) may contain xpath objects
5989 * from doc associated with RVT, so can't be freed at this point.
5990 * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
5991 * I assume this shouldn't be required at this point.
5994 * Free all remaining tree fragments.
5999 * Do some post processing work depending on the generated output
6001 root
= xmlDocGetRootElement(res
);
6003 const xmlChar
*doctype
= NULL
;
6005 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
))
6006 doctype
= xmlDictQLookup(ctxt
->dict
, root
->ns
->prefix
, root
->name
);
6007 if (doctype
== NULL
)
6008 doctype
= root
->name
;
6011 * Apply the default selection of the method
6013 if ((method
== NULL
) &&
6014 (root
->ns
== NULL
) &&
6015 (!xmlStrcasecmp(root
->name
, (const xmlChar
*) "html"))) {
6018 tmp
= res
->children
;
6019 while ((tmp
!= NULL
) && (tmp
!= root
)) {
6020 if (tmp
->type
== XML_ELEMENT_NODE
)
6022 if ((tmp
->type
== XML_TEXT_NODE
) && (!xmlIsBlankNode(tmp
)))
6027 ctxt
->type
= XSLT_OUTPUT_HTML
;
6029 * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
6030 * transformation on the doc, but functions like
6032 res
->type
= XML_HTML_DOCUMENT_NODE
;
6033 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
6034 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
6037 #ifdef XSLT_GENERATE_HTML_DOCTYPE
6038 } else if (version
!= NULL
) {
6039 xsltGetHTMLIDs(version
, &doctypePublic
,
6041 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
6043 xmlCreateIntSubset(res
, doctype
,
6051 if (ctxt
->type
== XSLT_OUTPUT_XML
) {
6052 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
6053 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
6054 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
6056 /* Need a small "hack" here to assure DTD comes before
6057 possible comment nodes */
6058 node
= res
->children
;
6060 res
->children
= NULL
;
6062 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
6065 if (res
->children
!= NULL
) {
6066 res
->children
->next
= node
;
6067 node
->prev
= res
->children
;
6070 res
->children
= node
;
6076 xmlXPathFreeNodeSet(ctxt
->nodeList
);
6078 #ifdef WITH_PROFILER
6079 if (profile
!= NULL
) {
6080 xsltSaveProfiling(ctxt
, profile
);
6087 if ((ctxt
!= NULL
) && (ctxt
->state
!= XSLT_STATE_OK
)) {
6091 if ((res
!= NULL
) && (ctxt
!= NULL
) && (output
!= NULL
)) {
6094 ret
= xsltCheckWrite(ctxt
->sec
, ctxt
, (const xmlChar
*) output
);
6096 xsltTransformError(ctxt
, NULL
, NULL
,
6097 "xsltApplyStylesheet: forbidden to save to %s\n",
6099 } else if (ret
< 0) {
6100 xsltTransformError(ctxt
, NULL
, NULL
,
6101 "xsltApplyStylesheet: saving to %s may not be possible\n",
6106 #ifdef XSLT_DEBUG_PROFILE_CACHE
6107 printf("# Cache:\n");
6108 printf("# Reused tree fragments: %d\n", ctxt
->cache
->dbgReusedRVTs
);
6109 printf("# Reused variables : %d\n", ctxt
->cache
->dbgReusedVars
);
6112 if ((ctxt
!= NULL
) && (userCtxt
== NULL
))
6113 xsltFreeTransformContext(ctxt
);
6121 #ifdef XSLT_DEBUG_PROFILE_CACHE
6122 printf("# Cache:\n");
6123 printf("# Reused tree fragments: %d\n", ctxt
->cache
->dbgReusedRVTs
);
6124 printf("# Reused variables : %d\n", ctxt
->cache
->dbgReusedVars
);
6127 if ((ctxt
!= NULL
) && (userCtxt
== NULL
))
6128 xsltFreeTransformContext(ctxt
);
6133 * xsltApplyStylesheet:
6134 * @style: a parsed XSLT stylesheet
6135 * @doc: a parsed XML document
6136 * @params: a NULL terminated arry of parameters names/values tuples
6138 * Apply the stylesheet to the document
6139 * NOTE: This may lead to a non-wellformed output XML wise !
6141 * Returns the result document or NULL in case of error
6144 xsltApplyStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6145 const char **params
)
6147 return (xsltApplyStylesheetInternal(style
, doc
, params
, NULL
, NULL
, NULL
));
6151 * xsltProfileStylesheet:
6152 * @style: a parsed XSLT stylesheet
6153 * @doc: a parsed XML document
6154 * @params: a NULL terminated arry of parameters names/values tuples
6155 * @output: a FILE * for the profiling output
6157 * Apply the stylesheet to the document and dump the profiling to
6160 * Returns the result document or NULL in case of error
6163 xsltProfileStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6164 const char **params
, FILE * output
)
6168 res
= xsltApplyStylesheetInternal(style
, doc
, params
, NULL
, output
, NULL
);
6173 * xsltApplyStylesheetUser:
6174 * @style: a parsed XSLT stylesheet
6175 * @doc: a parsed XML document
6176 * @params: a NULL terminated array of parameters names/values tuples
6177 * @output: the targetted output
6178 * @profile: profile FILE * output or NULL
6179 * @userCtxt: user provided transform context
6181 * Apply the stylesheet to the document and allow the user to provide
6182 * its own transformation context.
6184 * Returns the result document or NULL in case of error
6187 xsltApplyStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
,
6188 const char **params
, const char *output
,
6189 FILE * profile
, xsltTransformContextPtr userCtxt
)
6193 res
= xsltApplyStylesheetInternal(style
, doc
, params
, output
,
6199 * xsltRunStylesheetUser:
6200 * @style: a parsed XSLT stylesheet
6201 * @doc: a parsed XML document
6202 * @params: a NULL terminated array of parameters names/values tuples
6203 * @output: the URL/filename ot the generated resource if available
6204 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6205 * @IObuf: an output buffer for progressive output (not implemented yet)
6206 * @profile: profile FILE * output or NULL
6207 * @userCtxt: user provided transform context
6209 * Apply the stylesheet to the document and generate the output according
6210 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6212 * NOTE: This may lead to a non-wellformed output XML wise !
6213 * NOTE: This may also result in multiple files being generated
6214 * NOTE: using IObuf, the result encoding used will be the one used for
6215 * creating the output buffer, use the following macro to read it
6216 * from the stylesheet
6217 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6218 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6219 * since the interface uses only UTF8
6221 * Returns the number of by written to the main resource or -1 in case of
6225 xsltRunStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
,
6226 const char **params
, const char *output
,
6227 xmlSAXHandlerPtr SAX
, xmlOutputBufferPtr IObuf
,
6228 FILE * profile
, xsltTransformContextPtr userCtxt
)
6233 if ((output
== NULL
) && (SAX
== NULL
) && (IObuf
== NULL
))
6235 if ((SAX
!= NULL
) && (IObuf
!= NULL
))
6238 /* unsupported yet */
6240 XSLT_TODO
/* xsltRunStylesheet xmlSAXHandlerPtr SAX */
6244 tmp
= xsltApplyStylesheetInternal(style
, doc
, params
, output
, profile
,
6247 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
6248 "xsltRunStylesheet : run failed\n");
6251 if (IObuf
!= NULL
) {
6252 /* TODO: incomplete, IObuf output not progressive */
6253 ret
= xsltSaveResultTo(IObuf
, tmp
, style
);
6255 ret
= xsltSaveResultToFilename(output
, tmp
, style
, 0);
6262 * xsltRunStylesheet:
6263 * @style: a parsed XSLT stylesheet
6264 * @doc: a parsed XML document
6265 * @params: a NULL terminated array of parameters names/values tuples
6266 * @output: the URL/filename ot the generated resource if available
6267 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6268 * @IObuf: an output buffer for progressive output (not implemented yet)
6270 * Apply the stylesheet to the document and generate the output according
6271 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6273 * NOTE: This may lead to a non-wellformed output XML wise !
6274 * NOTE: This may also result in multiple files being generated
6275 * NOTE: using IObuf, the result encoding used will be the one used for
6276 * creating the output buffer, use the following macro to read it
6277 * from the stylesheet
6278 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6279 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6280 * since the interface uses only UTF8
6282 * Returns the number of bytes written to the main resource or -1 in case of
6286 xsltRunStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6287 const char **params
, const char *output
,
6288 xmlSAXHandlerPtr SAX
, xmlOutputBufferPtr IObuf
)
6290 return(xsltRunStylesheetUser(style
, doc
, params
, output
, SAX
, IObuf
,
6295 xsltMessageWrapper(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
6296 xmlNodePtr inst
, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
) {
6297 xsltMessage(ctxt
, node
, inst
);
6301 * xsltRegisterAllElement:
6302 * @ctxt: the XPath context
6304 * Registers all default XSLT elements in this context
6307 xsltRegisterAllElement(xsltTransformContextPtr ctxt
)
6309 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "apply-templates",
6311 xsltApplyTemplates
);
6312 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "apply-imports",
6315 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "call-template",
6318 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "element",
6321 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "attribute",
6324 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "text",
6327 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "processing-instruction",
6329 xsltProcessingInstruction
);
6330 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "comment",
6333 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "copy",
6336 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "value-of",
6339 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "number",
6342 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "for-each",
6345 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "if",
6348 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "choose",
6351 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "sort",
6354 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "copy-of",
6357 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "message",
6359 xsltMessageWrapper
);
6362 * Those don't have callable entry points but are registered anyway
6364 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "variable",
6367 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "param",
6370 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "with-param",
6373 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "decimal-format",
6376 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "when",
6379 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "otherwise",
6382 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "fallback",