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