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