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