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;
310 * @ctxt: transform context
311 * @node: context node
312 * @comp: precompiled expression
314 * Evaluate a precompiled XPath expression.
316 static xmlXPathObjectPtr
317 xsltPreCompEval(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
318 xsltStylePreCompPtr comp
) {
319 xmlXPathObjectPtr res
;
320 xmlXPathContextPtr xpctxt
;
321 xmlNodePtr oldXPContextNode
;
322 xmlNsPtr
*oldXPNamespaces
;
323 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
325 xpctxt
= ctxt
->xpathCtxt
;
326 oldXPContextNode
= xpctxt
->node
;
327 oldXPProximityPosition
= xpctxt
->proximityPosition
;
328 oldXPContextSize
= xpctxt
->contextSize
;
329 oldXPNsNr
= xpctxt
->nsNr
;
330 oldXPNamespaces
= xpctxt
->namespaces
;
333 #ifdef XSLT_REFACTORED
334 if (comp
->inScopeNs
!= NULL
) {
335 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
336 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
338 xpctxt
->namespaces
= NULL
;
342 xpctxt
->namespaces
= comp
->nsList
;
343 xpctxt
->nsNr
= comp
->nsNr
;
346 res
= xmlXPathCompiledEval(comp
->comp
, xpctxt
);
348 xpctxt
->node
= oldXPContextNode
;
349 xpctxt
->proximityPosition
= oldXPProximityPosition
;
350 xpctxt
->contextSize
= oldXPContextSize
;
351 xpctxt
->nsNr
= oldXPNsNr
;
352 xpctxt
->namespaces
= oldXPNamespaces
;
358 * xsltPreCompEvalToBoolean:
359 * @ctxt: transform context
360 * @node: context node
361 * @comp: precompiled expression
363 * Evaluate a precompiled XPath expression as boolean.
366 xsltPreCompEvalToBoolean(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
367 xsltStylePreCompPtr comp
) {
369 xmlXPathContextPtr xpctxt
;
370 xmlNodePtr oldXPContextNode
;
371 xmlNsPtr
*oldXPNamespaces
;
372 int oldXPProximityPosition
, oldXPContextSize
, oldXPNsNr
;
374 xpctxt
= ctxt
->xpathCtxt
;
375 oldXPContextNode
= xpctxt
->node
;
376 oldXPProximityPosition
= xpctxt
->proximityPosition
;
377 oldXPContextSize
= xpctxt
->contextSize
;
378 oldXPNsNr
= xpctxt
->nsNr
;
379 oldXPNamespaces
= xpctxt
->namespaces
;
382 #ifdef XSLT_REFACTORED
383 if (comp
->inScopeNs
!= NULL
) {
384 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
385 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
387 xpctxt
->namespaces
= NULL
;
391 xpctxt
->namespaces
= comp
->nsList
;
392 xpctxt
->nsNr
= comp
->nsNr
;
395 res
= xmlXPathCompiledEvalToBoolean(comp
->comp
, xpctxt
);
397 xpctxt
->node
= oldXPContextNode
;
398 xpctxt
->proximityPosition
= oldXPProximityPosition
;
399 xpctxt
->contextSize
= oldXPContextSize
;
400 xpctxt
->nsNr
= oldXPNsNr
;
401 xpctxt
->namespaces
= oldXPNamespaces
;
406 /************************************************************************
408 * XInclude default settings *
410 ************************************************************************/
412 static int xsltDoXIncludeDefault
= 0;
415 * xsltSetXIncludeDefault:
416 * @xinclude: whether to do XInclude processing
418 * Set whether XInclude should be processed on document being loaded by default
421 xsltSetXIncludeDefault(int xinclude
) {
422 xsltDoXIncludeDefault
= (xinclude
!= 0);
426 * xsltGetXIncludeDefault:
428 * Provides the default state for XInclude processing
430 * Returns 0 if there is no processing 1 otherwise
433 xsltGetXIncludeDefault(void) {
434 return(xsltDoXIncludeDefault
);
437 unsigned long xsltDefaultTrace
= (unsigned long) XSLT_TRACE_ALL
;
440 * xsltDebugSetDefaultTrace:
441 * @val: tracing level mask
443 * Set the default debug tracing level mask
445 void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val
) {
446 xsltDefaultTrace
= val
;
450 * xsltDebugGetDefaultTrace:
452 * Get the current default debug tracing level mask
454 * Returns the current default debug tracing level mask
456 xsltDebugTraceCodes
xsltDebugGetDefaultTrace() {
457 return xsltDefaultTrace
;
460 /************************************************************************
462 * Handling of Transformation Contexts *
464 ************************************************************************/
466 static xsltTransformCachePtr
467 xsltTransformCacheCreate(void)
469 xsltTransformCachePtr ret
;
471 ret
= (xsltTransformCachePtr
) xmlMalloc(sizeof(xsltTransformCache
));
473 xsltTransformError(NULL
, NULL
, NULL
,
474 "xsltTransformCacheCreate : malloc failed\n");
477 memset(ret
, 0, sizeof(xsltTransformCache
));
482 xsltTransformCacheFree(xsltTransformCachePtr cache
)
487 * Free tree fragments.
490 xmlDocPtr tmp
, cur
= cache
->RVT
;
493 cur
= (xmlDocPtr
) cur
->next
;
494 if (tmp
->_private
!= NULL
) {
496 * Tree the document info.
498 xsltFreeDocumentKeys((xsltDocumentPtr
) tmp
->_private
);
499 xmlFree(tmp
->_private
);
507 if (cache
->stackItems
) {
508 xsltStackElemPtr tmp
, cur
= cache
->stackItems
;
513 * REVISIT TODO: Should be call a destruction-function
523 * xsltNewTransformContext:
524 * @style: a parsed XSLT stylesheet
525 * @doc: the input document
527 * Create a new XSLT TransformContext
529 * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
531 xsltTransformContextPtr
532 xsltNewTransformContext(xsltStylesheetPtr style
, xmlDocPtr doc
) {
533 xsltTransformContextPtr cur
;
534 xsltDocumentPtr docu
;
539 cur
= (xsltTransformContextPtr
) xmlMalloc(sizeof(xsltTransformContext
));
541 xsltTransformError(NULL
, NULL
, (xmlNodePtr
)doc
,
542 "xsltNewTransformContext : malloc failed\n");
545 memset(cur
, 0, sizeof(xsltTransformContext
));
547 cur
->cache
= xsltTransformCacheCreate();
548 if (cur
->cache
== NULL
)
551 * setup of the dictionary must be done early as some of the
552 * processing later like key handling may need it.
554 cur
->dict
= xmlDictCreateSub(style
->dict
);
555 cur
->internalized
= ((style
->internalized
) && (cur
->dict
!= NULL
));
556 #ifdef WITH_XSLT_DEBUG
557 xsltGenericDebug(xsltGenericDebugContext
,
558 "Creating sub-dictionary from stylesheet for transformation\n");
562 * initialize the template stack
564 cur
->templTab
= (xsltTemplatePtr
*)
565 xmlMalloc(10 * sizeof(xsltTemplatePtr
));
566 if (cur
->templTab
== NULL
) {
567 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
568 "xsltNewTransformContext: out of memory\n");
574 cur
->maxTemplateDepth
= xsltMaxDepth
;
577 * initialize the variables stack
579 cur
->varsTab
= (xsltStackElemPtr
*)
580 xmlMalloc(10 * sizeof(xsltStackElemPtr
));
581 if (cur
->varsTab
== NULL
) {
582 xmlGenericError(xmlGenericErrorContext
,
583 "xsltNewTransformContext: out of memory\n");
590 cur
->maxTemplateVars
= xsltMaxVars
;
593 * the profiling stack is not initialized by default
602 cur
->xpathCtxt
= xmlXPathNewContext(doc
);
603 if (cur
->xpathCtxt
== NULL
) {
604 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
605 "xsltNewTransformContext : xmlXPathNewContext failed\n");
609 * Create an XPath cache.
611 if (xmlXPathContextSetCache(cur
->xpathCtxt
, 1, -1, 0) == -1)
614 * Initialize the extras array
616 if (style
->extrasNr
!= 0) {
617 cur
->extrasMax
= style
->extrasNr
+ 20;
618 cur
->extras
= (xsltRuntimeExtraPtr
)
619 xmlMalloc(cur
->extrasMax
* sizeof(xsltRuntimeExtra
));
620 if (cur
->extras
== NULL
) {
621 xmlGenericError(xmlGenericErrorContext
,
622 "xsltNewTransformContext: out of memory\n");
625 cur
->extrasNr
= style
->extrasNr
;
626 for (i
= 0;i
< cur
->extrasMax
;i
++) {
627 cur
->extras
[i
].info
= NULL
;
628 cur
->extras
[i
].deallocate
= NULL
;
629 cur
->extras
[i
].val
.ptr
= NULL
;
637 XSLT_REGISTER_VARIABLE_LOOKUP(cur
);
638 XSLT_REGISTER_FUNCTION_LOOKUP(cur
);
639 cur
->xpathCtxt
->nsHash
= style
->nsHash
;
641 * Initialize the registered external modules
643 xsltInitCtxtExts(cur
);
645 * Setup document element ordering for later efficiencies
648 if (xslDebugStatus
== XSLT_DEBUG_NONE
)
649 xmlXPathOrderDocElems(doc
);
651 * Must set parserOptions before calling xsltNewDocument
654 cur
->parserOptions
= XSLT_PARSE_OPTIONS
;
655 docu
= xsltNewDocument(cur
, doc
);
657 xsltTransformError(cur
, NULL
, (xmlNodePtr
)doc
,
658 "xsltNewTransformContext : xsltNewDocument failed\n");
662 cur
->document
= docu
;
664 cur
->outputFile
= NULL
;
665 cur
->sec
= xsltGetDefaultSecurityPrefs();
666 cur
->debugStatus
= xslDebugStatus
;
667 cur
->traceCode
= (unsigned long*) &xsltDefaultTrace
;
668 cur
->xinclude
= xsltGetXIncludeDefault();
669 cur
->keyInitLevel
= 0;
675 xsltFreeTransformContext(cur
);
680 * xsltFreeTransformContext:
681 * @ctxt: an XSLT parser context
683 * Free up the memory allocated by @ctxt
686 xsltFreeTransformContext(xsltTransformContextPtr ctxt
) {
691 * Shutdown the extension modules associated to the stylesheet
694 xsltShutdownCtxtExts(ctxt
);
696 if (ctxt
->xpathCtxt
!= NULL
) {
697 ctxt
->xpathCtxt
->nsHash
= NULL
;
698 xmlXPathFreeContext(ctxt
->xpathCtxt
);
700 if (ctxt
->templTab
!= NULL
)
701 xmlFree(ctxt
->templTab
);
702 if (ctxt
->varsTab
!= NULL
)
703 xmlFree(ctxt
->varsTab
);
704 if (ctxt
->profTab
!= NULL
)
705 xmlFree(ctxt
->profTab
);
706 if ((ctxt
->extrasNr
> 0) && (ctxt
->extras
!= NULL
)) {
709 for (i
= 0;i
< ctxt
->extrasNr
;i
++) {
710 if ((ctxt
->extras
[i
].deallocate
!= NULL
) &&
711 (ctxt
->extras
[i
].info
!= NULL
))
712 ctxt
->extras
[i
].deallocate(ctxt
->extras
[i
].info
);
714 xmlFree(ctxt
->extras
);
716 xsltFreeGlobalVariables(ctxt
);
717 xsltFreeDocuments(ctxt
);
718 xsltFreeCtxtExts(ctxt
);
720 xsltTransformCacheFree(ctxt
->cache
);
721 xmlDictFree(ctxt
->dict
);
722 #ifdef WITH_XSLT_DEBUG
723 xsltGenericDebug(xsltGenericDebugContext
,
724 "freeing transformation dictionary\n");
726 memset(ctxt
, -1, sizeof(xsltTransformContext
));
730 /************************************************************************
732 * Copy of Nodes in an XSLT fashion *
734 ************************************************************************/
736 xmlNodePtr
xsltCopyTree(xsltTransformContextPtr ctxt
,
737 xmlNodePtr node
, xmlNodePtr insert
, int literal
);
741 * @parent: the parent node
742 * @cur: the child node
744 * Wrapper version of xmlAddChild with a more consistent behaviour on
745 * error. One expect the use to be child = xsltAddChild(parent, child);
746 * and the routine will take care of not leaking on errors or node merge
748 * Returns the child is successfully attached or NULL if merged or freed
751 xsltAddChild(xmlNodePtr parent
, xmlNodePtr cur
) {
754 if ((cur
== NULL
) || (parent
== NULL
))
756 if (parent
== NULL
) {
760 ret
= xmlAddChild(parent
, cur
);
767 * @ctxt: a XSLT process context
768 * @target: the text node where the text will be attached
769 * @string: the text string
770 * @len: the string length in byte
772 * Extend the current text node with the new string, it handles coalescing
774 * Returns: the text node
777 xsltAddTextString(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
778 const xmlChar
*string
, int len
) {
782 if ((len
<= 0) || (string
== NULL
) || (target
== NULL
))
785 if (ctxt
->lasttext
== target
->content
) {
787 if (ctxt
->lasttuse
+ len
>= ctxt
->lasttsize
) {
791 size
= ctxt
->lasttsize
+ len
+ 100;
793 newbuf
= (xmlChar
*) xmlRealloc(target
->content
,size
);
794 if (newbuf
== NULL
) {
795 xsltTransformError(ctxt
, NULL
, target
,
796 "xsltCopyText: text allocation failed\n");
799 ctxt
->lasttsize
= size
;
800 ctxt
->lasttext
= newbuf
;
801 target
->content
= newbuf
;
803 memcpy(&(target
->content
[ctxt
->lasttuse
]), string
, len
);
804 ctxt
->lasttuse
+= len
;
805 target
->content
[ctxt
->lasttuse
] = 0;
807 xmlNodeAddContent(target
, string
);
808 ctxt
->lasttext
= target
->content
;
809 len
= xmlStrlen(target
->content
);
810 ctxt
->lasttsize
= len
;
811 ctxt
->lasttuse
= len
;
817 * xsltCopyTextString:
818 * @ctxt: a XSLT process context
819 * @target: the element where the text will be attached
820 * @string: the text string
821 * @noescape: should disable-escaping be activated for this text node.
823 * Adds @string to a newly created or an existent text node child of
826 * Returns: the text node, where the text content of @cur is copied to.
827 * NULL in case of API or internal errors.
830 xsltCopyTextString(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
831 const xmlChar
*string
, int noescape
)
839 #ifdef WITH_XSLT_DEBUG_PROCESS
840 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
841 "xsltCopyTextString: copy text %s\n",
846 * Play safe and reset the merging mechanism for every new
849 if ((target
== NULL
) || (target
->children
== NULL
)) {
850 ctxt
->lasttext
= NULL
;
853 /* handle coalescing of text nodes here */
854 len
= xmlStrlen(string
);
855 if ((ctxt
->type
== XSLT_OUTPUT_XML
) &&
856 (ctxt
->style
->cdataSection
!= NULL
) &&
858 (target
->type
== XML_ELEMENT_NODE
) &&
859 (((target
->ns
== NULL
) &&
860 (xmlHashLookup2(ctxt
->style
->cdataSection
,
861 target
->name
, NULL
) != NULL
)) ||
862 ((target
->ns
!= NULL
) &&
863 (xmlHashLookup2(ctxt
->style
->cdataSection
,
864 target
->name
, target
->ns
->href
) != NULL
))))
867 * Process "cdata-section-elements".
869 if ((target
->last
!= NULL
) &&
870 (target
->last
->type
== XML_CDATA_SECTION_NODE
))
872 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
874 copy
= xmlNewCDataBlock(ctxt
->output
, string
, len
);
875 } else if (noescape
) {
877 * Process "disable-output-escaping".
879 if ((target
!= NULL
) && (target
->last
!= NULL
) &&
880 (target
->last
->type
== XML_TEXT_NODE
) &&
881 (target
->last
->name
== xmlStringTextNoenc
))
883 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
885 copy
= xmlNewTextLen(string
, len
);
887 copy
->name
= xmlStringTextNoenc
;
890 * Default processing.
892 if ((target
!= NULL
) && (target
->last
!= NULL
) &&
893 (target
->last
->type
== XML_TEXT_NODE
) &&
894 (target
->last
->name
== xmlStringText
)) {
895 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
897 copy
= xmlNewTextLen(string
, len
);
899 if (copy
!= NULL
&& target
!= NULL
)
900 copy
= xsltAddChild(target
, copy
);
902 ctxt
->lasttext
= copy
->content
;
903 ctxt
->lasttsize
= len
;
904 ctxt
->lasttuse
= len
;
906 xsltTransformError(ctxt
, NULL
, target
,
907 "xsltCopyTextString: text copy failed\n");
908 ctxt
->lasttext
= NULL
;
915 * @ctxt: a XSLT process context
916 * @target: the element where the text will be attached
917 * @cur: the text or CDATA node
918 * @interned: the string is in the target doc dictionary
920 * Copy the text content of @cur and append it to @target's children.
922 * Returns: the text node, where the text content of @cur is copied to.
923 * NULL in case of API or internal errors.
926 xsltCopyText(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
927 xmlNodePtr cur
, int interned
)
931 if ((cur
->type
!= XML_TEXT_NODE
) &&
932 (cur
->type
!= XML_CDATA_SECTION_NODE
))
934 if (cur
->content
== NULL
)
937 #ifdef WITH_XSLT_DEBUG_PROCESS
938 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
939 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
940 "xsltCopyText: copy CDATA text %s\n",
942 } else if (cur
->name
== xmlStringTextNoenc
) {
943 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
944 "xsltCopyText: copy unescaped text %s\n",
947 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
948 "xsltCopyText: copy text %s\n",
954 * Play save and reset the merging mechanism for every new
957 if ((target
== NULL
) || (target
->children
== NULL
)) {
958 ctxt
->lasttext
= NULL
;
961 if ((ctxt
->style
->cdataSection
!= NULL
) &&
962 (ctxt
->type
== XSLT_OUTPUT_XML
) &&
964 (target
->type
== XML_ELEMENT_NODE
) &&
965 (((target
->ns
== NULL
) &&
966 (xmlHashLookup2(ctxt
->style
->cdataSection
,
967 target
->name
, NULL
) != NULL
)) ||
968 ((target
->ns
!= NULL
) &&
969 (xmlHashLookup2(ctxt
->style
->cdataSection
,
970 target
->name
, target
->ns
->href
) != NULL
))))
973 * Process "cdata-section-elements".
976 * OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
979 * TODO: Since this doesn't merge adjacent CDATA-section nodes,
980 * we'll get: <![CDATA[x]]><!CDATA[y]]>.
981 * TODO: Reported in #321505.
983 if ((target
->last
!= NULL
) &&
984 (target
->last
->type
== XML_CDATA_SECTION_NODE
))
987 * Append to existing CDATA-section node.
989 copy
= xsltAddTextString(ctxt
, target
->last
, cur
->content
,
990 xmlStrlen(cur
->content
));
995 len
= xmlStrlen(cur
->content
);
996 copy
= xmlNewCDataBlock(ctxt
->output
, cur
->content
, len
);
999 ctxt
->lasttext
= copy
->content
;
1000 ctxt
->lasttsize
= len
;
1001 ctxt
->lasttuse
= len
;
1003 } else if ((target
!= NULL
) &&
1004 (target
->last
!= NULL
) &&
1005 /* both escaped or both non-escaped text-nodes */
1006 (((target
->last
->type
== XML_TEXT_NODE
) &&
1007 (target
->last
->name
== cur
->name
)) ||
1008 /* non-escaped text nodes and CDATA-section nodes */
1009 (((target
->last
->type
== XML_CDATA_SECTION_NODE
) &&
1010 (cur
->name
== xmlStringTextNoenc
)))))
1013 * we are appending to an existing text node
1015 copy
= xsltAddTextString(ctxt
, target
->last
, cur
->content
,
1016 xmlStrlen(cur
->content
));
1018 } else if ((interned
) && (target
!= NULL
) &&
1019 (target
->doc
!= NULL
) &&
1020 (target
->doc
->dict
== ctxt
->dict
))
1023 * TODO: DO we want to use this also for "text" output?
1025 copy
= xmlNewTextLen(NULL
, 0);
1028 if (cur
->name
== xmlStringTextNoenc
)
1029 copy
->name
= xmlStringTextNoenc
;
1032 * Must confirm that content is in dict (bug 302821)
1033 * TODO: This check should be not needed for text coming
1034 * from the stylesheets
1036 if (xmlDictOwns(ctxt
->dict
, cur
->content
))
1037 copy
->content
= cur
->content
;
1039 if ((copy
->content
= xmlStrdup(cur
->content
)) == NULL
)
1044 * normal processing. keep counters to extend the text node
1045 * in xsltAddTextString if needed.
1049 len
= xmlStrlen(cur
->content
);
1050 copy
= xmlNewTextLen(cur
->content
, len
);
1053 if (cur
->name
== xmlStringTextNoenc
)
1054 copy
->name
= xmlStringTextNoenc
;
1055 ctxt
->lasttext
= copy
->content
;
1056 ctxt
->lasttsize
= len
;
1057 ctxt
->lasttuse
= len
;
1060 if (target
!= NULL
) {
1061 copy
->doc
= target
->doc
;
1063 * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
1064 * to ensure that the optimized text-merging mechanism
1065 * won't interfere with normal node-merging in any case.
1067 copy
= xsltAddChild(target
, copy
);
1070 xsltTransformError(ctxt
, NULL
, target
,
1071 "xsltCopyText: text copy failed\n");
1075 if ((copy
== NULL
) || (copy
->content
== NULL
)) {
1076 xsltTransformError(ctxt
, NULL
, target
,
1077 "Internal error in xsltCopyText(): "
1078 "Failed to copy the string.\n");
1079 ctxt
->state
= XSLT_STATE_STOPPED
;
1085 * xsltShallowCopyAttr:
1086 * @ctxt: a XSLT process context
1087 * @invocNode: responsible node in the stylesheet; used for error reports
1088 * @target: the element where the attribute will be grafted
1089 * @attr: the attribute to be copied
1091 * Do a copy of an attribute.
1093 * - xsltCopyTreeInternal()
1097 * Returns: a new xmlAttrPtr, or NULL in case of error.
1100 xsltShallowCopyAttr(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1101 xmlNodePtr target
, xmlAttrPtr attr
)
1109 if (target
->type
!= XML_ELEMENT_NODE
) {
1110 xsltTransformError(ctxt
, NULL
, invocNode
,
1111 "Cannot add an attribute node to a non-element node.\n");
1115 if (target
->children
!= NULL
) {
1116 xsltTransformError(ctxt
, NULL
, invocNode
,
1117 "Attribute nodes must be added before "
1118 "any child nodes to an element.\n");
1122 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1123 if (attr
->ns
!= NULL
) {
1126 ns
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1127 attr
->ns
->href
, attr
->ns
->prefix
, target
);
1129 xsltTransformError(ctxt
, NULL
, invocNode
,
1130 "Namespace fixup error: Failed to acquire an in-scope "
1131 "namespace binding of the copied attribute '{%s}%s'.\n",
1132 attr
->ns
->href
, attr
->name
);
1134 * TODO: Should we just stop here?
1138 * Note that xmlSetNsProp() will take care of duplicates
1139 * and assigns the new namespace even to a duplicate.
1141 copy
= xmlSetNsProp(target
, ns
, attr
->name
, value
);
1143 copy
= xmlSetNsProp(target
, NULL
, attr
->name
, value
);
1153 * NOTE: This was optimized according to bug #342695.
1154 * TODO: Can this further be optimized, if source and target
1155 * share the same dict and attr->children is just 1 text node
1156 * which is in the dict? How probable is such a case?
1159 * TODO: Do we need to create an empty text node if the value
1160 * is the empty string?
1162 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1163 if (value
!= NULL
) {
1164 txtNode
= xmlNewDocText(target
->doc
, NULL
);
1165 if (txtNode
== NULL
)
1167 if ((target
->doc
!= NULL
) &&
1168 (target
->doc
->dict
!= NULL
))
1171 (xmlChar
*) xmlDictLookup(target
->doc
->dict
,
1172 BAD_CAST value
, -1);
1175 txtNode
->content
= value
;
1176 copy
->children
= txtNode
;
1184 * xsltCopyAttrListNoOverwrite:
1185 * @ctxt: a XSLT process context
1186 * @invocNode: responsible node in the stylesheet; used for error reports
1187 * @target: the element where the new attributes will be grafted
1188 * @attr: the first attribute in the list to be copied
1190 * Copies a list of attribute nodes, starting with @attr, over to the
1191 * @target element node.
1194 * - xsltCopyTreeInternal()
1196 * Returns 0 on success and -1 on errors and internal errors.
1199 xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt
,
1200 xmlNodePtr invocNode
,
1201 xmlNodePtr target
, xmlAttrPtr attr
)
1204 xmlNsPtr origNs
= NULL
, copyNs
= NULL
;
1208 * Don't use xmlCopyProp() here, since it will try to
1209 * reconciliate namespaces.
1211 while (attr
!= NULL
) {
1213 * Find a namespace node in the tree of @target.
1214 * Avoid searching for the same ns.
1216 if (attr
->ns
!= origNs
) {
1218 if (attr
->ns
!= NULL
) {
1219 copyNs
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1220 attr
->ns
->href
, attr
->ns
->prefix
, target
);
1227 * If attribute has a value, we need to copy it (watching out
1228 * for possible entities)
1230 if ((attr
->children
) && (attr
->children
->type
== XML_TEXT_NODE
) &&
1231 (attr
->children
->next
== NULL
)) {
1232 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
,
1233 attr
->children
->content
);
1234 } else if (attr
->children
!= NULL
) {
1235 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1236 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
, BAD_CAST value
);
1239 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
, NULL
);
1251 * xsltShallowCopyElem:
1252 * @ctxt: the XSLT process context
1253 * @node: the element node in the source tree
1254 * or the Literal Result Element
1255 * @insert: the parent in the result tree
1256 * @isLRE: if @node is a Literal Result Element
1258 * Make a copy of the element node @node
1259 * and insert it as last child of @insert.
1261 * URGENT TODO: The problem with this one (for the non-refactored code)
1262 * is that it is used for both, Literal Result Elements *and*
1263 * copying input nodes.
1265 * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
1268 * xsltApplySequenceConstructor()
1269 * (for Literal Result Elements - which is a problem)
1270 * xsltCopy() (for shallow-copying elements via xsl:copy)
1272 * Returns a pointer to the new node, or NULL in case of error
1275 xsltShallowCopyElem(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1276 xmlNodePtr insert
, int isLRE
)
1280 if ((node
->type
== XML_DTD_NODE
) || (insert
== NULL
))
1282 if ((node
->type
== XML_TEXT_NODE
) ||
1283 (node
->type
== XML_CDATA_SECTION_NODE
))
1284 return(xsltCopyText(ctxt
, insert
, node
, 0));
1286 copy
= xmlDocCopyNode(node
, insert
->doc
, 0);
1288 copy
->doc
= ctxt
->output
;
1289 copy
= xsltAddChild(insert
, copy
);
1291 xsltTransformError(ctxt
, NULL
, node
,
1292 "xsltShallowCopyElem: copy failed\n");
1296 if (node
->type
== XML_ELEMENT_NODE
) {
1298 * Add namespaces as they are needed
1300 if (node
->nsDef
!= NULL
) {
1302 * TODO: Remove the LRE case in the refactored code
1306 xsltCopyNamespaceList(ctxt
, copy
, node
->nsDef
);
1308 xsltCopyNamespaceListInternal(copy
, node
->nsDef
);
1312 * URGENT TODO: The problem with this is that it does not
1313 * copy over all namespace nodes in scope.
1314 * The damn thing about this is, that we would need to
1315 * use the xmlGetNsList(), for every single node; this is
1316 * also done in xsltCopyTreeInternal(), but only for the top node.
1318 if (node
->ns
!= NULL
) {
1321 * REVISIT TODO: Since the non-refactored code still does
1322 * ns-aliasing, we need to call xsltGetNamespace() here.
1323 * Remove this when ready.
1325 copy
->ns
= xsltGetNamespace(ctxt
, node
, node
->ns
, copy
);
1327 copy
->ns
= xsltGetSpecialNamespace(ctxt
,
1328 node
, node
->ns
->href
, node
->ns
->prefix
, copy
);
1331 } else if ((insert
->type
== XML_ELEMENT_NODE
) &&
1332 (insert
->ns
!= NULL
))
1335 * "Undeclare" the default namespace.
1337 xsltGetSpecialNamespace(ctxt
, node
, NULL
, NULL
, copy
);
1341 xsltTransformError(ctxt
, NULL
, node
,
1342 "xsltShallowCopyElem: copy %s failed\n", node
->name
);
1349 * @ctxt: a XSLT process context
1350 * @invocNode: responsible node in the stylesheet; used for error reports
1351 * @list: the list of element nodes in the source tree.
1352 * @insert: the parent in the result tree.
1353 * @isLRE: is this a literal result element list
1354 * @topElemVisited: indicates if a top-most element was already processed
1356 * Make a copy of the full list of tree @list
1357 * and insert it as last children of @insert
1359 * NOTE: Not to be used for Literal Result Elements.
1364 * Returns a pointer to the new list, or NULL in case of error
1367 xsltCopyTreeList(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1369 xmlNodePtr insert
, int isLRE
, int topElemVisited
)
1371 xmlNodePtr copy
, ret
= NULL
;
1373 while (list
!= NULL
) {
1374 copy
= xsltCopyTreeInternal(ctxt
, invocNode
,
1375 list
, insert
, isLRE
, topElemVisited
);
1387 * xsltCopyNamespaceListInternal:
1388 * @node: the target node
1389 * @cur: the first namespace
1391 * Do a copy of a namespace list. If @node is non-NULL the
1392 * new namespaces are added automatically.
1394 * xsltCopyTreeInternal()
1396 * QUESTION: What is the exact difference between this function
1397 * and xsltCopyNamespaceList() in "namespaces.c"?
1398 * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
1400 * Returns: a new xmlNsPtr, or NULL in case of error.
1403 xsltCopyNamespaceListInternal(xmlNodePtr elem
, xmlNsPtr ns
) {
1404 xmlNsPtr ret
= NULL
;
1405 xmlNsPtr p
= NULL
, q
, luNs
;
1410 * One can add namespaces only on element nodes
1412 if ((elem
!= NULL
) && (elem
->type
!= XML_ELEMENT_NODE
))
1416 if (ns
->type
!= XML_NAMESPACE_DECL
)
1419 * Avoid duplicating namespace declarations on the tree.
1422 if ((elem
->ns
!= NULL
) &&
1423 xmlStrEqual(elem
->ns
->prefix
, ns
->prefix
) &&
1424 xmlStrEqual(elem
->ns
->href
, ns
->href
))
1429 luNs
= xmlSearchNs(elem
->doc
, elem
, ns
->prefix
);
1430 if ((luNs
!= NULL
) && (xmlStrEqual(luNs
->href
, ns
->href
)))
1436 q
= xmlNewNs(elem
, ns
->href
, ns
->prefix
);
1439 } else if (q
!= NULL
) {
1444 } while (ns
!= NULL
);
1449 * xsltShallowCopyNsNode:
1450 * @ctxt: the XSLT transformation context
1451 * @invocNode: responsible node in the stylesheet; used for error reports
1452 * @insert: the target element node in the result tree
1453 * @ns: the namespace node
1455 * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
1457 * Returns a new/existing ns-node, or NULL.
1460 xsltShallowCopyNsNode(xsltTransformContextPtr ctxt
,
1461 xmlNodePtr invocNode
,
1466 * TODO: Contrary to header comments, this is declared as int.
1467 * be modified to return a node pointer, or NULL if any error
1471 if ((insert
== NULL
) || (insert
->type
!= XML_ELEMENT_NODE
))
1474 if (insert
->children
!= NULL
) {
1475 xsltTransformError(ctxt
, NULL
, invocNode
,
1476 "Namespace nodes must be added before "
1477 "any child nodes are added to an element.\n");
1481 * BIG NOTE: Xalan-J simply overwrites any ns-decls with
1482 * an equal prefix. We definitively won't do that.
1484 * MSXML 4.0 and the .NET ignores ns-decls for which an
1485 * equal prefix is already in use.
1487 * Saxon raises an error like:
1488 * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
1489 * nodes with the same name".
1491 * NOTE: We'll currently follow MSXML here.
1492 * REVISIT TODO: Check if it's better to follow Saxon here.
1494 if (ns
->prefix
== NULL
) {
1496 * If we are adding ns-nodes to an element using e.g.
1497 * <xsl:copy-of select="/foo/namespace::*">, then we need
1498 * to ensure that we don't incorrectly declare a default
1499 * namespace on an element in no namespace, which otherwise
1500 * would move the element incorrectly into a namespace, if
1501 * the node tree is serialized.
1503 if (insert
->ns
== NULL
)
1505 } else if ((ns
->prefix
[0] == 'x') &&
1506 xmlStrEqual(ns
->prefix
, BAD_CAST
"xml"))
1509 * The XML namespace is built in.
1514 if (insert
->nsDef
!= NULL
) {
1515 tmpns
= insert
->nsDef
;
1517 if ((tmpns
->prefix
== NULL
) == (ns
->prefix
== NULL
)) {
1518 if ((tmpns
->prefix
== ns
->prefix
) ||
1519 xmlStrEqual(tmpns
->prefix
, ns
->prefix
))
1524 if (xmlStrEqual(tmpns
->href
, ns
->href
))
1529 tmpns
= tmpns
->next
;
1530 } while (tmpns
!= NULL
);
1532 tmpns
= xmlSearchNs(insert
->doc
, insert
, ns
->prefix
);
1533 if ((tmpns
!= NULL
) && xmlStrEqual(tmpns
->href
, ns
->href
))
1536 * Declare a new namespace.
1537 * TODO: The problem (wrt efficiency) with this xmlNewNs() is
1538 * that it will again search the already declared namespaces
1539 * for a duplicate :-/
1541 return(xmlNewNs(insert
, ns
->href
, ns
->prefix
));
1545 * TODO: We could as well raise an error here (like Saxon does),
1546 * or at least generate a warning.
1552 * xsltCopyTreeInternal:
1553 * @ctxt: the XSLT transformation context
1554 * @invocNode: responsible node in the stylesheet; used for error reports
1555 * @node: the element node in the source tree
1556 * @insert: the parent in the result tree
1557 * @isLRE: indicates if @node is a Literal Result Element
1558 * @topElemVisited: indicates if a top-most element was already processed
1560 * Make a copy of the full tree under the element node @node
1561 * and insert it as last child of @insert
1563 * NOTE: Not to be used for Literal Result Elements.
1568 * Returns a pointer to the new tree, or NULL in case of error
1571 xsltCopyTreeInternal(xsltTransformContextPtr ctxt
,
1572 xmlNodePtr invocNode
,
1574 xmlNodePtr insert
, int isLRE
, int topElemVisited
)
1580 switch (node
->type
) {
1581 case XML_ELEMENT_NODE
:
1582 case XML_ENTITY_REF_NODE
:
1583 case XML_ENTITY_NODE
:
1585 case XML_COMMENT_NODE
:
1586 case XML_DOCUMENT_NODE
:
1587 case XML_HTML_DOCUMENT_NODE
:
1588 #ifdef LIBXML_DOCB_ENABLED
1589 case XML_DOCB_DOCUMENT_NODE
:
1592 case XML_TEXT_NODE
: {
1593 int noenc
= (node
->name
== xmlStringTextNoenc
);
1594 return(xsltCopyTextString(ctxt
, insert
, node
->content
, noenc
));
1596 case XML_CDATA_SECTION_NODE
:
1597 return(xsltCopyTextString(ctxt
, insert
, node
->content
, 0));
1598 case XML_ATTRIBUTE_NODE
:
1600 xsltShallowCopyAttr(ctxt
, invocNode
, insert
, (xmlAttrPtr
) node
));
1601 case XML_NAMESPACE_DECL
:
1602 return((xmlNodePtr
) xsltShallowCopyNsNode(ctxt
, invocNode
,
1603 insert
, (xmlNsPtr
) node
));
1605 case XML_DOCUMENT_TYPE_NODE
:
1606 case XML_DOCUMENT_FRAG_NODE
:
1607 case XML_NOTATION_NODE
:
1609 case XML_ELEMENT_DECL
:
1610 case XML_ATTRIBUTE_DECL
:
1611 case XML_ENTITY_DECL
:
1612 case XML_XINCLUDE_START
:
1613 case XML_XINCLUDE_END
:
1616 if (XSLT_IS_RES_TREE_FRAG(node
)) {
1617 if (node
->children
!= NULL
)
1618 copy
= xsltCopyTreeList(ctxt
, invocNode
,
1619 node
->children
, insert
, 0, 0);
1624 copy
= xmlDocCopyNode(node
, insert
->doc
, 0);
1626 copy
->doc
= ctxt
->output
;
1627 copy
= xsltAddChild(insert
, copy
);
1629 xsltTransformError(ctxt
, NULL
, invocNode
,
1630 "xsltCopyTreeInternal: Copying of '%s' failed.\n", node
->name
);
1634 * The node may have been coalesced into another text node.
1636 if (insert
->last
!= copy
)
1637 return(insert
->last
);
1640 if (node
->type
== XML_ELEMENT_NODE
) {
1642 * Copy in-scope namespace nodes.
1644 * REVISIT: Since we try to reuse existing in-scope ns-decls by
1645 * using xmlSearchNsByHref(), this will eventually change
1646 * the prefix of an original ns-binding; thus it might
1647 * break QNames in element/attribute content.
1648 * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
1649 * context, plus a ns-lookup function, which writes directly
1650 * to a given list, then we wouldn't need to create/free the
1651 * nsList every time.
1653 if ((topElemVisited
== 0) &&
1654 (node
->parent
!= NULL
) &&
1655 (node
->parent
->type
!= XML_DOCUMENT_NODE
) &&
1656 (node
->parent
->type
!= XML_HTML_DOCUMENT_NODE
))
1658 xmlNsPtr
*nsList
, *curns
, ns
;
1661 * If this is a top-most element in a tree to be
1662 * copied, then we need to ensure that all in-scope
1663 * namespaces are copied over. For nodes deeper in the
1664 * tree, it is sufficient to reconcile only the ns-decls
1665 * (node->nsDef entries).
1668 nsList
= xmlGetNsList(node
->doc
, node
);
1669 if (nsList
!= NULL
) {
1673 * Search by prefix first in order to break as less
1674 * QNames in element/attribute content as possible.
1676 ns
= xmlSearchNs(insert
->doc
, insert
,
1680 (! xmlStrEqual(ns
->href
, (*curns
)->href
)))
1684 * Search by namespace name.
1685 * REVISIT TODO: Currently disabled.
1688 ns
= xmlSearchNsByHref(insert
->doc
,
1689 insert
, (*curns
)->href
);
1694 * Declare a new namespace on the copied element.
1696 ns
= xmlNewNs(copy
, (*curns
)->href
,
1698 /* TODO: Handle errors */
1700 if (node
->ns
== *curns
) {
1702 * If this was the original's namespace then set
1703 * the generated counterpart on the copy.
1708 } while (*curns
!= NULL
);
1711 } else if (node
->nsDef
!= NULL
) {
1713 * Copy over all namespace declaration attributes.
1715 if (node
->nsDef
!= NULL
) {
1717 xsltCopyNamespaceList(ctxt
, copy
, node
->nsDef
);
1719 xsltCopyNamespaceListInternal(copy
, node
->nsDef
);
1723 * Set the namespace.
1725 if (node
->ns
!= NULL
) {
1726 if (copy
->ns
== NULL
) {
1728 * This will map copy->ns to one of the newly created
1729 * in-scope ns-decls, OR create a new ns-decl on @copy.
1731 copy
->ns
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1732 node
->ns
->href
, node
->ns
->prefix
, copy
);
1734 } else if ((insert
->type
== XML_ELEMENT_NODE
) &&
1735 (insert
->ns
!= NULL
))
1738 * "Undeclare" the default namespace on @copy with xmlns="".
1740 xsltGetSpecialNamespace(ctxt
, invocNode
, NULL
, NULL
, copy
);
1743 * Copy attribute nodes.
1745 if (node
->properties
!= NULL
) {
1746 xsltCopyAttrListNoOverwrite(ctxt
, invocNode
,
1747 copy
, node
->properties
);
1749 if (topElemVisited
== 0)
1755 if (node
->children
!= NULL
) {
1756 xsltCopyTreeList(ctxt
, invocNode
,
1757 node
->children
, copy
, isLRE
, topElemVisited
);
1760 xsltTransformError(ctxt
, NULL
, invocNode
,
1761 "xsltCopyTreeInternal: Copying of '%s' failed.\n", node
->name
);
1768 * @ctxt: the XSLT transformation context
1769 * @node: the element node in the source tree
1770 * @insert: the parent in the result tree
1771 * @literal: indicates if @node is a Literal Result Element
1773 * Make a copy of the full tree under the element node @node
1774 * and insert it as last child of @insert
1775 * For literal result element, some of the namespaces may not be copied
1776 * over according to section 7.1.
1777 * TODO: Why is this a public function?
1779 * Returns a pointer to the new tree, or NULL in case of error
1782 xsltCopyTree(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1783 xmlNodePtr insert
, int literal
)
1785 return(xsltCopyTreeInternal(ctxt
, node
, node
, insert
, literal
, 0));
1789 /************************************************************************
1791 * Error/fallback processing *
1793 ************************************************************************/
1796 * xsltApplyFallbacks:
1797 * @ctxt: a XSLT process context
1798 * @node: the node in the source tree.
1799 * @inst: the node generating the error
1801 * Process possible xsl:fallback nodes present under @inst
1803 * Returns the number of xsl:fallback element found and processed
1806 xsltApplyFallbacks(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1812 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) ||
1813 (inst
->children
== NULL
))
1816 child
= inst
->children
;
1817 while (child
!= NULL
) {
1818 if ((IS_XSLT_ELEM(child
)) &&
1819 (xmlStrEqual(child
->name
, BAD_CAST
"fallback"))) {
1820 #ifdef WITH_XSLT_DEBUG_PARSING
1821 xsltGenericDebug(xsltGenericDebugContext
,
1822 "applying xsl:fallback\n");
1825 xsltApplySequenceConstructor(ctxt
, node
, child
->children
,
1828 child
= child
->next
;
1833 /************************************************************************
1835 * Default processing *
1837 ************************************************************************/
1840 * xsltDefaultProcessOneNode:
1841 * @ctxt: a XSLT process context
1842 * @node: the node in the source tree.
1843 * @params: extra parameters passed to the template if any
1845 * Process the source node with the default built-in template rule:
1846 * <xsl:template match="*|/">
1847 * <xsl:apply-templates/>
1852 * <xsl:template match="text()|@*">
1853 * <xsl:value-of select="."/>
1856 * Note also that namespace declarations are copied directly:
1858 * the built-in template rule is the only template rule that is applied
1859 * for namespace nodes.
1862 xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1863 xsltStackElemPtr params
) {
1865 xmlNodePtr
delete = NULL
, cur
;
1866 int nbchild
= 0, oldSize
;
1867 int childno
= 0, oldPos
;
1868 xsltTemplatePtr
template;
1872 * Handling of leaves
1874 switch (node
->type
) {
1875 case XML_DOCUMENT_NODE
:
1876 case XML_HTML_DOCUMENT_NODE
:
1877 case XML_ELEMENT_NODE
:
1879 case XML_CDATA_SECTION_NODE
:
1880 #ifdef WITH_XSLT_DEBUG_PROCESS
1881 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1882 "xsltDefaultProcessOneNode: copy CDATA %s\n",
1885 copy
= xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
1887 xsltTransformError(ctxt
, NULL
, node
,
1888 "xsltDefaultProcessOneNode: cdata copy failed\n");
1892 #ifdef WITH_XSLT_DEBUG_PROCESS
1893 if (node
->content
== NULL
) {
1894 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1895 "xsltDefaultProcessOneNode: copy empty text\n"));
1898 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1899 "xsltDefaultProcessOneNode: copy text %s\n",
1903 copy
= xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
1905 xsltTransformError(ctxt
, NULL
, node
,
1906 "xsltDefaultProcessOneNode: text copy failed\n");
1909 case XML_ATTRIBUTE_NODE
:
1910 cur
= node
->children
;
1911 while ((cur
!= NULL
) && (cur
->type
!= XML_TEXT_NODE
))
1914 xsltTransformError(ctxt
, NULL
, node
,
1915 "xsltDefaultProcessOneNode: no text for attribute\n");
1917 #ifdef WITH_XSLT_DEBUG_PROCESS
1918 if (cur
->content
== NULL
) {
1919 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1920 "xsltDefaultProcessOneNode: copy empty text\n"));
1922 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1923 "xsltDefaultProcessOneNode: copy text %s\n",
1927 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
1929 xsltTransformError(ctxt
, NULL
, node
,
1930 "xsltDefaultProcessOneNode: text copy failed\n");
1938 * Handling of Elements: first pass, cleanup and counting
1940 cur
= node
->children
;
1941 while (cur
!= NULL
) {
1942 switch (cur
->type
) {
1944 case XML_CDATA_SECTION_NODE
:
1945 case XML_DOCUMENT_NODE
:
1946 case XML_HTML_DOCUMENT_NODE
:
1947 case XML_ELEMENT_NODE
:
1949 case XML_COMMENT_NODE
:
1953 /* Unlink the DTD, it's still reachable using doc->intSubset */
1954 if (cur
->next
!= NULL
)
1955 cur
->next
->prev
= cur
->prev
;
1956 if (cur
->prev
!= NULL
)
1957 cur
->prev
->next
= cur
->next
;
1960 #ifdef WITH_XSLT_DEBUG_PROCESS
1961 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1962 "xsltDefaultProcessOneNode: skipping node type %d\n",
1968 if (delete != NULL
) {
1969 #ifdef WITH_XSLT_DEBUG_PROCESS
1970 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1971 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1973 xmlUnlinkNode(delete);
1974 xmlFreeNode(delete);
1978 if (delete != NULL
) {
1979 #ifdef WITH_XSLT_DEBUG_PROCESS
1980 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1981 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1983 xmlUnlinkNode(delete);
1984 xmlFreeNode(delete);
1989 * Handling of Elements: second pass, actual processing
1991 oldSize
= ctxt
->xpathCtxt
->contextSize
;
1992 oldPos
= ctxt
->xpathCtxt
->proximityPosition
;
1993 cur
= node
->children
;
1994 while (cur
!= NULL
) {
1996 switch (cur
->type
) {
1997 case XML_DOCUMENT_NODE
:
1998 case XML_HTML_DOCUMENT_NODE
:
1999 case XML_ELEMENT_NODE
:
2000 ctxt
->xpathCtxt
->contextSize
= nbchild
;
2001 ctxt
->xpathCtxt
->proximityPosition
= childno
;
2002 xsltProcessOneNode(ctxt
, cur
, params
);
2004 case XML_CDATA_SECTION_NODE
:
2005 template = xsltGetTemplate(ctxt
, cur
, NULL
);
2007 #ifdef WITH_XSLT_DEBUG_PROCESS
2008 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2009 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
2013 * Instantiate the xsl:template.
2015 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
2017 } else /* if (ctxt->mode == NULL) */ {
2018 #ifdef WITH_XSLT_DEBUG_PROCESS
2019 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2020 "xsltDefaultProcessOneNode: copy CDATA %s\n",
2023 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
2025 xsltTransformError(ctxt
, NULL
, cur
,
2026 "xsltDefaultProcessOneNode: cdata copy failed\n");
2031 template = xsltGetTemplate(ctxt
, cur
, NULL
);
2033 #ifdef WITH_XSLT_DEBUG_PROCESS
2034 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2035 "xsltDefaultProcessOneNode: applying template for text %s\n",
2038 ctxt
->xpathCtxt
->contextSize
= nbchild
;
2039 ctxt
->xpathCtxt
->proximityPosition
= childno
;
2041 * Instantiate the xsl:template.
2043 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
2045 } else /* if (ctxt->mode == NULL) */ {
2046 #ifdef WITH_XSLT_DEBUG_PROCESS
2047 if (cur
->content
== NULL
) {
2048 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2049 "xsltDefaultProcessOneNode: copy empty text\n"));
2051 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2052 "xsltDefaultProcessOneNode: copy text %s\n",
2056 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
2058 xsltTransformError(ctxt
, NULL
, cur
,
2059 "xsltDefaultProcessOneNode: text copy failed\n");
2064 case XML_COMMENT_NODE
:
2065 template = xsltGetTemplate(ctxt
, cur
, NULL
);
2067 #ifdef WITH_XSLT_DEBUG_PROCESS
2068 if (cur
->type
== XML_PI_NODE
) {
2069 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2070 "xsltDefaultProcessOneNode: template found for PI %s\n",
2072 } else if (cur
->type
== XML_COMMENT_NODE
) {
2073 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2074 "xsltDefaultProcessOneNode: template found for comment\n"));
2077 ctxt
->xpathCtxt
->contextSize
= nbchild
;
2078 ctxt
->xpathCtxt
->proximityPosition
= childno
;
2080 * Instantiate the xsl:template.
2082 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
2091 ctxt
->xpathCtxt
->contextSize
= oldSize
;
2092 ctxt
->xpathCtxt
->proximityPosition
= oldPos
;
2096 * xsltProcessOneNode:
2097 * @ctxt: a XSLT process context
2098 * @contextNode: the "current node" in the source tree
2099 * @withParams: extra parameters (e.g. xsl:with-param) passed to the
2102 * Process the source node.
2105 xsltProcessOneNode(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
2106 xsltStackElemPtr withParams
)
2108 xsltTemplatePtr templ
;
2111 templ
= xsltGetTemplate(ctxt
, contextNode
, NULL
);
2113 * If no template is found, apply the default rule.
2115 if (templ
== NULL
) {
2116 #ifdef WITH_XSLT_DEBUG_PROCESS
2117 if (contextNode
->type
== XML_DOCUMENT_NODE
) {
2118 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2119 "xsltProcessOneNode: no template found for /\n"));
2120 } else if (contextNode
->type
== XML_CDATA_SECTION_NODE
) {
2121 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2122 "xsltProcessOneNode: no template found for CDATA\n"));
2123 } else if (contextNode
->type
== XML_ATTRIBUTE_NODE
) {
2124 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2125 "xsltProcessOneNode: no template found for attribute %s\n",
2126 ((xmlAttrPtr
) contextNode
)->name
));
2128 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2129 "xsltProcessOneNode: no template found for %s\n", contextNode
->name
));
2132 oldNode
= ctxt
->node
;
2133 ctxt
->node
= contextNode
;
2134 xsltDefaultProcessOneNode(ctxt
, contextNode
, withParams
);
2135 ctxt
->node
= oldNode
;
2139 if (contextNode
->type
== XML_ATTRIBUTE_NODE
) {
2140 xsltTemplatePtr oldCurTempRule
= ctxt
->currentTemplateRule
;
2142 * Set the "current template rule".
2144 ctxt
->currentTemplateRule
= templ
;
2146 #ifdef WITH_XSLT_DEBUG_PROCESS
2147 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2148 "xsltProcessOneNode: applying template '%s' for attribute %s\n",
2149 templ
->match
, contextNode
->name
));
2151 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
, templ
, withParams
);
2153 ctxt
->currentTemplateRule
= oldCurTempRule
;
2155 xsltTemplatePtr oldCurTempRule
= ctxt
->currentTemplateRule
;
2157 * Set the "current template rule".
2159 ctxt
->currentTemplateRule
= templ
;
2161 #ifdef WITH_XSLT_DEBUG_PROCESS
2162 if (contextNode
->type
== XML_DOCUMENT_NODE
) {
2163 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2164 "xsltProcessOneNode: applying template '%s' for /\n",
2167 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2168 "xsltProcessOneNode: applying template '%s' for %s\n",
2169 templ
->match
, contextNode
->name
));
2172 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
, templ
, withParams
);
2174 ctxt
->currentTemplateRule
= oldCurTempRule
;
2179 xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt
,
2180 xmlNodePtr contextNode
,
2182 xsltTemplatePtr templ
,
2185 xmlNodePtr debugedNode
= NULL
;
2187 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2189 *addCallResult
= xslAddCall(templ
, templ
->elem
);
2191 *addCallResult
= xslAddCall(NULL
, list
);
2193 switch (ctxt
->debugStatus
) {
2194 case XSLT_DEBUG_RUN_RESTART
:
2195 case XSLT_DEBUG_QUIT
:
2201 xslHandleDebugger(templ
->elem
, contextNode
, templ
, ctxt
);
2202 debugedNode
= templ
->elem
;
2204 xslHandleDebugger(list
, contextNode
, templ
, ctxt
);
2206 } else if (ctxt
->inst
) {
2207 xslHandleDebugger(ctxt
->inst
, contextNode
, templ
, ctxt
);
2208 debugedNode
= ctxt
->inst
;
2211 return(debugedNode
);
2215 * xsltLocalVariablePush:
2216 * @ctxt: the transformation context
2217 * @variable: variable to be pushed to the variable stack
2218 * @level: new value for variable's level
2220 * Places the variable onto the local variable stack
2222 * Returns: 0 for success, -1 for any error
2224 * This is an internal routine and should not be called by users!
2227 xsltLocalVariablePush(xsltTransformContextPtr ctxt
,
2228 xsltStackElemPtr variable
,
2231 if (ctxt
->varsMax
== 0) {
2234 (xsltStackElemPtr
*) xmlMalloc(ctxt
->varsMax
*
2235 sizeof(ctxt
->varsTab
[0]));
2236 if (ctxt
->varsTab
== NULL
) {
2237 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
2241 if (ctxt
->varsNr
>= ctxt
->varsMax
) {
2244 (xsltStackElemPtr
*) xmlRealloc(ctxt
->varsTab
,
2246 sizeof(ctxt
->varsTab
[0]));
2247 if (ctxt
->varsTab
== NULL
) {
2248 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
2252 ctxt
->varsTab
[ctxt
->varsNr
++] = variable
;
2253 ctxt
->vars
= variable
;
2254 variable
->level
= level
;
2259 * xsltReleaseLocalRVTs:
2261 * Fragments which are results of extension instructions
2262 * are preserved; all other fragments are freed/cached.
2265 xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt
, xmlDocPtr base
)
2267 xmlDocPtr cur
= ctxt
->localRVT
, tmp
;
2269 while ((cur
!= NULL
) && (cur
!= base
)) {
2270 if (cur
->psvi
== (void *) ((long) 1)) {
2271 cur
= (xmlDocPtr
) cur
->next
;
2274 cur
= (xmlDocPtr
) cur
->next
;
2276 if (tmp
== ctxt
->localRVT
)
2277 ctxt
->localRVT
= cur
;
2280 * We need ctxt->localRVTBase for extension instructions
2281 * which return values (like EXSLT's function).
2283 if (tmp
== ctxt
->localRVTBase
)
2284 ctxt
->localRVTBase
= cur
;
2287 tmp
->prev
->next
= (xmlNodePtr
) cur
;
2289 cur
->prev
= tmp
->prev
;
2290 xsltReleaseRVT(ctxt
, tmp
);
2296 * xsltApplySequenceConstructor:
2297 * @ctxt: a XSLT process context
2298 * @contextNode: the "current node" in the source tree
2299 * @list: the nodes of a sequence constructor;
2300 * (plus leading xsl:param elements)
2301 * @templ: the compiled xsl:template (optional)
2303 * Processes a sequence constructor.
2305 * NOTE: ctxt->currentTemplateRule was introduced to reflect the
2306 * semantics of "current template rule". I.e. the field ctxt->templ
2307 * is not intended to reflect this, thus always pushed onto the
2311 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt
,
2312 xmlNodePtr contextNode
, xmlNodePtr list
,
2313 xsltTemplatePtr templ
)
2315 xmlNodePtr oldInsert
, oldInst
, oldCurInst
, oldContextNode
;
2316 xmlNodePtr cur
, insert
, copy
= NULL
;
2317 int level
= 0, oldVarsNr
;
2318 xmlDocPtr oldLocalFragmentTop
, oldLocalFragmentBase
;
2320 #ifdef XSLT_REFACTORED
2321 xsltStylePreCompPtr info
;
2324 #ifdef WITH_DEBUGGER
2325 int addCallResult
= 0;
2326 xmlNodePtr debuggedNode
= NULL
;
2332 #ifdef WITH_DEBUGGER
2333 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2335 xsltDebuggerStartSequenceConstructor(ctxt
, contextNode
,
2336 list
, templ
, &addCallResult
);
2337 if (debuggedNode
== NULL
)
2346 oldLocalFragmentTop
= ctxt
->localRVT
;
2347 oldInsert
= insert
= ctxt
->insert
;
2348 oldInst
= oldCurInst
= ctxt
->inst
;
2349 oldContextNode
= ctxt
->node
;
2351 * Save current number of variables on the stack; new vars are popped when
2354 oldVarsNr
= ctxt
->varsNr
;
2356 * Process the sequence constructor.
2359 while (cur
!= NULL
) {
2362 #ifdef WITH_DEBUGGER
2363 switch (ctxt
->debugStatus
) {
2364 case XSLT_DEBUG_RUN_RESTART
:
2365 case XSLT_DEBUG_QUIT
:
2371 * Test; we must have a valid insertion point.
2373 if (insert
== NULL
) {
2375 #ifdef WITH_XSLT_DEBUG_PROCESS
2376 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2377 "xsltApplySequenceConstructor: insert == NULL !\n"));
2382 #ifdef WITH_DEBUGGER
2383 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (debuggedNode
!= cur
))
2384 xslHandleDebugger(cur
, contextNode
, templ
, ctxt
);
2387 #ifdef XSLT_REFACTORED
2388 if (cur
->type
== XML_ELEMENT_NODE
) {
2389 info
= (xsltStylePreCompPtr
) cur
->psvi
;
2391 * We expect a compiled representation on:
2392 * 1) XSLT instructions of this XSLT version (1.0)
2393 * (with a few exceptions)
2394 * 2) Literal result elements
2395 * 3) Extension instructions
2396 * 4) XSLT instructions of future XSLT versions
2397 * (forwards-compatible mode).
2401 * Handle the rare cases where we don't expect a compiled
2402 * representation on an XSLT element.
2404 if (IS_XSLT_ELEM_FAST(cur
) && IS_XSLT_NAME(cur
, "message")) {
2405 xsltMessage(ctxt
, contextNode
, cur
);
2409 * Something really went wrong:
2411 xsltTransformError(ctxt
, NULL
, cur
,
2412 "Internal error in xsltApplySequenceConstructor(): "
2413 "The element '%s' in the stylesheet has no compiled "
2414 "representation.\n",
2419 if (info
->type
== XSLT_FUNC_LITERAL_RESULT_ELEMENT
) {
2420 xsltStyleItemLRElementInfoPtr lrInfo
=
2421 (xsltStyleItemLRElementInfoPtr
) info
;
2423 * Literal result elements
2424 * --------------------------------------------------------
2426 #ifdef WITH_XSLT_DEBUG_PROCESS
2427 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2428 xsltGenericDebug(xsltGenericDebugContext
,
2429 "xsltApplySequenceConstructor: copy literal result "
2430 "element '%s'\n", cur
->name
));
2433 * Copy the raw element-node.
2434 * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2438 copy
= xmlDocCopyNode(cur
, insert
->doc
, 0);
2440 xsltTransformError(ctxt
, NULL
, cur
,
2441 "Internal error in xsltApplySequenceConstructor(): "
2442 "Failed to copy literal result element '%s'.\n",
2447 * Add the element-node to the result tree.
2449 copy
->doc
= ctxt
->output
;
2450 copy
= xsltAddChild(insert
, copy
);
2452 * Create effective namespaces declarations.
2453 * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2455 if (lrInfo
->effectiveNs
!= NULL
) {
2456 xsltEffectiveNsPtr effNs
= lrInfo
->effectiveNs
;
2457 xmlNsPtr ns
, lastns
= NULL
;
2459 while (effNs
!= NULL
) {
2461 * Avoid generating redundant namespace
2462 * declarations; thus lookup if there is already
2463 * such a ns-decl in the result.
2465 ns
= xmlSearchNs(copy
->doc
, copy
, effNs
->prefix
);
2467 (xmlStrEqual(ns
->href
, effNs
->nsName
)))
2469 effNs
= effNs
->next
;
2472 ns
= xmlNewNs(copy
, effNs
->nsName
, effNs
->prefix
);
2474 xsltTransformError(ctxt
, NULL
, cur
,
2475 "Internal error in "
2476 "xsltApplySequenceConstructor(): "
2477 "Failed to copy a namespace "
2488 effNs
= effNs
->next
;
2493 * NOTE that we don't need to apply ns-alising: this was
2494 * already done at compile-time.
2496 if (cur
->ns
!= NULL
) {
2498 * If there's no such ns-decl in the result tree,
2499 * then xsltGetSpecialNamespace() will
2500 * create a ns-decl on the copied node.
2502 copy
->ns
= xsltGetSpecialNamespace(ctxt
, cur
,
2503 cur
->ns
->href
, cur
->ns
->prefix
, copy
);
2506 * Undeclare the default namespace if needed.
2507 * This can be skipped, if the result element has
2508 * no ns-decls, in which case the result element
2509 * obviously does not declare a default namespace;
2510 * AND there's either no parent, or the parent
2511 * element is in no namespace; this means there's no
2512 * default namespace is scope to care about.
2514 * REVISIT: This might result in massive
2515 * generation of ns-decls if nodes in a default
2516 * namespaces are mixed with nodes in no namespace.
2520 ((insert
!= NULL
) &&
2521 (insert
->type
== XML_ELEMENT_NODE
) &&
2522 (insert
->ns
!= NULL
)))
2524 xsltGetSpecialNamespace(ctxt
, cur
,
2530 * SPEC XSLT 2.0 "Each attribute of the literal result
2531 * element, other than an attribute in the XSLT namespace,
2532 * is processed to produce an attribute for the element in
2534 * NOTE: See bug #341325.
2536 if (cur
->properties
!= NULL
) {
2537 xsltAttrListTemplateProcess(ctxt
, copy
, cur
->properties
);
2539 } else if (IS_XSLT_ELEM_FAST(cur
)) {
2542 * --------------------------------------------------------
2544 if (info
->type
== XSLT_FUNC_UNKOWN_FORWARDS_COMPAT
) {
2546 * We hit an unknown XSLT element.
2547 * Try to apply one of the fallback cases.
2549 ctxt
->insert
= insert
;
2550 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2551 xsltTransformError(ctxt
, NULL
, cur
,
2552 "The is no fallback behaviour defined for "
2553 "the unknown XSLT element '%s'.\n",
2556 ctxt
->insert
= oldInsert
;
2557 } else if (info
->func
!= NULL
) {
2559 * Execute the XSLT instruction.
2561 ctxt
->insert
= insert
;
2563 info
->func(ctxt
, contextNode
, cur
,
2564 (xsltElemPreCompPtr
) info
);
2567 * Cleanup temporary tree fragments.
2569 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2570 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2572 ctxt
->insert
= oldInsert
;
2573 } else if (info
->type
== XSLT_FUNC_VARIABLE
) {
2574 xsltStackElemPtr tmpvar
= ctxt
->vars
;
2576 xsltParseStylesheetVariable(ctxt
, cur
);
2578 if (tmpvar
!= ctxt
->vars
) {
2580 * TODO: Using a @tmpvar is an annoying workaround, but
2581 * the current mechanisms do not provide any other way
2582 * of knowing if the var was really pushed onto the
2585 ctxt
->vars
->level
= level
;
2587 } else if (info
->type
== XSLT_FUNC_MESSAGE
) {
2589 * TODO: Won't be hit, since we don't compile xsl:message.
2591 xsltMessage(ctxt
, contextNode
, cur
);
2593 xsltTransformError(ctxt
, NULL
, cur
,
2594 "Unexpected XSLT element '%s'.\n", cur
->name
);
2599 xsltTransformFunction func
;
2601 * Extension intructions (elements)
2602 * --------------------------------------------------------
2604 if (cur
->psvi
== xsltExtMarker
) {
2606 * The xsltExtMarker was set during the compilation
2607 * of extension instructions if there was no registered
2608 * handler for this specific extension function at
2610 * Libxslt will now lookup if a handler is
2611 * registered in the context of this transformation.
2613 func
= (xsltTransformFunction
)
2614 xsltExtElementLookup(ctxt
, cur
->name
, cur
->ns
->href
);
2616 func
= ((xsltElemPreCompPtr
) cur
->psvi
)->func
;
2620 * No handler available.
2621 * Try to execute fallback behaviour via xsl:fallback.
2623 #ifdef WITH_XSLT_DEBUG_PROCESS
2624 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2625 xsltGenericDebug(xsltGenericDebugContext
,
2626 "xsltApplySequenceConstructor: unknown extension %s\n",
2629 ctxt
->insert
= insert
;
2630 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2631 xsltTransformError(ctxt
, NULL
, cur
,
2632 "Unknown extension instruction '{%s}%s'.\n",
2633 cur
->ns
->href
, cur
->name
);
2635 ctxt
->insert
= oldInsert
;
2638 * Execute the handler-callback.
2640 #ifdef WITH_XSLT_DEBUG_PROCESS
2641 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2642 "xsltApplySequenceConstructor: extension construct %s\n",
2645 ctxt
->insert
= insert
;
2647 * We need the fragment base for extension instructions
2648 * which return values (like EXSLT's function).
2650 oldLocalFragmentBase
= ctxt
->localRVTBase
;
2651 ctxt
->localRVTBase
= NULL
;
2653 func(ctxt
, contextNode
, cur
, cur
->psvi
);
2655 ctxt
->localRVTBase
= oldLocalFragmentBase
;
2657 * Cleanup temporary tree fragments.
2659 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2660 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2662 ctxt
->insert
= oldInsert
;
2667 } else if (XSLT_IS_TEXT_NODE(cur
)) {
2670 * ------------------------------------------------------------
2672 #ifdef WITH_XSLT_DEBUG_PROCESS
2673 if (cur
->name
== xmlStringTextNoenc
) {
2674 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2675 xsltGenericDebug(xsltGenericDebugContext
,
2676 "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2679 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2680 xsltGenericDebug(xsltGenericDebugContext
,
2681 "xsltApplySequenceConstructor: copy text '%s'\n",
2685 if (xsltCopyText(ctxt
, insert
, cur
, ctxt
->internalized
) == NULL
)
2689 #else /* XSLT_REFACTORED */
2691 if (IS_XSLT_ELEM(cur
)) {
2693 * This is an XSLT node
2695 xsltStylePreCompPtr info
= (xsltStylePreCompPtr
) cur
->psvi
;
2698 if (IS_XSLT_NAME(cur
, "message")) {
2699 xsltMessage(ctxt
, contextNode
, cur
);
2702 * That's an error try to apply one of the fallback cases
2704 ctxt
->insert
= insert
;
2705 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2706 xsltGenericError(xsltGenericErrorContext
,
2707 "xsltApplySequenceConstructor: %s was not compiled\n",
2710 ctxt
->insert
= oldInsert
;
2715 if (info
->func
!= NULL
) {
2716 oldCurInst
= ctxt
->inst
;
2718 ctxt
->insert
= insert
;
2719 oldLocalFragmentBase
= ctxt
->localRVTBase
;
2720 ctxt
->localRVTBase
= NULL
;
2722 info
->func(ctxt
, contextNode
, cur
, (xsltElemPreCompPtr
) info
);
2724 ctxt
->localRVTBase
= oldLocalFragmentBase
;
2726 * Cleanup temporary tree fragments.
2728 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2729 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2731 ctxt
->insert
= oldInsert
;
2732 ctxt
->inst
= oldCurInst
;
2736 if (IS_XSLT_NAME(cur
, "variable")) {
2737 xsltStackElemPtr tmpvar
= ctxt
->vars
;
2739 oldCurInst
= ctxt
->inst
;
2742 xsltParseStylesheetVariable(ctxt
, cur
);
2744 ctxt
->inst
= oldCurInst
;
2746 if (tmpvar
!= ctxt
->vars
) {
2748 * TODO: Using a @tmpvar is an annoying workaround, but
2749 * the current mechanisms do not provide any other way
2750 * of knowing if the var was really pushed onto the
2753 ctxt
->vars
->level
= level
;
2755 } else if (IS_XSLT_NAME(cur
, "message")) {
2756 xsltMessage(ctxt
, contextNode
, cur
);
2758 xsltTransformError(ctxt
, NULL
, cur
,
2759 "Unexpected XSLT element '%s'.\n", cur
->name
);
2762 } else if ((cur
->type
== XML_TEXT_NODE
) ||
2763 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
2766 * This text comes from the stylesheet
2767 * For stylesheets, the set of whitespace-preserving
2768 * element names consists of just xsl:text.
2770 #ifdef WITH_XSLT_DEBUG_PROCESS
2771 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
2772 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2773 "xsltApplySequenceConstructor: copy CDATA text %s\n",
2775 } else if (cur
->name
== xmlStringTextNoenc
) {
2776 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2777 "xsltApplySequenceConstructor: copy unescaped text %s\n",
2780 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2781 "xsltApplySequenceConstructor: copy text %s\n",
2785 if (xsltCopyText(ctxt
, insert
, cur
, ctxt
->internalized
) == NULL
)
2787 } else if ((cur
->type
== XML_ELEMENT_NODE
) &&
2788 (cur
->ns
!= NULL
) && (cur
->psvi
!= NULL
)) {
2789 xsltTransformFunction function
;
2791 oldCurInst
= ctxt
->inst
;
2794 * Flagged as an extension element
2796 if (cur
->psvi
== xsltExtMarker
)
2797 function
= (xsltTransformFunction
)
2798 xsltExtElementLookup(ctxt
, cur
->name
, cur
->ns
->href
);
2800 function
= ((xsltElemPreCompPtr
) cur
->psvi
)->func
;
2802 if (function
== NULL
) {
2806 #ifdef WITH_XSLT_DEBUG_PROCESS
2807 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2808 "xsltApplySequenceConstructor: unknown extension %s\n",
2812 * Search if there are fallbacks
2814 child
= cur
->children
;
2815 while (child
!= NULL
) {
2816 if ((IS_XSLT_ELEM(child
)) &&
2817 (IS_XSLT_NAME(child
, "fallback")))
2820 xsltApplySequenceConstructor(ctxt
, contextNode
,
2821 child
->children
, NULL
);
2823 child
= child
->next
;
2827 xsltTransformError(ctxt
, NULL
, cur
,
2828 "xsltApplySequenceConstructor: failed to find extension %s\n",
2832 #ifdef WITH_XSLT_DEBUG_PROCESS
2833 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2834 "xsltApplySequenceConstructor: extension construct %s\n",
2838 ctxt
->insert
= insert
;
2840 * We need the fragment base for extension instructions
2841 * which return values (like EXSLT's function).
2843 oldLocalFragmentBase
= ctxt
->localRVTBase
;
2844 ctxt
->localRVTBase
= NULL
;
2846 function(ctxt
, contextNode
, cur
, cur
->psvi
);
2848 * Cleanup temporary tree fragments.
2850 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2851 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2853 ctxt
->localRVTBase
= oldLocalFragmentBase
;
2854 ctxt
->insert
= oldInsert
;
2857 ctxt
->inst
= oldCurInst
;
2859 } else if (cur
->type
== XML_ELEMENT_NODE
) {
2860 #ifdef WITH_XSLT_DEBUG_PROCESS
2861 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2862 "xsltApplySequenceConstructor: copy node %s\n",
2865 oldCurInst
= ctxt
->inst
;
2868 if ((copy
= xsltShallowCopyElem(ctxt
, cur
, insert
, 1)) == NULL
)
2871 * Add extra namespaces inherited from the current template
2872 * if we are in the first level children and this is a
2875 if ((templ
!= NULL
) && (oldInsert
== insert
) &&
2876 (ctxt
->templ
!= NULL
) && (ctxt
->templ
->inheritedNs
!= NULL
)) {
2880 for (i
= 0; i
< ctxt
->templ
->inheritedNsNr
; i
++) {
2881 const xmlChar
*URI
= NULL
;
2882 xsltStylesheetPtr style
;
2883 ns
= ctxt
->templ
->inheritedNs
[i
];
2885 /* Note that the XSLT namespace was already excluded
2886 * in xsltGetInheritedNsList().
2889 if (xmlStrEqual(ns
->href
, XSLT_NAMESPACE
))
2892 style
= ctxt
->style
;
2893 while (style
!= NULL
) {
2894 if (style
->nsAliases
!= NULL
)
2895 URI
= (const xmlChar
*)
2896 xmlHashLookup(style
->nsAliases
, ns
->href
);
2900 style
= xsltNextImport(style
);
2902 if (URI
== UNDEFINED_DEFAULT_NS
)
2907 * TODO: The following will still be buggy for the
2908 * non-refactored code.
2910 ret
= xmlSearchNs(copy
->doc
, copy
, ns
->prefix
);
2911 if ((ret
== NULL
) || (!xmlStrEqual(ret
->href
, URI
)))
2913 xmlNewNs(copy
, URI
, ns
->prefix
);
2916 if (copy
->ns
!= NULL
) {
2918 * Fix the node namespace if needed
2920 copy
->ns
= xsltGetNamespace(ctxt
, cur
, copy
->ns
, copy
);
2924 * all the attributes are directly inherited
2926 if (cur
->properties
!= NULL
) {
2927 xsltAttrListTemplateProcess(ctxt
, copy
, cur
->properties
);
2929 ctxt
->inst
= oldCurInst
;
2931 #endif /* else of XSLT_REFACTORED */
2934 * Descend into content in document order.
2936 if (cur
->children
!= NULL
) {
2937 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
2938 cur
= cur
->children
;
2948 * If xslt:message was just processed, we might have hit a
2949 * terminate='yes'; if so, then break the loop and clean up.
2950 * TODO: Do we need to check this also before trying to descend
2953 if (ctxt
->state
== XSLT_STATE_STOPPED
)
2955 if (cur
->next
!= NULL
) {
2964 * Pop variables/params (xsl:variable and xsl:param).
2966 if ((ctxt
->varsNr
> oldVarsNr
) && (ctxt
->vars
->level
> level
)) {
2967 xsltLocalVariablePop(ctxt
, oldVarsNr
, level
);
2970 insert
= insert
->parent
;
2973 if (cur
== list
->parent
) {
2977 if (cur
->next
!= NULL
) {
2981 } while (cur
!= NULL
);
2986 * In case of errors: pop remaining variables.
2988 if (ctxt
->varsNr
> oldVarsNr
)
2989 xsltLocalVariablePop(ctxt
, oldVarsNr
, -1);
2991 ctxt
->node
= oldContextNode
;
2992 ctxt
->inst
= oldInst
;
2993 ctxt
->insert
= oldInsert
;
2995 #ifdef WITH_DEBUGGER
2996 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (addCallResult
)) {
3003 * xsltApplyXSLTTemplate:
3004 * @ctxt: a XSLT transformation context
3005 * @contextNode: the node in the source tree.
3006 * @list: the nodes of a sequence constructor;
3007 * (plus leading xsl:param elements)
3008 * @templ: the compiled xsl:template declaration;
3009 * NULL if a sequence constructor
3010 * @withParams: a set of caller-parameters (xsl:with-param) or NULL
3013 * - xsltApplyImports()
3014 * - xsltCallTemplate()
3015 * - xsltDefaultProcessOneNode()
3016 * - xsltProcessOneNode()
3019 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt
,
3020 xmlNodePtr contextNode
,
3022 xsltTemplatePtr templ
,
3023 xsltStackElemPtr withParams
)
3025 int oldVarsBase
= 0;
3028 xsltStackElemPtr tmpParam
= NULL
;
3029 xmlDocPtr oldUserFragmentTop
, oldLocalFragmentTop
;
3031 #ifdef XSLT_REFACTORED
3032 xsltStyleItemParamPtr iparam
;
3034 xsltStylePreCompPtr iparam
;
3037 #ifdef WITH_DEBUGGER
3038 int addCallResult
= 0;
3043 if (templ
== NULL
) {
3044 xsltTransformError(ctxt
, NULL
, list
,
3045 "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
3049 #ifdef WITH_DEBUGGER
3050 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
3051 if (xsltDebuggerStartSequenceConstructor(ctxt
, contextNode
,
3052 list
, templ
, &addCallResult
) == NULL
)
3062 * Check for infinite recursion: stop if the maximum of nested templates
3063 * is excceeded. Adjust xsltMaxDepth if you need more.
3065 if (ctxt
->templNr
>= ctxt
->maxTemplateDepth
)
3067 xsltTransformError(ctxt
, NULL
, list
,
3068 "xsltApplyXSLTTemplate: A potential infinite template recursion "
3070 "You can adjust xsltMaxDepth (--maxdepth) in order to "
3071 "raise the maximum number of nested template calls and "
3072 "variables/params (currently set to %d).\n",
3073 ctxt
->maxTemplateDepth
);
3074 xsltDebug(ctxt
, contextNode
, list
, NULL
);
3078 if (ctxt
->varsNr
>= ctxt
->maxTemplateVars
)
3080 xsltTransformError(ctxt
, NULL
, list
,
3081 "xsltApplyXSLTTemplate: A potential infinite template recursion "
3083 "You can adjust maxTemplateVars (--maxvars) in order to "
3084 "raise the maximum number of variables/params (currently set to %d).\n",
3085 ctxt
->maxTemplateVars
);
3086 xsltDebug(ctxt
, contextNode
, list
, NULL
);
3090 oldUserFragmentTop
= ctxt
->tmpRVT
;
3091 ctxt
->tmpRVT
= NULL
;
3092 oldLocalFragmentTop
= ctxt
->localRVT
;
3095 * Initiate a distinct scope of local params/variables.
3097 oldVarsBase
= ctxt
->varsBase
;
3098 ctxt
->varsBase
= ctxt
->varsNr
;
3100 ctxt
->node
= contextNode
;
3101 if (ctxt
->profile
) {
3103 start
= xsltTimestamp();
3105 profCallgraphAdd(templ
, ctxt
->templ
);
3108 * Push the xsl:template declaration onto the stack.
3110 templPush(ctxt
, templ
);
3112 #ifdef WITH_XSLT_DEBUG_PROCESS
3113 if (templ
->name
!= NULL
)
3114 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
3115 "applying xsl:template '%s'\n", templ
->name
));
3118 * Process xsl:param instructions and skip those elements for
3119 * further processing.
3123 if (cur
->type
== XML_TEXT_NODE
) {
3127 if ((cur
->type
!= XML_ELEMENT_NODE
) ||
3128 (cur
->name
[0] != 'p') ||
3129 (cur
->psvi
== NULL
) ||
3130 (! xmlStrEqual(cur
->name
, BAD_CAST
"param")) ||
3131 (! IS_XSLT_ELEM(cur
)))
3138 #ifdef XSLT_REFACTORED
3139 iparam
= (xsltStyleItemParamPtr
) cur
->psvi
;
3141 iparam
= (xsltStylePreCompPtr
) cur
->psvi
;
3145 * Substitute xsl:param for a given xsl:with-param.
3146 * Since the XPath expression will reference the params/vars
3147 * by index, we need to slot the xsl:with-params in the
3148 * order of encountered xsl:params to keep the sequence of
3149 * params/variables in the stack exactly as it was at
3154 tmpParam
= withParams
;
3156 if ((tmpParam
->name
== (iparam
->name
)) &&
3157 (tmpParam
->nameURI
== (iparam
->ns
)))
3160 * Push the caller-parameter.
3162 xsltLocalVariablePush(ctxt
, tmpParam
, -1);
3165 tmpParam
= tmpParam
->next
;
3166 } while (tmpParam
!= NULL
);
3169 * Push the xsl:param.
3171 if (tmpParam
== NULL
) {
3173 * Note that we must assume that the added parameter
3174 * has a @depth of 0.
3176 xsltParseStylesheetParam(ctxt
, cur
);
3179 } while (cur
!= NULL
);
3181 * Process the sequence constructor.
3183 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3186 * Remove remaining xsl:param and xsl:with-param items from
3187 * the stack. Don't free xsl:with-param items.
3189 if (ctxt
->varsNr
> ctxt
->varsBase
)
3190 xsltTemplateParamsCleanup(ctxt
);
3191 ctxt
->varsBase
= oldVarsBase
;
3194 * Clean up remaining local tree fragments.
3195 * This also frees fragments which are the result of
3196 * extension instructions. Should normally not be hit; but
3197 * just for the case xsltExtensionInstructionResultFinalize()
3198 * was not called by the extension author.
3200 if (oldLocalFragmentTop
!= ctxt
->localRVT
) {
3201 xmlDocPtr curdoc
= ctxt
->localRVT
, tmp
;
3205 curdoc
= (xmlDocPtr
) curdoc
->next
;
3206 /* Need to housekeep localRVTBase */
3207 if (tmp
== ctxt
->localRVTBase
)
3208 ctxt
->localRVTBase
= curdoc
;
3210 tmp
->prev
->next
= (xmlNodePtr
) curdoc
;
3212 curdoc
->prev
= tmp
->prev
;
3213 xsltReleaseRVT(ctxt
, tmp
);
3214 } while (curdoc
!= oldLocalFragmentTop
);
3216 ctxt
->localRVT
= oldLocalFragmentTop
;
3219 * Release user-created fragments stored in the scope
3220 * of xsl:template. Note that this mechanism is deprecated:
3221 * user code should now use xsltRegisterLocalRVT() instead
3222 * of the obsolete xsltRegisterTmpRVT().
3225 xmlDocPtr curdoc
= ctxt
->tmpRVT
, tmp
;
3227 while (curdoc
!= NULL
) {
3229 curdoc
= (xmlDocPtr
) curdoc
->next
;
3230 xsltReleaseRVT(ctxt
, tmp
);
3233 ctxt
->tmpRVT
= oldUserFragmentTop
;
3236 * Pop the xsl:template declaration from the stack.
3239 if (ctxt
->profile
) {
3240 long spent
, child
, total
, end
;
3242 end
= xsltTimestamp();
3243 child
= profPop(ctxt
);
3244 total
= end
- start
;
3245 spent
= total
- child
;
3248 * Not possible unless the original calibration failed
3249 * we can try to correct it on the fly.
3251 xsltCalibrateAdjust(spent
);
3255 templ
->time
+= spent
;
3256 if (ctxt
->profNr
> 0)
3257 ctxt
->profTab
[ctxt
->profNr
- 1] += total
;
3260 #ifdef WITH_DEBUGGER
3261 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (addCallResult
)) {
3269 * xsltApplyOneTemplate:
3270 * @ctxt: a XSLT process context
3271 * @contextNode: the node in the source tree.
3272 * @list: the nodes of a sequence constructor
3274 * @params: a set of parameters (xsl:param) or NULL
3276 * Processes a sequence constructor on the current node in the source tree.
3278 * @params are the already computed variable stack items; this function
3279 * pushes them on the variable stack, and pops them before exiting; it's
3280 * left to the caller to free or reuse @params afterwards. The initial
3281 * states of the variable stack will always be restored before this
3283 * NOTE that this does *not* initiate a new distinct variable scope; i.e.
3284 * variables already on the stack are visible to the process. The caller's
3285 * side needs to start a new variable scope if needed (e.g. in exsl:function).
3287 * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
3288 * provide a @templ); a non-NULL @templ might raise an error in the future.
3290 * BIG NOTE: This function is not intended to process the content of an
3291 * xsl:template; it does not expect xsl:param instructions in @list and
3292 * will report errors if found.
3295 * - xsltEvalVariable() (variables.c)
3296 * - exsltFuncFunctionFunction() (libexsl/functions.c)
3299 xsltApplyOneTemplate(xsltTransformContextPtr ctxt
,
3300 xmlNodePtr contextNode
,
3302 xsltTemplatePtr templ ATTRIBUTE_UNUSED
,
3303 xsltStackElemPtr params
)
3305 if ((ctxt
== NULL
) || (list
== NULL
))
3311 * This code should be obsolete - was previously used
3312 * by libexslt/functions.c, but due to bug 381319 the
3313 * logic there was changed.
3315 int oldVarsNr
= ctxt
->varsNr
;
3318 * Push the given xsl:param(s) onto the variable stack.
3320 while (params
!= NULL
) {
3321 xsltLocalVariablePush(ctxt
, params
, -1);
3322 params
= params
->next
;
3324 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3326 * Pop the given xsl:param(s) from the stack but don't free them.
3328 xsltLocalVariablePop(ctxt
, oldVarsNr
, -2);
3330 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3333 /************************************************************************
3335 * XSLT-1.1 extensions *
3337 ************************************************************************/
3341 * @ctxt: an XSLT processing context
3342 * @node: The current node
3343 * @inst: the instruction in the stylesheet
3344 * @castedComp: precomputed information
3346 * Process an EXSLT/XSLT-1.1 document element
3349 xsltDocumentElem(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3350 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
3352 #ifdef XSLT_REFACTORED
3353 xsltStyleItemDocumentPtr comp
= (xsltStyleItemDocumentPtr
) castedComp
;
3355 xsltStylePreCompPtr comp
= castedComp
;
3357 xsltStylesheetPtr style
= NULL
;
3359 xmlChar
*filename
= NULL
, *prop
, *elements
;
3360 xmlChar
*element
, *end
;
3361 xmlDocPtr res
= NULL
;
3362 xmlDocPtr oldOutput
;
3363 xmlNodePtr oldInsert
, root
;
3364 const char *oldOutputFile
;
3365 xsltOutputType oldType
;
3366 xmlChar
*URL
= NULL
;
3367 const xmlChar
*method
;
3368 const xmlChar
*doctypePublic
;
3369 const xmlChar
*doctypeSystem
;
3370 const xmlChar
*version
;
3371 const xmlChar
*encoding
;
3372 int redirect_write_append
= 0;
3374 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
3377 if (comp
->filename
== NULL
) {
3379 if (xmlStrEqual(inst
->name
, (const xmlChar
*) "output")) {
3381 * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
3382 * (http://icl.com/saxon)
3383 * The @file is in no namespace.
3385 #ifdef WITH_XSLT_DEBUG_EXTRA
3386 xsltGenericDebug(xsltGenericDebugContext
,
3387 "Found saxon:output extension\n");
3389 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3390 (const xmlChar
*) "file",
3391 XSLT_SAXON_NAMESPACE
);
3394 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3395 (const xmlChar
*) "href",
3396 XSLT_SAXON_NAMESPACE
);
3397 } else if (xmlStrEqual(inst
->name
, (const xmlChar
*) "write")) {
3398 #ifdef WITH_XSLT_DEBUG_EXTRA
3399 xsltGenericDebug(xsltGenericDebugContext
,
3400 "Found xalan:write extension\n");
3402 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3405 XSLT_XALAN_NAMESPACE
);
3407 xmlXPathCompExprPtr cmp
;
3411 * Trying to handle bug #59212
3412 * The value of the "select" attribute is an
3414 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
3416 cmp
= xmlXPathCompile(URL
);
3417 val
= xsltEvalXPathString(ctxt
, cmp
);
3418 xmlXPathFreeCompExpr(cmp
);
3423 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3426 XSLT_XALAN_NAMESPACE
);
3428 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3431 XSLT_XALAN_NAMESPACE
);
3432 } else if (xmlStrEqual(inst
->name
, (const xmlChar
*) "document")) {
3433 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3434 (const xmlChar
*) "href",
3439 URL
= xmlStrdup(comp
->filename
);
3443 xsltTransformError(ctxt
, NULL
, inst
,
3444 "xsltDocumentElem: href/URI-Reference not found\n");
3449 * If the computation failed, it's likely that the URL wasn't escaped
3451 filename
= xmlBuildURI(URL
, (const xmlChar
*) ctxt
->outputFile
);
3452 if (filename
== NULL
) {
3455 escURL
=xmlURIEscapeStr(URL
, BAD_CAST
":/.?,");
3456 if (escURL
!= NULL
) {
3457 filename
= xmlBuildURI(escURL
, (const xmlChar
*) ctxt
->outputFile
);
3462 if (filename
== NULL
) {
3463 xsltTransformError(ctxt
, NULL
, inst
,
3464 "xsltDocumentElem: URL computation failed for %s\n",
3471 * Security checking: can we write to this resource
3473 if (ctxt
->sec
!= NULL
) {
3474 ret
= xsltCheckWrite(ctxt
->sec
, ctxt
, filename
);
3476 xsltTransformError(ctxt
, NULL
, inst
,
3477 "xsltDocumentElem: write rights for %s denied\n",
3485 oldOutputFile
= ctxt
->outputFile
;
3486 oldOutput
= ctxt
->output
;
3487 oldInsert
= ctxt
->insert
;
3488 oldType
= ctxt
->type
;
3489 ctxt
->outputFile
= (const char *) filename
;
3491 style
= xsltNewStylesheet();
3492 if (style
== NULL
) {
3493 xsltTransformError(ctxt
, NULL
, inst
,
3494 "xsltDocumentElem: out of memory\n");
3499 * Version described in 1.1 draft allows full parameterization
3502 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3503 (const xmlChar
*) "version",
3506 if (style
->version
!= NULL
)
3507 xmlFree(style
->version
);
3508 style
->version
= prop
;
3510 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3511 (const xmlChar
*) "encoding",
3514 if (style
->encoding
!= NULL
)
3515 xmlFree(style
->encoding
);
3516 style
->encoding
= prop
;
3518 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3519 (const xmlChar
*) "method",
3524 if (style
->method
!= NULL
)
3525 xmlFree(style
->method
);
3526 style
->method
= NULL
;
3527 if (style
->methodURI
!= NULL
)
3528 xmlFree(style
->methodURI
);
3529 style
->methodURI
= NULL
;
3531 URI
= xsltGetQNameURI(inst
, &prop
);
3533 if (style
!= NULL
) style
->errors
++;
3534 } else if (URI
== NULL
) {
3535 if ((xmlStrEqual(prop
, (const xmlChar
*) "xml")) ||
3536 (xmlStrEqual(prop
, (const xmlChar
*) "html")) ||
3537 (xmlStrEqual(prop
, (const xmlChar
*) "text"))) {
3538 style
->method
= prop
;
3540 xsltTransformError(ctxt
, NULL
, inst
,
3541 "invalid value for method: %s\n", prop
);
3542 if (style
!= NULL
) style
->warnings
++;
3545 style
->method
= prop
;
3546 style
->methodURI
= xmlStrdup(URI
);
3549 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3551 "doctype-system", NULL
);
3553 if (style
->doctypeSystem
!= NULL
)
3554 xmlFree(style
->doctypeSystem
);
3555 style
->doctypeSystem
= prop
;
3557 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3559 "doctype-public", NULL
);
3561 if (style
->doctypePublic
!= NULL
)
3562 xmlFree(style
->doctypePublic
);
3563 style
->doctypePublic
= prop
;
3565 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3566 (const xmlChar
*) "standalone",
3569 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3570 style
->standalone
= 1;
3571 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3572 style
->standalone
= 0;
3574 xsltTransformError(ctxt
, NULL
, inst
,
3575 "invalid value for standalone: %s\n",
3577 if (style
!= NULL
) style
->warnings
++;
3582 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3583 (const xmlChar
*) "indent",
3586 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3588 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3591 xsltTransformError(ctxt
, NULL
, inst
,
3592 "invalid value for indent: %s\n", prop
);
3593 if (style
!= NULL
) style
->warnings
++;
3598 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3600 "omit-xml-declaration",
3603 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3604 style
->omitXmlDeclaration
= 1;
3605 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3606 style
->omitXmlDeclaration
= 0;
3608 xsltTransformError(ctxt
, NULL
, inst
,
3609 "invalid value for omit-xml-declaration: %s\n",
3611 if (style
!= NULL
) style
->warnings
++;
3616 elements
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3618 "cdata-section-elements",
3620 if (elements
!= NULL
) {
3621 if (style
->stripSpaces
== NULL
)
3622 style
->stripSpaces
= xmlHashCreate(10);
3623 if (style
->stripSpaces
== NULL
)
3627 while (*element
!= 0) {
3628 while (IS_BLANK_CH(*element
))
3633 while ((*end
!= 0) && (!IS_BLANK_CH(*end
)))
3635 element
= xmlStrndup(element
, end
- element
);
3639 #ifdef WITH_XSLT_DEBUG_PARSING
3640 xsltGenericDebug(xsltGenericDebugContext
,
3641 "add cdata section output element %s\n",
3644 URI
= xsltGetQNameURI(inst
, &element
);
3646 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
3647 (xmlChar
*) "cdata");
3656 * Create a new document tree and process the element template
3658 XSLT_GET_IMPORT_PTR(method
, style
, method
)
3659 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
3660 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
3661 XSLT_GET_IMPORT_PTR(version
, style
, version
)
3662 XSLT_GET_IMPORT_PTR(encoding
, style
, encoding
)
3664 if ((method
!= NULL
) &&
3665 (!xmlStrEqual(method
, (const xmlChar
*) "xml"))) {
3666 if (xmlStrEqual(method
, (const xmlChar
*) "html")) {
3667 ctxt
->type
= XSLT_OUTPUT_HTML
;
3668 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3669 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
3671 if (version
!= NULL
) {
3672 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3673 xsltGetHTMLIDs(version
, &doctypePublic
, &doctypeSystem
);
3676 res
= htmlNewDocNoDtD(doctypeSystem
, doctypePublic
);
3680 res
->dict
= ctxt
->dict
;
3681 xmlDictReference(res
->dict
);
3682 } else if (xmlStrEqual(method
, (const xmlChar
*) "xhtml")) {
3683 xsltTransformError(ctxt
, NULL
, inst
,
3684 "xsltDocumentElem: unsupported method xhtml\n");
3685 ctxt
->type
= XSLT_OUTPUT_HTML
;
3686 res
= htmlNewDocNoDtD(doctypeSystem
, doctypePublic
);
3689 res
->dict
= ctxt
->dict
;
3690 xmlDictReference(res
->dict
);
3691 } else if (xmlStrEqual(method
, (const xmlChar
*) "text")) {
3692 ctxt
->type
= XSLT_OUTPUT_TEXT
;
3693 res
= xmlNewDoc(style
->version
);
3696 res
->dict
= ctxt
->dict
;
3697 xmlDictReference(res
->dict
);
3698 #ifdef WITH_XSLT_DEBUG
3699 xsltGenericDebug(xsltGenericDebugContext
,
3700 "reusing transformation dict for output\n");
3703 xsltTransformError(ctxt
, NULL
, inst
,
3704 "xsltDocumentElem: unsupported method (%s)\n",
3709 ctxt
->type
= XSLT_OUTPUT_XML
;
3710 res
= xmlNewDoc(style
->version
);
3713 res
->dict
= ctxt
->dict
;
3714 xmlDictReference(res
->dict
);
3715 #ifdef WITH_XSLT_DEBUG
3716 xsltGenericDebug(xsltGenericDebugContext
,
3717 "reusing transformation dict for output\n");
3720 res
->charset
= XML_CHAR_ENCODING_UTF8
;
3721 if (encoding
!= NULL
)
3722 res
->encoding
= xmlStrdup(encoding
);
3724 ctxt
->insert
= (xmlNodePtr
) res
;
3725 xsltApplySequenceConstructor(ctxt
, node
, inst
->children
, NULL
);
3728 * Do some post processing work depending on the generated output
3730 root
= xmlDocGetRootElement(res
);
3732 const xmlChar
*doctype
= NULL
;
3734 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
))
3735 doctype
= xmlDictQLookup(ctxt
->dict
, root
->ns
->prefix
, root
->name
);
3736 if (doctype
== NULL
)
3737 doctype
= root
->name
;
3740 * Apply the default selection of the method
3742 if ((method
== NULL
) &&
3743 (root
->ns
== NULL
) &&
3744 (!xmlStrcasecmp(root
->name
, (const xmlChar
*) "html"))) {
3747 tmp
= res
->children
;
3748 while ((tmp
!= NULL
) && (tmp
!= root
)) {
3749 if (tmp
->type
== XML_ELEMENT_NODE
)
3751 if ((tmp
->type
== XML_TEXT_NODE
) && (!xmlIsBlankNode(tmp
)))
3756 ctxt
->type
= XSLT_OUTPUT_HTML
;
3757 res
->type
= XML_HTML_DOCUMENT_NODE
;
3758 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
3759 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
3762 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3763 } else if (version
!= NULL
) {
3764 xsltGetHTMLIDs(version
, &doctypePublic
,
3766 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3768 xmlCreateIntSubset(res
, doctype
,
3776 if (ctxt
->type
== XSLT_OUTPUT_XML
) {
3777 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
3778 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
3779 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3780 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
3787 * Calls to redirect:write also take an optional attribute append.
3788 * Attribute append="true|yes" which will attempt to simply append
3789 * to an existing file instead of always opening a new file. The
3790 * default behavior of always overwriting the file still happens
3791 * if we do not specify append.
3792 * Note that append use will forbid use of remote URI target.
3794 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
, (const xmlChar
*)"append",
3797 if (xmlStrEqual(prop
, (const xmlChar
*) "true") ||
3798 xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3799 style
->omitXmlDeclaration
= 1;
3800 redirect_write_append
= 1;
3802 style
->omitXmlDeclaration
= 0;
3806 if (redirect_write_append
) {
3809 f
= fopen((const char *) filename
, "ab");
3813 ret
= xsltSaveResultToFile(f
, res
, style
);
3817 ret
= xsltSaveResultToFilename((const char *) filename
, res
, style
, 0);
3820 xsltTransformError(ctxt
, NULL
, inst
,
3821 "xsltDocumentElem: unable to save to %s\n",
3823 ctxt
->state
= XSLT_STATE_ERROR
;
3824 #ifdef WITH_XSLT_DEBUG_EXTRA
3826 xsltGenericDebug(xsltGenericDebugContext
,
3827 "Wrote %d bytes to %s\n", ret
, filename
);
3832 ctxt
->output
= oldOutput
;
3833 ctxt
->insert
= oldInsert
;
3834 ctxt
->type
= oldType
;
3835 ctxt
->outputFile
= oldOutputFile
;
3838 if (filename
!= NULL
)
3841 xsltFreeStylesheet(style
);
3846 /************************************************************************
3848 * Most of the XSLT-1.0 transformations *
3850 ************************************************************************/
3854 * @ctxt: a XSLT process context
3855 * @node: the node in the source tree.
3856 * @inst: the xslt sort node
3857 * @comp: precomputed information
3859 * function attached to xsl:sort nodes, but this should not be
3863 xsltSort(xsltTransformContextPtr ctxt
,
3864 xmlNodePtr node ATTRIBUTE_UNUSED
, xmlNodePtr inst
,
3865 xsltStylePreCompPtr comp
) {
3867 xsltTransformError(ctxt
, NULL
, inst
,
3868 "xsl:sort : compilation failed\n");
3871 xsltTransformError(ctxt
, NULL
, inst
,
3872 "xsl:sort : improper use this should not be reached\n");
3877 * @ctxt: an XSLT process context
3878 * @node: the node in the source tree
3879 * @inst: the element node of the XSLT-copy instruction
3880 * @castedComp: computed information of the XSLT-copy instruction
3882 * Execute the XSLT-copy instruction on the source node.
3885 xsltCopy(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3886 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
3888 #ifdef XSLT_REFACTORED
3889 xsltStyleItemCopyPtr comp
= (xsltStyleItemCopyPtr
) castedComp
;
3891 xsltStylePreCompPtr comp
= castedComp
;
3893 xmlNodePtr copy
, oldInsert
;
3895 oldInsert
= ctxt
->insert
;
3896 if (ctxt
->insert
!= NULL
) {
3897 switch (node
->type
) {
3899 case XML_CDATA_SECTION_NODE
:
3901 * This text comes from the stylesheet
3902 * For stylesheets, the set of whitespace-preserving
3903 * element names consists of just xsl:text.
3905 #ifdef WITH_XSLT_DEBUG_PROCESS
3906 if (node
->type
== XML_CDATA_SECTION_NODE
) {
3907 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3908 "xsltCopy: CDATA text %s\n", node
->content
));
3910 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3911 "xsltCopy: text %s\n", node
->content
));
3914 xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
3916 case XML_DOCUMENT_NODE
:
3917 case XML_HTML_DOCUMENT_NODE
:
3919 case XML_ELEMENT_NODE
:
3921 * REVISIT NOTE: The "fake" is a doc-node, not an element node.
3923 * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3927 #ifdef WITH_XSLT_DEBUG_PROCESS
3928 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3929 "xsltCopy: node %s\n", node
->name
));
3931 copy
= xsltShallowCopyElem(ctxt
, node
, ctxt
->insert
, 0);
3932 ctxt
->insert
= copy
;
3933 if (comp
->use
!= NULL
) {
3934 xsltApplyAttributeSet(ctxt
, node
, inst
, comp
->use
);
3937 case XML_ATTRIBUTE_NODE
: {
3938 #ifdef WITH_XSLT_DEBUG_PROCESS
3939 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3940 "xsltCopy: attribute %s\n", node
->name
));
3943 * REVISIT: We could also raise an error if the parent is not
3945 * OPTIMIZE TODO: Can we set the value/children of the
3946 * attribute without an intermediate copy of the string value?
3948 xsltShallowCopyAttr(ctxt
, inst
, ctxt
->insert
, (xmlAttrPtr
) node
);
3952 #ifdef WITH_XSLT_DEBUG_PROCESS
3953 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3954 "xsltCopy: PI %s\n", node
->name
));
3956 copy
= xmlNewDocPI(ctxt
->insert
->doc
, node
->name
,
3958 copy
= xsltAddChild(ctxt
->insert
, copy
);
3960 case XML_COMMENT_NODE
:
3961 #ifdef WITH_XSLT_DEBUG_PROCESS
3962 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3963 "xsltCopy: comment\n"));
3965 copy
= xmlNewComment(node
->content
);
3966 copy
= xsltAddChild(ctxt
->insert
, copy
);
3968 case XML_NAMESPACE_DECL
:
3969 #ifdef WITH_XSLT_DEBUG_PROCESS
3970 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3971 "xsltCopy: namespace declaration\n"));
3973 xsltShallowCopyNsNode(ctxt
, inst
, ctxt
->insert
, (xmlNsPtr
)node
);
3981 switch (node
->type
) {
3982 case XML_DOCUMENT_NODE
:
3983 case XML_HTML_DOCUMENT_NODE
:
3984 case XML_ELEMENT_NODE
:
3985 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, inst
->children
,
3991 ctxt
->insert
= oldInsert
;
3996 * @ctxt: a XSLT process context
3997 * @node: the node in the source tree.
3998 * @inst: the xslt text node
3999 * @comp: precomputed information
4001 * Process the xslt text node on the source node
4004 xsltText(xsltTransformContextPtr ctxt
, xmlNodePtr node ATTRIBUTE_UNUSED
,
4005 xmlNodePtr inst
, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED
) {
4006 if ((inst
->children
!= NULL
) && (comp
!= NULL
)) {
4007 xmlNodePtr text
= inst
->children
;
4010 while (text
!= NULL
) {
4011 if ((text
->type
!= XML_TEXT_NODE
) &&
4012 (text
->type
!= XML_CDATA_SECTION_NODE
)) {
4013 xsltTransformError(ctxt
, NULL
, inst
,
4014 "xsl:text content problem\n");
4017 copy
= xmlNewDocText(ctxt
->output
, text
->content
);
4018 if (text
->type
!= XML_CDATA_SECTION_NODE
) {
4019 #ifdef WITH_XSLT_DEBUG_PARSING
4020 xsltGenericDebug(xsltGenericDebugContext
,
4021 "Disable escaping: %s\n", text
->content
);
4023 copy
->name
= xmlStringTextNoenc
;
4025 copy
= xsltAddChild(ctxt
->insert
, copy
);
4033 * @ctxt: a XSLT process context
4034 * @node: the node in the source tree.
4035 * @inst: the xslt element node
4036 * @castedComp: precomputed information
4038 * Process the xslt element node on the source node
4041 xsltElement(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4042 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
) {
4043 #ifdef XSLT_REFACTORED
4044 xsltStyleItemElementPtr comp
= (xsltStyleItemElementPtr
) castedComp
;
4046 xsltStylePreCompPtr comp
= castedComp
;
4048 xmlChar
*prop
= NULL
;
4049 const xmlChar
*name
, *prefix
= NULL
, *nsName
= NULL
;
4051 xmlNodePtr oldInsert
;
4053 if (ctxt
->insert
== NULL
)
4057 * A comp->has_name == 0 indicates that we need to skip this instruction,
4058 * since it was evaluated to be invalid already during compilation.
4060 if (!comp
->has_name
)
4066 oldInsert
= ctxt
->insert
;
4068 if (comp
->name
== NULL
) {
4069 /* TODO: fix attr acquisition wrt to the XSLT namespace */
4070 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4071 (const xmlChar
*) "name", XSLT_NAMESPACE
);
4073 xsltTransformError(ctxt
, NULL
, inst
,
4074 "xsl:element: The attribute 'name' is missing.\n");
4077 if (xmlValidateQName(prop
, 0)) {
4078 xsltTransformError(ctxt
, NULL
, inst
,
4079 "xsl:element: The effective name '%s' is not a "
4080 "valid QName.\n", prop
);
4081 /* we fall through to catch any further errors, if possible */
4083 name
= xsltSplitQName(ctxt
->dict
, prop
, &prefix
);
4087 * The "name" value was static.
4089 #ifdef XSLT_REFACTORED
4090 prefix
= comp
->nsPrefix
;
4093 name
= xsltSplitQName(ctxt
->dict
, comp
->name
, &prefix
);
4098 * Create the new element
4100 if (ctxt
->output
->dict
== ctxt
->dict
) {
4101 copy
= xmlNewDocNodeEatName(ctxt
->output
, NULL
, (xmlChar
*)name
, NULL
);
4103 copy
= xmlNewDocNode(ctxt
->output
, NULL
, (xmlChar
*)name
, NULL
);
4106 xsltTransformError(ctxt
, NULL
, inst
,
4107 "xsl:element : creation of %s failed\n", name
);
4110 copy
= xsltAddChild(ctxt
->insert
, copy
);
4112 xsltTransformError(ctxt
, NULL
, inst
,
4113 "xsl:element : xsltAddChild failed\n");
4122 if (comp
->ns
!= NULL
) {
4124 * No AVT; just plain text for the namespace name.
4126 if (comp
->ns
[0] != 0)
4133 /* TODO: check attr acquisition wrt to the XSLT namespace */
4134 tmpNsName
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4135 (const xmlChar
*) "namespace", XSLT_NAMESPACE
);
4138 * "If the string is empty, then the expanded-name of the
4139 * attribute has a null namespace URI."
4141 if ((tmpNsName
!= NULL
) && (tmpNsName
[0] != 0))
4142 nsName
= xmlDictLookup(ctxt
->dict
, BAD_CAST tmpNsName
, -1);
4146 if (xmlStrEqual(nsName
, BAD_CAST
"http://www.w3.org/2000/xmlns/")) {
4147 xsltTransformError(ctxt
, NULL
, inst
,
4148 "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
4152 if (xmlStrEqual(nsName
, XML_XML_NAMESPACE
)) {
4153 prefix
= BAD_CAST
"xml";
4154 } else if (xmlStrEqual(prefix
, BAD_CAST
"xml")) {
4161 * "If the namespace attribute is not present, then the QName is
4162 * expanded into an expanded-name using the namespace declarations
4163 * in effect for the xsl:element element, including any default
4164 * namespace declaration.
4166 ns
= xmlSearchNs(inst
->doc
, inst
, prefix
);
4169 * TODO: Check this in the compilation layer in case it's a
4172 if (prefix
!= NULL
) {
4173 xsltTransformError(ctxt
, NULL
, inst
,
4174 "xsl:element: The QName '%s:%s' has no "
4175 "namespace binding in scope in the stylesheet; "
4176 "this is an error, since the namespace was not "
4177 "specified by the instruction itself.\n", prefix
, name
);
4183 * Find/create a matching ns-decl in the result tree.
4185 if (nsName
!= NULL
) {
4186 if (xmlStrEqual(prefix
, BAD_CAST
"xmlns")) {
4187 /* Don't use a prefix of "xmlns" */
4188 xmlChar
*pref
= xmlStrdup(BAD_CAST
"ns_1");
4190 copy
->ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, pref
, copy
);
4194 copy
->ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, prefix
,
4197 } else if ((copy
->parent
!= NULL
) &&
4198 (copy
->parent
->type
== XML_ELEMENT_NODE
) &&
4199 (copy
->parent
->ns
!= NULL
))
4202 * "Undeclare" the default namespace.
4204 xsltGetSpecialNamespace(ctxt
, inst
, NULL
, NULL
, copy
);
4207 ctxt
->insert
= copy
;
4209 if (comp
->has_use
) {
4210 if (comp
->use
!= NULL
) {
4211 xsltApplyAttributeSet(ctxt
, node
, inst
, comp
->use
);
4213 xmlChar
*attrSets
= NULL
;
4215 * BUG TODO: use-attribute-sets is not a value template.
4216 * use-attribute-sets = qnames
4218 attrSets
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4219 (const xmlChar
*)"use-attribute-sets", NULL
);
4220 if (attrSets
!= NULL
) {
4221 xsltApplyAttributeSet(ctxt
, node
, inst
, attrSets
);
4227 * Instantiate the sequence constructor.
4229 if (inst
->children
!= NULL
)
4230 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, inst
->children
,
4234 ctxt
->insert
= oldInsert
;
4241 * @ctxt: a XSLT process context
4242 * @node: the node in the source tree.
4243 * @inst: the xslt comment node
4244 * @comp: precomputed information
4246 * Process the xslt comment node on the source node
4249 xsltComment(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4250 xmlNodePtr inst
, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED
) {
4251 xmlChar
*value
= NULL
;
4252 xmlNodePtr commentNode
;
4255 value
= xsltEvalTemplateString(ctxt
, node
, inst
);
4256 /* TODO: use or generate the compiled form */
4257 len
= xmlStrlen(value
);
4259 if ((value
[len
-1] == '-') ||
4260 (xmlStrstr(value
, BAD_CAST
"--"))) {
4261 xsltTransformError(ctxt
, NULL
, inst
,
4262 "xsl:comment : '--' or ending '-' not allowed in comment\n");
4263 /* fall through to try to catch further errors */
4266 #ifdef WITH_XSLT_DEBUG_PROCESS
4267 if (value
== NULL
) {
4268 XSLT_TRACE(ctxt
,XSLT_TRACE_COMMENT
,xsltGenericDebug(xsltGenericDebugContext
,
4269 "xsltComment: empty\n"));
4271 XSLT_TRACE(ctxt
,XSLT_TRACE_COMMENT
,xsltGenericDebug(xsltGenericDebugContext
,
4272 "xsltComment: content %s\n", value
));
4276 commentNode
= xmlNewComment(value
);
4277 commentNode
= xsltAddChild(ctxt
->insert
, commentNode
);
4284 * xsltProcessingInstruction:
4285 * @ctxt: a XSLT process context
4286 * @node: the node in the source tree.
4287 * @inst: the xslt processing-instruction node
4288 * @castedComp: precomputed information
4290 * Process the xslt processing-instruction node on the source node
4293 xsltProcessingInstruction(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4294 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
) {
4295 #ifdef XSLT_REFACTORED
4296 xsltStyleItemPIPtr comp
= (xsltStyleItemPIPtr
) castedComp
;
4298 xsltStylePreCompPtr comp
= castedComp
;
4300 const xmlChar
*name
;
4301 xmlChar
*value
= NULL
;
4305 if (ctxt
->insert
== NULL
)
4307 if (comp
->has_name
== 0)
4309 if (comp
->name
== NULL
) {
4310 name
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4311 (const xmlChar
*)"name", NULL
);
4313 xsltTransformError(ctxt
, NULL
, inst
,
4314 "xsl:processing-instruction : name is missing\n");
4320 /* TODO: check that it's both an an NCName and a PITarget. */
4323 value
= xsltEvalTemplateString(ctxt
, node
, inst
);
4324 if (xmlStrstr(value
, BAD_CAST
"?>") != NULL
) {
4325 xsltTransformError(ctxt
, NULL
, inst
,
4326 "xsl:processing-instruction: '?>' not allowed within PI content\n");
4329 #ifdef WITH_XSLT_DEBUG_PROCESS
4330 if (value
== NULL
) {
4331 XSLT_TRACE(ctxt
,XSLT_TRACE_PI
,xsltGenericDebug(xsltGenericDebugContext
,
4332 "xsltProcessingInstruction: %s empty\n", name
));
4334 XSLT_TRACE(ctxt
,XSLT_TRACE_PI
,xsltGenericDebug(xsltGenericDebugContext
,
4335 "xsltProcessingInstruction: %s content %s\n", name
, value
));
4339 pi
= xmlNewDocPI(ctxt
->insert
->doc
, name
, value
);
4340 pi
= xsltAddChild(ctxt
->insert
, pi
);
4343 if ((name
!= NULL
) && (name
!= comp
->name
))
4344 xmlFree((xmlChar
*) name
);
4351 * @ctxt: an XSLT transformation context
4352 * @node: the current node in the source tree
4353 * @inst: the element node of the XSLT copy-of instruction
4354 * @castedComp: precomputed information of the XSLT copy-of instruction
4356 * Process the XSLT copy-of instruction.
4359 xsltCopyOf(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4360 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
) {
4361 #ifdef XSLT_REFACTORED
4362 xsltStyleItemCopyOfPtr comp
= (xsltStyleItemCopyOfPtr
) castedComp
;
4364 xsltStylePreCompPtr comp
= castedComp
;
4366 xmlXPathObjectPtr res
= NULL
;
4367 xmlNodeSetPtr list
= NULL
;
4370 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
))
4372 if ((comp
== NULL
) || (comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
4373 xsltTransformError(ctxt
, NULL
, inst
,
4374 "xsl:copy-of : compilation failed\n");
4380 * "The xsl:copy-of element can be used to insert a result tree
4381 * fragment into the result tree, without first converting it to
4382 * a string as xsl:value-of does (see [7.6.1 Generating Text with
4383 * xsl:value-of]). The required select attribute contains an
4384 * expression. When the result of evaluating the expression is a
4385 * result tree fragment, the complete fragment is copied into the
4386 * result tree. When the result is a node-set, all the nodes in the
4387 * set are copied in document order into the result tree; copying
4388 * an element node copies the attribute nodes, namespace nodes and
4389 * children of the element node as well as the element node itself;
4390 * a root node is copied by copying its children. When the result
4391 * is neither a node-set nor a result tree fragment, the result is
4392 * converted to a string and then inserted into the result tree,
4393 * as with xsl:value-of.
4396 #ifdef WITH_XSLT_DEBUG_PROCESS
4397 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4398 "xsltCopyOf: select %s\n", comp
->select
));
4402 * Evaluate the "select" expression.
4404 res
= xsltPreCompEval(ctxt
, node
, comp
);
4407 if (res
->type
== XPATH_NODESET
) {
4412 #ifdef WITH_XSLT_DEBUG_PROCESS
4413 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4414 "xsltCopyOf: result is a node set\n"));
4416 list
= res
->nodesetval
;
4420 * The list is already sorted in document order by XPath.
4421 * Append everything in this order under ctxt->insert.
4423 for (i
= 0;i
< list
->nodeNr
;i
++) {
4424 cur
= list
->nodeTab
[i
];
4427 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
4428 (cur
->type
== XML_HTML_DOCUMENT_NODE
))
4430 xsltCopyTreeList(ctxt
, inst
,
4431 cur
->children
, ctxt
->insert
, 0, 0);
4432 } else if (cur
->type
== XML_ATTRIBUTE_NODE
) {
4433 xsltShallowCopyAttr(ctxt
, inst
,
4434 ctxt
->insert
, (xmlAttrPtr
) cur
);
4436 xsltCopyTreeInternal(ctxt
, inst
,
4437 cur
, ctxt
->insert
, 0, 0);
4441 } else if (res
->type
== XPATH_XSLT_TREE
) {
4443 * Result tree fragment
4444 * --------------------
4445 * E.g. via <xsl:variable ...><foo/></xsl:variable>
4446 * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4448 #ifdef WITH_XSLT_DEBUG_PROCESS
4449 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4450 "xsltCopyOf: result is a result tree fragment\n"));
4452 list
= res
->nodesetval
;
4453 if ((list
!= NULL
) && (list
->nodeTab
!= NULL
) &&
4454 (list
->nodeTab
[0] != NULL
) &&
4455 (IS_XSLT_REAL_NODE(list
->nodeTab
[0])))
4457 xsltCopyTreeList(ctxt
, inst
,
4458 list
->nodeTab
[0]->children
, ctxt
->insert
, 0, 0);
4461 xmlChar
*value
= NULL
;
4463 * Convert to a string.
4465 value
= xmlXPathCastToString(res
);
4466 if (value
== NULL
) {
4467 xsltTransformError(ctxt
, NULL
, inst
,
4468 "Internal error in xsltCopyOf(): "
4469 "failed to cast an XPath object to string.\n");
4470 ctxt
->state
= XSLT_STATE_STOPPED
;
4472 if (value
[0] != 0) {
4474 * Append content as text node.
4476 xsltCopyTextString(ctxt
, ctxt
->insert
, value
, 0);
4480 #ifdef WITH_XSLT_DEBUG_PROCESS
4481 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4482 "xsltCopyOf: result %s\n", res
->stringval
));
4487 ctxt
->state
= XSLT_STATE_STOPPED
;
4491 xmlXPathFreeObject(res
);
4496 * @ctxt: a XSLT process context
4497 * @node: the node in the source tree.
4498 * @inst: the xslt value-of node
4499 * @castedComp: precomputed information
4501 * Process the xslt value-of node on the source node
4504 xsltValueOf(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4505 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
4507 #ifdef XSLT_REFACTORED
4508 xsltStyleItemValueOfPtr comp
= (xsltStyleItemValueOfPtr
) castedComp
;
4510 xsltStylePreCompPtr comp
= castedComp
;
4512 xmlXPathObjectPtr res
= NULL
;
4513 xmlChar
*value
= NULL
;
4515 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
))
4518 if ((comp
== NULL
) || (comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
4519 xsltTransformError(ctxt
, NULL
, inst
,
4520 "Internal error in xsltValueOf(): "
4521 "The XSLT 'value-of' instruction was not compiled.\n");
4525 #ifdef WITH_XSLT_DEBUG_PROCESS
4526 XSLT_TRACE(ctxt
,XSLT_TRACE_VALUE_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4527 "xsltValueOf: select %s\n", comp
->select
));
4530 res
= xsltPreCompEval(ctxt
, node
, comp
);
4533 * Cast the XPath object to string.
4536 value
= xmlXPathCastToString(res
);
4537 if (value
== NULL
) {
4538 xsltTransformError(ctxt
, NULL
, inst
,
4539 "Internal error in xsltValueOf(): "
4540 "failed to cast an XPath object to string.\n");
4541 ctxt
->state
= XSLT_STATE_STOPPED
;
4544 if (value
[0] != 0) {
4545 xsltCopyTextString(ctxt
, ctxt
->insert
, value
, comp
->noescape
);
4548 xsltTransformError(ctxt
, NULL
, inst
,
4549 "XPath evaluation returned no result.\n");
4550 ctxt
->state
= XSLT_STATE_STOPPED
;
4554 #ifdef WITH_XSLT_DEBUG_PROCESS
4556 XSLT_TRACE(ctxt
,XSLT_TRACE_VALUE_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4557 "xsltValueOf: result '%s'\n", value
));
4565 xmlXPathFreeObject(res
);
4570 * @ctxt: a XSLT process context
4571 * @node: the node in the source tree.
4572 * @inst: the xslt number node
4573 * @castedComp: precomputed information
4575 * Process the xslt number node on the source node
4578 xsltNumber(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4579 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
4581 #ifdef XSLT_REFACTORED
4582 xsltStyleItemNumberPtr comp
= (xsltStyleItemNumberPtr
) castedComp
;
4584 xsltStylePreCompPtr comp
= castedComp
;
4586 xmlXPathContextPtr xpctxt
;
4587 xmlNsPtr
*oldXPNamespaces
;
4591 xsltTransformError(ctxt
, NULL
, inst
,
4592 "xsl:number : compilation failed\n");
4596 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
4599 comp
->numdata
.doc
= inst
->doc
;
4600 comp
->numdata
.node
= inst
;
4602 xpctxt
= ctxt
->xpathCtxt
;
4603 oldXPNsNr
= xpctxt
->nsNr
;
4604 oldXPNamespaces
= xpctxt
->namespaces
;
4606 #ifdef XSLT_REFACTORED
4607 if (comp
->inScopeNs
!= NULL
) {
4608 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
4609 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
4611 xpctxt
->namespaces
= NULL
;
4615 xpctxt
->namespaces
= comp
->nsList
;
4616 xpctxt
->nsNr
= comp
->nsNr
;
4619 xsltNumberFormat(ctxt
, &comp
->numdata
, node
);
4621 xpctxt
->nsNr
= oldXPNsNr
;
4622 xpctxt
->namespaces
= oldXPNamespaces
;
4627 * @ctxt: an XSLT transformation context
4628 * @contextNode: the current node in the source tree.
4629 * @inst: the element node of the XSLT 'apply-imports' instruction
4630 * @comp: the compiled instruction
4632 * Process the XSLT apply-imports element.
4635 xsltApplyImports(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
4637 xsltStylePreCompPtr comp ATTRIBUTE_UNUSED
)
4639 xsltTemplatePtr templ
;
4641 if ((ctxt
== NULL
) || (inst
== NULL
))
4645 xsltTransformError(ctxt
, NULL
, inst
,
4646 "Internal error in xsltApplyImports(): "
4647 "The XSLT 'apply-imports' instruction was not compiled.\n");
4651 * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4652 * same; the former is the "Current Template Rule" as defined by the
4653 * XSLT spec, the latter is simply the template struct being
4654 * currently processed.
4656 if (ctxt
->currentTemplateRule
== NULL
) {
4659 * "[ERR XTDE0560] It is a non-recoverable dynamic error if
4660 * xsl:apply-imports or xsl:next-match is evaluated when the
4661 * current template rule is null."
4663 xsltTransformError(ctxt
, NULL
, inst
,
4664 "It is an error to call 'apply-imports' "
4665 "when there's no current template rule.\n");
4669 * TODO: Check if this is correct.
4671 templ
= xsltGetTemplate(ctxt
, contextNode
,
4672 ctxt
->currentTemplateRule
->style
);
4674 if (templ
!= NULL
) {
4675 xsltTemplatePtr oldCurTemplRule
= ctxt
->currentTemplateRule
;
4677 * Set the current template rule.
4679 ctxt
->currentTemplateRule
= templ
;
4681 * URGENT TODO: Need xsl:with-param be handled somehow here?
4683 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
,
4686 ctxt
->currentTemplateRule
= oldCurTemplRule
;
4692 * @ctxt: a XSLT transformation context
4693 * @node: the "current node" in the source tree
4694 * @inst: the XSLT 'call-template' instruction
4695 * @castedComp: the compiled information of the instruction
4697 * Processes the XSLT call-template instruction on the source node.
4700 xsltCallTemplate(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4701 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
4703 #ifdef XSLT_REFACTORED
4704 xsltStyleItemCallTemplatePtr comp
=
4705 (xsltStyleItemCallTemplatePtr
) castedComp
;
4707 xsltStylePreCompPtr comp
= castedComp
;
4709 xsltStackElemPtr withParams
= NULL
;
4711 if (ctxt
->insert
== NULL
)
4714 xsltTransformError(ctxt
, NULL
, inst
,
4715 "The XSLT 'call-template' instruction was not compiled.\n");
4720 * The template must have been precomputed
4722 if (comp
->templ
== NULL
) {
4723 comp
->templ
= xsltFindTemplate(ctxt
, comp
->name
, comp
->ns
);
4724 if (comp
->templ
== NULL
) {
4725 if (comp
->ns
!= NULL
) {
4726 xsltTransformError(ctxt
, NULL
, inst
,
4727 "The called template '{%s}%s' was not found.\n",
4728 comp
->ns
, comp
->name
);
4730 xsltTransformError(ctxt
, NULL
, inst
,
4731 "The called template '%s' was not found.\n",
4738 #ifdef WITH_XSLT_DEBUG_PROCESS
4739 if ((comp
!= NULL
) && (comp
->name
!= NULL
))
4740 XSLT_TRACE(ctxt
,XSLT_TRACE_CALL_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
4741 "call-template: name %s\n", comp
->name
));
4744 if (inst
->children
) {
4746 xsltStackElemPtr param
;
4748 cur
= inst
->children
;
4749 while (cur
!= NULL
) {
4750 #ifdef WITH_DEBUGGER
4751 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
4752 xslHandleDebugger(cur
, node
, comp
->templ
, ctxt
);
4754 if (ctxt
->state
== XSLT_STATE_STOPPED
) break;
4756 * TODO: The "with-param"s could be part of the "call-template"
4757 * structure. Avoid to "search" for params dynamically
4758 * in the XML tree every time.
4760 if (IS_XSLT_ELEM(cur
)) {
4761 if (IS_XSLT_NAME(cur
, "with-param")) {
4762 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
4763 if (param
!= NULL
) {
4764 param
->next
= withParams
;
4768 xsltGenericError(xsltGenericErrorContext
,
4769 "xsl:call-template: misplaced xsl:%s\n", cur
->name
);
4772 xsltGenericError(xsltGenericErrorContext
,
4773 "xsl:call-template: misplaced %s element\n", cur
->name
);
4779 * Create a new frame using the params first
4781 xsltApplyXSLTTemplate(ctxt
, node
, comp
->templ
->content
, comp
->templ
,
4783 if (withParams
!= NULL
)
4784 xsltFreeStackElemList(withParams
);
4786 #ifdef WITH_XSLT_DEBUG_PROCESS
4787 if ((comp
!= NULL
) && (comp
->name
!= NULL
))
4788 XSLT_TRACE(ctxt
,XSLT_TRACE_CALL_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
4789 "call-template returned: name %s\n", comp
->name
));
4794 * xsltApplyTemplates:
4795 * @ctxt: a XSLT transformation context
4796 * @node: the 'current node' in the source tree
4797 * @inst: the element node of an XSLT 'apply-templates' instruction
4798 * @castedComp: the compiled instruction
4800 * Processes the XSLT 'apply-templates' instruction on the current node.
4803 xsltApplyTemplates(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4804 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
4806 #ifdef XSLT_REFACTORED
4807 xsltStyleItemApplyTemplatesPtr comp
=
4808 (xsltStyleItemApplyTemplatesPtr
) castedComp
;
4810 xsltStylePreCompPtr comp
= castedComp
;
4813 xmlNodePtr cur
, delNode
= NULL
, oldContextNode
;
4814 xmlNodeSetPtr list
= NULL
, oldList
;
4815 xsltStackElemPtr withParams
= NULL
;
4816 int oldXPProximityPosition
, oldXPContextSize
;
4817 const xmlChar
*oldMode
, *oldModeURI
;
4819 xsltDocumentPtr oldDocInfo
;
4820 xmlXPathContextPtr xpctxt
;
4823 xsltTransformError(ctxt
, NULL
, inst
,
4824 "xsl:apply-templates : compilation failed\n");
4827 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
4830 #ifdef WITH_XSLT_DEBUG_PROCESS
4831 if ((node
!= NULL
) && (node
->name
!= NULL
))
4832 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4833 "xsltApplyTemplates: node: '%s'\n", node
->name
));
4836 xpctxt
= ctxt
->xpathCtxt
;
4838 * Save context states.
4840 oldContextNode
= ctxt
->node
;
4841 oldMode
= ctxt
->mode
;
4842 oldModeURI
= ctxt
->modeURI
;
4843 oldDocInfo
= ctxt
->document
;
4844 oldList
= ctxt
->nodeList
;
4847 * The xpath context size and proximity position, as
4848 * well as the xpath and context documents, may be changed
4849 * so we save their initial state and will restore on exit
4851 oldXPContextSize
= xpctxt
->contextSize
;
4852 oldXPProximityPosition
= xpctxt
->proximityPosition
;
4853 oldXPDoc
= xpctxt
->doc
;
4858 ctxt
->mode
= comp
->mode
;
4859 ctxt
->modeURI
= comp
->modeURI
;
4861 if (comp
->select
!= NULL
) {
4862 xmlXPathObjectPtr res
= NULL
;
4864 if (comp
->comp
== NULL
) {
4865 xsltTransformError(ctxt
, NULL
, inst
,
4866 "xsl:apply-templates : compilation failed\n");
4869 #ifdef WITH_XSLT_DEBUG_PROCESS
4870 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4871 "xsltApplyTemplates: select %s\n", comp
->select
));
4874 res
= xsltPreCompEval(ctxt
, node
, comp
);
4877 if (res
->type
== XPATH_NODESET
) {
4878 list
= res
->nodesetval
; /* consume the node set */
4879 res
->nodesetval
= NULL
;
4881 xsltTransformError(ctxt
, NULL
, inst
,
4882 "The 'select' expression did not evaluate to a "
4884 ctxt
->state
= XSLT_STATE_STOPPED
;
4885 xmlXPathFreeObject(res
);
4888 xmlXPathFreeObject(res
);
4890 * Note: An xsl:apply-templates with a 'select' attribute,
4891 * can change the current source doc.
4894 xsltTransformError(ctxt
, NULL
, inst
,
4895 "Failed to evaluate the 'select' expression.\n");
4896 ctxt
->state
= XSLT_STATE_STOPPED
;
4900 #ifdef WITH_XSLT_DEBUG_PROCESS
4901 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4902 "xsltApplyTemplates: select didn't evaluate to a node list\n"));
4908 * NOTE: Previously a document info (xsltDocument) was
4909 * created and attached to the Result Tree Fragment.
4910 * But such a document info is created on demand in
4911 * xsltKeyFunction() (functions.c), so we need to create
4912 * it here beforehand.
4913 * In order to take care of potential keys we need to
4914 * do some extra work for the case when a Result Tree Fragment
4915 * is converted into a nodeset (e.g. exslt:node-set()) :
4916 * We attach a "pseudo-doc" (xsltDocument) to _private.
4917 * This xsltDocument, together with the keyset, will be freed
4918 * when the Result Tree Fragment is freed.
4922 if ((ctxt
->nbKeys
> 0) &&
4923 (list
->nodeNr
!= 0) &&
4924 (list
->nodeTab
[0]->doc
!= NULL
) &&
4925 XSLT_IS_RES_TREE_FRAG(list
->nodeTab
[0]->doc
))
4928 * NOTE that it's also OK if @effectiveDocInfo will be
4932 effectiveDocInfo
= list
->nodeTab
[0]->doc
->_private
;
4937 * Build an XPath node set with the children
4939 list
= xmlXPathNodeSetCreate(NULL
);
4942 if (node
->type
!= XML_NAMESPACE_DECL
)
4943 cur
= node
->children
;
4946 while (cur
!= NULL
) {
4947 switch (cur
->type
) {
4949 if ((IS_BLANK_NODE(cur
)) &&
4950 (cur
->parent
!= NULL
) &&
4951 (cur
->parent
->type
== XML_ELEMENT_NODE
) &&
4952 (ctxt
->style
->stripSpaces
!= NULL
)) {
4955 if (cur
->parent
->ns
!= NULL
) {
4956 val
= (const xmlChar
*)
4957 xmlHashLookup2(ctxt
->style
->stripSpaces
,
4959 cur
->parent
->ns
->href
);
4961 val
= (const xmlChar
*)
4962 xmlHashLookup2(ctxt
->style
->stripSpaces
,
4964 cur
->parent
->ns
->href
);
4967 val
= (const xmlChar
*)
4968 xmlHashLookup2(ctxt
->style
->stripSpaces
,
4969 cur
->parent
->name
, NULL
);
4971 if ((val
!= NULL
) &&
4972 (xmlStrEqual(val
, (xmlChar
*) "strip"))) {
4977 /* no break on purpose */
4978 case XML_ELEMENT_NODE
:
4979 case XML_DOCUMENT_NODE
:
4980 case XML_HTML_DOCUMENT_NODE
:
4981 case XML_CDATA_SECTION_NODE
:
4983 case XML_COMMENT_NODE
:
4984 xmlXPathNodeSetAddUnique(list
, cur
);
4987 /* Unlink the DTD, it's still reachable
4988 * using doc->intSubset */
4989 if (cur
->next
!= NULL
)
4990 cur
->next
->prev
= cur
->prev
;
4991 if (cur
->prev
!= NULL
)
4992 cur
->prev
->next
= cur
->next
;
4994 case XML_NAMESPACE_DECL
:
4997 #ifdef WITH_XSLT_DEBUG_PROCESS
4998 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4999 "xsltApplyTemplates: skipping cur type %d\n",
5005 if (delNode
!= NULL
) {
5006 #ifdef WITH_XSLT_DEBUG_PROCESS
5007 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
5008 "xsltApplyTemplates: removing ignorable blank cur\n"));
5010 xmlUnlinkNode(delNode
);
5011 xmlFreeNode(delNode
);
5017 #ifdef WITH_XSLT_DEBUG_PROCESS
5019 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
5020 "xsltApplyTemplates: list of %d nodes\n", list
->nodeNr
));
5023 if ((list
== NULL
) || (list
->nodeNr
== 0))
5027 * Set the context's node set and size; this is also needed for
5028 * for xsltDoSortFunction().
5030 ctxt
->nodeList
= list
;
5032 * Process xsl:with-param and xsl:sort instructions.
5033 * (The code became so verbose just to avoid the
5034 * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
5035 * BUG TODO: We are not using namespaced potentially defined on the
5036 * xsl:sort or xsl:with-param elements; XPath expression might fail.
5038 if (inst
->children
) {
5039 xsltStackElemPtr param
;
5041 cur
= inst
->children
;
5044 #ifdef WITH_DEBUGGER
5045 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
5046 xslHandleDebugger(cur
, node
, NULL
, ctxt
);
5048 if (ctxt
->state
== XSLT_STATE_STOPPED
)
5050 if (cur
->type
== XML_TEXT_NODE
) {
5054 if (! IS_XSLT_ELEM(cur
))
5056 if (IS_XSLT_NAME(cur
, "with-param")) {
5057 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
5058 if (param
!= NULL
) {
5059 param
->next
= withParams
;
5063 if (IS_XSLT_NAME(cur
, "sort")) {
5064 xsltTemplatePtr oldCurTempRule
=
5065 ctxt
->currentTemplateRule
;
5067 xmlNodePtr sorts
[XSLT_MAX_SORT
];
5069 sorts
[nbsorts
++] = cur
;
5073 #ifdef WITH_DEBUGGER
5074 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
5075 xslHandleDebugger(cur
, node
, NULL
, ctxt
);
5077 if (ctxt
->state
== XSLT_STATE_STOPPED
)
5080 if (cur
->type
== XML_TEXT_NODE
) {
5085 if (! IS_XSLT_ELEM(cur
))
5087 if (IS_XSLT_NAME(cur
, "with-param")) {
5088 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
5089 if (param
!= NULL
) {
5090 param
->next
= withParams
;
5094 if (IS_XSLT_NAME(cur
, "sort")) {
5095 if (nbsorts
>= XSLT_MAX_SORT
) {
5096 xsltTransformError(ctxt
, NULL
, cur
,
5097 "The number (%d) of xsl:sort instructions exceeds the "
5098 "maximum allowed by this processor's settings.\n",
5100 ctxt
->state
= XSLT_STATE_STOPPED
;
5103 sorts
[nbsorts
++] = cur
;
5109 * The "current template rule" is cleared for xsl:sort.
5111 ctxt
->currentTemplateRule
= NULL
;
5115 xsltDoSortFunction(ctxt
, sorts
, nbsorts
);
5116 ctxt
->currentTemplateRule
= oldCurTempRule
;
5122 xpctxt
->contextSize
= list
->nodeNr
;
5124 * Apply templates for all selected source nodes.
5126 for (i
= 0; i
< list
->nodeNr
; i
++) {
5127 cur
= list
->nodeTab
[i
];
5129 * The node becomes the "current node".
5133 * An xsl:apply-templates can change the current context doc.
5134 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5136 if ((cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->doc
!= NULL
))
5137 xpctxt
->doc
= cur
->doc
;
5139 xpctxt
->proximityPosition
= i
+ 1;
5141 * Find and apply a template for this node.
5143 xsltProcessOneNode(ctxt
, cur
, withParams
);
5149 * Free the parameter list.
5151 if (withParams
!= NULL
)
5152 xsltFreeStackElemList(withParams
);
5154 xmlXPathFreeNodeSet(list
);
5156 * Restore context states.
5158 xpctxt
->doc
= oldXPDoc
;
5159 xpctxt
->contextSize
= oldXPContextSize
;
5160 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5162 ctxt
->document
= oldDocInfo
;
5163 ctxt
->nodeList
= oldList
;
5164 ctxt
->node
= oldContextNode
;
5165 ctxt
->mode
= oldMode
;
5166 ctxt
->modeURI
= oldModeURI
;
5172 * @ctxt: a XSLT process context
5173 * @contextNode: the current node in the source tree
5174 * @inst: the xsl:choose instruction
5175 * @comp: compiled information of the instruction
5177 * Processes the xsl:choose instruction on the source node.
5180 xsltChoose(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5181 xmlNodePtr inst
, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED
)
5185 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
))
5189 * TODO: Content model checks should be done only at compilation
5192 cur
= inst
->children
;
5194 xsltTransformError(ctxt
, NULL
, inst
,
5195 "xsl:choose: The instruction has no content.\n");
5199 #ifdef XSLT_REFACTORED
5201 * We don't check the content model during transformation.
5204 if ((! IS_XSLT_ELEM(cur
)) || (! IS_XSLT_NAME(cur
, "when"))) {
5205 xsltTransformError(ctxt
, NULL
, inst
,
5206 "xsl:choose: xsl:when expected first\n");
5212 int testRes
= 0, res
= 0;
5214 #ifdef XSLT_REFACTORED
5215 xsltStyleItemWhenPtr wcomp
= NULL
;
5217 xsltStylePreCompPtr wcomp
= NULL
;
5221 * Process xsl:when ---------------------------------------------------
5223 while (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "when")) {
5226 if ((wcomp
== NULL
) || (wcomp
->test
== NULL
) ||
5227 (wcomp
->comp
== NULL
))
5229 xsltTransformError(ctxt
, NULL
, cur
,
5230 "Internal error in xsltChoose(): "
5231 "The XSLT 'when' instruction was not compiled.\n");
5236 #ifdef WITH_DEBUGGER
5237 if (xslDebugStatus
!= XSLT_DEBUG_NONE
) {
5239 * TODO: Isn't comp->templ always NULL for xsl:choose?
5241 xslHandleDebugger(cur
, contextNode
, NULL
, ctxt
);
5244 #ifdef WITH_XSLT_DEBUG_PROCESS
5245 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5246 "xsltChoose: test %s\n", wcomp
->test
));
5250 res
= xsltPreCompEvalToBoolean(ctxt
, contextNode
, wcomp
);
5253 ctxt
->state
= XSLT_STATE_STOPPED
;
5256 testRes
= (res
== 1) ? 1 : 0;
5258 #else /* XSLT_FAST_IF */
5260 res
= xsltPreCompEval(ctxt
, cotextNode
, wcomp
);
5263 if (res
->type
!= XPATH_BOOLEAN
)
5264 res
= xmlXPathConvertBoolean(res
);
5265 if (res
->type
== XPATH_BOOLEAN
)
5266 testRes
= res
->boolval
;
5268 #ifdef WITH_XSLT_DEBUG_PROCESS
5269 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5270 "xsltChoose: test didn't evaluate to a boolean\n"));
5274 xmlXPathFreeObject(res
);
5277 ctxt
->state
= XSLT_STATE_STOPPED
;
5281 #endif /* else of XSLT_FAST_IF */
5283 #ifdef WITH_XSLT_DEBUG_PROCESS
5284 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5285 "xsltChoose: test evaluate to %d\n", testRes
));
5294 * Process xsl:otherwise ----------------------------------------------
5296 if (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "otherwise")) {
5298 #ifdef WITH_DEBUGGER
5299 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5300 xslHandleDebugger(cur
, contextNode
, NULL
, ctxt
);
5303 #ifdef WITH_XSLT_DEBUG_PROCESS
5304 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5305 "evaluating xsl:otherwise\n"));
5313 goto process_sequence
;
5319 * Instantiate the sequence constructor.
5321 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, cur
->children
,
5331 * @ctxt: a XSLT process context
5332 * @contextNode: the current node in the source tree
5333 * @inst: the xsl:if instruction
5334 * @castedComp: compiled information of the instruction
5336 * Processes the xsl:if instruction on the source node.
5339 xsltIf(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5340 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
5344 #ifdef XSLT_REFACTORED
5345 xsltStyleItemIfPtr comp
= (xsltStyleItemIfPtr
) castedComp
;
5347 xsltStylePreCompPtr comp
= castedComp
;
5350 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
))
5352 if ((comp
== NULL
) || (comp
->test
== NULL
) || (comp
->comp
== NULL
)) {
5353 xsltTransformError(ctxt
, NULL
, inst
,
5354 "Internal error in xsltIf(): "
5355 "The XSLT 'if' instruction was not compiled.\n");
5359 #ifdef WITH_XSLT_DEBUG_PROCESS
5360 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5361 "xsltIf: test %s\n", comp
->test
));
5366 xmlDocPtr oldLocalFragmentTop
= ctxt
->localRVT
;
5368 res
= xsltPreCompEvalToBoolean(ctxt
, contextNode
, comp
);
5371 * Cleanup fragments created during evaluation of the
5372 * "select" expression.
5374 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
5375 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
5378 #ifdef WITH_XSLT_DEBUG_PROCESS
5379 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5380 "xsltIf: test evaluate to %d\n", res
));
5384 ctxt
->state
= XSLT_STATE_STOPPED
;
5389 * Instantiate the sequence constructor of xsl:if.
5391 xsltApplySequenceConstructor(ctxt
,
5392 contextNode
, inst
->children
, NULL
);
5395 #else /* XSLT_FAST_IF */
5400 xmlXPathObjectPtr xpobj
= xsltPreCompEval(ctxt
, contextNode
, comp
);
5401 if (xpobj
!= NULL
) {
5402 if (xpobj
->type
!= XPATH_BOOLEAN
)
5403 xpobj
= xmlXPathConvertBoolean(xpobj
);
5404 if (xpobj
->type
== XPATH_BOOLEAN
) {
5405 res
= xpobj
->boolval
;
5407 #ifdef WITH_XSLT_DEBUG_PROCESS
5408 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5409 "xsltIf: test evaluate to %d\n", res
));
5412 xsltApplySequenceConstructor(ctxt
,
5413 contextNode
, inst
->children
, NULL
);
5417 #ifdef WITH_XSLT_DEBUG_PROCESS
5418 XSLT_TRACE(ctxt
, XSLT_TRACE_IF
,
5419 xsltGenericDebug(xsltGenericDebugContext
,
5420 "xsltIf: test didn't evaluate to a boolean\n"));
5422 ctxt
->state
= XSLT_STATE_STOPPED
;
5424 xmlXPathFreeObject(xpobj
);
5426 ctxt
->state
= XSLT_STATE_STOPPED
;
5429 #endif /* else of XSLT_FAST_IF */
5437 * @ctxt: an XSLT transformation context
5438 * @contextNode: the "current node" in the source tree
5439 * @inst: the element node of the xsl:for-each instruction
5440 * @castedComp: the compiled information of the instruction
5442 * Process the xslt for-each node on the source node
5445 xsltForEach(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5446 xmlNodePtr inst
, xsltStylePreCompPtr castedComp
)
5448 #ifdef XSLT_REFACTORED
5449 xsltStyleItemForEachPtr comp
= (xsltStyleItemForEachPtr
) castedComp
;
5451 xsltStylePreCompPtr comp
= castedComp
;
5454 xmlXPathObjectPtr res
= NULL
;
5455 xmlNodePtr cur
, curInst
;
5456 xmlNodeSetPtr list
= NULL
;
5457 xmlNodeSetPtr oldList
;
5458 int oldXPProximityPosition
, oldXPContextSize
;
5459 xmlNodePtr oldContextNode
;
5460 xsltTemplatePtr oldCurTemplRule
;
5462 xsltDocumentPtr oldDocInfo
;
5463 xmlXPathContextPtr xpctxt
;
5465 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
)) {
5466 xsltGenericError(xsltGenericErrorContext
,
5467 "xsltForEach(): Bad arguments.\n");
5472 xsltTransformError(ctxt
, NULL
, inst
,
5473 "Internal error in xsltForEach(): "
5474 "The XSLT 'for-each' instruction was not compiled.\n");
5477 if ((comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
5478 xsltTransformError(ctxt
, NULL
, inst
,
5479 "Internal error in xsltForEach(): "
5480 "The selecting expression of the XSLT 'for-each' "
5481 "instruction was not compiled correctly.\n");
5484 xpctxt
= ctxt
->xpathCtxt
;
5486 #ifdef WITH_XSLT_DEBUG_PROCESS
5487 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5488 "xsltForEach: select %s\n", comp
->select
));
5492 * Save context states.
5494 oldDocInfo
= ctxt
->document
;
5495 oldList
= ctxt
->nodeList
;
5496 oldContextNode
= ctxt
->node
;
5498 * The "current template rule" is cleared for the instantiation of
5501 oldCurTemplRule
= ctxt
->currentTemplateRule
;
5502 ctxt
->currentTemplateRule
= NULL
;
5504 oldXPDoc
= xpctxt
->doc
;
5505 oldXPProximityPosition
= xpctxt
->proximityPosition
;
5506 oldXPContextSize
= xpctxt
->contextSize
;
5509 * Evaluate the 'select' expression.
5511 res
= xsltPreCompEval(ctxt
, contextNode
, comp
);
5514 if (res
->type
== XPATH_NODESET
)
5515 list
= res
->nodesetval
;
5517 xsltTransformError(ctxt
, NULL
, inst
,
5518 "The 'select' expression does not evaluate to a node set.\n");
5520 #ifdef WITH_XSLT_DEBUG_PROCESS
5521 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5522 "xsltForEach: select didn't evaluate to a node list\n"));
5527 xsltTransformError(ctxt
, NULL
, inst
,
5528 "Failed to evaluate the 'select' expression.\n");
5529 ctxt
->state
= XSLT_STATE_STOPPED
;
5533 if ((list
== NULL
) || (list
->nodeNr
<= 0))
5536 #ifdef WITH_XSLT_DEBUG_PROCESS
5537 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5538 "xsltForEach: select evaluates to %d nodes\n", list
->nodeNr
));
5542 * Set the list; this has to be done already here for xsltDoSortFunction().
5544 ctxt
->nodeList
= list
;
5546 * Handle xsl:sort instructions and skip them for further processing.
5547 * BUG TODO: We are not using namespaced potentially defined on the
5548 * xsl:sort element; XPath expression might fail.
5550 curInst
= inst
->children
;
5551 if (IS_XSLT_ELEM(curInst
) && IS_XSLT_NAME(curInst
, "sort")) {
5553 xmlNodePtr sorts
[XSLT_MAX_SORT
];
5555 sorts
[nbsorts
++] = curInst
;
5557 #ifdef WITH_DEBUGGER
5558 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5559 xslHandleDebugger(curInst
, contextNode
, NULL
, ctxt
);
5562 curInst
= curInst
->next
;
5563 while (IS_XSLT_ELEM(curInst
) && IS_XSLT_NAME(curInst
, "sort")) {
5564 if (nbsorts
>= XSLT_MAX_SORT
) {
5565 xsltTransformError(ctxt
, NULL
, curInst
,
5566 "The number of xsl:sort instructions exceeds the "
5567 "maximum (%d) allowed by this processor.\n",
5571 sorts
[nbsorts
++] = curInst
;
5574 #ifdef WITH_DEBUGGER
5575 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5576 xslHandleDebugger(curInst
, contextNode
, NULL
, ctxt
);
5578 curInst
= curInst
->next
;
5580 xsltDoSortFunction(ctxt
, sorts
, nbsorts
);
5582 xpctxt
->contextSize
= list
->nodeNr
;
5584 * Instantiate the sequence constructor for each selected node.
5586 for (i
= 0; i
< list
->nodeNr
; i
++) {
5587 cur
= list
->nodeTab
[i
];
5589 * The selected node becomes the "current node".
5593 * An xsl:for-each can change the current context doc.
5594 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5596 if ((cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->doc
!= NULL
))
5597 xpctxt
->doc
= cur
->doc
;
5599 xpctxt
->proximityPosition
= i
+ 1;
5601 xsltApplySequenceConstructor(ctxt
, cur
, curInst
, NULL
);
5607 xmlXPathFreeObject(res
);
5609 * Restore old states.
5611 ctxt
->document
= oldDocInfo
;
5612 ctxt
->nodeList
= oldList
;
5613 ctxt
->node
= oldContextNode
;
5614 ctxt
->currentTemplateRule
= oldCurTemplRule
;
5616 xpctxt
->doc
= oldXPDoc
;
5617 xpctxt
->contextSize
= oldXPContextSize
;
5618 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5621 /************************************************************************
5623 * Generic interface *
5625 ************************************************************************/
5627 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5628 typedef struct xsltHTMLVersion
{
5629 const char *version
;
5634 static xsltHTMLVersion xsltHTMLVersions
[] = {
5635 { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5636 "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
5637 { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
5638 "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
5639 { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5640 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5641 { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
5642 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5643 { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
5644 "http://www.w3.org/TR/html4/strict.dtd"},
5645 { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5646 "http://www.w3.org/TR/html4/loose.dtd"},
5647 { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5648 "http://www.w3.org/TR/html4/frameset.dtd"},
5649 { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
5650 "http://www.w3.org/TR/html4/loose.dtd"},
5651 { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL
}
5656 * @version: the version string
5657 * @publicID: used to return the public ID
5658 * @systemID: used to return the system ID
5660 * Returns -1 if not found, 0 otherwise and the system and public
5661 * Identifier for this given verion of HTML
5664 xsltGetHTMLIDs(const xmlChar
*version
, const xmlChar
**publicID
,
5665 const xmlChar
**systemID
) {
5667 if (version
== NULL
)
5669 for (i
= 0;i
< (sizeof(xsltHTMLVersions
)/sizeof(xsltHTMLVersions
[1]));
5671 if (!xmlStrcasecmp(version
,
5672 (const xmlChar
*) xsltHTMLVersions
[i
].version
)) {
5673 if (publicID
!= NULL
)
5674 *publicID
= (const xmlChar
*) xsltHTMLVersions
[i
].public;
5675 if (systemID
!= NULL
)
5676 *systemID
= (const xmlChar
*) xsltHTMLVersions
[i
].system
;
5685 * xsltApplyStripSpaces:
5686 * @ctxt: a XSLT process context
5687 * @node: the root of the XML tree
5689 * Strip the unwanted ignorable spaces from the input tree
5692 xsltApplyStripSpaces(xsltTransformContextPtr ctxt
, xmlNodePtr node
) {
5694 #ifdef WITH_XSLT_DEBUG_PROCESS
5700 while (current
!= NULL
) {
5702 * Cleanup children empty nodes if asked for
5704 if ((IS_XSLT_REAL_NODE(current
)) &&
5705 (current
->children
!= NULL
) &&
5706 (xsltFindElemSpaceHandling(ctxt
, current
))) {
5707 xmlNodePtr
delete = NULL
, cur
= current
->children
;
5709 while (cur
!= NULL
) {
5710 if (IS_BLANK_NODE(cur
))
5714 if (delete != NULL
) {
5715 xmlUnlinkNode(delete);
5716 xmlFreeNode(delete);
5718 #ifdef WITH_XSLT_DEBUG_PROCESS
5726 * Skip to next node in document order.
5728 if (node
->type
== XML_ENTITY_REF_NODE
) {
5729 /* process deep in entities */
5730 xsltApplyStripSpaces(ctxt
, node
->children
);
5732 if ((current
->children
!= NULL
) &&
5733 (current
->type
!= XML_ENTITY_REF_NODE
)) {
5734 current
= current
->children
;
5735 } else if (current
->next
!= NULL
) {
5736 current
= current
->next
;
5739 current
= current
->parent
;
5740 if (current
== NULL
)
5742 if (current
== node
)
5744 if (current
->next
!= NULL
) {
5745 current
= current
->next
;
5748 } while (current
!= NULL
);
5753 #ifdef WITH_XSLT_DEBUG_PROCESS
5754 XSLT_TRACE(ctxt
,XSLT_TRACE_STRIP_SPACES
,xsltGenericDebug(xsltGenericDebugContext
,
5755 "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb
));
5761 xsltCountKeys(xsltTransformContextPtr ctxt
)
5763 xsltStylesheetPtr style
;
5770 * Do we have those nastly templates with a key() in the match pattern?
5772 ctxt
->hasTemplKeyPatterns
= 0;
5773 style
= ctxt
->style
;
5774 while (style
!= NULL
) {
5775 if (style
->keyMatch
!= NULL
) {
5776 ctxt
->hasTemplKeyPatterns
= 1;
5779 style
= xsltNextImport(style
);
5782 * Count number of key declarations.
5785 style
= ctxt
->style
;
5786 while (style
!= NULL
) {
5792 style
= xsltNextImport(style
);
5794 return(ctxt
->nbKeys
);
5798 * xsltApplyStylesheetInternal:
5799 * @style: a parsed XSLT stylesheet
5800 * @doc: a parsed XML document
5801 * @params: a NULL terminated array of parameters names/values tuples
5802 * @output: the targetted output
5803 * @profile: profile FILE * output or NULL
5804 * @user: user provided parameter
5806 * Apply the stylesheet to the document
5807 * NOTE: This may lead to a non-wellformed output XML wise !
5809 * Returns the result document or NULL in case of error
5812 xsltApplyStylesheetInternal(xsltStylesheetPtr style
, xmlDocPtr doc
,
5813 const char **params
, const char *output
,
5814 FILE * profile
, xsltTransformContextPtr userCtxt
)
5816 xmlDocPtr res
= NULL
;
5817 xsltTransformContextPtr ctxt
= NULL
;
5818 xmlNodePtr root
, node
;
5819 const xmlChar
*method
;
5820 const xmlChar
*doctypePublic
;
5821 const xmlChar
*doctypeSystem
;
5822 const xmlChar
*version
;
5823 const xmlChar
*encoding
;
5824 xsltStackElemPtr variables
;
5825 xsltStackElemPtr vptr
;
5829 if ((style
== NULL
) || (doc
== NULL
))
5832 if (style
->internalized
== 0) {
5833 #ifdef WITH_XSLT_DEBUG
5834 xsltGenericDebug(xsltGenericDebugContext
,
5835 "Stylesheet was not fully internalized !\n");
5838 if (doc
->intSubset
!= NULL
) {
5840 * Avoid hitting the DTD when scanning nodes
5841 * but keep it linked as doc->intSubset
5843 xmlNodePtr cur
= (xmlNodePtr
) doc
->intSubset
;
5844 if (cur
->next
!= NULL
)
5845 cur
->next
->prev
= cur
->prev
;
5846 if (cur
->prev
!= NULL
)
5847 cur
->prev
->next
= cur
->next
;
5848 if (doc
->children
== cur
)
5849 doc
->children
= cur
->next
;
5850 if (doc
->last
== cur
)
5851 doc
->last
= cur
->prev
;
5852 cur
->prev
= cur
->next
= NULL
;
5856 * Check for XPath document order availability
5858 root
= xmlDocGetRootElement(doc
);
5860 if (((long) root
->content
) >= 0 && (xslDebugStatus
== XSLT_DEBUG_NONE
))
5861 xmlXPathOrderDocElems(doc
);
5864 if (userCtxt
!= NULL
)
5867 ctxt
= xsltNewTransformContext(style
, doc
);
5872 ctxt
->initialContextDoc
= doc
;
5873 ctxt
->initialContextNode
= (xmlNodePtr
) doc
;
5875 if (profile
!= NULL
)
5879 ctxt
->outputFile
= output
;
5881 ctxt
->outputFile
= NULL
;
5884 * internalize the modes if needed
5886 if (ctxt
->dict
!= NULL
) {
5887 if (ctxt
->mode
!= NULL
)
5888 ctxt
->mode
= xmlDictLookup(ctxt
->dict
, ctxt
->mode
, -1);
5889 if (ctxt
->modeURI
!= NULL
)
5890 ctxt
->modeURI
= xmlDictLookup(ctxt
->dict
, ctxt
->modeURI
, -1);
5893 XSLT_GET_IMPORT_PTR(method
, style
, method
)
5894 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
5895 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
5896 XSLT_GET_IMPORT_PTR(version
, style
, version
)
5897 XSLT_GET_IMPORT_PTR(encoding
, style
, encoding
)
5899 if ((method
!= NULL
) &&
5900 (!xmlStrEqual(method
, (const xmlChar
*) "xml")))
5902 if (xmlStrEqual(method
, (const xmlChar
*) "html")) {
5903 ctxt
->type
= XSLT_OUTPUT_HTML
;
5904 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
5905 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5907 if (version
== NULL
) {
5910 res
= htmlNewDoc(NULL
, NULL
);
5912 * Make sure no DTD node is generated in this case
5915 dtd
= xmlGetIntSubset(res
);
5917 xmlUnlinkNode((xmlNodePtr
) dtd
);
5920 res
->intSubset
= NULL
;
5921 res
->extSubset
= NULL
;
5925 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5926 xsltGetHTMLIDs(version
, &doctypePublic
, &doctypeSystem
);
5928 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5933 res
->dict
= ctxt
->dict
;
5934 xmlDictReference(res
->dict
);
5936 #ifdef WITH_XSLT_DEBUG
5937 xsltGenericDebug(xsltGenericDebugContext
,
5938 "reusing transformation dict for output\n");
5940 } else if (xmlStrEqual(method
, (const xmlChar
*) "xhtml")) {
5941 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
5942 "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n");
5943 ctxt
->type
= XSLT_OUTPUT_HTML
;
5944 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5947 res
->dict
= ctxt
->dict
;
5948 xmlDictReference(res
->dict
);
5950 #ifdef WITH_XSLT_DEBUG
5951 xsltGenericDebug(xsltGenericDebugContext
,
5952 "reusing transformation dict for output\n");
5954 } else if (xmlStrEqual(method
, (const xmlChar
*) "text")) {
5955 ctxt
->type
= XSLT_OUTPUT_TEXT
;
5956 res
= xmlNewDoc(style
->version
);
5959 res
->dict
= ctxt
->dict
;
5960 xmlDictReference(res
->dict
);
5962 #ifdef WITH_XSLT_DEBUG
5963 xsltGenericDebug(xsltGenericDebugContext
,
5964 "reusing transformation dict for output\n");
5967 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
5968 "xsltApplyStylesheetInternal: unsupported method (%s)\n",
5973 ctxt
->type
= XSLT_OUTPUT_XML
;
5974 res
= xmlNewDoc(style
->version
);
5977 res
->dict
= ctxt
->dict
;
5978 xmlDictReference(ctxt
->dict
);
5979 #ifdef WITH_XSLT_DEBUG
5980 xsltGenericDebug(xsltGenericDebugContext
,
5981 "reusing transformation dict for output\n");
5984 res
->charset
= XML_CHAR_ENCODING_UTF8
;
5985 if (encoding
!= NULL
)
5986 res
->encoding
= xmlStrdup(encoding
);
5987 variables
= style
->variables
;
5990 * Start the evaluation, evaluate the params, the stylesheets globals
5991 * and start by processing the top node.
5993 if (xsltNeedElemSpaceHandling(ctxt
))
5994 xsltApplyStripSpaces(ctxt
, xmlDocGetRootElement(doc
));
5996 * Evaluate global params and user-provided params.
5998 ctxt
->node
= (xmlNodePtr
) doc
;
5999 if (ctxt
->globalVars
== NULL
)
6000 ctxt
->globalVars
= xmlHashCreate(20);
6001 if (params
!= NULL
) {
6002 xsltEvalUserParams(ctxt
, params
);
6005 /* need to be called before evaluating global variables */
6006 xsltCountKeys(ctxt
);
6008 xsltEvalGlobalVariables(ctxt
);
6010 ctxt
->node
= (xmlNodePtr
) doc
;
6012 ctxt
->insert
= (xmlNodePtr
) res
;
6013 ctxt
->varsBase
= ctxt
->varsNr
- 1;
6015 ctxt
->xpathCtxt
->contextSize
= 1;
6016 ctxt
->xpathCtxt
->proximityPosition
= 1;
6017 ctxt
->xpathCtxt
->node
= NULL
; /* TODO: Set the context node here? */
6019 * Start processing the source tree -----------------------------------
6021 xsltProcessOneNode(ctxt
, ctxt
->node
, NULL
);
6023 * Remove all remaining vars from the stack.
6025 xsltLocalVariablePop(ctxt
, 0, -2);
6026 xsltShutdownCtxtExts(ctxt
);
6028 xsltCleanupTemplates(style
); /* TODO: <- style should be read only */
6031 * Now cleanup our variables so stylesheet can be re-used
6033 * TODO: this is not needed anymore global variables are copied
6034 * and not evaluated directly anymore, keep this as a check
6036 if (style
->variables
!= variables
) {
6037 vptr
= style
->variables
;
6038 while (vptr
->next
!= variables
)
6041 xsltFreeStackElemList(style
->variables
);
6042 style
->variables
= variables
;
6044 vptr
= style
->variables
;
6045 while (vptr
!= NULL
) {
6046 if (vptr
->computed
) {
6047 if (vptr
->value
!= NULL
) {
6048 xmlXPathFreeObject(vptr
->value
);
6057 * code disabled by wmb; awaiting kb's review
6058 * problem is that global variable(s) may contain xpath objects
6059 * from doc associated with RVT, so can't be freed at this point.
6060 * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
6061 * I assume this shouldn't be required at this point.
6064 * Free all remaining tree fragments.
6069 * Do some post processing work depending on the generated output
6071 root
= xmlDocGetRootElement(res
);
6073 const xmlChar
*doctype
= NULL
;
6075 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
))
6076 doctype
= xmlDictQLookup(ctxt
->dict
, root
->ns
->prefix
, root
->name
);
6077 if (doctype
== NULL
)
6078 doctype
= root
->name
;
6081 * Apply the default selection of the method
6083 if ((method
== NULL
) &&
6084 (root
->ns
== NULL
) &&
6085 (!xmlStrcasecmp(root
->name
, (const xmlChar
*) "html"))) {
6088 tmp
= res
->children
;
6089 while ((tmp
!= NULL
) && (tmp
!= root
)) {
6090 if (tmp
->type
== XML_ELEMENT_NODE
)
6092 if ((tmp
->type
== XML_TEXT_NODE
) && (!xmlIsBlankNode(tmp
)))
6097 ctxt
->type
= XSLT_OUTPUT_HTML
;
6099 * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
6100 * transformation on the doc, but functions like
6102 res
->type
= XML_HTML_DOCUMENT_NODE
;
6103 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
6104 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
6107 #ifdef XSLT_GENERATE_HTML_DOCTYPE
6108 } else if (version
!= NULL
) {
6109 xsltGetHTMLIDs(version
, &doctypePublic
,
6111 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
6113 xmlCreateIntSubset(res
, doctype
,
6121 if (ctxt
->type
== XSLT_OUTPUT_XML
) {
6122 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
6123 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
6124 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
6126 /* Need a small "hack" here to assure DTD comes before
6127 possible comment nodes */
6128 node
= res
->children
;
6130 res
->children
= NULL
;
6132 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
6135 if (res
->children
!= NULL
) {
6136 res
->children
->next
= node
;
6137 node
->prev
= res
->children
;
6140 res
->children
= node
;
6146 xmlXPathFreeNodeSet(ctxt
->nodeList
);
6147 if (profile
!= NULL
) {
6148 xsltSaveProfiling(ctxt
, profile
);
6154 if ((ctxt
!= NULL
) && (ctxt
->state
== XSLT_STATE_ERROR
)) {
6158 if ((res
!= NULL
) && (ctxt
!= NULL
) && (output
!= NULL
)) {
6161 ret
= xsltCheckWrite(ctxt
->sec
, ctxt
, (const xmlChar
*) output
);
6163 xsltTransformError(ctxt
, NULL
, NULL
,
6164 "xsltApplyStylesheet: forbidden to save to %s\n",
6166 } else if (ret
< 0) {
6167 xsltTransformError(ctxt
, NULL
, NULL
,
6168 "xsltApplyStylesheet: saving to %s may not be possible\n",
6173 #ifdef XSLT_DEBUG_PROFILE_CACHE
6174 printf("# Cache:\n");
6175 printf("# Reused tree fragments: %d\n", ctxt
->cache
->dbgReusedRVTs
);
6176 printf("# Reused variables : %d\n", ctxt
->cache
->dbgReusedVars
);
6179 if ((ctxt
!= NULL
) && (userCtxt
== NULL
))
6180 xsltFreeTransformContext(ctxt
);
6188 #ifdef XSLT_DEBUG_PROFILE_CACHE
6189 printf("# Cache:\n");
6190 printf("# Reused tree fragments: %d\n", ctxt
->cache
->dbgReusedRVTs
);
6191 printf("# Reused variables : %d\n", ctxt
->cache
->dbgReusedVars
);
6194 if ((ctxt
!= NULL
) && (userCtxt
== NULL
))
6195 xsltFreeTransformContext(ctxt
);
6200 * xsltApplyStylesheet:
6201 * @style: a parsed XSLT stylesheet
6202 * @doc: a parsed XML document
6203 * @params: a NULL terminated arry of parameters names/values tuples
6205 * Apply the stylesheet to the document
6206 * NOTE: This may lead to a non-wellformed output XML wise !
6208 * Returns the result document or NULL in case of error
6211 xsltApplyStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6212 const char **params
)
6214 return (xsltApplyStylesheetInternal(style
, doc
, params
, NULL
, NULL
, NULL
));
6218 * xsltProfileStylesheet:
6219 * @style: a parsed XSLT stylesheet
6220 * @doc: a parsed XML document
6221 * @params: a NULL terminated arry of parameters names/values tuples
6222 * @output: a FILE * for the profiling output
6224 * Apply the stylesheet to the document and dump the profiling to
6227 * Returns the result document or NULL in case of error
6230 xsltProfileStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6231 const char **params
, FILE * output
)
6235 res
= xsltApplyStylesheetInternal(style
, doc
, params
, NULL
, output
, NULL
);
6240 * xsltApplyStylesheetUser:
6241 * @style: a parsed XSLT stylesheet
6242 * @doc: a parsed XML document
6243 * @params: a NULL terminated array of parameters names/values tuples
6244 * @output: the targetted output
6245 * @profile: profile FILE * output or NULL
6246 * @userCtxt: user provided transform context
6248 * Apply the stylesheet to the document and allow the user to provide
6249 * its own transformation context.
6251 * Returns the result document or NULL in case of error
6254 xsltApplyStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
,
6255 const char **params
, const char *output
,
6256 FILE * profile
, xsltTransformContextPtr userCtxt
)
6260 res
= xsltApplyStylesheetInternal(style
, doc
, params
, output
,
6266 * xsltRunStylesheetUser:
6267 * @style: a parsed XSLT stylesheet
6268 * @doc: a parsed XML document
6269 * @params: a NULL terminated array of parameters names/values tuples
6270 * @output: the URL/filename ot the generated resource if available
6271 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6272 * @IObuf: an output buffer for progressive output (not implemented yet)
6273 * @profile: profile FILE * output or NULL
6274 * @userCtxt: user provided transform context
6276 * Apply the stylesheet to the document and generate the output according
6277 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6279 * NOTE: This may lead to a non-wellformed output XML wise !
6280 * NOTE: This may also result in multiple files being generated
6281 * NOTE: using IObuf, the result encoding used will be the one used for
6282 * creating the output buffer, use the following macro to read it
6283 * from the stylesheet
6284 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6285 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6286 * since the interface uses only UTF8
6288 * Returns the number of by written to the main resource or -1 in case of
6292 xsltRunStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
,
6293 const char **params
, const char *output
,
6294 xmlSAXHandlerPtr SAX
, xmlOutputBufferPtr IObuf
,
6295 FILE * profile
, xsltTransformContextPtr userCtxt
)
6300 if ((output
== NULL
) && (SAX
== NULL
) && (IObuf
== NULL
))
6302 if ((SAX
!= NULL
) && (IObuf
!= NULL
))
6305 /* unsupported yet */
6307 XSLT_TODO
/* xsltRunStylesheet xmlSAXHandlerPtr SAX */
6311 tmp
= xsltApplyStylesheetInternal(style
, doc
, params
, output
, profile
,
6314 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
6315 "xsltRunStylesheet : run failed\n");
6318 if (IObuf
!= NULL
) {
6319 /* TODO: incomplete, IObuf output not progressive */
6320 ret
= xsltSaveResultTo(IObuf
, tmp
, style
);
6322 ret
= xsltSaveResultToFilename(output
, tmp
, style
, 0);
6329 * xsltRunStylesheet:
6330 * @style: a parsed XSLT stylesheet
6331 * @doc: a parsed XML document
6332 * @params: a NULL terminated array of parameters names/values tuples
6333 * @output: the URL/filename ot the generated resource if available
6334 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6335 * @IObuf: an output buffer for progressive output (not implemented yet)
6337 * Apply the stylesheet to the document and generate the output according
6338 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6340 * NOTE: This may lead to a non-wellformed output XML wise !
6341 * NOTE: This may also result in multiple files being generated
6342 * NOTE: using IObuf, the result encoding used will be the one used for
6343 * creating the output buffer, use the following macro to read it
6344 * from the stylesheet
6345 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6346 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6347 * since the interface uses only UTF8
6349 * Returns the number of bytes written to the main resource or -1 in case of
6353 xsltRunStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6354 const char **params
, const char *output
,
6355 xmlSAXHandlerPtr SAX
, xmlOutputBufferPtr IObuf
)
6357 return(xsltRunStylesheetUser(style
, doc
, params
, output
, SAX
, IObuf
,
6362 * xsltRegisterAllElement:
6363 * @ctxt: the XPath context
6365 * Registers all default XSLT elements in this context
6368 xsltRegisterAllElement(xsltTransformContextPtr ctxt
)
6370 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "apply-templates",
6372 (xsltTransformFunction
) xsltApplyTemplates
);
6373 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "apply-imports",
6375 (xsltTransformFunction
) xsltApplyImports
);
6376 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "call-template",
6378 (xsltTransformFunction
) xsltCallTemplate
);
6379 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "element",
6381 (xsltTransformFunction
) xsltElement
);
6382 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "attribute",
6384 (xsltTransformFunction
) xsltAttribute
);
6385 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "text",
6387 (xsltTransformFunction
) xsltText
);
6388 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "processing-instruction",
6390 (xsltTransformFunction
) xsltProcessingInstruction
);
6391 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "comment",
6393 (xsltTransformFunction
) xsltComment
);
6394 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "copy",
6396 (xsltTransformFunction
) xsltCopy
);
6397 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "value-of",
6399 (xsltTransformFunction
) xsltValueOf
);
6400 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "number",
6402 (xsltTransformFunction
) xsltNumber
);
6403 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "for-each",
6405 (xsltTransformFunction
) xsltForEach
);
6406 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "if",
6408 (xsltTransformFunction
) xsltIf
);
6409 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "choose",
6411 (xsltTransformFunction
) xsltChoose
);
6412 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "sort",
6414 (xsltTransformFunction
) xsltSort
);
6415 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "copy-of",
6417 (xsltTransformFunction
) xsltCopyOf
);
6418 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "message",
6420 (xsltTransformFunction
) xsltMessage
);
6423 * Those don't have callable entry points but are registered anyway
6425 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "variable",
6427 (xsltTransformFunction
) xsltDebug
);
6428 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "param",
6430 (xsltTransformFunction
) xsltDebug
);
6431 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "with-param",
6433 (xsltTransformFunction
) xsltDebug
);
6434 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "decimal-format",
6436 (xsltTransformFunction
) xsltDebug
);
6437 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "when",
6439 (xsltTransformFunction
) xsltDebug
);
6440 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "otherwise",
6442 (xsltTransformFunction
) xsltDebug
);
6443 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "fallback",
6445 (xsltTransformFunction
) xsltDebug
);