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