1/*
2 * transform.c: Implementation of the XSL Transformation 1.0 engine
3 *              transform part, i.e. applying a Stylesheet to a document
4 *
5 * References:
6 *   http://www.w3.org/TR/1999/REC-xslt-19991116
7 *
8 *   Michael Kay "XSLT Programmer's Reference" pp 637-643
9 *   Writing Multiple Output Files
10 *
11 *   XSLT-1.1 Working Draft
12 *   http://www.w3.org/TR/xslt11#multiple-output
13 *
14 * See Copyright for the status of this software.
15 *
16 * daniel@veillard.com
17 */
18
19#define IN_LIBXSLT
20#include "libxslt.h"
21
22#include <string.h>
23
24#include <libxml/xmlmemory.h>
25#include <libxml/parser.h>
26#include <libxml/tree.h>
27#include <libxml/valid.h>
28#include <libxml/hash.h>
29#include <libxml/encoding.h>
30#include <libxml/xmlerror.h>
31#include <libxml/xpath.h>
32#include <libxml/parserInternals.h>
33#include <libxml/xpathInternals.h>
34#include <libxml/HTMLtree.h>
35#include <libxml/debugXML.h>
36#include <libxml/uri.h>
37#include "xslt.h"
38#include "xsltInternals.h"
39#include "xsltutils.h"
40#include "pattern.h"
41#include "transform.h"
42#include "variables.h"
43#include "numbersInternals.h"
44#include "namespaces.h"
45#include "attributes.h"
46#include "templates.h"
47#include "imports.h"
48#include "keys.h"
49#include "documents.h"
50#include "extensions.h"
51#include "extra.h"
52#include "preproc.h"
53#include "security.h"
54
55#ifdef WITH_XSLT_DEBUG
56#define WITH_XSLT_DEBUG_EXTRA
57#define WITH_XSLT_DEBUG_PROCESS
58#endif
59
60#define XSLT_GENERATE_HTML_DOCTYPE
61#ifdef XSLT_GENERATE_HTML_DOCTYPE
62static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
63			  const xmlChar **systemID);
64#endif
65
66int xsltMaxDepth = 3000;
67
68/*
69 * Useful macros
70 */
71
72#ifndef FALSE
73# define FALSE (0 == 1)
74# define TRUE (!FALSE)
75#endif
76
77#define IS_BLANK_NODE(n)						\
78    (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
79
80
81/*
82* Forward declarations
83*/
84
85static xmlNsPtr
86xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur);
87
88static xmlNodePtr
89xsltCopyTreeInternal(xsltTransformContextPtr ctxt,
90		     xmlNodePtr invocNode,
91		     xmlNodePtr node,
92		     xmlNodePtr insert, int isLRE, int topElemVisited);
93
94static void
95xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
96			     xmlNodePtr contextNode, xmlNodePtr list,
97			     xsltTemplatePtr templ);
98
99static void
100xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
101		      xmlNodePtr contextNode,
102		      xmlNodePtr list,
103		      xsltTemplatePtr templ,
104		      xsltStackElemPtr withParams);
105
106/**
107 * templPush:
108 * @ctxt: the transformation context
109 * @value:  the template to push on the stack
110 *
111 * Push a template on the stack
112 *
113 * Returns the new index in the stack or 0 in case of error
114 */
115static int
116templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value)
117{
118    if (ctxt->templMax == 0) {
119        ctxt->templMax = 4;
120        ctxt->templTab =
121            (xsltTemplatePtr *) xmlMalloc(ctxt->templMax *
122                                          sizeof(ctxt->templTab[0]));
123        if (ctxt->templTab == NULL) {
124            xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
125            return (0);
126        }
127    }
128    if (ctxt->templNr >= ctxt->templMax) {
129        ctxt->templMax *= 2;
130        ctxt->templTab =
131            (xsltTemplatePtr *) xmlRealloc(ctxt->templTab,
132                                           ctxt->templMax *
133                                           sizeof(ctxt->templTab[0]));
134        if (ctxt->templTab == NULL) {
135            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
136            return (0);
137        }
138    }
139    ctxt->templTab[ctxt->templNr] = value;
140    ctxt->templ = value;
141    return (ctxt->templNr++);
142}
143/**
144 * templPop:
145 * @ctxt: the transformation context
146 *
147 * Pop a template value from the stack
148 *
149 * Returns the stored template value
150 */
151static xsltTemplatePtr
152templPop(xsltTransformContextPtr ctxt)
153{
154    xsltTemplatePtr ret;
155
156    if (ctxt->templNr <= 0)
157        return (0);
158    ctxt->templNr--;
159    if (ctxt->templNr > 0)
160        ctxt->templ = ctxt->templTab[ctxt->templNr - 1];
161    else
162        ctxt->templ = (xsltTemplatePtr) 0;
163    ret = ctxt->templTab[ctxt->templNr];
164    ctxt->templTab[ctxt->templNr] = 0;
165    return (ret);
166}
167
168/**
169 * xsltLocalVariablePop:
170 * @ctxt: the transformation context
171 * @limitNr: number of variables which should remain
172 * @level: the depth in the xsl:template's tree
173 *
174 * Pops all variable values at the given @depth from the stack.
175 *
176 * Returns the stored variable value
177 * **NOTE:**
178 * This is an internal routine and should not be called by users!
179 */
180void
181xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level)
182{
183    xsltStackElemPtr variable;
184
185    if (ctxt->varsNr <= 0)
186        return;
187
188    do {
189	if (ctxt->varsNr <= limitNr)
190	    break;
191	variable = ctxt->varsTab[ctxt->varsNr - 1];
192	if (variable->level <= level)
193	    break;
194	if (variable->level >= 0)
195	    xsltFreeStackElemList(variable);
196	ctxt->varsNr--;
197    } while (ctxt->varsNr != 0);
198    if (ctxt->varsNr > 0)
199        ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
200    else
201        ctxt->vars = NULL;
202}
203
204/**
205 * xsltTemplateParamsCleanup:
206 *
207 * Removes xsl:param and xsl:with-param items from the
208 * variable-stack. Only xsl:with-param items are not freed.
209 */
210static void
211xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt)
212{
213    xsltStackElemPtr param;
214
215    for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) {
216	param = ctxt->varsTab[ctxt->varsNr -1];
217	/*
218	* Free xsl:param items.
219	* xsl:with-param items will have a level of -1 or -2.
220	*/
221	if (param->level >= 0) {
222	    xsltFreeStackElemList(param);
223	}
224    }
225    if (ctxt->varsNr > 0)
226        ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
227    else
228        ctxt->vars = NULL;
229}
230
231/**
232 * profPush:
233 * @ctxt: the transformation context
234 * @value:  the profiling value to push on the stack
235 *
236 * Push a profiling value on the stack
237 *
238 * Returns the new index in the stack or 0 in case of error
239 */
240static int
241profPush(xsltTransformContextPtr ctxt, long value)
242{
243    if (ctxt->profMax == 0) {
244        ctxt->profMax = 4;
245        ctxt->profTab =
246            (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0]));
247        if (ctxt->profTab == NULL) {
248            xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
249            return (0);
250        }
251    }
252    if (ctxt->profNr >= ctxt->profMax) {
253        ctxt->profMax *= 2;
254        ctxt->profTab =
255            (long *) xmlRealloc(ctxt->profTab,
256                                ctxt->profMax * sizeof(ctxt->profTab[0]));
257        if (ctxt->profTab == NULL) {
258            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
259            return (0);
260        }
261    }
262    ctxt->profTab[ctxt->profNr] = value;
263    ctxt->prof = value;
264    return (ctxt->profNr++);
265}
266/**
267 * profPop:
268 * @ctxt: the transformation context
269 *
270 * Pop a profiling value from the stack
271 *
272 * Returns the stored profiling value
273 */
274static long
275profPop(xsltTransformContextPtr ctxt)
276{
277    long ret;
278
279    if (ctxt->profNr <= 0)
280        return (0);
281    ctxt->profNr--;
282    if (ctxt->profNr > 0)
283        ctxt->prof = ctxt->profTab[ctxt->profNr - 1];
284    else
285        ctxt->prof = (long) 0;
286    ret = ctxt->profTab[ctxt->profNr];
287    ctxt->profTab[ctxt->profNr] = 0;
288    return (ret);
289}
290
291/************************************************************************
292 *									*
293 *			XInclude default settings			*
294 *									*
295 ************************************************************************/
296
297static int xsltDoXIncludeDefault = 0;
298
299/**
300 * xsltSetXIncludeDefault:
301 * @xinclude: whether to do XInclude processing
302 *
303 * Set whether XInclude should be processed on document being loaded by default
304 */
305void
306xsltSetXIncludeDefault(int xinclude) {
307    xsltDoXIncludeDefault = (xinclude != 0);
308}
309
310/**
311 * xsltGetXIncludeDefault:
312 *
313 * Provides the default state for XInclude processing
314 *
315 * Returns 0 if there is no processing 1 otherwise
316 */
317int
318xsltGetXIncludeDefault(void) {
319    return(xsltDoXIncludeDefault);
320}
321
322unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL;
323
324/**
325 * xsltDebugSetDefaultTrace:
326 * @val: tracing level mask
327 *
328 * Set the default debug tracing level mask
329 */
330void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) {
331	xsltDefaultTrace = val;
332}
333
334/**
335 * xsltDebugGetDefaultTrace:
336 *
337 * Get the current default debug tracing level mask
338 *
339 * Returns the current default debug tracing level mask
340 */
341xsltDebugTraceCodes xsltDebugGetDefaultTrace() {
342	return xsltDefaultTrace;
343}
344
345/************************************************************************
346 *									*
347 *			Handling of Transformation Contexts		*
348 *									*
349 ************************************************************************/
350
351static xsltTransformCachePtr
352xsltTransformCacheCreate(void)
353{
354    xsltTransformCachePtr ret;
355
356    ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache));
357    if (ret == NULL) {
358	xsltTransformError(NULL, NULL, NULL,
359	    "xsltTransformCacheCreate : malloc failed\n");
360	return(NULL);
361    }
362    memset(ret, 0, sizeof(xsltTransformCache));
363    return(ret);
364}
365
366static void
367xsltTransformCacheFree(xsltTransformCachePtr cache)
368{
369    if (cache == NULL)
370	return;
371    /*
372    * Free tree fragments.
373    */
374    if (cache->RVT) {
375	xmlDocPtr tmp, cur = cache->RVT;
376	while (cur) {
377	    tmp = cur;
378	    cur = (xmlDocPtr) cur->next;
379	    if (tmp->_private != NULL) {
380		/*
381		* Tree the document info.
382		*/
383		xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private);
384		xmlFree(tmp->_private);
385	    }
386	    xmlFreeDoc(tmp);
387	}
388    }
389    /*
390    * Free vars/params.
391    */
392    if (cache->stackItems) {
393	xsltStackElemPtr tmp, cur = cache->stackItems;
394	while (cur) {
395	    tmp = cur;
396	    cur = cur->next;
397	    /*
398	    * REVISIT TODO: Should be call a destruction-function
399	    * instead?
400	    */
401	    xmlFree(tmp);
402	}
403    }
404    xmlFree(cache);
405}
406
407/**
408 * xsltNewTransformContext:
409 * @style:  a parsed XSLT stylesheet
410 * @doc:  the input document
411 *
412 * Create a new XSLT TransformContext
413 *
414 * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
415 */
416xsltTransformContextPtr
417xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
418    xsltTransformContextPtr cur;
419    xsltDocumentPtr docu;
420    int i;
421
422    xsltInitGlobals();
423
424    cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext));
425    if (cur == NULL) {
426	xsltTransformError(NULL, NULL, (xmlNodePtr)doc,
427		"xsltNewTransformContext : malloc failed\n");
428	return(NULL);
429    }
430    memset(cur, 0, sizeof(xsltTransformContext));
431
432    cur->cache = xsltTransformCacheCreate();
433    if (cur->cache == NULL)
434	goto internal_err;
435    /*
436     * setup of the dictionary must be done early as some of the
437     * processing later like key handling may need it.
438     */
439    cur->dict = xmlDictCreateSub(style->dict);
440    cur->internalized = ((style->internalized) && (cur->dict != NULL));
441#ifdef WITH_XSLT_DEBUG
442    xsltGenericDebug(xsltGenericDebugContext,
443	     "Creating sub-dictionary from stylesheet for transformation\n");
444#endif
445
446    /*
447     * initialize the template stack
448     */
449    cur->templTab = (xsltTemplatePtr *)
450	        xmlMalloc(10 * sizeof(xsltTemplatePtr));
451    if (cur->templTab == NULL) {
452	xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
453		"xsltNewTransformContext: out of memory\n");
454	goto internal_err;
455    }
456    cur->templNr = 0;
457    cur->templMax = 5;
458    cur->templ = NULL;
459
460    /*
461     * initialize the variables stack
462     */
463    cur->varsTab = (xsltStackElemPtr *)
464	        xmlMalloc(10 * sizeof(xsltStackElemPtr));
465    if (cur->varsTab == NULL) {
466        xmlGenericError(xmlGenericErrorContext,
467		"xsltNewTransformContext: out of memory\n");
468	goto internal_err;
469    }
470    cur->varsNr = 0;
471    cur->varsMax = 10;
472    cur->vars = NULL;
473    cur->varsBase = 0;
474
475    /*
476     * the profiling stack is not initialized by default
477     */
478    cur->profTab = NULL;
479    cur->profNr = 0;
480    cur->profMax = 0;
481    cur->prof = 0;
482
483    cur->style = style;
484    xmlXPathInit();
485    cur->xpathCtxt = xmlXPathNewContext(doc);
486    if (cur->xpathCtxt == NULL) {
487	xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
488		"xsltNewTransformContext : xmlXPathNewContext failed\n");
489	goto internal_err;
490    }
491    /*
492    * Create an XPath cache.
493    */
494    if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1)
495	goto internal_err;
496    /*
497     * Initialize the extras array
498     */
499    if (style->extrasNr != 0) {
500	cur->extrasMax = style->extrasNr + 20;
501	cur->extras = (xsltRuntimeExtraPtr)
502	    xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra));
503	if (cur->extras == NULL) {
504	    xmlGenericError(xmlGenericErrorContext,
505		    "xsltNewTransformContext: out of memory\n");
506	    goto internal_err;
507	}
508	cur->extrasNr = style->extrasNr;
509	for (i = 0;i < cur->extrasMax;i++) {
510	    cur->extras[i].info = NULL;
511	    cur->extras[i].deallocate = NULL;
512	    cur->extras[i].val.ptr = NULL;
513	}
514    } else {
515	cur->extras = NULL;
516	cur->extrasNr = 0;
517	cur->extrasMax = 0;
518    }
519
520    XSLT_REGISTER_VARIABLE_LOOKUP(cur);
521    XSLT_REGISTER_FUNCTION_LOOKUP(cur);
522    cur->xpathCtxt->nsHash = style->nsHash;
523    /*
524     * Initialize the registered external modules
525     */
526    xsltInitCtxtExts(cur);
527    /*
528     * Setup document element ordering for later efficiencies
529     * (bug 133289)
530     */
531    if (xslDebugStatus == XSLT_DEBUG_NONE)
532        xmlXPathOrderDocElems(doc);
533    /*
534     * Must set parserOptions before calling xsltNewDocument
535     * (bug 164530)
536     */
537    cur->parserOptions = XSLT_PARSE_OPTIONS;
538    docu = xsltNewDocument(cur, doc);
539    if (docu == NULL) {
540	xsltTransformError(cur, NULL, (xmlNodePtr)doc,
541		"xsltNewTransformContext : xsltNewDocument failed\n");
542	goto internal_err;
543    }
544    docu->main = 1;
545    cur->document = docu;
546    cur->inst = NULL;
547    cur->outputFile = NULL;
548    cur->sec = xsltGetDefaultSecurityPrefs();
549    cur->debugStatus = xslDebugStatus;
550    cur->traceCode = (unsigned long*) &xsltDefaultTrace;
551    cur->xinclude = xsltGetXIncludeDefault();
552    cur->keyInitLevel = 0;
553
554    return(cur);
555
556internal_err:
557    if (cur != NULL)
558	xsltFreeTransformContext(cur);
559    return(NULL);
560}
561
562/**
563 * xsltFreeTransformContext:
564 * @ctxt:  an XSLT parser context
565 *
566 * Free up the memory allocated by @ctxt
567 */
568void
569xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
570    if (ctxt == NULL)
571	return;
572
573    /*
574     * Shutdown the extension modules associated to the stylesheet
575     * used if needed.
576     */
577    xsltShutdownCtxtExts(ctxt);
578
579    if (ctxt->xpathCtxt != NULL) {
580	ctxt->xpathCtxt->nsHash = NULL;
581	xmlXPathFreeContext(ctxt->xpathCtxt);
582    }
583    if (ctxt->templTab != NULL)
584	xmlFree(ctxt->templTab);
585    if (ctxt->varsTab != NULL)
586	xmlFree(ctxt->varsTab);
587    if (ctxt->profTab != NULL)
588	xmlFree(ctxt->profTab);
589    if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) {
590	int i;
591
592	for (i = 0;i < ctxt->extrasNr;i++) {
593	    if ((ctxt->extras[i].deallocate != NULL) &&
594		(ctxt->extras[i].info != NULL))
595		ctxt->extras[i].deallocate(ctxt->extras[i].info);
596	}
597	xmlFree(ctxt->extras);
598    }
599    xsltFreeGlobalVariables(ctxt);
600    xsltFreeDocuments(ctxt);
601    xsltFreeCtxtExts(ctxt);
602    xsltFreeRVTs(ctxt);
603    xsltTransformCacheFree(ctxt->cache);
604    xmlDictFree(ctxt->dict);
605#ifdef WITH_XSLT_DEBUG
606    xsltGenericDebug(xsltGenericDebugContext,
607                     "freeing transformation dictionary\n");
608#endif
609    memset(ctxt, -1, sizeof(xsltTransformContext));
610    xmlFree(ctxt);
611}
612
613/************************************************************************
614 *									*
615 *			Copy of Nodes in an XSLT fashion		*
616 *									*
617 ************************************************************************/
618
619xmlNodePtr xsltCopyTree(xsltTransformContextPtr ctxt,
620                        xmlNodePtr node, xmlNodePtr insert, int literal);
621
622/**
623 * xsltAddChild:
624 * @parent:  the parent node
625 * @cur:  the child node
626 *
627 * Wrapper version of xmlAddChild with a more consistent behaviour on
628 * error. One expect the use to be child = xsltAddChild(parent, child);
629 * and the routine will take care of not leaking on errors or node merge
630 *
631 * Returns the child is successfully attached or NULL if merged or freed
632 */
633static xmlNodePtr
634xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) {
635   xmlNodePtr ret;
636
637   if ((cur == NULL) || (parent == NULL))
638       return(NULL);
639   if (parent == NULL) {
640       xmlFreeNode(cur);
641       return(NULL);
642   }
643   ret = xmlAddChild(parent, cur);
644
645   return(ret);
646}
647
648/**
649 * xsltAddTextString:
650 * @ctxt:  a XSLT process context
651 * @target:  the text node where the text will be attached
652 * @string:  the text string
653 * @len:  the string length in byte
654 *
655 * Extend the current text node with the new string, it handles coalescing
656 *
657 * Returns: the text node
658 */
659static xmlNodePtr
660xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
661		  const xmlChar *string, int len) {
662    /*
663     * optimization
664     */
665    if ((len <= 0) || (string == NULL) || (target == NULL))
666        return(target);
667
668    if (ctxt->lasttext == target->content) {
669
670	if (ctxt->lasttuse + len >= ctxt->lasttsize) {
671	    xmlChar *newbuf;
672	    int size;
673
674	    size = ctxt->lasttsize + len + 100;
675	    size *= 2;
676	    newbuf = (xmlChar *) xmlRealloc(target->content,size);
677	    if (newbuf == NULL) {
678		xsltTransformError(ctxt, NULL, target,
679		 "xsltCopyText: text allocation failed\n");
680		return(NULL);
681	    }
682	    ctxt->lasttsize = size;
683	    ctxt->lasttext = newbuf;
684	    target->content = newbuf;
685	}
686	memcpy(&(target->content[ctxt->lasttuse]), string, len);
687	ctxt->lasttuse += len;
688	target->content[ctxt->lasttuse] = 0;
689    } else {
690	xmlNodeAddContent(target, string);
691	ctxt->lasttext = target->content;
692	len = xmlStrlen(target->content);
693	ctxt->lasttsize = len;
694	ctxt->lasttuse = len;
695    }
696    return(target);
697}
698
699/**
700 * xsltCopyTextString:
701 * @ctxt:  a XSLT process context
702 * @target:  the element where the text will be attached
703 * @string:  the text string
704 * @noescape:  should disable-escaping be activated for this text node.
705 *
706 * Adds @string to a newly created or an existent text node child of
707 * @target.
708 *
709 * Returns: the text node, where the text content of @cur is copied to.
710 *          NULL in case of API or internal errors.
711 */
712xmlNodePtr
713xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
714	           const xmlChar *string, int noescape)
715{
716    xmlNodePtr copy;
717    int len;
718
719    if (string == NULL)
720	return(NULL);
721
722#ifdef WITH_XSLT_DEBUG_PROCESS
723    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
724		     "xsltCopyTextString: copy text %s\n",
725		     string));
726#endif
727
728    /*
729    * Play save and reset the merging mechanism for every new
730    * target node.
731    */
732    if ((target == NULL) || (target->children == NULL)) {
733	ctxt->lasttext = NULL;
734    }
735
736    /* handle coalescing of text nodes here */
737    len = xmlStrlen(string);
738    if ((ctxt->type == XSLT_OUTPUT_XML) &&
739	(ctxt->style->cdataSection != NULL) &&
740	(target != NULL) &&
741	(target->type == XML_ELEMENT_NODE) &&
742	(((target->ns == NULL) &&
743	  (xmlHashLookup2(ctxt->style->cdataSection,
744		          target->name, NULL) != NULL)) ||
745	 ((target->ns != NULL) &&
746	  (xmlHashLookup2(ctxt->style->cdataSection,
747	                  target->name, target->ns->href) != NULL))))
748    {
749	/*
750	* Process "cdata-section-elements".
751	*/
752	if ((target->last != NULL) &&
753	    (target->last->type == XML_CDATA_SECTION_NODE))
754	{
755	    return(xsltAddTextString(ctxt, target->last, string, len));
756	}
757	copy = xmlNewCDataBlock(ctxt->output, string, len);
758    } else if (noescape) {
759	/*
760	* Process "disable-output-escaping".
761	*/
762	if ((target != NULL) && (target->last != NULL) &&
763	    (target->last->type == XML_TEXT_NODE) &&
764	    (target->last->name == xmlStringTextNoenc))
765	{
766	    return(xsltAddTextString(ctxt, target->last, string, len));
767	}
768	copy = xmlNewTextLen(string, len);
769	if (copy != NULL)
770	    copy->name = xmlStringTextNoenc;
771    } else {
772	/*
773	* Default processing.
774	*/
775	if ((target != NULL) && (target->last != NULL) &&
776	    (target->last->type == XML_TEXT_NODE) &&
777	    (target->last->name == xmlStringText)) {
778	    return(xsltAddTextString(ctxt, target->last, string, len));
779	}
780	copy = xmlNewTextLen(string, len);
781    }
782    if (copy != NULL) {
783	if (target != NULL)
784	    copy = xsltAddChild(target, copy);
785	ctxt->lasttext = copy->content;
786	ctxt->lasttsize = len;
787	ctxt->lasttuse = len;
788    } else {
789	xsltTransformError(ctxt, NULL, target,
790			 "xsltCopyTextString: text copy failed\n");
791	ctxt->lasttext = NULL;
792    }
793    return(copy);
794}
795
796/**
797 * xsltCopyText:
798 * @ctxt:  a XSLT process context
799 * @target:  the element where the text will be attached
800 * @cur:  the text or CDATA node
801 * @interned:  the string is in the target doc dictionary
802 *
803 * Copy the text content of @cur and append it to @target's children.
804 *
805 * Returns: the text node, where the text content of @cur is copied to.
806 *          NULL in case of API or internal errors.
807 */
808static xmlNodePtr
809xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target,
810	     xmlNodePtr cur, int interned)
811{
812    xmlNodePtr copy;
813
814    if ((cur->type != XML_TEXT_NODE) &&
815	(cur->type != XML_CDATA_SECTION_NODE))
816	return(NULL);
817    if (cur->content == NULL)
818	return(NULL);
819
820#ifdef WITH_XSLT_DEBUG_PROCESS
821    if (cur->type == XML_CDATA_SECTION_NODE) {
822	XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
823			 "xsltCopyText: copy CDATA text %s\n",
824			 cur->content));
825    } else if (cur->name == xmlStringTextNoenc) {
826	XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
827		     "xsltCopyText: copy unescaped text %s\n",
828			 cur->content));
829    } else {
830	XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
831			 "xsltCopyText: copy text %s\n",
832			 cur->content));
833    }
834#endif
835
836    /*
837    * Play save and reset the merging mechanism for every new
838    * target node.
839    */
840    if ((target == NULL) || (target->children == NULL)) {
841	ctxt->lasttext = NULL;
842    }
843
844    if ((ctxt->style->cdataSection != NULL) &&
845	(ctxt->type == XSLT_OUTPUT_XML) &&
846	(target != NULL) &&
847	(target->type == XML_ELEMENT_NODE) &&
848	(((target->ns == NULL) &&
849	  (xmlHashLookup2(ctxt->style->cdataSection,
850		          target->name, NULL) != NULL)) ||
851	 ((target->ns != NULL) &&
852	  (xmlHashLookup2(ctxt->style->cdataSection,
853	                  target->name, target->ns->href) != NULL))))
854    {
855	/*
856	* Process "cdata-section-elements".
857	*/
858	/*
859	* OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
860	*/
861	/*
862	* TODO: Since this doesn't merge adjacent CDATA-section nodes,
863	* we'll get: <![CDATA[x]]><!CDATA[y]]>.
864	* TODO: Reported in #321505.
865	*/
866	if ((target->last != NULL) &&
867	     (target->last->type == XML_CDATA_SECTION_NODE))
868	{
869	    /*
870	    * Append to existing CDATA-section node.
871	    */
872	    copy = xsltAddTextString(ctxt, target->last, cur->content,
873		xmlStrlen(cur->content));
874	    goto exit;
875	} else {
876	    unsigned int len;
877
878	    len = xmlStrlen(cur->content);
879	    copy = xmlNewCDataBlock(ctxt->output, cur->content, len);
880	    if (copy == NULL)
881		goto exit;
882	    ctxt->lasttext = copy->content;
883	    ctxt->lasttsize = len;
884	    ctxt->lasttuse = len;
885	}
886    } else if ((target != NULL) &&
887	(target->last != NULL) &&
888	/* both escaped or both non-escaped text-nodes */
889	(((target->last->type == XML_TEXT_NODE) &&
890	(target->last->name == cur->name)) ||
891        /* non-escaped text nodes and CDATA-section nodes */
892	(((target->last->type == XML_CDATA_SECTION_NODE) &&
893	(cur->name == xmlStringTextNoenc)))))
894    {
895	/*
896	 * we are appending to an existing text node
897	 */
898	copy = xsltAddTextString(ctxt, target->last, cur->content,
899	    xmlStrlen(cur->content));
900	goto exit;
901    } else if ((interned) && (target != NULL) &&
902	(target->doc != NULL) &&
903	(target->doc->dict == ctxt->dict))
904    {
905	/*
906	* TODO: DO we want to use this also for "text" output?
907	*/
908        copy = xmlNewTextLen(NULL, 0);
909	if (copy == NULL)
910	    goto exit;
911	if (cur->name == xmlStringTextNoenc)
912	    copy->name = xmlStringTextNoenc;
913
914	/*
915	 * Must confirm that content is in dict (bug 302821)
916	 * TODO: This check should be not needed for text coming
917	 * from the stylesheets
918	 */
919	if (xmlDictOwns(ctxt->dict, cur->content))
920	    copy->content = cur->content;
921	else {
922	    if ((copy->content = xmlStrdup(cur->content)) == NULL)
923		return NULL;
924	}
925    } else {
926        /*
927	 * normal processing. keep counters to extend the text node
928	 * in xsltAddTextString if needed.
929	 */
930        unsigned int len;
931
932	len = xmlStrlen(cur->content);
933	copy = xmlNewTextLen(cur->content, len);
934	if (copy == NULL)
935	    goto exit;
936	if (cur->name == xmlStringTextNoenc)
937	    copy->name = xmlStringTextNoenc;
938	ctxt->lasttext = copy->content;
939	ctxt->lasttsize = len;
940	ctxt->lasttuse = len;
941    }
942    if (copy != NULL) {
943	if (target != NULL) {
944	    copy->doc = target->doc;
945	    /*
946	    * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
947	    *  to ensure that the optimized text-merging mechanism
948	    *  won't interfere with normal node-merging in any case.
949	    */
950	    copy = xsltAddChild(target, copy);
951	}
952    } else {
953	xsltTransformError(ctxt, NULL, target,
954			 "xsltCopyText: text copy failed\n");
955    }
956
957exit:
958    if ((copy == NULL) || (copy->content == NULL)) {
959	xsltTransformError(ctxt, NULL, target,
960	    "Internal error in xsltCopyText(): "
961	    "Failed to copy the string.\n");
962	ctxt->state = XSLT_STATE_STOPPED;
963    }
964    return(copy);
965}
966
967/**
968 * xsltShallowCopyAttr:
969 * @ctxt:  a XSLT process context
970 * @invocNode: responsible node in the stylesheet; used for error reports
971 * @target:  the element where the attribute will be grafted
972 * @attr: the attribute to be copied
973 *
974 * Do a copy of an attribute.
975 * Called by:
976 *  - xsltCopyTreeInternal()
977 *  - xsltCopyOf()
978 *  - xsltCopy()
979 *
980 * Returns: a new xmlAttrPtr, or NULL in case of error.
981 */
982static xmlAttrPtr
983xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
984	     xmlNodePtr target, xmlAttrPtr attr)
985{
986    xmlAttrPtr copy;
987    xmlChar *value;
988
989    if (attr == NULL)
990	return(NULL);
991
992    if (target->type != XML_ELEMENT_NODE) {
993	xsltTransformError(ctxt, NULL, invocNode,
994	    "Cannot add an attribute node to a non-element node.\n");
995	return(NULL);
996    }
997
998    if (target->children != NULL) {
999	xsltTransformError(ctxt, NULL, invocNode,
1000	    "Attribute nodes must be added before "
1001	    "any child nodes to an element.\n");
1002	return(NULL);
1003    }
1004
1005    value = xmlNodeListGetString(attr->doc, attr->children, 1);
1006    if (attr->ns != NULL) {
1007	xmlNsPtr ns;
1008
1009	ns = xsltGetSpecialNamespace(ctxt, invocNode,
1010	    attr->ns->href, attr->ns->prefix, target);
1011	if (ns == NULL) {
1012	    xsltTransformError(ctxt, NULL, invocNode,
1013		"Namespace fixup error: Failed to acquire an in-scope "
1014		"namespace binding of the copied attribute '{%s}%s'.\n",
1015		attr->ns->href, attr->name);
1016	    /*
1017	    * TODO: Should we just stop here?
1018	    */
1019	}
1020	/*
1021	* Note that xmlSetNsProp() will take care of duplicates
1022	* and assigns the new namespace even to a duplicate.
1023	*/
1024	copy = xmlSetNsProp(target, ns, attr->name, value);
1025    } else {
1026	copy = xmlSetNsProp(target, NULL, attr->name, value);
1027    }
1028    if (value != NULL)
1029	xmlFree(value);
1030
1031    if (copy == NULL)
1032	return(NULL);
1033
1034#if 0
1035    /*
1036    * NOTE: This was optimized according to bug #342695.
1037    * TODO: Can this further be optimized, if source and target
1038    *  share the same dict and attr->children is just 1 text node
1039    *  which is in the dict? How probable is such a case?
1040    */
1041    /*
1042    * TODO: Do we need to create an empty text node if the value
1043    *  is the empty string?
1044    */
1045    value = xmlNodeListGetString(attr->doc, attr->children, 1);
1046    if (value != NULL) {
1047	txtNode = xmlNewDocText(target->doc, NULL);
1048	if (txtNode == NULL)
1049	    return(NULL);
1050	if ((target->doc != NULL) &&
1051	    (target->doc->dict != NULL))
1052	{
1053	    txtNode->content =
1054		(xmlChar *) xmlDictLookup(target->doc->dict,
1055		    BAD_CAST value, -1);
1056	    xmlFree(value);
1057	} else
1058	    txtNode->content = value;
1059	copy->children = txtNode;
1060    }
1061#endif
1062
1063    return(copy);
1064}
1065
1066/**
1067 * xsltCopyAttrListNoOverwrite:
1068 * @ctxt:  a XSLT process context
1069 * @invocNode: responsible node in the stylesheet; used for error reports
1070 * @target:  the element where the new attributes will be grafted
1071 * @attr:  the first attribute in the list to be copied
1072 *
1073 * Copies a list of attribute nodes, starting with @attr, over to the
1074 * @target element node.
1075 *
1076 * Called by:
1077 *  - xsltCopyTreeInternal()
1078 *
1079 * Returns 0 on success and -1 on errors and internal errors.
1080 */
1081static int
1082xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt,
1083			    xmlNodePtr invocNode,
1084			    xmlNodePtr target, xmlAttrPtr attr)
1085{
1086    xmlAttrPtr copy;
1087    xmlNsPtr origNs = NULL, copyNs = NULL;
1088    xmlChar *value;
1089
1090    /*
1091    * Don't use xmlCopyProp() here, since it will try to
1092    * reconciliate namespaces.
1093    */
1094    while (attr != NULL) {
1095	/*
1096	* Find a namespace node in the tree of @target.
1097	* Avoid searching for the same ns.
1098	*/
1099	if (attr->ns != origNs) {
1100	    origNs = attr->ns;
1101	    if (attr->ns != NULL) {
1102		copyNs = xsltGetSpecialNamespace(ctxt, invocNode,
1103		    attr->ns->href, attr->ns->prefix, target);
1104		if (copyNs == NULL)
1105		    return(-1);
1106	    } else
1107		copyNs = NULL;
1108	}
1109	/*
1110	 * If attribute has a value, we need to copy it (watching out
1111	 * for possible entities)
1112	 */
1113	if ((attr->children) && (attr->children->type == XML_TEXT_NODE) &&
1114            (attr->children->next == NULL)) {
1115            copy = xmlNewNsProp(target, copyNs, attr->name,
1116                                attr->children->content);
1117        } else if (attr->children != NULL) {
1118	    value = xmlNodeListGetString(attr->doc, attr->children, 1);
1119            copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value);
1120	    xmlFree(value);
1121        } else {
1122            copy = xmlNewNsProp(target, copyNs, attr->name, NULL);
1123        }
1124
1125	if (copy == NULL)
1126	    return(-1);
1127
1128	attr = attr->next;
1129    }
1130    return(0);
1131}
1132
1133/**
1134 * xsltShallowCopyElem:
1135 * @ctxt:  the XSLT process context
1136 * @node:  the element node in the source tree
1137 *         or the Literal Result Element
1138 * @insert:  the parent in the result tree
1139 * @isLRE: if @node is a Literal Result Element
1140 *
1141 * Make a copy of the element node @node
1142 * and insert it as last child of @insert.
1143 *
1144 * URGENT TODO: The problem with this one (for the non-refactored code)
1145 * is that it is used for both, Literal Result Elements *and*
1146 * copying input nodes.
1147 *
1148 * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
1149 *
1150 * Called from:
1151 *   xsltApplySequenceConstructor()
1152 *    (for Literal Result Elements - which is a problem)
1153 *   xsltCopy() (for shallow-copying elements via xsl:copy)
1154 *
1155 * Returns a pointer to the new node, or NULL in case of error
1156 */
1157static xmlNodePtr
1158xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
1159		    xmlNodePtr insert, int isLRE)
1160{
1161    xmlNodePtr copy;
1162
1163    if ((node->type == XML_DTD_NODE) || (insert == NULL))
1164	return(NULL);
1165    if ((node->type == XML_TEXT_NODE) ||
1166	(node->type == XML_CDATA_SECTION_NODE))
1167	return(xsltCopyText(ctxt, insert, node, 0));
1168
1169    copy = xmlDocCopyNode(node, insert->doc, 0);
1170    if (copy != NULL) {
1171	copy->doc = ctxt->output;
1172	copy = xsltAddChild(insert, copy);
1173
1174	if (node->type == XML_ELEMENT_NODE) {
1175	    /*
1176	     * Add namespaces as they are needed
1177	     */
1178	    if (node->nsDef != NULL) {
1179		/*
1180		* TODO: Remove the LRE case in the refactored code
1181		* gets enabled.
1182		*/
1183		if (isLRE)
1184		    xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1185		else
1186		    xsltCopyNamespaceListInternal(copy, node->nsDef);
1187	    }
1188
1189	    /*
1190	    * URGENT TODO: The problem with this is that it does not
1191	    *  copy over all namespace nodes in scope.
1192	    *  The damn thing about this is, that we would need to
1193	    *  use the xmlGetNsList(), for every single node; this is
1194	    *  also done in xsltCopyTreeInternal(), but only for the top node.
1195	    */
1196	    if (node->ns != NULL) {
1197		if (isLRE) {
1198		    /*
1199		    * REVISIT TODO: Since the non-refactored code still does
1200		    *  ns-aliasing, we need to call xsltGetNamespace() here.
1201		    *  Remove this when ready.
1202		    */
1203		    copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
1204		} else {
1205		    copy->ns = xsltGetSpecialNamespace(ctxt,
1206			node, node->ns->href, node->ns->prefix, copy);
1207
1208		}
1209	    } else if ((insert->type == XML_ELEMENT_NODE) &&
1210		       (insert->ns != NULL))
1211	    {
1212		/*
1213		* "Undeclare" the default namespace.
1214		*/
1215		xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy);
1216	    }
1217	}
1218    } else {
1219	xsltTransformError(ctxt, NULL, node,
1220		"xsltShallowCopyElem: copy %s failed\n", node->name);
1221    }
1222    return(copy);
1223}
1224
1225/**
1226 * xsltCopyTreeList:
1227 * @ctxt:  a XSLT process context
1228 * @invocNode: responsible node in the stylesheet; used for error reports
1229 * @list:  the list of element nodes in the source tree.
1230 * @insert:  the parent in the result tree.
1231 * @isLRE:  is this a literal result element list
1232 * @topElemVisited: indicates if a top-most element was already processed
1233 *
1234 * Make a copy of the full list of tree @list
1235 * and insert it as last children of @insert
1236 *
1237 * NOTE: Not to be used for Literal Result Elements.
1238 *
1239 * Used by:
1240 *  - xsltCopyOf()
1241 *
1242 * Returns a pointer to the new list, or NULL in case of error
1243 */
1244static xmlNodePtr
1245xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
1246		 xmlNodePtr list,
1247		 xmlNodePtr insert, int isLRE, int topElemVisited)
1248{
1249    xmlNodePtr copy, ret = NULL;
1250
1251    while (list != NULL) {
1252	copy = xsltCopyTreeInternal(ctxt, invocNode,
1253	    list, insert, isLRE, topElemVisited);
1254	if (copy != NULL) {
1255	    if (ret == NULL) {
1256		ret = copy;
1257	    }
1258	}
1259	list = list->next;
1260    }
1261    return(ret);
1262}
1263
1264/**
1265 * xsltCopyNamespaceListInternal:
1266 * @node:  the target node
1267 * @cur:  the first namespace
1268 *
1269 * Do a copy of a namespace list. If @node is non-NULL the
1270 * new namespaces are added automatically.
1271 * Called by:
1272 *   xsltCopyTreeInternal()
1273 *
1274 * QUESTION: What is the exact difference between this function
1275 *  and xsltCopyNamespaceList() in "namespaces.c"?
1276 * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
1277 *
1278 * Returns: a new xmlNsPtr, or NULL in case of error.
1279 */
1280static xmlNsPtr
1281xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) {
1282    xmlNsPtr ret = NULL;
1283    xmlNsPtr p = NULL, q, luNs;
1284
1285    if (ns == NULL)
1286	return(NULL);
1287    /*
1288     * One can add namespaces only on element nodes
1289     */
1290    if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
1291	elem = NULL;
1292
1293    do {
1294	if (ns->type != XML_NAMESPACE_DECL)
1295	    break;
1296	/*
1297	 * Avoid duplicating namespace declarations on the tree.
1298	 */
1299	if (elem != NULL) {
1300	    if ((elem->ns != NULL) &&
1301		xmlStrEqual(elem->ns->prefix, ns->prefix) &&
1302		xmlStrEqual(elem->ns->href, ns->href))
1303	    {
1304		ns = ns->next;
1305		continue;
1306	    }
1307	    luNs = xmlSearchNs(elem->doc, elem, ns->prefix);
1308	    if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href)))
1309	    {
1310		ns = ns->next;
1311		continue;
1312	    }
1313	}
1314	q = xmlNewNs(elem, ns->href, ns->prefix);
1315	if (p == NULL) {
1316	    ret = p = q;
1317	} else if (q != NULL) {
1318	    p->next = q;
1319	    p = q;
1320	}
1321	ns = ns->next;
1322    } while (ns != NULL);
1323    return(ret);
1324}
1325
1326/**
1327 * xsltShallowCopyNsNode:
1328 * @ctxt:  the XSLT transformation context
1329 * @invocNode: responsible node in the stylesheet; used for error reports
1330 * @insert:  the target element node in the result tree
1331 * @ns: the namespace node
1332 *
1333 * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
1334 *
1335 * Returns a new/existing ns-node, or NULL.
1336 */
1337static xmlNsPtr
1338xsltShallowCopyNsNode(xsltTransformContextPtr ctxt,
1339		      xmlNodePtr invocNode,
1340		      xmlNodePtr insert,
1341		      xmlNsPtr ns)
1342{
1343    /*
1344     * TODO: Contrary to header comments, this is declared as int.
1345     * be modified to return a node pointer, or NULL if any error
1346     */
1347    xmlNsPtr tmpns;
1348
1349    if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))
1350	return(NULL);
1351
1352    if (insert->children != NULL) {
1353	xsltTransformError(ctxt, NULL, invocNode,
1354	    "Namespace nodes must be added before "
1355	    "any child nodes are added to an element.\n");
1356	return(NULL);
1357    }
1358    /*
1359     * BIG NOTE: Xalan-J simply overwrites any ns-decls with
1360     * an equal prefix. We definitively won't do that.
1361     *
1362     * MSXML 4.0 and the .NET ignores ns-decls for which an
1363     * equal prefix is already in use.
1364     *
1365     * Saxon raises an error like:
1366     * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
1367     * nodes with the same name".
1368     *
1369     * NOTE: We'll currently follow MSXML here.
1370     * REVISIT TODO: Check if it's better to follow Saxon here.
1371     */
1372    if (ns->prefix == NULL) {
1373	/*
1374	* If we are adding ns-nodes to an element using e.g.
1375	* <xsl:copy-of select="/foo/namespace::*">, then we need
1376	* to ensure that we don't incorrectly declare a default
1377	* namespace on an element in no namespace, which otherwise
1378	* would move the element incorrectly into a namespace, if
1379	* the node tree is serialized.
1380	*/
1381	if (insert->ns == NULL)
1382	    goto occupied;
1383    } else if ((ns->prefix[0] == 'x') &&
1384	xmlStrEqual(ns->prefix, BAD_CAST "xml"))
1385    {
1386	/*
1387	* The XML namespace is built in.
1388	*/
1389	return(NULL);
1390    }
1391
1392    if (insert->nsDef != NULL) {
1393	tmpns = insert->nsDef;
1394	do {
1395	    if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) {
1396		if ((tmpns->prefix == ns->prefix) ||
1397		    xmlStrEqual(tmpns->prefix, ns->prefix))
1398		{
1399		    /*
1400		    * Same prefix.
1401		    */
1402		    if (xmlStrEqual(tmpns->href, ns->href))
1403			return(NULL);
1404		    goto occupied;
1405		}
1406	    }
1407	    tmpns = tmpns->next;
1408	} while (tmpns != NULL);
1409    }
1410    tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);
1411    if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))
1412	return(NULL);
1413    /*
1414    * Declare a new namespace.
1415    * TODO: The problem (wrt efficiency) with this xmlNewNs() is
1416    * that it will again search the already declared namespaces
1417    * for a duplicate :-/
1418    */
1419    return(xmlNewNs(insert, ns->href, ns->prefix));
1420
1421occupied:
1422    /*
1423    * TODO: We could as well raise an error here (like Saxon does),
1424    * or at least generate a warning.
1425    */
1426    return(NULL);
1427}
1428
1429/**
1430 * xsltCopyTreeInternal:
1431 * @ctxt:  the XSLT transformation context
1432 * @invocNode: responsible node in the stylesheet; used for error reports
1433 * @node:  the element node in the source tree
1434 * @insert:  the parent in the result tree
1435 * @isLRE:  indicates if @node is a Literal Result Element
1436 * @topElemVisited: indicates if a top-most element was already processed
1437 *
1438 * Make a copy of the full tree under the element node @node
1439 * and insert it as last child of @insert
1440 *
1441 * NOTE: Not to be used for Literal Result Elements.
1442 *
1443 * Used by:
1444 *  - xsltCopyOf()
1445 *
1446 * Returns a pointer to the new tree, or NULL in case of error
1447 */
1448static xmlNodePtr
1449xsltCopyTreeInternal(xsltTransformContextPtr ctxt,
1450		     xmlNodePtr invocNode,
1451		     xmlNodePtr node,
1452		     xmlNodePtr insert, int isLRE, int topElemVisited)
1453{
1454    xmlNodePtr copy;
1455
1456    if (node == NULL)
1457	return(NULL);
1458    switch (node->type) {
1459        case XML_ELEMENT_NODE:
1460        case XML_ENTITY_REF_NODE:
1461        case XML_ENTITY_NODE:
1462        case XML_PI_NODE:
1463        case XML_COMMENT_NODE:
1464        case XML_DOCUMENT_NODE:
1465        case XML_HTML_DOCUMENT_NODE:
1466#ifdef LIBXML_DOCB_ENABLED
1467        case XML_DOCB_DOCUMENT_NODE:
1468#endif
1469	    break;
1470        case XML_TEXT_NODE: {
1471	    int noenc = (node->name == xmlStringTextNoenc);
1472	    return(xsltCopyTextString(ctxt, insert, node->content, noenc));
1473	    }
1474        case XML_CDATA_SECTION_NODE:
1475	    return(xsltCopyTextString(ctxt, insert, node->content, 0));
1476        case XML_ATTRIBUTE_NODE:
1477	    return((xmlNodePtr)
1478		xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node));
1479        case XML_NAMESPACE_DECL:
1480	    return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode,
1481		insert, (xmlNsPtr) node));
1482
1483        case XML_DOCUMENT_TYPE_NODE:
1484        case XML_DOCUMENT_FRAG_NODE:
1485        case XML_NOTATION_NODE:
1486        case XML_DTD_NODE:
1487        case XML_ELEMENT_DECL:
1488        case XML_ATTRIBUTE_DECL:
1489        case XML_ENTITY_DECL:
1490        case XML_XINCLUDE_START:
1491        case XML_XINCLUDE_END:
1492            return(NULL);
1493    }
1494    if (XSLT_IS_RES_TREE_FRAG(node)) {
1495	if (node->children != NULL)
1496	    copy = xsltCopyTreeList(ctxt, invocNode,
1497		node->children, insert, 0, 0);
1498	else
1499	    copy = NULL;
1500	return(copy);
1501    }
1502    copy = xmlDocCopyNode(node, insert->doc, 0);
1503    if (copy != NULL) {
1504	copy->doc = ctxt->output;
1505	copy = xsltAddChild(insert, copy);
1506	/*
1507	 * The node may have been coalesced into another text node.
1508	 */
1509	if (insert->last != copy)
1510	    return(insert->last);
1511	copy->next = NULL;
1512
1513	if (node->type == XML_ELEMENT_NODE) {
1514	    /*
1515	    * Copy in-scope namespace nodes.
1516	    *
1517	    * REVISIT: Since we try to reuse existing in-scope ns-decls by
1518	    *  using xmlSearchNsByHref(), this will eventually change
1519	    *  the prefix of an original ns-binding; thus it might
1520	    *  break QNames in element/attribute content.
1521	    * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
1522	    *  context, plus a ns-lookup function, which writes directly
1523	    *  to a given list, then we wouldn't need to create/free the
1524	    *  nsList every time.
1525	    */
1526	    if ((topElemVisited == 0) &&
1527		(node->parent != NULL) &&
1528		(node->parent->type != XML_DOCUMENT_NODE) &&
1529		(node->parent->type != XML_HTML_DOCUMENT_NODE))
1530	    {
1531		xmlNsPtr *nsList, *curns, ns;
1532
1533		/*
1534		* If this is a top-most element in a tree to be
1535		* copied, then we need to ensure that all in-scope
1536		* namespaces are copied over. For nodes deeper in the
1537		* tree, it is sufficient to reconcile only the ns-decls
1538		* (node->nsDef entries).
1539		*/
1540
1541		nsList = xmlGetNsList(node->doc, node);
1542		if (nsList != NULL) {
1543		    curns = nsList;
1544		    do {
1545			/*
1546			* Search by prefix first in order to break as less
1547			* QNames in element/attribute content as possible.
1548			*/
1549			ns = xmlSearchNs(insert->doc, insert,
1550			    (*curns)->prefix);
1551
1552			if ((ns == NULL) ||
1553			    (! xmlStrEqual(ns->href, (*curns)->href)))
1554			{
1555			    ns = NULL;
1556			    /*
1557			    * Search by namespace name.
1558			    * REVISIT TODO: Currently disabled.
1559			    */
1560#if 0
1561			    ns = xmlSearchNsByHref(insert->doc,
1562				insert, (*curns)->href);
1563#endif
1564			}
1565			if (ns == NULL) {
1566			    /*
1567			    * Declare a new namespace on the copied element.
1568			    */
1569			    ns = xmlNewNs(copy, (*curns)->href,
1570				(*curns)->prefix);
1571			    /* TODO: Handle errors */
1572			}
1573			if (node->ns == *curns) {
1574			    /*
1575			    * If this was the original's namespace then set
1576			    * the generated counterpart on the copy.
1577			    */
1578			    copy->ns = ns;
1579			}
1580			curns++;
1581		    } while (*curns != NULL);
1582		    xmlFree(nsList);
1583		}
1584	    } else if (node->nsDef != NULL) {
1585		/*
1586		* Copy over all namespace declaration attributes.
1587		*/
1588		if (node->nsDef != NULL) {
1589		    if (isLRE)
1590			xsltCopyNamespaceList(ctxt, copy, node->nsDef);
1591		    else
1592			xsltCopyNamespaceListInternal(copy, node->nsDef);
1593		}
1594	    }
1595	    /*
1596	    * Set the namespace.
1597	    */
1598	    if (node->ns != NULL) {
1599		if (copy->ns == NULL) {
1600		    /*
1601		    * This will map copy->ns to one of the newly created
1602		    * in-scope ns-decls, OR create a new ns-decl on @copy.
1603		    */
1604		    copy->ns = xsltGetSpecialNamespace(ctxt, invocNode,
1605			node->ns->href, node->ns->prefix, copy);
1606		}
1607	    } else if ((insert->type == XML_ELEMENT_NODE) &&
1608		(insert->ns != NULL))
1609	    {
1610		/*
1611		* "Undeclare" the default namespace on @copy with xmlns="".
1612		*/
1613		xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy);
1614	    }
1615	    /*
1616	    * Copy attribute nodes.
1617	    */
1618	    if (node->properties != NULL) {
1619		xsltCopyAttrListNoOverwrite(ctxt, invocNode,
1620		    copy, node->properties);
1621	    }
1622	    if (topElemVisited == 0)
1623		topElemVisited = 1;
1624	}
1625	/*
1626	* Copy the subtree.
1627	*/
1628	if (node->children != NULL) {
1629	    xsltCopyTreeList(ctxt, invocNode,
1630		node->children, copy, isLRE, topElemVisited);
1631	}
1632    } else {
1633	xsltTransformError(ctxt, NULL, invocNode,
1634	    "xsltCopyTreeInternal: Copying of '%s' failed.\n", node->name);
1635    }
1636    return(copy);
1637}
1638
1639/**
1640 * xsltCopyTree:
1641 * @ctxt:  the XSLT transformation context
1642 * @node:  the element node in the source tree
1643 * @insert:  the parent in the result tree
1644 * @literal:  indicates if @node is a Literal Result Element
1645 *
1646 * Make a copy of the full tree under the element node @node
1647 * and insert it as last child of @insert
1648 * For literal result element, some of the namespaces may not be copied
1649 * over according to section 7.1.
1650 * TODO: Why is this a public function?
1651 *
1652 * Returns a pointer to the new tree, or NULL in case of error
1653 */
1654xmlNodePtr
1655xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
1656	     xmlNodePtr insert, int literal)
1657{
1658    return(xsltCopyTreeInternal(ctxt, node, node, insert, literal, 0));
1659
1660}
1661
1662/************************************************************************
1663 *									*
1664 *		Error/fallback processing				*
1665 *									*
1666 ************************************************************************/
1667
1668/**
1669 * xsltApplyFallbacks:
1670 * @ctxt:  a XSLT process context
1671 * @node:  the node in the source tree.
1672 * @inst:  the node generating the error
1673 *
1674 * Process possible xsl:fallback nodes present under @inst
1675 *
1676 * Returns the number of xsl:fallback element found and processed
1677 */
1678static int
1679xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node,
1680	           xmlNodePtr inst) {
1681
1682    xmlNodePtr child;
1683    int ret = 0;
1684
1685    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) ||
1686	(inst->children == NULL))
1687	return(0);
1688
1689    child = inst->children;
1690    while (child != NULL) {
1691        if ((IS_XSLT_ELEM(child)) &&
1692            (xmlStrEqual(child->name, BAD_CAST "fallback"))) {
1693#ifdef WITH_XSLT_DEBUG_PARSING
1694	    xsltGenericDebug(xsltGenericDebugContext,
1695			     "applying xsl:fallback\n");
1696#endif
1697	    ret++;
1698	    xsltApplySequenceConstructor(ctxt, node, child->children,
1699		NULL);
1700	}
1701	child = child->next;
1702    }
1703    return(ret);
1704}
1705
1706/************************************************************************
1707 *									*
1708 *			Default processing				*
1709 *									*
1710 ************************************************************************/
1711
1712/**
1713 * xsltDefaultProcessOneNode:
1714 * @ctxt:  a XSLT process context
1715 * @node:  the node in the source tree.
1716 * @params: extra parameters passed to the template if any
1717 *
1718 * Process the source node with the default built-in template rule:
1719 * <xsl:template match="*|/">
1720 *   <xsl:apply-templates/>
1721 * </xsl:template>
1722 *
1723 * and
1724 *
1725 * <xsl:template match="text()|@*">
1726 *   <xsl:value-of select="."/>
1727 * </xsl:template>
1728 *
1729 * Note also that namespace declarations are copied directly:
1730 *
1731 * the built-in template rule is the only template rule that is applied
1732 * for namespace nodes.
1733 */
1734static void
1735xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
1736			  xsltStackElemPtr params) {
1737    xmlNodePtr copy;
1738    xmlNodePtr delete = NULL, cur;
1739    int nbchild = 0, oldSize;
1740    int childno = 0, oldPos;
1741    xsltTemplatePtr template;
1742
1743    CHECK_STOPPED;
1744    /*
1745     * Handling of leaves
1746     */
1747    switch (node->type) {
1748	case XML_DOCUMENT_NODE:
1749	case XML_HTML_DOCUMENT_NODE:
1750	case XML_ELEMENT_NODE:
1751	    break;
1752	case XML_CDATA_SECTION_NODE:
1753#ifdef WITH_XSLT_DEBUG_PROCESS
1754	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1755	     "xsltDefaultProcessOneNode: copy CDATA %s\n",
1756		node->content));
1757#endif
1758	    copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1759	    if (copy == NULL) {
1760		xsltTransformError(ctxt, NULL, node,
1761		 "xsltDefaultProcessOneNode: cdata copy failed\n");
1762	    }
1763	    return;
1764	case XML_TEXT_NODE:
1765#ifdef WITH_XSLT_DEBUG_PROCESS
1766	    if (node->content == NULL) {
1767		XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1768		 "xsltDefaultProcessOneNode: copy empty text\n"));
1769		return;
1770	    } else {
1771		XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1772		 "xsltDefaultProcessOneNode: copy text %s\n",
1773			node->content));
1774            }
1775#endif
1776	    copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
1777	    if (copy == NULL) {
1778		xsltTransformError(ctxt, NULL, node,
1779		 "xsltDefaultProcessOneNode: text copy failed\n");
1780	    }
1781	    return;
1782	case XML_ATTRIBUTE_NODE:
1783	    cur = node->children;
1784	    while ((cur != NULL) && (cur->type != XML_TEXT_NODE))
1785		cur = cur->next;
1786	    if (cur == NULL) {
1787		xsltTransformError(ctxt, NULL, node,
1788		 "xsltDefaultProcessOneNode: no text for attribute\n");
1789	    } else {
1790#ifdef WITH_XSLT_DEBUG_PROCESS
1791		if (cur->content == NULL) {
1792		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1793		     "xsltDefaultProcessOneNode: copy empty text\n"));
1794		} else {
1795		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1796		     "xsltDefaultProcessOneNode: copy text %s\n",
1797			cur->content));
1798                }
1799#endif
1800		copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
1801		if (copy == NULL) {
1802		    xsltTransformError(ctxt, NULL, node,
1803		     "xsltDefaultProcessOneNode: text copy failed\n");
1804		}
1805	    }
1806	    return;
1807	default:
1808	    return;
1809    }
1810    /*
1811     * Handling of Elements: first pass, cleanup and counting
1812     */
1813    cur = node->children;
1814    while (cur != NULL) {
1815	switch (cur->type) {
1816	    case XML_TEXT_NODE:
1817	    case XML_CDATA_SECTION_NODE:
1818	    case XML_DOCUMENT_NODE:
1819	    case XML_HTML_DOCUMENT_NODE:
1820	    case XML_ELEMENT_NODE:
1821	    case XML_PI_NODE:
1822	    case XML_COMMENT_NODE:
1823		nbchild++;
1824		break;
1825            case XML_DTD_NODE:
1826		/* Unlink the DTD, it's still reachable using doc->intSubset */
1827		if (cur->next != NULL)
1828		    cur->next->prev = cur->prev;
1829		if (cur->prev != NULL)
1830		    cur->prev->next = cur->next;
1831		break;
1832	    default:
1833#ifdef WITH_XSLT_DEBUG_PROCESS
1834		XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1835		 "xsltDefaultProcessOneNode: skipping node type %d\n",
1836		                 cur->type));
1837#endif
1838		delete = cur;
1839	}
1840	cur = cur->next;
1841	if (delete != NULL) {
1842#ifdef WITH_XSLT_DEBUG_PROCESS
1843	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1844		 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1845#endif
1846	    xmlUnlinkNode(delete);
1847	    xmlFreeNode(delete);
1848	    delete = NULL;
1849	}
1850    }
1851    if (delete != NULL) {
1852#ifdef WITH_XSLT_DEBUG_PROCESS
1853	XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1854	     "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
1855#endif
1856	xmlUnlinkNode(delete);
1857	xmlFreeNode(delete);
1858	delete = NULL;
1859    }
1860
1861    /*
1862     * Handling of Elements: second pass, actual processing
1863     */
1864    oldSize = ctxt->xpathCtxt->contextSize;
1865    oldPos = ctxt->xpathCtxt->proximityPosition;
1866    cur = node->children;
1867    while (cur != NULL) {
1868	childno++;
1869	switch (cur->type) {
1870	    case XML_DOCUMENT_NODE:
1871	    case XML_HTML_DOCUMENT_NODE:
1872	    case XML_ELEMENT_NODE:
1873		ctxt->xpathCtxt->contextSize = nbchild;
1874		ctxt->xpathCtxt->proximityPosition = childno;
1875		xsltProcessOneNode(ctxt, cur, params);
1876		break;
1877	    case XML_CDATA_SECTION_NODE:
1878		template = xsltGetTemplate(ctxt, cur, NULL);
1879		if (template) {
1880#ifdef WITH_XSLT_DEBUG_PROCESS
1881		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1882		 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
1883				     cur->content));
1884#endif
1885		    /*
1886		    * Instantiate the xsl:template.
1887		    */
1888		    xsltApplyXSLTTemplate(ctxt, cur, template->content,
1889			template, params);
1890		} else /* if (ctxt->mode == NULL) */ {
1891#ifdef WITH_XSLT_DEBUG_PROCESS
1892		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1893		     "xsltDefaultProcessOneNode: copy CDATA %s\n",
1894				     cur->content));
1895#endif
1896		    copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
1897		    if (copy == NULL) {
1898			xsltTransformError(ctxt, NULL, cur,
1899			    "xsltDefaultProcessOneNode: cdata copy failed\n");
1900		    }
1901		}
1902		break;
1903	    case XML_TEXT_NODE:
1904		template = xsltGetTemplate(ctxt, cur, NULL);
1905		if (template) {
1906#ifdef WITH_XSLT_DEBUG_PROCESS
1907		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1908	     "xsltDefaultProcessOneNode: applying template for text %s\n",
1909				     cur->content));
1910#endif
1911		    ctxt->xpathCtxt->contextSize = nbchild;
1912		    ctxt->xpathCtxt->proximityPosition = childno;
1913		    /*
1914		    * Instantiate the xsl:template.
1915		    */
1916		    xsltApplyXSLTTemplate(ctxt, cur, template->content,
1917			template, params);
1918		} else /* if (ctxt->mode == NULL) */ {
1919#ifdef WITH_XSLT_DEBUG_PROCESS
1920		    if (cur->content == NULL) {
1921			XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1922			 "xsltDefaultProcessOneNode: copy empty text\n"));
1923		    } else {
1924			XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1925		     "xsltDefaultProcessOneNode: copy text %s\n",
1926					 cur->content));
1927                    }
1928#endif
1929		    copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
1930		    if (copy == NULL) {
1931			xsltTransformError(ctxt, NULL, cur,
1932			    "xsltDefaultProcessOneNode: text copy failed\n");
1933		    }
1934		}
1935		break;
1936	    case XML_PI_NODE:
1937	    case XML_COMMENT_NODE:
1938		template = xsltGetTemplate(ctxt, cur, NULL);
1939		if (template) {
1940#ifdef WITH_XSLT_DEBUG_PROCESS
1941		    if (cur->type == XML_PI_NODE) {
1942			XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1943		     "xsltDefaultProcessOneNode: template found for PI %s\n",
1944			                 cur->name));
1945		    } else if (cur->type == XML_COMMENT_NODE) {
1946			XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1947		     "xsltDefaultProcessOneNode: template found for comment\n"));
1948                    }
1949#endif
1950		    ctxt->xpathCtxt->contextSize = nbchild;
1951		    ctxt->xpathCtxt->proximityPosition = childno;
1952		    /*
1953		    * Instantiate the xsl:template.
1954		    */
1955		    xsltApplyXSLTTemplate(ctxt, cur, template->content,
1956			template, params);
1957		}
1958		break;
1959	    default:
1960		break;
1961	}
1962	cur = cur->next;
1963    }
1964    ctxt->xpathCtxt->contextSize = oldSize;
1965    ctxt->xpathCtxt->proximityPosition = oldPos;
1966}
1967
1968/**
1969 * xsltProcessOneNode:
1970 * @ctxt:  a XSLT process context
1971 * @contextNode:  the "current node" in the source tree
1972 * @withParams:  extra parameters (e.g. xsl:with-param) passed to the
1973 *               template if any
1974 *
1975 * Process the source node.
1976 */
1977void
1978xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
1979	           xsltStackElemPtr withParams)
1980{
1981    xsltTemplatePtr templ;
1982    xmlNodePtr oldNode;
1983
1984    templ = xsltGetTemplate(ctxt, contextNode, NULL);
1985    /*
1986     * If no template is found, apply the default rule.
1987     */
1988    if (templ == NULL) {
1989#ifdef WITH_XSLT_DEBUG_PROCESS
1990	if (contextNode->type == XML_DOCUMENT_NODE) {
1991	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1992	     "xsltProcessOneNode: no template found for /\n"));
1993	} else if (contextNode->type == XML_CDATA_SECTION_NODE) {
1994	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1995	     "xsltProcessOneNode: no template found for CDATA\n"));
1996	} else if (contextNode->type == XML_ATTRIBUTE_NODE) {
1997	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
1998	     "xsltProcessOneNode: no template found for attribute %s\n",
1999	                     ((xmlAttrPtr) contextNode)->name));
2000	} else  {
2001	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2002	     "xsltProcessOneNode: no template found for %s\n", contextNode->name));
2003        }
2004#endif
2005	oldNode = ctxt->node;
2006	ctxt->node = contextNode;
2007	xsltDefaultProcessOneNode(ctxt, contextNode, withParams);
2008	ctxt->node = oldNode;
2009	return;
2010    }
2011
2012    if (contextNode->type == XML_ATTRIBUTE_NODE) {
2013	xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2014	/*
2015	* Set the "current template rule".
2016	*/
2017	ctxt->currentTemplateRule = templ;
2018
2019#ifdef WITH_XSLT_DEBUG_PROCESS
2020	XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2021	     "xsltProcessOneNode: applying template '%s' for attribute %s\n",
2022	                 templ->match, contextNode->name));
2023#endif
2024	xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
2025
2026	ctxt->currentTemplateRule = oldCurTempRule;
2027    } else {
2028	xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
2029	/*
2030	* Set the "current template rule".
2031	*/
2032	ctxt->currentTemplateRule = templ;
2033
2034#ifdef WITH_XSLT_DEBUG_PROCESS
2035	if (contextNode->type == XML_DOCUMENT_NODE) {
2036	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2037	     "xsltProcessOneNode: applying template '%s' for /\n",
2038	                     templ->match));
2039	} else {
2040	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
2041	     "xsltProcessOneNode: applying template '%s' for %s\n",
2042	                     templ->match, contextNode->name));
2043        }
2044#endif
2045	xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
2046
2047	ctxt->currentTemplateRule = oldCurTempRule;
2048    }
2049}
2050
2051static xmlNodePtr
2052xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt,
2053				     xmlNodePtr contextNode,
2054				     xmlNodePtr list,
2055				     xsltTemplatePtr templ,
2056				     int *addCallResult)
2057{
2058    xmlNodePtr debugedNode = NULL;
2059
2060    if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2061        if (templ) {
2062            *addCallResult = xslAddCall(templ, templ->elem);
2063        } else {
2064            *addCallResult = xslAddCall(NULL, list);
2065        }
2066        switch (ctxt->debugStatus) {
2067            case XSLT_DEBUG_RUN_RESTART:
2068            case XSLT_DEBUG_QUIT:
2069                if (*addCallResult)
2070                    xslDropCall();
2071                return(NULL);
2072        }
2073        if (templ) {
2074            xslHandleDebugger(templ->elem, contextNode, templ, ctxt);
2075            debugedNode = templ->elem;
2076        } else if (list) {
2077            xslHandleDebugger(list, contextNode, templ, ctxt);
2078            debugedNode = list;
2079        } else if (ctxt->inst) {
2080            xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt);
2081            debugedNode = ctxt->inst;
2082        }
2083    }
2084    return(debugedNode);
2085}
2086
2087/**
2088 * xsltLocalVariablePush:
2089 * @ctxt: the transformation context
2090 * @variable: variable to be pushed to the variable stack
2091 * @level: new value for variable's level
2092 *
2093 * Places the variable onto the local variable stack
2094 *
2095 * Returns: 0 for success, -1 for any error
2096 * **NOTE:**
2097 * This is an internal routine and should not be called by users!
2098 */
2099int
2100xsltLocalVariablePush(xsltTransformContextPtr ctxt,
2101		      xsltStackElemPtr variable,
2102		      int level)
2103{
2104    if (ctxt->varsMax == 0) {
2105	ctxt->varsMax = 10;
2106	ctxt->varsTab =
2107	    (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
2108	    sizeof(ctxt->varsTab[0]));
2109	if (ctxt->varsTab == NULL) {
2110	    xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
2111	    return (-1);
2112	}
2113    }
2114    if (ctxt->varsNr >= ctxt->varsMax) {
2115	ctxt->varsMax *= 2;
2116	ctxt->varsTab =
2117	    (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
2118	    ctxt->varsMax *
2119	    sizeof(ctxt->varsTab[0]));
2120	if (ctxt->varsTab == NULL) {
2121	    xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2122	    return (-1);
2123	}
2124    }
2125    ctxt->varsTab[ctxt->varsNr++] = variable;
2126    ctxt->vars = variable;
2127    variable->level = level;
2128    return(0);
2129}
2130
2131/**
2132 * xsltReleaseLocalRVTs:
2133 *
2134 * Fragments which are results of extension instructions
2135 * are preserved; all other fragments are freed/cached.
2136 */
2137static void
2138xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
2139{
2140    xmlDocPtr cur = ctxt->localRVT, tmp;
2141
2142    while ((cur != NULL) && (cur != base)) {
2143	if (cur->psvi == (void *) ((long) 1)) {
2144	    cur = (xmlDocPtr) cur->next;
2145	} else {
2146	    tmp = cur;
2147	    cur = (xmlDocPtr) cur->next;
2148
2149	    if (tmp == ctxt->localRVT)
2150		ctxt->localRVT = cur;
2151
2152	    /*
2153	    * We need ctxt->localRVTBase for extension instructions
2154	    * which return values (like EXSLT's function).
2155	    */
2156	    if (tmp == ctxt->localRVTBase)
2157		ctxt->localRVTBase = cur;
2158
2159	    if (tmp->prev)
2160		tmp->prev->next = (xmlNodePtr) cur;
2161	    if (cur)
2162		cur->prev = tmp->prev;
2163	    xsltReleaseRVT(ctxt, tmp);
2164	}
2165    }
2166}
2167
2168/**
2169 * xsltApplySequenceConstructor:
2170 * @ctxt:  a XSLT process context
2171 * @contextNode:  the "current node" in the source tree
2172 * @list:  the nodes of a sequence constructor;
2173 *         (plus leading xsl:param elements)
2174 * @templ: the compiled xsl:template (optional)
2175 *
2176 * Processes a sequence constructor.
2177 *
2178 * NOTE: ctxt->currentTemplateRule was introduced to reflect the
2179 * semantics of "current template rule". I.e. the field ctxt->templ
2180 * is not intended to reflect this, thus always pushed onto the
2181 * template stack.
2182 */
2183static void
2184xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
2185			     xmlNodePtr contextNode, xmlNodePtr list,
2186			     xsltTemplatePtr templ)
2187{
2188    xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;
2189    xmlNodePtr cur, insert, copy = NULL;
2190    int level = 0, oldVarsNr;
2191    xmlDocPtr oldLocalFragmentTop, oldLocalFragmentBase;
2192
2193#ifdef XSLT_REFACTORED
2194    xsltStylePreCompPtr info;
2195#endif
2196
2197#ifdef WITH_DEBUGGER
2198    int addCallResult = 0;
2199    xmlNodePtr debuggedNode = NULL;
2200#endif
2201
2202    if (ctxt == NULL)
2203	return;
2204
2205#ifdef WITH_DEBUGGER
2206    if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2207	debuggedNode =
2208	    xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
2209		list, templ, &addCallResult);
2210	if (debuggedNode == NULL)
2211	    return;
2212    }
2213#endif
2214
2215    if (list == NULL)
2216        return;
2217    CHECK_STOPPED;
2218
2219    oldLocalFragmentTop = ctxt->localRVT;
2220    oldInsert = insert = ctxt->insert;
2221    oldInst = oldCurInst = ctxt->inst;
2222    oldContextNode = ctxt->node;
2223    /*
2224    * Save current number of variables on the stack; new vars are popped when
2225    * exiting.
2226    */
2227    oldVarsNr = ctxt->varsNr;
2228    /*
2229    * Process the sequence constructor.
2230    */
2231    cur = list;
2232    while (cur != NULL) {
2233        ctxt->inst = cur;
2234
2235#ifdef WITH_DEBUGGER
2236        switch (ctxt->debugStatus) {
2237            case XSLT_DEBUG_RUN_RESTART:
2238            case XSLT_DEBUG_QUIT:
2239                break;
2240
2241        }
2242#endif
2243        /*
2244         * Test; we must have a valid insertion point.
2245         */
2246        if (insert == NULL) {
2247
2248#ifdef WITH_XSLT_DEBUG_PROCESS
2249            XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2250		"xsltApplySequenceConstructor: insert == NULL !\n"));
2251#endif
2252            goto error;
2253        }
2254
2255#ifdef WITH_DEBUGGER
2256        if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur))
2257            xslHandleDebugger(cur, contextNode, templ, ctxt);
2258#endif
2259
2260#ifdef XSLT_REFACTORED
2261	if (cur->type == XML_ELEMENT_NODE) {
2262	    info = (xsltStylePreCompPtr) cur->psvi;
2263	    /*
2264	    * We expect a compiled representation on:
2265	    * 1) XSLT instructions of this XSLT version (1.0)
2266	    *    (with a few exceptions)
2267	    * 2) Literal result elements
2268	    * 3) Extension instructions
2269	    * 4) XSLT instructions of future XSLT versions
2270	    *    (forwards-compatible mode).
2271	    */
2272	    if (info == NULL) {
2273		/*
2274		* Handle the rare cases where we don't expect a compiled
2275		* representation on an XSLT element.
2276		*/
2277		if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) {
2278		    xsltMessage(ctxt, contextNode, cur);
2279		    goto skip_children;
2280		}
2281		/*
2282		* Something really went wrong:
2283		*/
2284		xsltTransformError(ctxt, NULL, cur,
2285		    "Internal error in xsltApplySequenceConstructor(): "
2286		    "The element '%s' in the stylesheet has no compiled "
2287		    "representation.\n",
2288		    cur->name);
2289                goto skip_children;
2290            }
2291
2292	    if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) {
2293		xsltStyleItemLRElementInfoPtr lrInfo =
2294		    (xsltStyleItemLRElementInfoPtr) info;
2295		/*
2296		* Literal result elements
2297		* --------------------------------------------------------
2298		*/
2299#ifdef WITH_XSLT_DEBUG_PROCESS
2300		XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2301		    xsltGenericDebug(xsltGenericDebugContext,
2302		    "xsltApplySequenceConstructor: copy literal result "
2303		    "element '%s'\n", cur->name));
2304#endif
2305		/*
2306		* Copy the raw element-node.
2307		* OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
2308		*     == NULL)
2309		*   goto error;
2310		*/
2311		copy = xmlDocCopyNode(cur, insert->doc, 0);
2312		if (copy == NULL) {
2313		    xsltTransformError(ctxt, NULL, cur,
2314			"Internal error in xsltApplySequenceConstructor(): "
2315			"Failed to copy literal result element '%s'.\n",
2316			cur->name);
2317		    goto error;
2318		} else {
2319		    /*
2320		    * Add the element-node to the result tree.
2321		    */
2322		    copy->doc = ctxt->output;
2323		    copy = xsltAddChild(insert, copy);
2324		    /*
2325		    * Create effective namespaces declarations.
2326		    * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
2327		    */
2328		    if (lrInfo->effectiveNs != NULL) {
2329			xsltEffectiveNsPtr effNs = lrInfo->effectiveNs;
2330			xmlNsPtr ns, lastns = NULL;
2331
2332			while (effNs != NULL) {
2333			    /*
2334			    * Avoid generating redundant namespace
2335			    * declarations; thus lookup if there is already
2336			    * such a ns-decl in the result.
2337			    */
2338			    ns = xmlSearchNs(copy->doc, copy, effNs->prefix);
2339			    if ((ns != NULL) &&
2340				(xmlStrEqual(ns->href, effNs->nsName)))
2341			    {
2342				effNs = effNs->next;
2343				continue;
2344			    }
2345			    ns = xmlNewNs(copy, effNs->nsName, effNs->prefix);
2346			    if (ns == NULL) {
2347				xsltTransformError(ctxt, NULL, cur,
2348				    "Internal error in "
2349				    "xsltApplySequenceConstructor(): "
2350				    "Failed to copy a namespace "
2351				    "declaration.\n");
2352				goto error;
2353			    }
2354
2355			    if (lastns == NULL)
2356				copy->nsDef = ns;
2357			    else
2358				lastns->next =ns;
2359			    lastns = ns;
2360
2361			    effNs = effNs->next;
2362			}
2363
2364		    }
2365		    /*
2366		    * NOTE that we don't need to apply ns-alising: this was
2367		    *  already done at compile-time.
2368		    */
2369		    if (cur->ns != NULL) {
2370			/*
2371			* If there's no such ns-decl in the result tree,
2372			* then xsltGetSpecialNamespace() will
2373			* create a ns-decl on the copied node.
2374			*/
2375			copy->ns = xsltGetSpecialNamespace(ctxt, cur,
2376			    cur->ns->href, cur->ns->prefix, copy);
2377		    } else {
2378			/*
2379			* Undeclare the default namespace if needed.
2380			* This can be skipped, if the result element has
2381			*  no ns-decls, in which case the result element
2382			*  obviously does not declare a default namespace;
2383			*  AND there's either no parent, or the parent
2384			*  element is in no namespace; this means there's no
2385			*  default namespace is scope to care about.
2386			*
2387			* REVISIT: This might result in massive
2388			*  generation of ns-decls if nodes in a default
2389			*  namespaces are mixed with nodes in no namespace.
2390			*
2391			*/
2392			if (copy->nsDef ||
2393			    ((insert != NULL) &&
2394			     (insert->type == XML_ELEMENT_NODE) &&
2395			     (insert->ns != NULL)))
2396			{
2397			    xsltGetSpecialNamespace(ctxt, cur,
2398				NULL, NULL, copy);
2399			}
2400		    }
2401		}
2402		/*
2403		* SPEC XSLT 2.0 "Each attribute of the literal result
2404		*  element, other than an attribute in the XSLT namespace,
2405		*  is processed to produce an attribute for the element in
2406		*  the result tree."
2407		* NOTE: See bug #341325.
2408		*/
2409		if (cur->properties != NULL) {
2410		    xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2411		}
2412	    } else if (IS_XSLT_ELEM_FAST(cur)) {
2413		/*
2414		* XSLT instructions
2415		* --------------------------------------------------------
2416		*/
2417		if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) {
2418		    /*
2419		    * We hit an unknown XSLT element.
2420		    * Try to apply one of the fallback cases.
2421		    */
2422		    ctxt->insert = insert;
2423		    if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2424			xsltTransformError(ctxt, NULL, cur,
2425			    "The is no fallback behaviour defined for "
2426			    "the unknown XSLT element '%s'.\n",
2427			    cur->name);
2428		    }
2429		    ctxt->insert = oldInsert;
2430		} else if (info->func != NULL) {
2431		    /*
2432		    * Execute the XSLT instruction.
2433		    */
2434		    ctxt->insert = insert;
2435
2436		    info->func(ctxt, contextNode, cur,
2437			(xsltElemPreCompPtr) info);
2438
2439		    /*
2440		    * Cleanup temporary tree fragments.
2441		    */
2442		    if (oldLocalFragmentTop != ctxt->localRVT)
2443			xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2444
2445		    ctxt->insert = oldInsert;
2446		} else if (info->type == XSLT_FUNC_VARIABLE) {
2447		    xsltStackElemPtr tmpvar = ctxt->vars;
2448
2449		    xsltParseStylesheetVariable(ctxt, cur);
2450
2451		    if (tmpvar != ctxt->vars) {
2452			/*
2453			* TODO: Using a @tmpvar is an annoying workaround, but
2454			*  the current mechanisms do not provide any other way
2455			*  of knowing if the var was really pushed onto the
2456			*  stack.
2457			*/
2458			ctxt->vars->level = level;
2459		    }
2460		} else if (info->type == XSLT_FUNC_MESSAGE) {
2461		    /*
2462		    * TODO: Won't be hit, since we don't compile xsl:message.
2463		    */
2464		    xsltMessage(ctxt, contextNode, cur);
2465		} else {
2466		    xsltTransformError(ctxt, NULL, cur,
2467			"Unexpected XSLT element '%s'.\n", cur->name);
2468		}
2469		goto skip_children;
2470
2471	    } else {
2472		xsltTransformFunction func;
2473		/*
2474		* Extension intructions (elements)
2475		* --------------------------------------------------------
2476		*/
2477		if (cur->psvi == xsltExtMarker) {
2478		    /*
2479		    * The xsltExtMarker was set during the compilation
2480		    * of extension instructions if there was no registered
2481		    * handler for this specific extension function at
2482		    * compile-time.
2483		    * Libxslt will now lookup if a handler is
2484		    * registered in the context of this transformation.
2485		    */
2486		    func = (xsltTransformFunction)
2487			xsltExtElementLookup(ctxt, cur->name, cur->ns->href);
2488		} else
2489		    func = ((xsltElemPreCompPtr) cur->psvi)->func;
2490
2491		if (func == NULL) {
2492		    /*
2493		    * No handler available.
2494		    * Try to execute fallback behaviour via xsl:fallback.
2495		    */
2496#ifdef WITH_XSLT_DEBUG_PROCESS
2497		    XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2498			xsltGenericDebug(xsltGenericDebugContext,
2499			    "xsltApplySequenceConstructor: unknown extension %s\n",
2500			    cur->name));
2501#endif
2502		    ctxt->insert = insert;
2503		    if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2504			xsltTransformError(ctxt, NULL, cur,
2505			    "Unknown extension instruction '{%s}%s'.\n",
2506			    cur->ns->href, cur->name);
2507		    }
2508		    ctxt->insert = oldInsert;
2509		} else {
2510		    /*
2511		    * Execute the handler-callback.
2512		    */
2513#ifdef WITH_XSLT_DEBUG_PROCESS
2514		    XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2515			"xsltApplySequenceConstructor: extension construct %s\n",
2516			cur->name));
2517#endif
2518		    ctxt->insert = insert;
2519		    /*
2520		    * We need the fragment base for extension instructions
2521		    * which return values (like EXSLT's function).
2522		    */
2523		    oldLocalFragmentBase = ctxt->localRVTBase;
2524		    ctxt->localRVTBase = NULL;
2525
2526		    func(ctxt, contextNode, cur, cur->psvi);
2527
2528		    ctxt->localRVTBase = oldLocalFragmentBase;
2529		    /*
2530		    * Cleanup temporary tree fragments.
2531		    */
2532		    if (oldLocalFragmentTop != ctxt->localRVT)
2533			xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2534
2535		    ctxt->insert = oldInsert;
2536		}
2537		goto skip_children;
2538	    }
2539
2540	} else if (XSLT_IS_TEXT_NODE(cur)) {
2541	    /*
2542	    * Text
2543	    * ------------------------------------------------------------
2544	    */
2545#ifdef WITH_XSLT_DEBUG_PROCESS
2546            if (cur->name == xmlStringTextNoenc) {
2547                XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2548		    xsltGenericDebug(xsltGenericDebugContext,
2549		    "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
2550		    cur->content));
2551            } else {
2552                XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
2553		    xsltGenericDebug(xsltGenericDebugContext,
2554		    "xsltApplySequenceConstructor: copy text '%s'\n",
2555		    cur->content));
2556            }
2557#endif
2558            if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2559		goto error;
2560	}
2561
2562#else /* XSLT_REFACTORED */
2563
2564        if (IS_XSLT_ELEM(cur)) {
2565            /*
2566             * This is an XSLT node
2567             */
2568            xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi;
2569
2570            if (info == NULL) {
2571                if (IS_XSLT_NAME(cur, "message")) {
2572                    xsltMessage(ctxt, contextNode, cur);
2573                } else {
2574                    /*
2575                     * That's an error try to apply one of the fallback cases
2576                     */
2577                    ctxt->insert = insert;
2578                    if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
2579                        xsltGenericError(xsltGenericErrorContext,
2580			    "xsltApplySequenceConstructor: %s was not compiled\n",
2581			    cur->name);
2582                    }
2583                    ctxt->insert = oldInsert;
2584                }
2585                goto skip_children;
2586            }
2587
2588            if (info->func != NULL) {
2589		oldCurInst = ctxt->inst;
2590		ctxt->inst = cur;
2591                ctxt->insert = insert;
2592		oldLocalFragmentBase = ctxt->localRVTBase;
2593		ctxt->localRVTBase = NULL;
2594
2595                info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info);
2596
2597		ctxt->localRVTBase = oldLocalFragmentBase;
2598		/*
2599		* Cleanup temporary tree fragments.
2600		*/
2601		if (oldLocalFragmentTop != ctxt->localRVT)
2602		    xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2603
2604                ctxt->insert = oldInsert;
2605		ctxt->inst = oldCurInst;
2606                goto skip_children;
2607            }
2608
2609            if (IS_XSLT_NAME(cur, "variable")) {
2610		xsltStackElemPtr tmpvar = ctxt->vars;
2611
2612		oldCurInst = ctxt->inst;
2613		ctxt->inst = cur;
2614
2615		xsltParseStylesheetVariable(ctxt, cur);
2616
2617		ctxt->inst = oldCurInst;
2618
2619		if (tmpvar != ctxt->vars) {
2620		    /*
2621		    * TODO: Using a @tmpvar is an annoying workaround, but
2622		    *  the current mechanisms do not provide any other way
2623		    *  of knowing if the var was really pushed onto the
2624		    *  stack.
2625		    */
2626		    ctxt->vars->level = level;
2627		}
2628            } else if (IS_XSLT_NAME(cur, "message")) {
2629                xsltMessage(ctxt, contextNode, cur);
2630            } else {
2631		xsltTransformError(ctxt, NULL, cur,
2632		    "Unexpected XSLT element '%s'.\n", cur->name);
2633            }
2634            goto skip_children;
2635        } else if ((cur->type == XML_TEXT_NODE) ||
2636                   (cur->type == XML_CDATA_SECTION_NODE)) {
2637
2638            /*
2639             * This text comes from the stylesheet
2640             * For stylesheets, the set of whitespace-preserving
2641             * element names consists of just xsl:text.
2642             */
2643#ifdef WITH_XSLT_DEBUG_PROCESS
2644            if (cur->type == XML_CDATA_SECTION_NODE) {
2645                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2646                                 "xsltApplySequenceConstructor: copy CDATA text %s\n",
2647                                 cur->content));
2648            } else if (cur->name == xmlStringTextNoenc) {
2649                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2650                                 "xsltApplySequenceConstructor: copy unescaped text %s\n",
2651                                 cur->content));
2652            } else {
2653                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2654                                 "xsltApplySequenceConstructor: copy text %s\n",
2655                                 cur->content));
2656            }
2657#endif
2658            if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
2659		goto error;
2660        } else if ((cur->type == XML_ELEMENT_NODE) &&
2661                   (cur->ns != NULL) && (cur->psvi != NULL)) {
2662            xsltTransformFunction function;
2663
2664	    oldCurInst = ctxt->inst;
2665	    ctxt->inst = cur;
2666            /*
2667             * Flagged as an extension element
2668             */
2669            if (cur->psvi == xsltExtMarker)
2670                function = (xsltTransformFunction)
2671                    xsltExtElementLookup(ctxt, cur->name, cur->ns->href);
2672            else
2673                function = ((xsltElemPreCompPtr) cur->psvi)->func;
2674
2675            if (function == NULL) {
2676                xmlNodePtr child;
2677                int found = 0;
2678
2679#ifdef WITH_XSLT_DEBUG_PROCESS
2680                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2681		    "xsltApplySequenceConstructor: unknown extension %s\n",
2682                    cur->name));
2683#endif
2684                /*
2685                 * Search if there are fallbacks
2686                 */
2687                child = cur->children;
2688                while (child != NULL) {
2689                    if ((IS_XSLT_ELEM(child)) &&
2690                        (IS_XSLT_NAME(child, "fallback")))
2691		    {
2692                        found = 1;
2693                        xsltApplySequenceConstructor(ctxt, contextNode,
2694			    child->children, NULL);
2695                    }
2696                    child = child->next;
2697                }
2698
2699                if (!found) {
2700                    xsltTransformError(ctxt, NULL, cur,
2701			"xsltApplySequenceConstructor: failed to find extension %s\n",
2702			cur->name);
2703                }
2704            } else {
2705#ifdef WITH_XSLT_DEBUG_PROCESS
2706                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2707		    "xsltApplySequenceConstructor: extension construct %s\n",
2708                    cur->name));
2709#endif
2710
2711                ctxt->insert = insert;
2712		/*
2713		* We need the fragment base for extension instructions
2714		* which return values (like EXSLT's function).
2715		*/
2716		oldLocalFragmentBase = ctxt->localRVTBase;
2717		ctxt->localRVTBase = NULL;
2718
2719                function(ctxt, contextNode, cur, cur->psvi);
2720		/*
2721		* Cleanup temporary tree fragments.
2722		*/
2723		if (oldLocalFragmentTop != ctxt->localRVT)
2724		    xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
2725
2726		ctxt->localRVTBase = oldLocalFragmentBase;
2727                ctxt->insert = oldInsert;
2728
2729            }
2730	    ctxt->inst = oldCurInst;
2731            goto skip_children;
2732        } else if (cur->type == XML_ELEMENT_NODE) {
2733#ifdef WITH_XSLT_DEBUG_PROCESS
2734            XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2735		"xsltApplySequenceConstructor: copy node %s\n",
2736                cur->name));
2737#endif
2738	    oldCurInst = ctxt->inst;
2739	    ctxt->inst = cur;
2740
2741            if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)
2742		goto error;
2743            /*
2744             * Add extra namespaces inherited from the current template
2745             * if we are in the first level children and this is a
2746	     * "real" template.
2747             */
2748            if ((templ != NULL) && (oldInsert == insert) &&
2749                (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) {
2750                int i;
2751                xmlNsPtr ns, ret;
2752
2753                for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
2754		    const xmlChar *URI = NULL;
2755		    xsltStylesheetPtr style;
2756                    ns = ctxt->templ->inheritedNs[i];
2757
2758		    /* Note that the XSLT namespace was already excluded
2759		    * in xsltGetInheritedNsList().
2760		    */
2761#if 0
2762		    if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2763			continue;
2764#endif
2765		    style = ctxt->style;
2766		    while (style != NULL) {
2767			if (style->nsAliases != NULL)
2768			    URI = (const xmlChar *)
2769				xmlHashLookup(style->nsAliases, ns->href);
2770			if (URI != NULL)
2771			    break;
2772
2773			style = xsltNextImport(style);
2774		    }
2775		    if (URI == UNDEFINED_DEFAULT_NS)
2776			continue;
2777		    if (URI == NULL)
2778			URI = ns->href;
2779		    /*
2780		    * TODO: The following will still be buggy for the
2781		    * non-refactored code.
2782		    */
2783		    ret = xmlSearchNs(copy->doc, copy, ns->prefix);
2784		    if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))
2785		    {
2786			xmlNewNs(copy, URI, ns->prefix);
2787		    }
2788                }
2789		if (copy->ns != NULL) {
2790		    /*
2791		     * Fix the node namespace if needed
2792		     */
2793		    copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);
2794		}
2795            }
2796	    /*
2797             * all the attributes are directly inherited
2798             */
2799            if (cur->properties != NULL) {
2800                xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
2801            }
2802	    ctxt->inst = oldCurInst;
2803        }
2804#endif /* else of XSLT_REFACTORED */
2805
2806        /*
2807         * Descend into content in document order.
2808         */
2809        if (cur->children != NULL) {
2810            if (cur->children->type != XML_ENTITY_DECL) {
2811                cur = cur->children;
2812		level++;
2813                if (copy != NULL)
2814                    insert = copy;
2815                continue;
2816            }
2817        }
2818
2819skip_children:
2820	/*
2821	* If xslt:message was just processed, we might have hit a
2822	* terminate='yes'; if so, then break the loop and clean up.
2823	* TODO: Do we need to check this also before trying to descend
2824	*  into the content?
2825	*/
2826	if (ctxt->state == XSLT_STATE_STOPPED)
2827	    break;
2828        if (cur->next != NULL) {
2829            cur = cur->next;
2830            continue;
2831        }
2832
2833        do {
2834            cur = cur->parent;
2835	    level--;
2836	    /*
2837	    * Pop variables/params (xsl:variable and xsl:param).
2838	    */
2839	    if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) {
2840		xsltLocalVariablePop(ctxt, oldVarsNr, level);
2841	    }
2842
2843            insert = insert->parent;
2844            if (cur == NULL)
2845                break;
2846            if (cur == list->parent) {
2847                cur = NULL;
2848                break;
2849            }
2850            if (cur->next != NULL) {
2851                cur = cur->next;
2852                break;
2853            }
2854        } while (cur != NULL);
2855    }
2856
2857error:
2858    /*
2859    * In case of errors: pop remaining variables.
2860    */
2861    if (ctxt->varsNr > oldVarsNr)
2862	xsltLocalVariablePop(ctxt, oldVarsNr, -1);
2863
2864    ctxt->node = oldContextNode;
2865    ctxt->inst = oldInst;
2866    ctxt->insert = oldInsert;
2867
2868#ifdef WITH_DEBUGGER
2869    if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
2870        xslDropCall();
2871    }
2872#endif
2873}
2874
2875/*
2876* xsltApplyXSLTTemplate:
2877* @ctxt:  a XSLT transformation context
2878* @contextNode:  the node in the source tree.
2879* @list:  the nodes of a sequence constructor;
2880*         (plus leading xsl:param elements)
2881* @templ: the compiled xsl:template declaration;
2882*         NULL if a sequence constructor
2883* @withParams:  a set of caller-parameters (xsl:with-param) or NULL
2884*
2885* Called by:
2886* - xsltApplyImports()
2887* - xsltCallTemplate()
2888* - xsltDefaultProcessOneNode()
2889* - xsltProcessOneNode()
2890*/
2891static void
2892xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
2893		      xmlNodePtr contextNode,
2894		      xmlNodePtr list,
2895		      xsltTemplatePtr templ,
2896		      xsltStackElemPtr withParams)
2897{
2898    int oldVarsBase = 0;
2899    long start = 0;
2900    xmlNodePtr cur;
2901    xsltStackElemPtr tmpParam = NULL;
2902    xmlDocPtr oldUserFragmentTop, oldLocalFragmentTop;
2903
2904#ifdef XSLT_REFACTORED
2905    xsltStyleItemParamPtr iparam;
2906#else
2907    xsltStylePreCompPtr iparam;
2908#endif
2909
2910#ifdef WITH_DEBUGGER
2911    int addCallResult = 0;
2912#endif
2913
2914    if (ctxt == NULL)
2915	return;
2916    if (templ == NULL) {
2917	xsltTransformError(ctxt, NULL, list,
2918	    "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
2919	return;
2920    }
2921
2922#ifdef WITH_DEBUGGER
2923    if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
2924	if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
2925		list, templ, &addCallResult) == NULL)
2926	    return;
2927    }
2928#endif
2929
2930    if (list == NULL)
2931        return;
2932    CHECK_STOPPED;
2933
2934    /*
2935    * Check for infinite recursion: stop if the maximum of nested templates
2936    * is excceeded. Adjust xsltMaxDepth if you need more.
2937    */
2938    if (((ctxt->templNr >= xsltMaxDepth) ||
2939        (ctxt->varsNr >= 5 * xsltMaxDepth)))
2940    {
2941        xsltTransformError(ctxt, NULL, list,
2942	    "xsltApplyXSLTTemplate: A potential infinite template recursion "
2943	    "was detected.\n"
2944	    "You can adjust xsltMaxDepth (--maxdepth) in order to "
2945	    "raise the maximum number of nested template calls and "
2946	    "variables/params (currently set to %d).\n",
2947	    xsltMaxDepth);
2948        xsltDebug(ctxt, contextNode, list, NULL);
2949        return;
2950    }
2951
2952    oldUserFragmentTop = ctxt->tmpRVT;
2953    ctxt->tmpRVT = NULL;
2954    oldLocalFragmentTop = ctxt->localRVT;
2955
2956    /*
2957    * Initiate a distinct scope of local params/variables.
2958    */
2959    oldVarsBase = ctxt->varsBase;
2960    ctxt->varsBase = ctxt->varsNr;
2961
2962    ctxt->node = contextNode;
2963    if (ctxt->profile) {
2964	templ->nbCalls++;
2965	start = xsltTimestamp();
2966	profPush(ctxt, 0);
2967    }
2968    /*
2969    * Push the xsl:template declaration onto the stack.
2970    */
2971    templPush(ctxt, templ);
2972
2973#ifdef WITH_XSLT_DEBUG_PROCESS
2974    if (templ->name != NULL)
2975	XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
2976	"applying xsl:template '%s'\n", templ->name));
2977#endif
2978    /*
2979    * Process xsl:param instructions and skip those elements for
2980    * further processing.
2981    */
2982    cur = list;
2983    do {
2984	if (cur->type == XML_TEXT_NODE) {
2985	    cur = cur->next;
2986	    continue;
2987	}
2988	if ((cur->type != XML_ELEMENT_NODE) ||
2989	    (cur->name[0] != 'p') ||
2990	    (cur->psvi == NULL) ||
2991	    (! xmlStrEqual(cur->name, BAD_CAST "param")) ||
2992	    (! IS_XSLT_ELEM(cur)))
2993	{
2994	    break;
2995	}
2996
2997	list = cur->next;
2998
2999#ifdef XSLT_REFACTORED
3000	iparam = (xsltStyleItemParamPtr) cur->psvi;
3001#else
3002	iparam = (xsltStylePreCompPtr) cur->psvi;
3003#endif
3004
3005	/*
3006	* Substitute xsl:param for a given xsl:with-param.
3007	* Since the XPath expression will reference the params/vars
3008	* by index, we need to slot the xsl:with-params in the
3009	* order of encountered xsl:params to keep the sequence of
3010	* params/variables in the stack exactly as it was at
3011	* compile time,
3012	*/
3013	tmpParam = NULL;
3014	if (withParams) {
3015	    tmpParam = withParams;
3016	    do {
3017		if ((tmpParam->name == (iparam->name)) &&
3018		    (tmpParam->nameURI == (iparam->ns)))
3019		{
3020		    /*
3021		    * Push the caller-parameter.
3022		    */
3023		    xsltLocalVariablePush(ctxt, tmpParam, -1);
3024		    break;
3025		}
3026		tmpParam = tmpParam->next;
3027	    } while (tmpParam != NULL);
3028	}
3029	/*
3030	* Push the xsl:param.
3031	*/
3032	if (tmpParam == NULL) {
3033	    /*
3034	    * Note that we must assume that the added parameter
3035	    * has a @depth of 0.
3036	    */
3037	    xsltParseStylesheetParam(ctxt, cur);
3038	}
3039	cur = cur->next;
3040    } while (cur != NULL);
3041    /*
3042    * Process the sequence constructor.
3043    */
3044    xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3045
3046    /*
3047    * Remove remaining xsl:param and xsl:with-param items from
3048    * the stack. Don't free xsl:with-param items.
3049    */
3050    if (ctxt->varsNr > ctxt->varsBase)
3051	xsltTemplateParamsCleanup(ctxt);
3052    ctxt->varsBase = oldVarsBase;
3053
3054    /*
3055    * Clean up remaining local tree fragments.
3056    * This also frees fragments which are the result of
3057    * extension instructions. Should normally not be hit; but
3058    * just for the case xsltExtensionInstructionResultFinalize()
3059    * was not called by the extension author.
3060    */
3061    if (oldLocalFragmentTop != ctxt->localRVT) {
3062	xmlDocPtr curdoc = ctxt->localRVT, tmp;
3063
3064	do {
3065	    tmp = curdoc;
3066	    curdoc = (xmlDocPtr) curdoc->next;
3067	    /* Need to housekeep localRVTBase */
3068	    if (tmp == ctxt->localRVTBase)
3069	        ctxt->localRVTBase = curdoc;
3070	    if (tmp->prev)
3071		tmp->prev->next = (xmlNodePtr) curdoc;
3072	    if (curdoc)
3073		curdoc->prev = tmp->prev;
3074	    xsltReleaseRVT(ctxt, tmp);
3075	} while (curdoc != oldLocalFragmentTop);
3076    }
3077    ctxt->localRVT = oldLocalFragmentTop;
3078
3079    /*
3080    * Release user-created fragments stored in the scope
3081    * of xsl:template. Note that this mechanism is deprecated:
3082    * user code should now use xsltRegisterLocalRVT() instead
3083    * of the obsolete xsltRegisterTmpRVT().
3084    */
3085    if (ctxt->tmpRVT) {
3086	xmlDocPtr curdoc = ctxt->tmpRVT, tmp;
3087
3088	while (curdoc != NULL) {
3089	    tmp = curdoc;
3090	    curdoc = (xmlDocPtr) curdoc->next;
3091	    xsltReleaseRVT(ctxt, tmp);
3092	}
3093    }
3094    ctxt->tmpRVT = oldUserFragmentTop;
3095
3096    /*
3097    * Pop the xsl:template declaration from the stack.
3098    */
3099    templPop(ctxt);
3100    if (ctxt->profile) {
3101	long spent, child, total, end;
3102
3103	end = xsltTimestamp();
3104	child = profPop(ctxt);
3105	total = end - start;
3106	spent = total - child;
3107	if (spent <= 0) {
3108	    /*
3109	    * Not possible unless the original calibration failed
3110	    * we can try to correct it on the fly.
3111	    */
3112	    xsltCalibrateAdjust(spent);
3113	    spent = 0;
3114	}
3115
3116	templ->time += spent;
3117	if (ctxt->profNr > 0)
3118	    ctxt->profTab[ctxt->profNr - 1] += total;
3119    }
3120
3121#ifdef WITH_DEBUGGER
3122    if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
3123        xslDropCall();
3124    }
3125#endif
3126}
3127
3128
3129/**
3130 * xsltApplyOneTemplate:
3131 * @ctxt:  a XSLT process context
3132 * @contextNode:  the node in the source tree.
3133 * @list:  the nodes of a sequence constructor
3134 * @templ: not used
3135 * @params:  a set of parameters (xsl:param) or NULL
3136 *
3137 * Processes a sequence constructor on the current node in the source tree.
3138 *
3139 * @params are the already computed variable stack items; this function
3140 * pushes them on the variable stack, and pops them before exiting; it's
3141 * left to the caller to free or reuse @params afterwards. The initial
3142 * states of the variable stack will always be restored before this
3143 * function exits.
3144 * NOTE that this does *not* initiate a new distinct variable scope; i.e.
3145 * variables already on the stack are visible to the process. The caller's
3146 * side needs to start a new variable scope if needed (e.g. in exsl:function).
3147 *
3148 * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
3149 * provide a @templ); a non-NULL @templ might raise an error in the future.
3150 *
3151 * BIG NOTE: This function is not intended to process the content of an
3152 * xsl:template; it does not expect xsl:param instructions in @list and
3153 * will report errors if found.
3154 *
3155 * Called by:
3156 *  - xsltEvalVariable() (variables.c)
3157 *  - exsltFuncFunctionFunction() (libexsl/functions.c)
3158 */
3159void
3160xsltApplyOneTemplate(xsltTransformContextPtr ctxt,
3161		     xmlNodePtr contextNode,
3162                     xmlNodePtr list,
3163		     xsltTemplatePtr templ ATTRIBUTE_UNUSED,
3164                     xsltStackElemPtr params)
3165{
3166    if ((ctxt == NULL) || (list == NULL))
3167	return;
3168    CHECK_STOPPED;
3169
3170    if (params) {
3171	/*
3172	 * This code should be obsolete - was previously used
3173	 * by libexslt/functions.c, but due to bug 381319 the
3174	 * logic there was changed.
3175	 */
3176	int oldVarsNr = ctxt->varsNr;
3177
3178	/*
3179	* Push the given xsl:param(s) onto the variable stack.
3180	*/
3181	while (params != NULL) {
3182	    xsltLocalVariablePush(ctxt, params, -1);
3183	    params = params->next;
3184	}
3185	xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3186	/*
3187	* Pop the given xsl:param(s) from the stack but don't free them.
3188	*/
3189	xsltLocalVariablePop(ctxt, oldVarsNr, -2);
3190    } else
3191	xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
3192}
3193
3194/************************************************************************
3195 *									*
3196 *		    XSLT-1.1 extensions					*
3197 *									*
3198 ************************************************************************/
3199
3200/**
3201 * xsltDocumentElem:
3202 * @ctxt:  an XSLT processing context
3203 * @node:  The current node
3204 * @inst:  the instruction in the stylesheet
3205 * @castedComp:  precomputed information
3206 *
3207 * Process an EXSLT/XSLT-1.1 document element
3208 */
3209void
3210xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
3211                 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
3212{
3213#ifdef XSLT_REFACTORED
3214    xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp;
3215#else
3216    xsltStylePreCompPtr comp = castedComp;
3217#endif
3218    xsltStylesheetPtr style = NULL;
3219    int ret;
3220    xmlChar *filename = NULL, *prop, *elements;
3221    xmlChar *element, *end;
3222    xmlDocPtr res = NULL;
3223    xmlDocPtr oldOutput;
3224    xmlNodePtr oldInsert, root;
3225    const char *oldOutputFile;
3226    xsltOutputType oldType;
3227    xmlChar *URL = NULL;
3228    const xmlChar *method;
3229    const xmlChar *doctypePublic;
3230    const xmlChar *doctypeSystem;
3231    const xmlChar *version;
3232    const xmlChar *encoding;
3233
3234    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
3235        return;
3236
3237    if (comp->filename == NULL) {
3238
3239        if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
3240	    /*
3241	    * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
3242	    *   (http://icl.com/saxon)
3243	    * The @file is in no namespace.
3244	    */
3245#ifdef WITH_XSLT_DEBUG_EXTRA
3246            xsltGenericDebug(xsltGenericDebugContext,
3247                             "Found saxon:output extension\n");
3248#endif
3249            URL = xsltEvalAttrValueTemplate(ctxt, inst,
3250                                                 (const xmlChar *) "file",
3251                                                 XSLT_SAXON_NAMESPACE);
3252
3253	    if (URL == NULL)
3254		URL = xsltEvalAttrValueTemplate(ctxt, inst,
3255                                                 (const xmlChar *) "href",
3256                                                 XSLT_SAXON_NAMESPACE);
3257        } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
3258#ifdef WITH_XSLT_DEBUG_EXTRA
3259            xsltGenericDebug(xsltGenericDebugContext,
3260                             "Found xalan:write extension\n");
3261#endif
3262            URL = xsltEvalAttrValueTemplate(ctxt, inst,
3263                                                 (const xmlChar *)
3264                                                 "select",
3265                                                 XSLT_XALAN_NAMESPACE);
3266	    if (URL != NULL) {
3267		xmlXPathCompExprPtr cmp;
3268		xmlChar *val;
3269
3270		/*
3271		 * Trying to handle bug #59212
3272		 * The value of the "select" attribute is an
3273		 * XPath expression.
3274		 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
3275		 */
3276		cmp = xmlXPathCompile(URL);
3277                val = xsltEvalXPathString(ctxt, cmp);
3278		xmlXPathFreeCompExpr(cmp);
3279		xmlFree(URL);
3280		URL = val;
3281	    }
3282	    if (URL == NULL)
3283		URL = xsltEvalAttrValueTemplate(ctxt, inst,
3284						     (const xmlChar *)
3285						     "file",
3286						     XSLT_XALAN_NAMESPACE);
3287	    if (URL == NULL)
3288		URL = xsltEvalAttrValueTemplate(ctxt, inst,
3289						     (const xmlChar *)
3290						     "href",
3291						     XSLT_XALAN_NAMESPACE);
3292        } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
3293            URL = xsltEvalAttrValueTemplate(ctxt, inst,
3294                                                 (const xmlChar *) "href",
3295                                                 NULL);
3296        }
3297
3298    } else {
3299        URL = xmlStrdup(comp->filename);
3300    }
3301
3302    if (URL == NULL) {
3303	xsltTransformError(ctxt, NULL, inst,
3304		         "xsltDocumentElem: href/URI-Reference not found\n");
3305	return;
3306    }
3307
3308    /*
3309     * If the computation failed, it's likely that the URL wasn't escaped
3310     */
3311    filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile);
3312    if (filename == NULL) {
3313	xmlChar *escURL;
3314
3315	escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,");
3316	if (escURL != NULL) {
3317	    filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile);
3318	    xmlFree(escURL);
3319	}
3320    }
3321
3322    if (filename == NULL) {
3323	xsltTransformError(ctxt, NULL, inst,
3324		         "xsltDocumentElem: URL computation failed for %s\n",
3325			 URL);
3326	xmlFree(URL);
3327	return;
3328    }
3329
3330    /*
3331     * Security checking: can we write to this resource
3332     */
3333    if (ctxt->sec != NULL) {
3334	ret = xsltCheckWrite(ctxt->sec, ctxt, filename);
3335	if (ret == 0) {
3336	    xsltTransformError(ctxt, NULL, inst,
3337		 "xsltDocumentElem: write rights for %s denied\n",
3338			     filename);
3339	    xmlFree(URL);
3340	    xmlFree(filename);
3341	    return;
3342	}
3343    }
3344
3345    oldOutputFile = ctxt->outputFile;
3346    oldOutput = ctxt->output;
3347    oldInsert = ctxt->insert;
3348    oldType = ctxt->type;
3349    ctxt->outputFile = (const char *) filename;
3350
3351    style = xsltNewStylesheet();
3352    if (style == NULL) {
3353	xsltTransformError(ctxt, NULL, inst,
3354                         "xsltDocumentElem: out of memory\n");
3355        goto error;
3356    }
3357
3358    /*
3359     * Version described in 1.1 draft allows full parameterization
3360     * of the output.
3361     */
3362    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3363				     (const xmlChar *) "version",
3364				     NULL);
3365    if (prop != NULL) {
3366	if (style->version != NULL)
3367	    xmlFree(style->version);
3368	style->version = prop;
3369    }
3370    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3371				     (const xmlChar *) "encoding",
3372				     NULL);
3373    if (prop != NULL) {
3374	if (style->encoding != NULL)
3375	    xmlFree(style->encoding);
3376	style->encoding = prop;
3377    }
3378    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3379				     (const xmlChar *) "method",
3380				     NULL);
3381    if (prop != NULL) {
3382	const xmlChar *URI;
3383
3384	if (style->method != NULL)
3385	    xmlFree(style->method);
3386	style->method = NULL;
3387	if (style->methodURI != NULL)
3388	    xmlFree(style->methodURI);
3389	style->methodURI = NULL;
3390
3391	URI = xsltGetQNameURI(inst, &prop);
3392	if (prop == NULL) {
3393	    if (style != NULL) style->errors++;
3394	} else if (URI == NULL) {
3395	    if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
3396		(xmlStrEqual(prop, (const xmlChar *) "html")) ||
3397		(xmlStrEqual(prop, (const xmlChar *) "text"))) {
3398		style->method = prop;
3399	    } else {
3400		xsltTransformError(ctxt, NULL, inst,
3401				 "invalid value for method: %s\n", prop);
3402		if (style != NULL) style->warnings++;
3403	    }
3404	} else {
3405	    style->method = prop;
3406	    style->methodURI = xmlStrdup(URI);
3407	}
3408    }
3409    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3410				     (const xmlChar *)
3411				     "doctype-system", NULL);
3412    if (prop != NULL) {
3413	if (style->doctypeSystem != NULL)
3414	    xmlFree(style->doctypeSystem);
3415	style->doctypeSystem = prop;
3416    }
3417    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3418				     (const xmlChar *)
3419				     "doctype-public", NULL);
3420    if (prop != NULL) {
3421	if (style->doctypePublic != NULL)
3422	    xmlFree(style->doctypePublic);
3423	style->doctypePublic = prop;
3424    }
3425    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3426				     (const xmlChar *) "standalone",
3427				     NULL);
3428    if (prop != NULL) {
3429	if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3430	    style->standalone = 1;
3431	} else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3432	    style->standalone = 0;
3433	} else {
3434	    xsltTransformError(ctxt, NULL, inst,
3435			     "invalid value for standalone: %s\n",
3436			     prop);
3437	    if (style != NULL) style->warnings++;
3438	}
3439	xmlFree(prop);
3440    }
3441
3442    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3443				     (const xmlChar *) "indent",
3444				     NULL);
3445    if (prop != NULL) {
3446	if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3447	    style->indent = 1;
3448	} else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3449	    style->indent = 0;
3450	} else {
3451	    xsltTransformError(ctxt, NULL, inst,
3452			     "invalid value for indent: %s\n", prop);
3453	    if (style != NULL) style->warnings++;
3454	}
3455	xmlFree(prop);
3456    }
3457
3458    prop = xsltEvalAttrValueTemplate(ctxt, inst,
3459				     (const xmlChar *)
3460				     "omit-xml-declaration",
3461				     NULL);
3462    if (prop != NULL) {
3463	if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3464	    style->omitXmlDeclaration = 1;
3465	} else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3466	    style->omitXmlDeclaration = 0;
3467	} else {
3468	    xsltTransformError(ctxt, NULL, inst,
3469			     "invalid value for omit-xml-declaration: %s\n",
3470			     prop);
3471	    if (style != NULL) style->warnings++;
3472	}
3473	xmlFree(prop);
3474    }
3475
3476    elements = xsltEvalAttrValueTemplate(ctxt, inst,
3477					 (const xmlChar *)
3478					 "cdata-section-elements",
3479					 NULL);
3480    if (elements != NULL) {
3481	if (style->stripSpaces == NULL)
3482	    style->stripSpaces = xmlHashCreate(10);
3483	if (style->stripSpaces == NULL)
3484	    return;
3485
3486	element = elements;
3487	while (*element != 0) {
3488	    while (IS_BLANK_CH(*element))
3489		element++;
3490	    if (*element == 0)
3491		break;
3492	    end = element;
3493	    while ((*end != 0) && (!IS_BLANK_CH(*end)))
3494		end++;
3495	    element = xmlStrndup(element, end - element);
3496	    if (element) {
3497		const xmlChar *URI;
3498
3499#ifdef WITH_XSLT_DEBUG_PARSING
3500		xsltGenericDebug(xsltGenericDebugContext,
3501				 "add cdata section output element %s\n",
3502				 element);
3503#endif
3504                URI = xsltGetQNameURI(inst, &element);
3505
3506		xmlHashAddEntry2(style->stripSpaces, element, URI,
3507			        (xmlChar *) "cdata");
3508		xmlFree(element);
3509	    }
3510	    element = end;
3511	}
3512	xmlFree(elements);
3513    }
3514
3515    /*
3516     * Create a new document tree and process the element template
3517     */
3518    XSLT_GET_IMPORT_PTR(method, style, method)
3519    XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3520    XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3521    XSLT_GET_IMPORT_PTR(version, style, version)
3522    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
3523
3524    if ((method != NULL) &&
3525	(!xmlStrEqual(method, (const xmlChar *) "xml"))) {
3526	if (xmlStrEqual(method, (const xmlChar *) "html")) {
3527	    ctxt->type = XSLT_OUTPUT_HTML;
3528	    if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3529		res = htmlNewDoc(doctypeSystem, doctypePublic);
3530	    else {
3531		if (version != NULL) {
3532#ifdef XSLT_GENERATE_HTML_DOCTYPE
3533		    xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
3534#endif
3535                }
3536		res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3537	    }
3538	    if (res == NULL)
3539		goto error;
3540	    res->dict = ctxt->dict;
3541	    xmlDictReference(res->dict);
3542	} else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
3543	    xsltTransformError(ctxt, NULL, inst,
3544	     "xsltDocumentElem: unsupported method xhtml\n",
3545		             style->method);
3546	    ctxt->type = XSLT_OUTPUT_HTML;
3547	    res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3548	    if (res == NULL)
3549		goto error;
3550	    res->dict = ctxt->dict;
3551	    xmlDictReference(res->dict);
3552	} else if (xmlStrEqual(method, (const xmlChar *) "text")) {
3553	    ctxt->type = XSLT_OUTPUT_TEXT;
3554	    res = xmlNewDoc(style->version);
3555	    if (res == NULL)
3556		goto error;
3557	    res->dict = ctxt->dict;
3558	    xmlDictReference(res->dict);
3559#ifdef WITH_XSLT_DEBUG
3560	    xsltGenericDebug(xsltGenericDebugContext,
3561                     "reusing transformation dict for output\n");
3562#endif
3563	} else {
3564	    xsltTransformError(ctxt, NULL, inst,
3565			     "xsltDocumentElem: unsupported method %s\n",
3566		             style->method);
3567	    goto error;
3568	}
3569    } else {
3570	ctxt->type = XSLT_OUTPUT_XML;
3571	res = xmlNewDoc(style->version);
3572	if (res == NULL)
3573	    goto error;
3574	res->dict = ctxt->dict;
3575	xmlDictReference(res->dict);
3576#ifdef WITH_XSLT_DEBUG
3577	xsltGenericDebug(xsltGenericDebugContext,
3578                     "reusing transformation dict for output\n");
3579#endif
3580    }
3581    res->charset = XML_CHAR_ENCODING_UTF8;
3582    if (encoding != NULL)
3583	res->encoding = xmlStrdup(encoding);
3584    ctxt->output = res;
3585    ctxt->insert = (xmlNodePtr) res;
3586    xsltApplySequenceConstructor(ctxt, node, inst->children, NULL);
3587
3588    /*
3589     * Do some post processing work depending on the generated output
3590     */
3591    root = xmlDocGetRootElement(res);
3592    if (root != NULL) {
3593        const xmlChar *doctype = NULL;
3594
3595        if ((root->ns != NULL) && (root->ns->prefix != NULL))
3596	    doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
3597	if (doctype == NULL)
3598	    doctype = root->name;
3599
3600        /*
3601         * Apply the default selection of the method
3602         */
3603        if ((method == NULL) &&
3604            (root->ns == NULL) &&
3605            (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
3606            xmlNodePtr tmp;
3607
3608            tmp = res->children;
3609            while ((tmp != NULL) && (tmp != root)) {
3610                if (tmp->type == XML_ELEMENT_NODE)
3611                    break;
3612                if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
3613                    break;
3614		tmp = tmp->next;
3615            }
3616            if (tmp == root) {
3617                ctxt->type = XSLT_OUTPUT_HTML;
3618                res->type = XML_HTML_DOCUMENT_NODE;
3619                if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
3620                    res->intSubset = xmlCreateIntSubset(res, doctype,
3621                                                        doctypePublic,
3622                                                        doctypeSystem);
3623#ifdef XSLT_GENERATE_HTML_DOCTYPE
3624		} else if (version != NULL) {
3625                    xsltGetHTMLIDs(version, &doctypePublic,
3626                                   &doctypeSystem);
3627                    if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3628                        res->intSubset =
3629                            xmlCreateIntSubset(res, doctype,
3630                                               doctypePublic,
3631                                               doctypeSystem);
3632#endif
3633                }
3634            }
3635
3636        }
3637        if (ctxt->type == XSLT_OUTPUT_XML) {
3638            XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3639                XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3640                if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3641                res->intSubset = xmlCreateIntSubset(res, doctype,
3642                                                    doctypePublic,
3643                                                    doctypeSystem);
3644        }
3645    }
3646
3647    /*
3648     * Save the result
3649     */
3650    ret = xsltSaveResultToFilename((const char *) filename,
3651                                   res, style, 0);
3652    if (ret < 0) {
3653	xsltTransformError(ctxt, NULL, inst,
3654                         "xsltDocumentElem: unable to save to %s\n",
3655                         filename);
3656	ctxt->state = XSLT_STATE_ERROR;
3657#ifdef WITH_XSLT_DEBUG_EXTRA
3658    } else {
3659        xsltGenericDebug(xsltGenericDebugContext,
3660                         "Wrote %d bytes to %s\n", ret, filename);
3661#endif
3662    }
3663
3664  error:
3665    ctxt->output = oldOutput;
3666    ctxt->insert = oldInsert;
3667    ctxt->type = oldType;
3668    ctxt->outputFile = oldOutputFile;
3669    if (URL != NULL)
3670        xmlFree(URL);
3671    if (filename != NULL)
3672        xmlFree(filename);
3673    if (style != NULL)
3674        xsltFreeStylesheet(style);
3675    if (res != NULL)
3676        xmlFreeDoc(res);
3677}
3678
3679/************************************************************************
3680 *									*
3681 *		Most of the XSLT-1.0 transformations			*
3682 *									*
3683 ************************************************************************/
3684
3685/**
3686 * xsltSort:
3687 * @ctxt:  a XSLT process context
3688 * @node:  the node in the source tree.
3689 * @inst:  the xslt sort node
3690 * @comp:  precomputed information
3691 *
3692 * function attached to xsl:sort nodes, but this should not be
3693 * called directly
3694 */
3695void
3696xsltSort(xsltTransformContextPtr ctxt,
3697	xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
3698	xsltStylePreCompPtr comp) {
3699    if (comp == NULL) {
3700	xsltTransformError(ctxt, NULL, inst,
3701	     "xsl:sort : compilation failed\n");
3702	return;
3703    }
3704    xsltTransformError(ctxt, NULL, inst,
3705	 "xsl:sort : improper use this should not be reached\n");
3706}
3707
3708/**
3709 * xsltCopy:
3710 * @ctxt:  an XSLT process context
3711 * @node:  the node in the source tree
3712 * @inst:  the element node of the XSLT-copy instruction
3713 * @castedComp:  computed information of the XSLT-copy instruction
3714 *
3715 * Execute the XSLT-copy instruction on the source node.
3716 */
3717void
3718xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
3719	 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
3720{
3721#ifdef XSLT_REFACTORED
3722    xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;
3723#else
3724    xsltStylePreCompPtr comp = castedComp;
3725#endif
3726    xmlNodePtr copy, oldInsert;
3727
3728    oldInsert = ctxt->insert;
3729    if (ctxt->insert != NULL) {
3730	switch (node->type) {
3731	    case XML_TEXT_NODE:
3732	    case XML_CDATA_SECTION_NODE:
3733		/*
3734		 * This text comes from the stylesheet
3735		 * For stylesheets, the set of whitespace-preserving
3736		 * element names consists of just xsl:text.
3737		 */
3738#ifdef WITH_XSLT_DEBUG_PROCESS
3739		if (node->type == XML_CDATA_SECTION_NODE) {
3740		    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3741			 "xsltCopy: CDATA text %s\n", node->content));
3742		} else {
3743		    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3744			 "xsltCopy: text %s\n", node->content));
3745                }
3746#endif
3747		xsltCopyText(ctxt, ctxt->insert, node, 0);
3748		break;
3749	    case XML_DOCUMENT_NODE:
3750	    case XML_HTML_DOCUMENT_NODE:
3751		break;
3752	    case XML_ELEMENT_NODE:
3753		/*
3754		* REVISIT NOTE: The "fake" is a doc-node, not an element node.
3755		* REMOVED:
3756		*   if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3757		*    return;
3758		*/
3759
3760#ifdef WITH_XSLT_DEBUG_PROCESS
3761		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3762				 "xsltCopy: node %s\n", node->name));
3763#endif
3764		copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);
3765		ctxt->insert = copy;
3766		if (comp->use != NULL) {
3767		    xsltApplyAttributeSet(ctxt, node, inst, comp->use);
3768		}
3769		break;
3770	    case XML_ATTRIBUTE_NODE: {
3771#ifdef WITH_XSLT_DEBUG_PROCESS
3772		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3773				 "xsltCopy: attribute %s\n", node->name));
3774#endif
3775		/*
3776		* REVISIT: We could also raise an error if the parent is not
3777		* an element node.
3778		* OPTIMIZE TODO: Can we set the value/children of the
3779		* attribute without an intermediate copy of the string value?
3780		*/
3781		xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node);
3782		break;
3783	    }
3784	    case XML_PI_NODE:
3785#ifdef WITH_XSLT_DEBUG_PROCESS
3786		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3787				 "xsltCopy: PI %s\n", node->name));
3788#endif
3789		copy = xmlNewDocPI(ctxt->insert->doc, node->name,
3790		                   node->content);
3791		copy = xsltAddChild(ctxt->insert, copy);
3792		break;
3793	    case XML_COMMENT_NODE:
3794#ifdef WITH_XSLT_DEBUG_PROCESS
3795		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3796				 "xsltCopy: comment\n"));
3797#endif
3798		copy = xmlNewComment(node->content);
3799		copy = xsltAddChild(ctxt->insert, copy);
3800		break;
3801	    case XML_NAMESPACE_DECL:
3802#ifdef WITH_XSLT_DEBUG_PROCESS
3803		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3804				 "xsltCopy: namespace declaration\n"));
3805#endif
3806		xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node);
3807		break;
3808	    default:
3809		break;
3810
3811	}
3812    }
3813
3814    switch (node->type) {
3815	case XML_DOCUMENT_NODE:
3816	case XML_HTML_DOCUMENT_NODE:
3817	case XML_ELEMENT_NODE:
3818	    xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
3819		NULL);
3820	    break;
3821	default:
3822	    break;
3823    }
3824    ctxt->insert = oldInsert;
3825}
3826
3827/**
3828 * xsltText:
3829 * @ctxt:  a XSLT process context
3830 * @node:  the node in the source tree.
3831 * @inst:  the xslt text node
3832 * @comp:  precomputed information
3833 *
3834 * Process the xslt text node on the source node
3835 */
3836void
3837xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
3838	    xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
3839    if ((inst->children != NULL) && (comp != NULL)) {
3840	xmlNodePtr text = inst->children;
3841	xmlNodePtr copy;
3842
3843	while (text != NULL) {
3844	    if ((text->type != XML_TEXT_NODE) &&
3845	         (text->type != XML_CDATA_SECTION_NODE)) {
3846		xsltTransformError(ctxt, NULL, inst,
3847				 "xsl:text content problem\n");
3848		break;
3849	    }
3850	    copy = xmlNewDocText(ctxt->output, text->content);
3851	    if (text->type != XML_CDATA_SECTION_NODE) {
3852#ifdef WITH_XSLT_DEBUG_PARSING
3853		xsltGenericDebug(xsltGenericDebugContext,
3854		     "Disable escaping: %s\n", text->content);
3855#endif
3856		copy->name = xmlStringTextNoenc;
3857	    }
3858	    copy = xsltAddChild(ctxt->insert, copy);
3859	    text = text->next;
3860	}
3861    }
3862}
3863
3864/**
3865 * xsltElement:
3866 * @ctxt:  a XSLT process context
3867 * @node:  the node in the source tree.
3868 * @inst:  the xslt element node
3869 * @castedComp:  precomputed information
3870 *
3871 * Process the xslt element node on the source node
3872 */
3873void
3874xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
3875	    xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
3876#ifdef XSLT_REFACTORED
3877    xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp;
3878#else
3879    xsltStylePreCompPtr comp = castedComp;
3880#endif
3881    xmlChar *prop = NULL;
3882    const xmlChar *name, *prefix = NULL, *nsName = NULL;
3883    xmlNodePtr copy;
3884    xmlNodePtr oldInsert;
3885
3886    if (ctxt->insert == NULL)
3887	return;
3888
3889    /*
3890    * A comp->has_name == 0 indicates that we need to skip this instruction,
3891    * since it was evaluated to be invalid already during compilation.
3892    */
3893    if (!comp->has_name)
3894        return;
3895
3896    /*
3897     * stack and saves
3898     */
3899    oldInsert = ctxt->insert;
3900
3901    if (comp->name == NULL) {
3902	/* TODO: fix attr acquisition wrt to the XSLT namespace */
3903        prop = xsltEvalAttrValueTemplate(ctxt, inst,
3904	    (const xmlChar *) "name", XSLT_NAMESPACE);
3905        if (prop == NULL) {
3906            xsltTransformError(ctxt, NULL, inst,
3907		"xsl:element: The attribute 'name' is missing.\n");
3908            goto error;
3909        }
3910	if (xmlValidateQName(prop, 0)) {
3911	    xsltTransformError(ctxt, NULL, inst,
3912		"xsl:element: The effective name '%s' is not a "
3913		"valid QName.\n", prop);
3914	    /* we fall through to catch any further errors, if possible */
3915	}
3916	name = xsltSplitQName(ctxt->dict, prop, &prefix);
3917	xmlFree(prop);
3918	if ((prefix != NULL) &&
3919	    (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))
3920	{
3921	    /*
3922	    * TODO: Should we really disallow an "xml" prefix?
3923	    */
3924	    goto error;
3925	}
3926    } else {
3927	/*
3928	* The "name" value was static.
3929	*/
3930#ifdef XSLT_REFACTORED
3931	prefix = comp->nsPrefix;
3932	name = comp->name;
3933#else
3934	name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
3935#endif
3936    }
3937
3938    /*
3939     * Create the new element
3940     */
3941    if (ctxt->output->dict == ctxt->dict) {
3942	copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL);
3943    } else {
3944	copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL);
3945    }
3946    if (copy == NULL) {
3947	xsltTransformError(ctxt, NULL, inst,
3948	    "xsl:element : creation of %s failed\n", name);
3949	return;
3950    }
3951    copy = xsltAddChild(ctxt->insert, copy);
3952
3953    /*
3954    * Namespace
3955    * ---------
3956    */
3957    if (comp->has_ns) {
3958	if (comp->ns != NULL) {
3959	    /*
3960	    * No AVT; just plain text for the namespace name.
3961	    */
3962	    if (comp->ns[0] != 0)
3963		nsName = comp->ns;
3964	} else {
3965	    xmlChar *tmpNsName;
3966	    /*
3967	    * Eval the AVT.
3968	    */
3969	    /* TODO: check attr acquisition wrt to the XSLT namespace */
3970	    tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
3971		(const xmlChar *) "namespace", XSLT_NAMESPACE);
3972	    /*
3973	    * SPEC XSLT 1.0:
3974	    *  "If the string is empty, then the expanded-name of the
3975	    *  attribute has a null namespace URI."
3976	    */
3977	    if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
3978		nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
3979	    xmlFree(tmpNsName);
3980	};
3981    } else {
3982	xmlNsPtr ns;
3983	/*
3984	* SPEC XSLT 1.0:
3985	*  "If the namespace attribute is not present, then the QName is
3986	*  expanded into an expanded-name using the namespace declarations
3987	*  in effect for the xsl:element element, including any default
3988	*  namespace declaration.
3989	*/
3990	ns = xmlSearchNs(inst->doc, inst, prefix);
3991	if (ns == NULL) {
3992	    /*
3993	    * TODO: Check this in the compilation layer in case it's a
3994	    * static value.
3995	    */
3996	    if (prefix != NULL) {
3997		xsltTransformError(ctxt, NULL, inst,
3998		    "xsl:element: The QName '%s:%s' has no "
3999		    "namespace binding in scope in the stylesheet; "
4000		    "this is an error, since the namespace was not "
4001		    "specified by the instruction itself.\n", prefix, name);
4002	    }
4003	} else
4004	    nsName = ns->href;
4005    }
4006    /*
4007    * Find/create a matching ns-decl in the result tree.
4008    */
4009    if (nsName != NULL) {
4010	copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, copy);
4011    } else if ((copy->parent != NULL) &&
4012	(copy->parent->type == XML_ELEMENT_NODE) &&
4013	(copy->parent->ns != NULL))
4014    {
4015	/*
4016	* "Undeclare" the default namespace.
4017	*/
4018	xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);
4019    }
4020
4021    ctxt->insert = copy;
4022
4023    if (comp->has_use) {
4024	if (comp->use != NULL) {
4025	    xsltApplyAttributeSet(ctxt, node, inst, comp->use);
4026	} else {
4027	    xmlChar *attrSets = NULL;
4028	    /*
4029	    * BUG TODO: use-attribute-sets is not a value template.
4030	    *  use-attribute-sets = qnames
4031	    */
4032	    attrSets = xsltEvalAttrValueTemplate(ctxt, inst,
4033		(const xmlChar *)"use-attribute-sets", NULL);
4034	    if (attrSets != NULL) {
4035		xsltApplyAttributeSet(ctxt, node, inst, attrSets);
4036		xmlFree(attrSets);
4037	    }
4038	}
4039    }
4040    /*
4041    * Instantiate the sequence constructor.
4042    */
4043    if (inst->children != NULL)
4044	xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
4045	    NULL);
4046
4047error:
4048    ctxt->insert = oldInsert;
4049    return;
4050}
4051
4052
4053/**
4054 * xsltComment:
4055 * @ctxt:  a XSLT process context
4056 * @node:  the node in the source tree.
4057 * @inst:  the xslt comment node
4058 * @comp:  precomputed information
4059 *
4060 * Process the xslt comment node on the source node
4061 */
4062void
4063xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node,
4064	           xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
4065    xmlChar *value = NULL;
4066    xmlNodePtr commentNode;
4067    int len;
4068
4069    value = xsltEvalTemplateString(ctxt, node, inst);
4070    /* TODO: use or generate the compiled form */
4071    len = xmlStrlen(value);
4072    if (len > 0) {
4073        if ((value[len-1] == '-') ||
4074	    (xmlStrstr(value, BAD_CAST "--"))) {
4075	    xsltTransformError(ctxt, NULL, inst,
4076		    "xsl:comment : '--' or ending '-' not allowed in comment\n");
4077	    /* fall through to try to catch further errors */
4078	}
4079    }
4080#ifdef WITH_XSLT_DEBUG_PROCESS
4081    if (value == NULL) {
4082	XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
4083	     "xsltComment: empty\n"));
4084    } else {
4085	XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
4086	     "xsltComment: content %s\n", value));
4087    }
4088#endif
4089
4090    commentNode = xmlNewComment(value);
4091    commentNode = xsltAddChild(ctxt->insert, commentNode);
4092
4093    if (value != NULL)
4094	xmlFree(value);
4095}
4096
4097/**
4098 * xsltProcessingInstruction:
4099 * @ctxt:  a XSLT process context
4100 * @node:  the node in the source tree.
4101 * @inst:  the xslt processing-instruction node
4102 * @castedComp:  precomputed information
4103 *
4104 * Process the xslt processing-instruction node on the source node
4105 */
4106void
4107xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node,
4108	           xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
4109#ifdef XSLT_REFACTORED
4110    xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp;
4111#else
4112    xsltStylePreCompPtr comp = castedComp;
4113#endif
4114    const xmlChar *name;
4115    xmlChar *value = NULL;
4116    xmlNodePtr pi;
4117
4118
4119    if (ctxt->insert == NULL)
4120	return;
4121    if (comp->has_name == 0)
4122	return;
4123    if (comp->name == NULL) {
4124	name = xsltEvalAttrValueTemplate(ctxt, inst,
4125			    (const xmlChar *)"name", NULL);
4126	if (name == NULL) {
4127	    xsltTransformError(ctxt, NULL, inst,
4128		 "xsl:processing-instruction : name is missing\n");
4129	    goto error;
4130	}
4131    } else {
4132	name = comp->name;
4133    }
4134    /* TODO: check that it's both an an NCName and a PITarget. */
4135
4136
4137    value = xsltEvalTemplateString(ctxt, node, inst);
4138    if (xmlStrstr(value, BAD_CAST "?>") != NULL) {
4139	xsltTransformError(ctxt, NULL, inst,
4140	     "xsl:processing-instruction: '?>' not allowed within PI content\n");
4141	goto error;
4142    }
4143#ifdef WITH_XSLT_DEBUG_PROCESS
4144    if (value == NULL) {
4145	XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
4146	     "xsltProcessingInstruction: %s empty\n", name));
4147    } else {
4148	XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
4149	     "xsltProcessingInstruction: %s content %s\n", name, value));
4150    }
4151#endif
4152
4153    pi = xmlNewDocPI(ctxt->insert->doc, name, value);
4154    pi = xsltAddChild(ctxt->insert, pi);
4155
4156error:
4157    if ((name != NULL) && (name != comp->name))
4158        xmlFree((xmlChar *) name);
4159    if (value != NULL)
4160	xmlFree(value);
4161}
4162
4163/**
4164 * xsltCopyOf:
4165 * @ctxt:  an XSLT transformation context
4166 * @node:  the current node in the source tree
4167 * @inst:  the element node of the XSLT copy-of instruction
4168 * @castedComp:  precomputed information of the XSLT copy-of instruction
4169 *
4170 * Process the XSLT copy-of instruction.
4171 */
4172void
4173xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
4174	           xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
4175#ifdef XSLT_REFACTORED
4176    xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp;
4177#else
4178    xsltStylePreCompPtr comp = castedComp;
4179#endif
4180    xmlXPathObjectPtr res = NULL;
4181    xmlNodeSetPtr list = NULL;
4182    int i;
4183    xmlDocPtr oldXPContextDoc;
4184    xmlNsPtr *oldXPNamespaces;
4185    xmlNodePtr oldXPContextNode;
4186    int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
4187    xmlXPathContextPtr xpctxt;
4188
4189    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4190	return;
4191    if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4192	xsltTransformError(ctxt, NULL, inst,
4193	     "xsl:copy-of : compilation failed\n");
4194	return;
4195    }
4196
4197     /*
4198    * SPEC XSLT 1.0:
4199    *  "The xsl:copy-of element can be used to insert a result tree
4200    *  fragment into the result tree, without first converting it to
4201    *  a string as xsl:value-of does (see [7.6.1 Generating Text with
4202    *  xsl:value-of]). The required select attribute contains an
4203    *  expression. When the result of evaluating the expression is a
4204    *  result tree fragment, the complete fragment is copied into the
4205    *  result tree. When the result is a node-set, all the nodes in the
4206    *  set are copied in document order into the result tree; copying
4207    *  an element node copies the attribute nodes, namespace nodes and
4208    *  children of the element node as well as the element node itself;
4209    *  a root node is copied by copying its children. When the result
4210    *  is neither a node-set nor a result tree fragment, the result is
4211    *  converted to a string and then inserted into the result tree,
4212    *  as with xsl:value-of.
4213    */
4214
4215#ifdef WITH_XSLT_DEBUG_PROCESS
4216    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4217	 "xsltCopyOf: select %s\n", comp->select));
4218#endif
4219
4220    /*
4221    * Evaluate the "select" expression.
4222    */
4223    xpctxt = ctxt->xpathCtxt;
4224    oldXPContextDoc = xpctxt->doc;
4225    oldXPContextNode = xpctxt->node;
4226    oldXPProximityPosition = xpctxt->proximityPosition;
4227    oldXPContextSize = xpctxt->contextSize;
4228    oldXPNsNr = xpctxt->nsNr;
4229    oldXPNamespaces = xpctxt->namespaces;
4230
4231    xpctxt->node = node;
4232    if (comp != NULL) {
4233
4234#ifdef XSLT_REFACTORED
4235	if (comp->inScopeNs != NULL) {
4236	    xpctxt->namespaces = comp->inScopeNs->list;
4237	    xpctxt->nsNr = comp->inScopeNs->xpathNumber;
4238	} else {
4239	    xpctxt->namespaces = NULL;
4240	    xpctxt->nsNr = 0;
4241	}
4242#else
4243	xpctxt->namespaces = comp->nsList;
4244	xpctxt->nsNr = comp->nsNr;
4245#endif
4246    } else {
4247	xpctxt->namespaces = NULL;
4248	xpctxt->nsNr = 0;
4249    }
4250
4251    res = xmlXPathCompiledEval(comp->comp, xpctxt);
4252
4253    xpctxt->doc = oldXPContextDoc;
4254    xpctxt->node = oldXPContextNode;
4255    xpctxt->contextSize = oldXPContextSize;
4256    xpctxt->proximityPosition = oldXPProximityPosition;
4257    xpctxt->nsNr = oldXPNsNr;
4258    xpctxt->namespaces = oldXPNamespaces;
4259
4260    if (res != NULL) {
4261	if (res->type == XPATH_NODESET) {
4262	    /*
4263	    * Node-set
4264	    * --------
4265	    */
4266#ifdef WITH_XSLT_DEBUG_PROCESS
4267	    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4268		 "xsltCopyOf: result is a node set\n"));
4269#endif
4270	    list = res->nodesetval;
4271	    if (list != NULL) {
4272		xmlNodePtr cur;
4273		/*
4274		* The list is already sorted in document order by XPath.
4275		* Append everything in this order under ctxt->insert.
4276		*/
4277		for (i = 0;i < list->nodeNr;i++) {
4278		    cur = list->nodeTab[i];
4279		    if (cur == NULL)
4280			continue;
4281		    if ((cur->type == XML_DOCUMENT_NODE) ||
4282			(cur->type == XML_HTML_DOCUMENT_NODE))
4283		    {
4284			xsltCopyTreeList(ctxt, inst,
4285			    cur->children, ctxt->insert, 0, 0);
4286		    } else if (cur->type == XML_ATTRIBUTE_NODE) {
4287			xsltShallowCopyAttr(ctxt, inst,
4288			    ctxt->insert, (xmlAttrPtr) cur);
4289		    } else {
4290			xsltCopyTreeInternal(ctxt, inst,
4291			    cur, ctxt->insert, 0, 0);
4292		    }
4293		}
4294	    }
4295	} else if (res->type == XPATH_XSLT_TREE) {
4296	    /*
4297	    * Result tree fragment
4298	    * --------------------
4299	    * E.g. via <xsl:variable ...><foo/></xsl:variable>
4300	    * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4301	    */
4302#ifdef WITH_XSLT_DEBUG_PROCESS
4303	    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4304		 "xsltCopyOf: result is a result tree fragment\n"));
4305#endif
4306	    list = res->nodesetval;
4307	    if ((list != NULL) && (list->nodeTab != NULL) &&
4308		(list->nodeTab[0] != NULL) &&
4309		(IS_XSLT_REAL_NODE(list->nodeTab[0])))
4310	    {
4311		xsltCopyTreeList(ctxt, inst,
4312		    list->nodeTab[0]->children, ctxt->insert, 0, 0);
4313	    }
4314	} else {
4315	    xmlChar *value = NULL;
4316	    /*
4317	    * Convert to a string.
4318	    */
4319	    value = xmlXPathCastToString(res);
4320	    if (value == NULL) {
4321		xsltTransformError(ctxt, NULL, inst,
4322		    "Internal error in xsltCopyOf(): "
4323		    "failed to cast an XPath object to string.\n");
4324		ctxt->state = XSLT_STATE_STOPPED;
4325	    } else {
4326		if (value[0] != 0) {
4327		    /*
4328		    * Append content as text node.
4329		    */
4330		    xsltCopyTextString(ctxt, ctxt->insert, value, 0);
4331		}
4332		xmlFree(value);
4333
4334#ifdef WITH_XSLT_DEBUG_PROCESS
4335		XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4336		    "xsltCopyOf: result %s\n", res->stringval));
4337#endif
4338	    }
4339	}
4340    } else {
4341	ctxt->state = XSLT_STATE_STOPPED;
4342    }
4343
4344    if (res != NULL)
4345	xmlXPathFreeObject(res);
4346}
4347
4348/**
4349 * xsltValueOf:
4350 * @ctxt:  a XSLT process context
4351 * @node:  the node in the source tree.
4352 * @inst:  the xslt value-of node
4353 * @castedComp:  precomputed information
4354 *
4355 * Process the xslt value-of node on the source node
4356 */
4357void
4358xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
4359	           xmlNodePtr inst, xsltStylePreCompPtr castedComp)
4360{
4361#ifdef XSLT_REFACTORED
4362    xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp;
4363#else
4364    xsltStylePreCompPtr comp = castedComp;
4365#endif
4366    xmlXPathObjectPtr res = NULL;
4367    xmlNodePtr copy = NULL;
4368    xmlChar *value = NULL;
4369    xmlDocPtr oldXPContextDoc;
4370    xmlNsPtr *oldXPNamespaces;
4371    xmlNodePtr oldXPContextNode;
4372    int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
4373    xmlXPathContextPtr xpctxt;
4374
4375    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4376	return;
4377
4378    if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4379	xsltTransformError(ctxt, NULL, inst,
4380	    "Internal error in xsltValueOf(): "
4381	    "The XSLT 'value-of' instruction was not compiled.\n");
4382	return;
4383    }
4384
4385#ifdef WITH_XSLT_DEBUG_PROCESS
4386    XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
4387	 "xsltValueOf: select %s\n", comp->select));
4388#endif
4389
4390    xpctxt = ctxt->xpathCtxt;
4391    oldXPContextDoc = xpctxt->doc;
4392    oldXPContextNode = xpctxt->node;
4393    oldXPProximityPosition = xpctxt->proximityPosition;
4394    oldXPContextSize = xpctxt->contextSize;
4395    oldXPNsNr = xpctxt->nsNr;
4396    oldXPNamespaces = xpctxt->namespaces;
4397
4398    xpctxt->node = node;
4399    if (comp != NULL) {
4400
4401#ifdef XSLT_REFACTORED
4402	if (comp->inScopeNs != NULL) {
4403	    xpctxt->namespaces = comp->inScopeNs->list;
4404	    xpctxt->nsNr = comp->inScopeNs->xpathNumber;
4405	} else {
4406	    xpctxt->namespaces = NULL;
4407	    xpctxt->nsNr = 0;
4408	}
4409#else
4410	xpctxt->namespaces = comp->nsList;
4411	xpctxt->nsNr = comp->nsNr;
4412#endif
4413    } else {
4414	xpctxt->namespaces = NULL;
4415	xpctxt->nsNr = 0;
4416    }
4417
4418    res = xmlXPathCompiledEval(comp->comp, xpctxt);
4419
4420    xpctxt->doc = oldXPContextDoc;
4421    xpctxt->node = oldXPContextNode;
4422    xpctxt->contextSize = oldXPContextSize;
4423    xpctxt->proximityPosition = oldXPProximityPosition;
4424    xpctxt->nsNr = oldXPNsNr;
4425    xpctxt->namespaces = oldXPNamespaces;
4426
4427    /*
4428    * Cast the XPath object to string.
4429    */
4430    if (res != NULL) {
4431	value = xmlXPathCastToString(res);
4432	if (value == NULL) {
4433	    xsltTransformError(ctxt, NULL, inst,
4434		"Internal error in xsltValueOf(): "
4435		"failed to cast an XPath object to string.\n");
4436	    ctxt->state = XSLT_STATE_STOPPED;
4437	    goto error;
4438	}
4439	if (value[0] != 0) {
4440	    copy = xsltCopyTextString(ctxt,
4441		ctxt->insert, value, comp->noescape);
4442	}
4443    } else {
4444	xsltTransformError(ctxt, NULL, inst,
4445	    "XPath evaluation returned no result.\n");
4446	ctxt->state = XSLT_STATE_STOPPED;
4447	goto error;
4448    }
4449
4450#ifdef WITH_XSLT_DEBUG_PROCESS
4451    if (value) {
4452	XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
4453	     "xsltValueOf: result '%s'\n", value));
4454    }
4455#endif
4456
4457error:
4458    if (value != NULL)
4459	xmlFree(value);
4460    if (res != NULL)
4461	xmlXPathFreeObject(res);
4462}
4463
4464/**
4465 * xsltNumber:
4466 * @ctxt:  a XSLT process context
4467 * @node:  the node in the source tree.
4468 * @inst:  the xslt number node
4469 * @castedComp:  precomputed information
4470 *
4471 * Process the xslt number node on the source node
4472 */
4473void
4474xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node,
4475	   xmlNodePtr inst, xsltStylePreCompPtr castedComp)
4476{
4477#ifdef XSLT_REFACTORED
4478    xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp;
4479#else
4480    xsltStylePreCompPtr comp = castedComp;
4481#endif
4482    if (comp == NULL) {
4483	xsltTransformError(ctxt, NULL, inst,
4484	     "xsl:number : compilation failed\n");
4485	return;
4486    }
4487
4488    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4489	return;
4490
4491    comp->numdata.doc = inst->doc;
4492    comp->numdata.node = inst;
4493
4494    xsltNumberFormat(ctxt, &comp->numdata, node);
4495}
4496
4497/**
4498 * xsltApplyImports:
4499 * @ctxt:  an XSLT transformation context
4500 * @contextNode:  the current node in the source tree.
4501 * @inst:  the element node of the XSLT 'apply-imports' instruction
4502 * @comp:  the compiled instruction
4503 *
4504 * Process the XSLT apply-imports element.
4505 */
4506void
4507xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
4508	         xmlNodePtr inst,
4509		 xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
4510{
4511    xsltTemplatePtr templ;
4512
4513    if ((ctxt == NULL) || (inst == NULL))
4514	return;
4515
4516    if (comp == NULL) {
4517	xsltTransformError(ctxt, NULL, inst,
4518	    "Internal error in xsltApplyImports(): "
4519	    "The XSLT 'apply-imports' instruction was not compiled.\n");
4520	return;
4521    }
4522    /*
4523    * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4524    * same; the former is the "Current Template Rule" as defined by the
4525    * XSLT spec, the latter is simply the template struct being
4526    * currently processed.
4527    */
4528    if (ctxt->currentTemplateRule == NULL) {
4529	/*
4530	* SPEC XSLT 2.0:
4531	* "[ERR XTDE0560] It is a non-recoverable dynamic error if
4532	*  xsl:apply-imports or xsl:next-match is evaluated when the
4533	*  current template rule is null."
4534	*/
4535	xsltTransformError(ctxt, NULL, inst,
4536	     "It is an error to call 'apply-imports' "
4537	     "when there's no current template rule.\n");
4538	return;
4539    }
4540    /*
4541    * TODO: Check if this is correct.
4542    */
4543    templ = xsltGetTemplate(ctxt, contextNode,
4544	ctxt->currentTemplateRule->style);
4545
4546    if (templ != NULL) {
4547	xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule;
4548	/*
4549	* Set the current template rule.
4550	*/
4551	ctxt->currentTemplateRule = templ;
4552	/*
4553	* URGENT TODO: Need xsl:with-param be handled somehow here?
4554	*/
4555	xsltApplyXSLTTemplate(ctxt, contextNode, templ->content,
4556	    templ, NULL);
4557
4558	ctxt->currentTemplateRule = oldCurTemplRule;
4559    }
4560}
4561
4562/**
4563 * xsltCallTemplate:
4564 * @ctxt:  a XSLT transformation context
4565 * @node:  the "current node" in the source tree
4566 * @inst:  the XSLT 'call-template' instruction
4567 * @castedComp:  the compiled information of the instruction
4568 *
4569 * Processes the XSLT call-template instruction on the source node.
4570 */
4571void
4572xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
4573	           xmlNodePtr inst, xsltStylePreCompPtr castedComp)
4574{
4575#ifdef XSLT_REFACTORED
4576    xsltStyleItemCallTemplatePtr comp =
4577	(xsltStyleItemCallTemplatePtr) castedComp;
4578#else
4579    xsltStylePreCompPtr comp = castedComp;
4580#endif
4581    xsltStackElemPtr withParams = NULL;
4582
4583    if (ctxt->insert == NULL)
4584	return;
4585    if (comp == NULL) {
4586	xsltTransformError(ctxt, NULL, inst,
4587	     "The XSLT 'call-template' instruction was not compiled.\n");
4588	return;
4589    }
4590
4591    /*
4592     * The template must have been precomputed
4593     */
4594    if (comp->templ == NULL) {
4595	comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);
4596	if (comp->templ == NULL) {
4597	    if (comp->ns != NULL) {
4598	        xsltTransformError(ctxt, NULL, inst,
4599			"The called template '{%s}%s' was not found.\n",
4600			comp->ns, comp->name);
4601	    } else {
4602	        xsltTransformError(ctxt, NULL, inst,
4603			"The called template '%s' was not found.\n",
4604			comp->name);
4605	    }
4606	    return;
4607	}
4608    }
4609
4610#ifdef WITH_XSLT_DEBUG_PROCESS
4611    if ((comp != NULL) && (comp->name != NULL))
4612	XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
4613			 "call-template: name %s\n", comp->name));
4614#endif
4615
4616    if (inst->children) {
4617	xmlNodePtr cur;
4618	xsltStackElemPtr param;
4619
4620	cur = inst->children;
4621	while (cur != NULL) {
4622#ifdef WITH_DEBUGGER
4623	    if (ctxt->debugStatus != XSLT_DEBUG_NONE)
4624		xslHandleDebugger(cur, node, comp->templ, ctxt);
4625#endif
4626	    if (ctxt->state == XSLT_STATE_STOPPED) break;
4627	    /*
4628	    * TODO: The "with-param"s could be part of the "call-template"
4629	    *   structure. Avoid to "search" for params dynamically
4630	    *   in the XML tree every time.
4631	    */
4632	    if (IS_XSLT_ELEM(cur)) {
4633		if (IS_XSLT_NAME(cur, "with-param")) {
4634		    param = xsltParseStylesheetCallerParam(ctxt, cur);
4635		    if (param != NULL) {
4636			param->next = withParams;
4637			withParams = param;
4638		    }
4639		} else {
4640		    xsltGenericError(xsltGenericErrorContext,
4641			"xsl:call-template: misplaced xsl:%s\n", cur->name);
4642		}
4643	    } else {
4644		xsltGenericError(xsltGenericErrorContext,
4645		    "xsl:call-template: misplaced %s element\n", cur->name);
4646	    }
4647	    cur = cur->next;
4648	}
4649    }
4650    /*
4651     * Create a new frame using the params first
4652     */
4653    xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ,
4654	withParams);
4655    if (withParams != NULL)
4656	xsltFreeStackElemList(withParams);
4657
4658#ifdef WITH_XSLT_DEBUG_PROCESS
4659    if ((comp != NULL) && (comp->name != NULL))
4660	XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
4661			 "call-template returned: name %s\n", comp->name));
4662#endif
4663}
4664
4665/**
4666 * xsltApplyTemplates:
4667 * @ctxt:  a XSLT transformation context
4668 * @node:  the 'current node' in the source tree
4669 * @inst:  the element node of an XSLT 'apply-templates' instruction
4670 * @castedComp:  the compiled instruction
4671 *
4672 * Processes the XSLT 'apply-templates' instruction on the current node.
4673 */
4674void
4675xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
4676	           xmlNodePtr inst, xsltStylePreCompPtr castedComp)
4677{
4678#ifdef XSLT_REFACTORED
4679    xsltStyleItemApplyTemplatesPtr comp =
4680	(xsltStyleItemApplyTemplatesPtr) castedComp;
4681#else
4682    xsltStylePreCompPtr comp = castedComp;
4683#endif
4684    int i;
4685    xmlNodePtr cur, delNode = NULL, oldContextNode;
4686    xmlNodeSetPtr list = NULL, oldList;
4687    xsltStackElemPtr withParams = NULL;
4688    int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
4689    const xmlChar *oldMode, *oldModeURI;
4690    xmlDocPtr oldXPDoc;
4691    xsltDocumentPtr oldDocInfo;
4692    xmlXPathContextPtr xpctxt;
4693    xmlNsPtr *oldXPNamespaces;
4694
4695    if (comp == NULL) {
4696	xsltTransformError(ctxt, NULL, inst,
4697	     "xsl:apply-templates : compilation failed\n");
4698	return;
4699    }
4700    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4701	return;
4702
4703#ifdef WITH_XSLT_DEBUG_PROCESS
4704    if ((node != NULL) && (node->name != NULL))
4705	XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4706	     "xsltApplyTemplates: node: '%s'\n", node->name));
4707#endif
4708
4709    xpctxt = ctxt->xpathCtxt;
4710    /*
4711    * Save context states.
4712    */
4713    oldContextNode = ctxt->node;
4714    oldMode = ctxt->mode;
4715    oldModeURI = ctxt->modeURI;
4716    oldDocInfo = ctxt->document;
4717    oldList = ctxt->nodeList;
4718
4719    /*
4720     * The xpath context size and proximity position, as
4721     * well as the xpath and context documents, may be changed
4722     * so we save their initial state and will restore on exit
4723     */
4724    oldXPContextSize = xpctxt->contextSize;
4725    oldXPProximityPosition = xpctxt->proximityPosition;
4726    oldXPDoc = xpctxt->doc;
4727    oldXPNsNr = xpctxt->nsNr;
4728    oldXPNamespaces = xpctxt->namespaces;
4729
4730    /*
4731    * Set up contexts.
4732    */
4733    ctxt->mode = comp->mode;
4734    ctxt->modeURI = comp->modeURI;
4735
4736    if (comp->select != NULL) {
4737	xmlXPathObjectPtr res = NULL;
4738
4739	if (comp->comp == NULL) {
4740	    xsltTransformError(ctxt, NULL, inst,
4741		 "xsl:apply-templates : compilation failed\n");
4742	    goto error;
4743	}
4744#ifdef WITH_XSLT_DEBUG_PROCESS
4745	XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4746	     "xsltApplyTemplates: select %s\n", comp->select));
4747#endif
4748
4749	/*
4750	* Set up XPath.
4751	*/
4752	xpctxt->node = node; /* Set the "context node" */
4753#ifdef XSLT_REFACTORED
4754	if (comp->inScopeNs != NULL) {
4755	    xpctxt->namespaces = comp->inScopeNs->list;
4756	    xpctxt->nsNr = comp->inScopeNs->xpathNumber;
4757	} else {
4758	    xpctxt->namespaces = NULL;
4759	    xpctxt->nsNr = 0;
4760	}
4761#else
4762	xpctxt->namespaces = comp->nsList;
4763	xpctxt->nsNr = comp->nsNr;
4764#endif
4765	res = xmlXPathCompiledEval(comp->comp, xpctxt);
4766
4767	xpctxt->contextSize = oldXPContextSize;
4768	xpctxt->proximityPosition = oldXPProximityPosition;
4769	if (res != NULL) {
4770	    if (res->type == XPATH_NODESET) {
4771		list = res->nodesetval; /* consume the node set */
4772		res->nodesetval = NULL;
4773	    } else {
4774		xsltTransformError(ctxt, NULL, inst,
4775		    "The 'select' expression did not evaluate to a "
4776		    "node set.\n");
4777		ctxt->state = XSLT_STATE_STOPPED;
4778		xmlXPathFreeObject(res);
4779		goto error;
4780	    }
4781	    xmlXPathFreeObject(res);
4782	    /*
4783	    * Note: An xsl:apply-templates with a 'select' attribute,
4784	    * can change the current source doc.
4785	    */
4786	} else {
4787	    xsltTransformError(ctxt, NULL, inst,
4788		"Failed to evaluate the 'select' expression.\n");
4789	    ctxt->state = XSLT_STATE_STOPPED;
4790	    goto error;
4791	}
4792	if (list == NULL) {
4793#ifdef WITH_XSLT_DEBUG_PROCESS
4794	    XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4795		"xsltApplyTemplates: select didn't evaluate to a node list\n"));
4796#endif
4797	    goto exit;
4798	}
4799	/*
4800	*
4801	* NOTE: Previously a document info (xsltDocument) was
4802	* created and attached to the Result Tree Fragment.
4803	* But such a document info is created on demand in
4804	* xsltKeyFunction() (functions.c), so we need to create
4805	* it here beforehand.
4806	* In order to take care of potential keys we need to
4807	* do some extra work for the case when a Result Tree Fragment
4808	* is converted into a nodeset (e.g. exslt:node-set()) :
4809	* We attach a "pseudo-doc" (xsltDocument) to _private.
4810	* This xsltDocument, together with the keyset, will be freed
4811	* when the Result Tree Fragment is freed.
4812	*
4813	*/
4814#if 0
4815	if ((ctxt->nbKeys > 0) &&
4816	    (list->nodeNr != 0) &&
4817	    (list->nodeTab[0]->doc != NULL) &&
4818	    XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc))
4819	{
4820	    /*
4821	    * NOTE that it's also OK if @effectiveDocInfo will be
4822	    * set to NULL.
4823	    */
4824	    isRTF = 1;
4825	    effectiveDocInfo = list->nodeTab[0]->doc->_private;
4826	}
4827#endif
4828    } else {
4829	/*
4830	 * Build an XPath node set with the children
4831	 */
4832	list = xmlXPathNodeSetCreate(NULL);
4833	if (list == NULL)
4834	    goto error;
4835	cur = node->children;
4836	while (cur != NULL) {
4837	    switch (cur->type) {
4838		case XML_TEXT_NODE:
4839		    if ((IS_BLANK_NODE(cur)) &&
4840			(cur->parent != NULL) &&
4841			(cur->parent->type == XML_ELEMENT_NODE) &&
4842			(ctxt->style->stripSpaces != NULL)) {
4843			const xmlChar *val;
4844
4845			if (cur->parent->ns != NULL) {
4846			    val = (const xmlChar *)
4847				  xmlHashLookup2(ctxt->style->stripSpaces,
4848						 cur->parent->name,
4849						 cur->parent->ns->href);
4850			    if (val == NULL) {
4851				val = (const xmlChar *)
4852				  xmlHashLookup2(ctxt->style->stripSpaces,
4853						 BAD_CAST "*",
4854						 cur->parent->ns->href);
4855			    }
4856			} else {
4857			    val = (const xmlChar *)
4858				  xmlHashLookup2(ctxt->style->stripSpaces,
4859						 cur->parent->name, NULL);
4860			}
4861			if ((val != NULL) &&
4862			    (xmlStrEqual(val, (xmlChar *) "strip"))) {
4863			    delNode = cur;
4864			    break;
4865			}
4866		    }
4867		    /* no break on purpose */
4868		case XML_ELEMENT_NODE:
4869		case XML_DOCUMENT_NODE:
4870		case XML_HTML_DOCUMENT_NODE:
4871		case XML_CDATA_SECTION_NODE:
4872		case XML_PI_NODE:
4873		case XML_COMMENT_NODE:
4874		    xmlXPathNodeSetAddUnique(list, cur);
4875		    break;
4876		case XML_DTD_NODE:
4877		    /* Unlink the DTD, it's still reachable
4878		     * using doc->intSubset */
4879		    if (cur->next != NULL)
4880			cur->next->prev = cur->prev;
4881		    if (cur->prev != NULL)
4882			cur->prev->next = cur->next;
4883		    break;
4884		default:
4885#ifdef WITH_XSLT_DEBUG_PROCESS
4886		    XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4887		     "xsltApplyTemplates: skipping cur type %d\n",
4888				     cur->type));
4889#endif
4890		    delNode = cur;
4891	    }
4892	    cur = cur->next;
4893	    if (delNode != NULL) {
4894#ifdef WITH_XSLT_DEBUG_PROCESS
4895		XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4896		     "xsltApplyTemplates: removing ignorable blank cur\n"));
4897#endif
4898		xmlUnlinkNode(delNode);
4899		xmlFreeNode(delNode);
4900		delNode = NULL;
4901	    }
4902	}
4903    }
4904
4905#ifdef WITH_XSLT_DEBUG_PROCESS
4906    if (list != NULL)
4907    XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4908	"xsltApplyTemplates: list of %d nodes\n", list->nodeNr));
4909#endif
4910
4911    if ((list == NULL) || (list->nodeNr == 0))
4912	goto exit;
4913
4914    /*
4915    * Set the context's node set and size; this is also needed for
4916    * for xsltDoSortFunction().
4917    */
4918    ctxt->nodeList = list;
4919    /*
4920    * Process xsl:with-param and xsl:sort instructions.
4921    * (The code became so verbose just to avoid the
4922    *  xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
4923    * BUG TODO: We are not using namespaced potentially defined on the
4924    * xsl:sort or xsl:with-param elements; XPath expression might fail.
4925    */
4926    if (inst->children) {
4927	xsltStackElemPtr param;
4928
4929	cur = inst->children;
4930	while (cur) {
4931
4932#ifdef WITH_DEBUGGER
4933	    if (ctxt->debugStatus != XSLT_DEBUG_NONE)
4934		xslHandleDebugger(cur, node, NULL, ctxt);
4935#endif
4936	    if (ctxt->state == XSLT_STATE_STOPPED)
4937		break;
4938	    if (cur->type == XML_TEXT_NODE) {
4939		cur = cur->next;
4940		continue;
4941	    }
4942	    if (! IS_XSLT_ELEM(cur))
4943		break;
4944	    if (IS_XSLT_NAME(cur, "with-param")) {
4945		param = xsltParseStylesheetCallerParam(ctxt, cur);
4946		if (param != NULL) {
4947		    param->next = withParams;
4948		    withParams = param;
4949		}
4950	    }
4951	    if (IS_XSLT_NAME(cur, "sort")) {
4952		xsltTemplatePtr oldCurTempRule =
4953		    ctxt->currentTemplateRule;
4954		int nbsorts = 0;
4955		xmlNodePtr sorts[XSLT_MAX_SORT];
4956
4957		sorts[nbsorts++] = cur;
4958
4959		while (cur) {
4960
4961#ifdef WITH_DEBUGGER
4962		    if (ctxt->debugStatus != XSLT_DEBUG_NONE)
4963			xslHandleDebugger(cur, node, NULL, ctxt);
4964#endif
4965		    if (ctxt->state == XSLT_STATE_STOPPED)
4966			break;
4967
4968		    if (cur->type == XML_TEXT_NODE) {
4969			cur = cur->next;
4970			continue;
4971		    }
4972
4973		    if (! IS_XSLT_ELEM(cur))
4974			break;
4975		    if (IS_XSLT_NAME(cur, "with-param")) {
4976			param = xsltParseStylesheetCallerParam(ctxt, cur);
4977			if (param != NULL) {
4978			    param->next = withParams;
4979			    withParams = param;
4980			}
4981		    }
4982		    if (IS_XSLT_NAME(cur, "sort")) {
4983			if (nbsorts >= XSLT_MAX_SORT) {
4984			    xsltTransformError(ctxt, NULL, cur,
4985				"The number (%d) of xsl:sort instructions exceeds the "
4986				"maximum allowed by this processor's settings.\n",
4987				nbsorts);
4988			    ctxt->state = XSLT_STATE_STOPPED;
4989			    break;
4990			} else {
4991			    sorts[nbsorts++] = cur;
4992			}
4993		    }
4994		    cur = cur->next;
4995		}
4996		/*
4997		* The "current template rule" is cleared for xsl:sort.
4998		*/
4999		ctxt->currentTemplateRule = NULL;
5000		/*
5001		* Sort.
5002		*/
5003		xsltDoSortFunction(ctxt, sorts, nbsorts);
5004		ctxt->currentTemplateRule = oldCurTempRule;
5005		break;
5006	    }
5007	    cur = cur->next;
5008	}
5009    }
5010    xpctxt->contextSize = list->nodeNr;
5011    /*
5012    * Apply templates for all selected source nodes.
5013    */
5014    for (i = 0; i < list->nodeNr; i++) {
5015	cur = list->nodeTab[i];
5016	/*
5017	* The node becomes the "current node".
5018	*/
5019	ctxt->node = cur;
5020	/*
5021	* An xsl:apply-templates can change the current context doc.
5022	* OPTIMIZE TODO: Get rid of the need to set the context doc.
5023	*/
5024	if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
5025	    xpctxt->doc = cur->doc;
5026
5027	xpctxt->proximityPosition = i + 1;
5028	/*
5029	* Find and apply a template for this node.
5030	*/
5031	xsltProcessOneNode(ctxt, cur, withParams);
5032    }
5033
5034exit:
5035error:
5036    /*
5037    * Free the parameter list.
5038    */
5039    if (withParams != NULL)
5040	xsltFreeStackElemList(withParams);
5041    if (list != NULL)
5042	xmlXPathFreeNodeSet(list);
5043    /*
5044    * Restore context states.
5045    */
5046    xpctxt->nsNr = oldXPNsNr;
5047    xpctxt->namespaces = oldXPNamespaces;
5048    xpctxt->doc = oldXPDoc;
5049    xpctxt->contextSize = oldXPContextSize;
5050    xpctxt->proximityPosition = oldXPProximityPosition;
5051
5052    ctxt->document = oldDocInfo;
5053    ctxt->nodeList = oldList;
5054    ctxt->node = oldContextNode;
5055    ctxt->mode = oldMode;
5056    ctxt->modeURI = oldModeURI;
5057}
5058
5059
5060/**
5061 * xsltChoose:
5062 * @ctxt:  a XSLT process context
5063 * @contextNode:  the current node in the source tree
5064 * @inst:  the xsl:choose instruction
5065 * @comp:  compiled information of the instruction
5066 *
5067 * Processes the xsl:choose instruction on the source node.
5068 */
5069void
5070xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5071	   xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
5072{
5073    xmlNodePtr cur;
5074
5075    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
5076	return;
5077
5078    /*
5079    * TODO: Content model checks should be done only at compilation
5080    * time.
5081    */
5082    cur = inst->children;
5083    if (cur == NULL) {
5084	xsltTransformError(ctxt, NULL, inst,
5085	    "xsl:choose: The instruction has no content.\n");
5086	return;
5087    }
5088
5089#ifdef XSLT_REFACTORED
5090    /*
5091    * We don't check the content model during transformation.
5092    */
5093#else
5094    if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) {
5095	xsltTransformError(ctxt, NULL, inst,
5096	     "xsl:choose: xsl:when expected first\n");
5097	return;
5098    }
5099#endif
5100
5101    {
5102	int testRes = 0, res = 0;
5103	xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
5104	xmlDocPtr oldXPContextDoc = xpctxt->doc;
5105	int oldXPProximityPosition = xpctxt->proximityPosition;
5106	int oldXPContextSize = xpctxt->contextSize;
5107	xmlNsPtr *oldXPNamespaces = xpctxt->namespaces;
5108	int oldXPNsNr = xpctxt->nsNr;
5109
5110#ifdef XSLT_REFACTORED
5111	xsltStyleItemWhenPtr wcomp = NULL;
5112#else
5113	xsltStylePreCompPtr wcomp = NULL;
5114#endif
5115
5116	/*
5117	* Process xsl:when ---------------------------------------------------
5118	*/
5119	while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) {
5120	    wcomp = cur->psvi;
5121
5122	    if ((wcomp == NULL) || (wcomp->test == NULL) ||
5123		(wcomp->comp == NULL))
5124	    {
5125		xsltTransformError(ctxt, NULL, cur,
5126		    "Internal error in xsltChoose(): "
5127		    "The XSLT 'when' instruction was not compiled.\n");
5128		goto error;
5129	    }
5130
5131
5132#ifdef WITH_DEBUGGER
5133	    if (xslDebugStatus != XSLT_DEBUG_NONE) {
5134		/*
5135		* TODO: Isn't comp->templ always NULL for xsl:choose?
5136		*/
5137		xslHandleDebugger(cur, contextNode, NULL, ctxt);
5138	    }
5139#endif
5140#ifdef WITH_XSLT_DEBUG_PROCESS
5141	    XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5142		"xsltChoose: test %s\n", wcomp->test));
5143#endif
5144
5145	    xpctxt->node = contextNode;
5146	    xpctxt->doc = oldXPContextDoc;
5147	    xpctxt->proximityPosition = oldXPProximityPosition;
5148	    xpctxt->contextSize = oldXPContextSize;
5149
5150#ifdef XSLT_REFACTORED
5151	    if (wcomp->inScopeNs != NULL) {
5152		xpctxt->namespaces = wcomp->inScopeNs->list;
5153		xpctxt->nsNr = wcomp->inScopeNs->xpathNumber;
5154	    } else {
5155		xpctxt->namespaces = NULL;
5156		xpctxt->nsNr = 0;
5157	    }
5158#else
5159	    xpctxt->namespaces = wcomp->nsList;
5160	    xpctxt->nsNr = wcomp->nsNr;
5161#endif
5162
5163
5164#ifdef XSLT_FAST_IF
5165	    res = xmlXPathCompiledEvalToBoolean(wcomp->comp, xpctxt);
5166
5167	    if (res == -1) {
5168		ctxt->state = XSLT_STATE_STOPPED;
5169		goto error;
5170	    }
5171	    testRes = (res == 1) ? 1 : 0;
5172
5173#else /* XSLT_FAST_IF */
5174
5175	    res = xmlXPathCompiledEval(wcomp->comp, xpctxt);
5176
5177	    if (res != NULL) {
5178		if (res->type != XPATH_BOOLEAN)
5179		    res = xmlXPathConvertBoolean(res);
5180		if (res->type == XPATH_BOOLEAN)
5181		    testRes = res->boolval;
5182		else {
5183#ifdef WITH_XSLT_DEBUG_PROCESS
5184		    XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5185			"xsltChoose: test didn't evaluate to a boolean\n"));
5186#endif
5187		    goto error;
5188		}
5189		xmlXPathFreeObject(res);
5190		res = NULL;
5191	    } else {
5192		ctxt->state = XSLT_STATE_STOPPED;
5193		goto error;
5194	    }
5195
5196#endif /* else of XSLT_FAST_IF */
5197
5198#ifdef WITH_XSLT_DEBUG_PROCESS
5199	    XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5200		"xsltChoose: test evaluate to %d\n", testRes));
5201#endif
5202	    if (testRes)
5203		goto test_is_true;
5204
5205	    cur = cur->next;
5206	}
5207
5208	/*
5209	* Process xsl:otherwise ----------------------------------------------
5210	*/
5211	if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) {
5212
5213#ifdef WITH_DEBUGGER
5214	    if (xslDebugStatus != XSLT_DEBUG_NONE)
5215		xslHandleDebugger(cur, contextNode, NULL, ctxt);
5216#endif
5217
5218#ifdef WITH_XSLT_DEBUG_PROCESS
5219	    XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5220		"evaluating xsl:otherwise\n"));
5221#endif
5222	    goto test_is_true;
5223	}
5224	xpctxt->node = contextNode;
5225	xpctxt->doc = oldXPContextDoc;
5226	xpctxt->proximityPosition = oldXPProximityPosition;
5227	xpctxt->contextSize = oldXPContextSize;
5228	xpctxt->namespaces = oldXPNamespaces;
5229	xpctxt->nsNr = oldXPNsNr;
5230	goto exit;
5231
5232test_is_true:
5233
5234	xpctxt->node = contextNode;
5235	xpctxt->doc = oldXPContextDoc;
5236	xpctxt->proximityPosition = oldXPProximityPosition;
5237	xpctxt->contextSize = oldXPContextSize;
5238	xpctxt->namespaces = oldXPNamespaces;
5239	xpctxt->nsNr = oldXPNsNr;
5240	goto process_sequence;
5241    }
5242
5243process_sequence:
5244
5245    /*
5246    * Instantiate the sequence constructor.
5247    */
5248    xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children,
5249	NULL);
5250
5251exit:
5252error:
5253    return;
5254}
5255
5256/**
5257 * xsltIf:
5258 * @ctxt:  a XSLT process context
5259 * @contextNode:  the current node in the source tree
5260 * @inst:  the xsl:if instruction
5261 * @castedComp:  compiled information of the instruction
5262 *
5263 * Processes the xsl:if instruction on the source node.
5264 */
5265void
5266xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5267	           xmlNodePtr inst, xsltStylePreCompPtr castedComp)
5268{
5269    int res = 0;
5270
5271#ifdef XSLT_REFACTORED
5272    xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp;
5273#else
5274    xsltStylePreCompPtr comp = castedComp;
5275#endif
5276
5277    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
5278	return;
5279    if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) {
5280	xsltTransformError(ctxt, NULL, inst,
5281	    "Internal error in xsltIf(): "
5282	    "The XSLT 'if' instruction was not compiled.\n");
5283	return;
5284    }
5285
5286#ifdef WITH_XSLT_DEBUG_PROCESS
5287    XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5288	 "xsltIf: test %s\n", comp->test));
5289#endif
5290
5291#ifdef XSLT_FAST_IF
5292    {
5293	xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
5294	xmlDocPtr oldXPContextDoc = xpctxt->doc;
5295	xmlNsPtr *oldXPNamespaces = xpctxt->namespaces;
5296	xmlNodePtr oldXPContextNode = xpctxt->node;
5297	int oldXPProximityPosition = xpctxt->proximityPosition;
5298	int oldXPContextSize = xpctxt->contextSize;
5299	int oldXPNsNr = xpctxt->nsNr;
5300	xmlDocPtr oldLocalFragmentTop = ctxt->localRVT;
5301
5302	xpctxt->node = contextNode;
5303	if (comp != NULL) {
5304
5305#ifdef XSLT_REFACTORED
5306	    if (comp->inScopeNs != NULL) {
5307		xpctxt->namespaces = comp->inScopeNs->list;
5308		xpctxt->nsNr = comp->inScopeNs->xpathNumber;
5309	    } else {
5310		xpctxt->namespaces = NULL;
5311		xpctxt->nsNr = 0;
5312	    }
5313#else
5314	    xpctxt->namespaces = comp->nsList;
5315	    xpctxt->nsNr = comp->nsNr;
5316#endif
5317	} else {
5318	    xpctxt->namespaces = NULL;
5319	    xpctxt->nsNr = 0;
5320	}
5321	/*
5322	* This XPath function is optimized for boolean results.
5323	*/
5324	res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt);
5325
5326	/*
5327	* Cleanup fragments created during evaluation of the
5328	* "select" expression.
5329	*/
5330	if (oldLocalFragmentTop != ctxt->localRVT)
5331	    xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
5332
5333	xpctxt->doc = oldXPContextDoc;
5334	xpctxt->node = oldXPContextNode;
5335	xpctxt->contextSize = oldXPContextSize;
5336	xpctxt->proximityPosition = oldXPProximityPosition;
5337	xpctxt->nsNr = oldXPNsNr;
5338	xpctxt->namespaces = oldXPNamespaces;
5339    }
5340
5341#ifdef WITH_XSLT_DEBUG_PROCESS
5342    XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5343	"xsltIf: test evaluate to %d\n", res));
5344#endif
5345
5346    if (res == -1) {
5347	ctxt->state = XSLT_STATE_STOPPED;
5348	goto error;
5349    }
5350    if (res == 1) {
5351	/*
5352	* Instantiate the sequence constructor of xsl:if.
5353	*/
5354	xsltApplySequenceConstructor(ctxt,
5355	    contextNode, inst->children, NULL);
5356    }
5357
5358#else /* XSLT_FAST_IF */
5359    {
5360	xmlXPathObjectPtr xpobj = NULL;
5361	/*
5362	* OLD CODE:
5363	*/
5364	{
5365	    xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
5366	    xmlDocPtr oldXPContextDoc = xpctxt->doc;
5367	    xmlNsPtr *oldXPNamespaces = xpctxt->namespaces;
5368	    xmlNodePtr oldXPContextNode = xpctxt->node;
5369	    int oldXPProximityPosition = xpctxt->proximityPosition;
5370	    int oldXPContextSize = xpctxt->contextSize;
5371	    int oldXPNsNr = xpctxt->nsNr;
5372
5373	    xpctxt->node = contextNode;
5374	    if (comp != NULL) {
5375
5376#ifdef XSLT_REFACTORED
5377		if (comp->inScopeNs != NULL) {
5378		    xpctxt->namespaces = comp->inScopeNs->list;
5379		    xpctxt->nsNr = comp->inScopeNs->xpathNumber;
5380		} else {
5381		    xpctxt->namespaces = NULL;
5382		    xpctxt->nsNr = 0;
5383		}
5384#else
5385		xpctxt->namespaces = comp->nsList;
5386		xpctxt->nsNr = comp->nsNr;
5387#endif
5388	    } else {
5389		xpctxt->namespaces = NULL;
5390		xpctxt->nsNr = 0;
5391	    }
5392
5393	    /*
5394	    * This XPath function is optimized for boolean results.
5395	    */
5396	    xpobj = xmlXPathCompiledEval(comp->comp, xpctxt);
5397
5398	    xpctxt->doc = oldXPContextDoc;
5399	    xpctxt->node = oldXPContextNode;
5400	    xpctxt->contextSize = oldXPContextSize;
5401	    xpctxt->proximityPosition = oldXPProximityPosition;
5402	    xpctxt->nsNr = oldXPNsNr;
5403	    xpctxt->namespaces = oldXPNamespaces;
5404	}
5405	if (xpobj != NULL) {
5406	    if (xpobj->type != XPATH_BOOLEAN)
5407		xpobj = xmlXPathConvertBoolean(xpobj);
5408	    if (xpobj->type == XPATH_BOOLEAN) {
5409		res = xpobj->boolval;
5410
5411#ifdef WITH_XSLT_DEBUG_PROCESS
5412		XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5413		    "xsltIf: test evaluate to %d\n", res));
5414#endif
5415		if (res) {
5416		    xsltApplySequenceConstructor(ctxt,
5417			contextNode, inst->children, NULL);
5418		}
5419	    } else {
5420
5421#ifdef WITH_XSLT_DEBUG_PROCESS
5422		XSLT_TRACE(ctxt, XSLT_TRACE_IF,
5423		    xsltGenericDebug(xsltGenericDebugContext,
5424		    "xsltIf: test didn't evaluate to a boolean\n"));
5425#endif
5426		ctxt->state = XSLT_STATE_STOPPED;
5427	    }
5428	    xmlXPathFreeObject(xpobj);
5429	} else {
5430	    ctxt->state = XSLT_STATE_STOPPED;
5431	}
5432    }
5433#endif /* else of XSLT_FAST_IF */
5434
5435error:
5436    return;
5437}
5438
5439/**
5440 * xsltForEach:
5441 * @ctxt:  an XSLT transformation context
5442 * @contextNode:  the "current node" in the source tree
5443 * @inst:  the element node of the xsl:for-each instruction
5444 * @castedComp:  the compiled information of the instruction
5445 *
5446 * Process the xslt for-each node on the source node
5447 */
5448void
5449xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5450	    xmlNodePtr inst, xsltStylePreCompPtr castedComp)
5451{
5452#ifdef XSLT_REFACTORED
5453    xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp;
5454#else
5455    xsltStylePreCompPtr comp = castedComp;
5456#endif
5457    int i;
5458    xmlXPathObjectPtr res = NULL;
5459    xmlNodePtr cur, curInst;
5460    xmlNodeSetPtr list = NULL;
5461    xmlNodeSetPtr oldList;
5462    int oldXPProximityPosition, oldXPContextSize;
5463    xmlNodePtr oldContextNode;
5464    xsltTemplatePtr oldCurTemplRule;
5465    xmlDocPtr oldXPDoc;
5466    xsltDocumentPtr oldDocInfo;
5467    xmlXPathContextPtr xpctxt;
5468
5469    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) {
5470	xsltGenericError(xsltGenericErrorContext,
5471	    "xsltForEach(): Bad arguments.\n");
5472	return;
5473    }
5474
5475    if (comp == NULL) {
5476        xsltTransformError(ctxt, NULL, inst,
5477	    "Internal error in xsltForEach(): "
5478	    "The XSLT 'for-each' instruction was not compiled.\n");
5479        return;
5480    }
5481    if ((comp->select == NULL) || (comp->comp == NULL)) {
5482	xsltTransformError(ctxt, NULL, inst,
5483	    "Internal error in xsltForEach(): "
5484	    "The selecting expression of the XSLT 'for-each' "
5485	    "instruction was not compiled correctly.\n");
5486	return;
5487    }
5488    xpctxt = ctxt->xpathCtxt;
5489
5490#ifdef WITH_XSLT_DEBUG_PROCESS
5491    XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5492	 "xsltForEach: select %s\n", comp->select));
5493#endif
5494
5495    /*
5496    * Save context states.
5497    */
5498    oldDocInfo = ctxt->document;
5499    oldList = ctxt->nodeList;
5500    oldContextNode = ctxt->node;
5501    /*
5502    * The "current template rule" is cleared for the instantiation of
5503    * xsl:for-each.
5504    */
5505    oldCurTemplRule = ctxt->currentTemplateRule;
5506    ctxt->currentTemplateRule = NULL;
5507
5508    oldXPDoc = xpctxt->doc;
5509    oldXPProximityPosition = xpctxt->proximityPosition;
5510    oldXPContextSize = xpctxt->contextSize;
5511    /*
5512    * Set up XPath.
5513    */
5514    xpctxt->node = contextNode;
5515#ifdef XSLT_REFACTORED
5516    if (comp->inScopeNs != NULL) {
5517	xpctxt->namespaces = comp->inScopeNs->list;
5518	xpctxt->nsNr = comp->inScopeNs->xpathNumber;
5519    } else {
5520	xpctxt->namespaces = NULL;
5521	xpctxt->nsNr = 0;
5522    }
5523#else
5524    xpctxt->namespaces = comp->nsList;
5525    xpctxt->nsNr = comp->nsNr;
5526#endif
5527
5528    /*
5529    * Evaluate the 'select' expression.
5530    */
5531    res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
5532
5533    if (res != NULL) {
5534	if (res->type == XPATH_NODESET)
5535	    list = res->nodesetval;
5536	else {
5537	    xsltTransformError(ctxt, NULL, inst,
5538		"The 'select' expression does not evaluate to a node set.\n");
5539
5540#ifdef WITH_XSLT_DEBUG_PROCESS
5541	    XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5542		"xsltForEach: select didn't evaluate to a node list\n"));
5543#endif
5544	    goto error;
5545	}
5546    } else {
5547	xsltTransformError(ctxt, NULL, inst,
5548	    "Failed to evaluate the 'select' expression.\n");
5549	ctxt->state = XSLT_STATE_STOPPED;
5550	goto error;
5551    }
5552
5553    if ((list == NULL) || (list->nodeNr <= 0))
5554	goto exit;
5555
5556#ifdef WITH_XSLT_DEBUG_PROCESS
5557    XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5558	"xsltForEach: select evaluates to %d nodes\n", list->nodeNr));
5559#endif
5560
5561    /*
5562    * Restore XPath states for the "current node".
5563    */
5564    xpctxt->contextSize = oldXPContextSize;
5565    xpctxt->proximityPosition = oldXPProximityPosition;
5566    xpctxt->node = contextNode;
5567
5568    /*
5569    * Set the list; this has to be done already here for xsltDoSortFunction().
5570    */
5571    ctxt->nodeList = list;
5572    /*
5573    * Handle xsl:sort instructions and skip them for further processing.
5574    * BUG TODO: We are not using namespaced potentially defined on the
5575    * xsl:sort element; XPath expression might fail.
5576    */
5577    curInst = inst->children;
5578    if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
5579	int nbsorts = 0;
5580	xmlNodePtr sorts[XSLT_MAX_SORT];
5581
5582	sorts[nbsorts++] = curInst;
5583
5584#ifdef WITH_DEBUGGER
5585	if (xslDebugStatus != XSLT_DEBUG_NONE)
5586	    xslHandleDebugger(curInst, contextNode, NULL, ctxt);
5587#endif
5588
5589	curInst = curInst->next;
5590	while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
5591	    if (nbsorts >= XSLT_MAX_SORT) {
5592		xsltTransformError(ctxt, NULL, curInst,
5593		    "The number of xsl:sort instructions exceeds the "
5594		    "maximum (%d) allowed by this processor.\n",
5595		    XSLT_MAX_SORT);
5596		goto error;
5597	    } else {
5598		sorts[nbsorts++] = curInst;
5599	    }
5600
5601#ifdef WITH_DEBUGGER
5602	    if (xslDebugStatus != XSLT_DEBUG_NONE)
5603		xslHandleDebugger(curInst, contextNode, NULL, ctxt);
5604#endif
5605	    curInst = curInst->next;
5606	}
5607	xsltDoSortFunction(ctxt, sorts, nbsorts);
5608    }
5609    xpctxt->contextSize = list->nodeNr;
5610    /*
5611    * Instantiate the sequence constructor for each selected node.
5612    */
5613    for (i = 0; i < list->nodeNr; i++) {
5614	cur = list->nodeTab[i];
5615	/*
5616	* The selected node becomes the "current node".
5617	*/
5618	ctxt->node = cur;
5619	/*
5620	* An xsl:for-each can change the current context doc.
5621	* OPTIMIZE TODO: Get rid of the need to set the context doc.
5622	*/
5623	if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
5624	    xpctxt->doc = cur->doc;
5625
5626	xpctxt->proximityPosition = i + 1;
5627
5628	xsltApplySequenceConstructor(ctxt, cur, curInst, NULL);
5629    }
5630
5631exit:
5632error:
5633    if (res != NULL)
5634	xmlXPathFreeObject(res);
5635    /*
5636    * Restore old states.
5637    */
5638    ctxt->document = oldDocInfo;
5639    ctxt->nodeList = oldList;
5640    ctxt->node = oldContextNode;
5641    ctxt->currentTemplateRule = oldCurTemplRule;
5642
5643    xpctxt->doc = oldXPDoc;
5644    xpctxt->contextSize = oldXPContextSize;
5645    xpctxt->proximityPosition = oldXPProximityPosition;
5646}
5647
5648/************************************************************************
5649 *									*
5650 *			Generic interface				*
5651 *									*
5652 ************************************************************************/
5653
5654#ifdef XSLT_GENERATE_HTML_DOCTYPE
5655typedef struct xsltHTMLVersion {
5656    const char *version;
5657    const char *public;
5658    const char *system;
5659} xsltHTMLVersion;
5660
5661static xsltHTMLVersion xsltHTMLVersions[] = {
5662    { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5663      "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
5664    { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
5665      "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
5666    { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5667      "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5668    { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
5669      "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5670    { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
5671      "http://www.w3.org/TR/html4/strict.dtd"},
5672    { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5673      "http://www.w3.org/TR/html4/loose.dtd"},
5674    { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5675      "http://www.w3.org/TR/html4/frameset.dtd"},
5676    { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
5677      "http://www.w3.org/TR/html4/loose.dtd"},
5678    { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL }
5679};
5680
5681/**
5682 * xsltGetHTMLIDs:
5683 * @version:  the version string
5684 * @publicID:  used to return the public ID
5685 * @systemID:  used to return the system ID
5686 *
5687 * Returns -1 if not found, 0 otherwise and the system and public
5688 *         Identifier for this given verion of HTML
5689 */
5690static int
5691xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
5692	            const xmlChar **systemID) {
5693    unsigned int i;
5694    if (version == NULL)
5695	return(-1);
5696    for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1]));
5697	 i++) {
5698	if (!xmlStrcasecmp(version,
5699		           (const xmlChar *) xsltHTMLVersions[i].version)) {
5700	    if (publicID != NULL)
5701		*publicID = (const xmlChar *) xsltHTMLVersions[i].public;
5702	    if (systemID != NULL)
5703		*systemID = (const xmlChar *) xsltHTMLVersions[i].system;
5704	    return(0);
5705	}
5706    }
5707    return(-1);
5708}
5709#endif
5710
5711/**
5712 * xsltApplyStripSpaces:
5713 * @ctxt:  a XSLT process context
5714 * @node:  the root of the XML tree
5715 *
5716 * Strip the unwanted ignorable spaces from the input tree
5717 */
5718void
5719xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) {
5720    xmlNodePtr current;
5721#ifdef WITH_XSLT_DEBUG_PROCESS
5722    int nb = 0;
5723#endif
5724
5725
5726    current = node;
5727    while (current != NULL) {
5728	/*
5729	 * Cleanup children empty nodes if asked for
5730	 */
5731	if ((IS_XSLT_REAL_NODE(current)) &&
5732	    (current->children != NULL) &&
5733	    (xsltFindElemSpaceHandling(ctxt, current))) {
5734	    xmlNodePtr delete = NULL, cur = current->children;
5735
5736	    while (cur != NULL) {
5737		if (IS_BLANK_NODE(cur))
5738		    delete = cur;
5739
5740		cur = cur->next;
5741		if (delete != NULL) {
5742		    xmlUnlinkNode(delete);
5743		    xmlFreeNode(delete);
5744		    delete = NULL;
5745#ifdef WITH_XSLT_DEBUG_PROCESS
5746		    nb++;
5747#endif
5748		}
5749	    }
5750	}
5751
5752	/*
5753	 * Skip to next node in document order.
5754	 */
5755	if (node->type == XML_ENTITY_REF_NODE) {
5756	    /* process deep in entities */
5757	    xsltApplyStripSpaces(ctxt, node->children);
5758	}
5759	if ((current->children != NULL) &&
5760            (current->type != XML_ENTITY_REF_NODE)) {
5761	    current = current->children;
5762	} else if (current->next != NULL) {
5763	    current = current->next;
5764	} else {
5765	    do {
5766		current = current->parent;
5767		if (current == NULL)
5768		    break;
5769		if (current == node)
5770		    goto done;
5771		if (current->next != NULL) {
5772		    current = current->next;
5773		    break;
5774		}
5775	    } while (current != NULL);
5776	}
5777    }
5778
5779done:
5780#ifdef WITH_XSLT_DEBUG_PROCESS
5781    XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext,
5782	     "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb));
5783#endif
5784    return;
5785}
5786
5787static int
5788xsltCountKeys(xsltTransformContextPtr ctxt)
5789{
5790    xsltStylesheetPtr style;
5791    xsltKeyDefPtr keyd;
5792
5793    if (ctxt == NULL)
5794	return(-1);
5795
5796    /*
5797    * Do we have those nastly templates with a key() in the match pattern?
5798    */
5799    ctxt->hasTemplKeyPatterns = 0;
5800    style = ctxt->style;
5801    while (style != NULL) {
5802	if (style->keyMatch != NULL) {
5803	    ctxt->hasTemplKeyPatterns = 1;
5804	    break;
5805	}
5806	style = xsltNextImport(style);
5807    }
5808    /*
5809    * Count number of key declarations.
5810    */
5811    ctxt->nbKeys = 0;
5812    style = ctxt->style;
5813    while (style != NULL) {
5814	keyd = style->keys;
5815	while (keyd) {
5816	    ctxt->nbKeys++;
5817	    keyd = keyd->next;
5818	}
5819	style = xsltNextImport(style);
5820    }
5821    return(ctxt->nbKeys);
5822}
5823
5824/**
5825 * xsltApplyStylesheetInternal:
5826 * @style:  a parsed XSLT stylesheet
5827 * @doc:  a parsed XML document
5828 * @params:  a NULL terminated array of parameters names/values tuples
5829 * @output:  the targetted output
5830 * @profile:  profile FILE * output or NULL
5831 * @user:  user provided parameter
5832 *
5833 * Apply the stylesheet to the document
5834 * NOTE: This may lead to a non-wellformed output XML wise !
5835 *
5836 * Returns the result document or NULL in case of error
5837 */
5838static xmlDocPtr
5839xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
5840                            const char **params, const char *output,
5841                            FILE * profile, xsltTransformContextPtr userCtxt)
5842{
5843    xmlDocPtr res = NULL;
5844    xsltTransformContextPtr ctxt = NULL;
5845    xmlNodePtr root, node;
5846    const xmlChar *method;
5847    const xmlChar *doctypePublic;
5848    const xmlChar *doctypeSystem;
5849    const xmlChar *version;
5850    const xmlChar *encoding;
5851    xsltStackElemPtr variables;
5852    xsltStackElemPtr vptr;
5853
5854    xsltInitGlobals();
5855
5856    if ((style == NULL) || (doc == NULL))
5857        return (NULL);
5858
5859    if (style->internalized == 0) {
5860#ifdef WITH_XSLT_DEBUG
5861	xsltGenericDebug(xsltGenericDebugContext,
5862			 "Stylesheet was not fully internalized !\n");
5863#endif
5864    }
5865    if (doc->intSubset != NULL) {
5866	/*
5867	 * Avoid hitting the DTD when scanning nodes
5868	 * but keep it linked as doc->intSubset
5869	 */
5870	xmlNodePtr cur = (xmlNodePtr) doc->intSubset;
5871	if (cur->next != NULL)
5872	    cur->next->prev = cur->prev;
5873	if (cur->prev != NULL)
5874	    cur->prev->next = cur->next;
5875	if (doc->children == cur)
5876	    doc->children = cur->next;
5877	if (doc->last == cur)
5878	    doc->last = cur->prev;
5879	cur->prev = cur->next = NULL;
5880    }
5881
5882    /*
5883     * Check for XPath document order availability
5884     */
5885    root = xmlDocGetRootElement(doc);
5886    if (root != NULL) {
5887	if (((long) root->content) >= 0 && (xslDebugStatus == XSLT_DEBUG_NONE))
5888	    xmlXPathOrderDocElems(doc);
5889    }
5890
5891    if (userCtxt != NULL)
5892	ctxt = userCtxt;
5893    else
5894	ctxt = xsltNewTransformContext(style, doc);
5895
5896    if (ctxt == NULL)
5897        return (NULL);
5898
5899    ctxt->initialContextDoc = doc;
5900    ctxt->initialContextNode = (xmlNodePtr) doc;
5901
5902    if (profile != NULL)
5903        ctxt->profile = 1;
5904
5905    if (output != NULL)
5906        ctxt->outputFile = output;
5907    else
5908        ctxt->outputFile = NULL;
5909
5910    /*
5911     * internalize the modes if needed
5912     */
5913    if (ctxt->dict != NULL) {
5914        if (ctxt->mode != NULL)
5915	    ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1);
5916        if (ctxt->modeURI != NULL)
5917	    ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1);
5918    }
5919
5920    XSLT_GET_IMPORT_PTR(method, style, method)
5921    XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
5922    XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
5923    XSLT_GET_IMPORT_PTR(version, style, version)
5924    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
5925
5926    if ((method != NULL) &&
5927	(!xmlStrEqual(method, (const xmlChar *) "xml")))
5928    {
5929        if (xmlStrEqual(method, (const xmlChar *) "html")) {
5930            ctxt->type = XSLT_OUTPUT_HTML;
5931            if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
5932                res = htmlNewDoc(doctypeSystem, doctypePublic);
5933	    } else {
5934                if (version == NULL) {
5935		    xmlDtdPtr dtd;
5936
5937		    res = htmlNewDoc(NULL, NULL);
5938		    /*
5939		    * Make sure no DTD node is generated in this case
5940		    */
5941		    if (res != NULL) {
5942			dtd = xmlGetIntSubset(res);
5943			if (dtd != NULL) {
5944			    xmlUnlinkNode((xmlNodePtr) dtd);
5945			    xmlFreeDtd(dtd);
5946			}
5947			res->intSubset = NULL;
5948			res->extSubset = NULL;
5949		    }
5950		} else {
5951
5952#ifdef XSLT_GENERATE_HTML_DOCTYPE
5953		    xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
5954#endif
5955		    res = htmlNewDoc(doctypeSystem, doctypePublic);
5956		}
5957            }
5958            if (res == NULL)
5959                goto error;
5960	    res->dict = ctxt->dict;
5961	    xmlDictReference(res->dict);
5962
5963#ifdef WITH_XSLT_DEBUG
5964	    xsltGenericDebug(xsltGenericDebugContext,
5965		"reusing transformation dict for output\n");
5966#endif
5967        } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
5968	    xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5969		"xsltApplyStylesheetInternal: unsupported method xhtml, using html\n",
5970		style->method);
5971            ctxt->type = XSLT_OUTPUT_HTML;
5972            res = htmlNewDoc(doctypeSystem, doctypePublic);
5973            if (res == NULL)
5974                goto error;
5975	    res->dict = ctxt->dict;
5976	    xmlDictReference(res->dict);
5977
5978#ifdef WITH_XSLT_DEBUG
5979	    xsltGenericDebug(xsltGenericDebugContext,
5980		"reusing transformation dict for output\n");
5981#endif
5982        } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
5983            ctxt->type = XSLT_OUTPUT_TEXT;
5984            res = xmlNewDoc(style->version);
5985            if (res == NULL)
5986                goto error;
5987	    res->dict = ctxt->dict;
5988	    xmlDictReference(res->dict);
5989
5990#ifdef WITH_XSLT_DEBUG
5991	    xsltGenericDebug(xsltGenericDebugContext,
5992		"reusing transformation dict for output\n");
5993#endif
5994        } else {
5995	    xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5996		"xsltApplyStylesheetInternal: unsupported method %s\n",
5997		style->method);
5998            goto error;
5999        }
6000    } else {
6001        ctxt->type = XSLT_OUTPUT_XML;
6002        res = xmlNewDoc(style->version);
6003        if (res == NULL)
6004            goto error;
6005	res->dict = ctxt->dict;
6006	xmlDictReference(ctxt->dict);
6007#ifdef WITH_XSLT_DEBUG
6008	xsltGenericDebug(xsltGenericDebugContext,
6009			 "reusing transformation dict for output\n");
6010#endif
6011    }
6012    res->charset = XML_CHAR_ENCODING_UTF8;
6013    if (encoding != NULL)
6014        res->encoding = xmlStrdup(encoding);
6015    variables = style->variables;
6016
6017    /*
6018     * Start the evaluation, evaluate the params, the stylesheets globals
6019     * and start by processing the top node.
6020     */
6021    if (xsltNeedElemSpaceHandling(ctxt))
6022	xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
6023    /*
6024    * Evaluate global params and user-provided params.
6025    */
6026    ctxt->node = (xmlNodePtr) doc;
6027    if (ctxt->globalVars == NULL)
6028	ctxt->globalVars = xmlHashCreate(20);
6029    if (params != NULL) {
6030        xsltEvalUserParams(ctxt, params);
6031    }
6032
6033    /* need to be called before evaluating global variables */
6034    xsltCountKeys(ctxt);
6035
6036    xsltEvalGlobalVariables(ctxt);
6037
6038    ctxt->node = (xmlNodePtr) doc;
6039    ctxt->output = res;
6040    ctxt->insert = (xmlNodePtr) res;
6041    ctxt->varsBase = ctxt->varsNr - 1;
6042
6043    ctxt->xpathCtxt->contextSize = 1;
6044    ctxt->xpathCtxt->proximityPosition = 1;
6045    ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */
6046    /*
6047    * Start processing the source tree -----------------------------------
6048    */
6049    xsltProcessOneNode(ctxt, ctxt->node, NULL);
6050    /*
6051    * Remove all remaining vars from the stack.
6052    */
6053    xsltLocalVariablePop(ctxt, 0, -2);
6054    xsltShutdownCtxtExts(ctxt);
6055
6056    xsltCleanupTemplates(style); /* TODO: <- style should be read only */
6057
6058    /*
6059     * Now cleanup our variables so stylesheet can be re-used
6060     *
6061     * TODO: this is not needed anymore global variables are copied
6062     *       and not evaluated directly anymore, keep this as a check
6063     */
6064    if (style->variables != variables) {
6065        vptr = style->variables;
6066        while (vptr->next != variables)
6067            vptr = vptr->next;
6068        vptr->next = NULL;
6069        xsltFreeStackElemList(style->variables);
6070        style->variables = variables;
6071    }
6072    vptr = style->variables;
6073    while (vptr != NULL) {
6074        if (vptr->computed) {
6075            if (vptr->value != NULL) {
6076                xmlXPathFreeObject(vptr->value);
6077                vptr->value = NULL;
6078                vptr->computed = 0;
6079            }
6080        }
6081        vptr = vptr->next;
6082    }
6083#if 0
6084    /*
6085     * code disabled by wmb; awaiting kb's review
6086     * problem is that global variable(s) may contain xpath objects
6087     * from doc associated with RVT, so can't be freed at this point.
6088     * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
6089     * I assume this shouldn't be required at this point.
6090     */
6091    /*
6092    * Free all remaining tree fragments.
6093    */
6094    xsltFreeRVTs(ctxt);
6095#endif
6096    /*
6097     * Do some post processing work depending on the generated output
6098     */
6099    root = xmlDocGetRootElement(res);
6100    if (root != NULL) {
6101        const xmlChar *doctype = NULL;
6102
6103        if ((root->ns != NULL) && (root->ns->prefix != NULL))
6104	    doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
6105	if (doctype == NULL)
6106	    doctype = root->name;
6107
6108        /*
6109         * Apply the default selection of the method
6110         */
6111        if ((method == NULL) &&
6112            (root->ns == NULL) &&
6113            (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
6114            xmlNodePtr tmp;
6115
6116            tmp = res->children;
6117            while ((tmp != NULL) && (tmp != root)) {
6118                if (tmp->type == XML_ELEMENT_NODE)
6119                    break;
6120                if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
6121                    break;
6122		tmp = tmp->next;
6123            }
6124            if (tmp == root) {
6125                ctxt->type = XSLT_OUTPUT_HTML;
6126		/*
6127		* REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
6128		*  transformation on the doc, but functions like
6129		*/
6130                res->type = XML_HTML_DOCUMENT_NODE;
6131                if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
6132                    res->intSubset = xmlCreateIntSubset(res, doctype,
6133                                                        doctypePublic,
6134                                                        doctypeSystem);
6135#ifdef XSLT_GENERATE_HTML_DOCTYPE
6136		} else if (version != NULL) {
6137                    xsltGetHTMLIDs(version, &doctypePublic,
6138                                   &doctypeSystem);
6139                    if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
6140                        res->intSubset =
6141                            xmlCreateIntSubset(res, doctype,
6142                                               doctypePublic,
6143                                               doctypeSystem);
6144#endif
6145                }
6146            }
6147
6148        }
6149        if (ctxt->type == XSLT_OUTPUT_XML) {
6150            XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
6151            XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
6152            if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
6153	        xmlNodePtr last;
6154		/* Need a small "hack" here to assure DTD comes before
6155		   possible comment nodes */
6156		node = res->children;
6157		last = res->last;
6158		res->children = NULL;
6159		res->last = NULL;
6160                res->intSubset = xmlCreateIntSubset(res, doctype,
6161                                                    doctypePublic,
6162                                                    doctypeSystem);
6163		if (res->children != NULL) {
6164		    res->children->next = node;
6165		    node->prev = res->children;
6166		    res->last = last;
6167		} else {
6168		    res->children = node;
6169		    res->last = last;
6170		}
6171	    }
6172        }
6173    }
6174    xmlXPathFreeNodeSet(ctxt->nodeList);
6175    if (profile != NULL) {
6176        xsltSaveProfiling(ctxt, profile);
6177    }
6178
6179    /*
6180     * Be pedantic.
6181     */
6182    if ((ctxt != NULL) && (ctxt->state == XSLT_STATE_ERROR)) {
6183	xmlFreeDoc(res);
6184	res = NULL;
6185    }
6186    if ((res != NULL) && (ctxt != NULL) && (output != NULL)) {
6187	int ret;
6188
6189	ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output);
6190	if (ret == 0) {
6191	    xsltTransformError(ctxt, NULL, NULL,
6192		     "xsltApplyStylesheet: forbidden to save to %s\n",
6193			       output);
6194	} else if (ret < 0) {
6195	    xsltTransformError(ctxt, NULL, NULL,
6196		     "xsltApplyStylesheet: saving to %s may not be possible\n",
6197			       output);
6198	}
6199    }
6200
6201#ifdef XSLT_DEBUG_PROFILE_CACHE
6202    printf("# Cache:\n");
6203    printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
6204    printf("# Reused variables     : %d\n", ctxt->cache->dbgReusedVars);
6205#endif
6206
6207    if ((ctxt != NULL) && (userCtxt == NULL))
6208	xsltFreeTransformContext(ctxt);
6209
6210    return (res);
6211
6212error:
6213    if (res != NULL)
6214        xmlFreeDoc(res);
6215
6216#ifdef XSLT_DEBUG_PROFILE_CACHE
6217    printf("# Cache:\n");
6218    printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
6219    printf("# Reused variables     : %d\n", ctxt->cache->dbgReusedVars);
6220#endif
6221
6222    if ((ctxt != NULL) && (userCtxt == NULL))
6223        xsltFreeTransformContext(ctxt);
6224    return (NULL);
6225}
6226
6227/**
6228 * xsltApplyStylesheet:
6229 * @style:  a parsed XSLT stylesheet
6230 * @doc:  a parsed XML document
6231 * @params:  a NULL terminated arry of parameters names/values tuples
6232 *
6233 * Apply the stylesheet to the document
6234 * NOTE: This may lead to a non-wellformed output XML wise !
6235 *
6236 * Returns the result document or NULL in case of error
6237 */
6238xmlDocPtr
6239xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6240                    const char **params)
6241{
6242    return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL));
6243}
6244
6245/**
6246 * xsltProfileStylesheet:
6247 * @style:  a parsed XSLT stylesheet
6248 * @doc:  a parsed XML document
6249 * @params:  a NULL terminated arry of parameters names/values tuples
6250 * @output:  a FILE * for the profiling output
6251 *
6252 * Apply the stylesheet to the document and dump the profiling to
6253 * the given output.
6254 *
6255 * Returns the result document or NULL in case of error
6256 */
6257xmlDocPtr
6258xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6259                      const char **params, FILE * output)
6260{
6261    xmlDocPtr res;
6262
6263    res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL);
6264    return (res);
6265}
6266
6267/**
6268 * xsltApplyStylesheetUser:
6269 * @style:  a parsed XSLT stylesheet
6270 * @doc:  a parsed XML document
6271 * @params:  a NULL terminated array of parameters names/values tuples
6272 * @output:  the targetted output
6273 * @profile:  profile FILE * output or NULL
6274 * @userCtxt:  user provided transform context
6275 *
6276 * Apply the stylesheet to the document and allow the user to provide
6277 * its own transformation context.
6278 *
6279 * Returns the result document or NULL in case of error
6280 */
6281xmlDocPtr
6282xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
6283                            const char **params, const char *output,
6284                            FILE * profile, xsltTransformContextPtr userCtxt)
6285{
6286    xmlDocPtr res;
6287
6288    res = xsltApplyStylesheetInternal(style, doc, params, output,
6289	                              profile, userCtxt);
6290    return (res);
6291}
6292
6293/**
6294 * xsltRunStylesheetUser:
6295 * @style:  a parsed XSLT stylesheet
6296 * @doc:  a parsed XML document
6297 * @params:  a NULL terminated array of parameters names/values tuples
6298 * @output:  the URL/filename ot the generated resource if available
6299 * @SAX:  a SAX handler for progressive callback output (not implemented yet)
6300 * @IObuf:  an output buffer for progressive output (not implemented yet)
6301 * @profile:  profile FILE * output or NULL
6302 * @userCtxt:  user provided transform context
6303 *
6304 * Apply the stylesheet to the document and generate the output according
6305 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6306 *
6307 * NOTE: This may lead to a non-wellformed output XML wise !
6308 * NOTE: This may also result in multiple files being generated
6309 * NOTE: using IObuf, the result encoding used will be the one used for
6310 *       creating the output buffer, use the following macro to read it
6311 *       from the stylesheet
6312 *       XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6313 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6314 *       since the interface uses only UTF8
6315 *
6316 * Returns the number of by written to the main resource or -1 in case of
6317 *         error.
6318 */
6319int
6320xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
6321                  const char **params, const char *output,
6322                  xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf,
6323		  FILE * profile, xsltTransformContextPtr userCtxt)
6324{
6325    xmlDocPtr tmp;
6326    int ret;
6327
6328    if ((output == NULL) && (SAX == NULL) && (IObuf == NULL))
6329        return (-1);
6330    if ((SAX != NULL) && (IObuf != NULL))
6331        return (-1);
6332
6333    /* unsupported yet */
6334    if (SAX != NULL) {
6335        XSLT_TODO   /* xsltRunStylesheet xmlSAXHandlerPtr SAX */
6336	return (-1);
6337    }
6338
6339    tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile,
6340	                              userCtxt);
6341    if (tmp == NULL) {
6342	xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
6343                         "xsltRunStylesheet : run failed\n");
6344        return (-1);
6345    }
6346    if (IObuf != NULL) {
6347        /* TODO: incomplete, IObuf output not progressive */
6348        ret = xsltSaveResultTo(IObuf, tmp, style);
6349    } else {
6350        ret = xsltSaveResultToFilename(output, tmp, style, 0);
6351    }
6352    xmlFreeDoc(tmp);
6353    return (ret);
6354}
6355
6356/**
6357 * xsltRunStylesheet:
6358 * @style:  a parsed XSLT stylesheet
6359 * @doc:  a parsed XML document
6360 * @params:  a NULL terminated array of parameters names/values tuples
6361 * @output:  the URL/filename ot the generated resource if available
6362 * @SAX:  a SAX handler for progressive callback output (not implemented yet)
6363 * @IObuf:  an output buffer for progressive output (not implemented yet)
6364 *
6365 * Apply the stylesheet to the document and generate the output according
6366 * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6367 *
6368 * NOTE: This may lead to a non-wellformed output XML wise !
6369 * NOTE: This may also result in multiple files being generated
6370 * NOTE: using IObuf, the result encoding used will be the one used for
6371 *       creating the output buffer, use the following macro to read it
6372 *       from the stylesheet
6373 *       XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6374 * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6375 *       since the interface uses only UTF8
6376 *
6377 * Returns the number of bytes written to the main resource or -1 in case of
6378 *         error.
6379 */
6380int
6381xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6382                  const char **params, const char *output,
6383                  xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf)
6384{
6385    return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf,
6386		                 NULL, NULL));
6387}
6388
6389/**
6390 * xsltRegisterAllElement:
6391 * @ctxt:  the XPath context
6392 *
6393 * Registers all default XSLT elements in this context
6394 */
6395void
6396xsltRegisterAllElement(xsltTransformContextPtr ctxt)
6397{
6398    xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates",
6399                           XSLT_NAMESPACE,
6400			   (xsltTransformFunction) xsltApplyTemplates);
6401    xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports",
6402                           XSLT_NAMESPACE,
6403			   (xsltTransformFunction) xsltApplyImports);
6404    xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template",
6405                           XSLT_NAMESPACE,
6406			   (xsltTransformFunction) xsltCallTemplate);
6407    xsltRegisterExtElement(ctxt, (const xmlChar *) "element",
6408                           XSLT_NAMESPACE,
6409			   (xsltTransformFunction) xsltElement);
6410    xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute",
6411                           XSLT_NAMESPACE,
6412			   (xsltTransformFunction) xsltAttribute);
6413    xsltRegisterExtElement(ctxt, (const xmlChar *) "text",
6414                           XSLT_NAMESPACE,
6415			   (xsltTransformFunction) xsltText);
6416    xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction",
6417                           XSLT_NAMESPACE,
6418			   (xsltTransformFunction) xsltProcessingInstruction);
6419    xsltRegisterExtElement(ctxt, (const xmlChar *) "comment",
6420                           XSLT_NAMESPACE,
6421			   (xsltTransformFunction) xsltComment);
6422    xsltRegisterExtElement(ctxt, (const xmlChar *) "copy",
6423                           XSLT_NAMESPACE,
6424			   (xsltTransformFunction) xsltCopy);
6425    xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of",
6426                           XSLT_NAMESPACE,
6427			   (xsltTransformFunction) xsltValueOf);
6428    xsltRegisterExtElement(ctxt, (const xmlChar *) "number",
6429                           XSLT_NAMESPACE,
6430			   (xsltTransformFunction) xsltNumber);
6431    xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each",
6432                           XSLT_NAMESPACE,
6433			   (xsltTransformFunction) xsltForEach);
6434    xsltRegisterExtElement(ctxt, (const xmlChar *) "if",
6435                           XSLT_NAMESPACE,
6436			   (xsltTransformFunction) xsltIf);
6437    xsltRegisterExtElement(ctxt, (const xmlChar *) "choose",
6438                           XSLT_NAMESPACE,
6439			   (xsltTransformFunction) xsltChoose);
6440    xsltRegisterExtElement(ctxt, (const xmlChar *) "sort",
6441                           XSLT_NAMESPACE,
6442			   (xsltTransformFunction) xsltSort);
6443    xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of",
6444                           XSLT_NAMESPACE,
6445			   (xsltTransformFunction) xsltCopyOf);
6446    xsltRegisterExtElement(ctxt, (const xmlChar *) "message",
6447                           XSLT_NAMESPACE,
6448			   (xsltTransformFunction) xsltMessage);
6449
6450    /*
6451     * Those don't have callable entry points but are registered anyway
6452     */
6453    xsltRegisterExtElement(ctxt, (const xmlChar *) "variable",
6454                           XSLT_NAMESPACE,
6455			   (xsltTransformFunction) xsltDebug);
6456    xsltRegisterExtElement(ctxt, (const xmlChar *) "param",
6457                           XSLT_NAMESPACE,
6458			   (xsltTransformFunction) xsltDebug);
6459    xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param",
6460                           XSLT_NAMESPACE,
6461			   (xsltTransformFunction) xsltDebug);
6462    xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format",
6463                           XSLT_NAMESPACE,
6464			   (xsltTransformFunction) xsltDebug);
6465    xsltRegisterExtElement(ctxt, (const xmlChar *) "when",
6466                           XSLT_NAMESPACE,
6467			   (xsltTransformFunction) xsltDebug);
6468    xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise",
6469                           XSLT_NAMESPACE,
6470			   (xsltTransformFunction) xsltDebug);
6471    xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback",
6472                           XSLT_NAMESPACE,
6473			   (xsltTransformFunction) xsltDebug);
6474
6475}
6476