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