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
28 #define XSLT_GENERATE_HTML_DOCTYPE
29 #ifdef XSLT_GENERATE_HTML_DOCTYPE
30 static int xsltGetHTMLIDs(const xmlChar
*version
, const xmlChar
**publicID
,
31 const xmlChar
**systemID
);
34 int xsltMaxDepth
= 3000;
35 int xsltMaxVars
= 15000;
42 # define FALSE (0 == 1)
43 # define TRUE (!FALSE)
46 #define IS_BLANK_NODE(n) \
47 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
51 * Forward declarations
55 xsltCopyNamespaceListInternal(xmlNodePtr node
, xmlNsPtr cur
);
58 xsltCopyTreeInternal(xsltTransformContextPtr ctxt
,
61 xmlNodePtr insert
, int isLRE
, int topElemVisited
);
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];
202 * @ctxt: the transformation context
203 * @value: the profiling value to push on the stack
205 * Push a profiling value on the stack
207 * Returns the new index in the stack or 0 in case of error
210 profPush(xsltTransformContextPtr ctxt
, long value
)
212 if (ctxt
->profMax
== 0) {
215 (long *) xmlMalloc(ctxt
->profMax
* sizeof(ctxt
->profTab
[0]));
216 if (ctxt
->profTab
== NULL
) {
217 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
221 else if (ctxt
->profNr
>= ctxt
->profMax
) {
224 (long *) xmlRealloc(ctxt
->profTab
,
225 ctxt
->profMax
* sizeof(ctxt
->profTab
[0]));
226 if (ctxt
->profTab
== NULL
) {
227 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
231 ctxt
->profTab
[ctxt
->profNr
] = value
;
233 return (ctxt
->profNr
++);
237 * @ctxt: the transformation context
239 * Pop a profiling value from the stack
241 * Returns the stored profiling value
244 profPop(xsltTransformContextPtr ctxt
)
248 if (ctxt
->profNr
<= 0)
251 if (ctxt
->profNr
> 0)
252 ctxt
->prof
= ctxt
->profTab
[ctxt
->profNr
- 1];
254 ctxt
->prof
= (long) 0;
255 ret
= ctxt
->profTab
[ctxt
->profNr
];
256 ctxt
->profTab
[ctxt
->profNr
] = 0;
261 profCallgraphAdd(xsltTemplatePtr templ
, xsltTemplatePtr parent
)
265 if (templ
->templMax
== 0) {
267 templ
->templCalledTab
=
268 (xsltTemplatePtr
*) xmlMalloc(templ
->templMax
*
269 sizeof(templ
->templCalledTab
[0]));
270 templ
->templCountTab
=
271 (int *) xmlMalloc(templ
->templMax
*
272 sizeof(templ
->templCountTab
[0]));
273 if (templ
->templCalledTab
== NULL
|| templ
->templCountTab
== NULL
) {
274 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
278 else if (templ
->templNr
>= templ
->templMax
) {
279 templ
->templMax
*= 2;
280 templ
->templCalledTab
=
281 (xsltTemplatePtr
*) xmlRealloc(templ
->templCalledTab
,
283 sizeof(templ
->templCalledTab
[0]));
284 templ
->templCountTab
=
285 (int *) xmlRealloc(templ
->templCountTab
,
287 sizeof(templ
->templCountTab
[0]));
288 if (templ
->templCalledTab
== NULL
|| templ
->templCountTab
== NULL
) {
289 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
294 for (i
= 0; i
< templ
->templNr
; i
++) {
295 if (templ
->templCalledTab
[i
] == parent
) {
296 templ
->templCountTab
[i
]++;
300 if (i
== templ
->templNr
) {
301 /* not found, add new one */
302 templ
->templCalledTab
[templ
->templNr
] = parent
;
303 templ
->templCountTab
[templ
->templNr
] = 1;
308 /************************************************************************
310 * XInclude default settings *
312 ************************************************************************/
314 static int xsltDoXIncludeDefault
= 0;
317 * xsltSetXIncludeDefault:
318 * @xinclude: whether to do XInclude processing
320 * Set whether XInclude should be processed on document being loaded by default
323 xsltSetXIncludeDefault(int xinclude
) {
324 xsltDoXIncludeDefault
= (xinclude
!= 0);
328 * xsltGetXIncludeDefault:
330 * Provides the default state for XInclude processing
332 * Returns 0 if there is no processing 1 otherwise
335 xsltGetXIncludeDefault(void) {
336 return(xsltDoXIncludeDefault
);
339 unsigned long xsltDefaultTrace
= (unsigned long) XSLT_TRACE_ALL
;
342 * xsltDebugSetDefaultTrace:
343 * @val: tracing level mask
345 * Set the default debug tracing level mask
347 void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val
) {
348 xsltDefaultTrace
= val
;
352 * xsltDebugGetDefaultTrace:
354 * Get the current default debug tracing level mask
356 * Returns the current default debug tracing level mask
358 xsltDebugTraceCodes
xsltDebugGetDefaultTrace() {
359 return xsltDefaultTrace
;
362 /************************************************************************
364 * Handling of Transformation Contexts *
366 ************************************************************************/
368 static xsltTransformCachePtr
369 xsltTransformCacheCreate(void)
371 xsltTransformCachePtr ret
;
373 ret
= (xsltTransformCachePtr
) xmlMalloc(sizeof(xsltTransformCache
));
375 xsltTransformError(NULL
, NULL
, NULL
,
376 "xsltTransformCacheCreate : malloc failed\n");
379 memset(ret
, 0, sizeof(xsltTransformCache
));
384 xsltTransformCacheFree(xsltTransformCachePtr cache
)
389 * Free tree fragments.
392 xmlDocPtr tmp
, cur
= cache
->RVT
;
395 cur
= (xmlDocPtr
) cur
->next
;
396 if (tmp
->_private
!= NULL
) {
398 * Tree the document info.
400 xsltFreeDocumentKeys((xsltDocumentPtr
) tmp
->_private
);
401 xmlFree(tmp
->_private
);
409 if (cache
->stackItems
) {
410 xsltStackElemPtr tmp
, cur
= cache
->stackItems
;
415 * REVISIT TODO: Should be call a destruction-function
425 * xsltNewTransformContext:
426 * @style: a parsed XSLT stylesheet
427 * @doc: the input document
429 * Create a new XSLT TransformContext
431 * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
433 xsltTransformContextPtr
434 xsltNewTransformContext(xsltStylesheetPtr style
, xmlDocPtr doc
) {
435 xsltTransformContextPtr cur
;
436 xsltDocumentPtr docu
;
441 cur
= (xsltTransformContextPtr
) xmlMalloc(sizeof(xsltTransformContext
));
443 xsltTransformError(NULL
, NULL
, (xmlNodePtr
)doc
,
444 "xsltNewTransformContext : malloc failed\n");
447 memset(cur
, 0, sizeof(xsltTransformContext
));
449 cur
->cache
= xsltTransformCacheCreate();
450 if (cur
->cache
== NULL
)
453 * setup of the dictionary must be done early as some of the
454 * processing later like key handling may need it.
456 cur
->dict
= xmlDictCreateSub(style
->dict
);
457 cur
->internalized
= ((style
->internalized
) && (cur
->dict
!= NULL
));
458 #ifdef WITH_XSLT_DEBUG
459 xsltGenericDebug(xsltGenericDebugContext
,
460 "Creating sub-dictionary from stylesheet for transformation\n");
464 * initialize the template stack
466 cur
->templTab
= (xsltTemplatePtr
*)
467 xmlMalloc(10 * sizeof(xsltTemplatePtr
));
468 if (cur
->templTab
== NULL
) {
469 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
470 "xsltNewTransformContext: out of memory\n");
476 cur
->maxTemplateDepth
= xsltMaxDepth
;
479 * initialize the variables stack
481 cur
->varsTab
= (xsltStackElemPtr
*)
482 xmlMalloc(10 * sizeof(xsltStackElemPtr
));
483 if (cur
->varsTab
== NULL
) {
484 xmlGenericError(xmlGenericErrorContext
,
485 "xsltNewTransformContext: out of memory\n");
492 cur
->maxTemplateVars
= xsltMaxVars
;
495 * the profiling stack is not initialized by default
504 cur
->xpathCtxt
= xmlXPathNewContext(doc
);
505 if (cur
->xpathCtxt
== NULL
) {
506 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
507 "xsltNewTransformContext : xmlXPathNewContext failed\n");
511 * Create an XPath cache.
513 if (xmlXPathContextSetCache(cur
->xpathCtxt
, 1, -1, 0) == -1)
516 * Initialize the extras array
518 if (style
->extrasNr
!= 0) {
519 cur
->extrasMax
= style
->extrasNr
+ 20;
520 cur
->extras
= (xsltRuntimeExtraPtr
)
521 xmlMalloc(cur
->extrasMax
* sizeof(xsltRuntimeExtra
));
522 if (cur
->extras
== NULL
) {
523 xmlGenericError(xmlGenericErrorContext
,
524 "xsltNewTransformContext: out of memory\n");
527 cur
->extrasNr
= style
->extrasNr
;
528 for (i
= 0;i
< cur
->extrasMax
;i
++) {
529 cur
->extras
[i
].info
= NULL
;
530 cur
->extras
[i
].deallocate
= NULL
;
531 cur
->extras
[i
].val
.ptr
= NULL
;
539 XSLT_REGISTER_VARIABLE_LOOKUP(cur
);
540 XSLT_REGISTER_FUNCTION_LOOKUP(cur
);
541 cur
->xpathCtxt
->nsHash
= style
->nsHash
;
543 * Initialize the registered external modules
545 xsltInitCtxtExts(cur
);
547 * Setup document element ordering for later efficiencies
550 if (xslDebugStatus
== XSLT_DEBUG_NONE
)
551 xmlXPathOrderDocElems(doc
);
553 * Must set parserOptions before calling xsltNewDocument
556 cur
->parserOptions
= XSLT_PARSE_OPTIONS
;
557 docu
= xsltNewDocument(cur
, doc
);
559 xsltTransformError(cur
, NULL
, (xmlNodePtr
)doc
,
560 "xsltNewTransformContext : xsltNewDocument failed\n");
564 cur
->document
= docu
;
566 cur
->outputFile
= NULL
;
567 cur
->sec
= xsltGetDefaultSecurityPrefs();
568 cur
->debugStatus
= xslDebugStatus
;
569 cur
->traceCode
= (unsigned long*) &xsltDefaultTrace
;
570 cur
->xinclude
= xsltGetXIncludeDefault();
571 cur
->keyInitLevel
= 0;
577 xsltFreeTransformContext(cur
);
582 * xsltFreeTransformContext:
583 * @ctxt: an XSLT parser context
585 * Free up the memory allocated by @ctxt
588 xsltFreeTransformContext(xsltTransformContextPtr ctxt
) {
593 * Shutdown the extension modules associated to the stylesheet
596 xsltShutdownCtxtExts(ctxt
);
598 if (ctxt
->xpathCtxt
!= NULL
) {
599 ctxt
->xpathCtxt
->nsHash
= NULL
;
600 xmlXPathFreeContext(ctxt
->xpathCtxt
);
602 if (ctxt
->templTab
!= NULL
)
603 xmlFree(ctxt
->templTab
);
604 if (ctxt
->varsTab
!= NULL
)
605 xmlFree(ctxt
->varsTab
);
606 if (ctxt
->profTab
!= NULL
)
607 xmlFree(ctxt
->profTab
);
608 if ((ctxt
->extrasNr
> 0) && (ctxt
->extras
!= NULL
)) {
611 for (i
= 0;i
< ctxt
->extrasNr
;i
++) {
612 if ((ctxt
->extras
[i
].deallocate
!= NULL
) &&
613 (ctxt
->extras
[i
].info
!= NULL
))
614 ctxt
->extras
[i
].deallocate(ctxt
->extras
[i
].info
);
616 xmlFree(ctxt
->extras
);
618 xsltFreeGlobalVariables(ctxt
);
619 xsltFreeDocuments(ctxt
);
620 xsltFreeCtxtExts(ctxt
);
622 xsltTransformCacheFree(ctxt
->cache
);
623 xmlDictFree(ctxt
->dict
);
624 #ifdef WITH_XSLT_DEBUG
625 xsltGenericDebug(xsltGenericDebugContext
,
626 "freeing transformation dictionary\n");
628 memset(ctxt
, -1, sizeof(xsltTransformContext
));
632 /************************************************************************
634 * Copy of Nodes in an XSLT fashion *
636 ************************************************************************/
638 xmlNodePtr
xsltCopyTree(xsltTransformContextPtr ctxt
,
639 xmlNodePtr node
, xmlNodePtr insert
, int literal
);
643 * @parent: the parent node
644 * @cur: the child node
646 * Wrapper version of xmlAddChild with a more consistent behaviour on
647 * error. One expect the use to be child = xsltAddChild(parent, child);
648 * and the routine will take care of not leaking on errors or node merge
650 * Returns the child is successfully attached or NULL if merged or freed
653 xsltAddChild(xmlNodePtr parent
, xmlNodePtr cur
) {
656 if ((cur
== NULL
) || (parent
== NULL
))
658 if (parent
== NULL
) {
662 ret
= xmlAddChild(parent
, cur
);
669 * @ctxt: a XSLT process context
670 * @target: the text node where the text will be attached
671 * @string: the text string
672 * @len: the string length in byte
674 * Extend the current text node with the new string, it handles coalescing
676 * Returns: the text node
679 xsltAddTextString(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
680 const xmlChar
*string
, int len
) {
684 if ((len
<= 0) || (string
== NULL
) || (target
== NULL
))
687 if (ctxt
->lasttext
== target
->content
) {
689 if (ctxt
->lasttuse
+ len
>= ctxt
->lasttsize
) {
693 size
= ctxt
->lasttsize
+ len
+ 100;
695 newbuf
= (xmlChar
*) xmlRealloc(target
->content
,size
);
696 if (newbuf
== NULL
) {
697 xsltTransformError(ctxt
, NULL
, target
,
698 "xsltCopyText: text allocation failed\n");
701 ctxt
->lasttsize
= size
;
702 ctxt
->lasttext
= newbuf
;
703 target
->content
= newbuf
;
705 memcpy(&(target
->content
[ctxt
->lasttuse
]), string
, len
);
706 ctxt
->lasttuse
+= len
;
707 target
->content
[ctxt
->lasttuse
] = 0;
709 xmlNodeAddContent(target
, string
);
710 ctxt
->lasttext
= target
->content
;
711 len
= xmlStrlen(target
->content
);
712 ctxt
->lasttsize
= len
;
713 ctxt
->lasttuse
= len
;
719 * xsltCopyTextString:
720 * @ctxt: a XSLT process context
721 * @target: the element where the text will be attached
722 * @string: the text string
723 * @noescape: should disable-escaping be activated for this text node.
725 * Adds @string to a newly created or an existent text node child of
728 * Returns: the text node, where the text content of @cur is copied to.
729 * NULL in case of API or internal errors.
732 xsltCopyTextString(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
733 const xmlChar
*string
, int noescape
)
741 #ifdef WITH_XSLT_DEBUG_PROCESS
742 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
743 "xsltCopyTextString: copy text %s\n",
748 * Play safe and reset the merging mechanism for every new
751 if ((target
== NULL
) || (target
->children
== NULL
)) {
752 ctxt
->lasttext
= NULL
;
755 /* handle coalescing of text nodes here */
756 len
= xmlStrlen(string
);
757 if ((ctxt
->type
== XSLT_OUTPUT_XML
) &&
758 (ctxt
->style
->cdataSection
!= NULL
) &&
760 (target
->type
== XML_ELEMENT_NODE
) &&
761 (((target
->ns
== NULL
) &&
762 (xmlHashLookup2(ctxt
->style
->cdataSection
,
763 target
->name
, NULL
) != NULL
)) ||
764 ((target
->ns
!= NULL
) &&
765 (xmlHashLookup2(ctxt
->style
->cdataSection
,
766 target
->name
, target
->ns
->href
) != NULL
))))
769 * Process "cdata-section-elements".
771 if ((target
->last
!= NULL
) &&
772 (target
->last
->type
== XML_CDATA_SECTION_NODE
))
774 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
776 copy
= xmlNewCDataBlock(ctxt
->output
, string
, len
);
777 } else if (noescape
) {
779 * Process "disable-output-escaping".
781 if ((target
!= NULL
) && (target
->last
!= NULL
) &&
782 (target
->last
->type
== XML_TEXT_NODE
) &&
783 (target
->last
->name
== xmlStringTextNoenc
))
785 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
787 copy
= xmlNewTextLen(string
, len
);
789 copy
->name
= xmlStringTextNoenc
;
792 * Default processing.
794 if ((target
!= NULL
) && (target
->last
!= NULL
) &&
795 (target
->last
->type
== XML_TEXT_NODE
) &&
796 (target
->last
->name
== xmlStringText
)) {
797 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
799 copy
= xmlNewTextLen(string
, len
);
803 copy
= xsltAddChild(target
, copy
);
804 ctxt
->lasttext
= copy
->content
;
805 ctxt
->lasttsize
= len
;
806 ctxt
->lasttuse
= len
;
808 xsltTransformError(ctxt
, NULL
, target
,
809 "xsltCopyTextString: text copy failed\n");
810 ctxt
->lasttext
= NULL
;
817 * @ctxt: a XSLT process context
818 * @target: the element where the text will be attached
819 * @cur: the text or CDATA node
820 * @interned: the string is in the target doc dictionary
822 * Copy the text content of @cur and append it to @target's children.
824 * Returns: the text node, where the text content of @cur is copied to.
825 * NULL in case of API or internal errors.
828 xsltCopyText(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
829 xmlNodePtr cur
, int interned
)
833 if ((cur
->type
!= XML_TEXT_NODE
) &&
834 (cur
->type
!= XML_CDATA_SECTION_NODE
))
836 if (cur
->content
== NULL
)
839 #ifdef WITH_XSLT_DEBUG_PROCESS
840 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
841 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
842 "xsltCopyText: copy CDATA text %s\n",
844 } else if (cur
->name
== xmlStringTextNoenc
) {
845 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
846 "xsltCopyText: copy unescaped text %s\n",
849 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
850 "xsltCopyText: copy text %s\n",
856 * Play save and reset the merging mechanism for every new
859 if ((target
== NULL
) || (target
->children
== NULL
)) {
860 ctxt
->lasttext
= NULL
;
863 if ((ctxt
->style
->cdataSection
!= NULL
) &&
864 (ctxt
->type
== XSLT_OUTPUT_XML
) &&
866 (target
->type
== XML_ELEMENT_NODE
) &&
867 (((target
->ns
== NULL
) &&
868 (xmlHashLookup2(ctxt
->style
->cdataSection
,
869 target
->name
, NULL
) != NULL
)) ||
870 ((target
->ns
!= NULL
) &&
871 (xmlHashLookup2(ctxt
->style
->cdataSection
,
872 target
->name
, target
->ns
->href
) != NULL
))))
875 * Process "cdata-section-elements".
878 * OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
881 * TODO: Since this doesn't merge adjacent CDATA-section nodes,
882 * we'll get: <![CDATA[x]]><!CDATA[y]]>.
883 * TODO: Reported in #321505.
885 if ((target
->last
!= NULL
) &&
886 (target
->last
->type
== XML_CDATA_SECTION_NODE
))
889 * Append to existing CDATA-section node.
891 copy
= xsltAddTextString(ctxt
, target
->last
, cur
->content
,
892 xmlStrlen(cur
->content
));
897 len
= xmlStrlen(cur
->content
);
898 copy
= xmlNewCDataBlock(ctxt
->output
, cur
->content
, len
);
901 ctxt
->lasttext
= copy
->content
;
902 ctxt
->lasttsize
= len
;
903 ctxt
->lasttuse
= len
;
905 } else if ((target
!= NULL
) &&
906 (target
->last
!= NULL
) &&
907 /* both escaped or both non-escaped text-nodes */
908 (((target
->last
->type
== XML_TEXT_NODE
) &&
909 (target
->last
->name
== cur
->name
)) ||
910 /* non-escaped text nodes and CDATA-section nodes */
911 (((target
->last
->type
== XML_CDATA_SECTION_NODE
) &&
912 (cur
->name
== xmlStringTextNoenc
)))))
915 * we are appending to an existing text node
917 copy
= xsltAddTextString(ctxt
, target
->last
, cur
->content
,
918 xmlStrlen(cur
->content
));
920 } else if ((interned
) && (target
!= NULL
) &&
921 (target
->doc
!= NULL
) &&
922 (target
->doc
->dict
== ctxt
->dict
))
925 * TODO: DO we want to use this also for "text" output?
927 copy
= xmlNewTextLen(NULL
, 0);
930 if (cur
->name
== xmlStringTextNoenc
)
931 copy
->name
= xmlStringTextNoenc
;
934 * Must confirm that content is in dict (bug 302821)
935 * TODO: This check should be not needed for text coming
936 * from the stylesheets
938 if (xmlDictOwns(ctxt
->dict
, cur
->content
))
939 copy
->content
= cur
->content
;
941 if ((copy
->content
= xmlStrdup(cur
->content
)) == NULL
)
946 * normal processing. keep counters to extend the text node
947 * in xsltAddTextString if needed.
951 len
= xmlStrlen(cur
->content
);
952 copy
= xmlNewTextLen(cur
->content
, len
);
955 if (cur
->name
== xmlStringTextNoenc
)
956 copy
->name
= xmlStringTextNoenc
;
957 ctxt
->lasttext
= copy
->content
;
958 ctxt
->lasttsize
= len
;
959 ctxt
->lasttuse
= len
;
962 if (target
!= NULL
) {
963 copy
->doc
= target
->doc
;
965 * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
966 * to ensure that the optimized text-merging mechanism
967 * won't interfere with normal node-merging in any case.
969 copy
= xsltAddChild(target
, copy
);
972 xsltTransformError(ctxt
, NULL
, target
,
973 "xsltCopyText: text copy failed\n");
977 if ((copy
== NULL
) || (copy
->content
== NULL
)) {
978 xsltTransformError(ctxt
, NULL
, target
,
979 "Internal error in xsltCopyText(): "
980 "Failed to copy the string.\n");
981 ctxt
->state
= XSLT_STATE_STOPPED
;
987 * xsltShallowCopyAttr:
988 * @ctxt: a XSLT process context
989 * @invocNode: responsible node in the stylesheet; used for error reports
990 * @target: the element where the attribute will be grafted
991 * @attr: the attribute to be copied
993 * Do a copy of an attribute.
995 * - xsltCopyTreeInternal()
999 * Returns: a new xmlAttrPtr, or NULL in case of error.
1002 xsltShallowCopyAttr(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1003 xmlNodePtr target
, xmlAttrPtr attr
)
1011 if (target
->type
!= XML_ELEMENT_NODE
) {
1012 xsltTransformError(ctxt
, NULL
, invocNode
,
1013 "Cannot add an attribute node to a non-element node.\n");
1017 if (target
->children
!= NULL
) {
1018 xsltTransformError(ctxt
, NULL
, invocNode
,
1019 "Attribute nodes must be added before "
1020 "any child nodes to an element.\n");
1024 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1025 if (attr
->ns
!= NULL
) {
1028 ns
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1029 attr
->ns
->href
, attr
->ns
->prefix
, target
);
1031 xsltTransformError(ctxt
, NULL
, invocNode
,
1032 "Namespace fixup error: Failed to acquire an in-scope "
1033 "namespace binding of the copied attribute '{%s}%s'.\n",
1034 attr
->ns
->href
, attr
->name
);
1036 * TODO: Should we just stop here?
1040 * Note that xmlSetNsProp() will take care of duplicates
1041 * and assigns the new namespace even to a duplicate.
1043 copy
= xmlSetNsProp(target
, ns
, attr
->name
, value
);
1045 copy
= xmlSetNsProp(target
, NULL
, attr
->name
, value
);
1055 * NOTE: This was optimized according to bug #342695.
1056 * TODO: Can this further be optimized, if source and target
1057 * share the same dict and attr->children is just 1 text node
1058 * which is in the dict? How probable is such a case?
1061 * TODO: Do we need to create an empty text node if the value
1062 * is the empty string?
1064 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1065 if (value
!= NULL
) {
1066 txtNode
= xmlNewDocText(target
->doc
, NULL
);
1067 if (txtNode
== NULL
)
1069 if ((target
->doc
!= NULL
) &&
1070 (target
->doc
->dict
!= NULL
))
1073 (xmlChar
*) xmlDictLookup(target
->doc
->dict
,
1074 BAD_CAST value
, -1);
1077 txtNode
->content
= value
;
1078 copy
->children
= txtNode
;
1086 * xsltCopyAttrListNoOverwrite:
1087 * @ctxt: a XSLT process context
1088 * @invocNode: responsible node in the stylesheet; used for error reports
1089 * @target: the element where the new attributes will be grafted
1090 * @attr: the first attribute in the list to be copied
1092 * Copies a list of attribute nodes, starting with @attr, over to the
1093 * @target element node.
1096 * - xsltCopyTreeInternal()
1098 * Returns 0 on success and -1 on errors and internal errors.
1101 xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt
,
1102 xmlNodePtr invocNode
,
1103 xmlNodePtr target
, xmlAttrPtr attr
)
1106 xmlNsPtr origNs
= NULL
, copyNs
= NULL
;
1110 * Don't use xmlCopyProp() here, since it will try to
1111 * reconciliate namespaces.
1113 while (attr
!= NULL
) {
1115 * Find a namespace node in the tree of @target.
1116 * Avoid searching for the same ns.
1118 if (attr
->ns
!= origNs
) {
1120 if (attr
->ns
!= NULL
) {
1121 copyNs
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1122 attr
->ns
->href
, attr
->ns
->prefix
, target
);
1129 * If attribute has a value, we need to copy it (watching out
1130 * for possible entities)
1132 if ((attr
->children
) && (attr
->children
->type
== XML_TEXT_NODE
) &&
1133 (attr
->children
->next
== NULL
)) {
1134 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
,
1135 attr
->children
->content
);
1136 } else if (attr
->children
!= NULL
) {
1137 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1138 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
, BAD_CAST value
);
1141 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
, NULL
);
1153 * xsltShallowCopyElem:
1154 * @ctxt: the XSLT process context
1155 * @node: the element node in the source tree
1156 * or the Literal Result Element
1157 * @insert: the parent in the result tree
1158 * @isLRE: if @node is a Literal Result Element
1160 * Make a copy of the element node @node
1161 * and insert it as last child of @insert.
1163 * URGENT TODO: The problem with this one (for the non-refactored code)
1164 * is that it is used for both, Literal Result Elements *and*
1165 * copying input nodes.
1167 * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
1170 * xsltApplySequenceConstructor()
1171 * (for Literal Result Elements - which is a problem)
1172 * xsltCopy() (for shallow-copying elements via xsl:copy)
1174 * Returns a pointer to the new node, or NULL in case of error
1177 xsltShallowCopyElem(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1178 xmlNodePtr insert
, int isLRE
)
1182 if ((node
->type
== XML_DTD_NODE
) || (insert
== NULL
))
1184 if ((node
->type
== XML_TEXT_NODE
) ||
1185 (node
->type
== XML_CDATA_SECTION_NODE
))
1186 return(xsltCopyText(ctxt
, insert
, node
, 0));
1188 copy
= xmlDocCopyNode(node
, insert
->doc
, 0);
1190 copy
->doc
= ctxt
->output
;
1191 copy
= xsltAddChild(insert
, copy
);
1193 if (node
->type
== XML_ELEMENT_NODE
) {
1195 * Add namespaces as they are needed
1197 if (node
->nsDef
!= NULL
) {
1199 * TODO: Remove the LRE case in the refactored code
1203 xsltCopyNamespaceList(ctxt
, copy
, node
->nsDef
);
1205 xsltCopyNamespaceListInternal(copy
, node
->nsDef
);
1209 * URGENT TODO: The problem with this is that it does not
1210 * copy over all namespace nodes in scope.
1211 * The damn thing about this is, that we would need to
1212 * use the xmlGetNsList(), for every single node; this is
1213 * also done in xsltCopyTreeInternal(), but only for the top node.
1215 if (node
->ns
!= NULL
) {
1218 * REVISIT TODO: Since the non-refactored code still does
1219 * ns-aliasing, we need to call xsltGetNamespace() here.
1220 * Remove this when ready.
1222 copy
->ns
= xsltGetNamespace(ctxt
, node
, node
->ns
, copy
);
1224 copy
->ns
= xsltGetSpecialNamespace(ctxt
,
1225 node
, node
->ns
->href
, node
->ns
->prefix
, copy
);
1228 } else if ((insert
->type
== XML_ELEMENT_NODE
) &&
1229 (insert
->ns
!= NULL
))
1232 * "Undeclare" the default namespace.
1234 xsltGetSpecialNamespace(ctxt
, node
, NULL
, NULL
, copy
);
1238 xsltTransformError(ctxt
, NULL
, node
,
1239 "xsltShallowCopyElem: copy %s failed\n", node
->name
);
1246 * @ctxt: a XSLT process context
1247 * @invocNode: responsible node in the stylesheet; used for error reports
1248 * @list: the list of element nodes in the source tree.
1249 * @insert: the parent in the result tree.
1250 * @isLRE: is this a literal result element list
1251 * @topElemVisited: indicates if a top-most element was already processed
1253 * Make a copy of the full list of tree @list
1254 * and insert it as last children of @insert
1256 * NOTE: Not to be used for Literal Result Elements.
1261 * Returns a pointer to the new list, or NULL in case of error
1264 xsltCopyTreeList(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1266 xmlNodePtr insert
, int isLRE
, int topElemVisited
)
1268 xmlNodePtr copy
, ret
= NULL
;
1270 while (list
!= NULL
) {
1271 copy
= xsltCopyTreeInternal(ctxt
, invocNode
,
1272 list
, insert
, isLRE
, topElemVisited
);
1284 * xsltCopyNamespaceListInternal:
1285 * @node: the target node
1286 * @cur: the first namespace
1288 * Do a copy of a namespace list. If @node is non-NULL the
1289 * new namespaces are added automatically.
1291 * xsltCopyTreeInternal()
1293 * QUESTION: What is the exact difference between this function
1294 * and xsltCopyNamespaceList() in "namespaces.c"?
1295 * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
1297 * Returns: a new xmlNsPtr, or NULL in case of error.
1300 xsltCopyNamespaceListInternal(xmlNodePtr elem
, xmlNsPtr ns
) {
1301 xmlNsPtr ret
= NULL
;
1302 xmlNsPtr p
= NULL
, q
, luNs
;
1307 * One can add namespaces only on element nodes
1309 if ((elem
!= NULL
) && (elem
->type
!= XML_ELEMENT_NODE
))
1313 if (ns
->type
!= XML_NAMESPACE_DECL
)
1316 * Avoid duplicating namespace declarations on the tree.
1319 if ((elem
->ns
!= NULL
) &&
1320 xmlStrEqual(elem
->ns
->prefix
, ns
->prefix
) &&
1321 xmlStrEqual(elem
->ns
->href
, ns
->href
))
1326 luNs
= xmlSearchNs(elem
->doc
, elem
, ns
->prefix
);
1327 if ((luNs
!= NULL
) && (xmlStrEqual(luNs
->href
, ns
->href
)))
1333 q
= xmlNewNs(elem
, ns
->href
, ns
->prefix
);
1336 } else if (q
!= NULL
) {
1341 } while (ns
!= NULL
);
1346 * xsltShallowCopyNsNode:
1347 * @ctxt: the XSLT transformation context
1348 * @invocNode: responsible node in the stylesheet; used for error reports
1349 * @insert: the target element node in the result tree
1350 * @ns: the namespace node
1352 * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
1354 * Returns a new/existing ns-node, or NULL.
1357 xsltShallowCopyNsNode(xsltTransformContextPtr ctxt
,
1358 xmlNodePtr invocNode
,
1363 * TODO: Contrary to header comments, this is declared as int.
1364 * be modified to return a node pointer, or NULL if any error
1368 if ((insert
== NULL
) || (insert
->type
!= XML_ELEMENT_NODE
))
1371 if (insert
->children
!= NULL
) {
1372 xsltTransformError(ctxt
, NULL
, invocNode
,
1373 "Namespace nodes must be added before "
1374 "any child nodes are added to an element.\n");
1378 * BIG NOTE: Xalan-J simply overwrites any ns-decls with
1379 * an equal prefix. We definitively won't do that.
1381 * MSXML 4.0 and the .NET ignores ns-decls for which an
1382 * equal prefix is already in use.
1384 * Saxon raises an error like:
1385 * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
1386 * nodes with the same name".
1388 * NOTE: We'll currently follow MSXML here.
1389 * REVISIT TODO: Check if it's better to follow Saxon here.
1391 if (ns
->prefix
== NULL
) {
1393 * If we are adding ns-nodes to an element using e.g.
1394 * <xsl:copy-of select="/foo/namespace::*">, then we need
1395 * to ensure that we don't incorrectly declare a default
1396 * namespace on an element in no namespace, which otherwise
1397 * would move the element incorrectly into a namespace, if
1398 * the node tree is serialized.
1400 if (insert
->ns
== NULL
)
1402 } else if ((ns
->prefix
[0] == 'x') &&
1403 xmlStrEqual(ns
->prefix
, BAD_CAST
"xml"))
1406 * The XML namespace is built in.
1411 if (insert
->nsDef
!= NULL
) {
1412 tmpns
= insert
->nsDef
;
1414 if ((tmpns
->prefix
== NULL
) == (ns
->prefix
== NULL
)) {
1415 if ((tmpns
->prefix
== ns
->prefix
) ||
1416 xmlStrEqual(tmpns
->prefix
, ns
->prefix
))
1421 if (xmlStrEqual(tmpns
->href
, ns
->href
))
1426 tmpns
= tmpns
->next
;
1427 } while (tmpns
!= NULL
);
1429 tmpns
= xmlSearchNs(insert
->doc
, insert
, ns
->prefix
);
1430 if ((tmpns
!= NULL
) && xmlStrEqual(tmpns
->href
, ns
->href
))
1433 * Declare a new namespace.
1434 * TODO: The problem (wrt efficiency) with this xmlNewNs() is
1435 * that it will again search the already declared namespaces
1436 * for a duplicate :-/
1438 return(xmlNewNs(insert
, ns
->href
, ns
->prefix
));
1442 * TODO: We could as well raise an error here (like Saxon does),
1443 * or at least generate a warning.
1449 * xsltCopyTreeInternal:
1450 * @ctxt: the XSLT transformation context
1451 * @invocNode: responsible node in the stylesheet; used for error reports
1452 * @node: the element node in the source tree
1453 * @insert: the parent in the result tree
1454 * @isLRE: indicates if @node is a Literal Result Element
1455 * @topElemVisited: indicates if a top-most element was already processed
1457 * Make a copy of the full tree under the element node @node
1458 * and insert it as last child of @insert
1460 * NOTE: Not to be used for Literal Result Elements.
1465 * Returns a pointer to the new tree, or NULL in case of error
1468 xsltCopyTreeInternal(xsltTransformContextPtr ctxt
,
1469 xmlNodePtr invocNode
,
1471 xmlNodePtr insert
, int isLRE
, int topElemVisited
)
1477 switch (node
->type
) {
1478 case XML_ELEMENT_NODE
:
1479 case XML_ENTITY_REF_NODE
:
1480 case XML_ENTITY_NODE
:
1482 case XML_COMMENT_NODE
:
1483 case XML_DOCUMENT_NODE
:
1484 case XML_HTML_DOCUMENT_NODE
:
1485 #ifdef LIBXML_DOCB_ENABLED
1486 case XML_DOCB_DOCUMENT_NODE
:
1489 case XML_TEXT_NODE
: {
1490 int noenc
= (node
->name
== xmlStringTextNoenc
);
1491 return(xsltCopyTextString(ctxt
, insert
, node
->content
, noenc
));
1493 case XML_CDATA_SECTION_NODE
:
1494 return(xsltCopyTextString(ctxt
, insert
, node
->content
, 0));
1495 case XML_ATTRIBUTE_NODE
:
1497 xsltShallowCopyAttr(ctxt
, invocNode
, insert
, (xmlAttrPtr
) node
));
1498 case XML_NAMESPACE_DECL
:
1499 return((xmlNodePtr
) xsltShallowCopyNsNode(ctxt
, invocNode
,
1500 insert
, (xmlNsPtr
) node
));
1502 case XML_DOCUMENT_TYPE_NODE
:
1503 case XML_DOCUMENT_FRAG_NODE
:
1504 case XML_NOTATION_NODE
:
1506 case XML_ELEMENT_DECL
:
1507 case XML_ATTRIBUTE_DECL
:
1508 case XML_ENTITY_DECL
:
1509 case XML_XINCLUDE_START
:
1510 case XML_XINCLUDE_END
:
1513 if (XSLT_IS_RES_TREE_FRAG(node
)) {
1514 if (node
->children
!= NULL
)
1515 copy
= xsltCopyTreeList(ctxt
, invocNode
,
1516 node
->children
, insert
, 0, 0);
1521 copy
= xmlDocCopyNode(node
, insert
->doc
, 0);
1523 copy
->doc
= ctxt
->output
;
1524 copy
= xsltAddChild(insert
, copy
);
1526 * The node may have been coalesced into another text node.
1528 if (insert
->last
!= copy
)
1529 return(insert
->last
);
1532 if (node
->type
== XML_ELEMENT_NODE
) {
1534 * Copy in-scope namespace nodes.
1536 * REVISIT: Since we try to reuse existing in-scope ns-decls by
1537 * using xmlSearchNsByHref(), this will eventually change
1538 * the prefix of an original ns-binding; thus it might
1539 * break QNames in element/attribute content.
1540 * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
1541 * context, plus a ns-lookup function, which writes directly
1542 * to a given list, then we wouldn't need to create/free the
1543 * nsList every time.
1545 if ((topElemVisited
== 0) &&
1546 (node
->parent
!= NULL
) &&
1547 (node
->parent
->type
!= XML_DOCUMENT_NODE
) &&
1548 (node
->parent
->type
!= XML_HTML_DOCUMENT_NODE
))
1550 xmlNsPtr
*nsList
, *curns
, ns
;
1553 * If this is a top-most element in a tree to be
1554 * copied, then we need to ensure that all in-scope
1555 * namespaces are copied over. For nodes deeper in the
1556 * tree, it is sufficient to reconcile only the ns-decls
1557 * (node->nsDef entries).
1560 nsList
= xmlGetNsList(node
->doc
, node
);
1561 if (nsList
!= NULL
) {
1565 * Search by prefix first in order to break as less
1566 * QNames in element/attribute content as possible.
1568 ns
= xmlSearchNs(insert
->doc
, insert
,
1572 (! xmlStrEqual(ns
->href
, (*curns
)->href
)))
1576 * Search by namespace name.
1577 * REVISIT TODO: Currently disabled.
1580 ns
= xmlSearchNsByHref(insert
->doc
,
1581 insert
, (*curns
)->href
);
1586 * Declare a new namespace on the copied element.
1588 ns
= xmlNewNs(copy
, (*curns
)->href
,
1590 /* TODO: Handle errors */
1592 if (node
->ns
== *curns
) {
1594 * If this was the original's namespace then set
1595 * the generated counterpart on the copy.
1600 } while (*curns
!= NULL
);
1603 } else if (node
->nsDef
!= NULL
) {
1605 * Copy over all namespace declaration attributes.
1607 if (node
->nsDef
!= NULL
) {
1609 xsltCopyNamespaceList(ctxt
, copy
, node
->nsDef
);
1611 xsltCopyNamespaceListInternal(copy
, node
->nsDef
);
1615 * Set the namespace.
1617 if (node
->ns
!= NULL
) {
1618 if (copy
->ns
== NULL
) {
1620 * This will map copy->ns to one of the newly created
1621 * in-scope ns-decls, OR create a new ns-decl on @copy.
1623 copy
->ns
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1624 node
->ns
->href
, node
->ns
->prefix
, copy
);
1626 } else if ((insert
->type
== XML_ELEMENT_NODE
) &&
1627 (insert
->ns
!= NULL
))
1630 * "Undeclare" the default namespace on @copy with xmlns="".
1632 xsltGetSpecialNamespace(ctxt
, invocNode
, NULL
, NULL
, copy
);
1635 * Copy attribute nodes.
1637 if (node
->properties
!= NULL
) {
1638 xsltCopyAttrListNoOverwrite(ctxt
, invocNode
,
1639 copy
, node
->properties
);
1641 if (topElemVisited
== 0)
1647 if (node
->children
!= NULL
) {
1648 xsltCopyTreeList(ctxt
, invocNode
,
1649 node
->children
, copy
, isLRE
, topElemVisited
);
1652 xsltTransformError(ctxt
, NULL
, invocNode
,
1653 "xsltCopyTreeInternal: Copying of '%s' failed.\n", node
->name
);
1660 * @ctxt: the XSLT transformation context
1661 * @node: the element node in the source tree
1662 * @insert: the parent in the result tree
1663 * @literal: indicates if @node is a Literal Result Element
1665 * Make a copy of the full tree under the element node @node
1666 * and insert it as last child of @insert
1667 * For literal result element, some of the namespaces may not be copied
1668 * over according to section 7.1.
1669 * TODO: Why is this a public function?
1671 * Returns a pointer to the new tree, or NULL in case of error
1674 xsltCopyTree(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1675 xmlNodePtr insert
, int literal
)
1677 return(xsltCopyTreeInternal(ctxt
, node
, node
, insert
, literal
, 0));
1681 /************************************************************************
1683 * Error/fallback processing *
1685 ************************************************************************/
1688 * xsltApplyFallbacks:
1689 * @ctxt: a XSLT process context
1690 * @node: the node in the source tree.
1691 * @inst: the node generating the error
1693 * Process possible xsl:fallback nodes present under @inst
1695 * Returns the number of xsl:fallback element found and processed
1698 xsltApplyFallbacks(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1704 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) ||
1705 (inst
->children
== NULL
))
1708 child
= inst
->children
;
1709 while (child
!= NULL
) {
1710 if ((IS_XSLT_ELEM(child
)) &&
1711 (xmlStrEqual(child
->name
, BAD_CAST
"fallback"))) {
1712 #ifdef WITH_XSLT_DEBUG_PARSING
1713 xsltGenericDebug(xsltGenericDebugContext
,
1714 "applying xsl:fallback\n");
1717 xsltApplySequenceConstructor(ctxt
, node
, child
->children
,
1720 child
= child
->next
;
1725 /************************************************************************
1727 * Default processing *
1729 ************************************************************************/
1732 * xsltDefaultProcessOneNode:
1733 * @ctxt: a XSLT process context
1734 * @node: the node in the source tree.
1735 * @params: extra parameters passed to the template if any
1737 * Process the source node with the default built-in template rule:
1738 * <xsl:template match="*|/">
1739 * <xsl:apply-templates/>
1744 * <xsl:template match="text()|@*">
1745 * <xsl:value-of select="."/>
1748 * Note also that namespace declarations are copied directly:
1750 * the built-in template rule is the only template rule that is applied
1751 * for namespace nodes.
1754 xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1755 xsltStackElemPtr params
) {
1757 xmlNodePtr
delete = NULL
, cur
;
1758 int nbchild
= 0, oldSize
;
1759 int childno
= 0, oldPos
;
1760 xsltTemplatePtr
template;
1764 * Handling of leaves
1766 switch (node
->type
) {
1767 case XML_DOCUMENT_NODE
:
1768 case XML_HTML_DOCUMENT_NODE
:
1769 case XML_ELEMENT_NODE
:
1771 case XML_CDATA_SECTION_NODE
:
1772 #ifdef WITH_XSLT_DEBUG_PROCESS
1773 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1774 "xsltDefaultProcessOneNode: copy CDATA %s\n",
1777 copy
= xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
1779 xsltTransformError(ctxt
, NULL
, node
,
1780 "xsltDefaultProcessOneNode: cdata copy failed\n");
1784 #ifdef WITH_XSLT_DEBUG_PROCESS
1785 if (node
->content
== NULL
) {
1786 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1787 "xsltDefaultProcessOneNode: copy empty text\n"));
1790 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1791 "xsltDefaultProcessOneNode: copy text %s\n",
1795 copy
= xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
1797 xsltTransformError(ctxt
, NULL
, node
,
1798 "xsltDefaultProcessOneNode: text copy failed\n");
1801 case XML_ATTRIBUTE_NODE
:
1802 cur
= node
->children
;
1803 while ((cur
!= NULL
) && (cur
->type
!= XML_TEXT_NODE
))
1806 xsltTransformError(ctxt
, NULL
, node
,
1807 "xsltDefaultProcessOneNode: no text for attribute\n");
1809 #ifdef WITH_XSLT_DEBUG_PROCESS
1810 if (cur
->content
== NULL
) {
1811 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1812 "xsltDefaultProcessOneNode: copy empty text\n"));
1814 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1815 "xsltDefaultProcessOneNode: copy text %s\n",
1819 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
1821 xsltTransformError(ctxt
, NULL
, node
,
1822 "xsltDefaultProcessOneNode: text copy failed\n");
1830 * Handling of Elements: first pass, cleanup and counting
1832 cur
= node
->children
;
1833 while (cur
!= NULL
) {
1834 switch (cur
->type
) {
1836 case XML_CDATA_SECTION_NODE
:
1837 case XML_DOCUMENT_NODE
:
1838 case XML_HTML_DOCUMENT_NODE
:
1839 case XML_ELEMENT_NODE
:
1841 case XML_COMMENT_NODE
:
1845 /* Unlink the DTD, it's still reachable using doc->intSubset */
1846 if (cur
->next
!= NULL
)
1847 cur
->next
->prev
= cur
->prev
;
1848 if (cur
->prev
!= NULL
)
1849 cur
->prev
->next
= cur
->next
;
1852 #ifdef WITH_XSLT_DEBUG_PROCESS
1853 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1854 "xsltDefaultProcessOneNode: skipping node type %d\n",
1860 if (delete != NULL
) {
1861 #ifdef WITH_XSLT_DEBUG_PROCESS
1862 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1863 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1865 xmlUnlinkNode(delete);
1866 xmlFreeNode(delete);
1870 if (delete != NULL
) {
1871 #ifdef WITH_XSLT_DEBUG_PROCESS
1872 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1873 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1875 xmlUnlinkNode(delete);
1876 xmlFreeNode(delete);
1881 * Handling of Elements: second pass, actual processing
1883 oldSize
= ctxt
->xpathCtxt
->contextSize
;
1884 oldPos
= ctxt
->xpathCtxt
->proximityPosition
;
1885 cur
= node
->children
;
1886 while (cur
!= NULL
) {
1888 switch (cur
->type
) {
1889 case XML_DOCUMENT_NODE
:
1890 case XML_HTML_DOCUMENT_NODE
:
1891 case XML_ELEMENT_NODE
:
1892 ctxt
->xpathCtxt
->contextSize
= nbchild
;
1893 ctxt
->xpathCtxt
->proximityPosition
= childno
;
1894 xsltProcessOneNode(ctxt
, cur
, params
);
1896 case XML_CDATA_SECTION_NODE
:
1897 template = xsltGetTemplate(ctxt
, cur
, NULL
);
1899 #ifdef WITH_XSLT_DEBUG_PROCESS
1900 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1901 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
1905 * Instantiate the xsl:template.
1907 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
1909 } else /* if (ctxt->mode == NULL) */ {
1910 #ifdef WITH_XSLT_DEBUG_PROCESS
1911 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1912 "xsltDefaultProcessOneNode: copy CDATA %s\n",
1915 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
1917 xsltTransformError(ctxt
, NULL
, cur
,
1918 "xsltDefaultProcessOneNode: cdata copy failed\n");
1923 template = xsltGetTemplate(ctxt
, cur
, NULL
);
1925 #ifdef WITH_XSLT_DEBUG_PROCESS
1926 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1927 "xsltDefaultProcessOneNode: applying template for text %s\n",
1930 ctxt
->xpathCtxt
->contextSize
= nbchild
;
1931 ctxt
->xpathCtxt
->proximityPosition
= childno
;
1933 * Instantiate the xsl:template.
1935 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
1937 } else /* if (ctxt->mode == NULL) */ {
1938 #ifdef WITH_XSLT_DEBUG_PROCESS
1939 if (cur
->content
== NULL
) {
1940 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1941 "xsltDefaultProcessOneNode: copy empty text\n"));
1943 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1944 "xsltDefaultProcessOneNode: copy text %s\n",
1948 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
1950 xsltTransformError(ctxt
, NULL
, cur
,
1951 "xsltDefaultProcessOneNode: text copy failed\n");
1956 case XML_COMMENT_NODE
:
1957 template = xsltGetTemplate(ctxt
, cur
, NULL
);
1959 #ifdef WITH_XSLT_DEBUG_PROCESS
1960 if (cur
->type
== XML_PI_NODE
) {
1961 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1962 "xsltDefaultProcessOneNode: template found for PI %s\n",
1964 } else if (cur
->type
== XML_COMMENT_NODE
) {
1965 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1966 "xsltDefaultProcessOneNode: template found for comment\n"));
1969 ctxt
->xpathCtxt
->contextSize
= nbchild
;
1970 ctxt
->xpathCtxt
->proximityPosition
= childno
;
1972 * Instantiate the xsl:template.
1974 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
1983 ctxt
->xpathCtxt
->contextSize
= oldSize
;
1984 ctxt
->xpathCtxt
->proximityPosition
= oldPos
;
1988 * xsltProcessOneNode:
1989 * @ctxt: a XSLT process context
1990 * @contextNode: the "current node" in the source tree
1991 * @withParams: extra parameters (e.g. xsl:with-param) passed to the
1994 * Process the source node.
1997 xsltProcessOneNode(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
1998 xsltStackElemPtr withParams
)
2000 xsltTemplatePtr templ
;
2003 templ
= xsltGetTemplate(ctxt
, contextNode
, NULL
);
2005 * If no template is found, apply the default rule.
2007 if (templ
== NULL
) {
2008 #ifdef WITH_XSLT_DEBUG_PROCESS
2009 if (contextNode
->type
== XML_DOCUMENT_NODE
) {
2010 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2011 "xsltProcessOneNode: no template found for /\n"));
2012 } else if (contextNode
->type
== XML_CDATA_SECTION_NODE
) {
2013 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2014 "xsltProcessOneNode: no template found for CDATA\n"));
2015 } else if (contextNode
->type
== XML_ATTRIBUTE_NODE
) {
2016 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2017 "xsltProcessOneNode: no template found for attribute %s\n",
2018 ((xmlAttrPtr
) contextNode
)->name
));
2020 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2021 "xsltProcessOneNode: no template found for %s\n", contextNode
->name
));
2024 oldNode
= ctxt
->node
;
2025 ctxt
->node
= contextNode
;
2026 xsltDefaultProcessOneNode(ctxt
, contextNode
, withParams
);
2027 ctxt
->node
= oldNode
;
2031 if (contextNode
->type
== XML_ATTRIBUTE_NODE
) {
2032 xsltTemplatePtr oldCurTempRule
= ctxt
->currentTemplateRule
;
2034 * Set the "current template rule".
2036 ctxt
->currentTemplateRule
= templ
;
2038 #ifdef WITH_XSLT_DEBUG_PROCESS
2039 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2040 "xsltProcessOneNode: applying template '%s' for attribute %s\n",
2041 templ
->match
, contextNode
->name
));
2043 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
, templ
, withParams
);
2045 ctxt
->currentTemplateRule
= oldCurTempRule
;
2047 xsltTemplatePtr oldCurTempRule
= ctxt
->currentTemplateRule
;
2049 * Set the "current template rule".
2051 ctxt
->currentTemplateRule
= templ
;
2053 #ifdef WITH_XSLT_DEBUG_PROCESS
2054 if (contextNode
->type
== XML_DOCUMENT_NODE
) {
2055 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2056 "xsltProcessOneNode: applying template '%s' for /\n",
2059 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2060 "xsltProcessOneNode: applying template '%s' for %s\n",
2061 templ
->match
, contextNode
->name
));
2064 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
, templ
, withParams
);
2066 ctxt
->currentTemplateRule
= oldCurTempRule
;
2071 xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt
,
2072 xmlNodePtr contextNode
,
2074 xsltTemplatePtr templ
,
2077 xmlNodePtr debugedNode
= NULL
;
2079 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2081 *addCallResult
= xslAddCall(templ
, templ
->elem
);
2083 *addCallResult
= xslAddCall(NULL
, list
);
2085 switch (ctxt
->debugStatus
) {
2086 case XSLT_DEBUG_RUN_RESTART
:
2087 case XSLT_DEBUG_QUIT
:
2093 xslHandleDebugger(templ
->elem
, contextNode
, templ
, ctxt
);
2094 debugedNode
= templ
->elem
;
2096 xslHandleDebugger(list
, contextNode
, templ
, ctxt
);
2098 } else if (ctxt
->inst
) {
2099 xslHandleDebugger(ctxt
->inst
, contextNode
, templ
, ctxt
);
2100 debugedNode
= ctxt
->inst
;
2103 return(debugedNode
);
2107 * xsltLocalVariablePush:
2108 * @ctxt: the transformation context
2109 * @variable: variable to be pushed to the variable stack
2110 * @level: new value for variable's level
2112 * Places the variable onto the local variable stack
2114 * Returns: 0 for success, -1 for any error
2116 * This is an internal routine and should not be called by users!
2119 xsltLocalVariablePush(xsltTransformContextPtr ctxt
,
2120 xsltStackElemPtr variable
,
2123 if (ctxt
->varsMax
== 0) {
2126 (xsltStackElemPtr
*) xmlMalloc(ctxt
->varsMax
*
2127 sizeof(ctxt
->varsTab
[0]));
2128 if (ctxt
->varsTab
== NULL
) {
2129 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
2133 if (ctxt
->varsNr
>= ctxt
->varsMax
) {
2136 (xsltStackElemPtr
*) xmlRealloc(ctxt
->varsTab
,
2138 sizeof(ctxt
->varsTab
[0]));
2139 if (ctxt
->varsTab
== NULL
) {
2140 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
2144 ctxt
->varsTab
[ctxt
->varsNr
++] = variable
;
2145 ctxt
->vars
= variable
;
2146 variable
->level
= level
;
2151 * xsltReleaseLocalRVTs:
2153 * Fragments which are results of extension instructions
2154 * are preserved; all other fragments are freed/cached.
2157 xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt
, xmlDocPtr base
)
2159 xmlDocPtr cur
= ctxt
->localRVT
, tmp
;
2161 while ((cur
!= NULL
) && (cur
!= base
)) {
2162 if (cur
->psvi
== (void *) ((long) 1)) {
2163 cur
= (xmlDocPtr
) cur
->next
;
2166 cur
= (xmlDocPtr
) cur
->next
;
2168 if (tmp
== ctxt
->localRVT
)
2169 ctxt
->localRVT
= cur
;
2172 * We need ctxt->localRVTBase for extension instructions
2173 * which return values (like EXSLT's function).
2175 if (tmp
== ctxt
->localRVTBase
)
2176 ctxt
->localRVTBase
= cur
;
2179 tmp
->prev
->next
= (xmlNodePtr
) cur
;
2181 cur
->prev
= tmp
->prev
;
2182 xsltReleaseRVT(ctxt
, tmp
);
2188 * xsltApplySequenceConstructor:
2189 * @ctxt: a XSLT process context
2190 * @contextNode: the "current node" in the source tree
2191 * @list: the nodes of a sequence constructor;
2192 * (plus leading xsl:param elements)
2193 * @templ: the compiled xsl:template (optional)
2195 * Processes a sequence constructor.
2197 * NOTE: ctxt->currentTemplateRule was introduced to reflect the
2198 * semantics of "current template rule". I.e. the field ctxt->templ
2199 * is not intended to reflect this, thus always pushed onto the
2203 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt
,
2204 xmlNodePtr contextNode
, xmlNodePtr list
,
2205 xsltTemplatePtr templ
)
2207 xmlNodePtr oldInsert
, oldInst
, oldCurInst
, oldContextNode
;
2208 xmlNodePtr cur
, insert
, copy
= NULL
;
2209 int level
= 0, oldVarsNr
;
2210 xmlDocPtr oldLocalFragmentTop
, oldLocalFragmentBase
;
2212 #ifdef XSLT_REFACTORED
2213 xsltStylePreCompPtr info
;
2216 #ifdef WITH_DEBUGGER
2217 int addCallResult
= 0;
2218 xmlNodePtr debuggedNode
= NULL
;
2224 #ifdef WITH_DEBUGGER
2225 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2227 xsltDebuggerStartSequenceConstructor(ctxt
, contextNode
,
2228 list
, templ
, &addCallResult
);
2229 if (debuggedNode
== NULL
)
2238 oldLocalFragmentTop
= ctxt
->localRVT
;
2239 oldInsert
= insert
= ctxt
->insert
;
2240 oldInst
= oldCurInst
= ctxt
->inst
;
2241 oldContextNode
= ctxt
->node
;
2243 * Save current number of variables on the stack; new vars are popped when
2246 oldVarsNr
= ctxt
->varsNr
;
2248 * Process the sequence constructor.
2251 while (cur
!= NULL
) {
2254 #ifdef WITH_DEBUGGER
2255 switch (ctxt
->debugStatus
) {
2256 case XSLT_DEBUG_RUN_RESTART
:
2257 case XSLT_DEBUG_QUIT
:
2263 * Test; we must have a valid insertion point.
2265 if (insert
== NULL
) {
2267 #ifdef WITH_XSLT_DEBUG_PROCESS
2268 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2269 "xsltApplySequenceConstructor: insert == NULL !\n"));
2274 #ifdef WITH_DEBUGGER
2275 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (debuggedNode
!= cur
))
2276 xslHandleDebugger(cur
, contextNode
, templ
, ctxt
);
2279 #ifdef XSLT_REFACTORED
2280 if (cur
->type
== XML_ELEMENT_NODE
) {
2281 info
= (xsltStylePreCompPtr
) cur
->psvi
;
2283 * We expect a compiled representation on:
2284 * 1) XSLT instructions of this XSLT version (1.0)
2285 * (with a few exceptions)
2286 * 2) Literal result elements
2287 * 3) Extension instructions
2288 * 4) XSLT instructions of future XSLT versions
2289 * (forwards-compatible mode).
2293 * Handle the rare cases where we don't expect a compiled
2294 * representation on an XSLT element.
2296 if (IS_XSLT_ELEM_FAST(cur
) && IS_XSLT_NAME(cur
, "message")) {
2297 xsltMessage(ctxt
, contextNode
, cur
);
2301 * Something really went wrong:
2303 xsltTransformError(ctxt
, NULL
, cur
,
2304 "Internal error in xsltApplySequenceConstructor(): "
2305 "The element '%s' in the stylesheet has no compiled "
2306 "representation.\n",
2311 if (info
->type
== XSLT_FUNC_LITERAL_RESULT_ELEMENT
) {
2312 xsltStyleItemLRElementInfoPtr lrInfo
=
2313 (xsltStyleItemLRElementInfoPtr
) info
;
2315 * Literal result elements
2316 * --------------------------------------------------------
2318 #ifdef WITH_XSLT_DEBUG_PROCESS
2319 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2320 xsltGenericDebug(xsltGenericDebugContext
,
2321 "xsltApplySequenceConstructor: copy literal result "
2322 "element '%s'\n", cur
->name
));
2325 * Copy the raw element-node.
2326 * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2330 copy
= xmlDocCopyNode(cur
, insert
->doc
, 0);
2332 xsltTransformError(ctxt
, NULL
, cur
,
2333 "Internal error in xsltApplySequenceConstructor(): "
2334 "Failed to copy literal result element '%s'.\n",
2339 * Add the element-node to the result tree.
2341 copy
->doc
= ctxt
->output
;
2342 copy
= xsltAddChild(insert
, copy
);
2344 * Create effective namespaces declarations.
2345 * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2347 if (lrInfo
->effectiveNs
!= NULL
) {
2348 xsltEffectiveNsPtr effNs
= lrInfo
->effectiveNs
;
2349 xmlNsPtr ns
, lastns
= NULL
;
2351 while (effNs
!= NULL
) {
2353 * Avoid generating redundant namespace
2354 * declarations; thus lookup if there is already
2355 * such a ns-decl in the result.
2357 ns
= xmlSearchNs(copy
->doc
, copy
, effNs
->prefix
);
2359 (xmlStrEqual(ns
->href
, effNs
->nsName
)))
2361 effNs
= effNs
->next
;
2364 ns
= xmlNewNs(copy
, effNs
->nsName
, effNs
->prefix
);
2366 xsltTransformError(ctxt
, NULL
, cur
,
2367 "Internal error in "
2368 "xsltApplySequenceConstructor(): "
2369 "Failed to copy a namespace "
2380 effNs
= effNs
->next
;
2385 * NOTE that we don't need to apply ns-alising: this was
2386 * already done at compile-time.
2388 if (cur
->ns
!= NULL
) {
2390 * If there's no such ns-decl in the result tree,
2391 * then xsltGetSpecialNamespace() will
2392 * create a ns-decl on the copied node.
2394 copy
->ns
= xsltGetSpecialNamespace(ctxt
, cur
,
2395 cur
->ns
->href
, cur
->ns
->prefix
, copy
);
2398 * Undeclare the default namespace if needed.
2399 * This can be skipped, if the result element has
2400 * no ns-decls, in which case the result element
2401 * obviously does not declare a default namespace;
2402 * AND there's either no parent, or the parent
2403 * element is in no namespace; this means there's no
2404 * default namespace is scope to care about.
2406 * REVISIT: This might result in massive
2407 * generation of ns-decls if nodes in a default
2408 * namespaces are mixed with nodes in no namespace.
2412 ((insert
!= NULL
) &&
2413 (insert
->type
== XML_ELEMENT_NODE
) &&
2414 (insert
->ns
!= NULL
)))
2416 xsltGetSpecialNamespace(ctxt
, cur
,
2422 * SPEC XSLT 2.0 "Each attribute of the literal result
2423 * element, other than an attribute in the XSLT namespace,
2424 * is processed to produce an attribute for the element in
2426 * NOTE: See bug #341325.
2428 if (cur
->properties
!= NULL
) {
2429 xsltAttrListTemplateProcess(ctxt
, copy
, cur
->properties
);
2431 } else if (IS_XSLT_ELEM_FAST(cur
)) {
2434 * --------------------------------------------------------
2436 if (info
->type
== XSLT_FUNC_UNKOWN_FORWARDS_COMPAT
) {
2438 * We hit an unknown XSLT element.
2439 * Try to apply one of the fallback cases.
2441 ctxt
->insert
= insert
;
2442 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2443 xsltTransformError(ctxt
, NULL
, cur
,
2444 "The is no fallback behaviour defined for "
2445 "the unknown XSLT element '%s'.\n",
2448 ctxt
->insert
= oldInsert
;
2449 } else if (info
->func
!= NULL
) {
2451 * Execute the XSLT instruction.
2453 ctxt
->insert
= insert
;
2455 info
->func(ctxt
, contextNode
, cur
,
2456 (xsltElemPreCompPtr
) info
);
2459 * Cleanup temporary tree fragments.
2461 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2462 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2464 ctxt
->insert
= oldInsert
;
2465 } else if (info
->type
== XSLT_FUNC_VARIABLE
) {
2466 xsltStackElemPtr tmpvar
= ctxt
->vars
;
2468 xsltParseStylesheetVariable(ctxt
, cur
);
2470 if (tmpvar
!= ctxt
->vars
) {
2472 * TODO: Using a @tmpvar is an annoying workaround, but
2473 * the current mechanisms do not provide any other way
2474 * of knowing if the var was really pushed onto the
2477 ctxt
->vars
->level
= level
;
2479 } else if (info
->type
== XSLT_FUNC_MESSAGE
) {
2481 * TODO: Won't be hit, since we don't compile xsl:message.
2483 xsltMessage(ctxt
, contextNode
, cur
);
2485 xsltTransformError(ctxt
, NULL
, cur
,
2486 "Unexpected XSLT element '%s'.\n", cur
->name
);
2491 xsltTransformFunction func
;
2493 * Extension intructions (elements)
2494 * --------------------------------------------------------
2496 if (cur
->psvi
== xsltExtMarker
) {
2498 * The xsltExtMarker was set during the compilation
2499 * of extension instructions if there was no registered
2500 * handler for this specific extension function at
2502 * Libxslt will now lookup if a handler is
2503 * registered in the context of this transformation.
2505 func
= (xsltTransformFunction
)
2506 xsltExtElementLookup(ctxt
, cur
->name
, cur
->ns
->href
);
2508 func
= ((xsltElemPreCompPtr
) cur
->psvi
)->func
;
2512 * No handler available.
2513 * Try to execute fallback behaviour via xsl:fallback.
2515 #ifdef WITH_XSLT_DEBUG_PROCESS
2516 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2517 xsltGenericDebug(xsltGenericDebugContext
,
2518 "xsltApplySequenceConstructor: unknown extension %s\n",
2521 ctxt
->insert
= insert
;
2522 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2523 xsltTransformError(ctxt
, NULL
, cur
,
2524 "Unknown extension instruction '{%s}%s'.\n",
2525 cur
->ns
->href
, cur
->name
);
2527 ctxt
->insert
= oldInsert
;
2530 * Execute the handler-callback.
2532 #ifdef WITH_XSLT_DEBUG_PROCESS
2533 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2534 "xsltApplySequenceConstructor: extension construct %s\n",
2537 ctxt
->insert
= insert
;
2539 * We need the fragment base for extension instructions
2540 * which return values (like EXSLT's function).
2542 oldLocalFragmentBase
= ctxt
->localRVTBase
;
2543 ctxt
->localRVTBase
= NULL
;
2545 func(ctxt
, contextNode
, cur
, cur
->psvi
);
2547 ctxt
->localRVTBase
= oldLocalFragmentBase
;
2549 * Cleanup temporary tree fragments.
2551 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2552 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2554 ctxt
->insert
= oldInsert
;
2559 } else if (XSLT_IS_TEXT_NODE(cur
)) {
2562 * ------------------------------------------------------------
2564 #ifdef WITH_XSLT_DEBUG_PROCESS
2565 if (cur
->name
== xmlStringTextNoenc
) {
2566 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2567 xsltGenericDebug(xsltGenericDebugContext
,
2568 "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2571 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2572 xsltGenericDebug(xsltGenericDebugContext
,
2573 "xsltApplySequenceConstructor: copy text '%s'\n",
2577 if (xsltCopyText(ctxt
, insert
, cur
, ctxt
->internalized
) == NULL
)
2581 #else /* XSLT_REFACTORED */
2583 if (IS_XSLT_ELEM(cur
)) {
2585 * This is an XSLT node
2587 xsltStylePreCompPtr info
= (xsltStylePreCompPtr
) cur
->psvi
;
2590 if (IS_XSLT_NAME(cur
, "message")) {
2591 xsltMessage(ctxt
, contextNode
, cur
);
2594 * That's an error try to apply one of the fallback cases
2596 ctxt
->insert
= insert
;
2597 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2598 xsltGenericError(xsltGenericErrorContext
,
2599 "xsltApplySequenceConstructor: %s was not compiled\n",
2602 ctxt
->insert
= oldInsert
;
2607 if (info
->func
!= NULL
) {
2608 oldCurInst
= ctxt
->inst
;
2610 ctxt
->insert
= insert
;
2611 oldLocalFragmentBase
= ctxt
->localRVTBase
;
2612 ctxt
->localRVTBase
= NULL
;
2614 info
->func(ctxt
, contextNode
, cur
, (xsltElemPreCompPtr
) info
);
2616 ctxt
->localRVTBase
= oldLocalFragmentBase
;
2618 * Cleanup temporary tree fragments.
2620 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2621 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2623 ctxt
->insert
= oldInsert
;
2624 ctxt
->inst
= oldCurInst
;
2628 if (IS_XSLT_NAME(cur
, "variable")) {
2629 xsltStackElemPtr tmpvar
= ctxt
->vars
;
2631 oldCurInst
= ctxt
->inst
;
2634 xsltParseStylesheetVariable(ctxt
, cur
);
2636 ctxt
->inst
= oldCurInst
;
2638 if (tmpvar
!= ctxt
->vars
) {
2640 * TODO: Using a @tmpvar is an annoying workaround, but
2641 * the current mechanisms do not provide any other way
2642 * of knowing if the var was really pushed onto the
2645 ctxt
->vars
->level
= level
;
2647 } else if (IS_XSLT_NAME(cur
, "message")) {
2648 xsltMessage(ctxt
, contextNode
, cur
);
2650 xsltTransformError(ctxt
, NULL
, cur
,
2651 "Unexpected XSLT element '%s'.\n", cur
->name
);
2654 } else if ((cur
->type
== XML_TEXT_NODE
) ||
2655 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
2658 * This text comes from the stylesheet
2659 * For stylesheets, the set of whitespace-preserving
2660 * element names consists of just xsl:text.
2662 #ifdef WITH_XSLT_DEBUG_PROCESS
2663 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
2664 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2665 "xsltApplySequenceConstructor: copy CDATA text %s\n",
2667 } else if (cur
->name
== xmlStringTextNoenc
) {
2668 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2669 "xsltApplySequenceConstructor: copy unescaped text %s\n",
2672 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2673 "xsltApplySequenceConstructor: copy text %s\n",
2677 if (xsltCopyText(ctxt
, insert
, cur
, ctxt
->internalized
) == NULL
)
2679 } else if ((cur
->type
== XML_ELEMENT_NODE
) &&
2680 (cur
->ns
!= NULL
) && (cur
->psvi
!= NULL
)) {
2681 xsltTransformFunction function
;
2683 oldCurInst
= ctxt
->inst
;
2686 * Flagged as an extension element
2688 if (cur
->psvi
== xsltExtMarker
)
2689 function
= (xsltTransformFunction
)
2690 xsltExtElementLookup(ctxt
, cur
->name
, cur
->ns
->href
);
2692 function
= ((xsltElemPreCompPtr
) cur
->psvi
)->func
;
2694 if (function
== NULL
) {
2698 #ifdef WITH_XSLT_DEBUG_PROCESS
2699 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2700 "xsltApplySequenceConstructor: unknown extension %s\n",
2704 * Search if there are fallbacks
2706 child
= cur
->children
;
2707 while (child
!= NULL
) {
2708 if ((IS_XSLT_ELEM(child
)) &&
2709 (IS_XSLT_NAME(child
, "fallback")))
2712 xsltApplySequenceConstructor(ctxt
, contextNode
,
2713 child
->children
, NULL
);
2715 child
= child
->next
;
2719 xsltTransformError(ctxt
, NULL
, cur
,
2720 "xsltApplySequenceConstructor: failed to find extension %s\n",
2724 #ifdef WITH_XSLT_DEBUG_PROCESS
2725 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2726 "xsltApplySequenceConstructor: extension construct %s\n",
2730 ctxt
->insert
= insert
;
2732 * We need the fragment base for extension instructions
2733 * which return values (like EXSLT's function).
2735 oldLocalFragmentBase
= ctxt
->localRVTBase
;
2736 ctxt
->localRVTBase
= NULL
;
2738 function(ctxt
, contextNode
, cur
, cur
->psvi
);
2740 * Cleanup temporary tree fragments.
2742 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2743 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2745 ctxt
->localRVTBase
= oldLocalFragmentBase
;
2746 ctxt
->insert
= oldInsert
;
2749 ctxt
->inst
= oldCurInst
;
2751 } else if (cur
->type
== XML_ELEMENT_NODE
) {
2752 #ifdef WITH_XSLT_DEBUG_PROCESS
2753 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2754 "xsltApplySequenceConstructor: copy node %s\n",
2757 oldCurInst
= ctxt
->inst
;
2760 if ((copy
= xsltShallowCopyElem(ctxt
, cur
, insert
, 1)) == NULL
)
2763 * Add extra namespaces inherited from the current template
2764 * if we are in the first level children and this is a
2767 if ((templ
!= NULL
) && (oldInsert
== insert
) &&
2768 (ctxt
->templ
!= NULL
) && (ctxt
->templ
->inheritedNs
!= NULL
)) {
2772 for (i
= 0; i
< ctxt
->templ
->inheritedNsNr
; i
++) {
2773 const xmlChar
*URI
= NULL
;
2774 xsltStylesheetPtr style
;
2775 ns
= ctxt
->templ
->inheritedNs
[i
];
2777 /* Note that the XSLT namespace was already excluded
2778 * in xsltGetInheritedNsList().
2781 if (xmlStrEqual(ns
->href
, XSLT_NAMESPACE
))
2784 style
= ctxt
->style
;
2785 while (style
!= NULL
) {
2786 if (style
->nsAliases
!= NULL
)
2787 URI
= (const xmlChar
*)
2788 xmlHashLookup(style
->nsAliases
, ns
->href
);
2792 style
= xsltNextImport(style
);
2794 if (URI
== UNDEFINED_DEFAULT_NS
)
2799 * TODO: The following will still be buggy for the
2800 * non-refactored code.
2802 ret
= xmlSearchNs(copy
->doc
, copy
, ns
->prefix
);
2803 if ((ret
== NULL
) || (!xmlStrEqual(ret
->href
, URI
)))
2805 xmlNewNs(copy
, URI
, ns
->prefix
);
2808 if (copy
->ns
!= NULL
) {
2810 * Fix the node namespace if needed
2812 copy
->ns
= xsltGetNamespace(ctxt
, cur
, copy
->ns
, copy
);
2816 * all the attributes are directly inherited
2818 if (cur
->properties
!= NULL
) {
2819 xsltAttrListTemplateProcess(ctxt
, copy
, cur
->properties
);
2821 ctxt
->inst
= oldCurInst
;
2823 #endif /* else of XSLT_REFACTORED */
2826 * Descend into content in document order.
2828 if (cur
->children
!= NULL
) {
2829 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
2830 cur
= cur
->children
;
2840 * If xslt:message was just processed, we might have hit a
2841 * terminate='yes'; if so, then break the loop and clean up.
2842 * TODO: Do we need to check this also before trying to descend
2845 if (ctxt
->state
== XSLT_STATE_STOPPED
)
2847 if (cur
->next
!= NULL
) {
2856 * Pop variables/params (xsl:variable and xsl:param).
2858 if ((ctxt
->varsNr
> oldVarsNr
) && (ctxt
->vars
->level
> level
)) {
2859 xsltLocalVariablePop(ctxt
, oldVarsNr
, level
);
2862 insert
= insert
->parent
;
2865 if (cur
== list
->parent
) {
2869 if (cur
->next
!= NULL
) {
2873 } while (cur
!= NULL
);
2878 * In case of errors: pop remaining variables.
2880 if (ctxt
->varsNr
> oldVarsNr
)
2881 xsltLocalVariablePop(ctxt
, oldVarsNr
, -1);
2883 ctxt
->node
= oldContextNode
;
2884 ctxt
->inst
= oldInst
;
2885 ctxt
->insert
= oldInsert
;
2887 #ifdef WITH_DEBUGGER
2888 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (addCallResult
)) {
2895 * xsltApplyXSLTTemplate:
2896 * @ctxt: a XSLT transformation context
2897 * @contextNode: the node in the source tree.
2898 * @list: the nodes of a sequence constructor;
2899 * (plus leading xsl:param elements)
2900 * @templ: the compiled xsl:template declaration;
2901 * NULL if a sequence constructor
2902 * @withParams: a set of caller-parameters (xsl:with-param) or NULL
2905 * - xsltApplyImports()
2906 * - xsltCallTemplate()
2907 * - xsltDefaultProcessOneNode()
2908 * - xsltProcessOneNode()
2911 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt
,
2912 xmlNodePtr contextNode
,
2914 xsltTemplatePtr templ
,
2915 xsltStackElemPtr withParams
)
2917 int oldVarsBase
= 0;
2920 xsltStackElemPtr tmpParam
= NULL
;
2921 xmlDocPtr oldUserFragmentTop
, oldLocalFragmentTop
;
2923 #ifdef XSLT_REFACTORED
2924 xsltStyleItemParamPtr iparam
;
2926 xsltStylePreCompPtr iparam
;
2929 #ifdef WITH_DEBUGGER
2930 int addCallResult
= 0;
2935 if (templ
== NULL
) {
2936 xsltTransformError(ctxt
, NULL
, list
,
2937 "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
2941 #ifdef WITH_DEBUGGER
2942 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2943 if (xsltDebuggerStartSequenceConstructor(ctxt
, contextNode
,
2944 list
, templ
, &addCallResult
) == NULL
)
2954 * Check for infinite recursion: stop if the maximum of nested templates
2955 * is excceeded. Adjust xsltMaxDepth if you need more.
2957 if (ctxt
->templNr
>= ctxt
->maxTemplateDepth
)
2959 xsltTransformError(ctxt
, NULL
, list
,
2960 "xsltApplyXSLTTemplate: A potential infinite template recursion "
2962 "You can adjust xsltMaxDepth (--maxdepth) in order to "
2963 "raise the maximum number of nested template calls and "
2964 "variables/params (currently set to %d).\n",
2965 ctxt
->maxTemplateDepth
);
2966 xsltDebug(ctxt
, contextNode
, list
, NULL
);
2970 if (ctxt
->varsNr
>= ctxt
->maxTemplateVars
)
2972 xsltTransformError(ctxt
, NULL
, list
,
2973 "xsltApplyXSLTTemplate: A potential infinite template recursion "
2975 "You can adjust maxTemplateVars (--maxvars) in order to "
2976 "raise the maximum number of variables/params (currently set to %d).\n",
2977 ctxt
->maxTemplateVars
);
2978 xsltDebug(ctxt
, contextNode
, list
, NULL
);
2982 oldUserFragmentTop
= ctxt
->tmpRVT
;
2983 ctxt
->tmpRVT
= NULL
;
2984 oldLocalFragmentTop
= ctxt
->localRVT
;
2987 * Initiate a distinct scope of local params/variables.
2989 oldVarsBase
= ctxt
->varsBase
;
2990 ctxt
->varsBase
= ctxt
->varsNr
;
2992 ctxt
->node
= contextNode
;
2993 if (ctxt
->profile
) {
2995 start
= xsltTimestamp();
2997 profCallgraphAdd(templ
, ctxt
->templ
);
3000 * Push the xsl:template declaration onto the stack.
3002 templPush(ctxt
, templ
);
3004 #ifdef WITH_XSLT_DEBUG_PROCESS
3005 if (templ
->name
!= NULL
)
3006 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
3007 "applying xsl:template '%s'\n", templ
->name
));
3010 * Process xsl:param instructions and skip those elements for
3011 * further processing.
3015 if (cur
->type
== XML_TEXT_NODE
) {
3019 if ((cur
->type
!= XML_ELEMENT_NODE
) ||
3020 (cur
->name
[0] != 'p') ||
3021 (cur
->psvi
== NULL
) ||
3022 (! xmlStrEqual(cur
->name
, BAD_CAST
"param")) ||
3023 (! IS_XSLT_ELEM(cur
)))
3030 #ifdef XSLT_REFACTORED
3031 iparam
= (xsltStyleItemParamPtr
) cur
->psvi
;
3033 iparam
= (xsltStylePreCompPtr
) cur
->psvi
;
3037 * Substitute xsl:param for a given xsl:with-param.
3038 * Since the XPath expression will reference the params/vars
3039 * by index, we need to slot the xsl:with-params in the
3040 * order of encountered xsl:params to keep the sequence of
3041 * params/variables in the stack exactly as it was at
3046 tmpParam
= withParams
;
3048 if ((tmpParam
->name
== (iparam
->name
)) &&
3049 (tmpParam
->nameURI
== (iparam
->ns
)))
3052 * Push the caller-parameter.
3054 xsltLocalVariablePush(ctxt
, tmpParam
, -1);
3057 tmpParam
= tmpParam
->next
;
3058 } while (tmpParam
!= NULL
);
3061 * Push the xsl:param.
3063 if (tmpParam
== NULL
) {
3065 * Note that we must assume that the added parameter
3066 * has a @depth of 0.
3068 xsltParseStylesheetParam(ctxt
, cur
);
3071 } while (cur
!= NULL
);
3073 * Process the sequence constructor.
3075 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3078 * Remove remaining xsl:param and xsl:with-param items from
3079 * the stack. Don't free xsl:with-param items.
3081 if (ctxt
->varsNr
> ctxt
->varsBase
)
3082 xsltTemplateParamsCleanup(ctxt
);
3083 ctxt
->varsBase
= oldVarsBase
;
3086 * Clean up remaining local tree fragments.
3087 * This also frees fragments which are the result of
3088 * extension instructions. Should normally not be hit; but
3089 * just for the case xsltExtensionInstructionResultFinalize()
3090 * was not called by the extension author.
3092 if (oldLocalFragmentTop
!= ctxt
->localRVT
) {
3093 xmlDocPtr curdoc
= ctxt
->localRVT
, tmp
;
3097 curdoc
= (xmlDocPtr
) curdoc
->next
;
3098 /* Need to housekeep localRVTBase */
3099 if (tmp
== ctxt
->localRVTBase
)
3100 ctxt
->localRVTBase
= curdoc
;
3102 tmp
->prev
->next
= (xmlNodePtr
) curdoc
;
3104 curdoc
->prev
= tmp
->prev
;
3105 xsltReleaseRVT(ctxt
, tmp
);
3106 } while (curdoc
!= oldLocalFragmentTop
);
3108 ctxt
->localRVT
= oldLocalFragmentTop
;
3111 * Release user-created fragments stored in the scope
3112 * of xsl:template. Note that this mechanism is deprecated:
3113 * user code should now use xsltRegisterLocalRVT() instead
3114 * of the obsolete xsltRegisterTmpRVT().
3117 xmlDocPtr curdoc
= ctxt
->tmpRVT
, tmp
;
3119 while (curdoc
!= NULL
) {
3121 curdoc
= (xmlDocPtr
) curdoc
->next
;
3122 xsltReleaseRVT(ctxt
, tmp
);
3125 ctxt
->tmpRVT
= oldUserFragmentTop
;
3128 * Pop the xsl:template declaration from the stack.
3131 if (ctxt
->profile
) {
3132 long spent
, child
, total
, end
;
3134 end
= xsltTimestamp();
3135 child
= profPop(ctxt
);
3136 total
= end
- start
;
3137 spent
= total
- child
;
3140 * Not possible unless the original calibration failed
3141 * we can try to correct it on the fly.
3143 xsltCalibrateAdjust(spent
);
3147 templ
->time
+= spent
;
3148 if (ctxt
->profNr
> 0)
3149 ctxt
->profTab
[ctxt
->profNr
- 1] += total
;
3152 #ifdef WITH_DEBUGGER
3153 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (addCallResult
)) {
3161 * xsltApplyOneTemplate:
3162 * @ctxt: a XSLT process context
3163 * @contextNode: the node in the source tree.
3164 * @list: the nodes of a sequence constructor
3166 * @params: a set of parameters (xsl:param) or NULL
3168 * Processes a sequence constructor on the current node in the source tree.
3170 * @params are the already computed variable stack items; this function
3171 * pushes them on the variable stack, and pops them before exiting; it's
3172 * left to the caller to free or reuse @params afterwards. The initial
3173 * states of the variable stack will always be restored before this
3175 * NOTE that this does *not* initiate a new distinct variable scope; i.e.
3176 * variables already on the stack are visible to the process. The caller's
3177 * side needs to start a new variable scope if needed (e.g. in exsl:function).
3179 * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
3180 * provide a @templ); a non-NULL @templ might raise an error in the future.
3182 * BIG NOTE: This function is not intended to process the content of an
3183 * xsl:template; it does not expect xsl:param instructions in @list and
3184 * will report errors if found.
3187 * - xsltEvalVariable() (variables.c)
3188 * - exsltFuncFunctionFunction() (libexsl/functions.c)
3191 xsltApplyOneTemplate(xsltTransformContextPtr ctxt
,
3192 xmlNodePtr contextNode
,
3194 xsltTemplatePtr templ ATTRIBUTE_UNUSED
,
3195 xsltStackElemPtr params
)
3197 if ((ctxt
== NULL
) || (list
== NULL
))
3203 * This code should be obsolete - was previously used
3204 * by libexslt/functions.c, but due to bug 381319 the
3205 * logic there was changed.
3207 int oldVarsNr
= ctxt
->varsNr
;
3210 * Push the given xsl:param(s) onto the variable stack.
3212 while (params
!= NULL
) {
3213 xsltLocalVariablePush(ctxt
, params
, -1);
3214 params
= params
->next
;
3216 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3218 * Pop the given xsl:param(s) from the stack but don't free them.
3220 xsltLocalVariablePop(ctxt
, oldVarsNr
, -2);
3222 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3225 /************************************************************************
3227 * XSLT-1.1 extensions *
3229 ************************************************************************/
3233 * @ctxt: an XSLT processing context
3234 * @node: The current node
3235 * @inst: the instruction in the stylesheet
3236 * @castedComp: precomputed information
3238 * Process an EXSLT/XSLT-1.1 document element
3241 xsltDocumentElem(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3242 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
3244 #ifdef XSLT_REFACTORED
3245 xsltStyleItemDocumentPtr comp
= (xsltStyleItemDocumentPtr
) castedComp
;
3247 xsltStylePreCompPtr comp
= castedComp
;
3249 xsltStylesheetPtr style
= NULL
;
3251 xmlChar
*filename
= NULL
, *prop
, *elements
;
3252 xmlChar
*element
, *end
;
3253 xmlDocPtr res
= NULL
;
3254 xmlDocPtr oldOutput
;
3255 xmlNodePtr oldInsert
, root
;
3256 const char *oldOutputFile
;
3257 xsltOutputType oldType
;
3258 xmlChar
*URL
= NULL
;
3259 const xmlChar
*method
;
3260 const xmlChar
*doctypePublic
;
3261 const xmlChar
*doctypeSystem
;
3262 const xmlChar
*version
;
3263 const xmlChar
*encoding
;
3264 int redirect_write_append
= 0;
3266 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
3269 if (comp
->filename
== NULL
) {
3271 if (xmlStrEqual(inst
->name
, (const xmlChar
*) "output")) {
3273 * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
3274 * (http://icl.com/saxon)
3275 * The @file is in no namespace.
3277 #ifdef WITH_XSLT_DEBUG_EXTRA
3278 xsltGenericDebug(xsltGenericDebugContext
,
3279 "Found saxon:output extension\n");
3281 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3282 (const xmlChar
*) "file",
3283 XSLT_SAXON_NAMESPACE
);
3286 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3287 (const xmlChar
*) "href",
3288 XSLT_SAXON_NAMESPACE
);
3289 } else if (xmlStrEqual(inst
->name
, (const xmlChar
*) "write")) {
3290 #ifdef WITH_XSLT_DEBUG_EXTRA
3291 xsltGenericDebug(xsltGenericDebugContext
,
3292 "Found xalan:write extension\n");
3294 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3297 XSLT_XALAN_NAMESPACE
);
3299 xmlXPathCompExprPtr cmp
;
3303 * Trying to handle bug #59212
3304 * The value of the "select" attribute is an
3306 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
3308 cmp
= xmlXPathCompile(URL
);
3309 val
= xsltEvalXPathString(ctxt
, cmp
);
3310 xmlXPathFreeCompExpr(cmp
);
3315 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3318 XSLT_XALAN_NAMESPACE
);
3320 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3323 XSLT_XALAN_NAMESPACE
);
3324 } else if (xmlStrEqual(inst
->name
, (const xmlChar
*) "document")) {
3325 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3326 (const xmlChar
*) "href",
3331 URL
= xmlStrdup(comp
->filename
);
3335 xsltTransformError(ctxt
, NULL
, inst
,
3336 "xsltDocumentElem: href/URI-Reference not found\n");
3341 * If the computation failed, it's likely that the URL wasn't escaped
3343 filename
= xmlBuildURI(URL
, (const xmlChar
*) ctxt
->outputFile
);
3344 if (filename
== NULL
) {
3347 escURL
=xmlURIEscapeStr(URL
, BAD_CAST
":/.?,");
3348 if (escURL
!= NULL
) {
3349 filename
= xmlBuildURI(escURL
, (const xmlChar
*) ctxt
->outputFile
);
3354 if (filename
== NULL
) {
3355 xsltTransformError(ctxt
, NULL
, inst
,
3356 "xsltDocumentElem: URL computation failed for %s\n",
3363 * Security checking: can we write to this resource
3365 if (ctxt
->sec
!= NULL
) {
3366 ret
= xsltCheckWrite(ctxt
->sec
, ctxt
, filename
);
3368 xsltTransformError(ctxt
, NULL
, inst
,
3369 "xsltDocumentElem: write rights for %s denied\n",
3377 oldOutputFile
= ctxt
->outputFile
;
3378 oldOutput
= ctxt
->output
;
3379 oldInsert
= ctxt
->insert
;
3380 oldType
= ctxt
->type
;
3381 ctxt
->outputFile
= (const char *) filename
;
3383 style
= xsltNewStylesheet();
3384 if (style
== NULL
) {
3385 xsltTransformError(ctxt
, NULL
, inst
,
3386 "xsltDocumentElem: out of memory\n");
3391 * Version described in 1.1 draft allows full parameterization
3394 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3395 (const xmlChar
*) "version",
3398 if (style
->version
!= NULL
)
3399 xmlFree(style
->version
);
3400 style
->version
= prop
;
3402 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3403 (const xmlChar
*) "encoding",
3406 if (style
->encoding
!= NULL
)
3407 xmlFree(style
->encoding
);
3408 style
->encoding
= prop
;
3410 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3411 (const xmlChar
*) "method",
3416 if (style
->method
!= NULL
)
3417 xmlFree(style
->method
);
3418 style
->method
= NULL
;
3419 if (style
->methodURI
!= NULL
)
3420 xmlFree(style
->methodURI
);
3421 style
->methodURI
= NULL
;
3423 URI
= xsltGetQNameURI(inst
, &prop
);
3425 if (style
!= NULL
) style
->errors
++;
3426 } else if (URI
== NULL
) {
3427 if ((xmlStrEqual(prop
, (const xmlChar
*) "xml")) ||
3428 (xmlStrEqual(prop
, (const xmlChar
*) "html")) ||
3429 (xmlStrEqual(prop
, (const xmlChar
*) "text"))) {
3430 style
->method
= prop
;
3432 xsltTransformError(ctxt
, NULL
, inst
,
3433 "invalid value for method: %s\n", prop
);
3434 if (style
!= NULL
) style
->warnings
++;
3437 style
->method
= prop
;
3438 style
->methodURI
= xmlStrdup(URI
);
3441 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3443 "doctype-system", NULL
);
3445 if (style
->doctypeSystem
!= NULL
)
3446 xmlFree(style
->doctypeSystem
);
3447 style
->doctypeSystem
= prop
;
3449 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3451 "doctype-public", NULL
);
3453 if (style
->doctypePublic
!= NULL
)
3454 xmlFree(style
->doctypePublic
);
3455 style
->doctypePublic
= prop
;
3457 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3458 (const xmlChar
*) "standalone",
3461 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3462 style
->standalone
= 1;
3463 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3464 style
->standalone
= 0;
3466 xsltTransformError(ctxt
, NULL
, inst
,
3467 "invalid value for standalone: %s\n",
3469 if (style
!= NULL
) style
->warnings
++;
3474 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3475 (const xmlChar
*) "indent",
3478 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3480 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3483 xsltTransformError(ctxt
, NULL
, inst
,
3484 "invalid value for indent: %s\n", prop
);
3485 if (style
!= NULL
) style
->warnings
++;
3490 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3492 "omit-xml-declaration",
3495 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3496 style
->omitXmlDeclaration
= 1;
3497 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3498 style
->omitXmlDeclaration
= 0;
3500 xsltTransformError(ctxt
, NULL
, inst
,
3501 "invalid value for omit-xml-declaration: %s\n",
3503 if (style
!= NULL
) style
->warnings
++;
3508 elements
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3510 "cdata-section-elements",
3512 if (elements
!= NULL
) {
3513 if (style
->stripSpaces
== NULL
)
3514 style
->stripSpaces
= xmlHashCreate(10);
3515 if (style
->stripSpaces
== NULL
)
3519 while (*element
!= 0) {
3520 while (IS_BLANK_CH(*element
))
3525 while ((*end
!= 0) && (!IS_BLANK_CH(*end
)))
3527 element
= xmlStrndup(element
, end
- element
);
3531 #ifdef WITH_XSLT_DEBUG_PARSING
3532 xsltGenericDebug(xsltGenericDebugContext
,
3533 "add cdata section output element %s\n",
3536 URI
= xsltGetQNameURI(inst
, &element
);
3538 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
3539 (xmlChar
*) "cdata");
3548 * Create a new document tree and process the element template
3550 XSLT_GET_IMPORT_PTR(method
, style
, method
)
3551 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
3552 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
3553 XSLT_GET_IMPORT_PTR(version
, style
, version
)
3554 XSLT_GET_IMPORT_PTR(encoding
, style
, encoding
)
3556 if ((method
!= NULL
) &&
3557 (!xmlStrEqual(method
, (const xmlChar
*) "xml"))) {
3558 if (xmlStrEqual(method
, (const xmlChar
*) "html")) {
3559 ctxt
->type
= XSLT_OUTPUT_HTML
;
3560 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3561 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
3563 if (version
!= NULL
) {
3564 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3565 xsltGetHTMLIDs(version
, &doctypePublic
, &doctypeSystem
);
3568 res
= htmlNewDocNoDtD(doctypeSystem
, doctypePublic
);
3572 res
->dict
= ctxt
->dict
;
3573 xmlDictReference(res
->dict
);
3574 } else if (xmlStrEqual(method
, (const xmlChar
*) "xhtml")) {
3575 xsltTransformError(ctxt
, NULL
, inst
,
3576 "xsltDocumentElem: unsupported method xhtml\n",
3578 ctxt
->type
= XSLT_OUTPUT_HTML
;
3579 res
= htmlNewDocNoDtD(doctypeSystem
, doctypePublic
);
3582 res
->dict
= ctxt
->dict
;
3583 xmlDictReference(res
->dict
);
3584 } else if (xmlStrEqual(method
, (const xmlChar
*) "text")) {
3585 ctxt
->type
= XSLT_OUTPUT_TEXT
;
3586 res
= xmlNewDoc(style
->version
);
3589 res
->dict
= ctxt
->dict
;
3590 xmlDictReference(res
->dict
);
3591 #ifdef WITH_XSLT_DEBUG
3592 xsltGenericDebug(xsltGenericDebugContext
,
3593 "reusing transformation dict for output\n");
3596 xsltTransformError(ctxt
, NULL
, inst
,
3597 "xsltDocumentElem: unsupported method %s\n",
3602 ctxt
->type
= XSLT_OUTPUT_XML
;
3603 res
= xmlNewDoc(style
->version
);
3606 res
->dict
= ctxt
->dict
;
3607 xmlDictReference(res
->dict
);
3608 #ifdef WITH_XSLT_DEBUG
3609 xsltGenericDebug(xsltGenericDebugContext
,
3610 "reusing transformation dict for output\n");
3613 res
->charset
= XML_CHAR_ENCODING_UTF8
;
3614 if (encoding
!= NULL
)
3615 res
->encoding
= xmlStrdup(encoding
);
3617 ctxt
->insert
= (xmlNodePtr
) res
;
3618 xsltApplySequenceConstructor(ctxt
, node
, inst
->children
, NULL
);
3621 * Do some post processing work depending on the generated output
3623 root
= xmlDocGetRootElement(res
);
3625 const xmlChar
*doctype
= NULL
;
3627 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
))
3628 doctype
= xmlDictQLookup(ctxt
->dict
, root
->ns
->prefix
, root
->name
);
3629 if (doctype
== NULL
)
3630 doctype
= root
->name
;
3633 * Apply the default selection of the method
3635 if ((method
== NULL
) &&
3636 (root
->ns
== NULL
) &&
3637 (!xmlStrcasecmp(root
->name
, (const xmlChar
*) "html"))) {
3640 tmp
= res
->children
;
3641 while ((tmp
!= NULL
) && (tmp
!= root
)) {
3642 if (tmp
->type
== XML_ELEMENT_NODE
)
3644 if ((tmp
->type
== XML_TEXT_NODE
) && (!xmlIsBlankNode(tmp
)))
3649 ctxt
->type
= XSLT_OUTPUT_HTML
;
3650 res
->type
= XML_HTML_DOCUMENT_NODE
;
3651 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
3652 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
3655 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3656 } else if (version
!= NULL
) {
3657 xsltGetHTMLIDs(version
, &doctypePublic
,
3659 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3661 xmlCreateIntSubset(res
, doctype
,
3669 if (ctxt
->type
== XSLT_OUTPUT_XML
) {
3670 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
3671 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
3672 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3673 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
3680 * Calls to redirect:write also take an optional attribute append.
3681 * Attribute append="true|yes" which will attempt to simply append
3682 * to an existing file instead of always opening a new file. The
3683 * default behavior of always overwriting the file still happens
3684 * if we do not specify append.
3685 * Note that append use will forbid use of remote URI target.
3687 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
, (const xmlChar
*)"append",
3690 if (xmlStrEqual(prop
, (const xmlChar
*) "true") ||
3691 xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3692 style
->omitXmlDeclaration
= 1;
3693 redirect_write_append
= 1;
3695 style
->omitXmlDeclaration
= 0;
3699 if (redirect_write_append
) {
3702 f
= fopen((const char *) filename
, "ab");
3706 ret
= xsltSaveResultToFile(f
, res
, style
);
3710 ret
= xsltSaveResultToFilename((const char *) filename
, res
, style
, 0);
3713 xsltTransformError(ctxt
, NULL
, inst
,
3714 "xsltDocumentElem: unable to save to %s\n",
3716 ctxt
->state
= XSLT_STATE_ERROR
;
3717 #ifdef WITH_XSLT_DEBUG_EXTRA
3719 xsltGenericDebug(xsltGenericDebugContext
,
3720 "Wrote %d bytes to %s\n", ret
, filename
);
3725 ctxt
->output
= oldOutput
;
3726 ctxt
->insert
= oldInsert
;
3727 ctxt
->type
= oldType
;
3728 ctxt
->outputFile
= oldOutputFile
;
3731 if (filename
!= NULL
)
3734 xsltFreeStylesheet(style
);
3739 /************************************************************************
3741 * Most of the XSLT-1.0 transformations *
3743 ************************************************************************/
3747 * @ctxt: a XSLT process context
3748 * @node: the node in the source tree.
3749 * @inst: the xslt sort node
3750 * @comp: precomputed information
3752 * function attached to xsl:sort nodes, but this should not be
3756 xsltSort(xsltTransformContextPtr ctxt
,
3757 xmlNodePtr node ATTRIBUTE_UNUSED
, xmlNodePtr inst
,
3758 xsltStylePreCompPtr comp
) {
3760 xsltTransformError(ctxt
, NULL
, inst
,
3761 "xsl:sort : compilation failed\n");
3764 xsltTransformError(ctxt
, NULL
, inst
,
3765 "xsl:sort : improper use this should not be reached\n");
3770 * @ctxt: an XSLT process context
3771 * @node: the node in the source tree
3772 * @inst: the element node of the XSLT-copy instruction
3773 * @castedComp: computed information of the XSLT-copy instruction
3775 * Execute the XSLT-copy instruction on the source node.
3778 xsltCopy(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3779 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
3781 #ifdef XSLT_REFACTORED
3782 xsltStyleItemCopyPtr comp
= (xsltStyleItemCopyPtr
) castedComp
;
3784 xsltStylePreCompPtr comp
= castedComp
;
3786 xmlNodePtr copy
, oldInsert
;
3788 oldInsert
= ctxt
->insert
;
3789 if (ctxt
->insert
!= NULL
) {
3790 switch (node
->type
) {
3792 case XML_CDATA_SECTION_NODE
:
3794 * This text comes from the stylesheet
3795 * For stylesheets, the set of whitespace-preserving
3796 * element names consists of just xsl:text.
3798 #ifdef WITH_XSLT_DEBUG_PROCESS
3799 if (node
->type
== XML_CDATA_SECTION_NODE
) {
3800 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3801 "xsltCopy: CDATA text %s\n", node
->content
));
3803 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3804 "xsltCopy: text %s\n", node
->content
));
3807 xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
3809 case XML_DOCUMENT_NODE
:
3810 case XML_HTML_DOCUMENT_NODE
:
3812 case XML_ELEMENT_NODE
:
3814 * REVISIT NOTE: The "fake" is a doc-node, not an element node.
3816 * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3820 #ifdef WITH_XSLT_DEBUG_PROCESS
3821 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3822 "xsltCopy: node %s\n", node
->name
));
3824 copy
= xsltShallowCopyElem(ctxt
, node
, ctxt
->insert
, 0);
3825 ctxt
->insert
= copy
;
3826 if (comp
->use
!= NULL
) {
3827 xsltApplyAttributeSet(ctxt
, node
, inst
, comp
->use
);
3830 case XML_ATTRIBUTE_NODE
: {
3831 #ifdef WITH_XSLT_DEBUG_PROCESS
3832 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3833 "xsltCopy: attribute %s\n", node
->name
));
3836 * REVISIT: We could also raise an error if the parent is not
3838 * OPTIMIZE TODO: Can we set the value/children of the
3839 * attribute without an intermediate copy of the string value?
3841 xsltShallowCopyAttr(ctxt
, inst
, ctxt
->insert
, (xmlAttrPtr
) node
);
3845 #ifdef WITH_XSLT_DEBUG_PROCESS
3846 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3847 "xsltCopy: PI %s\n", node
->name
));
3849 copy
= xmlNewDocPI(ctxt
->insert
->doc
, node
->name
,
3851 copy
= xsltAddChild(ctxt
->insert
, copy
);
3853 case XML_COMMENT_NODE
:
3854 #ifdef WITH_XSLT_DEBUG_PROCESS
3855 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3856 "xsltCopy: comment\n"));
3858 copy
= xmlNewComment(node
->content
);
3859 copy
= xsltAddChild(ctxt
->insert
, copy
);
3861 case XML_NAMESPACE_DECL
:
3862 #ifdef WITH_XSLT_DEBUG_PROCESS
3863 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3864 "xsltCopy: namespace declaration\n"));
3866 xsltShallowCopyNsNode(ctxt
, inst
, ctxt
->insert
, (xmlNsPtr
)node
);
3874 switch (node
->type
) {
3875 case XML_DOCUMENT_NODE
:
3876 case XML_HTML_DOCUMENT_NODE
:
3877 case XML_ELEMENT_NODE
:
3878 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, inst
->children
,
3884 ctxt
->insert
= oldInsert
;
3889 * @ctxt: a XSLT process context
3890 * @node: the node in the source tree.
3891 * @inst: the xslt text node
3892 * @comp: precomputed information
3894 * Process the xslt text node on the source node
3897 xsltText(xsltTransformContextPtr ctxt
, xmlNodePtr node ATTRIBUTE_UNUSED
,
3898 xmlNodePtr inst
, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED
) {
3899 if ((inst
->children
!= NULL
) && (comp
!= NULL
)) {
3900 xmlNodePtr text
= inst
->children
;
3903 while (text
!= NULL
) {
3904 if ((text
->type
!= XML_TEXT_NODE
) &&
3905 (text
->type
!= XML_CDATA_SECTION_NODE
)) {
3906 xsltTransformError(ctxt
, NULL
, inst
,
3907 "xsl:text content problem\n");
3910 copy
= xmlNewDocText(ctxt
->output
, text
->content
);
3911 if (text
->type
!= XML_CDATA_SECTION_NODE
) {
3912 #ifdef WITH_XSLT_DEBUG_PARSING
3913 xsltGenericDebug(xsltGenericDebugContext
,
3914 "Disable escaping: %s\n", text
->content
);
3916 copy
->name
= xmlStringTextNoenc
;
3918 copy
= xsltAddChild(ctxt
->insert
, copy
);
3926 * @ctxt: a XSLT process context
3927 * @node: the node in the source tree.
3928 * @inst: the xslt element node
3929 * @castedComp: precomputed information
3931 * Process the xslt element node on the source node
3934 xsltElement(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3935 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
) {
3936 #ifdef XSLT_REFACTORED
3937 xsltStyleItemElementPtr comp
= (xsltStyleItemElementPtr
) castedComp
;
3939 xsltStylePreCompPtr comp
= castedComp
;
3941 xmlChar
*prop
= NULL
;
3942 const xmlChar
*name
, *prefix
= NULL
, *nsName
= NULL
;
3944 xmlNodePtr oldInsert
;
3946 if (ctxt
->insert
== NULL
)
3950 * A comp->has_name == 0 indicates that we need to skip this instruction,
3951 * since it was evaluated to be invalid already during compilation.
3953 if (!comp
->has_name
)
3959 oldInsert
= ctxt
->insert
;
3961 if (comp
->name
== NULL
) {
3962 /* TODO: fix attr acquisition wrt to the XSLT namespace */
3963 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3964 (const xmlChar
*) "name", XSLT_NAMESPACE
);
3966 xsltTransformError(ctxt
, NULL
, inst
,
3967 "xsl:element: The attribute 'name' is missing.\n");
3970 if (xmlValidateQName(prop
, 0)) {
3971 xsltTransformError(ctxt
, NULL
, inst
,
3972 "xsl:element: The effective name '%s' is not a "
3973 "valid QName.\n", prop
);
3974 /* we fall through to catch any further errors, if possible */
3976 name
= xsltSplitQName(ctxt
->dict
, prop
, &prefix
);
3980 * The "name" value was static.
3982 #ifdef XSLT_REFACTORED
3983 prefix
= comp
->nsPrefix
;
3986 name
= xsltSplitQName(ctxt
->dict
, comp
->name
, &prefix
);
3991 * Create the new element
3993 if (ctxt
->output
->dict
== ctxt
->dict
) {
3994 copy
= xmlNewDocNodeEatName(ctxt
->output
, NULL
, (xmlChar
*)name
, NULL
);
3996 copy
= xmlNewDocNode(ctxt
->output
, NULL
, (xmlChar
*)name
, NULL
);
3999 xsltTransformError(ctxt
, NULL
, inst
,
4000 "xsl:element : creation of %s failed\n", name
);
4003 copy
= xsltAddChild(ctxt
->insert
, copy
);
4010 if (comp
->ns
!= NULL
) {
4012 * No AVT; just plain text for the namespace name.
4014 if (comp
->ns
[0] != 0)
4021 /* TODO: check attr acquisition wrt to the XSLT namespace */
4022 tmpNsName
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4023 (const xmlChar
*) "namespace", XSLT_NAMESPACE
);
4026 * "If the string is empty, then the expanded-name of the
4027 * attribute has a null namespace URI."
4029 if ((tmpNsName
!= NULL
) && (tmpNsName
[0] != 0))
4030 nsName
= xmlDictLookup(ctxt
->dict
, BAD_CAST tmpNsName
, -1);
4034 if (xmlStrEqual(nsName
, BAD_CAST
"http://www.w3.org/2000/xmlns/")) {
4035 xsltTransformError(ctxt
, NULL
, inst
,
4036 "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
4040 if (xmlStrEqual(nsName
, XML_XML_NAMESPACE
)) {
4041 prefix
= BAD_CAST
"xml";
4042 } else if (xmlStrEqual(prefix
, BAD_CAST
"xml")) {
4049 * "If the namespace attribute is not present, then the QName is
4050 * expanded into an expanded-name using the namespace declarations
4051 * in effect for the xsl:element element, including any default
4052 * namespace declaration.
4054 ns
= xmlSearchNs(inst
->doc
, inst
, prefix
);
4057 * TODO: Check this in the compilation layer in case it's a
4060 if (prefix
!= NULL
) {
4061 xsltTransformError(ctxt
, NULL
, inst
,
4062 "xsl:element: The QName '%s:%s' has no "
4063 "namespace binding in scope in the stylesheet; "
4064 "this is an error, since the namespace was not "
4065 "specified by the instruction itself.\n", prefix
, name
);
4071 * Find/create a matching ns-decl in the result tree.
4073 if (nsName
!= NULL
) {
4074 if (xmlStrEqual(prefix
, BAD_CAST
"xmlns")) {
4075 /* Don't use a prefix of "xmlns" */
4076 xmlChar
*pref
= xmlStrdup(BAD_CAST
"ns_1");
4078 copy
->ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, pref
, copy
);
4082 copy
->ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, prefix
,
4085 } else if ((copy
->parent
!= NULL
) &&
4086 (copy
->parent
->type
== XML_ELEMENT_NODE
) &&
4087 (copy
->parent
->ns
!= NULL
))
4090 * "Undeclare" the default namespace.
4092 xsltGetSpecialNamespace(ctxt
, inst
, NULL
, NULL
, copy
);
4095 ctxt
->insert
= copy
;
4097 if (comp
->has_use
) {
4098 if (comp
->use
!= NULL
) {
4099 xsltApplyAttributeSet(ctxt
, node
, inst
, comp
->use
);
4101 xmlChar
*attrSets
= NULL
;
4103 * BUG TODO: use-attribute-sets is not a value template.
4104 * use-attribute-sets = qnames
4106 attrSets
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4107 (const xmlChar
*)"use-attribute-sets", NULL
);
4108 if (attrSets
!= NULL
) {
4109 xsltApplyAttributeSet(ctxt
, node
, inst
, attrSets
);
4115 * Instantiate the sequence constructor.
4117 if (inst
->children
!= NULL
)
4118 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, inst
->children
,
4122 ctxt
->insert
= oldInsert
;
4129 * @ctxt: a XSLT process context
4130 * @node: the node in the source tree.
4131 * @inst: the xslt comment node
4132 * @comp: precomputed information
4134 * Process the xslt comment node on the source node
4137 xsltComment(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4138 xmlNodePtr inst
, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED
) {
4139 xmlChar
*value
= NULL
;
4140 xmlNodePtr commentNode
;
4143 value
= xsltEvalTemplateString(ctxt
, node
, inst
);
4144 /* TODO: use or generate the compiled form */
4145 len
= xmlStrlen(value
);
4147 if ((value
[len
-1] == '-') ||
4148 (xmlStrstr(value
, BAD_CAST
"--"))) {
4149 xsltTransformError(ctxt
, NULL
, inst
,
4150 "xsl:comment : '--' or ending '-' not allowed in comment\n");
4151 /* fall through to try to catch further errors */
4154 #ifdef WITH_XSLT_DEBUG_PROCESS
4155 if (value
== NULL
) {
4156 XSLT_TRACE(ctxt
,XSLT_TRACE_COMMENT
,xsltGenericDebug(xsltGenericDebugContext
,
4157 "xsltComment: empty\n"));
4159 XSLT_TRACE(ctxt
,XSLT_TRACE_COMMENT
,xsltGenericDebug(xsltGenericDebugContext
,
4160 "xsltComment: content %s\n", value
));
4164 commentNode
= xmlNewComment(value
);
4165 commentNode
= xsltAddChild(ctxt
->insert
, commentNode
);
4172 * xsltProcessingInstruction:
4173 * @ctxt: a XSLT process context
4174 * @node: the node in the source tree.
4175 * @inst: the xslt processing-instruction node
4176 * @castedComp: precomputed information
4178 * Process the xslt processing-instruction node on the source node
4181 xsltProcessingInstruction(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4182 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
) {
4183 #ifdef XSLT_REFACTORED
4184 xsltStyleItemPIPtr comp
= (xsltStyleItemPIPtr
) castedComp
;
4186 xsltStylePreCompPtr comp
= castedComp
;
4188 const xmlChar
*name
;
4189 xmlChar
*value
= NULL
;
4193 if (ctxt
->insert
== NULL
)
4195 if (comp
->has_name
== 0)
4197 if (comp
->name
== NULL
) {
4198 name
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4199 (const xmlChar
*)"name", NULL
);
4201 xsltTransformError(ctxt
, NULL
, inst
,
4202 "xsl:processing-instruction : name is missing\n");
4208 /* TODO: check that it's both an an NCName and a PITarget. */
4211 value
= xsltEvalTemplateString(ctxt
, node
, inst
);
4212 if (xmlStrstr(value
, BAD_CAST
"?>") != NULL
) {
4213 xsltTransformError(ctxt
, NULL
, inst
,
4214 "xsl:processing-instruction: '?>' not allowed within PI content\n");
4217 #ifdef WITH_XSLT_DEBUG_PROCESS
4218 if (value
== NULL
) {
4219 XSLT_TRACE(ctxt
,XSLT_TRACE_PI
,xsltGenericDebug(xsltGenericDebugContext
,
4220 "xsltProcessingInstruction: %s empty\n", name
));
4222 XSLT_TRACE(ctxt
,XSLT_TRACE_PI
,xsltGenericDebug(xsltGenericDebugContext
,
4223 "xsltProcessingInstruction: %s content %s\n", name
, value
));
4227 pi
= xmlNewDocPI(ctxt
->insert
->doc
, name
, value
);
4228 pi
= xsltAddChild(ctxt
->insert
, pi
);
4231 if ((name
!= NULL
) && (name
!= comp
->name
))
4232 xmlFree((xmlChar
*) name
);
4239 * @ctxt: an XSLT transformation context
4240 * @node: the current node in the source tree
4241 * @inst: the element node of the XSLT copy-of instruction
4242 * @castedComp: precomputed information of the XSLT copy-of instruction
4244 * Process the XSLT copy-of instruction.
4247 xsltCopyOf(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4248 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
) {
4249 #ifdef XSLT_REFACTORED
4250 xsltStyleItemCopyOfPtr comp
= (xsltStyleItemCopyOfPtr
) castedComp
;
4252 xsltStylePreCompPtr comp
= castedComp
;
4254 xmlXPathObjectPtr res
= NULL
;
4255 xmlNodeSetPtr list
= NULL
;
4257 xmlDocPtr oldXPContextDoc
;
4258 xmlNsPtr
*oldXPNamespaces
;
4259 xmlNodePtr oldXPContextNode
;
4260 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
4261 xmlXPathContextPtr xpctxt
;
4263 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
))
4265 if ((comp
== NULL
) || (comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
4266 xsltTransformError(ctxt
, NULL
, inst
,
4267 "xsl:copy-of : compilation failed\n");
4273 * "The xsl:copy-of element can be used to insert a result tree
4274 * fragment into the result tree, without first converting it to
4275 * a string as xsl:value-of does (see [7.6.1 Generating Text with
4276 * xsl:value-of]). The required select attribute contains an
4277 * expression. When the result of evaluating the expression is a
4278 * result tree fragment, the complete fragment is copied into the
4279 * result tree. When the result is a node-set, all the nodes in the
4280 * set are copied in document order into the result tree; copying
4281 * an element node copies the attribute nodes, namespace nodes and
4282 * children of the element node as well as the element node itself;
4283 * a root node is copied by copying its children. When the result
4284 * is neither a node-set nor a result tree fragment, the result is
4285 * converted to a string and then inserted into the result tree,
4286 * as with xsl:value-of.
4289 #ifdef WITH_XSLT_DEBUG_PROCESS
4290 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4291 "xsltCopyOf: select %s\n", comp
->select
));
4295 * Evaluate the "select" expression.
4297 xpctxt
= ctxt
->xpathCtxt
;
4298 oldXPContextDoc
= xpctxt
->doc
;
4299 oldXPContextNode
= xpctxt
->node
;
4300 oldXPProximityPosition
= xpctxt
->proximityPosition
;
4301 oldXPContextSize
= xpctxt
->contextSize
;
4302 oldXPNsNr
= xpctxt
->nsNr
;
4303 oldXPNamespaces
= xpctxt
->namespaces
;
4305 xpctxt
->node
= node
;
4308 #ifdef XSLT_REFACTORED
4309 if (comp
->inScopeNs
!= NULL
) {
4310 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
4311 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
4313 xpctxt
->namespaces
= NULL
;
4317 xpctxt
->namespaces
= comp
->nsList
;
4318 xpctxt
->nsNr
= comp
->nsNr
;
4321 xpctxt
->namespaces
= NULL
;
4325 res
= xmlXPathCompiledEval(comp
->comp
, xpctxt
);
4327 xpctxt
->doc
= oldXPContextDoc
;
4328 xpctxt
->node
= oldXPContextNode
;
4329 xpctxt
->contextSize
= oldXPContextSize
;
4330 xpctxt
->proximityPosition
= oldXPProximityPosition
;
4331 xpctxt
->nsNr
= oldXPNsNr
;
4332 xpctxt
->namespaces
= oldXPNamespaces
;
4335 if (res
->type
== XPATH_NODESET
) {
4340 #ifdef WITH_XSLT_DEBUG_PROCESS
4341 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4342 "xsltCopyOf: result is a node set\n"));
4344 list
= res
->nodesetval
;
4348 * The list is already sorted in document order by XPath.
4349 * Append everything in this order under ctxt->insert.
4351 for (i
= 0;i
< list
->nodeNr
;i
++) {
4352 cur
= list
->nodeTab
[i
];
4355 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
4356 (cur
->type
== XML_HTML_DOCUMENT_NODE
))
4358 xsltCopyTreeList(ctxt
, inst
,
4359 cur
->children
, ctxt
->insert
, 0, 0);
4360 } else if (cur
->type
== XML_ATTRIBUTE_NODE
) {
4361 xsltShallowCopyAttr(ctxt
, inst
,
4362 ctxt
->insert
, (xmlAttrPtr
) cur
);
4364 xsltCopyTreeInternal(ctxt
, inst
,
4365 cur
, ctxt
->insert
, 0, 0);
4369 } else if (res
->type
== XPATH_XSLT_TREE
) {
4371 * Result tree fragment
4372 * --------------------
4373 * E.g. via <xsl:variable ...><foo/></xsl:variable>
4374 * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4376 #ifdef WITH_XSLT_DEBUG_PROCESS
4377 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4378 "xsltCopyOf: result is a result tree fragment\n"));
4380 list
= res
->nodesetval
;
4381 if ((list
!= NULL
) && (list
->nodeTab
!= NULL
) &&
4382 (list
->nodeTab
[0] != NULL
) &&
4383 (IS_XSLT_REAL_NODE(list
->nodeTab
[0])))
4385 xsltCopyTreeList(ctxt
, inst
,
4386 list
->nodeTab
[0]->children
, ctxt
->insert
, 0, 0);
4389 xmlChar
*value
= NULL
;
4391 * Convert to a string.
4393 value
= xmlXPathCastToString(res
);
4394 if (value
== NULL
) {
4395 xsltTransformError(ctxt
, NULL
, inst
,
4396 "Internal error in xsltCopyOf(): "
4397 "failed to cast an XPath object to string.\n");
4398 ctxt
->state
= XSLT_STATE_STOPPED
;
4400 if (value
[0] != 0) {
4402 * Append content as text node.
4404 xsltCopyTextString(ctxt
, ctxt
->insert
, value
, 0);
4408 #ifdef WITH_XSLT_DEBUG_PROCESS
4409 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4410 "xsltCopyOf: result %s\n", res
->stringval
));
4415 ctxt
->state
= XSLT_STATE_STOPPED
;
4419 xmlXPathFreeObject(res
);
4424 * @ctxt: a XSLT process context
4425 * @node: the node in the source tree.
4426 * @inst: the xslt value-of node
4427 * @castedComp: precomputed information
4429 * Process the xslt value-of node on the source node
4432 xsltValueOf(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4433 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
4435 #ifdef XSLT_REFACTORED
4436 xsltStyleItemValueOfPtr comp
= (xsltStyleItemValueOfPtr
) castedComp
;
4438 xsltStylePreCompPtr comp
= castedComp
;
4440 xmlXPathObjectPtr res
= NULL
;
4441 xmlChar
*value
= NULL
;
4442 xmlDocPtr oldXPContextDoc
;
4443 xmlNsPtr
*oldXPNamespaces
;
4444 xmlNodePtr oldXPContextNode
;
4445 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
4446 xmlXPathContextPtr xpctxt
;
4448 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
))
4451 if ((comp
== NULL
) || (comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
4452 xsltTransformError(ctxt
, NULL
, inst
,
4453 "Internal error in xsltValueOf(): "
4454 "The XSLT 'value-of' instruction was not compiled.\n");
4458 #ifdef WITH_XSLT_DEBUG_PROCESS
4459 XSLT_TRACE(ctxt
,XSLT_TRACE_VALUE_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4460 "xsltValueOf: select %s\n", comp
->select
));
4463 xpctxt
= ctxt
->xpathCtxt
;
4464 oldXPContextDoc
= xpctxt
->doc
;
4465 oldXPContextNode
= xpctxt
->node
;
4466 oldXPProximityPosition
= xpctxt
->proximityPosition
;
4467 oldXPContextSize
= xpctxt
->contextSize
;
4468 oldXPNsNr
= xpctxt
->nsNr
;
4469 oldXPNamespaces
= xpctxt
->namespaces
;
4471 xpctxt
->node
= node
;
4474 #ifdef XSLT_REFACTORED
4475 if (comp
->inScopeNs
!= NULL
) {
4476 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
4477 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
4479 xpctxt
->namespaces
= NULL
;
4483 xpctxt
->namespaces
= comp
->nsList
;
4484 xpctxt
->nsNr
= comp
->nsNr
;
4487 xpctxt
->namespaces
= NULL
;
4491 res
= xmlXPathCompiledEval(comp
->comp
, xpctxt
);
4493 xpctxt
->doc
= oldXPContextDoc
;
4494 xpctxt
->node
= oldXPContextNode
;
4495 xpctxt
->contextSize
= oldXPContextSize
;
4496 xpctxt
->proximityPosition
= oldXPProximityPosition
;
4497 xpctxt
->nsNr
= oldXPNsNr
;
4498 xpctxt
->namespaces
= oldXPNamespaces
;
4501 * Cast the XPath object to string.
4504 value
= xmlXPathCastToString(res
);
4505 if (value
== NULL
) {
4506 xsltTransformError(ctxt
, NULL
, inst
,
4507 "Internal error in xsltValueOf(): "
4508 "failed to cast an XPath object to string.\n");
4509 ctxt
->state
= XSLT_STATE_STOPPED
;
4512 if (value
[0] != 0) {
4513 xsltCopyTextString(ctxt
, ctxt
->insert
, value
, comp
->noescape
);
4516 xsltTransformError(ctxt
, NULL
, inst
,
4517 "XPath evaluation returned no result.\n");
4518 ctxt
->state
= XSLT_STATE_STOPPED
;
4522 #ifdef WITH_XSLT_DEBUG_PROCESS
4524 XSLT_TRACE(ctxt
,XSLT_TRACE_VALUE_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4525 "xsltValueOf: result '%s'\n", value
));
4533 xmlXPathFreeObject(res
);
4538 * @ctxt: a XSLT process context
4539 * @node: the node in the source tree.
4540 * @inst: the xslt number node
4541 * @castedComp: precomputed information
4543 * Process the xslt number node on the source node
4546 xsltNumber(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4547 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
4549 #ifdef XSLT_REFACTORED
4550 xsltStyleItemNumberPtr comp
= (xsltStyleItemNumberPtr
) castedComp
;
4552 xsltStylePreCompPtr comp
= castedComp
;
4555 xsltTransformError(ctxt
, NULL
, inst
,
4556 "xsl:number : compilation failed\n");
4560 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
4563 comp
->numdata
.doc
= inst
->doc
;
4564 comp
->numdata
.node
= inst
;
4566 xsltNumberFormat(ctxt
, &comp
->numdata
, node
);
4571 * @ctxt: an XSLT transformation context
4572 * @contextNode: the current node in the source tree.
4573 * @inst: the element node of the XSLT 'apply-imports' instruction
4574 * @comp: the compiled instruction
4576 * Process the XSLT apply-imports element.
4579 xsltApplyImports(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
4581 xsltStylePreCompPtr comp ATTRIBUTE_UNUSED
)
4583 xsltTemplatePtr templ
;
4585 if ((ctxt
== NULL
) || (inst
== NULL
))
4589 xsltTransformError(ctxt
, NULL
, inst
,
4590 "Internal error in xsltApplyImports(): "
4591 "The XSLT 'apply-imports' instruction was not compiled.\n");
4595 * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4596 * same; the former is the "Current Template Rule" as defined by the
4597 * XSLT spec, the latter is simply the template struct being
4598 * currently processed.
4600 if (ctxt
->currentTemplateRule
== NULL
) {
4603 * "[ERR XTDE0560] It is a non-recoverable dynamic error if
4604 * xsl:apply-imports or xsl:next-match is evaluated when the
4605 * current template rule is null."
4607 xsltTransformError(ctxt
, NULL
, inst
,
4608 "It is an error to call 'apply-imports' "
4609 "when there's no current template rule.\n");
4613 * TODO: Check if this is correct.
4615 templ
= xsltGetTemplate(ctxt
, contextNode
,
4616 ctxt
->currentTemplateRule
->style
);
4618 if (templ
!= NULL
) {
4619 xsltTemplatePtr oldCurTemplRule
= ctxt
->currentTemplateRule
;
4621 * Set the current template rule.
4623 ctxt
->currentTemplateRule
= templ
;
4625 * URGENT TODO: Need xsl:with-param be handled somehow here?
4627 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
,
4630 ctxt
->currentTemplateRule
= oldCurTemplRule
;
4636 * @ctxt: a XSLT transformation context
4637 * @node: the "current node" in the source tree
4638 * @inst: the XSLT 'call-template' instruction
4639 * @castedComp: the compiled information of the instruction
4641 * Processes the XSLT call-template instruction on the source node.
4644 xsltCallTemplate(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4645 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
4647 #ifdef XSLT_REFACTORED
4648 xsltStyleItemCallTemplatePtr comp
=
4649 (xsltStyleItemCallTemplatePtr
) castedComp
;
4651 xsltStylePreCompPtr comp
= castedComp
;
4653 xsltStackElemPtr withParams
= NULL
;
4655 if (ctxt
->insert
== NULL
)
4658 xsltTransformError(ctxt
, NULL
, inst
,
4659 "The XSLT 'call-template' instruction was not compiled.\n");
4664 * The template must have been precomputed
4666 if (comp
->templ
== NULL
) {
4667 comp
->templ
= xsltFindTemplate(ctxt
, comp
->name
, comp
->ns
);
4668 if (comp
->templ
== NULL
) {
4669 if (comp
->ns
!= NULL
) {
4670 xsltTransformError(ctxt
, NULL
, inst
,
4671 "The called template '{%s}%s' was not found.\n",
4672 comp
->ns
, comp
->name
);
4674 xsltTransformError(ctxt
, NULL
, inst
,
4675 "The called template '%s' was not found.\n",
4682 #ifdef WITH_XSLT_DEBUG_PROCESS
4683 if ((comp
!= NULL
) && (comp
->name
!= NULL
))
4684 XSLT_TRACE(ctxt
,XSLT_TRACE_CALL_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
4685 "call-template: name %s\n", comp
->name
));
4688 if (inst
->children
) {
4690 xsltStackElemPtr param
;
4692 cur
= inst
->children
;
4693 while (cur
!= NULL
) {
4694 #ifdef WITH_DEBUGGER
4695 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
4696 xslHandleDebugger(cur
, node
, comp
->templ
, ctxt
);
4698 if (ctxt
->state
== XSLT_STATE_STOPPED
) break;
4700 * TODO: The "with-param"s could be part of the "call-template"
4701 * structure. Avoid to "search" for params dynamically
4702 * in the XML tree every time.
4704 if (IS_XSLT_ELEM(cur
)) {
4705 if (IS_XSLT_NAME(cur
, "with-param")) {
4706 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
4707 if (param
!= NULL
) {
4708 param
->next
= withParams
;
4712 xsltGenericError(xsltGenericErrorContext
,
4713 "xsl:call-template: misplaced xsl:%s\n", cur
->name
);
4716 xsltGenericError(xsltGenericErrorContext
,
4717 "xsl:call-template: misplaced %s element\n", cur
->name
);
4723 * Create a new frame using the params first
4725 xsltApplyXSLTTemplate(ctxt
, node
, comp
->templ
->content
, comp
->templ
,
4727 if (withParams
!= NULL
)
4728 xsltFreeStackElemList(withParams
);
4730 #ifdef WITH_XSLT_DEBUG_PROCESS
4731 if ((comp
!= NULL
) && (comp
->name
!= NULL
))
4732 XSLT_TRACE(ctxt
,XSLT_TRACE_CALL_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
4733 "call-template returned: name %s\n", comp
->name
));
4738 * xsltApplyTemplates:
4739 * @ctxt: a XSLT transformation context
4740 * @node: the 'current node' in the source tree
4741 * @inst: the element node of an XSLT 'apply-templates' instruction
4742 * @castedComp: the compiled instruction
4744 * Processes the XSLT 'apply-templates' instruction on the current node.
4747 xsltApplyTemplates(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4748 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
4750 #ifdef XSLT_REFACTORED
4751 xsltStyleItemApplyTemplatesPtr comp
=
4752 (xsltStyleItemApplyTemplatesPtr
) castedComp
;
4754 xsltStylePreCompPtr comp
= castedComp
;
4757 xmlNodePtr cur
, delNode
= NULL
, oldContextNode
;
4758 xmlNodeSetPtr list
= NULL
, oldList
;
4759 xsltStackElemPtr withParams
= NULL
;
4760 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
4761 const xmlChar
*oldMode
, *oldModeURI
;
4763 xsltDocumentPtr oldDocInfo
;
4764 xmlXPathContextPtr xpctxt
;
4765 xmlNsPtr
*oldXPNamespaces
;
4768 xsltTransformError(ctxt
, NULL
, inst
,
4769 "xsl:apply-templates : compilation failed\n");
4772 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
4775 #ifdef WITH_XSLT_DEBUG_PROCESS
4776 if ((node
!= NULL
) && (node
->name
!= NULL
))
4777 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4778 "xsltApplyTemplates: node: '%s'\n", node
->name
));
4781 xpctxt
= ctxt
->xpathCtxt
;
4783 * Save context states.
4785 oldContextNode
= ctxt
->node
;
4786 oldMode
= ctxt
->mode
;
4787 oldModeURI
= ctxt
->modeURI
;
4788 oldDocInfo
= ctxt
->document
;
4789 oldList
= ctxt
->nodeList
;
4792 * The xpath context size and proximity position, as
4793 * well as the xpath and context documents, may be changed
4794 * so we save their initial state and will restore on exit
4796 oldXPContextSize
= xpctxt
->contextSize
;
4797 oldXPProximityPosition
= xpctxt
->proximityPosition
;
4798 oldXPDoc
= xpctxt
->doc
;
4799 oldXPNsNr
= xpctxt
->nsNr
;
4800 oldXPNamespaces
= xpctxt
->namespaces
;
4805 ctxt
->mode
= comp
->mode
;
4806 ctxt
->modeURI
= comp
->modeURI
;
4808 if (comp
->select
!= NULL
) {
4809 xmlXPathObjectPtr res
= NULL
;
4811 if (comp
->comp
== NULL
) {
4812 xsltTransformError(ctxt
, NULL
, inst
,
4813 "xsl:apply-templates : compilation failed\n");
4816 #ifdef WITH_XSLT_DEBUG_PROCESS
4817 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4818 "xsltApplyTemplates: select %s\n", comp
->select
));
4824 xpctxt
->node
= node
; /* Set the "context node" */
4825 #ifdef XSLT_REFACTORED
4826 if (comp
->inScopeNs
!= NULL
) {
4827 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
4828 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
4830 xpctxt
->namespaces
= NULL
;
4834 xpctxt
->namespaces
= comp
->nsList
;
4835 xpctxt
->nsNr
= comp
->nsNr
;
4837 res
= xmlXPathCompiledEval(comp
->comp
, xpctxt
);
4839 xpctxt
->contextSize
= oldXPContextSize
;
4840 xpctxt
->proximityPosition
= oldXPProximityPosition
;
4842 if (res
->type
== XPATH_NODESET
) {
4843 list
= res
->nodesetval
; /* consume the node set */
4844 res
->nodesetval
= NULL
;
4846 xsltTransformError(ctxt
, NULL
, inst
,
4847 "The 'select' expression did not evaluate to a "
4849 ctxt
->state
= XSLT_STATE_STOPPED
;
4850 xmlXPathFreeObject(res
);
4853 xmlXPathFreeObject(res
);
4855 * Note: An xsl:apply-templates with a 'select' attribute,
4856 * can change the current source doc.
4859 xsltTransformError(ctxt
, NULL
, inst
,
4860 "Failed to evaluate the 'select' expression.\n");
4861 ctxt
->state
= XSLT_STATE_STOPPED
;
4865 #ifdef WITH_XSLT_DEBUG_PROCESS
4866 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4867 "xsltApplyTemplates: select didn't evaluate to a node list\n"));
4873 * NOTE: Previously a document info (xsltDocument) was
4874 * created and attached to the Result Tree Fragment.
4875 * But such a document info is created on demand in
4876 * xsltKeyFunction() (functions.c), so we need to create
4877 * it here beforehand.
4878 * In order to take care of potential keys we need to
4879 * do some extra work for the case when a Result Tree Fragment
4880 * is converted into a nodeset (e.g. exslt:node-set()) :
4881 * We attach a "pseudo-doc" (xsltDocument) to _private.
4882 * This xsltDocument, together with the keyset, will be freed
4883 * when the Result Tree Fragment is freed.
4887 if ((ctxt
->nbKeys
> 0) &&
4888 (list
->nodeNr
!= 0) &&
4889 (list
->nodeTab
[0]->doc
!= NULL
) &&
4890 XSLT_IS_RES_TREE_FRAG(list
->nodeTab
[0]->doc
))
4893 * NOTE that it's also OK if @effectiveDocInfo will be
4897 effectiveDocInfo
= list
->nodeTab
[0]->doc
->_private
;
4902 * Build an XPath node set with the children
4904 list
= xmlXPathNodeSetCreate(NULL
);
4907 if (node
->type
!= XML_NAMESPACE_DECL
)
4908 cur
= node
->children
;
4911 while (cur
!= NULL
) {
4912 switch (cur
->type
) {
4914 if ((IS_BLANK_NODE(cur
)) &&
4915 (cur
->parent
!= NULL
) &&
4916 (cur
->parent
->type
== XML_ELEMENT_NODE
) &&
4917 (ctxt
->style
->stripSpaces
!= NULL
)) {
4920 if (cur
->parent
->ns
!= NULL
) {
4921 val
= (const xmlChar
*)
4922 xmlHashLookup2(ctxt
->style
->stripSpaces
,
4924 cur
->parent
->ns
->href
);
4926 val
= (const xmlChar
*)
4927 xmlHashLookup2(ctxt
->style
->stripSpaces
,
4929 cur
->parent
->ns
->href
);
4932 val
= (const xmlChar
*)
4933 xmlHashLookup2(ctxt
->style
->stripSpaces
,
4934 cur
->parent
->name
, NULL
);
4936 if ((val
!= NULL
) &&
4937 (xmlStrEqual(val
, (xmlChar
*) "strip"))) {
4942 /* no break on purpose */
4943 case XML_ELEMENT_NODE
:
4944 case XML_DOCUMENT_NODE
:
4945 case XML_HTML_DOCUMENT_NODE
:
4946 case XML_CDATA_SECTION_NODE
:
4948 case XML_COMMENT_NODE
:
4949 xmlXPathNodeSetAddUnique(list
, cur
);
4952 /* Unlink the DTD, it's still reachable
4953 * using doc->intSubset */
4954 if (cur
->next
!= NULL
)
4955 cur
->next
->prev
= cur
->prev
;
4956 if (cur
->prev
!= NULL
)
4957 cur
->prev
->next
= cur
->next
;
4959 case XML_NAMESPACE_DECL
:
4962 #ifdef WITH_XSLT_DEBUG_PROCESS
4963 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4964 "xsltApplyTemplates: skipping cur type %d\n",
4970 if (delNode
!= NULL
) {
4971 #ifdef WITH_XSLT_DEBUG_PROCESS
4972 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4973 "xsltApplyTemplates: removing ignorable blank cur\n"));
4975 xmlUnlinkNode(delNode
);
4976 xmlFreeNode(delNode
);
4982 #ifdef WITH_XSLT_DEBUG_PROCESS
4984 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4985 "xsltApplyTemplates: list of %d nodes\n", list
->nodeNr
));
4988 if ((list
== NULL
) || (list
->nodeNr
== 0))
4992 * Set the context's node set and size; this is also needed for
4993 * for xsltDoSortFunction().
4995 ctxt
->nodeList
= list
;
4997 * Process xsl:with-param and xsl:sort instructions.
4998 * (The code became so verbose just to avoid the
4999 * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
5000 * BUG TODO: We are not using namespaced potentially defined on the
5001 * xsl:sort or xsl:with-param elements; XPath expression might fail.
5003 if (inst
->children
) {
5004 xsltStackElemPtr param
;
5006 cur
= inst
->children
;
5009 #ifdef WITH_DEBUGGER
5010 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
5011 xslHandleDebugger(cur
, node
, NULL
, ctxt
);
5013 if (ctxt
->state
== XSLT_STATE_STOPPED
)
5015 if (cur
->type
== XML_TEXT_NODE
) {
5019 if (! IS_XSLT_ELEM(cur
))
5021 if (IS_XSLT_NAME(cur
, "with-param")) {
5022 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
5023 if (param
!= NULL
) {
5024 param
->next
= withParams
;
5028 if (IS_XSLT_NAME(cur
, "sort")) {
5029 xsltTemplatePtr oldCurTempRule
=
5030 ctxt
->currentTemplateRule
;
5032 xmlNodePtr sorts
[XSLT_MAX_SORT
];
5034 sorts
[nbsorts
++] = cur
;
5038 #ifdef WITH_DEBUGGER
5039 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
5040 xslHandleDebugger(cur
, node
, NULL
, ctxt
);
5042 if (ctxt
->state
== XSLT_STATE_STOPPED
)
5045 if (cur
->type
== XML_TEXT_NODE
) {
5050 if (! IS_XSLT_ELEM(cur
))
5052 if (IS_XSLT_NAME(cur
, "with-param")) {
5053 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
5054 if (param
!= NULL
) {
5055 param
->next
= withParams
;
5059 if (IS_XSLT_NAME(cur
, "sort")) {
5060 if (nbsorts
>= XSLT_MAX_SORT
) {
5061 xsltTransformError(ctxt
, NULL
, cur
,
5062 "The number (%d) of xsl:sort instructions exceeds the "
5063 "maximum allowed by this processor's settings.\n",
5065 ctxt
->state
= XSLT_STATE_STOPPED
;
5068 sorts
[nbsorts
++] = cur
;
5074 * The "current template rule" is cleared for xsl:sort.
5076 ctxt
->currentTemplateRule
= NULL
;
5080 xsltDoSortFunction(ctxt
, sorts
, nbsorts
);
5081 ctxt
->currentTemplateRule
= oldCurTempRule
;
5087 xpctxt
->contextSize
= list
->nodeNr
;
5089 * Apply templates for all selected source nodes.
5091 for (i
= 0; i
< list
->nodeNr
; i
++) {
5092 cur
= list
->nodeTab
[i
];
5094 * The node becomes the "current node".
5098 * An xsl:apply-templates can change the current context doc.
5099 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5101 if ((cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->doc
!= NULL
))
5102 xpctxt
->doc
= cur
->doc
;
5104 xpctxt
->proximityPosition
= i
+ 1;
5106 * Find and apply a template for this node.
5108 xsltProcessOneNode(ctxt
, cur
, withParams
);
5114 * Free the parameter list.
5116 if (withParams
!= NULL
)
5117 xsltFreeStackElemList(withParams
);
5119 xmlXPathFreeNodeSet(list
);
5121 * Restore context states.
5123 xpctxt
->nsNr
= oldXPNsNr
;
5124 xpctxt
->namespaces
= oldXPNamespaces
;
5125 xpctxt
->doc
= oldXPDoc
;
5126 xpctxt
->contextSize
= oldXPContextSize
;
5127 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5129 ctxt
->document
= oldDocInfo
;
5130 ctxt
->nodeList
= oldList
;
5131 ctxt
->node
= oldContextNode
;
5132 ctxt
->mode
= oldMode
;
5133 ctxt
->modeURI
= oldModeURI
;
5139 * @ctxt: a XSLT process context
5140 * @contextNode: the current node in the source tree
5141 * @inst: the xsl:choose instruction
5142 * @comp: compiled information of the instruction
5144 * Processes the xsl:choose instruction on the source node.
5147 xsltChoose(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5148 xmlNodePtr inst
, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED
)
5152 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
))
5156 * TODO: Content model checks should be done only at compilation
5159 cur
= inst
->children
;
5161 xsltTransformError(ctxt
, NULL
, inst
,
5162 "xsl:choose: The instruction has no content.\n");
5166 #ifdef XSLT_REFACTORED
5168 * We don't check the content model during transformation.
5171 if ((! IS_XSLT_ELEM(cur
)) || (! IS_XSLT_NAME(cur
, "when"))) {
5172 xsltTransformError(ctxt
, NULL
, inst
,
5173 "xsl:choose: xsl:when expected first\n");
5179 int testRes
= 0, res
= 0;
5180 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
5181 xmlDocPtr oldXPContextDoc
= xpctxt
->doc
;
5182 int oldXPProximityPosition
= xpctxt
->proximityPosition
;
5183 int oldXPContextSize
= xpctxt
->contextSize
;
5184 xmlNsPtr
*oldXPNamespaces
= xpctxt
->namespaces
;
5185 int oldXPNsNr
= xpctxt
->nsNr
;
5187 #ifdef XSLT_REFACTORED
5188 xsltStyleItemWhenPtr wcomp
= NULL
;
5190 xsltStylePreCompPtr wcomp
= NULL
;
5194 * Process xsl:when ---------------------------------------------------
5196 while (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "when")) {
5199 if ((wcomp
== NULL
) || (wcomp
->test
== NULL
) ||
5200 (wcomp
->comp
== NULL
))
5202 xsltTransformError(ctxt
, NULL
, cur
,
5203 "Internal error in xsltChoose(): "
5204 "The XSLT 'when' instruction was not compiled.\n");
5209 #ifdef WITH_DEBUGGER
5210 if (xslDebugStatus
!= XSLT_DEBUG_NONE
) {
5212 * TODO: Isn't comp->templ always NULL for xsl:choose?
5214 xslHandleDebugger(cur
, contextNode
, NULL
, ctxt
);
5217 #ifdef WITH_XSLT_DEBUG_PROCESS
5218 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5219 "xsltChoose: test %s\n", wcomp
->test
));
5222 xpctxt
->node
= contextNode
;
5223 xpctxt
->doc
= oldXPContextDoc
;
5224 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5225 xpctxt
->contextSize
= oldXPContextSize
;
5227 #ifdef XSLT_REFACTORED
5228 if (wcomp
->inScopeNs
!= NULL
) {
5229 xpctxt
->namespaces
= wcomp
->inScopeNs
->list
;
5230 xpctxt
->nsNr
= wcomp
->inScopeNs
->xpathNumber
;
5232 xpctxt
->namespaces
= NULL
;
5236 xpctxt
->namespaces
= wcomp
->nsList
;
5237 xpctxt
->nsNr
= wcomp
->nsNr
;
5242 res
= xmlXPathCompiledEvalToBoolean(wcomp
->comp
, xpctxt
);
5245 ctxt
->state
= XSLT_STATE_STOPPED
;
5248 testRes
= (res
== 1) ? 1 : 0;
5250 #else /* XSLT_FAST_IF */
5252 res
= xmlXPathCompiledEval(wcomp
->comp
, xpctxt
);
5255 if (res
->type
!= XPATH_BOOLEAN
)
5256 res
= xmlXPathConvertBoolean(res
);
5257 if (res
->type
== XPATH_BOOLEAN
)
5258 testRes
= res
->boolval
;
5260 #ifdef WITH_XSLT_DEBUG_PROCESS
5261 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5262 "xsltChoose: test didn't evaluate to a boolean\n"));
5266 xmlXPathFreeObject(res
);
5269 ctxt
->state
= XSLT_STATE_STOPPED
;
5273 #endif /* else of XSLT_FAST_IF */
5275 #ifdef WITH_XSLT_DEBUG_PROCESS
5276 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5277 "xsltChoose: test evaluate to %d\n", testRes
));
5286 * Process xsl:otherwise ----------------------------------------------
5288 if (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "otherwise")) {
5290 #ifdef WITH_DEBUGGER
5291 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5292 xslHandleDebugger(cur
, contextNode
, NULL
, ctxt
);
5295 #ifdef WITH_XSLT_DEBUG_PROCESS
5296 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5297 "evaluating xsl:otherwise\n"));
5301 xpctxt
->node
= contextNode
;
5302 xpctxt
->doc
= oldXPContextDoc
;
5303 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5304 xpctxt
->contextSize
= oldXPContextSize
;
5305 xpctxt
->namespaces
= oldXPNamespaces
;
5306 xpctxt
->nsNr
= oldXPNsNr
;
5311 xpctxt
->node
= contextNode
;
5312 xpctxt
->doc
= oldXPContextDoc
;
5313 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5314 xpctxt
->contextSize
= oldXPContextSize
;
5315 xpctxt
->namespaces
= oldXPNamespaces
;
5316 xpctxt
->nsNr
= oldXPNsNr
;
5317 goto process_sequence
;
5323 * Instantiate the sequence constructor.
5325 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, cur
->children
,
5335 * @ctxt: a XSLT process context
5336 * @contextNode: the current node in the source tree
5337 * @inst: the xsl:if instruction
5338 * @castedComp: compiled information of the instruction
5340 * Processes the xsl:if instruction on the source node.
5343 xsltIf(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5344 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
5348 #ifdef XSLT_REFACTORED
5349 xsltStyleItemIfPtr comp
= (xsltStyleItemIfPtr
) castedComp
;
5351 xsltStylePreCompPtr comp
= castedComp
;
5354 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
))
5356 if ((comp
== NULL
) || (comp
->test
== NULL
) || (comp
->comp
== NULL
)) {
5357 xsltTransformError(ctxt
, NULL
, inst
,
5358 "Internal error in xsltIf(): "
5359 "The XSLT 'if' instruction was not compiled.\n");
5363 #ifdef WITH_XSLT_DEBUG_PROCESS
5364 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5365 "xsltIf: test %s\n", comp
->test
));
5370 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
5371 xmlDocPtr oldXPContextDoc
= xpctxt
->doc
;
5372 xmlNsPtr
*oldXPNamespaces
= xpctxt
->namespaces
;
5373 xmlNodePtr oldXPContextNode
= xpctxt
->node
;
5374 int oldXPProximityPosition
= xpctxt
->proximityPosition
;
5375 int oldXPContextSize
= xpctxt
->contextSize
;
5376 int oldXPNsNr
= xpctxt
->nsNr
;
5377 xmlDocPtr oldLocalFragmentTop
= ctxt
->localRVT
;
5379 xpctxt
->node
= contextNode
;
5382 #ifdef XSLT_REFACTORED
5383 if (comp
->inScopeNs
!= NULL
) {
5384 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
5385 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
5387 xpctxt
->namespaces
= NULL
;
5391 xpctxt
->namespaces
= comp
->nsList
;
5392 xpctxt
->nsNr
= comp
->nsNr
;
5395 xpctxt
->namespaces
= NULL
;
5399 * This XPath function is optimized for boolean results.
5401 res
= xmlXPathCompiledEvalToBoolean(comp
->comp
, xpctxt
);
5404 * Cleanup fragments created during evaluation of the
5405 * "select" expression.
5407 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
5408 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
5410 xpctxt
->doc
= oldXPContextDoc
;
5411 xpctxt
->node
= oldXPContextNode
;
5412 xpctxt
->contextSize
= oldXPContextSize
;
5413 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5414 xpctxt
->nsNr
= oldXPNsNr
;
5415 xpctxt
->namespaces
= oldXPNamespaces
;
5418 #ifdef WITH_XSLT_DEBUG_PROCESS
5419 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5420 "xsltIf: test evaluate to %d\n", res
));
5424 ctxt
->state
= XSLT_STATE_STOPPED
;
5429 * Instantiate the sequence constructor of xsl:if.
5431 xsltApplySequenceConstructor(ctxt
,
5432 contextNode
, inst
->children
, NULL
);
5435 #else /* XSLT_FAST_IF */
5437 xmlXPathObjectPtr xpobj
= NULL
;
5442 xmlXPathContextPtr xpctxt
= ctxt
->xpathCtxt
;
5443 xmlDocPtr oldXPContextDoc
= xpctxt
->doc
;
5444 xmlNsPtr
*oldXPNamespaces
= xpctxt
->namespaces
;
5445 xmlNodePtr oldXPContextNode
= xpctxt
->node
;
5446 int oldXPProximityPosition
= xpctxt
->proximityPosition
;
5447 int oldXPContextSize
= xpctxt
->contextSize
;
5448 int oldXPNsNr
= xpctxt
->nsNr
;
5450 xpctxt
->node
= contextNode
;
5453 #ifdef XSLT_REFACTORED
5454 if (comp
->inScopeNs
!= NULL
) {
5455 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
5456 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
5458 xpctxt
->namespaces
= NULL
;
5462 xpctxt
->namespaces
= comp
->nsList
;
5463 xpctxt
->nsNr
= comp
->nsNr
;
5466 xpctxt
->namespaces
= NULL
;
5471 * This XPath function is optimized for boolean results.
5473 xpobj
= xmlXPathCompiledEval(comp
->comp
, xpctxt
);
5475 xpctxt
->doc
= oldXPContextDoc
;
5476 xpctxt
->node
= oldXPContextNode
;
5477 xpctxt
->contextSize
= oldXPContextSize
;
5478 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5479 xpctxt
->nsNr
= oldXPNsNr
;
5480 xpctxt
->namespaces
= oldXPNamespaces
;
5482 if (xpobj
!= NULL
) {
5483 if (xpobj
->type
!= XPATH_BOOLEAN
)
5484 xpobj
= xmlXPathConvertBoolean(xpobj
);
5485 if (xpobj
->type
== XPATH_BOOLEAN
) {
5486 res
= xpobj
->boolval
;
5488 #ifdef WITH_XSLT_DEBUG_PROCESS
5489 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5490 "xsltIf: test evaluate to %d\n", res
));
5493 xsltApplySequenceConstructor(ctxt
,
5494 contextNode
, inst
->children
, NULL
);
5498 #ifdef WITH_XSLT_DEBUG_PROCESS
5499 XSLT_TRACE(ctxt
, XSLT_TRACE_IF
,
5500 xsltGenericDebug(xsltGenericDebugContext
,
5501 "xsltIf: test didn't evaluate to a boolean\n"));
5503 ctxt
->state
= XSLT_STATE_STOPPED
;
5505 xmlXPathFreeObject(xpobj
);
5507 ctxt
->state
= XSLT_STATE_STOPPED
;
5510 #endif /* else of XSLT_FAST_IF */
5518 * @ctxt: an XSLT transformation context
5519 * @contextNode: the "current node" in the source tree
5520 * @inst: the element node of the xsl:for-each instruction
5521 * @castedComp: the compiled information of the instruction
5523 * Process the xslt for-each node on the source node
5526 xsltForEach(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5527 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
5529 #ifdef XSLT_REFACTORED
5530 xsltStyleItemForEachPtr comp
= (xsltStyleItemForEachPtr
) castedComp
;
5532 xsltStylePreCompPtr comp
= castedComp
;
5535 xmlXPathObjectPtr res
= NULL
;
5536 xmlNodePtr cur
, curInst
;
5537 xmlNodeSetPtr list
= NULL
;
5538 xmlNodeSetPtr oldList
;
5539 int oldXPProximityPosition
, oldXPContextSize
;
5540 xmlNodePtr oldContextNode
;
5541 xsltTemplatePtr oldCurTemplRule
;
5543 xsltDocumentPtr oldDocInfo
;
5544 xmlXPathContextPtr xpctxt
;
5546 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
)) {
5547 xsltGenericError(xsltGenericErrorContext
,
5548 "xsltForEach(): Bad arguments.\n");
5553 xsltTransformError(ctxt
, NULL
, inst
,
5554 "Internal error in xsltForEach(): "
5555 "The XSLT 'for-each' instruction was not compiled.\n");
5558 if ((comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
5559 xsltTransformError(ctxt
, NULL
, inst
,
5560 "Internal error in xsltForEach(): "
5561 "The selecting expression of the XSLT 'for-each' "
5562 "instruction was not compiled correctly.\n");
5565 xpctxt
= ctxt
->xpathCtxt
;
5567 #ifdef WITH_XSLT_DEBUG_PROCESS
5568 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5569 "xsltForEach: select %s\n", comp
->select
));
5573 * Save context states.
5575 oldDocInfo
= ctxt
->document
;
5576 oldList
= ctxt
->nodeList
;
5577 oldContextNode
= ctxt
->node
;
5579 * The "current template rule" is cleared for the instantiation of
5582 oldCurTemplRule
= ctxt
->currentTemplateRule
;
5583 ctxt
->currentTemplateRule
= NULL
;
5585 oldXPDoc
= xpctxt
->doc
;
5586 oldXPProximityPosition
= xpctxt
->proximityPosition
;
5587 oldXPContextSize
= xpctxt
->contextSize
;
5591 xpctxt
->node
= contextNode
;
5592 #ifdef XSLT_REFACTORED
5593 if (comp
->inScopeNs
!= NULL
) {
5594 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
5595 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
5597 xpctxt
->namespaces
= NULL
;
5601 xpctxt
->namespaces
= comp
->nsList
;
5602 xpctxt
->nsNr
= comp
->nsNr
;
5606 * Evaluate the 'select' expression.
5608 res
= xmlXPathCompiledEval(comp
->comp
, ctxt
->xpathCtxt
);
5611 if (res
->type
== XPATH_NODESET
)
5612 list
= res
->nodesetval
;
5614 xsltTransformError(ctxt
, NULL
, inst
,
5615 "The 'select' expression does not evaluate to a node set.\n");
5617 #ifdef WITH_XSLT_DEBUG_PROCESS
5618 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5619 "xsltForEach: select didn't evaluate to a node list\n"));
5624 xsltTransformError(ctxt
, NULL
, inst
,
5625 "Failed to evaluate the 'select' expression.\n");
5626 ctxt
->state
= XSLT_STATE_STOPPED
;
5630 if ((list
== NULL
) || (list
->nodeNr
<= 0))
5633 #ifdef WITH_XSLT_DEBUG_PROCESS
5634 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5635 "xsltForEach: select evaluates to %d nodes\n", list
->nodeNr
));
5639 * Restore XPath states for the "current node".
5641 xpctxt
->contextSize
= oldXPContextSize
;
5642 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5643 xpctxt
->node
= contextNode
;
5646 * Set the list; this has to be done already here for xsltDoSortFunction().
5648 ctxt
->nodeList
= list
;
5650 * Handle xsl:sort instructions and skip them for further processing.
5651 * BUG TODO: We are not using namespaced potentially defined on the
5652 * xsl:sort element; XPath expression might fail.
5654 curInst
= inst
->children
;
5655 if (IS_XSLT_ELEM(curInst
) && IS_XSLT_NAME(curInst
, "sort")) {
5657 xmlNodePtr sorts
[XSLT_MAX_SORT
];
5659 sorts
[nbsorts
++] = curInst
;
5661 #ifdef WITH_DEBUGGER
5662 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5663 xslHandleDebugger(curInst
, contextNode
, NULL
, ctxt
);
5666 curInst
= curInst
->next
;
5667 while (IS_XSLT_ELEM(curInst
) && IS_XSLT_NAME(curInst
, "sort")) {
5668 if (nbsorts
>= XSLT_MAX_SORT
) {
5669 xsltTransformError(ctxt
, NULL
, curInst
,
5670 "The number of xsl:sort instructions exceeds the "
5671 "maximum (%d) allowed by this processor.\n",
5675 sorts
[nbsorts
++] = curInst
;
5678 #ifdef WITH_DEBUGGER
5679 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5680 xslHandleDebugger(curInst
, contextNode
, NULL
, ctxt
);
5682 curInst
= curInst
->next
;
5684 xsltDoSortFunction(ctxt
, sorts
, nbsorts
);
5686 xpctxt
->contextSize
= list
->nodeNr
;
5688 * Instantiate the sequence constructor for each selected node.
5690 for (i
= 0; i
< list
->nodeNr
; i
++) {
5691 cur
= list
->nodeTab
[i
];
5693 * The selected node becomes the "current node".
5697 * An xsl:for-each can change the current context doc.
5698 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5700 if ((cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->doc
!= NULL
))
5701 xpctxt
->doc
= cur
->doc
;
5703 xpctxt
->proximityPosition
= i
+ 1;
5705 xsltApplySequenceConstructor(ctxt
, cur
, curInst
, NULL
);
5711 xmlXPathFreeObject(res
);
5713 * Restore old states.
5715 ctxt
->document
= oldDocInfo
;
5716 ctxt
->nodeList
= oldList
;
5717 ctxt
->node
= oldContextNode
;
5718 ctxt
->currentTemplateRule
= oldCurTemplRule
;
5720 xpctxt
->doc
= oldXPDoc
;
5721 xpctxt
->contextSize
= oldXPContextSize
;
5722 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5725 /************************************************************************
5727 * Generic interface *
5729 ************************************************************************/
5731 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5732 typedef struct xsltHTMLVersion
{
5733 const char *version
;
5738 static xsltHTMLVersion xsltHTMLVersions
[] = {
5739 { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5740 "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
5741 { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
5742 "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
5743 { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5744 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5745 { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
5746 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5747 { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
5748 "http://www.w3.org/TR/html4/strict.dtd"},
5749 { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5750 "http://www.w3.org/TR/html4/loose.dtd"},
5751 { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5752 "http://www.w3.org/TR/html4/frameset.dtd"},
5753 { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
5754 "http://www.w3.org/TR/html4/loose.dtd"},
5755 { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL
}
5760 * @version: the version string
5761 * @publicID: used to return the public ID
5762 * @systemID: used to return the system ID
5764 * Returns -1 if not found, 0 otherwise and the system and public
5765 * Identifier for this given verion of HTML
5768 xsltGetHTMLIDs(const xmlChar
*version
, const xmlChar
**publicID
,
5769 const xmlChar
**systemID
) {
5771 if (version
== NULL
)
5773 for (i
= 0;i
< (sizeof(xsltHTMLVersions
)/sizeof(xsltHTMLVersions
[1]));
5775 if (!xmlStrcasecmp(version
,
5776 (const xmlChar
*) xsltHTMLVersions
[i
].version
)) {
5777 if (publicID
!= NULL
)
5778 *publicID
= (const xmlChar
*) xsltHTMLVersions
[i
].public;
5779 if (systemID
!= NULL
)
5780 *systemID
= (const xmlChar
*) xsltHTMLVersions
[i
].system
;
5789 * xsltApplyStripSpaces:
5790 * @ctxt: a XSLT process context
5791 * @node: the root of the XML tree
5793 * Strip the unwanted ignorable spaces from the input tree
5796 xsltApplyStripSpaces(xsltTransformContextPtr ctxt
, xmlNodePtr node
) {
5798 #ifdef WITH_XSLT_DEBUG_PROCESS
5804 while (current
!= NULL
) {
5806 * Cleanup children empty nodes if asked for
5808 if ((IS_XSLT_REAL_NODE(current
)) &&
5809 (current
->children
!= NULL
) &&
5810 (xsltFindElemSpaceHandling(ctxt
, current
))) {
5811 xmlNodePtr
delete = NULL
, cur
= current
->children
;
5813 while (cur
!= NULL
) {
5814 if (IS_BLANK_NODE(cur
))
5818 if (delete != NULL
) {
5819 xmlUnlinkNode(delete);
5820 xmlFreeNode(delete);
5822 #ifdef WITH_XSLT_DEBUG_PROCESS
5830 * Skip to next node in document order.
5832 if (node
->type
== XML_ENTITY_REF_NODE
) {
5833 /* process deep in entities */
5834 xsltApplyStripSpaces(ctxt
, node
->children
);
5836 if ((current
->children
!= NULL
) &&
5837 (current
->type
!= XML_ENTITY_REF_NODE
)) {
5838 current
= current
->children
;
5839 } else if (current
->next
!= NULL
) {
5840 current
= current
->next
;
5843 current
= current
->parent
;
5844 if (current
== NULL
)
5846 if (current
== node
)
5848 if (current
->next
!= NULL
) {
5849 current
= current
->next
;
5852 } while (current
!= NULL
);
5857 #ifdef WITH_XSLT_DEBUG_PROCESS
5858 XSLT_TRACE(ctxt
,XSLT_TRACE_STRIP_SPACES
,xsltGenericDebug(xsltGenericDebugContext
,
5859 "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb
));
5865 xsltCountKeys(xsltTransformContextPtr ctxt
)
5867 xsltStylesheetPtr style
;
5874 * Do we have those nastly templates with a key() in the match pattern?
5876 ctxt
->hasTemplKeyPatterns
= 0;
5877 style
= ctxt
->style
;
5878 while (style
!= NULL
) {
5879 if (style
->keyMatch
!= NULL
) {
5880 ctxt
->hasTemplKeyPatterns
= 1;
5883 style
= xsltNextImport(style
);
5886 * Count number of key declarations.
5889 style
= ctxt
->style
;
5890 while (style
!= NULL
) {
5896 style
= xsltNextImport(style
);
5898 return(ctxt
->nbKeys
);
5902 * xsltApplyStylesheetInternal:
5903 * @style: a parsed XSLT stylesheet
5904 * @doc: a parsed XML document
5905 * @params: a NULL terminated array of parameters names/values tuples
5906 * @output: the targetted output
5907 * @profile: profile FILE * output or NULL
5908 * @user: user provided parameter
5910 * Apply the stylesheet to the document
5911 * NOTE: This may lead to a non-wellformed output XML wise !
5913 * Returns the result document or NULL in case of error
5916 xsltApplyStylesheetInternal(xsltStylesheetPtr style
, xmlDocPtr doc
,
5917 const char **params
, const char *output
,
5918 FILE * profile
, xsltTransformContextPtr userCtxt
)
5920 xmlDocPtr res
= NULL
;
5921 xsltTransformContextPtr ctxt
= NULL
;
5922 xmlNodePtr root
, node
;
5923 const xmlChar
*method
;
5924 const xmlChar
*doctypePublic
;
5925 const xmlChar
*doctypeSystem
;
5926 const xmlChar
*version
;
5927 const xmlChar
*encoding
;
5928 xsltStackElemPtr variables
;
5929 xsltStackElemPtr vptr
;
5933 if ((style
== NULL
) || (doc
== NULL
))
5936 if (style
->internalized
== 0) {
5937 #ifdef WITH_XSLT_DEBUG
5938 xsltGenericDebug(xsltGenericDebugContext
,
5939 "Stylesheet was not fully internalized !\n");
5942 if (doc
->intSubset
!= NULL
) {
5944 * Avoid hitting the DTD when scanning nodes
5945 * but keep it linked as doc->intSubset
5947 xmlNodePtr cur
= (xmlNodePtr
) doc
->intSubset
;
5948 if (cur
->next
!= NULL
)
5949 cur
->next
->prev
= cur
->prev
;
5950 if (cur
->prev
!= NULL
)
5951 cur
->prev
->next
= cur
->next
;
5952 if (doc
->children
== cur
)
5953 doc
->children
= cur
->next
;
5954 if (doc
->last
== cur
)
5955 doc
->last
= cur
->prev
;
5956 cur
->prev
= cur
->next
= NULL
;
5960 * Check for XPath document order availability
5962 root
= xmlDocGetRootElement(doc
);
5964 if (((long) root
->content
) >= 0 && (xslDebugStatus
== XSLT_DEBUG_NONE
))
5965 xmlXPathOrderDocElems(doc
);
5968 if (userCtxt
!= NULL
)
5971 ctxt
= xsltNewTransformContext(style
, doc
);
5976 ctxt
->initialContextDoc
= doc
;
5977 ctxt
->initialContextNode
= (xmlNodePtr
) doc
;
5979 if (profile
!= NULL
)
5983 ctxt
->outputFile
= output
;
5985 ctxt
->outputFile
= NULL
;
5988 * internalize the modes if needed
5990 if (ctxt
->dict
!= NULL
) {
5991 if (ctxt
->mode
!= NULL
)
5992 ctxt
->mode
= xmlDictLookup(ctxt
->dict
, ctxt
->mode
, -1);
5993 if (ctxt
->modeURI
!= NULL
)
5994 ctxt
->modeURI
= xmlDictLookup(ctxt
->dict
, ctxt
->modeURI
, -1);
5997 XSLT_GET_IMPORT_PTR(method
, style
, method
)
5998 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
5999 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
6000 XSLT_GET_IMPORT_PTR(version
, style
, version
)
6001 XSLT_GET_IMPORT_PTR(encoding
, style
, encoding
)
6003 if ((method
!= NULL
) &&
6004 (!xmlStrEqual(method
, (const xmlChar
*) "xml")))
6006 if (xmlStrEqual(method
, (const xmlChar
*) "html")) {
6007 ctxt
->type
= XSLT_OUTPUT_HTML
;
6008 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
6009 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
6011 if (version
== NULL
) {
6014 res
= htmlNewDoc(NULL
, NULL
);
6016 * Make sure no DTD node is generated in this case
6019 dtd
= xmlGetIntSubset(res
);
6021 xmlUnlinkNode((xmlNodePtr
) dtd
);
6024 res
->intSubset
= NULL
;
6025 res
->extSubset
= NULL
;
6029 #ifdef XSLT_GENERATE_HTML_DOCTYPE
6030 xsltGetHTMLIDs(version
, &doctypePublic
, &doctypeSystem
);
6032 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
6037 res
->dict
= ctxt
->dict
;
6038 xmlDictReference(res
->dict
);
6040 #ifdef WITH_XSLT_DEBUG
6041 xsltGenericDebug(xsltGenericDebugContext
,
6042 "reusing transformation dict for output\n");
6044 } else if (xmlStrEqual(method
, (const xmlChar
*) "xhtml")) {
6045 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
6046 "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n",
6048 ctxt
->type
= XSLT_OUTPUT_HTML
;
6049 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
6052 res
->dict
= ctxt
->dict
;
6053 xmlDictReference(res
->dict
);
6055 #ifdef WITH_XSLT_DEBUG
6056 xsltGenericDebug(xsltGenericDebugContext
,
6057 "reusing transformation dict for output\n");
6059 } else if (xmlStrEqual(method
, (const xmlChar
*) "text")) {
6060 ctxt
->type
= XSLT_OUTPUT_TEXT
;
6061 res
= xmlNewDoc(style
->version
);
6064 res
->dict
= ctxt
->dict
;
6065 xmlDictReference(res
->dict
);
6067 #ifdef WITH_XSLT_DEBUG
6068 xsltGenericDebug(xsltGenericDebugContext
,
6069 "reusing transformation dict for output\n");
6072 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
6073 "xsltApplyStylesheetInternal: unsupported method %s\n",
6078 ctxt
->type
= XSLT_OUTPUT_XML
;
6079 res
= xmlNewDoc(style
->version
);
6082 res
->dict
= ctxt
->dict
;
6083 xmlDictReference(ctxt
->dict
);
6084 #ifdef WITH_XSLT_DEBUG
6085 xsltGenericDebug(xsltGenericDebugContext
,
6086 "reusing transformation dict for output\n");
6089 res
->charset
= XML_CHAR_ENCODING_UTF8
;
6090 if (encoding
!= NULL
)
6091 res
->encoding
= xmlStrdup(encoding
);
6092 variables
= style
->variables
;
6095 * Start the evaluation, evaluate the params, the stylesheets globals
6096 * and start by processing the top node.
6098 if (xsltNeedElemSpaceHandling(ctxt
))
6099 xsltApplyStripSpaces(ctxt
, xmlDocGetRootElement(doc
));
6101 * Evaluate global params and user-provided params.
6103 ctxt
->node
= (xmlNodePtr
) doc
;
6104 if (ctxt
->globalVars
== NULL
)
6105 ctxt
->globalVars
= xmlHashCreate(20);
6106 if (params
!= NULL
) {
6107 xsltEvalUserParams(ctxt
, params
);
6110 /* need to be called before evaluating global variables */
6111 xsltCountKeys(ctxt
);
6113 xsltEvalGlobalVariables(ctxt
);
6115 ctxt
->node
= (xmlNodePtr
) doc
;
6117 ctxt
->insert
= (xmlNodePtr
) res
;
6118 ctxt
->varsBase
= ctxt
->varsNr
- 1;
6120 ctxt
->xpathCtxt
->contextSize
= 1;
6121 ctxt
->xpathCtxt
->proximityPosition
= 1;
6122 ctxt
->xpathCtxt
->node
= NULL
; /* TODO: Set the context node here? */
6124 * Start processing the source tree -----------------------------------
6126 xsltProcessOneNode(ctxt
, ctxt
->node
, NULL
);
6128 * Remove all remaining vars from the stack.
6130 xsltLocalVariablePop(ctxt
, 0, -2);
6131 xsltShutdownCtxtExts(ctxt
);
6133 xsltCleanupTemplates(style
); /* TODO: <- style should be read only */
6136 * Now cleanup our variables so stylesheet can be re-used
6138 * TODO: this is not needed anymore global variables are copied
6139 * and not evaluated directly anymore, keep this as a check
6141 if (style
->variables
!= variables
) {
6142 vptr
= style
->variables
;
6143 while (vptr
->next
!= variables
)
6146 xsltFreeStackElemList(style
->variables
);
6147 style
->variables
= variables
;
6149 vptr
= style
->variables
;
6150 while (vptr
!= NULL
) {
6151 if (vptr
->computed
) {
6152 if (vptr
->value
!= NULL
) {
6153 xmlXPathFreeObject(vptr
->value
);
6162 * code disabled by wmb; awaiting kb's review
6163 * problem is that global variable(s) may contain xpath objects
6164 * from doc associated with RVT, so can't be freed at this point.
6165 * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
6166 * I assume this shouldn't be required at this point.
6169 * Free all remaining tree fragments.
6174 * Do some post processing work depending on the generated output
6176 root
= xmlDocGetRootElement(res
);
6178 const xmlChar
*doctype
= NULL
;
6180 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
))
6181 doctype
= xmlDictQLookup(ctxt
->dict
, root
->ns
->prefix
, root
->name
);
6182 if (doctype
== NULL
)
6183 doctype
= root
->name
;
6186 * Apply the default selection of the method
6188 if ((method
== NULL
) &&
6189 (root
->ns
== NULL
) &&
6190 (!xmlStrcasecmp(root
->name
, (const xmlChar
*) "html"))) {
6193 tmp
= res
->children
;
6194 while ((tmp
!= NULL
) && (tmp
!= root
)) {
6195 if (tmp
->type
== XML_ELEMENT_NODE
)
6197 if ((tmp
->type
== XML_TEXT_NODE
) && (!xmlIsBlankNode(tmp
)))
6202 ctxt
->type
= XSLT_OUTPUT_HTML
;
6204 * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
6205 * transformation on the doc, but functions like
6207 res
->type
= XML_HTML_DOCUMENT_NODE
;
6208 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
6209 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
6212 #ifdef XSLT_GENERATE_HTML_DOCTYPE
6213 } else if (version
!= NULL
) {
6214 xsltGetHTMLIDs(version
, &doctypePublic
,
6216 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
6218 xmlCreateIntSubset(res
, doctype
,
6226 if (ctxt
->type
== XSLT_OUTPUT_XML
) {
6227 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
6228 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
6229 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
6231 /* Need a small "hack" here to assure DTD comes before
6232 possible comment nodes */
6233 node
= res
->children
;
6235 res
->children
= NULL
;
6237 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
6240 if (res
->children
!= NULL
) {
6241 res
->children
->next
= node
;
6242 node
->prev
= res
->children
;
6245 res
->children
= node
;
6251 xmlXPathFreeNodeSet(ctxt
->nodeList
);
6252 if (profile
!= NULL
) {
6253 xsltSaveProfiling(ctxt
, profile
);
6259 if ((ctxt
!= NULL
) && (ctxt
->state
== XSLT_STATE_ERROR
)) {
6263 if ((res
!= NULL
) && (ctxt
!= NULL
) && (output
!= NULL
)) {
6266 ret
= xsltCheckWrite(ctxt
->sec
, ctxt
, (const xmlChar
*) output
);
6268 xsltTransformError(ctxt
, NULL
, NULL
,
6269 "xsltApplyStylesheet: forbidden to save to %s\n",
6271 } else if (ret
< 0) {
6272 xsltTransformError(ctxt
, NULL
, NULL
,
6273 "xsltApplyStylesheet: saving to %s may not be possible\n",
6278 #ifdef XSLT_DEBUG_PROFILE_CACHE
6279 printf("# Cache:\n");
6280 printf("# Reused tree fragments: %d\n", ctxt
->cache
->dbgReusedRVTs
);
6281 printf("# Reused variables : %d\n", ctxt
->cache
->dbgReusedVars
);
6284 if ((ctxt
!= NULL
) && (userCtxt
== NULL
))
6285 xsltFreeTransformContext(ctxt
);
6293 #ifdef XSLT_DEBUG_PROFILE_CACHE
6294 printf("# Cache:\n");
6295 printf("# Reused tree fragments: %d\n", ctxt
->cache
->dbgReusedRVTs
);
6296 printf("# Reused variables : %d\n", ctxt
->cache
->dbgReusedVars
);
6299 if ((ctxt
!= NULL
) && (userCtxt
== NULL
))
6300 xsltFreeTransformContext(ctxt
);
6305 * xsltApplyStylesheet:
6306 * @style: a parsed XSLT stylesheet
6307 * @doc: a parsed XML document
6308 * @params: a NULL terminated arry of parameters names/values tuples
6310 * Apply the stylesheet to the document
6311 * NOTE: This may lead to a non-wellformed output XML wise !
6313 * Returns the result document or NULL in case of error
6316 xsltApplyStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6317 const char **params
)
6319 return (xsltApplyStylesheetInternal(style
, doc
, params
, NULL
, NULL
, NULL
));
6323 * xsltProfileStylesheet:
6324 * @style: a parsed XSLT stylesheet
6325 * @doc: a parsed XML document
6326 * @params: a NULL terminated arry of parameters names/values tuples
6327 * @output: a FILE * for the profiling output
6329 * Apply the stylesheet to the document and dump the profiling to
6332 * Returns the result document or NULL in case of error
6335 xsltProfileStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6336 const char **params
, FILE * output
)
6340 res
= xsltApplyStylesheetInternal(style
, doc
, params
, NULL
, output
, NULL
);
6345 * xsltApplyStylesheetUser:
6346 * @style: a parsed XSLT stylesheet
6347 * @doc: a parsed XML document
6348 * @params: a NULL terminated array of parameters names/values tuples
6349 * @output: the targetted output
6350 * @profile: profile FILE * output or NULL
6351 * @userCtxt: user provided transform context
6353 * Apply the stylesheet to the document and allow the user to provide
6354 * its own transformation context.
6356 * Returns the result document or NULL in case of error
6359 xsltApplyStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
,
6360 const char **params
, const char *output
,
6361 FILE * profile
, xsltTransformContextPtr userCtxt
)
6365 res
= xsltApplyStylesheetInternal(style
, doc
, params
, output
,
6371 * xsltRunStylesheetUser:
6372 * @style: a parsed XSLT stylesheet
6373 * @doc: a parsed XML document
6374 * @params: a NULL terminated array of parameters names/values tuples
6375 * @output: the URL/filename ot the generated resource if available
6376 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6377 * @IObuf: an output buffer for progressive output (not implemented yet)
6378 * @profile: profile FILE * output or NULL
6379 * @userCtxt: user provided transform context
6381 * Apply the stylesheet to the document and generate the output according
6382 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6384 * NOTE: This may lead to a non-wellformed output XML wise !
6385 * NOTE: This may also result in multiple files being generated
6386 * NOTE: using IObuf, the result encoding used will be the one used for
6387 * creating the output buffer, use the following macro to read it
6388 * from the stylesheet
6389 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6390 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6391 * since the interface uses only UTF8
6393 * Returns the number of by written to the main resource or -1 in case of
6397 xsltRunStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
,
6398 const char **params
, const char *output
,
6399 xmlSAXHandlerPtr SAX
, xmlOutputBufferPtr IObuf
,
6400 FILE * profile
, xsltTransformContextPtr userCtxt
)
6405 if ((output
== NULL
) && (SAX
== NULL
) && (IObuf
== NULL
))
6407 if ((SAX
!= NULL
) && (IObuf
!= NULL
))
6410 /* unsupported yet */
6412 XSLT_TODO
/* xsltRunStylesheet xmlSAXHandlerPtr SAX */
6416 tmp
= xsltApplyStylesheetInternal(style
, doc
, params
, output
, profile
,
6419 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
6420 "xsltRunStylesheet : run failed\n");
6423 if (IObuf
!= NULL
) {
6424 /* TODO: incomplete, IObuf output not progressive */
6425 ret
= xsltSaveResultTo(IObuf
, tmp
, style
);
6427 ret
= xsltSaveResultToFilename(output
, tmp
, style
, 0);
6434 * xsltRunStylesheet:
6435 * @style: a parsed XSLT stylesheet
6436 * @doc: a parsed XML document
6437 * @params: a NULL terminated array of parameters names/values tuples
6438 * @output: the URL/filename ot the generated resource if available
6439 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6440 * @IObuf: an output buffer for progressive output (not implemented yet)
6442 * Apply the stylesheet to the document and generate the output according
6443 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6445 * NOTE: This may lead to a non-wellformed output XML wise !
6446 * NOTE: This may also result in multiple files being generated
6447 * NOTE: using IObuf, the result encoding used will be the one used for
6448 * creating the output buffer, use the following macro to read it
6449 * from the stylesheet
6450 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6451 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6452 * since the interface uses only UTF8
6454 * Returns the number of bytes written to the main resource or -1 in case of
6458 xsltRunStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6459 const char **params
, const char *output
,
6460 xmlSAXHandlerPtr SAX
, xmlOutputBufferPtr IObuf
)
6462 return(xsltRunStylesheetUser(style
, doc
, params
, output
, SAX
, IObuf
,
6467 * xsltRegisterAllElement:
6468 * @ctxt: the XPath context
6470 * Registers all default XSLT elements in this context
6473 xsltRegisterAllElement(xsltTransformContextPtr ctxt
)
6475 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "apply-templates",
6477 (xsltTransformFunction
) xsltApplyTemplates
);
6478 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "apply-imports",
6480 (xsltTransformFunction
) xsltApplyImports
);
6481 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "call-template",
6483 (xsltTransformFunction
) xsltCallTemplate
);
6484 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "element",
6486 (xsltTransformFunction
) xsltElement
);
6487 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "attribute",
6489 (xsltTransformFunction
) xsltAttribute
);
6490 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "text",
6492 (xsltTransformFunction
) xsltText
);
6493 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "processing-instruction",
6495 (xsltTransformFunction
) xsltProcessingInstruction
);
6496 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "comment",
6498 (xsltTransformFunction
) xsltComment
);
6499 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "copy",
6501 (xsltTransformFunction
) xsltCopy
);
6502 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "value-of",
6504 (xsltTransformFunction
) xsltValueOf
);
6505 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "number",
6507 (xsltTransformFunction
) xsltNumber
);
6508 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "for-each",
6510 (xsltTransformFunction
) xsltForEach
);
6511 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "if",
6513 (xsltTransformFunction
) xsltIf
);
6514 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "choose",
6516 (xsltTransformFunction
) xsltChoose
);
6517 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "sort",
6519 (xsltTransformFunction
) xsltSort
);
6520 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "copy-of",
6522 (xsltTransformFunction
) xsltCopyOf
);
6523 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "message",
6525 (xsltTransformFunction
) xsltMessage
);
6528 * Those don't have callable entry points but are registered anyway
6530 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "variable",
6532 (xsltTransformFunction
) xsltDebug
);
6533 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "param",
6535 (xsltTransformFunction
) xsltDebug
);
6536 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "with-param",
6538 (xsltTransformFunction
) xsltDebug
);
6539 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "decimal-format",
6541 (xsltTransformFunction
) xsltDebug
);
6542 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "when",
6544 (xsltTransformFunction
) xsltDebug
);
6545 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "otherwise",
6547 (xsltTransformFunction
) xsltDebug
);
6548 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "fallback",
6550 (xsltTransformFunction
) xsltDebug
);