2 * transform.c: Implementation of the XSL Transformation 1.0 engine
3 * transform part, i.e. applying a Stylesheet to a document
6 * http://www.w3.org/TR/1999/REC-xslt-19991116
8 * Michael Kay "XSLT Programmer's Reference" pp 637-643
9 * Writing Multiple Output Files
11 * XSLT-1.1 Working Draft
12 * http://www.w3.org/TR/xslt11#multiple-output
14 * See Copyright for the status of this software.
21 #include <libxml/debugXML.h>
23 #ifdef WITH_XSLT_DEBUG
24 #define WITH_XSLT_DEBUG_EXTRA
25 #define WITH_XSLT_DEBUG_PROCESS
26 #define WITH_XSLT_DEBUG_VARIABLE
29 #define XSLT_GENERATE_HTML_DOCTYPE
30 #ifdef XSLT_GENERATE_HTML_DOCTYPE
31 static int xsltGetHTMLIDs(const xmlChar
*version
, const xmlChar
**publicID
,
32 const xmlChar
**systemID
);
35 int xsltMaxDepth
= 3000;
36 int xsltMaxVars
= 15000;
43 # define FALSE (0 == 1)
44 # define TRUE (!FALSE)
47 #define IS_BLANK_NODE(n) \
48 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
52 * Forward declarations
56 xsltCopyNamespaceListInternal(xmlNodePtr node
, xmlNsPtr cur
);
59 xsltCopyTree(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
60 xmlNodePtr node
, xmlNodePtr insert
, int isLRE
,
64 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt
,
65 xmlNodePtr contextNode
, xmlNodePtr list
,
66 xsltTemplatePtr templ
);
69 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt
,
70 xmlNodePtr contextNode
,
72 xsltTemplatePtr templ
,
73 xsltStackElemPtr withParams
);
77 * @ctxt: the transformation context
78 * @value: the template to push on the stack
80 * Push a template on the stack
82 * Returns the new index in the stack or 0 in case of error
85 templPush(xsltTransformContextPtr ctxt
, xsltTemplatePtr value
)
87 if (ctxt
->templMax
== 0) {
90 (xsltTemplatePtr
*) xmlMalloc(ctxt
->templMax
*
91 sizeof(ctxt
->templTab
[0]));
92 if (ctxt
->templTab
== NULL
) {
93 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
97 else if (ctxt
->templNr
>= ctxt
->templMax
) {
100 (xsltTemplatePtr
*) xmlRealloc(ctxt
->templTab
,
102 sizeof(ctxt
->templTab
[0]));
103 if (ctxt
->templTab
== NULL
) {
104 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
108 ctxt
->templTab
[ctxt
->templNr
] = value
;
110 return (ctxt
->templNr
++);
114 * @ctxt: the transformation context
116 * Pop a template value from the stack
118 * Returns the stored template value
120 static xsltTemplatePtr
121 templPop(xsltTransformContextPtr ctxt
)
125 if (ctxt
->templNr
<= 0)
128 if (ctxt
->templNr
> 0)
129 ctxt
->templ
= ctxt
->templTab
[ctxt
->templNr
- 1];
131 ctxt
->templ
= (xsltTemplatePtr
) 0;
132 ret
= ctxt
->templTab
[ctxt
->templNr
];
133 ctxt
->templTab
[ctxt
->templNr
] = 0;
138 * xsltLocalVariablePop:
139 * @ctxt: the transformation context
140 * @limitNr: number of variables which should remain
141 * @level: the depth in the xsl:template's tree
143 * Pops all variable values at the given @depth from the stack.
145 * Returns the stored variable value
147 * This is an internal routine and should not be called by users!
150 xsltLocalVariablePop(xsltTransformContextPtr ctxt
, int limitNr
, int level
)
152 xsltStackElemPtr variable
;
154 if (ctxt
->varsNr
<= 0)
158 if (ctxt
->varsNr
<= limitNr
)
160 variable
= ctxt
->varsTab
[ctxt
->varsNr
- 1];
161 if (variable
->level
<= level
)
163 if (variable
->level
>= 0)
164 xsltFreeStackElemList(variable
);
166 } while (ctxt
->varsNr
!= 0);
167 if (ctxt
->varsNr
> 0)
168 ctxt
->vars
= ctxt
->varsTab
[ctxt
->varsNr
- 1];
174 * xsltTemplateParamsCleanup:
176 * Removes xsl:param and xsl:with-param items from the
177 * variable-stack. Only xsl:with-param items are not freed.
180 xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt
)
182 xsltStackElemPtr param
;
184 for (; ctxt
->varsNr
> ctxt
->varsBase
; ctxt
->varsNr
--) {
185 param
= ctxt
->varsTab
[ctxt
->varsNr
-1];
187 * Free xsl:param items.
188 * xsl:with-param items will have a level of -1 or -2.
190 if (param
->level
>= 0) {
191 xsltFreeStackElemList(param
);
194 if (ctxt
->varsNr
> 0)
195 ctxt
->vars
= ctxt
->varsTab
[ctxt
->varsNr
- 1];
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 static 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 ************************************************************************/
738 * @parent: the parent node
739 * @cur: the child node
741 * Wrapper version of xmlAddChild with a more consistent behaviour on
742 * error. One expect the use to be child = xsltAddChild(parent, child);
743 * and the routine will take care of not leaking on errors or node merge
745 * Returns the child is successfully attached or NULL if merged or freed
748 xsltAddChild(xmlNodePtr parent
, xmlNodePtr cur
) {
753 if (parent
== NULL
) {
757 ret
= xmlAddChild(parent
, cur
);
764 * @ctxt: a XSLT process context
765 * @target: the text node where the text will be attached
766 * @string: the text string
767 * @len: the string length in byte
769 * Extend the current text node with the new string, it handles coalescing
771 * Returns: the text node
774 xsltAddTextString(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
775 const xmlChar
*string
, int len
) {
779 if ((len
<= 0) || (string
== NULL
) || (target
== NULL
))
782 if (ctxt
->lasttext
== target
->content
) {
785 /* Check for integer overflow accounting for NUL terminator. */
786 if (len
>= INT_MAX
- ctxt
->lasttuse
) {
787 xsltTransformError(ctxt
, NULL
, target
,
788 "xsltCopyText: text allocation failed\n");
791 minSize
= ctxt
->lasttuse
+ len
+ 1;
793 if (ctxt
->lasttsize
< minSize
) {
798 /* Double buffer size but increase by at least 100 bytes. */
799 extra
= minSize
< 100 ? 100 : minSize
;
801 /* Check for integer overflow. */
802 if (extra
> INT_MAX
- ctxt
->lasttsize
) {
806 size
= ctxt
->lasttsize
+ extra
;
809 newbuf
= (xmlChar
*) xmlRealloc(target
->content
,size
);
810 if (newbuf
== NULL
) {
811 xsltTransformError(ctxt
, NULL
, target
,
812 "xsltCopyText: text allocation failed\n");
815 ctxt
->lasttsize
= size
;
816 ctxt
->lasttext
= newbuf
;
817 target
->content
= newbuf
;
819 memcpy(&(target
->content
[ctxt
->lasttuse
]), string
, len
);
820 ctxt
->lasttuse
+= len
;
821 target
->content
[ctxt
->lasttuse
] = 0;
823 xmlNodeAddContent(target
, string
);
824 ctxt
->lasttext
= target
->content
;
825 len
= xmlStrlen(target
->content
);
826 ctxt
->lasttsize
= len
;
827 ctxt
->lasttuse
= len
;
833 * xsltCopyTextString:
834 * @ctxt: a XSLT process context
835 * @target: the element where the text will be attached
836 * @string: the text string
837 * @noescape: should disable-escaping be activated for this text node.
839 * Adds @string to a newly created or an existent text node child of
842 * Returns: the text node, where the text content of @cur is copied to.
843 * NULL in case of API or internal errors.
846 xsltCopyTextString(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
847 const xmlChar
*string
, int noescape
)
855 #ifdef WITH_XSLT_DEBUG_PROCESS
856 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
857 "xsltCopyTextString: copy text %s\n",
862 * Play safe and reset the merging mechanism for every new
865 if ((target
== NULL
) || (target
->children
== NULL
)) {
866 ctxt
->lasttext
= NULL
;
869 /* handle coalescing of text nodes here */
870 len
= xmlStrlen(string
);
871 if ((ctxt
->type
== XSLT_OUTPUT_XML
) &&
872 (ctxt
->style
->cdataSection
!= NULL
) &&
874 (target
->type
== XML_ELEMENT_NODE
) &&
875 (((target
->ns
== NULL
) &&
876 (xmlHashLookup2(ctxt
->style
->cdataSection
,
877 target
->name
, NULL
) != NULL
)) ||
878 ((target
->ns
!= NULL
) &&
879 (xmlHashLookup2(ctxt
->style
->cdataSection
,
880 target
->name
, target
->ns
->href
) != NULL
))))
883 * Process "cdata-section-elements".
885 if ((target
->last
!= NULL
) &&
886 (target
->last
->type
== XML_CDATA_SECTION_NODE
))
888 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
890 copy
= xmlNewCDataBlock(ctxt
->output
, string
, len
);
891 } else if (noescape
) {
893 * Process "disable-output-escaping".
895 if ((target
!= NULL
) && (target
->last
!= NULL
) &&
896 (target
->last
->type
== XML_TEXT_NODE
) &&
897 (target
->last
->name
== xmlStringTextNoenc
))
899 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
901 copy
= xmlNewTextLen(string
, len
);
903 copy
->name
= xmlStringTextNoenc
;
906 * Default processing.
908 if ((target
!= NULL
) && (target
->last
!= NULL
) &&
909 (target
->last
->type
== XML_TEXT_NODE
) &&
910 (target
->last
->name
== xmlStringText
)) {
911 return(xsltAddTextString(ctxt
, target
->last
, string
, len
));
913 copy
= xmlNewTextLen(string
, len
);
915 if (copy
!= NULL
&& target
!= NULL
)
916 copy
= xsltAddChild(target
, copy
);
918 ctxt
->lasttext
= copy
->content
;
919 ctxt
->lasttsize
= len
;
920 ctxt
->lasttuse
= len
;
922 xsltTransformError(ctxt
, NULL
, target
,
923 "xsltCopyTextString: text copy failed\n");
924 ctxt
->lasttext
= NULL
;
931 * @ctxt: a XSLT process context
932 * @target: the element where the text will be attached
933 * @cur: the text or CDATA node
934 * @interned: the string is in the target doc dictionary
936 * Copy the text content of @cur and append it to @target's children.
938 * Returns: the text node, where the text content of @cur is copied to.
939 * NULL in case of API or internal errors.
942 xsltCopyText(xsltTransformContextPtr ctxt
, xmlNodePtr target
,
943 xmlNodePtr cur
, int interned
)
947 if ((cur
->type
!= XML_TEXT_NODE
) &&
948 (cur
->type
!= XML_CDATA_SECTION_NODE
))
950 if (cur
->content
== NULL
)
953 #ifdef WITH_XSLT_DEBUG_PROCESS
954 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
955 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
956 "xsltCopyText: copy CDATA text %s\n",
958 } else if (cur
->name
== xmlStringTextNoenc
) {
959 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
960 "xsltCopyText: copy unescaped text %s\n",
963 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_TEXT
,xsltGenericDebug(xsltGenericDebugContext
,
964 "xsltCopyText: copy text %s\n",
970 * Play save and reset the merging mechanism for every new
973 if ((target
== NULL
) || (target
->children
== NULL
)) {
974 ctxt
->lasttext
= NULL
;
977 if ((ctxt
->style
->cdataSection
!= NULL
) &&
978 (ctxt
->type
== XSLT_OUTPUT_XML
) &&
980 (target
->type
== XML_ELEMENT_NODE
) &&
981 (((target
->ns
== NULL
) &&
982 (xmlHashLookup2(ctxt
->style
->cdataSection
,
983 target
->name
, NULL
) != NULL
)) ||
984 ((target
->ns
!= NULL
) &&
985 (xmlHashLookup2(ctxt
->style
->cdataSection
,
986 target
->name
, target
->ns
->href
) != NULL
))))
989 * Process "cdata-section-elements".
992 * OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
995 * TODO: Since this doesn't merge adjacent CDATA-section nodes,
996 * we'll get: <![CDATA[x]]><!CDATA[y]]>.
997 * TODO: Reported in #321505.
999 if ((target
->last
!= NULL
) &&
1000 (target
->last
->type
== XML_CDATA_SECTION_NODE
))
1003 * Append to existing CDATA-section node.
1005 copy
= xsltAddTextString(ctxt
, target
->last
, cur
->content
,
1006 xmlStrlen(cur
->content
));
1011 len
= xmlStrlen(cur
->content
);
1012 copy
= xmlNewCDataBlock(ctxt
->output
, cur
->content
, len
);
1015 ctxt
->lasttext
= copy
->content
;
1016 ctxt
->lasttsize
= len
;
1017 ctxt
->lasttuse
= len
;
1019 } else if ((target
!= NULL
) &&
1020 (target
->last
!= NULL
) &&
1021 /* both escaped or both non-escaped text-nodes */
1022 (((target
->last
->type
== XML_TEXT_NODE
) &&
1023 (target
->last
->name
== cur
->name
)) ||
1024 /* non-escaped text nodes and CDATA-section nodes */
1025 (((target
->last
->type
== XML_CDATA_SECTION_NODE
) &&
1026 (cur
->name
== xmlStringTextNoenc
)))))
1029 * we are appending to an existing text node
1031 copy
= xsltAddTextString(ctxt
, target
->last
, cur
->content
,
1032 xmlStrlen(cur
->content
));
1034 } else if ((interned
) && (target
!= NULL
) &&
1035 (target
->doc
!= NULL
) &&
1036 (target
->doc
->dict
== ctxt
->dict
))
1039 * TODO: DO we want to use this also for "text" output?
1041 copy
= xmlNewTextLen(NULL
, 0);
1044 if (cur
->name
== xmlStringTextNoenc
)
1045 copy
->name
= xmlStringTextNoenc
;
1048 * Must confirm that content is in dict (bug 302821)
1049 * TODO: This check should be not needed for text coming
1050 * from the stylesheets
1052 if (xmlDictOwns(ctxt
->dict
, cur
->content
))
1053 copy
->content
= cur
->content
;
1055 if ((copy
->content
= xmlStrdup(cur
->content
)) == NULL
)
1060 * normal processing. keep counters to extend the text node
1061 * in xsltAddTextString if needed.
1065 len
= xmlStrlen(cur
->content
);
1066 copy
= xmlNewTextLen(cur
->content
, len
);
1069 if (cur
->name
== xmlStringTextNoenc
)
1070 copy
->name
= xmlStringTextNoenc
;
1071 ctxt
->lasttext
= copy
->content
;
1072 ctxt
->lasttsize
= len
;
1073 ctxt
->lasttuse
= len
;
1076 if (target
!= NULL
) {
1077 copy
->doc
= target
->doc
;
1079 * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
1080 * to ensure that the optimized text-merging mechanism
1081 * won't interfere with normal node-merging in any case.
1083 copy
= xsltAddChild(target
, copy
);
1086 xsltTransformError(ctxt
, NULL
, target
,
1087 "xsltCopyText: text copy failed\n");
1091 if ((copy
== NULL
) || (copy
->content
== NULL
)) {
1092 xsltTransformError(ctxt
, NULL
, target
,
1093 "Internal error in xsltCopyText(): "
1094 "Failed to copy the string.\n");
1095 ctxt
->state
= XSLT_STATE_STOPPED
;
1101 * xsltShallowCopyAttr:
1102 * @ctxt: a XSLT process context
1103 * @invocNode: responsible node in the stylesheet; used for error reports
1104 * @target: the element where the attribute will be grafted
1105 * @attr: the attribute to be copied
1107 * Do a copy of an attribute.
1113 * Returns: a new xmlAttrPtr, or NULL in case of error.
1116 xsltShallowCopyAttr(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1117 xmlNodePtr target
, xmlAttrPtr attr
)
1125 if (target
->type
!= XML_ELEMENT_NODE
) {
1126 xsltTransformError(ctxt
, NULL
, invocNode
,
1127 "Cannot add an attribute node to a non-element node.\n");
1131 if (target
->children
!= NULL
) {
1132 xsltTransformError(ctxt
, NULL
, invocNode
,
1133 "Attribute nodes must be added before "
1134 "any child nodes to an element.\n");
1138 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1139 if (attr
->ns
!= NULL
) {
1142 ns
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1143 attr
->ns
->href
, attr
->ns
->prefix
, target
);
1145 xsltTransformError(ctxt
, NULL
, invocNode
,
1146 "Namespace fixup error: Failed to acquire an in-scope "
1147 "namespace binding of the copied attribute '{%s}%s'.\n",
1148 attr
->ns
->href
, attr
->name
);
1150 * TODO: Should we just stop here?
1154 * Note that xmlSetNsProp() will take care of duplicates
1155 * and assigns the new namespace even to a duplicate.
1157 copy
= xmlSetNsProp(target
, ns
, attr
->name
, value
);
1159 copy
= xmlSetNsProp(target
, NULL
, attr
->name
, value
);
1169 * NOTE: This was optimized according to bug #342695.
1170 * TODO: Can this further be optimized, if source and target
1171 * share the same dict and attr->children is just 1 text node
1172 * which is in the dict? How probable is such a case?
1175 * TODO: Do we need to create an empty text node if the value
1176 * is the empty string?
1178 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1179 if (value
!= NULL
) {
1180 txtNode
= xmlNewDocText(target
->doc
, NULL
);
1181 if (txtNode
== NULL
)
1183 if ((target
->doc
!= NULL
) &&
1184 (target
->doc
->dict
!= NULL
))
1187 (xmlChar
*) xmlDictLookup(target
->doc
->dict
,
1188 BAD_CAST value
, -1);
1191 txtNode
->content
= value
;
1192 copy
->children
= txtNode
;
1200 * xsltCopyAttrListNoOverwrite:
1201 * @ctxt: a XSLT process context
1202 * @invocNode: responsible node in the stylesheet; used for error reports
1203 * @target: the element where the new attributes will be grafted
1204 * @attr: the first attribute in the list to be copied
1206 * Copies a list of attribute nodes, starting with @attr, over to the
1207 * @target element node.
1212 * Returns 0 on success and -1 on errors and internal errors.
1215 xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt
,
1216 xmlNodePtr invocNode
,
1217 xmlNodePtr target
, xmlAttrPtr attr
)
1220 xmlNsPtr origNs
= NULL
, copyNs
= NULL
;
1224 * Don't use xmlCopyProp() here, since it will try to
1225 * reconciliate namespaces.
1227 while (attr
!= NULL
) {
1229 * Find a namespace node in the tree of @target.
1230 * Avoid searching for the same ns.
1232 if (attr
->ns
!= origNs
) {
1234 if (attr
->ns
!= NULL
) {
1235 copyNs
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1236 attr
->ns
->href
, attr
->ns
->prefix
, target
);
1243 * If attribute has a value, we need to copy it (watching out
1244 * for possible entities)
1246 if ((attr
->children
) && (attr
->children
->type
== XML_TEXT_NODE
) &&
1247 (attr
->children
->next
== NULL
)) {
1248 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
,
1249 attr
->children
->content
);
1250 } else if (attr
->children
!= NULL
) {
1251 value
= xmlNodeListGetString(attr
->doc
, attr
->children
, 1);
1252 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
, BAD_CAST value
);
1255 copy
= xmlNewNsProp(target
, copyNs
, attr
->name
, NULL
);
1267 * xsltShallowCopyElem:
1268 * @ctxt: the XSLT process context
1269 * @node: the element node in the source tree
1270 * or the Literal Result Element
1271 * @insert: the parent in the result tree
1272 * @isLRE: if @node is a Literal Result Element
1274 * Make a copy of the element node @node
1275 * and insert it as last child of @insert.
1277 * URGENT TODO: The problem with this one (for the non-refactored code)
1278 * is that it is used for both, Literal Result Elements *and*
1279 * copying input nodes.
1281 * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
1284 * xsltApplySequenceConstructor()
1285 * (for Literal Result Elements - which is a problem)
1286 * xsltCopy() (for shallow-copying elements via xsl:copy)
1288 * Returns a pointer to the new node, or NULL in case of error
1291 xsltShallowCopyElem(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1292 xmlNodePtr insert
, int isLRE
)
1296 if ((node
->type
== XML_DTD_NODE
) || (insert
== NULL
))
1298 if ((node
->type
== XML_TEXT_NODE
) ||
1299 (node
->type
== XML_CDATA_SECTION_NODE
))
1300 return(xsltCopyText(ctxt
, insert
, node
, 0));
1302 copy
= xmlDocCopyNode(node
, insert
->doc
, 0);
1304 copy
->doc
= ctxt
->output
;
1305 copy
= xsltAddChild(insert
, copy
);
1307 xsltTransformError(ctxt
, NULL
, node
,
1308 "xsltShallowCopyElem: copy failed\n");
1312 if (node
->type
== XML_ELEMENT_NODE
) {
1314 * Add namespaces as they are needed
1316 if (node
->nsDef
!= NULL
) {
1318 * TODO: Remove the LRE case in the refactored code
1322 xsltCopyNamespaceList(ctxt
, copy
, node
->nsDef
);
1324 xsltCopyNamespaceListInternal(copy
, node
->nsDef
);
1328 * URGENT TODO: The problem with this is that it does not
1329 * copy over all namespace nodes in scope.
1330 * The damn thing about this is, that we would need to
1331 * use the xmlGetNsList(), for every single node; this is
1332 * also done in xsltCopyTree(), but only for the top node.
1334 if (node
->ns
!= NULL
) {
1337 * REVISIT TODO: Since the non-refactored code still does
1338 * ns-aliasing, we need to call xsltGetNamespace() here.
1339 * Remove this when ready.
1341 copy
->ns
= xsltGetNamespace(ctxt
, node
, node
->ns
, copy
);
1343 copy
->ns
= xsltGetSpecialNamespace(ctxt
,
1344 node
, node
->ns
->href
, node
->ns
->prefix
, copy
);
1347 } else if ((insert
->type
== XML_ELEMENT_NODE
) &&
1348 (insert
->ns
!= NULL
))
1351 * "Undeclare" the default namespace.
1353 xsltGetSpecialNamespace(ctxt
, node
, NULL
, NULL
, copy
);
1357 xsltTransformError(ctxt
, NULL
, node
,
1358 "xsltShallowCopyElem: copy %s failed\n", node
->name
);
1365 * @ctxt: a XSLT process context
1366 * @invocNode: responsible node in the stylesheet; used for error reports
1367 * @list: the list of element nodes in the source tree.
1368 * @insert: the parent in the result tree.
1369 * @isLRE: is this a literal result element list
1370 * @topElemVisited: indicates if a top-most element was already processed
1372 * Make a copy of the full list of tree @list
1373 * and insert it as last children of @insert
1375 * NOTE: Not to be used for Literal Result Elements.
1380 * Returns a pointer to the new list, or NULL in case of error
1383 xsltCopyTreeList(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1385 xmlNodePtr insert
, int isLRE
, int topElemVisited
)
1387 xmlNodePtr copy
, ret
= NULL
;
1389 while (list
!= NULL
) {
1390 copy
= xsltCopyTree(ctxt
, invocNode
,
1391 list
, insert
, isLRE
, topElemVisited
);
1403 * xsltCopyNamespaceListInternal:
1404 * @node: the target node
1405 * @cur: the first namespace
1407 * Do a copy of a namespace list. If @node is non-NULL the
1408 * new namespaces are added automatically.
1412 * QUESTION: What is the exact difference between this function
1413 * and xsltCopyNamespaceList() in "namespaces.c"?
1414 * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
1416 * Returns: a new xmlNsPtr, or NULL in case of error.
1419 xsltCopyNamespaceListInternal(xmlNodePtr elem
, xmlNsPtr ns
) {
1420 xmlNsPtr ret
= NULL
;
1421 xmlNsPtr p
= NULL
, q
, luNs
;
1426 * One can add namespaces only on element nodes
1428 if ((elem
!= NULL
) && (elem
->type
!= XML_ELEMENT_NODE
))
1432 if (ns
->type
!= XML_NAMESPACE_DECL
)
1435 * Avoid duplicating namespace declarations on the tree.
1438 if ((elem
->ns
!= NULL
) &&
1439 xmlStrEqual(elem
->ns
->prefix
, ns
->prefix
) &&
1440 xmlStrEqual(elem
->ns
->href
, ns
->href
))
1445 luNs
= xmlSearchNs(elem
->doc
, elem
, ns
->prefix
);
1446 if ((luNs
!= NULL
) && (xmlStrEqual(luNs
->href
, ns
->href
)))
1452 q
= xmlNewNs(elem
, ns
->href
, ns
->prefix
);
1455 } else if (q
!= NULL
) {
1460 } while (ns
!= NULL
);
1465 * xsltShallowCopyNsNode:
1466 * @ctxt: the XSLT transformation context
1467 * @invocNode: responsible node in the stylesheet; used for error reports
1468 * @insert: the target element node in the result tree
1469 * @ns: the namespace node
1471 * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
1473 * Returns a new/existing ns-node, or NULL.
1476 xsltShallowCopyNsNode(xsltTransformContextPtr ctxt
,
1477 xmlNodePtr invocNode
,
1482 * TODO: Contrary to header comments, this is declared as int.
1483 * be modified to return a node pointer, or NULL if any error
1487 if ((insert
== NULL
) || (insert
->type
!= XML_ELEMENT_NODE
))
1490 if (insert
->children
!= NULL
) {
1491 xsltTransformError(ctxt
, NULL
, invocNode
,
1492 "Namespace nodes must be added before "
1493 "any child nodes are added to an element.\n");
1497 * BIG NOTE: Xalan-J simply overwrites any ns-decls with
1498 * an equal prefix. We definitively won't do that.
1500 * MSXML 4.0 and the .NET ignores ns-decls for which an
1501 * equal prefix is already in use.
1503 * Saxon raises an error like:
1504 * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
1505 * nodes with the same name".
1507 * NOTE: We'll currently follow MSXML here.
1508 * REVISIT TODO: Check if it's better to follow Saxon here.
1510 if (ns
->prefix
== NULL
) {
1512 * If we are adding ns-nodes to an element using e.g.
1513 * <xsl:copy-of select="/foo/namespace::*">, then we need
1514 * to ensure that we don't incorrectly declare a default
1515 * namespace on an element in no namespace, which otherwise
1516 * would move the element incorrectly into a namespace, if
1517 * the node tree is serialized.
1519 if (insert
->ns
== NULL
)
1521 } else if ((ns
->prefix
[0] == 'x') &&
1522 xmlStrEqual(ns
->prefix
, BAD_CAST
"xml"))
1525 * The XML namespace is built in.
1530 if (insert
->nsDef
!= NULL
) {
1531 tmpns
= insert
->nsDef
;
1533 if ((tmpns
->prefix
== NULL
) == (ns
->prefix
== NULL
)) {
1534 if ((tmpns
->prefix
== ns
->prefix
) ||
1535 xmlStrEqual(tmpns
->prefix
, ns
->prefix
))
1540 if (xmlStrEqual(tmpns
->href
, ns
->href
))
1545 tmpns
= tmpns
->next
;
1546 } while (tmpns
!= NULL
);
1548 tmpns
= xmlSearchNs(insert
->doc
, insert
, ns
->prefix
);
1549 if ((tmpns
!= NULL
) && xmlStrEqual(tmpns
->href
, ns
->href
))
1552 * Declare a new namespace.
1553 * TODO: The problem (wrt efficiency) with this xmlNewNs() is
1554 * that it will again search the already declared namespaces
1555 * for a duplicate :-/
1557 return(xmlNewNs(insert
, ns
->href
, ns
->prefix
));
1561 * TODO: We could as well raise an error here (like Saxon does),
1562 * or at least generate a warning.
1569 * @ctxt: the XSLT transformation context
1570 * @invocNode: responsible node in the stylesheet; used for error reports
1571 * @node: the element node in the source tree
1572 * @insert: the parent in the result tree
1573 * @isLRE: indicates if @node is a Literal Result Element
1574 * @topElemVisited: indicates if a top-most element was already processed
1576 * Make a copy of the full tree under the element node @node
1577 * and insert it as last child of @insert
1579 * NOTE: Not to be used for Literal Result Elements.
1584 * Returns a pointer to the new tree, or NULL in case of error
1587 xsltCopyTree(xsltTransformContextPtr ctxt
, xmlNodePtr invocNode
,
1588 xmlNodePtr node
, xmlNodePtr insert
, int isLRE
,
1595 switch (node
->type
) {
1596 case XML_ELEMENT_NODE
:
1597 case XML_ENTITY_REF_NODE
:
1598 case XML_ENTITY_NODE
:
1600 case XML_COMMENT_NODE
:
1601 case XML_DOCUMENT_NODE
:
1602 case XML_HTML_DOCUMENT_NODE
:
1603 #ifdef LIBXML_DOCB_ENABLED
1604 case XML_DOCB_DOCUMENT_NODE
:
1607 case XML_TEXT_NODE
: {
1608 int noenc
= (node
->name
== xmlStringTextNoenc
);
1609 return(xsltCopyTextString(ctxt
, insert
, node
->content
, noenc
));
1611 case XML_CDATA_SECTION_NODE
:
1612 return(xsltCopyTextString(ctxt
, insert
, node
->content
, 0));
1613 case XML_ATTRIBUTE_NODE
:
1615 xsltShallowCopyAttr(ctxt
, invocNode
, insert
, (xmlAttrPtr
) node
));
1616 case XML_NAMESPACE_DECL
:
1617 return((xmlNodePtr
) xsltShallowCopyNsNode(ctxt
, invocNode
,
1618 insert
, (xmlNsPtr
) node
));
1620 case XML_DOCUMENT_TYPE_NODE
:
1621 case XML_DOCUMENT_FRAG_NODE
:
1622 case XML_NOTATION_NODE
:
1624 case XML_ELEMENT_DECL
:
1625 case XML_ATTRIBUTE_DECL
:
1626 case XML_ENTITY_DECL
:
1627 case XML_XINCLUDE_START
:
1628 case XML_XINCLUDE_END
:
1631 if (XSLT_IS_RES_TREE_FRAG(node
)) {
1632 if (node
->children
!= NULL
)
1633 copy
= xsltCopyTreeList(ctxt
, invocNode
,
1634 node
->children
, insert
, 0, 0);
1639 copy
= xmlDocCopyNode(node
, insert
->doc
, 0);
1641 copy
->doc
= ctxt
->output
;
1642 copy
= xsltAddChild(insert
, copy
);
1644 xsltTransformError(ctxt
, NULL
, invocNode
,
1645 "xsltCopyTree: Copying of '%s' failed.\n", node
->name
);
1649 * The node may have been coalesced into another text node.
1651 if (insert
->last
!= copy
)
1652 return(insert
->last
);
1655 if (node
->type
== XML_ELEMENT_NODE
) {
1657 * Copy in-scope namespace nodes.
1659 * REVISIT: Since we try to reuse existing in-scope ns-decls by
1660 * using xmlSearchNsByHref(), this will eventually change
1661 * the prefix of an original ns-binding; thus it might
1662 * break QNames in element/attribute content.
1663 * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
1664 * context, plus a ns-lookup function, which writes directly
1665 * to a given list, then we wouldn't need to create/free the
1666 * nsList every time.
1668 if ((topElemVisited
== 0) &&
1669 (node
->parent
!= NULL
) &&
1670 (node
->parent
->type
!= XML_DOCUMENT_NODE
) &&
1671 (node
->parent
->type
!= XML_HTML_DOCUMENT_NODE
))
1673 xmlNsPtr
*nsList
, *curns
, ns
;
1676 * If this is a top-most element in a tree to be
1677 * copied, then we need to ensure that all in-scope
1678 * namespaces are copied over. For nodes deeper in the
1679 * tree, it is sufficient to reconcile only the ns-decls
1680 * (node->nsDef entries).
1683 nsList
= xmlGetNsList(node
->doc
, node
);
1684 if (nsList
!= NULL
) {
1688 * Search by prefix first in order to break as less
1689 * QNames in element/attribute content as possible.
1691 ns
= xmlSearchNs(insert
->doc
, insert
,
1695 (! xmlStrEqual(ns
->href
, (*curns
)->href
)))
1699 * Search by namespace name.
1700 * REVISIT TODO: Currently disabled.
1703 ns
= xmlSearchNsByHref(insert
->doc
,
1704 insert
, (*curns
)->href
);
1709 * Declare a new namespace on the copied element.
1711 ns
= xmlNewNs(copy
, (*curns
)->href
,
1713 /* TODO: Handle errors */
1715 if (node
->ns
== *curns
) {
1717 * If this was the original's namespace then set
1718 * the generated counterpart on the copy.
1723 } while (*curns
!= NULL
);
1726 } else if (node
->nsDef
!= NULL
) {
1728 * Copy over all namespace declaration attributes.
1730 if (node
->nsDef
!= NULL
) {
1732 xsltCopyNamespaceList(ctxt
, copy
, node
->nsDef
);
1734 xsltCopyNamespaceListInternal(copy
, node
->nsDef
);
1738 * Set the namespace.
1740 if (node
->ns
!= NULL
) {
1741 if (copy
->ns
== NULL
) {
1743 * This will map copy->ns to one of the newly created
1744 * in-scope ns-decls, OR create a new ns-decl on @copy.
1746 copy
->ns
= xsltGetSpecialNamespace(ctxt
, invocNode
,
1747 node
->ns
->href
, node
->ns
->prefix
, copy
);
1749 } else if ((insert
->type
== XML_ELEMENT_NODE
) &&
1750 (insert
->ns
!= NULL
))
1753 * "Undeclare" the default namespace on @copy with xmlns="".
1755 xsltGetSpecialNamespace(ctxt
, invocNode
, NULL
, NULL
, copy
);
1758 * Copy attribute nodes.
1760 if (node
->properties
!= NULL
) {
1761 xsltCopyAttrListNoOverwrite(ctxt
, invocNode
,
1762 copy
, node
->properties
);
1764 if (topElemVisited
== 0)
1770 if (node
->children
!= NULL
) {
1771 xsltCopyTreeList(ctxt
, invocNode
,
1772 node
->children
, copy
, isLRE
, topElemVisited
);
1775 xsltTransformError(ctxt
, NULL
, invocNode
,
1776 "xsltCopyTree: Copying of '%s' failed.\n", node
->name
);
1781 /************************************************************************
1783 * Error/fallback processing *
1785 ************************************************************************/
1788 * xsltApplyFallbacks:
1789 * @ctxt: a XSLT process context
1790 * @node: the node in the source tree.
1791 * @inst: the node generating the error
1793 * Process possible xsl:fallback nodes present under @inst
1795 * Returns the number of xsl:fallback element found and processed
1798 xsltApplyFallbacks(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1804 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) ||
1805 (inst
->children
== NULL
))
1808 child
= inst
->children
;
1809 while (child
!= NULL
) {
1810 if ((IS_XSLT_ELEM(child
)) &&
1811 (xmlStrEqual(child
->name
, BAD_CAST
"fallback"))) {
1812 #ifdef WITH_XSLT_DEBUG_PARSING
1813 xsltGenericDebug(xsltGenericDebugContext
,
1814 "applying xsl:fallback\n");
1817 xsltApplySequenceConstructor(ctxt
, node
, child
->children
,
1820 child
= child
->next
;
1825 /************************************************************************
1827 * Default processing *
1829 ************************************************************************/
1832 * xsltDefaultProcessOneNode:
1833 * @ctxt: a XSLT process context
1834 * @node: the node in the source tree.
1835 * @params: extra parameters passed to the template if any
1837 * Process the source node with the default built-in template rule:
1838 * <xsl:template match="*|/">
1839 * <xsl:apply-templates/>
1844 * <xsl:template match="text()|@*">
1845 * <xsl:value-of select="."/>
1848 * Note also that namespace declarations are copied directly:
1850 * the built-in template rule is the only template rule that is applied
1851 * for namespace nodes.
1854 xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1855 xsltStackElemPtr params
) {
1857 xmlNodePtr
delete = NULL
, cur
;
1858 int nbchild
= 0, oldSize
;
1859 int childno
= 0, oldPos
;
1860 xsltTemplatePtr
template;
1864 * Handling of leaves
1866 switch (node
->type
) {
1867 case XML_DOCUMENT_NODE
:
1868 case XML_HTML_DOCUMENT_NODE
:
1869 case XML_ELEMENT_NODE
:
1871 case XML_CDATA_SECTION_NODE
:
1872 #ifdef WITH_XSLT_DEBUG_PROCESS
1873 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1874 "xsltDefaultProcessOneNode: copy CDATA %s\n",
1877 copy
= xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
1879 xsltTransformError(ctxt
, NULL
, node
,
1880 "xsltDefaultProcessOneNode: cdata copy failed\n");
1884 #ifdef WITH_XSLT_DEBUG_PROCESS
1885 if (node
->content
== NULL
) {
1886 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1887 "xsltDefaultProcessOneNode: copy empty text\n"));
1890 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1891 "xsltDefaultProcessOneNode: copy text %s\n",
1895 copy
= xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
1897 xsltTransformError(ctxt
, NULL
, node
,
1898 "xsltDefaultProcessOneNode: text copy failed\n");
1901 case XML_ATTRIBUTE_NODE
:
1902 cur
= node
->children
;
1903 while ((cur
!= NULL
) && (cur
->type
!= XML_TEXT_NODE
))
1906 xsltTransformError(ctxt
, NULL
, node
,
1907 "xsltDefaultProcessOneNode: no text for attribute\n");
1909 #ifdef WITH_XSLT_DEBUG_PROCESS
1910 if (cur
->content
== NULL
) {
1911 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1912 "xsltDefaultProcessOneNode: copy empty text\n"));
1914 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1915 "xsltDefaultProcessOneNode: copy text %s\n",
1919 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
1921 xsltTransformError(ctxt
, NULL
, node
,
1922 "xsltDefaultProcessOneNode: text copy failed\n");
1930 * Handling of Elements: first pass, cleanup and counting
1932 cur
= node
->children
;
1933 while (cur
!= NULL
) {
1934 switch (cur
->type
) {
1936 case XML_CDATA_SECTION_NODE
:
1937 case XML_DOCUMENT_NODE
:
1938 case XML_HTML_DOCUMENT_NODE
:
1939 case XML_ELEMENT_NODE
:
1941 case XML_COMMENT_NODE
:
1945 /* Unlink the DTD, it's still reachable using doc->intSubset */
1946 if (cur
->next
!= NULL
)
1947 cur
->next
->prev
= cur
->prev
;
1948 if (cur
->prev
!= NULL
)
1949 cur
->prev
->next
= cur
->next
;
1952 #ifdef WITH_XSLT_DEBUG_PROCESS
1953 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1954 "xsltDefaultProcessOneNode: skipping node type %d\n",
1960 if (delete != NULL
) {
1961 #ifdef WITH_XSLT_DEBUG_PROCESS
1962 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1963 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1965 xmlUnlinkNode(delete);
1966 xmlFreeNode(delete);
1970 if (delete != NULL
) {
1971 #ifdef WITH_XSLT_DEBUG_PROCESS
1972 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
1973 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1975 xmlUnlinkNode(delete);
1976 xmlFreeNode(delete);
1981 * Handling of Elements: second pass, actual processing
1983 * Note that params are passed to the next template. This matches
1984 * XSLT 2.0 behavior but doesn't conform to XSLT 1.0.
1986 oldSize
= ctxt
->xpathCtxt
->contextSize
;
1987 oldPos
= ctxt
->xpathCtxt
->proximityPosition
;
1988 cur
= node
->children
;
1989 while (cur
!= NULL
) {
1991 switch (cur
->type
) {
1992 case XML_DOCUMENT_NODE
:
1993 case XML_HTML_DOCUMENT_NODE
:
1994 case XML_ELEMENT_NODE
:
1995 ctxt
->xpathCtxt
->contextSize
= nbchild
;
1996 ctxt
->xpathCtxt
->proximityPosition
= childno
;
1997 xsltProcessOneNode(ctxt
, cur
, params
);
1999 case XML_CDATA_SECTION_NODE
:
2000 template = xsltGetTemplate(ctxt
, cur
, NULL
);
2002 #ifdef WITH_XSLT_DEBUG_PROCESS
2003 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2004 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
2008 * Instantiate the xsl:template.
2010 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
2012 } else /* if (ctxt->mode == NULL) */ {
2013 #ifdef WITH_XSLT_DEBUG_PROCESS
2014 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2015 "xsltDefaultProcessOneNode: copy CDATA %s\n",
2018 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
2020 xsltTransformError(ctxt
, NULL
, cur
,
2021 "xsltDefaultProcessOneNode: cdata copy failed\n");
2026 template = xsltGetTemplate(ctxt
, cur
, NULL
);
2028 #ifdef WITH_XSLT_DEBUG_PROCESS
2029 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2030 "xsltDefaultProcessOneNode: applying template for text %s\n",
2033 ctxt
->xpathCtxt
->contextSize
= nbchild
;
2034 ctxt
->xpathCtxt
->proximityPosition
= childno
;
2036 * Instantiate the xsl:template.
2038 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
2040 } else /* if (ctxt->mode == NULL) */ {
2041 #ifdef WITH_XSLT_DEBUG_PROCESS
2042 if (cur
->content
== NULL
) {
2043 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2044 "xsltDefaultProcessOneNode: copy empty text\n"));
2046 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2047 "xsltDefaultProcessOneNode: copy text %s\n",
2051 copy
= xsltCopyText(ctxt
, ctxt
->insert
, cur
, 0);
2053 xsltTransformError(ctxt
, NULL
, cur
,
2054 "xsltDefaultProcessOneNode: text copy failed\n");
2059 case XML_COMMENT_NODE
:
2060 template = xsltGetTemplate(ctxt
, cur
, NULL
);
2062 #ifdef WITH_XSLT_DEBUG_PROCESS
2063 if (cur
->type
== XML_PI_NODE
) {
2064 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2065 "xsltDefaultProcessOneNode: template found for PI %s\n",
2067 } else if (cur
->type
== XML_COMMENT_NODE
) {
2068 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2069 "xsltDefaultProcessOneNode: template found for comment\n"));
2072 ctxt
->xpathCtxt
->contextSize
= nbchild
;
2073 ctxt
->xpathCtxt
->proximityPosition
= childno
;
2075 * Instantiate the xsl:template.
2077 xsltApplyXSLTTemplate(ctxt
, cur
, template->content
,
2086 ctxt
->xpathCtxt
->contextSize
= oldSize
;
2087 ctxt
->xpathCtxt
->proximityPosition
= oldPos
;
2091 * xsltProcessOneNode:
2092 * @ctxt: a XSLT process context
2093 * @contextNode: the "current node" in the source tree
2094 * @withParams: extra parameters (e.g. xsl:with-param) passed to the
2097 * Process the source node.
2100 xsltProcessOneNode(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
2101 xsltStackElemPtr withParams
)
2103 xsltTemplatePtr templ
;
2106 templ
= xsltGetTemplate(ctxt
, contextNode
, NULL
);
2108 * If no template is found, apply the default rule.
2110 if (templ
== NULL
) {
2111 #ifdef WITH_XSLT_DEBUG_PROCESS
2112 if (contextNode
->type
== XML_DOCUMENT_NODE
) {
2113 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2114 "xsltProcessOneNode: no template found for /\n"));
2115 } else if (contextNode
->type
== XML_CDATA_SECTION_NODE
) {
2116 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2117 "xsltProcessOneNode: no template found for CDATA\n"));
2118 } else if (contextNode
->type
== XML_ATTRIBUTE_NODE
) {
2119 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2120 "xsltProcessOneNode: no template found for attribute %s\n",
2121 ((xmlAttrPtr
) contextNode
)->name
));
2123 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2124 "xsltProcessOneNode: no template found for %s\n", contextNode
->name
));
2127 oldNode
= ctxt
->node
;
2128 ctxt
->node
= contextNode
;
2129 xsltDefaultProcessOneNode(ctxt
, contextNode
, withParams
);
2130 ctxt
->node
= oldNode
;
2134 if (contextNode
->type
== XML_ATTRIBUTE_NODE
) {
2135 xsltTemplatePtr oldCurTempRule
= ctxt
->currentTemplateRule
;
2137 * Set the "current template rule".
2139 ctxt
->currentTemplateRule
= templ
;
2141 #ifdef WITH_XSLT_DEBUG_PROCESS
2142 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2143 "xsltProcessOneNode: applying template '%s' for attribute %s\n",
2144 templ
->match
, contextNode
->name
));
2146 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
, templ
, withParams
);
2148 ctxt
->currentTemplateRule
= oldCurTempRule
;
2150 xsltTemplatePtr oldCurTempRule
= ctxt
->currentTemplateRule
;
2152 * Set the "current template rule".
2154 ctxt
->currentTemplateRule
= templ
;
2156 #ifdef WITH_XSLT_DEBUG_PROCESS
2157 if (contextNode
->type
== XML_DOCUMENT_NODE
) {
2158 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2159 "xsltProcessOneNode: applying template '%s' for /\n",
2162 XSLT_TRACE(ctxt
,XSLT_TRACE_PROCESS_NODE
,xsltGenericDebug(xsltGenericDebugContext
,
2163 "xsltProcessOneNode: applying template '%s' for %s\n",
2164 templ
->match
, contextNode
->name
));
2167 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
, templ
, withParams
);
2169 ctxt
->currentTemplateRule
= oldCurTempRule
;
2174 xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt
,
2175 xmlNodePtr contextNode
,
2177 xsltTemplatePtr templ
,
2180 xmlNodePtr debugedNode
= NULL
;
2182 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2184 *addCallResult
= xslAddCall(templ
, templ
->elem
);
2186 *addCallResult
= xslAddCall(NULL
, list
);
2188 switch (ctxt
->debugStatus
) {
2189 case XSLT_DEBUG_RUN_RESTART
:
2190 case XSLT_DEBUG_QUIT
:
2196 xslHandleDebugger(templ
->elem
, contextNode
, templ
, ctxt
);
2197 debugedNode
= templ
->elem
;
2199 xslHandleDebugger(list
, contextNode
, templ
, ctxt
);
2201 } else if (ctxt
->inst
) {
2202 xslHandleDebugger(ctxt
->inst
, contextNode
, templ
, ctxt
);
2203 debugedNode
= ctxt
->inst
;
2206 return(debugedNode
);
2210 * xsltLocalVariablePush:
2211 * @ctxt: the transformation context
2212 * @variable: variable to be pushed to the variable stack
2213 * @level: new value for variable's level
2215 * Places the variable onto the local variable stack
2217 * Returns: 0 for success, -1 for any error
2219 * This is an internal routine and should not be called by users!
2222 xsltLocalVariablePush(xsltTransformContextPtr ctxt
,
2223 xsltStackElemPtr variable
,
2226 if (ctxt
->varsMax
== 0) {
2229 (xsltStackElemPtr
*) xmlMalloc(ctxt
->varsMax
*
2230 sizeof(ctxt
->varsTab
[0]));
2231 if (ctxt
->varsTab
== NULL
) {
2232 xmlGenericError(xmlGenericErrorContext
, "malloc failed !\n");
2236 if (ctxt
->varsNr
>= ctxt
->varsMax
) {
2239 (xsltStackElemPtr
*) xmlRealloc(ctxt
->varsTab
,
2241 sizeof(ctxt
->varsTab
[0]));
2242 if (ctxt
->varsTab
== NULL
) {
2243 xmlGenericError(xmlGenericErrorContext
, "realloc failed !\n");
2247 ctxt
->varsTab
[ctxt
->varsNr
++] = variable
;
2248 ctxt
->vars
= variable
;
2249 variable
->level
= level
;
2254 * xsltReleaseLocalRVTs:
2256 * Fragments which are results of extension instructions
2257 * are preserved; all other fragments are freed/cached.
2260 xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt
, xmlDocPtr base
)
2262 xmlDocPtr cur
= ctxt
->localRVT
, tmp
;
2266 if (cur
->prev
!= NULL
)
2267 xsltTransformError(ctxt
, NULL
, NULL
, "localRVT not head of list\n");
2269 /* Reset localRVT early because some RVTs might be registered again. */
2270 ctxt
->localRVT
= base
;
2276 cur
= (xmlDocPtr
) cur
->next
;
2277 if (tmp
->psvi
== XSLT_RVT_LOCAL
) {
2278 xsltReleaseRVT(ctxt
, tmp
);
2279 } else if (tmp
->psvi
== XSLT_RVT_GLOBAL
) {
2280 xsltRegisterPersistRVT(ctxt
, tmp
);
2281 } else if (tmp
->psvi
== XSLT_RVT_FUNC_RESULT
) {
2283 * This will either register the RVT again or move it to the
2286 xsltRegisterLocalRVT(ctxt
, tmp
);
2287 tmp
->psvi
= XSLT_RVT_FUNC_RESULT
;
2289 xmlGenericError(xmlGenericErrorContext
,
2290 "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
2293 } while (cur
!= base
);
2297 * xsltApplySequenceConstructor:
2298 * @ctxt: a XSLT process context
2299 * @contextNode: the "current node" in the source tree
2300 * @list: the nodes of a sequence constructor;
2301 * (plus leading xsl:param elements)
2302 * @templ: the compiled xsl:template (optional)
2304 * Processes a sequence constructor.
2306 * NOTE: ctxt->currentTemplateRule was introduced to reflect the
2307 * semantics of "current template rule". I.e. the field ctxt->templ
2308 * is not intended to reflect this, thus always pushed onto the
2312 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt
,
2313 xmlNodePtr contextNode
, xmlNodePtr list
,
2314 xsltTemplatePtr templ
)
2316 xmlNodePtr oldInsert
, oldInst
, oldCurInst
, oldContextNode
;
2317 xmlNodePtr cur
, insert
, copy
= NULL
;
2318 int level
= 0, oldVarsNr
;
2319 xmlDocPtr oldLocalFragmentTop
;
2321 #ifdef XSLT_REFACTORED
2322 xsltStylePreCompPtr info
;
2325 #ifdef WITH_DEBUGGER
2326 int addCallResult
= 0;
2327 xmlNodePtr debuggedNode
= NULL
;
2333 #ifdef WITH_DEBUGGER
2334 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
2336 xsltDebuggerStartSequenceConstructor(ctxt
, contextNode
,
2337 list
, templ
, &addCallResult
);
2338 if (debuggedNode
== NULL
)
2348 * Check for infinite recursion: stop if the maximum of nested templates
2349 * is excceeded. Adjust xsltMaxDepth if you need more.
2351 if (ctxt
->depth
>= ctxt
->maxTemplateDepth
) {
2352 xsltTransformError(ctxt
, NULL
, list
,
2353 "xsltApplySequenceConstructor: A potential infinite template "
2354 "recursion was detected.\n"
2355 "You can adjust xsltMaxDepth (--maxdepth) in order to "
2356 "raise the maximum number of nested template calls and "
2357 "variables/params (currently set to %d).\n",
2358 ctxt
->maxTemplateDepth
);
2359 xsltDebug(ctxt
, contextNode
, list
, NULL
);
2360 ctxt
->state
= XSLT_STATE_STOPPED
;
2365 oldLocalFragmentTop
= ctxt
->localRVT
;
2366 oldInsert
= insert
= ctxt
->insert
;
2367 oldInst
= oldCurInst
= ctxt
->inst
;
2368 oldContextNode
= ctxt
->node
;
2370 * Save current number of variables on the stack; new vars are popped when
2373 oldVarsNr
= ctxt
->varsNr
;
2375 * Process the sequence constructor.
2378 while (cur
!= NULL
) {
2381 #ifdef WITH_DEBUGGER
2382 switch (ctxt
->debugStatus
) {
2383 case XSLT_DEBUG_RUN_RESTART
:
2384 case XSLT_DEBUG_QUIT
:
2390 * Test; we must have a valid insertion point.
2392 if (insert
== NULL
) {
2394 #ifdef WITH_XSLT_DEBUG_PROCESS
2395 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2396 "xsltApplySequenceConstructor: insert == NULL !\n"));
2401 #ifdef WITH_DEBUGGER
2402 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (debuggedNode
!= cur
))
2403 xslHandleDebugger(cur
, contextNode
, templ
, ctxt
);
2406 #ifdef XSLT_REFACTORED
2407 if (cur
->type
== XML_ELEMENT_NODE
) {
2408 info
= (xsltStylePreCompPtr
) cur
->psvi
;
2410 * We expect a compiled representation on:
2411 * 1) XSLT instructions of this XSLT version (1.0)
2412 * (with a few exceptions)
2413 * 2) Literal result elements
2414 * 3) Extension instructions
2415 * 4) XSLT instructions of future XSLT versions
2416 * (forwards-compatible mode).
2420 * Handle the rare cases where we don't expect a compiled
2421 * representation on an XSLT element.
2423 if (IS_XSLT_ELEM_FAST(cur
) && IS_XSLT_NAME(cur
, "message")) {
2424 xsltMessage(ctxt
, contextNode
, cur
);
2428 * Something really went wrong:
2430 xsltTransformError(ctxt
, NULL
, cur
,
2431 "Internal error in xsltApplySequenceConstructor(): "
2432 "The element '%s' in the stylesheet has no compiled "
2433 "representation.\n",
2438 if (info
->type
== XSLT_FUNC_LITERAL_RESULT_ELEMENT
) {
2439 xsltStyleItemLRElementInfoPtr lrInfo
=
2440 (xsltStyleItemLRElementInfoPtr
) info
;
2442 * Literal result elements
2443 * --------------------------------------------------------
2445 #ifdef WITH_XSLT_DEBUG_PROCESS
2446 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2447 xsltGenericDebug(xsltGenericDebugContext
,
2448 "xsltApplySequenceConstructor: copy literal result "
2449 "element '%s'\n", cur
->name
));
2452 * Copy the raw element-node.
2453 * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2457 copy
= xmlDocCopyNode(cur
, insert
->doc
, 0);
2459 xsltTransformError(ctxt
, NULL
, cur
,
2460 "Internal error in xsltApplySequenceConstructor(): "
2461 "Failed to copy literal result element '%s'.\n",
2466 * Add the element-node to the result tree.
2468 copy
->doc
= ctxt
->output
;
2469 copy
= xsltAddChild(insert
, copy
);
2471 * Create effective namespaces declarations.
2472 * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2474 if (lrInfo
->effectiveNs
!= NULL
) {
2475 xsltEffectiveNsPtr effNs
= lrInfo
->effectiveNs
;
2476 xmlNsPtr ns
, lastns
= NULL
;
2478 while (effNs
!= NULL
) {
2480 * Avoid generating redundant namespace
2481 * declarations; thus lookup if there is already
2482 * such a ns-decl in the result.
2484 ns
= xmlSearchNs(copy
->doc
, copy
, effNs
->prefix
);
2486 (xmlStrEqual(ns
->href
, effNs
->nsName
)))
2488 effNs
= effNs
->next
;
2491 ns
= xmlNewNs(copy
, effNs
->nsName
, effNs
->prefix
);
2493 xsltTransformError(ctxt
, NULL
, cur
,
2494 "Internal error in "
2495 "xsltApplySequenceConstructor(): "
2496 "Failed to copy a namespace "
2507 effNs
= effNs
->next
;
2512 * NOTE that we don't need to apply ns-alising: this was
2513 * already done at compile-time.
2515 if (cur
->ns
!= NULL
) {
2517 * If there's no such ns-decl in the result tree,
2518 * then xsltGetSpecialNamespace() will
2519 * create a ns-decl on the copied node.
2521 copy
->ns
= xsltGetSpecialNamespace(ctxt
, cur
,
2522 cur
->ns
->href
, cur
->ns
->prefix
, copy
);
2525 * Undeclare the default namespace if needed.
2526 * This can be skipped, if the result element has
2527 * no ns-decls, in which case the result element
2528 * obviously does not declare a default namespace;
2529 * AND there's either no parent, or the parent
2530 * element is in no namespace; this means there's no
2531 * default namespace is scope to care about.
2533 * REVISIT: This might result in massive
2534 * generation of ns-decls if nodes in a default
2535 * namespaces are mixed with nodes in no namespace.
2539 ((insert
!= NULL
) &&
2540 (insert
->type
== XML_ELEMENT_NODE
) &&
2541 (insert
->ns
!= NULL
)))
2543 xsltGetSpecialNamespace(ctxt
, cur
,
2549 * SPEC XSLT 2.0 "Each attribute of the literal result
2550 * element, other than an attribute in the XSLT namespace,
2551 * is processed to produce an attribute for the element in
2553 * NOTE: See bug #341325.
2555 if (cur
->properties
!= NULL
) {
2556 xsltAttrListTemplateProcess(ctxt
, copy
, cur
->properties
);
2558 } else if (IS_XSLT_ELEM_FAST(cur
)) {
2561 * --------------------------------------------------------
2563 if (info
->type
== XSLT_FUNC_UNKOWN_FORWARDS_COMPAT
) {
2565 * We hit an unknown XSLT element.
2566 * Try to apply one of the fallback cases.
2568 ctxt
->insert
= insert
;
2569 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2570 xsltTransformError(ctxt
, NULL
, cur
,
2571 "The is no fallback behaviour defined for "
2572 "the unknown XSLT element '%s'.\n",
2575 ctxt
->insert
= oldInsert
;
2576 } else if (info
->func
!= NULL
) {
2578 * Execute the XSLT instruction.
2580 ctxt
->insert
= insert
;
2582 info
->func(ctxt
, contextNode
, cur
,
2583 (xsltElemPreCompPtr
) info
);
2586 * Cleanup temporary tree fragments.
2588 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2589 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2591 ctxt
->insert
= oldInsert
;
2592 } else if (info
->type
== XSLT_FUNC_VARIABLE
) {
2593 xsltStackElemPtr tmpvar
= ctxt
->vars
;
2595 xsltParseStylesheetVariable(ctxt
, cur
);
2597 if (tmpvar
!= ctxt
->vars
) {
2599 * TODO: Using a @tmpvar is an annoying workaround, but
2600 * the current mechanisms do not provide any other way
2601 * of knowing if the var was really pushed onto the
2604 ctxt
->vars
->level
= level
;
2606 } else if (info
->type
== XSLT_FUNC_MESSAGE
) {
2608 * TODO: Won't be hit, since we don't compile xsl:message.
2610 xsltMessage(ctxt
, contextNode
, cur
);
2612 xsltTransformError(ctxt
, NULL
, cur
,
2613 "Unexpected XSLT element '%s'.\n", cur
->name
);
2618 xsltTransformFunction func
;
2620 * Extension intructions (elements)
2621 * --------------------------------------------------------
2623 if (cur
->psvi
== xsltExtMarker
) {
2625 * The xsltExtMarker was set during the compilation
2626 * of extension instructions if there was no registered
2627 * handler for this specific extension function at
2629 * Libxslt will now lookup if a handler is
2630 * registered in the context of this transformation.
2632 func
= xsltExtElementLookup(ctxt
, cur
->name
,
2635 func
= ((xsltElemPreCompPtr
) cur
->psvi
)->func
;
2639 * No handler available.
2640 * Try to execute fallback behaviour via xsl:fallback.
2642 #ifdef WITH_XSLT_DEBUG_PROCESS
2643 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2644 xsltGenericDebug(xsltGenericDebugContext
,
2645 "xsltApplySequenceConstructor: unknown extension %s\n",
2648 ctxt
->insert
= insert
;
2649 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2650 xsltTransformError(ctxt
, NULL
, cur
,
2651 "Unknown extension instruction '{%s}%s'.\n",
2652 cur
->ns
->href
, cur
->name
);
2654 ctxt
->insert
= oldInsert
;
2657 * Execute the handler-callback.
2659 #ifdef WITH_XSLT_DEBUG_PROCESS
2660 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2661 "xsltApplySequenceConstructor: extension construct %s\n",
2665 * Disable the xsltCopyTextString optimization for
2666 * extension elements. Extensions could append text using
2667 * xmlAddChild which will free the buffer pointed to by
2668 * 'lasttext'. This buffer could later be reallocated with
2669 * a different size than recorded in 'lasttsize'. See bug
2672 if (cur
->psvi
== xsltExtMarker
) {
2673 ctxt
->lasttext
= NULL
;
2676 ctxt
->insert
= insert
;
2678 func(ctxt
, contextNode
, cur
, cur
->psvi
);
2681 * Cleanup temporary tree fragments.
2683 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2684 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2686 ctxt
->insert
= oldInsert
;
2691 } else if (XSLT_IS_TEXT_NODE(cur
)) {
2694 * ------------------------------------------------------------
2696 #ifdef WITH_XSLT_DEBUG_PROCESS
2697 if (cur
->name
== xmlStringTextNoenc
) {
2698 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2699 xsltGenericDebug(xsltGenericDebugContext
,
2700 "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2703 XSLT_TRACE(ctxt
, XSLT_TRACE_APPLY_TEMPLATE
,
2704 xsltGenericDebug(xsltGenericDebugContext
,
2705 "xsltApplySequenceConstructor: copy text '%s'\n",
2709 if (xsltCopyText(ctxt
, insert
, cur
, ctxt
->internalized
) == NULL
)
2713 #else /* XSLT_REFACTORED */
2715 if (IS_XSLT_ELEM(cur
)) {
2717 * This is an XSLT node
2719 xsltStylePreCompPtr info
= (xsltStylePreCompPtr
) cur
->psvi
;
2722 if (IS_XSLT_NAME(cur
, "message")) {
2723 xsltMessage(ctxt
, contextNode
, cur
);
2726 * That's an error try to apply one of the fallback cases
2728 ctxt
->insert
= insert
;
2729 if (!xsltApplyFallbacks(ctxt
, contextNode
, cur
)) {
2730 xsltGenericError(xsltGenericErrorContext
,
2731 "xsltApplySequenceConstructor: %s was not compiled\n",
2734 ctxt
->insert
= oldInsert
;
2739 if (info
->func
!= NULL
) {
2740 oldCurInst
= ctxt
->inst
;
2742 ctxt
->insert
= insert
;
2744 info
->func(ctxt
, contextNode
, cur
, (xsltElemPreCompPtr
) info
);
2747 * Cleanup temporary tree fragments.
2749 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2750 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2752 ctxt
->insert
= oldInsert
;
2753 ctxt
->inst
= oldCurInst
;
2757 if (IS_XSLT_NAME(cur
, "variable")) {
2758 xsltStackElemPtr tmpvar
= ctxt
->vars
;
2760 oldCurInst
= ctxt
->inst
;
2763 xsltParseStylesheetVariable(ctxt
, cur
);
2765 ctxt
->inst
= oldCurInst
;
2767 if (tmpvar
!= ctxt
->vars
) {
2769 * TODO: Using a @tmpvar is an annoying workaround, but
2770 * the current mechanisms do not provide any other way
2771 * of knowing if the var was really pushed onto the
2774 ctxt
->vars
->level
= level
;
2776 } else if (IS_XSLT_NAME(cur
, "message")) {
2777 xsltMessage(ctxt
, contextNode
, cur
);
2779 xsltTransformError(ctxt
, NULL
, cur
,
2780 "Unexpected XSLT element '%s'.\n", cur
->name
);
2783 } else if ((cur
->type
== XML_TEXT_NODE
) ||
2784 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
2787 * This text comes from the stylesheet
2788 * For stylesheets, the set of whitespace-preserving
2789 * element names consists of just xsl:text.
2791 #ifdef WITH_XSLT_DEBUG_PROCESS
2792 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
2793 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2794 "xsltApplySequenceConstructor: copy CDATA text %s\n",
2796 } else if (cur
->name
== xmlStringTextNoenc
) {
2797 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2798 "xsltApplySequenceConstructor: copy unescaped text %s\n",
2801 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2802 "xsltApplySequenceConstructor: copy text %s\n",
2806 if (xsltCopyText(ctxt
, insert
, cur
, ctxt
->internalized
) == NULL
)
2808 } else if ((cur
->type
== XML_ELEMENT_NODE
) &&
2809 (cur
->ns
!= NULL
) && (cur
->psvi
!= NULL
)) {
2810 xsltTransformFunction function
;
2812 oldCurInst
= ctxt
->inst
;
2815 * Flagged as an extension element
2817 if (cur
->psvi
== xsltExtMarker
)
2818 function
= xsltExtElementLookup(ctxt
, cur
->name
,
2821 function
= ((xsltElemPreCompPtr
) cur
->psvi
)->func
;
2823 if (function
== NULL
) {
2827 #ifdef WITH_XSLT_DEBUG_PROCESS
2828 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2829 "xsltApplySequenceConstructor: unknown extension %s\n",
2833 * Search if there are fallbacks
2835 child
= cur
->children
;
2836 while (child
!= NULL
) {
2837 if ((IS_XSLT_ELEM(child
)) &&
2838 (IS_XSLT_NAME(child
, "fallback")))
2841 xsltApplySequenceConstructor(ctxt
, contextNode
,
2842 child
->children
, NULL
);
2844 child
= child
->next
;
2848 xsltTransformError(ctxt
, NULL
, cur
,
2849 "xsltApplySequenceConstructor: failed to find extension %s\n",
2853 #ifdef WITH_XSLT_DEBUG_PROCESS
2854 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2855 "xsltApplySequenceConstructor: extension construct %s\n",
2860 * Disable the xsltCopyTextString optimization for
2861 * extension elements. Extensions could append text using
2862 * xmlAddChild which will free the buffer pointed to by
2863 * 'lasttext'. This buffer could later be reallocated with
2864 * a different size than recorded in 'lasttsize'. See bug
2867 if (cur
->psvi
== xsltExtMarker
) {
2868 ctxt
->lasttext
= NULL
;
2871 ctxt
->insert
= insert
;
2873 function(ctxt
, contextNode
, cur
, cur
->psvi
);
2875 * Cleanup temporary tree fragments.
2877 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
2878 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
2880 ctxt
->insert
= oldInsert
;
2883 ctxt
->inst
= oldCurInst
;
2885 } else if (cur
->type
== XML_ELEMENT_NODE
) {
2886 #ifdef WITH_XSLT_DEBUG_PROCESS
2887 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
2888 "xsltApplySequenceConstructor: copy node %s\n",
2891 oldCurInst
= ctxt
->inst
;
2894 if ((copy
= xsltShallowCopyElem(ctxt
, cur
, insert
, 1)) == NULL
)
2897 * Add extra namespaces inherited from the current template
2898 * if we are in the first level children and this is a
2901 if ((templ
!= NULL
) && (oldInsert
== insert
) &&
2902 (ctxt
->templ
!= NULL
) && (ctxt
->templ
->inheritedNs
!= NULL
)) {
2906 for (i
= 0; i
< ctxt
->templ
->inheritedNsNr
; i
++) {
2907 const xmlChar
*URI
= NULL
;
2908 xsltStylesheetPtr style
;
2909 ns
= ctxt
->templ
->inheritedNs
[i
];
2911 /* Note that the XSLT namespace was already excluded
2912 * in xsltGetInheritedNsList().
2915 if (xmlStrEqual(ns
->href
, XSLT_NAMESPACE
))
2918 style
= ctxt
->style
;
2919 while (style
!= NULL
) {
2920 if (style
->nsAliases
!= NULL
)
2921 URI
= (const xmlChar
*)
2922 xmlHashLookup(style
->nsAliases
, ns
->href
);
2926 style
= xsltNextImport(style
);
2928 if (URI
== UNDEFINED_DEFAULT_NS
)
2933 * TODO: The following will still be buggy for the
2934 * non-refactored code.
2936 ret
= xmlSearchNs(copy
->doc
, copy
, ns
->prefix
);
2937 if ((ret
== NULL
) || (!xmlStrEqual(ret
->href
, URI
)))
2939 xmlNewNs(copy
, URI
, ns
->prefix
);
2942 if (copy
->ns
!= NULL
) {
2944 * Fix the node namespace if needed
2946 copy
->ns
= xsltGetNamespace(ctxt
, cur
, copy
->ns
, copy
);
2950 * all the attributes are directly inherited
2952 if (cur
->properties
!= NULL
) {
2953 xsltAttrListTemplateProcess(ctxt
, copy
, cur
->properties
);
2955 ctxt
->inst
= oldCurInst
;
2957 #endif /* else of XSLT_REFACTORED */
2960 * Descend into content in document order.
2962 if (cur
->children
!= NULL
) {
2963 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
2964 cur
= cur
->children
;
2974 * If xslt:message was just processed, we might have hit a
2975 * terminate='yes'; if so, then break the loop and clean up.
2976 * TODO: Do we need to check this also before trying to descend
2979 if (ctxt
->state
== XSLT_STATE_STOPPED
)
2981 if (cur
->next
!= NULL
) {
2990 * Pop variables/params (xsl:variable and xsl:param).
2992 if ((ctxt
->varsNr
> oldVarsNr
) && (ctxt
->vars
->level
> level
)) {
2993 xsltLocalVariablePop(ctxt
, oldVarsNr
, level
);
2996 insert
= insert
->parent
;
2999 if (cur
== list
->parent
) {
3003 if (cur
->next
!= NULL
) {
3007 } while (cur
!= NULL
);
3012 * In case of errors: pop remaining variables.
3014 if (ctxt
->varsNr
> oldVarsNr
)
3015 xsltLocalVariablePop(ctxt
, oldVarsNr
, -1);
3017 ctxt
->node
= oldContextNode
;
3018 ctxt
->inst
= oldInst
;
3019 ctxt
->insert
= oldInsert
;
3023 #ifdef WITH_DEBUGGER
3024 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (addCallResult
)) {
3031 * xsltApplyXSLTTemplate:
3032 * @ctxt: a XSLT transformation context
3033 * @contextNode: the node in the source tree.
3034 * @list: the nodes of a sequence constructor;
3035 * (plus leading xsl:param elements)
3036 * @templ: the compiled xsl:template declaration;
3037 * NULL if a sequence constructor
3038 * @withParams: a set of caller-parameters (xsl:with-param) or NULL
3041 * - xsltApplyImports()
3042 * - xsltCallTemplate()
3043 * - xsltDefaultProcessOneNode()
3044 * - xsltProcessOneNode()
3047 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt
,
3048 xmlNodePtr contextNode
,
3050 xsltTemplatePtr templ
,
3051 xsltStackElemPtr withParams
)
3053 int oldVarsBase
= 0;
3056 xsltStackElemPtr tmpParam
= NULL
;
3057 xmlDocPtr oldUserFragmentTop
;
3059 #ifdef XSLT_REFACTORED
3060 xsltStyleItemParamPtr iparam
;
3062 xsltStylePreCompPtr iparam
;
3065 #ifdef WITH_DEBUGGER
3066 int addCallResult
= 0;
3071 if (templ
== NULL
) {
3072 xsltTransformError(ctxt
, NULL
, list
,
3073 "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
3077 #ifdef WITH_DEBUGGER
3078 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) {
3079 if (xsltDebuggerStartSequenceConstructor(ctxt
, contextNode
,
3080 list
, templ
, &addCallResult
) == NULL
)
3089 if (ctxt
->varsNr
>= ctxt
->maxTemplateVars
)
3091 xsltTransformError(ctxt
, NULL
, list
,
3092 "xsltApplyXSLTTemplate: A potential infinite template recursion "
3094 "You can adjust maxTemplateVars (--maxvars) in order to "
3095 "raise the maximum number of variables/params (currently set to %d).\n",
3096 ctxt
->maxTemplateVars
);
3097 xsltDebug(ctxt
, contextNode
, list
, NULL
);
3098 ctxt
->state
= XSLT_STATE_STOPPED
;
3102 oldUserFragmentTop
= ctxt
->tmpRVT
;
3103 ctxt
->tmpRVT
= NULL
;
3106 * Initiate a distinct scope of local params/variables.
3108 oldVarsBase
= ctxt
->varsBase
;
3109 ctxt
->varsBase
= ctxt
->varsNr
;
3111 ctxt
->node
= contextNode
;
3112 if (ctxt
->profile
) {
3114 start
= xsltTimestamp();
3116 profCallgraphAdd(templ
, ctxt
->templ
);
3119 * Push the xsl:template declaration onto the stack.
3121 templPush(ctxt
, templ
);
3123 #ifdef WITH_XSLT_DEBUG_PROCESS
3124 if (templ
->name
!= NULL
)
3125 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
3126 "applying xsl:template '%s'\n", templ
->name
));
3129 * Process xsl:param instructions and skip those elements for
3130 * further processing.
3134 if (cur
->type
== XML_TEXT_NODE
) {
3138 if ((cur
->type
!= XML_ELEMENT_NODE
) ||
3139 (cur
->name
[0] != 'p') ||
3140 (cur
->psvi
== NULL
) ||
3141 (! xmlStrEqual(cur
->name
, BAD_CAST
"param")) ||
3142 (! IS_XSLT_ELEM(cur
)))
3149 #ifdef XSLT_REFACTORED
3150 iparam
= (xsltStyleItemParamPtr
) cur
->psvi
;
3152 iparam
= (xsltStylePreCompPtr
) cur
->psvi
;
3156 * Substitute xsl:param for a given xsl:with-param.
3157 * Since the XPath expression will reference the params/vars
3158 * by index, we need to slot the xsl:with-params in the
3159 * order of encountered xsl:params to keep the sequence of
3160 * params/variables in the stack exactly as it was at
3165 tmpParam
= withParams
;
3167 if ((tmpParam
->name
== (iparam
->name
)) &&
3168 (tmpParam
->nameURI
== (iparam
->ns
)))
3171 * Push the caller-parameter.
3173 xsltLocalVariablePush(ctxt
, tmpParam
, -1);
3176 tmpParam
= tmpParam
->next
;
3177 } while (tmpParam
!= NULL
);
3180 * Push the xsl:param.
3182 if (tmpParam
== NULL
) {
3184 * Note that we must assume that the added parameter
3185 * has a @depth of 0.
3187 xsltParseStylesheetParam(ctxt
, cur
);
3190 } while (cur
!= NULL
);
3192 * Process the sequence constructor.
3194 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3197 * Remove remaining xsl:param and xsl:with-param items from
3198 * the stack. Don't free xsl:with-param items.
3200 if (ctxt
->varsNr
> ctxt
->varsBase
)
3201 xsltTemplateParamsCleanup(ctxt
);
3202 ctxt
->varsBase
= oldVarsBase
;
3205 * Release user-created fragments stored in the scope
3206 * of xsl:template. Note that this mechanism is deprecated:
3207 * user code should now use xsltRegisterLocalRVT() instead
3208 * of the obsolete xsltRegisterTmpRVT().
3211 xmlDocPtr curdoc
= ctxt
->tmpRVT
, tmp
;
3213 while (curdoc
!= NULL
) {
3215 curdoc
= (xmlDocPtr
) curdoc
->next
;
3216 xsltReleaseRVT(ctxt
, tmp
);
3219 ctxt
->tmpRVT
= oldUserFragmentTop
;
3222 * Pop the xsl:template declaration from the stack.
3225 if (ctxt
->profile
) {
3226 long spent
, child
, total
, end
;
3228 end
= xsltTimestamp();
3229 child
= profPop(ctxt
);
3230 total
= end
- start
;
3231 spent
= total
- child
;
3234 * Not possible unless the original calibration failed
3235 * we can try to correct it on the fly.
3237 xsltCalibrateAdjust(spent
);
3241 templ
->time
+= spent
;
3242 if (ctxt
->profNr
> 0)
3243 ctxt
->profTab
[ctxt
->profNr
- 1] += total
;
3246 #ifdef WITH_DEBUGGER
3247 if ((ctxt
->debugStatus
!= XSLT_DEBUG_NONE
) && (addCallResult
)) {
3255 * xsltApplyOneTemplate:
3256 * @ctxt: a XSLT process context
3257 * @contextNode: the node in the source tree.
3258 * @list: the nodes of a sequence constructor
3260 * @params: a set of parameters (xsl:param) or NULL
3262 * Processes a sequence constructor on the current node in the source tree.
3264 * @params are the already computed variable stack items; this function
3265 * pushes them on the variable stack, and pops them before exiting; it's
3266 * left to the caller to free or reuse @params afterwards. The initial
3267 * states of the variable stack will always be restored before this
3269 * NOTE that this does *not* initiate a new distinct variable scope; i.e.
3270 * variables already on the stack are visible to the process. The caller's
3271 * side needs to start a new variable scope if needed (e.g. in exsl:function).
3273 * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
3274 * provide a @templ); a non-NULL @templ might raise an error in the future.
3276 * BIG NOTE: This function is not intended to process the content of an
3277 * xsl:template; it does not expect xsl:param instructions in @list and
3278 * will report errors if found.
3281 * - xsltEvalVariable() (variables.c)
3282 * - exsltFuncFunctionFunction() (libexsl/functions.c)
3285 xsltApplyOneTemplate(xsltTransformContextPtr ctxt
,
3286 xmlNodePtr contextNode
,
3288 xsltTemplatePtr templ ATTRIBUTE_UNUSED
,
3289 xsltStackElemPtr params
)
3291 if ((ctxt
== NULL
) || (list
== NULL
))
3297 * This code should be obsolete - was previously used
3298 * by libexslt/functions.c, but due to bug 381319 the
3299 * logic there was changed.
3301 int oldVarsNr
= ctxt
->varsNr
;
3304 * Push the given xsl:param(s) onto the variable stack.
3306 while (params
!= NULL
) {
3307 xsltLocalVariablePush(ctxt
, params
, -1);
3308 params
= params
->next
;
3310 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3312 * Pop the given xsl:param(s) from the stack but don't free them.
3314 xsltLocalVariablePop(ctxt
, oldVarsNr
, -2);
3316 xsltApplySequenceConstructor(ctxt
, contextNode
, list
, templ
);
3319 /************************************************************************
3321 * XSLT-1.1 extensions *
3323 ************************************************************************/
3327 * @ctxt: an XSLT processing context
3328 * @node: The current node
3329 * @inst: the instruction in the stylesheet
3330 * @castedComp: precomputed information
3332 * Process an EXSLT/XSLT-1.1 document element
3335 xsltDocumentElem(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3336 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
3338 #ifdef XSLT_REFACTORED
3339 xsltStyleItemDocumentPtr comp
= (xsltStyleItemDocumentPtr
) castedComp
;
3341 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
3343 xsltStylesheetPtr style
= NULL
;
3345 xmlChar
*filename
= NULL
, *prop
, *elements
;
3346 xmlChar
*element
, *end
;
3347 xmlDocPtr res
= NULL
;
3348 xmlDocPtr oldOutput
;
3349 xmlNodePtr oldInsert
, root
;
3350 const char *oldOutputFile
;
3351 xsltOutputType oldType
;
3352 xmlChar
*URL
= NULL
;
3353 const xmlChar
*method
;
3354 const xmlChar
*doctypePublic
;
3355 const xmlChar
*doctypeSystem
;
3356 const xmlChar
*version
;
3357 const xmlChar
*encoding
;
3358 int redirect_write_append
= 0;
3360 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
3363 if (comp
->filename
== NULL
) {
3365 if (xmlStrEqual(inst
->name
, (const xmlChar
*) "output")) {
3367 * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
3368 * (http://icl.com/saxon)
3369 * The @file is in no namespace.
3371 #ifdef WITH_XSLT_DEBUG_EXTRA
3372 xsltGenericDebug(xsltGenericDebugContext
,
3373 "Found saxon:output extension\n");
3375 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3376 (const xmlChar
*) "file",
3377 XSLT_SAXON_NAMESPACE
);
3380 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3381 (const xmlChar
*) "href",
3382 XSLT_SAXON_NAMESPACE
);
3383 } else if (xmlStrEqual(inst
->name
, (const xmlChar
*) "write")) {
3384 #ifdef WITH_XSLT_DEBUG_EXTRA
3385 xsltGenericDebug(xsltGenericDebugContext
,
3386 "Found xalan:write extension\n");
3388 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3391 XSLT_XALAN_NAMESPACE
);
3393 xmlXPathCompExprPtr cmp
;
3397 * Trying to handle bug #59212
3398 * The value of the "select" attribute is an
3400 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
3402 cmp
= xmlXPathCompile(URL
);
3403 val
= xsltEvalXPathString(ctxt
, cmp
);
3404 xmlXPathFreeCompExpr(cmp
);
3409 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3412 XSLT_XALAN_NAMESPACE
);
3414 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3417 XSLT_XALAN_NAMESPACE
);
3418 } else if (xmlStrEqual(inst
->name
, (const xmlChar
*) "document")) {
3419 URL
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3420 (const xmlChar
*) "href",
3425 URL
= xmlStrdup(comp
->filename
);
3429 xsltTransformError(ctxt
, NULL
, inst
,
3430 "xsltDocumentElem: href/URI-Reference not found\n");
3435 * If the computation failed, it's likely that the URL wasn't escaped
3437 filename
= xmlBuildURI(URL
, (const xmlChar
*) ctxt
->outputFile
);
3438 if (filename
== NULL
) {
3441 escURL
=xmlURIEscapeStr(URL
, BAD_CAST
":/.?,");
3442 if (escURL
!= NULL
) {
3443 filename
= xmlBuildURI(escURL
, (const xmlChar
*) ctxt
->outputFile
);
3448 if (filename
== NULL
) {
3449 xsltTransformError(ctxt
, NULL
, inst
,
3450 "xsltDocumentElem: URL computation failed for %s\n",
3457 * Security checking: can we write to this resource
3459 if (ctxt
->sec
!= NULL
) {
3460 ret
= xsltCheckWrite(ctxt
->sec
, ctxt
, filename
);
3462 xsltTransformError(ctxt
, NULL
, inst
,
3463 "xsltDocumentElem: write rights for %s denied\n",
3471 oldOutputFile
= ctxt
->outputFile
;
3472 oldOutput
= ctxt
->output
;
3473 oldInsert
= ctxt
->insert
;
3474 oldType
= ctxt
->type
;
3475 ctxt
->outputFile
= (const char *) filename
;
3477 style
= xsltNewStylesheet();
3478 if (style
== NULL
) {
3479 xsltTransformError(ctxt
, NULL
, inst
,
3480 "xsltDocumentElem: out of memory\n");
3485 * Version described in 1.1 draft allows full parameterization
3488 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3489 (const xmlChar
*) "version",
3492 if (style
->version
!= NULL
)
3493 xmlFree(style
->version
);
3494 style
->version
= prop
;
3496 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3497 (const xmlChar
*) "encoding",
3500 if (style
->encoding
!= NULL
)
3501 xmlFree(style
->encoding
);
3502 style
->encoding
= prop
;
3504 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3505 (const xmlChar
*) "method",
3510 if (style
->method
!= NULL
)
3511 xmlFree(style
->method
);
3512 style
->method
= NULL
;
3513 if (style
->methodURI
!= NULL
)
3514 xmlFree(style
->methodURI
);
3515 style
->methodURI
= NULL
;
3517 URI
= xsltGetQNameURI(inst
, &prop
);
3519 if (style
!= NULL
) style
->errors
++;
3520 } else if (URI
== NULL
) {
3521 if ((xmlStrEqual(prop
, (const xmlChar
*) "xml")) ||
3522 (xmlStrEqual(prop
, (const xmlChar
*) "html")) ||
3523 (xmlStrEqual(prop
, (const xmlChar
*) "text"))) {
3524 style
->method
= prop
;
3526 xsltTransformError(ctxt
, NULL
, inst
,
3527 "invalid value for method: %s\n", prop
);
3528 if (style
!= NULL
) style
->warnings
++;
3531 style
->method
= prop
;
3532 style
->methodURI
= xmlStrdup(URI
);
3535 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3537 "doctype-system", NULL
);
3539 if (style
->doctypeSystem
!= NULL
)
3540 xmlFree(style
->doctypeSystem
);
3541 style
->doctypeSystem
= prop
;
3543 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3545 "doctype-public", NULL
);
3547 if (style
->doctypePublic
!= NULL
)
3548 xmlFree(style
->doctypePublic
);
3549 style
->doctypePublic
= prop
;
3551 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3552 (const xmlChar
*) "standalone",
3555 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3556 style
->standalone
= 1;
3557 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3558 style
->standalone
= 0;
3560 xsltTransformError(ctxt
, NULL
, inst
,
3561 "invalid value for standalone: %s\n",
3563 if (style
!= NULL
) style
->warnings
++;
3568 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3569 (const xmlChar
*) "indent",
3572 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3574 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3577 xsltTransformError(ctxt
, NULL
, inst
,
3578 "invalid value for indent: %s\n", prop
);
3579 if (style
!= NULL
) style
->warnings
++;
3584 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3586 "omit-xml-declaration",
3589 if (xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3590 style
->omitXmlDeclaration
= 1;
3591 } else if (xmlStrEqual(prop
, (const xmlChar
*) "no")) {
3592 style
->omitXmlDeclaration
= 0;
3594 xsltTransformError(ctxt
, NULL
, inst
,
3595 "invalid value for omit-xml-declaration: %s\n",
3597 if (style
!= NULL
) style
->warnings
++;
3602 elements
= xsltEvalAttrValueTemplate(ctxt
, inst
,
3604 "cdata-section-elements",
3606 if (elements
!= NULL
) {
3607 if (style
->stripSpaces
== NULL
)
3608 style
->stripSpaces
= xmlHashCreate(10);
3609 if (style
->stripSpaces
== NULL
)
3613 while (*element
!= 0) {
3614 while (IS_BLANK_CH(*element
))
3619 while ((*end
!= 0) && (!IS_BLANK_CH(*end
)))
3621 element
= xmlStrndup(element
, end
- element
);
3625 #ifdef WITH_XSLT_DEBUG_PARSING
3626 xsltGenericDebug(xsltGenericDebugContext
,
3627 "add cdata section output element %s\n",
3630 URI
= xsltGetQNameURI(inst
, &element
);
3632 xmlHashAddEntry2(style
->stripSpaces
, element
, URI
,
3633 (xmlChar
*) "cdata");
3642 * Create a new document tree and process the element template
3644 XSLT_GET_IMPORT_PTR(method
, style
, method
)
3645 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
3646 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
3647 XSLT_GET_IMPORT_PTR(version
, style
, version
)
3648 XSLT_GET_IMPORT_PTR(encoding
, style
, encoding
)
3650 if ((method
!= NULL
) &&
3651 (!xmlStrEqual(method
, (const xmlChar
*) "xml"))) {
3652 if (xmlStrEqual(method
, (const xmlChar
*) "html")) {
3653 ctxt
->type
= XSLT_OUTPUT_HTML
;
3654 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3655 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
3657 if (version
!= NULL
) {
3658 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3659 xsltGetHTMLIDs(version
, &doctypePublic
, &doctypeSystem
);
3662 res
= htmlNewDocNoDtD(doctypeSystem
, doctypePublic
);
3666 res
->dict
= ctxt
->dict
;
3667 xmlDictReference(res
->dict
);
3668 } else if (xmlStrEqual(method
, (const xmlChar
*) "xhtml")) {
3669 xsltTransformError(ctxt
, NULL
, inst
,
3670 "xsltDocumentElem: unsupported method xhtml\n");
3671 ctxt
->type
= XSLT_OUTPUT_HTML
;
3672 res
= htmlNewDocNoDtD(doctypeSystem
, doctypePublic
);
3675 res
->dict
= ctxt
->dict
;
3676 xmlDictReference(res
->dict
);
3677 } else if (xmlStrEqual(method
, (const xmlChar
*) "text")) {
3678 ctxt
->type
= XSLT_OUTPUT_TEXT
;
3679 res
= xmlNewDoc(style
->version
);
3682 res
->dict
= ctxt
->dict
;
3683 xmlDictReference(res
->dict
);
3684 #ifdef WITH_XSLT_DEBUG
3685 xsltGenericDebug(xsltGenericDebugContext
,
3686 "reusing transformation dict for output\n");
3689 xsltTransformError(ctxt
, NULL
, inst
,
3690 "xsltDocumentElem: unsupported method (%s)\n",
3695 ctxt
->type
= XSLT_OUTPUT_XML
;
3696 res
= xmlNewDoc(style
->version
);
3699 res
->dict
= ctxt
->dict
;
3700 xmlDictReference(res
->dict
);
3701 #ifdef WITH_XSLT_DEBUG
3702 xsltGenericDebug(xsltGenericDebugContext
,
3703 "reusing transformation dict for output\n");
3706 res
->charset
= XML_CHAR_ENCODING_UTF8
;
3707 if (encoding
!= NULL
)
3708 res
->encoding
= xmlStrdup(encoding
);
3710 ctxt
->insert
= (xmlNodePtr
) res
;
3711 xsltApplySequenceConstructor(ctxt
, node
, inst
->children
, NULL
);
3714 * Do some post processing work depending on the generated output
3716 root
= xmlDocGetRootElement(res
);
3718 const xmlChar
*doctype
= NULL
;
3720 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
))
3721 doctype
= xmlDictQLookup(ctxt
->dict
, root
->ns
->prefix
, root
->name
);
3722 if (doctype
== NULL
)
3723 doctype
= root
->name
;
3726 * Apply the default selection of the method
3728 if ((method
== NULL
) &&
3729 (root
->ns
== NULL
) &&
3730 (!xmlStrcasecmp(root
->name
, (const xmlChar
*) "html"))) {
3733 tmp
= res
->children
;
3734 while ((tmp
!= NULL
) && (tmp
!= root
)) {
3735 if (tmp
->type
== XML_ELEMENT_NODE
)
3737 if ((tmp
->type
== XML_TEXT_NODE
) && (!xmlIsBlankNode(tmp
)))
3742 ctxt
->type
= XSLT_OUTPUT_HTML
;
3743 res
->type
= XML_HTML_DOCUMENT_NODE
;
3744 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
3745 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
3748 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3749 } else if (version
!= NULL
) {
3750 xsltGetHTMLIDs(version
, &doctypePublic
,
3752 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3754 xmlCreateIntSubset(res
, doctype
,
3762 if (ctxt
->type
== XSLT_OUTPUT_XML
) {
3763 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
3764 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
3765 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
3766 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
3773 * Calls to redirect:write also take an optional attribute append.
3774 * Attribute append="true|yes" which will attempt to simply append
3775 * to an existing file instead of always opening a new file. The
3776 * default behavior of always overwriting the file still happens
3777 * if we do not specify append.
3778 * Note that append use will forbid use of remote URI target.
3780 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
, (const xmlChar
*)"append",
3783 if (xmlStrEqual(prop
, (const xmlChar
*) "true") ||
3784 xmlStrEqual(prop
, (const xmlChar
*) "yes")) {
3785 style
->omitXmlDeclaration
= 1;
3786 redirect_write_append
= 1;
3788 style
->omitXmlDeclaration
= 0;
3792 if (redirect_write_append
) {
3795 f
= fopen((const char *) filename
, "ab");
3799 ret
= xsltSaveResultToFile(f
, res
, style
);
3803 ret
= xsltSaveResultToFilename((const char *) filename
, res
, style
, 0);
3806 xsltTransformError(ctxt
, NULL
, inst
,
3807 "xsltDocumentElem: unable to save to %s\n",
3809 #ifdef WITH_XSLT_DEBUG_EXTRA
3811 xsltGenericDebug(xsltGenericDebugContext
,
3812 "Wrote %d bytes to %s\n", ret
, filename
);
3817 ctxt
->output
= oldOutput
;
3818 ctxt
->insert
= oldInsert
;
3819 ctxt
->type
= oldType
;
3820 ctxt
->outputFile
= oldOutputFile
;
3823 if (filename
!= NULL
)
3826 xsltFreeStylesheet(style
);
3831 /************************************************************************
3833 * Most of the XSLT-1.0 transformations *
3835 ************************************************************************/
3839 * @ctxt: a XSLT process context
3840 * @node: the node in the source tree.
3841 * @inst: the xslt sort node
3842 * @comp: precomputed information
3844 * function attached to xsl:sort nodes, but this should not be
3848 xsltSort(xsltTransformContextPtr ctxt
,
3849 xmlNodePtr node ATTRIBUTE_UNUSED
, xmlNodePtr inst
,
3850 xsltElemPreCompPtr comp
) {
3852 xsltTransformError(ctxt
, NULL
, inst
,
3853 "xsl:sort : compilation failed\n");
3856 xsltTransformError(ctxt
, NULL
, inst
,
3857 "xsl:sort : improper use this should not be reached\n");
3862 * @ctxt: an XSLT process context
3863 * @node: the node in the source tree
3864 * @inst: the element node of the XSLT-copy instruction
3865 * @castedComp: computed information of the XSLT-copy instruction
3867 * Execute the XSLT-copy instruction on the source node.
3870 xsltCopy(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
3871 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
3873 #ifdef XSLT_REFACTORED
3874 xsltStyleItemCopyPtr comp
= (xsltStyleItemCopyPtr
) castedComp
;
3876 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
3878 xmlNodePtr copy
, oldInsert
;
3880 oldInsert
= ctxt
->insert
;
3881 if (ctxt
->insert
!= NULL
) {
3882 switch (node
->type
) {
3884 case XML_CDATA_SECTION_NODE
:
3886 * This text comes from the stylesheet
3887 * For stylesheets, the set of whitespace-preserving
3888 * element names consists of just xsl:text.
3890 #ifdef WITH_XSLT_DEBUG_PROCESS
3891 if (node
->type
== XML_CDATA_SECTION_NODE
) {
3892 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3893 "xsltCopy: CDATA text %s\n", node
->content
));
3895 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3896 "xsltCopy: text %s\n", node
->content
));
3899 xsltCopyText(ctxt
, ctxt
->insert
, node
, 0);
3901 case XML_DOCUMENT_NODE
:
3902 case XML_HTML_DOCUMENT_NODE
:
3904 case XML_ELEMENT_NODE
:
3906 * REVISIT NOTE: The "fake" is a doc-node, not an element node.
3908 * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3912 #ifdef WITH_XSLT_DEBUG_PROCESS
3913 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3914 "xsltCopy: node %s\n", node
->name
));
3916 copy
= xsltShallowCopyElem(ctxt
, node
, ctxt
->insert
, 0);
3917 ctxt
->insert
= copy
;
3918 if (comp
->use
!= NULL
) {
3919 xsltApplyAttributeSet(ctxt
, node
, inst
, comp
->use
);
3922 case XML_ATTRIBUTE_NODE
: {
3923 #ifdef WITH_XSLT_DEBUG_PROCESS
3924 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3925 "xsltCopy: attribute %s\n", node
->name
));
3928 * REVISIT: We could also raise an error if the parent is not
3930 * OPTIMIZE TODO: Can we set the value/children of the
3931 * attribute without an intermediate copy of the string value?
3933 xsltShallowCopyAttr(ctxt
, inst
, ctxt
->insert
, (xmlAttrPtr
) node
);
3937 #ifdef WITH_XSLT_DEBUG_PROCESS
3938 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3939 "xsltCopy: PI %s\n", node
->name
));
3941 copy
= xmlNewDocPI(ctxt
->insert
->doc
, node
->name
,
3943 copy
= xsltAddChild(ctxt
->insert
, copy
);
3945 case XML_COMMENT_NODE
:
3946 #ifdef WITH_XSLT_DEBUG_PROCESS
3947 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3948 "xsltCopy: comment\n"));
3950 copy
= xmlNewComment(node
->content
);
3951 copy
= xsltAddChild(ctxt
->insert
, copy
);
3953 case XML_NAMESPACE_DECL
:
3954 #ifdef WITH_XSLT_DEBUG_PROCESS
3955 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY
,xsltGenericDebug(xsltGenericDebugContext
,
3956 "xsltCopy: namespace declaration\n"));
3958 xsltShallowCopyNsNode(ctxt
, inst
, ctxt
->insert
, (xmlNsPtr
)node
);
3966 switch (node
->type
) {
3967 case XML_DOCUMENT_NODE
:
3968 case XML_HTML_DOCUMENT_NODE
:
3969 case XML_ELEMENT_NODE
:
3970 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, inst
->children
,
3976 ctxt
->insert
= oldInsert
;
3981 * @ctxt: a XSLT process context
3982 * @node: the node in the source tree.
3983 * @inst: the xslt text node
3984 * @comp: precomputed information
3986 * Process the xslt text node on the source node
3989 xsltText(xsltTransformContextPtr ctxt
, xmlNodePtr node ATTRIBUTE_UNUSED
,
3990 xmlNodePtr inst
, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
) {
3991 if ((inst
->children
!= NULL
) && (comp
!= NULL
)) {
3992 xmlNodePtr text
= inst
->children
;
3995 while (text
!= NULL
) {
3996 if ((text
->type
!= XML_TEXT_NODE
) &&
3997 (text
->type
!= XML_CDATA_SECTION_NODE
)) {
3998 xsltTransformError(ctxt
, NULL
, inst
,
3999 "xsl:text content problem\n");
4002 copy
= xmlNewDocText(ctxt
->output
, text
->content
);
4003 if (text
->type
!= XML_CDATA_SECTION_NODE
) {
4004 #ifdef WITH_XSLT_DEBUG_PARSING
4005 xsltGenericDebug(xsltGenericDebugContext
,
4006 "Disable escaping: %s\n", text
->content
);
4008 copy
->name
= xmlStringTextNoenc
;
4010 copy
= xsltAddChild(ctxt
->insert
, copy
);
4018 * @ctxt: a XSLT process context
4019 * @node: the node in the source tree.
4020 * @inst: the xslt element node
4021 * @castedComp: precomputed information
4023 * Process the xslt element node on the source node
4026 xsltElement(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4027 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
) {
4028 #ifdef XSLT_REFACTORED
4029 xsltStyleItemElementPtr comp
= (xsltStyleItemElementPtr
) castedComp
;
4031 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4033 xmlChar
*prop
= NULL
;
4034 const xmlChar
*name
, *prefix
= NULL
, *nsName
= NULL
;
4036 xmlNodePtr oldInsert
;
4038 if (ctxt
->insert
== NULL
)
4042 * A comp->has_name == 0 indicates that we need to skip this instruction,
4043 * since it was evaluated to be invalid already during compilation.
4045 if (!comp
->has_name
)
4051 oldInsert
= ctxt
->insert
;
4053 if (comp
->name
== NULL
) {
4054 /* TODO: fix attr acquisition wrt to the XSLT namespace */
4055 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4056 (const xmlChar
*) "name", XSLT_NAMESPACE
);
4058 xsltTransformError(ctxt
, NULL
, inst
,
4059 "xsl:element: The attribute 'name' is missing.\n");
4062 if (xmlValidateQName(prop
, 0)) {
4063 xsltTransformError(ctxt
, NULL
, inst
,
4064 "xsl:element: The effective name '%s' is not a "
4065 "valid QName.\n", prop
);
4066 /* we fall through to catch any further errors, if possible */
4068 name
= xsltSplitQName(ctxt
->dict
, prop
, &prefix
);
4072 * The "name" value was static.
4074 #ifdef XSLT_REFACTORED
4075 prefix
= comp
->nsPrefix
;
4078 name
= xsltSplitQName(ctxt
->dict
, comp
->name
, &prefix
);
4083 * Create the new element
4085 if (ctxt
->output
->dict
== ctxt
->dict
) {
4086 copy
= xmlNewDocNodeEatName(ctxt
->output
, NULL
, (xmlChar
*)name
, NULL
);
4088 copy
= xmlNewDocNode(ctxt
->output
, NULL
, (xmlChar
*)name
, NULL
);
4091 xsltTransformError(ctxt
, NULL
, inst
,
4092 "xsl:element : creation of %s failed\n", name
);
4095 copy
= xsltAddChild(ctxt
->insert
, copy
);
4097 xsltTransformError(ctxt
, NULL
, inst
,
4098 "xsl:element : xsltAddChild failed\n");
4107 if (comp
->ns
!= NULL
) {
4109 * No AVT; just plain text for the namespace name.
4111 if (comp
->ns
[0] != 0)
4118 /* TODO: check attr acquisition wrt to the XSLT namespace */
4119 tmpNsName
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4120 (const xmlChar
*) "namespace", XSLT_NAMESPACE
);
4123 * "If the string is empty, then the expanded-name of the
4124 * attribute has a null namespace URI."
4126 if ((tmpNsName
!= NULL
) && (tmpNsName
[0] != 0))
4127 nsName
= xmlDictLookup(ctxt
->dict
, BAD_CAST tmpNsName
, -1);
4131 if (xmlStrEqual(nsName
, BAD_CAST
"http://www.w3.org/2000/xmlns/")) {
4132 xsltTransformError(ctxt
, NULL
, inst
,
4133 "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
4137 if (xmlStrEqual(nsName
, XML_XML_NAMESPACE
)) {
4138 prefix
= BAD_CAST
"xml";
4139 } else if (xmlStrEqual(prefix
, BAD_CAST
"xml")) {
4146 * "If the namespace attribute is not present, then the QName is
4147 * expanded into an expanded-name using the namespace declarations
4148 * in effect for the xsl:element element, including any default
4149 * namespace declaration.
4151 ns
= xmlSearchNs(inst
->doc
, inst
, prefix
);
4154 * TODO: Check this in the compilation layer in case it's a
4157 if (prefix
!= NULL
) {
4158 xsltTransformError(ctxt
, NULL
, inst
,
4159 "xsl:element: The QName '%s:%s' has no "
4160 "namespace binding in scope in the stylesheet; "
4161 "this is an error, since the namespace was not "
4162 "specified by the instruction itself.\n", prefix
, name
);
4168 * Find/create a matching ns-decl in the result tree.
4170 if (nsName
!= NULL
) {
4171 if (xmlStrEqual(prefix
, BAD_CAST
"xmlns")) {
4172 /* Don't use a prefix of "xmlns" */
4173 xmlChar
*pref
= xmlStrdup(BAD_CAST
"ns_1");
4175 copy
->ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, pref
, copy
);
4179 copy
->ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, prefix
,
4182 } else if ((copy
->parent
!= NULL
) &&
4183 (copy
->parent
->type
== XML_ELEMENT_NODE
) &&
4184 (copy
->parent
->ns
!= NULL
))
4187 * "Undeclare" the default namespace.
4189 xsltGetSpecialNamespace(ctxt
, inst
, NULL
, NULL
, copy
);
4192 ctxt
->insert
= copy
;
4194 if (comp
->has_use
) {
4195 if (comp
->use
!= NULL
) {
4196 xsltApplyAttributeSet(ctxt
, node
, inst
, comp
->use
);
4198 xmlChar
*attrSets
= NULL
;
4200 * BUG TODO: use-attribute-sets is not a value template.
4201 * use-attribute-sets = qnames
4203 attrSets
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4204 (const xmlChar
*)"use-attribute-sets", NULL
);
4205 if (attrSets
!= NULL
) {
4206 xsltApplyAttributeSet(ctxt
, node
, inst
, attrSets
);
4212 * Instantiate the sequence constructor.
4214 if (inst
->children
!= NULL
)
4215 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, inst
->children
,
4219 ctxt
->insert
= oldInsert
;
4226 * @ctxt: a XSLT process context
4227 * @node: the node in the source tree.
4228 * @inst: the xslt comment node
4229 * @comp: precomputed information
4231 * Process the xslt comment node on the source node
4234 xsltComment(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4235 xmlNodePtr inst
, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
) {
4236 xmlChar
*value
= NULL
;
4237 xmlNodePtr commentNode
;
4240 value
= xsltEvalTemplateString(ctxt
, node
, inst
);
4241 /* TODO: use or generate the compiled form */
4242 len
= xmlStrlen(value
);
4244 if ((value
[len
-1] == '-') ||
4245 (xmlStrstr(value
, BAD_CAST
"--"))) {
4246 xsltTransformError(ctxt
, NULL
, inst
,
4247 "xsl:comment : '--' or ending '-' not allowed in comment\n");
4248 /* fall through to try to catch further errors */
4251 #ifdef WITH_XSLT_DEBUG_PROCESS
4252 if (value
== NULL
) {
4253 XSLT_TRACE(ctxt
,XSLT_TRACE_COMMENT
,xsltGenericDebug(xsltGenericDebugContext
,
4254 "xsltComment: empty\n"));
4256 XSLT_TRACE(ctxt
,XSLT_TRACE_COMMENT
,xsltGenericDebug(xsltGenericDebugContext
,
4257 "xsltComment: content %s\n", value
));
4261 commentNode
= xmlNewComment(value
);
4262 commentNode
= xsltAddChild(ctxt
->insert
, commentNode
);
4269 * xsltProcessingInstruction:
4270 * @ctxt: a XSLT process context
4271 * @node: the node in the source tree.
4272 * @inst: the xslt processing-instruction node
4273 * @castedComp: precomputed information
4275 * Process the xslt processing-instruction node on the source node
4278 xsltProcessingInstruction(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4279 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
) {
4280 #ifdef XSLT_REFACTORED
4281 xsltStyleItemPIPtr comp
= (xsltStyleItemPIPtr
) castedComp
;
4283 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4285 const xmlChar
*name
;
4286 xmlChar
*value
= NULL
;
4290 if (ctxt
->insert
== NULL
)
4292 if (comp
->has_name
== 0)
4294 if (comp
->name
== NULL
) {
4295 name
= xsltEvalAttrValueTemplate(ctxt
, inst
,
4296 (const xmlChar
*)"name", NULL
);
4298 xsltTransformError(ctxt
, NULL
, inst
,
4299 "xsl:processing-instruction : name is missing\n");
4305 /* TODO: check that it's both an an NCName and a PITarget. */
4308 value
= xsltEvalTemplateString(ctxt
, node
, inst
);
4309 if (xmlStrstr(value
, BAD_CAST
"?>") != NULL
) {
4310 xsltTransformError(ctxt
, NULL
, inst
,
4311 "xsl:processing-instruction: '?>' not allowed within PI content\n");
4314 #ifdef WITH_XSLT_DEBUG_PROCESS
4315 if (value
== NULL
) {
4316 XSLT_TRACE(ctxt
,XSLT_TRACE_PI
,xsltGenericDebug(xsltGenericDebugContext
,
4317 "xsltProcessingInstruction: %s empty\n", name
));
4319 XSLT_TRACE(ctxt
,XSLT_TRACE_PI
,xsltGenericDebug(xsltGenericDebugContext
,
4320 "xsltProcessingInstruction: %s content %s\n", name
, value
));
4324 pi
= xmlNewDocPI(ctxt
->insert
->doc
, name
, value
);
4325 pi
= xsltAddChild(ctxt
->insert
, pi
);
4328 if ((name
!= NULL
) && (name
!= comp
->name
))
4329 xmlFree((xmlChar
*) name
);
4336 * @ctxt: an XSLT transformation context
4337 * @node: the current node in the source tree
4338 * @inst: the element node of the XSLT copy-of instruction
4339 * @castedComp: precomputed information of the XSLT copy-of instruction
4341 * Process the XSLT copy-of instruction.
4344 xsltCopyOf(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4345 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
) {
4346 #ifdef XSLT_REFACTORED
4347 xsltStyleItemCopyOfPtr comp
= (xsltStyleItemCopyOfPtr
) castedComp
;
4349 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4351 xmlXPathObjectPtr res
= NULL
;
4352 xmlNodeSetPtr list
= NULL
;
4355 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
))
4357 if ((comp
== NULL
) || (comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
4358 xsltTransformError(ctxt
, NULL
, inst
,
4359 "xsl:copy-of : compilation failed\n");
4365 * "The xsl:copy-of element can be used to insert a result tree
4366 * fragment into the result tree, without first converting it to
4367 * a string as xsl:value-of does (see [7.6.1 Generating Text with
4368 * xsl:value-of]). The required select attribute contains an
4369 * expression. When the result of evaluating the expression is a
4370 * result tree fragment, the complete fragment is copied into the
4371 * result tree. When the result is a node-set, all the nodes in the
4372 * set are copied in document order into the result tree; copying
4373 * an element node copies the attribute nodes, namespace nodes and
4374 * children of the element node as well as the element node itself;
4375 * a root node is copied by copying its children. When the result
4376 * is neither a node-set nor a result tree fragment, the result is
4377 * converted to a string and then inserted into the result tree,
4378 * as with xsl:value-of.
4381 #ifdef WITH_XSLT_DEBUG_PROCESS
4382 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4383 "xsltCopyOf: select %s\n", comp
->select
));
4387 * Evaluate the "select" expression.
4389 res
= xsltPreCompEval(ctxt
, node
, comp
);
4392 if (res
->type
== XPATH_NODESET
) {
4397 #ifdef WITH_XSLT_DEBUG_PROCESS
4398 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4399 "xsltCopyOf: result is a node set\n"));
4401 list
= res
->nodesetval
;
4405 * The list is already sorted in document order by XPath.
4406 * Append everything in this order under ctxt->insert.
4408 for (i
= 0;i
< list
->nodeNr
;i
++) {
4409 cur
= list
->nodeTab
[i
];
4412 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
4413 (cur
->type
== XML_HTML_DOCUMENT_NODE
))
4415 xsltCopyTreeList(ctxt
, inst
,
4416 cur
->children
, ctxt
->insert
, 0, 0);
4417 } else if (cur
->type
== XML_ATTRIBUTE_NODE
) {
4418 xsltShallowCopyAttr(ctxt
, inst
,
4419 ctxt
->insert
, (xmlAttrPtr
) cur
);
4421 xsltCopyTree(ctxt
, inst
, cur
, ctxt
->insert
, 0, 0);
4425 } else if (res
->type
== XPATH_XSLT_TREE
) {
4427 * Result tree fragment
4428 * --------------------
4429 * E.g. via <xsl:variable ...><foo/></xsl:variable>
4430 * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4432 #ifdef WITH_XSLT_DEBUG_PROCESS
4433 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4434 "xsltCopyOf: result is a result tree fragment\n"));
4436 list
= res
->nodesetval
;
4437 if ((list
!= NULL
) && (list
->nodeTab
!= NULL
) &&
4438 (list
->nodeTab
[0] != NULL
) &&
4439 (IS_XSLT_REAL_NODE(list
->nodeTab
[0])))
4441 xsltCopyTreeList(ctxt
, inst
,
4442 list
->nodeTab
[0]->children
, ctxt
->insert
, 0, 0);
4445 xmlChar
*value
= NULL
;
4447 * Convert to a string.
4449 value
= xmlXPathCastToString(res
);
4450 if (value
== NULL
) {
4451 xsltTransformError(ctxt
, NULL
, inst
,
4452 "Internal error in xsltCopyOf(): "
4453 "failed to cast an XPath object to string.\n");
4454 ctxt
->state
= XSLT_STATE_STOPPED
;
4456 if (value
[0] != 0) {
4458 * Append content as text node.
4460 xsltCopyTextString(ctxt
, ctxt
->insert
, value
, 0);
4464 #ifdef WITH_XSLT_DEBUG_PROCESS
4465 XSLT_TRACE(ctxt
,XSLT_TRACE_COPY_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4466 "xsltCopyOf: result %s\n", res
->stringval
));
4471 ctxt
->state
= XSLT_STATE_STOPPED
;
4475 xmlXPathFreeObject(res
);
4480 * @ctxt: a XSLT process context
4481 * @node: the node in the source tree.
4482 * @inst: the xslt value-of node
4483 * @castedComp: precomputed information
4485 * Process the xslt value-of node on the source node
4488 xsltValueOf(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4489 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
4491 #ifdef XSLT_REFACTORED
4492 xsltStyleItemValueOfPtr comp
= (xsltStyleItemValueOfPtr
) castedComp
;
4494 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4496 xmlXPathObjectPtr res
= NULL
;
4497 xmlChar
*value
= NULL
;
4499 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
))
4502 if ((comp
== NULL
) || (comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
4503 xsltTransformError(ctxt
, NULL
, inst
,
4504 "Internal error in xsltValueOf(): "
4505 "The XSLT 'value-of' instruction was not compiled.\n");
4509 #ifdef WITH_XSLT_DEBUG_PROCESS
4510 XSLT_TRACE(ctxt
,XSLT_TRACE_VALUE_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4511 "xsltValueOf: select %s\n", comp
->select
));
4514 res
= xsltPreCompEval(ctxt
, node
, comp
);
4517 * Cast the XPath object to string.
4520 value
= xmlXPathCastToString(res
);
4521 if (value
== NULL
) {
4522 xsltTransformError(ctxt
, NULL
, inst
,
4523 "Internal error in xsltValueOf(): "
4524 "failed to cast an XPath object to string.\n");
4525 ctxt
->state
= XSLT_STATE_STOPPED
;
4528 if (value
[0] != 0) {
4529 xsltCopyTextString(ctxt
, ctxt
->insert
, value
, comp
->noescape
);
4532 xsltTransformError(ctxt
, NULL
, inst
,
4533 "XPath evaluation returned no result.\n");
4534 ctxt
->state
= XSLT_STATE_STOPPED
;
4538 #ifdef WITH_XSLT_DEBUG_PROCESS
4540 XSLT_TRACE(ctxt
,XSLT_TRACE_VALUE_OF
,xsltGenericDebug(xsltGenericDebugContext
,
4541 "xsltValueOf: result '%s'\n", value
));
4549 xmlXPathFreeObject(res
);
4554 * @ctxt: a XSLT process context
4555 * @node: the node in the source tree.
4556 * @inst: the xslt number node
4557 * @castedComp: precomputed information
4559 * Process the xslt number node on the source node
4562 xsltNumber(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4563 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
4565 #ifdef XSLT_REFACTORED
4566 xsltStyleItemNumberPtr comp
= (xsltStyleItemNumberPtr
) castedComp
;
4568 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4570 xmlXPathContextPtr xpctxt
;
4571 xmlNsPtr
*oldXPNamespaces
;
4575 xsltTransformError(ctxt
, NULL
, inst
,
4576 "xsl:number : compilation failed\n");
4580 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
4583 comp
->numdata
.doc
= inst
->doc
;
4584 comp
->numdata
.node
= inst
;
4586 xpctxt
= ctxt
->xpathCtxt
;
4587 oldXPNsNr
= xpctxt
->nsNr
;
4588 oldXPNamespaces
= xpctxt
->namespaces
;
4590 #ifdef XSLT_REFACTORED
4591 if (comp
->inScopeNs
!= NULL
) {
4592 xpctxt
->namespaces
= comp
->inScopeNs
->list
;
4593 xpctxt
->nsNr
= comp
->inScopeNs
->xpathNumber
;
4595 xpctxt
->namespaces
= NULL
;
4599 xpctxt
->namespaces
= comp
->nsList
;
4600 xpctxt
->nsNr
= comp
->nsNr
;
4603 xsltNumberFormat(ctxt
, &comp
->numdata
, node
);
4605 xpctxt
->nsNr
= oldXPNsNr
;
4606 xpctxt
->namespaces
= oldXPNamespaces
;
4611 * @ctxt: an XSLT transformation context
4612 * @contextNode: the current node in the source tree.
4613 * @inst: the element node of the XSLT 'apply-imports' instruction
4614 * @comp: the compiled instruction
4616 * Process the XSLT apply-imports element.
4619 xsltApplyImports(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
4621 xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
)
4623 xsltTemplatePtr templ
;
4625 if ((ctxt
== NULL
) || (inst
== NULL
))
4629 xsltTransformError(ctxt
, NULL
, inst
,
4630 "Internal error in xsltApplyImports(): "
4631 "The XSLT 'apply-imports' instruction was not compiled.\n");
4635 * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4636 * same; the former is the "Current Template Rule" as defined by the
4637 * XSLT spec, the latter is simply the template struct being
4638 * currently processed.
4640 if (ctxt
->currentTemplateRule
== NULL
) {
4643 * "[ERR XTDE0560] It is a non-recoverable dynamic error if
4644 * xsl:apply-imports or xsl:next-match is evaluated when the
4645 * current template rule is null."
4647 xsltTransformError(ctxt
, NULL
, inst
,
4648 "It is an error to call 'apply-imports' "
4649 "when there's no current template rule.\n");
4653 * TODO: Check if this is correct.
4655 templ
= xsltGetTemplate(ctxt
, contextNode
,
4656 ctxt
->currentTemplateRule
->style
);
4658 if (templ
!= NULL
) {
4659 xsltTemplatePtr oldCurTemplRule
= ctxt
->currentTemplateRule
;
4661 * Set the current template rule.
4663 ctxt
->currentTemplateRule
= templ
;
4665 * URGENT TODO: Need xsl:with-param be handled somehow here?
4667 xsltApplyXSLTTemplate(ctxt
, contextNode
, templ
->content
,
4670 ctxt
->currentTemplateRule
= oldCurTemplRule
;
4673 /* Use built-in templates. */
4674 xsltDefaultProcessOneNode(ctxt
, contextNode
, NULL
);
4680 * @ctxt: a XSLT transformation context
4681 * @node: the "current node" in the source tree
4682 * @inst: the XSLT 'call-template' instruction
4683 * @castedComp: the compiled information of the instruction
4685 * Processes the XSLT call-template instruction on the source node.
4688 xsltCallTemplate(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4689 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
4691 #ifdef XSLT_REFACTORED
4692 xsltStyleItemCallTemplatePtr comp
=
4693 (xsltStyleItemCallTemplatePtr
) castedComp
;
4695 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4697 xsltStackElemPtr withParams
= NULL
;
4699 if (ctxt
->insert
== NULL
)
4702 xsltTransformError(ctxt
, NULL
, inst
,
4703 "The XSLT 'call-template' instruction was not compiled.\n");
4708 * The template must have been precomputed
4710 if (comp
->templ
== NULL
) {
4711 comp
->templ
= xsltFindTemplate(ctxt
, comp
->name
, comp
->ns
);
4712 if (comp
->templ
== NULL
) {
4713 if (comp
->ns
!= NULL
) {
4714 xsltTransformError(ctxt
, NULL
, inst
,
4715 "The called template '{%s}%s' was not found.\n",
4716 comp
->ns
, comp
->name
);
4718 xsltTransformError(ctxt
, NULL
, inst
,
4719 "The called template '%s' was not found.\n",
4726 #ifdef WITH_XSLT_DEBUG_PROCESS
4727 if ((comp
!= NULL
) && (comp
->name
!= NULL
))
4728 XSLT_TRACE(ctxt
,XSLT_TRACE_CALL_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
4729 "call-template: name %s\n", comp
->name
));
4732 if (inst
->children
) {
4734 xsltStackElemPtr param
;
4736 cur
= inst
->children
;
4737 while (cur
!= NULL
) {
4738 #ifdef WITH_DEBUGGER
4739 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
4740 xslHandleDebugger(cur
, node
, comp
->templ
, ctxt
);
4742 if (ctxt
->state
== XSLT_STATE_STOPPED
) break;
4744 * TODO: The "with-param"s could be part of the "call-template"
4745 * structure. Avoid to "search" for params dynamically
4746 * in the XML tree every time.
4748 if (IS_XSLT_ELEM(cur
)) {
4749 if (IS_XSLT_NAME(cur
, "with-param")) {
4750 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
4751 if (param
!= NULL
) {
4752 param
->next
= withParams
;
4756 xsltGenericError(xsltGenericErrorContext
,
4757 "xsl:call-template: misplaced xsl:%s\n", cur
->name
);
4760 xsltGenericError(xsltGenericErrorContext
,
4761 "xsl:call-template: misplaced %s element\n", cur
->name
);
4767 * Create a new frame using the params first
4769 xsltApplyXSLTTemplate(ctxt
, node
, comp
->templ
->content
, comp
->templ
,
4771 if (withParams
!= NULL
)
4772 xsltFreeStackElemList(withParams
);
4774 #ifdef WITH_XSLT_DEBUG_PROCESS
4775 if ((comp
!= NULL
) && (comp
->name
!= NULL
))
4776 XSLT_TRACE(ctxt
,XSLT_TRACE_CALL_TEMPLATE
,xsltGenericDebug(xsltGenericDebugContext
,
4777 "call-template returned: name %s\n", comp
->name
));
4782 * xsltApplyTemplates:
4783 * @ctxt: a XSLT transformation context
4784 * @node: the 'current node' in the source tree
4785 * @inst: the element node of an XSLT 'apply-templates' instruction
4786 * @castedComp: the compiled instruction
4788 * Processes the XSLT 'apply-templates' instruction on the current node.
4791 xsltApplyTemplates(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
4792 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
4794 #ifdef XSLT_REFACTORED
4795 xsltStyleItemApplyTemplatesPtr comp
=
4796 (xsltStyleItemApplyTemplatesPtr
) castedComp
;
4798 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
4801 xmlNodePtr cur
, delNode
= NULL
, oldContextNode
;
4802 xmlNodeSetPtr list
= NULL
, oldList
;
4803 xsltStackElemPtr withParams
= NULL
;
4804 int oldXPProximityPosition
, oldXPContextSize
;
4805 const xmlChar
*oldMode
, *oldModeURI
;
4807 xsltDocumentPtr oldDocInfo
;
4808 xmlXPathContextPtr xpctxt
;
4811 xsltTransformError(ctxt
, NULL
, inst
,
4812 "xsl:apply-templates : compilation failed\n");
4815 if ((ctxt
== NULL
) || (node
== NULL
) || (inst
== NULL
) || (comp
== NULL
))
4818 #ifdef WITH_XSLT_DEBUG_PROCESS
4819 if ((node
!= NULL
) && (node
->name
!= NULL
))
4820 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4821 "xsltApplyTemplates: node: '%s'\n", node
->name
));
4824 xpctxt
= ctxt
->xpathCtxt
;
4826 * Save context states.
4828 oldContextNode
= ctxt
->node
;
4829 oldMode
= ctxt
->mode
;
4830 oldModeURI
= ctxt
->modeURI
;
4831 oldDocInfo
= ctxt
->document
;
4832 oldList
= ctxt
->nodeList
;
4835 * The xpath context size and proximity position, as
4836 * well as the xpath and context documents, may be changed
4837 * so we save their initial state and will restore on exit
4839 oldXPContextSize
= xpctxt
->contextSize
;
4840 oldXPProximityPosition
= xpctxt
->proximityPosition
;
4841 oldXPDoc
= xpctxt
->doc
;
4846 ctxt
->mode
= comp
->mode
;
4847 ctxt
->modeURI
= comp
->modeURI
;
4849 if (comp
->select
!= NULL
) {
4850 xmlXPathObjectPtr res
= NULL
;
4852 if (comp
->comp
== NULL
) {
4853 xsltTransformError(ctxt
, NULL
, inst
,
4854 "xsl:apply-templates : compilation failed\n");
4857 #ifdef WITH_XSLT_DEBUG_PROCESS
4858 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4859 "xsltApplyTemplates: select %s\n", comp
->select
));
4862 res
= xsltPreCompEval(ctxt
, node
, comp
);
4865 if (res
->type
== XPATH_NODESET
) {
4866 list
= res
->nodesetval
; /* consume the node set */
4867 res
->nodesetval
= NULL
;
4869 xsltTransformError(ctxt
, NULL
, inst
,
4870 "The 'select' expression did not evaluate to a "
4872 ctxt
->state
= XSLT_STATE_STOPPED
;
4873 xmlXPathFreeObject(res
);
4876 xmlXPathFreeObject(res
);
4878 * Note: An xsl:apply-templates with a 'select' attribute,
4879 * can change the current source doc.
4882 xsltTransformError(ctxt
, NULL
, inst
,
4883 "Failed to evaluate the 'select' expression.\n");
4884 ctxt
->state
= XSLT_STATE_STOPPED
;
4888 #ifdef WITH_XSLT_DEBUG_PROCESS
4889 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4890 "xsltApplyTemplates: select didn't evaluate to a node list\n"));
4896 * NOTE: Previously a document info (xsltDocument) was
4897 * created and attached to the Result Tree Fragment.
4898 * But such a document info is created on demand in
4899 * xsltKeyFunction() (functions.c), so we need to create
4900 * it here beforehand.
4901 * In order to take care of potential keys we need to
4902 * do some extra work for the case when a Result Tree Fragment
4903 * is converted into a nodeset (e.g. exslt:node-set()) :
4904 * We attach a "pseudo-doc" (xsltDocument) to _private.
4905 * This xsltDocument, together with the keyset, will be freed
4906 * when the Result Tree Fragment is freed.
4910 if ((ctxt
->nbKeys
> 0) &&
4911 (list
->nodeNr
!= 0) &&
4912 (list
->nodeTab
[0]->doc
!= NULL
) &&
4913 XSLT_IS_RES_TREE_FRAG(list
->nodeTab
[0]->doc
))
4916 * NOTE that it's also OK if @effectiveDocInfo will be
4920 effectiveDocInfo
= list
->nodeTab
[0]->doc
->_private
;
4925 * Build an XPath node set with the children
4927 list
= xmlXPathNodeSetCreate(NULL
);
4930 if (node
->type
!= XML_NAMESPACE_DECL
)
4931 cur
= node
->children
;
4934 while (cur
!= NULL
) {
4935 switch (cur
->type
) {
4937 if ((IS_BLANK_NODE(cur
)) &&
4938 (cur
->parent
!= NULL
) &&
4939 (cur
->parent
->type
== XML_ELEMENT_NODE
) &&
4940 (ctxt
->style
->stripSpaces
!= NULL
)) {
4943 if (cur
->parent
->ns
!= NULL
) {
4944 val
= (const xmlChar
*)
4945 xmlHashLookup2(ctxt
->style
->stripSpaces
,
4947 cur
->parent
->ns
->href
);
4949 val
= (const xmlChar
*)
4950 xmlHashLookup2(ctxt
->style
->stripSpaces
,
4952 cur
->parent
->ns
->href
);
4955 val
= (const xmlChar
*)
4956 xmlHashLookup2(ctxt
->style
->stripSpaces
,
4957 cur
->parent
->name
, NULL
);
4959 if ((val
!= NULL
) &&
4960 (xmlStrEqual(val
, (xmlChar
*) "strip"))) {
4965 /* no break on purpose */
4966 case XML_ELEMENT_NODE
:
4967 case XML_DOCUMENT_NODE
:
4968 case XML_HTML_DOCUMENT_NODE
:
4969 case XML_CDATA_SECTION_NODE
:
4971 case XML_COMMENT_NODE
:
4972 xmlXPathNodeSetAddUnique(list
, cur
);
4975 /* Unlink the DTD, it's still reachable
4976 * using doc->intSubset */
4977 if (cur
->next
!= NULL
)
4978 cur
->next
->prev
= cur
->prev
;
4979 if (cur
->prev
!= NULL
)
4980 cur
->prev
->next
= cur
->next
;
4982 case XML_NAMESPACE_DECL
:
4985 #ifdef WITH_XSLT_DEBUG_PROCESS
4986 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4987 "xsltApplyTemplates: skipping cur type %d\n",
4993 if (delNode
!= NULL
) {
4994 #ifdef WITH_XSLT_DEBUG_PROCESS
4995 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
4996 "xsltApplyTemplates: removing ignorable blank cur\n"));
4998 xmlUnlinkNode(delNode
);
4999 xmlFreeNode(delNode
);
5005 #ifdef WITH_XSLT_DEBUG_PROCESS
5007 XSLT_TRACE(ctxt
,XSLT_TRACE_APPLY_TEMPLATES
,xsltGenericDebug(xsltGenericDebugContext
,
5008 "xsltApplyTemplates: list of %d nodes\n", list
->nodeNr
));
5011 if ((list
== NULL
) || (list
->nodeNr
== 0))
5015 * Set the context's node set and size; this is also needed for
5016 * for xsltDoSortFunction().
5018 ctxt
->nodeList
= list
;
5020 * Process xsl:with-param and xsl:sort instructions.
5021 * (The code became so verbose just to avoid the
5022 * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
5023 * BUG TODO: We are not using namespaced potentially defined on the
5024 * xsl:sort or xsl:with-param elements; XPath expression might fail.
5026 if (inst
->children
) {
5027 xsltStackElemPtr param
;
5029 cur
= inst
->children
;
5032 #ifdef WITH_DEBUGGER
5033 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
5034 xslHandleDebugger(cur
, node
, NULL
, ctxt
);
5036 if (ctxt
->state
== XSLT_STATE_STOPPED
)
5038 if (cur
->type
== XML_TEXT_NODE
) {
5042 if (! IS_XSLT_ELEM(cur
))
5044 if (IS_XSLT_NAME(cur
, "with-param")) {
5045 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
5046 if (param
!= NULL
) {
5047 param
->next
= withParams
;
5051 if (IS_XSLT_NAME(cur
, "sort")) {
5052 xsltTemplatePtr oldCurTempRule
=
5053 ctxt
->currentTemplateRule
;
5055 xmlNodePtr sorts
[XSLT_MAX_SORT
];
5057 sorts
[nbsorts
++] = cur
;
5061 #ifdef WITH_DEBUGGER
5062 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
5063 xslHandleDebugger(cur
, node
, NULL
, ctxt
);
5065 if (ctxt
->state
== XSLT_STATE_STOPPED
)
5068 if (cur
->type
== XML_TEXT_NODE
) {
5073 if (! IS_XSLT_ELEM(cur
))
5075 if (IS_XSLT_NAME(cur
, "with-param")) {
5076 param
= xsltParseStylesheetCallerParam(ctxt
, cur
);
5077 if (param
!= NULL
) {
5078 param
->next
= withParams
;
5082 if (IS_XSLT_NAME(cur
, "sort")) {
5083 if (nbsorts
>= XSLT_MAX_SORT
) {
5084 xsltTransformError(ctxt
, NULL
, cur
,
5085 "The number (%d) of xsl:sort instructions exceeds the "
5086 "maximum allowed by this processor's settings.\n",
5088 ctxt
->state
= XSLT_STATE_STOPPED
;
5091 sorts
[nbsorts
++] = cur
;
5097 * The "current template rule" is cleared for xsl:sort.
5099 ctxt
->currentTemplateRule
= NULL
;
5103 xsltDoSortFunction(ctxt
, sorts
, nbsorts
);
5104 ctxt
->currentTemplateRule
= oldCurTempRule
;
5110 xpctxt
->contextSize
= list
->nodeNr
;
5112 * Apply templates for all selected source nodes.
5114 for (i
= 0; i
< list
->nodeNr
; i
++) {
5115 cur
= list
->nodeTab
[i
];
5117 * The node becomes the "current node".
5121 * An xsl:apply-templates can change the current context doc.
5122 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5124 if ((cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->doc
!= NULL
))
5125 xpctxt
->doc
= cur
->doc
;
5127 xpctxt
->proximityPosition
= i
+ 1;
5129 * Find and apply a template for this node.
5131 xsltProcessOneNode(ctxt
, cur
, withParams
);
5137 * Free the parameter list.
5139 if (withParams
!= NULL
)
5140 xsltFreeStackElemList(withParams
);
5142 xmlXPathFreeNodeSet(list
);
5144 * Restore context states.
5146 xpctxt
->doc
= oldXPDoc
;
5147 xpctxt
->contextSize
= oldXPContextSize
;
5148 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5150 ctxt
->document
= oldDocInfo
;
5151 ctxt
->nodeList
= oldList
;
5152 ctxt
->node
= oldContextNode
;
5153 ctxt
->mode
= oldMode
;
5154 ctxt
->modeURI
= oldModeURI
;
5160 * @ctxt: a XSLT process context
5161 * @contextNode: the current node in the source tree
5162 * @inst: the xsl:choose instruction
5163 * @comp: compiled information of the instruction
5165 * Processes the xsl:choose instruction on the source node.
5168 xsltChoose(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5169 xmlNodePtr inst
, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
)
5173 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
))
5177 * TODO: Content model checks should be done only at compilation
5180 cur
= inst
->children
;
5182 xsltTransformError(ctxt
, NULL
, inst
,
5183 "xsl:choose: The instruction has no content.\n");
5187 #ifdef XSLT_REFACTORED
5189 * We don't check the content model during transformation.
5192 if ((! IS_XSLT_ELEM(cur
)) || (! IS_XSLT_NAME(cur
, "when"))) {
5193 xsltTransformError(ctxt
, NULL
, inst
,
5194 "xsl:choose: xsl:when expected first\n");
5200 int testRes
= 0, res
= 0;
5202 #ifdef XSLT_REFACTORED
5203 xsltStyleItemWhenPtr wcomp
= NULL
;
5205 xsltStylePreCompPtr wcomp
= NULL
;
5209 * Process xsl:when ---------------------------------------------------
5211 while (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "when")) {
5214 if ((wcomp
== NULL
) || (wcomp
->test
== NULL
) ||
5215 (wcomp
->comp
== NULL
))
5217 xsltTransformError(ctxt
, NULL
, cur
,
5218 "Internal error in xsltChoose(): "
5219 "The XSLT 'when' instruction was not compiled.\n");
5224 #ifdef WITH_DEBUGGER
5225 if (xslDebugStatus
!= XSLT_DEBUG_NONE
) {
5227 * TODO: Isn't comp->templ always NULL for xsl:choose?
5229 xslHandleDebugger(cur
, contextNode
, NULL
, ctxt
);
5232 #ifdef WITH_XSLT_DEBUG_PROCESS
5233 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5234 "xsltChoose: test %s\n", wcomp
->test
));
5238 res
= xsltPreCompEvalToBoolean(ctxt
, contextNode
, wcomp
);
5241 ctxt
->state
= XSLT_STATE_STOPPED
;
5244 testRes
= (res
== 1) ? 1 : 0;
5246 #else /* XSLT_FAST_IF */
5248 res
= xsltPreCompEval(ctxt
, cotextNode
, wcomp
);
5251 if (res
->type
!= XPATH_BOOLEAN
)
5252 res
= xmlXPathConvertBoolean(res
);
5253 if (res
->type
== XPATH_BOOLEAN
)
5254 testRes
= res
->boolval
;
5256 #ifdef WITH_XSLT_DEBUG_PROCESS
5257 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5258 "xsltChoose: test didn't evaluate to a boolean\n"));
5262 xmlXPathFreeObject(res
);
5265 ctxt
->state
= XSLT_STATE_STOPPED
;
5269 #endif /* else of XSLT_FAST_IF */
5271 #ifdef WITH_XSLT_DEBUG_PROCESS
5272 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5273 "xsltChoose: test evaluate to %d\n", testRes
));
5282 * Process xsl:otherwise ----------------------------------------------
5284 if (IS_XSLT_ELEM(cur
) && IS_XSLT_NAME(cur
, "otherwise")) {
5286 #ifdef WITH_DEBUGGER
5287 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5288 xslHandleDebugger(cur
, contextNode
, NULL
, ctxt
);
5291 #ifdef WITH_XSLT_DEBUG_PROCESS
5292 XSLT_TRACE(ctxt
,XSLT_TRACE_CHOOSE
,xsltGenericDebug(xsltGenericDebugContext
,
5293 "evaluating xsl:otherwise\n"));
5301 goto process_sequence
;
5307 * Instantiate the sequence constructor.
5309 xsltApplySequenceConstructor(ctxt
, ctxt
->node
, cur
->children
,
5319 * @ctxt: a XSLT process context
5320 * @contextNode: the current node in the source tree
5321 * @inst: the xsl:if instruction
5322 * @castedComp: compiled information of the instruction
5324 * Processes the xsl:if instruction on the source node.
5327 xsltIf(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5328 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
5332 #ifdef XSLT_REFACTORED
5333 xsltStyleItemIfPtr comp
= (xsltStyleItemIfPtr
) castedComp
;
5335 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
5338 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
))
5340 if ((comp
== NULL
) || (comp
->test
== NULL
) || (comp
->comp
== NULL
)) {
5341 xsltTransformError(ctxt
, NULL
, inst
,
5342 "Internal error in xsltIf(): "
5343 "The XSLT 'if' instruction was not compiled.\n");
5347 #ifdef WITH_XSLT_DEBUG_PROCESS
5348 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5349 "xsltIf: test %s\n", comp
->test
));
5354 xmlDocPtr oldLocalFragmentTop
= ctxt
->localRVT
;
5356 res
= xsltPreCompEvalToBoolean(ctxt
, contextNode
, comp
);
5359 * Cleanup fragments created during evaluation of the
5360 * "select" expression.
5362 if (oldLocalFragmentTop
!= ctxt
->localRVT
)
5363 xsltReleaseLocalRVTs(ctxt
, oldLocalFragmentTop
);
5366 #ifdef WITH_XSLT_DEBUG_PROCESS
5367 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5368 "xsltIf: test evaluate to %d\n", res
));
5372 ctxt
->state
= XSLT_STATE_STOPPED
;
5377 * Instantiate the sequence constructor of xsl:if.
5379 xsltApplySequenceConstructor(ctxt
,
5380 contextNode
, inst
->children
, NULL
);
5383 #else /* XSLT_FAST_IF */
5388 xmlXPathObjectPtr xpobj
= xsltPreCompEval(ctxt
, contextNode
, comp
);
5389 if (xpobj
!= NULL
) {
5390 if (xpobj
->type
!= XPATH_BOOLEAN
)
5391 xpobj
= xmlXPathConvertBoolean(xpobj
);
5392 if (xpobj
->type
== XPATH_BOOLEAN
) {
5393 res
= xpobj
->boolval
;
5395 #ifdef WITH_XSLT_DEBUG_PROCESS
5396 XSLT_TRACE(ctxt
,XSLT_TRACE_IF
,xsltGenericDebug(xsltGenericDebugContext
,
5397 "xsltIf: test evaluate to %d\n", res
));
5400 xsltApplySequenceConstructor(ctxt
,
5401 contextNode
, inst
->children
, NULL
);
5405 #ifdef WITH_XSLT_DEBUG_PROCESS
5406 XSLT_TRACE(ctxt
, XSLT_TRACE_IF
,
5407 xsltGenericDebug(xsltGenericDebugContext
,
5408 "xsltIf: test didn't evaluate to a boolean\n"));
5410 ctxt
->state
= XSLT_STATE_STOPPED
;
5412 xmlXPathFreeObject(xpobj
);
5414 ctxt
->state
= XSLT_STATE_STOPPED
;
5417 #endif /* else of XSLT_FAST_IF */
5425 * @ctxt: an XSLT transformation context
5426 * @contextNode: the "current node" in the source tree
5427 * @inst: the element node of the xsl:for-each instruction
5428 * @castedComp: the compiled information of the instruction
5430 * Process the xslt for-each node on the source node
5433 xsltForEach(xsltTransformContextPtr ctxt
, xmlNodePtr contextNode
,
5434 xmlNodePtr inst
, xsltElemPreCompPtr castedComp
)
5436 #ifdef XSLT_REFACTORED
5437 xsltStyleItemForEachPtr comp
= (xsltStyleItemForEachPtr
) castedComp
;
5439 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
5442 xmlXPathObjectPtr res
= NULL
;
5443 xmlNodePtr cur
, curInst
;
5444 xmlNodeSetPtr list
= NULL
;
5445 xmlNodeSetPtr oldList
;
5446 int oldXPProximityPosition
, oldXPContextSize
;
5447 xmlNodePtr oldContextNode
;
5448 xsltTemplatePtr oldCurTemplRule
;
5450 xsltDocumentPtr oldDocInfo
;
5451 xmlXPathContextPtr xpctxt
;
5453 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
)) {
5454 xsltGenericError(xsltGenericErrorContext
,
5455 "xsltForEach(): Bad arguments.\n");
5460 xsltTransformError(ctxt
, NULL
, inst
,
5461 "Internal error in xsltForEach(): "
5462 "The XSLT 'for-each' instruction was not compiled.\n");
5465 if ((comp
->select
== NULL
) || (comp
->comp
== NULL
)) {
5466 xsltTransformError(ctxt
, NULL
, inst
,
5467 "Internal error in xsltForEach(): "
5468 "The selecting expression of the XSLT 'for-each' "
5469 "instruction was not compiled correctly.\n");
5472 xpctxt
= ctxt
->xpathCtxt
;
5474 #ifdef WITH_XSLT_DEBUG_PROCESS
5475 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5476 "xsltForEach: select %s\n", comp
->select
));
5480 * Save context states.
5482 oldDocInfo
= ctxt
->document
;
5483 oldList
= ctxt
->nodeList
;
5484 oldContextNode
= ctxt
->node
;
5486 * The "current template rule" is cleared for the instantiation of
5489 oldCurTemplRule
= ctxt
->currentTemplateRule
;
5490 ctxt
->currentTemplateRule
= NULL
;
5492 oldXPDoc
= xpctxt
->doc
;
5493 oldXPProximityPosition
= xpctxt
->proximityPosition
;
5494 oldXPContextSize
= xpctxt
->contextSize
;
5497 * Evaluate the 'select' expression.
5499 res
= xsltPreCompEval(ctxt
, contextNode
, comp
);
5502 if (res
->type
== XPATH_NODESET
)
5503 list
= res
->nodesetval
;
5505 xsltTransformError(ctxt
, NULL
, inst
,
5506 "The 'select' expression does not evaluate to a node set.\n");
5508 #ifdef WITH_XSLT_DEBUG_PROCESS
5509 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5510 "xsltForEach: select didn't evaluate to a node list\n"));
5515 xsltTransformError(ctxt
, NULL
, inst
,
5516 "Failed to evaluate the 'select' expression.\n");
5517 ctxt
->state
= XSLT_STATE_STOPPED
;
5521 if ((list
== NULL
) || (list
->nodeNr
<= 0))
5524 #ifdef WITH_XSLT_DEBUG_PROCESS
5525 XSLT_TRACE(ctxt
,XSLT_TRACE_FOR_EACH
,xsltGenericDebug(xsltGenericDebugContext
,
5526 "xsltForEach: select evaluates to %d nodes\n", list
->nodeNr
));
5530 * Set the list; this has to be done already here for xsltDoSortFunction().
5532 ctxt
->nodeList
= list
;
5534 * Handle xsl:sort instructions and skip them for further processing.
5535 * BUG TODO: We are not using namespaced potentially defined on the
5536 * xsl:sort element; XPath expression might fail.
5538 curInst
= inst
->children
;
5539 if (IS_XSLT_ELEM(curInst
) && IS_XSLT_NAME(curInst
, "sort")) {
5541 xmlNodePtr sorts
[XSLT_MAX_SORT
];
5543 sorts
[nbsorts
++] = curInst
;
5545 #ifdef WITH_DEBUGGER
5546 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5547 xslHandleDebugger(curInst
, contextNode
, NULL
, ctxt
);
5550 curInst
= curInst
->next
;
5551 while (IS_XSLT_ELEM(curInst
) && IS_XSLT_NAME(curInst
, "sort")) {
5552 if (nbsorts
>= XSLT_MAX_SORT
) {
5553 xsltTransformError(ctxt
, NULL
, curInst
,
5554 "The number of xsl:sort instructions exceeds the "
5555 "maximum (%d) allowed by this processor.\n",
5559 sorts
[nbsorts
++] = curInst
;
5562 #ifdef WITH_DEBUGGER
5563 if (xslDebugStatus
!= XSLT_DEBUG_NONE
)
5564 xslHandleDebugger(curInst
, contextNode
, NULL
, ctxt
);
5566 curInst
= curInst
->next
;
5568 xsltDoSortFunction(ctxt
, sorts
, nbsorts
);
5570 xpctxt
->contextSize
= list
->nodeNr
;
5572 * Instantiate the sequence constructor for each selected node.
5574 for (i
= 0; i
< list
->nodeNr
; i
++) {
5575 cur
= list
->nodeTab
[i
];
5577 * The selected node becomes the "current node".
5581 * An xsl:for-each can change the current context doc.
5582 * OPTIMIZE TODO: Get rid of the need to set the context doc.
5584 if ((cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->doc
!= NULL
))
5585 xpctxt
->doc
= cur
->doc
;
5587 xpctxt
->proximityPosition
= i
+ 1;
5589 xsltApplySequenceConstructor(ctxt
, cur
, curInst
, NULL
);
5595 xmlXPathFreeObject(res
);
5597 * Restore old states.
5599 ctxt
->document
= oldDocInfo
;
5600 ctxt
->nodeList
= oldList
;
5601 ctxt
->node
= oldContextNode
;
5602 ctxt
->currentTemplateRule
= oldCurTemplRule
;
5604 xpctxt
->doc
= oldXPDoc
;
5605 xpctxt
->contextSize
= oldXPContextSize
;
5606 xpctxt
->proximityPosition
= oldXPProximityPosition
;
5609 /************************************************************************
5611 * Generic interface *
5613 ************************************************************************/
5615 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5616 typedef struct xsltHTMLVersion
{
5617 const char *version
;
5622 static xsltHTMLVersion xsltHTMLVersions
[] = {
5623 { "5", NULL
, "about:legacy-compat" },
5624 { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5625 "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
5626 { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
5627 "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
5628 { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5629 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5630 { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
5631 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5632 { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
5633 "http://www.w3.org/TR/html4/strict.dtd"},
5634 { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5635 "http://www.w3.org/TR/html4/loose.dtd"},
5636 { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5637 "http://www.w3.org/TR/html4/frameset.dtd"},
5638 { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
5639 "http://www.w3.org/TR/html4/loose.dtd"},
5640 { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL
}
5645 * @version: the version string
5646 * @publicID: used to return the public ID
5647 * @systemID: used to return the system ID
5649 * Returns -1 if not found, 0 otherwise and the system and public
5650 * Identifier for this given verion of HTML
5653 xsltGetHTMLIDs(const xmlChar
*version
, const xmlChar
**publicID
,
5654 const xmlChar
**systemID
) {
5656 if (version
== NULL
)
5658 for (i
= 0;i
< (sizeof(xsltHTMLVersions
)/sizeof(xsltHTMLVersions
[1]));
5660 if (!xmlStrcasecmp(version
,
5661 (const xmlChar
*) xsltHTMLVersions
[i
].version
)) {
5662 if (publicID
!= NULL
)
5663 *publicID
= (const xmlChar
*) xsltHTMLVersions
[i
].public;
5664 if (systemID
!= NULL
)
5665 *systemID
= (const xmlChar
*) xsltHTMLVersions
[i
].system
;
5674 * xsltApplyStripSpaces:
5675 * @ctxt: a XSLT process context
5676 * @node: the root of the XML tree
5678 * Strip the unwanted ignorable spaces from the input tree
5681 xsltApplyStripSpaces(xsltTransformContextPtr ctxt
, xmlNodePtr node
) {
5683 #ifdef WITH_XSLT_DEBUG_PROCESS
5689 while (current
!= NULL
) {
5691 * Cleanup children empty nodes if asked for
5693 if ((IS_XSLT_REAL_NODE(current
)) &&
5694 (current
->children
!= NULL
) &&
5695 (xsltFindElemSpaceHandling(ctxt
, current
))) {
5696 xmlNodePtr
delete = NULL
, cur
= current
->children
;
5698 while (cur
!= NULL
) {
5699 if (IS_BLANK_NODE(cur
))
5703 if (delete != NULL
) {
5704 xmlUnlinkNode(delete);
5705 xmlFreeNode(delete);
5707 #ifdef WITH_XSLT_DEBUG_PROCESS
5715 * Skip to next node in document order.
5717 if (node
->type
== XML_ENTITY_REF_NODE
) {
5718 /* process deep in entities */
5719 xsltApplyStripSpaces(ctxt
, node
->children
);
5721 if ((current
->children
!= NULL
) &&
5722 (current
->type
!= XML_ENTITY_REF_NODE
)) {
5723 current
= current
->children
;
5724 } else if (current
->next
!= NULL
) {
5725 current
= current
->next
;
5728 current
= current
->parent
;
5729 if (current
== NULL
)
5731 if (current
== node
)
5733 if (current
->next
!= NULL
) {
5734 current
= current
->next
;
5737 } while (current
!= NULL
);
5742 #ifdef WITH_XSLT_DEBUG_PROCESS
5743 XSLT_TRACE(ctxt
,XSLT_TRACE_STRIP_SPACES
,xsltGenericDebug(xsltGenericDebugContext
,
5744 "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb
));
5750 xsltCountKeys(xsltTransformContextPtr ctxt
)
5752 xsltStylesheetPtr style
;
5759 * Do we have those nastly templates with a key() in the match pattern?
5761 ctxt
->hasTemplKeyPatterns
= 0;
5762 style
= ctxt
->style
;
5763 while (style
!= NULL
) {
5764 if (style
->keyMatch
!= NULL
) {
5765 ctxt
->hasTemplKeyPatterns
= 1;
5768 style
= xsltNextImport(style
);
5771 * Count number of key declarations.
5774 style
= ctxt
->style
;
5775 while (style
!= NULL
) {
5781 style
= xsltNextImport(style
);
5783 return(ctxt
->nbKeys
);
5787 * xsltApplyStylesheetInternal:
5788 * @style: a parsed XSLT stylesheet
5789 * @doc: a parsed XML document
5790 * @params: a NULL terminated array of parameters names/values tuples
5791 * @output: the targetted output
5792 * @profile: profile FILE * output or NULL
5793 * @user: user provided parameter
5795 * Apply the stylesheet to the document
5796 * NOTE: This may lead to a non-wellformed output XML wise !
5798 * Returns the result document or NULL in case of error
5801 xsltApplyStylesheetInternal(xsltStylesheetPtr style
, xmlDocPtr doc
,
5802 const char **params
, const char *output
,
5803 FILE * profile
, xsltTransformContextPtr userCtxt
)
5805 xmlDocPtr res
= NULL
;
5806 xsltTransformContextPtr ctxt
= NULL
;
5807 xmlNodePtr root
, node
;
5808 const xmlChar
*method
;
5809 const xmlChar
*doctypePublic
;
5810 const xmlChar
*doctypeSystem
;
5811 const xmlChar
*version
;
5812 const xmlChar
*encoding
;
5813 xsltStackElemPtr variables
;
5814 xsltStackElemPtr vptr
;
5818 if ((style
== NULL
) || (doc
== NULL
))
5821 if (style
->internalized
== 0) {
5822 #ifdef WITH_XSLT_DEBUG
5823 xsltGenericDebug(xsltGenericDebugContext
,
5824 "Stylesheet was not fully internalized !\n");
5827 if (doc
->intSubset
!= NULL
) {
5829 * Avoid hitting the DTD when scanning nodes
5830 * but keep it linked as doc->intSubset
5832 xmlNodePtr cur
= (xmlNodePtr
) doc
->intSubset
;
5833 if (cur
->next
!= NULL
)
5834 cur
->next
->prev
= cur
->prev
;
5835 if (cur
->prev
!= NULL
)
5836 cur
->prev
->next
= cur
->next
;
5837 if (doc
->children
== cur
)
5838 doc
->children
= cur
->next
;
5839 if (doc
->last
== cur
)
5840 doc
->last
= cur
->prev
;
5841 cur
->prev
= cur
->next
= NULL
;
5845 * Check for XPath document order availability
5847 root
= xmlDocGetRootElement(doc
);
5849 if (((ptrdiff_t) root
->content
>= 0) &&
5850 (xslDebugStatus
== XSLT_DEBUG_NONE
))
5851 xmlXPathOrderDocElems(doc
);
5854 if (userCtxt
!= NULL
)
5857 ctxt
= xsltNewTransformContext(style
, doc
);
5862 ctxt
->initialContextDoc
= doc
;
5863 ctxt
->initialContextNode
= (xmlNodePtr
) doc
;
5865 if (profile
!= NULL
)
5869 ctxt
->outputFile
= output
;
5871 ctxt
->outputFile
= NULL
;
5874 * internalize the modes if needed
5876 if (ctxt
->dict
!= NULL
) {
5877 if (ctxt
->mode
!= NULL
)
5878 ctxt
->mode
= xmlDictLookup(ctxt
->dict
, ctxt
->mode
, -1);
5879 if (ctxt
->modeURI
!= NULL
)
5880 ctxt
->modeURI
= xmlDictLookup(ctxt
->dict
, ctxt
->modeURI
, -1);
5883 XSLT_GET_IMPORT_PTR(method
, style
, method
)
5884 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
5885 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
5886 XSLT_GET_IMPORT_PTR(version
, style
, version
)
5887 XSLT_GET_IMPORT_PTR(encoding
, style
, encoding
)
5889 if ((method
!= NULL
) &&
5890 (!xmlStrEqual(method
, (const xmlChar
*) "xml")))
5892 if (xmlStrEqual(method
, (const xmlChar
*) "html")) {
5893 ctxt
->type
= XSLT_OUTPUT_HTML
;
5894 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
5895 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5897 if (version
== NULL
) {
5900 res
= htmlNewDoc(NULL
, NULL
);
5902 * Make sure no DTD node is generated in this case
5905 dtd
= xmlGetIntSubset(res
);
5907 xmlUnlinkNode((xmlNodePtr
) dtd
);
5910 res
->intSubset
= NULL
;
5911 res
->extSubset
= NULL
;
5915 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5916 xsltGetHTMLIDs(version
, &doctypePublic
, &doctypeSystem
);
5918 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5923 res
->dict
= ctxt
->dict
;
5924 xmlDictReference(res
->dict
);
5926 #ifdef WITH_XSLT_DEBUG
5927 xsltGenericDebug(xsltGenericDebugContext
,
5928 "reusing transformation dict for output\n");
5930 } else if (xmlStrEqual(method
, (const xmlChar
*) "xhtml")) {
5931 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
5932 "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n");
5933 ctxt
->type
= XSLT_OUTPUT_HTML
;
5934 res
= htmlNewDoc(doctypeSystem
, doctypePublic
);
5937 res
->dict
= ctxt
->dict
;
5938 xmlDictReference(res
->dict
);
5940 #ifdef WITH_XSLT_DEBUG
5941 xsltGenericDebug(xsltGenericDebugContext
,
5942 "reusing transformation dict for output\n");
5944 } else if (xmlStrEqual(method
, (const xmlChar
*) "text")) {
5945 ctxt
->type
= XSLT_OUTPUT_TEXT
;
5946 res
= xmlNewDoc(style
->version
);
5949 res
->dict
= ctxt
->dict
;
5950 xmlDictReference(res
->dict
);
5952 #ifdef WITH_XSLT_DEBUG
5953 xsltGenericDebug(xsltGenericDebugContext
,
5954 "reusing transformation dict for output\n");
5957 xsltTransformError(ctxt
, NULL
, (xmlNodePtr
) doc
,
5958 "xsltApplyStylesheetInternal: unsupported method (%s)\n",
5963 ctxt
->type
= XSLT_OUTPUT_XML
;
5964 res
= xmlNewDoc(style
->version
);
5967 res
->dict
= ctxt
->dict
;
5968 xmlDictReference(ctxt
->dict
);
5969 #ifdef WITH_XSLT_DEBUG
5970 xsltGenericDebug(xsltGenericDebugContext
,
5971 "reusing transformation dict for output\n");
5974 res
->charset
= XML_CHAR_ENCODING_UTF8
;
5975 if (encoding
!= NULL
)
5976 res
->encoding
= xmlStrdup(encoding
);
5977 variables
= style
->variables
;
5980 * Start the evaluation, evaluate the params, the stylesheets globals
5981 * and start by processing the top node.
5983 if (xsltNeedElemSpaceHandling(ctxt
))
5984 xsltApplyStripSpaces(ctxt
, xmlDocGetRootElement(doc
));
5986 * Evaluate global params and user-provided params.
5988 ctxt
->node
= (xmlNodePtr
) doc
;
5989 if (ctxt
->globalVars
== NULL
)
5990 ctxt
->globalVars
= xmlHashCreate(20);
5991 if (params
!= NULL
) {
5992 xsltEvalUserParams(ctxt
, params
);
5995 /* need to be called before evaluating global variables */
5996 xsltCountKeys(ctxt
);
5998 xsltEvalGlobalVariables(ctxt
);
6000 /* Clean up any unused RVTs. */
6001 xsltReleaseLocalRVTs(ctxt
, NULL
);
6003 ctxt
->node
= (xmlNodePtr
) doc
;
6005 ctxt
->insert
= (xmlNodePtr
) res
;
6006 ctxt
->varsBase
= ctxt
->varsNr
- 1;
6008 ctxt
->xpathCtxt
->contextSize
= 1;
6009 ctxt
->xpathCtxt
->proximityPosition
= 1;
6010 ctxt
->xpathCtxt
->node
= NULL
; /* TODO: Set the context node here? */
6012 * Start processing the source tree -----------------------------------
6014 xsltProcessOneNode(ctxt
, ctxt
->node
, NULL
);
6016 * Remove all remaining vars from the stack.
6018 xsltLocalVariablePop(ctxt
, 0, -2);
6019 xsltShutdownCtxtExts(ctxt
);
6021 xsltCleanupTemplates(style
); /* TODO: <- style should be read only */
6024 * Now cleanup our variables so stylesheet can be re-used
6026 * TODO: this is not needed anymore global variables are copied
6027 * and not evaluated directly anymore, keep this as a check
6029 if (style
->variables
!= variables
) {
6030 vptr
= style
->variables
;
6031 while (vptr
->next
!= variables
)
6034 xsltFreeStackElemList(style
->variables
);
6035 style
->variables
= variables
;
6037 vptr
= style
->variables
;
6038 while (vptr
!= NULL
) {
6039 if (vptr
->computed
) {
6040 if (vptr
->value
!= NULL
) {
6041 xmlXPathFreeObject(vptr
->value
);
6050 * code disabled by wmb; awaiting kb's review
6051 * problem is that global variable(s) may contain xpath objects
6052 * from doc associated with RVT, so can't be freed at this point.
6053 * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
6054 * I assume this shouldn't be required at this point.
6057 * Free all remaining tree fragments.
6062 * Do some post processing work depending on the generated output
6064 root
= xmlDocGetRootElement(res
);
6066 const xmlChar
*doctype
= NULL
;
6068 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
))
6069 doctype
= xmlDictQLookup(ctxt
->dict
, root
->ns
->prefix
, root
->name
);
6070 if (doctype
== NULL
)
6071 doctype
= root
->name
;
6074 * Apply the default selection of the method
6076 if ((method
== NULL
) &&
6077 (root
->ns
== NULL
) &&
6078 (!xmlStrcasecmp(root
->name
, (const xmlChar
*) "html"))) {
6081 tmp
= res
->children
;
6082 while ((tmp
!= NULL
) && (tmp
!= root
)) {
6083 if (tmp
->type
== XML_ELEMENT_NODE
)
6085 if ((tmp
->type
== XML_TEXT_NODE
) && (!xmlIsBlankNode(tmp
)))
6090 ctxt
->type
= XSLT_OUTPUT_HTML
;
6092 * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
6093 * transformation on the doc, but functions like
6095 res
->type
= XML_HTML_DOCUMENT_NODE
;
6096 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
6097 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
6100 #ifdef XSLT_GENERATE_HTML_DOCTYPE
6101 } else if (version
!= NULL
) {
6102 xsltGetHTMLIDs(version
, &doctypePublic
,
6104 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
)))
6106 xmlCreateIntSubset(res
, doctype
,
6114 if (ctxt
->type
== XSLT_OUTPUT_XML
) {
6115 XSLT_GET_IMPORT_PTR(doctypePublic
, style
, doctypePublic
)
6116 XSLT_GET_IMPORT_PTR(doctypeSystem
, style
, doctypeSystem
)
6117 if (((doctypePublic
!= NULL
) || (doctypeSystem
!= NULL
))) {
6119 /* Need a small "hack" here to assure DTD comes before
6120 possible comment nodes */
6121 node
= res
->children
;
6123 res
->children
= NULL
;
6125 res
->intSubset
= xmlCreateIntSubset(res
, doctype
,
6128 if (res
->children
!= NULL
) {
6129 res
->children
->next
= node
;
6130 node
->prev
= res
->children
;
6133 res
->children
= node
;
6139 xmlXPathFreeNodeSet(ctxt
->nodeList
);
6140 if (profile
!= NULL
) {
6141 xsltSaveProfiling(ctxt
, profile
);
6147 if ((ctxt
!= NULL
) && (ctxt
->state
!= XSLT_STATE_OK
)) {
6151 if ((res
!= NULL
) && (ctxt
!= NULL
) && (output
!= NULL
)) {
6154 ret
= xsltCheckWrite(ctxt
->sec
, ctxt
, (const xmlChar
*) output
);
6156 xsltTransformError(ctxt
, NULL
, NULL
,
6157 "xsltApplyStylesheet: forbidden to save to %s\n",
6159 } else if (ret
< 0) {
6160 xsltTransformError(ctxt
, NULL
, NULL
,
6161 "xsltApplyStylesheet: saving to %s may not be possible\n",
6166 #ifdef XSLT_DEBUG_PROFILE_CACHE
6167 printf("# Cache:\n");
6168 printf("# Reused tree fragments: %d\n", ctxt
->cache
->dbgReusedRVTs
);
6169 printf("# Reused variables : %d\n", ctxt
->cache
->dbgReusedVars
);
6172 if ((ctxt
!= NULL
) && (userCtxt
== NULL
))
6173 xsltFreeTransformContext(ctxt
);
6181 #ifdef XSLT_DEBUG_PROFILE_CACHE
6182 printf("# Cache:\n");
6183 printf("# Reused tree fragments: %d\n", ctxt
->cache
->dbgReusedRVTs
);
6184 printf("# Reused variables : %d\n", ctxt
->cache
->dbgReusedVars
);
6187 if ((ctxt
!= NULL
) && (userCtxt
== NULL
))
6188 xsltFreeTransformContext(ctxt
);
6193 * xsltApplyStylesheet:
6194 * @style: a parsed XSLT stylesheet
6195 * @doc: a parsed XML document
6196 * @params: a NULL terminated arry of parameters names/values tuples
6198 * Apply the stylesheet to the document
6199 * NOTE: This may lead to a non-wellformed output XML wise !
6201 * Returns the result document or NULL in case of error
6204 xsltApplyStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6205 const char **params
)
6207 return (xsltApplyStylesheetInternal(style
, doc
, params
, NULL
, NULL
, NULL
));
6211 * xsltProfileStylesheet:
6212 * @style: a parsed XSLT stylesheet
6213 * @doc: a parsed XML document
6214 * @params: a NULL terminated arry of parameters names/values tuples
6215 * @output: a FILE * for the profiling output
6217 * Apply the stylesheet to the document and dump the profiling to
6220 * Returns the result document or NULL in case of error
6223 xsltProfileStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6224 const char **params
, FILE * output
)
6228 res
= xsltApplyStylesheetInternal(style
, doc
, params
, NULL
, output
, NULL
);
6233 * xsltApplyStylesheetUser:
6234 * @style: a parsed XSLT stylesheet
6235 * @doc: a parsed XML document
6236 * @params: a NULL terminated array of parameters names/values tuples
6237 * @output: the targetted output
6238 * @profile: profile FILE * output or NULL
6239 * @userCtxt: user provided transform context
6241 * Apply the stylesheet to the document and allow the user to provide
6242 * its own transformation context.
6244 * Returns the result document or NULL in case of error
6247 xsltApplyStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
,
6248 const char **params
, const char *output
,
6249 FILE * profile
, xsltTransformContextPtr userCtxt
)
6253 res
= xsltApplyStylesheetInternal(style
, doc
, params
, output
,
6259 * xsltRunStylesheetUser:
6260 * @style: a parsed XSLT stylesheet
6261 * @doc: a parsed XML document
6262 * @params: a NULL terminated array of parameters names/values tuples
6263 * @output: the URL/filename ot the generated resource if available
6264 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6265 * @IObuf: an output buffer for progressive output (not implemented yet)
6266 * @profile: profile FILE * output or NULL
6267 * @userCtxt: user provided transform context
6269 * Apply the stylesheet to the document and generate the output according
6270 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6272 * NOTE: This may lead to a non-wellformed output XML wise !
6273 * NOTE: This may also result in multiple files being generated
6274 * NOTE: using IObuf, the result encoding used will be the one used for
6275 * creating the output buffer, use the following macro to read it
6276 * from the stylesheet
6277 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6278 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6279 * since the interface uses only UTF8
6281 * Returns the number of by written to the main resource or -1 in case of
6285 xsltRunStylesheetUser(xsltStylesheetPtr style
, xmlDocPtr doc
,
6286 const char **params
, const char *output
,
6287 xmlSAXHandlerPtr SAX
, xmlOutputBufferPtr IObuf
,
6288 FILE * profile
, xsltTransformContextPtr userCtxt
)
6293 if ((output
== NULL
) && (SAX
== NULL
) && (IObuf
== NULL
))
6295 if ((SAX
!= NULL
) && (IObuf
!= NULL
))
6298 /* unsupported yet */
6300 XSLT_TODO
/* xsltRunStylesheet xmlSAXHandlerPtr SAX */
6304 tmp
= xsltApplyStylesheetInternal(style
, doc
, params
, output
, profile
,
6307 xsltTransformError(NULL
, NULL
, (xmlNodePtr
) doc
,
6308 "xsltRunStylesheet : run failed\n");
6311 if (IObuf
!= NULL
) {
6312 /* TODO: incomplete, IObuf output not progressive */
6313 ret
= xsltSaveResultTo(IObuf
, tmp
, style
);
6315 ret
= xsltSaveResultToFilename(output
, tmp
, style
, 0);
6322 * xsltRunStylesheet:
6323 * @style: a parsed XSLT stylesheet
6324 * @doc: a parsed XML document
6325 * @params: a NULL terminated array of parameters names/values tuples
6326 * @output: the URL/filename ot the generated resource if available
6327 * @SAX: a SAX handler for progressive callback output (not implemented yet)
6328 * @IObuf: an output buffer for progressive output (not implemented yet)
6330 * Apply the stylesheet to the document and generate the output according
6331 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6333 * NOTE: This may lead to a non-wellformed output XML wise !
6334 * NOTE: This may also result in multiple files being generated
6335 * NOTE: using IObuf, the result encoding used will be the one used for
6336 * creating the output buffer, use the following macro to read it
6337 * from the stylesheet
6338 * XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6339 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6340 * since the interface uses only UTF8
6342 * Returns the number of bytes written to the main resource or -1 in case of
6346 xsltRunStylesheet(xsltStylesheetPtr style
, xmlDocPtr doc
,
6347 const char **params
, const char *output
,
6348 xmlSAXHandlerPtr SAX
, xmlOutputBufferPtr IObuf
)
6350 return(xsltRunStylesheetUser(style
, doc
, params
, output
, SAX
, IObuf
,
6355 xsltMessageWrapper(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
6356 xmlNodePtr inst
, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED
) {
6357 xsltMessage(ctxt
, node
, inst
);
6361 * xsltRegisterAllElement:
6362 * @ctxt: the XPath context
6364 * Registers all default XSLT elements in this context
6367 xsltRegisterAllElement(xsltTransformContextPtr ctxt
)
6369 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "apply-templates",
6371 xsltApplyTemplates
);
6372 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "apply-imports",
6375 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "call-template",
6378 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "element",
6381 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "attribute",
6384 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "text",
6387 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "processing-instruction",
6389 xsltProcessingInstruction
);
6390 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "comment",
6393 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "copy",
6396 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "value-of",
6399 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "number",
6402 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "for-each",
6405 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "if",
6408 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "choose",
6411 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "sort",
6414 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "copy-of",
6417 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "message",
6419 xsltMessageWrapper
);
6422 * Those don't have callable entry points but are registered anyway
6424 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "variable",
6427 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "param",
6430 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "with-param",
6433 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "decimal-format",
6436 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "when",
6439 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "otherwise",
6442 xsltRegisterExtElement(ctxt
, (const xmlChar
*) "fallback",