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