text: /*
   * transform.c: Implementation of the XSL Transformation 1.0 engine
   *              transform part, i.e. applying a Stylesheet to a document
   *
   * References:
   *   http://www.w3.org/TR/1999/REC-xslt-19991116
   *
   *   Michael Kay "XSLT Programmer's Reference" pp 637-643
   *   Writing Multiple Output Files
   *
   *   XSLT-1.1 Working Draft
   *   http://www.w3.org/TR/xslt11#multiple-output
   *
   * See Copyright for the status of this software.
   *
   * daniel@veillard.com
   */
  
  #define IN_LIBXSLT
  #include "libxslt.h"
  
  #include <limits.h>
  #include <string.h>
  #include <stdio.h>
  #include <stddef.h>
  
  #include <libxml/xmlmemory.h>
  #include <libxml/parser.h>
  #include <libxml/tree.h>
  #include <libxml/valid.h>
  #include <libxml/hash.h>
  #include <libxml/encoding.h>
  #include <libxml/xmlerror.h>
  #include <libxml/xpath.h>
  #include <libxml/parserInternals.h>
  #include <libxml/xpathInternals.h>
  #include <libxml/HTMLtree.h>
  #include <libxml/debugXML.h>
  #include <libxml/uri.h>
  #include "xslt.h"
  #include "xsltInternals.h"
  #include "xsltutils.h"
  #include "pattern.h"
  #include "transform.h"
  #include "variables.h"
  #include "numbersInternals.h"
  #include "namespaces.h"
  #include "attributes.h"
  #include "templates.h"
  #include "imports.h"
  #include "keys.h"
  #include "documents.h"
  #include "extensions.h"
  #include "extra.h"
  #include "preproc.h"
  #include "security.h"
  
  #ifdef WITH_XSLT_DEBUG
  #define WITH_XSLT_DEBUG_EXTRA
  #define WITH_XSLT_DEBUG_PROCESS
  #define WITH_XSLT_DEBUG_VARIABLE
  #endif
  
  #define XSLT_GENERATE_HTML_DOCTYPE
  #ifdef XSLT_GENERATE_HTML_DOCTYPE
  static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
  			  const xmlChar **systemID);
  #endif
  
  int xsltMaxDepth = 3000;
  int xsltMaxVars = 15000;
  
  /*
   * Useful macros
   */
  
  #ifndef FALSE
  # define FALSE (0 == 1)
  # define TRUE (!FALSE)
  #endif
  
  #define IS_BLANK_NODE(n)						\
      (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
  
  
  /*
  * Forward declarations
  */
  
  static xmlNsPtr
  xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur);
  
  static xmlNodePtr
  xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
  	     xmlNodePtr node, xmlNodePtr insert, int isLRE,
  	     int topElemVisited);
  
  static void
  xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
  			     xmlNodePtr contextNode, xmlNodePtr list,
  			     xsltTemplatePtr templ);
  
  static void
  xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
  		      xmlNodePtr contextNode,
  		      xmlNodePtr list,
  		      xsltTemplatePtr templ,
  		      xsltStackElemPtr withParams);
  
  /**
   * templPush:
   * @ctxt: the transformation context
   * @value:  the template to push on the stack
   *
   * Push a template on the stack
   *
   * Returns the new index in the stack or 0 in case of error
   */
  static int
  templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value)
  {
      if (ctxt->templMax == 0) {
          ctxt->templMax = 4;
          ctxt->templTab =
              (xsltTemplatePtr *) xmlMalloc(ctxt->templMax *
                                            sizeof(ctxt->templTab[0]));
          if (ctxt->templTab == NULL) {
              xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
              return (0);
          }
      }
      else if (ctxt->templNr >= ctxt->templMax) {
          ctxt->templMax *= 2;
          ctxt->templTab =
              (xsltTemplatePtr *) xmlRealloc(ctxt->templTab,
                                             ctxt->templMax *
                                             sizeof(ctxt->templTab[0]));
          if (ctxt->templTab == NULL) {
              xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
              return (0);
          }
      }
      ctxt->templTab[ctxt->templNr] = value;
      ctxt->templ = value;
      return (ctxt->templNr++);
  }
  /**
   * templPop:
   * @ctxt: the transformation context
   *
   * Pop a template value from the stack
   *
   * Returns the stored template value
   */
  static xsltTemplatePtr
  templPop(xsltTransformContextPtr ctxt)
  {
      xsltTemplatePtr ret;
  
      if (ctxt->templNr <= 0)
          return (0);
      ctxt->templNr--;
      if (ctxt->templNr > 0)
          ctxt->templ = ctxt->templTab[ctxt->templNr - 1];
      else
          ctxt->templ = (xsltTemplatePtr) 0;
      ret = ctxt->templTab[ctxt->templNr];
      ctxt->templTab[ctxt->templNr] = 0;
      return (ret);
  }
  
  /**
   * xsltLocalVariablePop:
   * @ctxt: the transformation context
   * @limitNr: number of variables which should remain
   * @level: the depth in the xsl:template's tree
   *
   * Pops all variable values at the given @depth from the stack.
   *
   * Returns the stored variable value
   * **NOTE:**
   * This is an internal routine and should not be called by users!
   */
  void
  xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level)
  {
      xsltStackElemPtr variable;
  
      if (ctxt->varsNr <= 0)
          return;
  
      do {
  	if (ctxt->varsNr <= limitNr)
  	    break;
  	variable = ctxt->varsTab[ctxt->varsNr - 1];
  	if (variable->level <= level)
  	    break;
  	if (variable->level >= 0)
  	    xsltFreeStackElemList(variable);
  	ctxt->varsNr--;
      } while (ctxt->varsNr != 0);
      if (ctxt->varsNr > 0)
          ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
      else
          ctxt->vars = NULL;
  }
  
  /**
   * xsltTemplateParamsCleanup:
   *
   * Removes xsl:param and xsl:with-param items from the
   * variable-stack. Only xsl:with-param items are not freed.
   */
  static void
  xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt)
  {
      xsltStackElemPtr param;
  
      for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) {
  	param = ctxt->varsTab[ctxt->varsNr -1];
  	/*
  	* Free xsl:param items.
  	* xsl:with-param items will have a level of -1 or -2.
  	*/
  	if (param->level >= 0) {
  	    xsltFreeStackElemList(param);
  	}
      }
      if (ctxt->varsNr > 0)
          ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
      else
          ctxt->vars = NULL;
  }
  
  #ifdef WITH_PROFILER
  
  /**
   * profPush:
   * @ctxt: the transformation context
   * @value:  the profiling value to push on the stack
   *
   * Push a profiling value on the stack
   *
   * Returns the new index in the stack or 0 in case of error
   */
  static int
  profPush(xsltTransformContextPtr ctxt, long value)
  {
      if (ctxt->profMax == 0) {
          ctxt->profMax = 4;
          ctxt->profTab =
              (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0]));
          if (ctxt->profTab == NULL) {
              xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
              return (0);
          }
      }
      else if (ctxt->profNr >= ctxt->profMax) {
          ctxt->profMax *= 2;
          ctxt->profTab =
              (long *) xmlRealloc(ctxt->profTab,
                                  ctxt->profMax * sizeof(ctxt->profTab[0]));
          if (ctxt->profTab == NULL) {
              xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
              return (0);
          }
      }
      ctxt->profTab[ctxt->profNr] = value;
      ctxt->prof = value;
      return (ctxt->profNr++);
  }
  /**
   * profPop:
   * @ctxt: the transformation context
   *
   * Pop a profiling value from the stack
   *
   * Returns the stored profiling value
   */
  static long
  profPop(xsltTransformContextPtr ctxt)
  {
      long ret;
  
      if (ctxt->profNr <= 0)
          return (0);
      ctxt->profNr--;
      if (ctxt->profNr > 0)
          ctxt->prof = ctxt->profTab[ctxt->profNr - 1];
      else
          ctxt->prof = (long) 0;
      ret = ctxt->profTab[ctxt->profNr];
      ctxt->profTab[ctxt->profNr] = 0;
      return (ret);
  }
  
  static void
  profCallgraphAdd(xsltTemplatePtr templ, xsltTemplatePtr parent)
  {
      int i;
  
      if (templ->templMax == 0) {
          templ->templMax = 4;
          templ->templCalledTab =
              (xsltTemplatePtr *) xmlMalloc(templ->templMax *
                                            sizeof(templ->templCalledTab[0]));
          templ->templCountTab =
              (int *) xmlMalloc(templ->templMax *
                                            sizeof(templ->templCountTab[0]));
          if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
              xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
              return;
          }
      }
      else if (templ->templNr >= templ->templMax) {
          templ->templMax *= 2;
          templ->templCalledTab =
              (xsltTemplatePtr *) xmlRealloc(templ->templCalledTab,
                                             templ->templMax *
                                             sizeof(templ->templCalledTab[0]));
          templ->templCountTab =
              (int *) xmlRealloc(templ->templCountTab,
                                             templ->templMax *
                                             sizeof(templ->templCountTab[0]));
          if (templ->templCalledTab == NULL || templ->templCountTab == NULL) {
              xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
              return;
          }
      }
  
      for (i = 0; i < templ->templNr; i++) {
          if (templ->templCalledTab[i] == parent) {
              templ->templCountTab[i]++;
              break;
          }
      }
      if (i == templ->templNr) {
          /* not found, add new one */
          templ->templCalledTab[templ->templNr] = parent;
          templ->templCountTab[templ->templNr] = 1;
          templ->templNr++;
      }
  }
  
  #endif /* WITH_PROFILER */
  
  /**
   * xsltPreCompEval:
   * @ctxt: transform context
   * @node: context node
   * @comp: precompiled expression
   *
   * Evaluate a precompiled XPath expression.
   */
  static xmlXPathObjectPtr
  xsltPreCompEval(xsltTransformContextPtr ctxt, xmlNodePtr node,
                  xsltStylePreCompPtr comp) {
      xmlXPathObjectPtr res;
      xmlXPathContextPtr xpctxt;
      xmlNodePtr oldXPContextNode;
      xmlNsPtr *oldXPNamespaces;
      int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
  
      xpctxt = ctxt->xpathCtxt;
      oldXPContextNode = xpctxt->node;
      oldXPProximityPosition = xpctxt->proximityPosition;
      oldXPContextSize = xpctxt->contextSize;
      oldXPNsNr = xpctxt->nsNr;
      oldXPNamespaces = xpctxt->namespaces;
  
      xpctxt->node = node;
  #ifdef XSLT_REFACTORED
      if (comp->inScopeNs != NULL) {
          xpctxt->namespaces = comp->inScopeNs->list;
          xpctxt->nsNr = comp->inScopeNs->xpathNumber;
      } else {
          xpctxt->namespaces = NULL;
          xpctxt->nsNr = 0;
      }
  #else
      xpctxt->namespaces = comp->nsList;
      xpctxt->nsNr = comp->nsNr;
  #endif
  
      res = xmlXPathCompiledEval(comp->comp, xpctxt);
  
      xpctxt->node = oldXPContextNode;
      xpctxt->proximityPosition = oldXPProximityPosition;
      xpctxt->contextSize = oldXPContextSize;
      xpctxt->nsNr = oldXPNsNr;
      xpctxt->namespaces = oldXPNamespaces;
  
      return(res);
  }
  
  /**
   * xsltPreCompEvalToBoolean:
   * @ctxt: transform context
   * @node: context node
   * @comp: precompiled expression
   *
   * Evaluate a precompiled XPath expression as boolean.
   */
  static int
  xsltPreCompEvalToBoolean(xsltTransformContextPtr ctxt, xmlNodePtr node,
                           xsltStylePreCompPtr comp) {
      int res;
      xmlXPathContextPtr xpctxt;
      xmlNodePtr oldXPContextNode;
      xmlNsPtr *oldXPNamespaces;
      int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
  
      xpctxt = ctxt->xpathCtxt;
      oldXPContextNode = xpctxt->node;
      oldXPProximityPosition = xpctxt->proximityPosition;
      oldXPContextSize = xpctxt->contextSize;
      oldXPNsNr = xpctxt->nsNr;
      oldXPNamespaces = xpctxt->namespaces;
  
      xpctxt->node = node;
  #ifdef XSLT_REFACTORED
      if (comp->inScopeNs != NULL) {
          xpctxt->namespaces = comp->inScopeNs->list;
          xpctxt->nsNr = comp->inScopeNs->xpathNumber;
      } else {
          xpctxt->namespaces = NULL;
          xpctxt->nsNr = 0;
      }
  #else
      xpctxt->namespaces = comp->nsList;
      xpctxt->nsNr = comp->nsNr;
  #endif
  
      res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt);
  
      xpctxt->node = oldXPContextNode;
      xpctxt->proximityPosition = oldXPProximityPosition;
      xpctxt->contextSize = oldXPContextSize;
      xpctxt->nsNr = oldXPNsNr;
      xpctxt->namespaces = oldXPNamespaces;
  
      return(res);
  }
  
  /************************************************************************
   *									*
   *			XInclude default settings			*
   *									*
   ************************************************************************/
  
  static int xsltDoXIncludeDefault = 0;
  
  /**
   * xsltSetXIncludeDefault:
   * @xinclude: whether to do XInclude processing
   *
   * Set whether XInclude should be processed on document being loaded by default
   */
  void
  xsltSetXIncludeDefault(int xinclude) {
      xsltDoXIncludeDefault = (xinclude != 0);
  }
  
  /**
   * xsltGetXIncludeDefault:
   *
   * Provides the default state for XInclude processing
   *
   * Returns 0 if there is no processing 1 otherwise
   */
  int
  xsltGetXIncludeDefault(void) {
      return(xsltDoXIncludeDefault);
  }
  
  static unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL;
  
  /**
   * xsltDebugSetDefaultTrace:
   * @val: tracing level mask
   *
   * Set the default debug tracing level mask
   */
  void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) {
  	xsltDefaultTrace = val;
  }
  
  /**
   * xsltDebugGetDefaultTrace:
   *
   * Get the current default debug tracing level mask
   *
   * Returns the current default debug tracing level mask
   */
  xsltDebugTraceCodes xsltDebugGetDefaultTrace() {
  	return xsltDefaultTrace;
  }
  
  /************************************************************************
   *									*
   *			Handling of Transformation Contexts		*
   *									*
   ************************************************************************/
  
  static xsltTransformCachePtr
  xsltTransformCacheCreate(void)
  {
      xsltTransformCachePtr ret;
  
      ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache));
      if (ret == NULL) {
  	xsltTransformError(NULL, NULL, NULL,
  	    "xsltTransformCacheCreate : malloc failed\n");
  	return(NULL);
      }
      memset(ret, 0, sizeof(xsltTransformCache));
      return(ret);
  }
  
  static void
  xsltTransformCacheFree(xsltTransformCachePtr cache)
  {
      if (cache == NULL)
  	return;
      /*
      * Free tree fragments.
      */
      if (cache->RVT) {
  	xmlDocPtr tmp, cur = cache->RVT;
  	while (cur) {
  	    tmp = cur;
  	    cur = (xmlDocPtr) cur->next;
  	    if (tmp->_private != NULL) {
  		/*
  		* Tree the document info.
  		*/
  		xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private);
  		xmlFree(tmp->_private);
  	    }
  	    xmlFreeDoc(tmp);
  	}
      }
      /*
      * Free vars/params.
      */
      if (cache->stackItems) {
  	xsltStackElemPtr tmp, cur = cache->stackItems;
  	while (cur) {
  	    tmp = cur;
  	    cur = cur->next;
  	    /*
  	    * REVISIT TODO: Should be call a destruction-function
  	    * instead?
  	    */
  	    xmlFree(tmp);
  	}
      }
      xmlFree(cache);
  }
  
  /**
   * xsltNewTransformContext:
   * @style:  a parsed XSLT stylesheet
   * @doc:  the input document
   *
   * Create a new XSLT TransformContext
   *
   * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
   */
  xsltTransformContextPtr
  xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
      xsltTransformContextPtr cur;
      xsltDocumentPtr docu;
      int i;
  
      xsltInitGlobals();
  
      cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext));
      if (cur == NULL) {
  	xsltTransformError(NULL, NULL, (xmlNodePtr)doc,
  		"xsltNewTransformContext : malloc failed\n");
  	return(NULL);
      }
      memset(cur, 0, sizeof(xsltTransformContext));
  
      cur->cache = xsltTransformCacheCreate();
      if (cur->cache == NULL)
  	goto internal_err;
      /*
       * setup of the dictionary must be done early as some of the
       * processing later like key handling may need it.
       */
      cur->dict = xmlDictCreateSub(style->dict);
      cur->internalized = ((style->internalized) && (cur->dict != NULL));
  #ifdef WITH_XSLT_DEBUG
      xsltGenericDebug(xsltGenericDebugContext,
  	     "Creating sub-dictionary from stylesheet for transformation\n");
  #endif
  
      /*
       * initialize the template stack
       */
      cur->templTab = (xsltTemplatePtr *)
  	        xmlMalloc(10 * sizeof(xsltTemplatePtr));
      if (cur->templTab == NULL) {
  	xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
  		"xsltNewTransformContext: out of memory\n");
  	goto internal_err;
      }
      cur->templNr = 0;
      cur->templMax = 5;
      cur->templ = NULL;
      cur->maxTemplateDepth = xsltMaxDepth;
  
      /*
       * initialize the variables stack
       */
      cur->varsTab = (xsltStackElemPtr *)
  	        xmlMalloc(10 * sizeof(xsltStackElemPtr));
      if (cur->varsTab == NULL) {
          xmlGenericError(xmlGenericErrorContext,
  		"xsltNewTransformContext: out of memory\n");
  	goto internal_err;
      }
      cur->varsNr = 0;
      cur->varsMax = 10;
      cur->vars = NULL;
      cur->varsBase = 0;
      cur->maxTemplateVars = xsltMaxVars;
  
      /*
       * the profiling stack is not initialized by default
       */
      cur->profTab = NULL;
      cur->profNr = 0;
      cur->profMax = 0;
      cur->prof = 0;
  
      cur->style = style;
      xmlXPathInit();
      cur->xpathCtxt = xmlXPathNewContext(doc);
      if (cur->xpathCtxt == NULL) {
  	xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
  		"xsltNewTransformContext : xmlXPathNewContext failed\n");
  	goto internal_err;
      }
      /*
      * Create an XPath cache.
      */
      if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1)
  	goto internal_err;
      /*
       * Initialize the extras array
       */
      if (style->extrasNr != 0) {
  	cur->extrasMax = style->extrasNr + 20;
  	cur->extras = (xsltRuntimeExtraPtr)
  	    xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra));
  	if (cur->extras == NULL) {
  	    xmlGenericError(xmlGenericErrorContext,
  		    "xsltNewTransformContext: out of memory\n");
  	    goto internal_err;
  	}
  	cur->extrasNr = style->extrasNr;
  	for (i = 0;i < cur->extrasMax;i++) {
  	    cur->extras[i].info = NULL;
  	    cur->extras[i].deallocate = NULL;
  	    cur->extras[i].val.ptr = NULL;
  	}
      } else {
  	cur->extras = NULL;
  	cur->extrasNr = 0;
  	cur->extrasMax = 0;
      }
  
      XSLT_REGISTER_VARIABLE_LOOKUP(cur);
      XSLT_REGISTER_FUNCTION_LOOKUP(cur);
      cur->xpathCtxt->nsHash = style->nsHash;
      /*
       * Initialize the registered external modules
       */
      xsltInitCtxtExts(cur);
      /*
       * Setup document element ordering for later efficiencies
       * (bug 133289)
       */
      if (xslDebugStatus == XSLT_DEBUG_NONE)
          xmlXPathOrderDocElems(doc);
      /*
       * Must set parserOptions before calling xsltNewDocument
       * (bug 164530)
       */
      cur->parserOptions = XSLT_PARSE_OPTIONS;
      docu = xsltNewDocument(cur, doc);
      if (docu == NULL) {
  	xsltTransformError(cur, NULL, (xmlNodePtr)doc,
  		"xsltNewTransformContext : xsltNewDocument failed\n");
  	goto internal_err;
      }
      docu->main = 1;
      cur->document = docu;
      cur->inst = NULL;
      cur->outputFile = NULL;
      cur->sec = xsltGetDefaultSecurityPrefs();
      cur->debugStatus = xslDebugStatus;
      cur->traceCode = (unsigned long*) &xsltDefaultTrace;
      cur->xinclude = xsltGetXIncludeDefault();
      cur->keyInitLevel = 0;
  
      return(cur);
  
  internal_err:
      if (cur != NULL)
  	xsltFreeTransformContext(cur);
      return(NULL);
  }
  
  /**
   * xsltFreeTransformContext:
   * @ctxt:  an XSLT parser context
   *
   * Free up the memory allocated by @ctxt
   */
  void
  xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
      if (ctxt == NULL)
  	return;
  
      /*
       * Shutdown the extension modules associated to the stylesheet
       * used if needed.
       */
      xsltShutdownCtxtExts(ctxt);
  
      if (ctxt->xpathCtxt != NULL) {
  	ctxt->xpathCtxt->nsHash = NULL;
  	xmlXPathFreeContext(ctxt->xpathCtxt);
      }
      if (ctxt->templTab != NULL)
  	xmlFree(ctxt->templTab);
      if (ctxt->varsTab != NULL)
  	xmlFree(ctxt->varsTab);
      if (ctxt->profTab != NULL)
  	xmlFree(ctxt->profTab);
      if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) {
  	int i;
  
  	for (i = 0;i < ctxt->extrasNr;i++) {
  	    if ((ctxt->extras[i].deallocate != NULL) &&
  		(ctxt->extras[i].info != NULL))
  		ctxt->extras[i].deallocate(ctxt->extras[i].info);
  	}
  	xmlFree(ctxt->extras);
      }
      xsltFreeGlobalVariables(ctxt);
      xsltFreeDocuments(ctxt);
      xsltFreeCtxtExts(ctxt);
      xsltFreeRVTs(ctxt);
      xsltTransformCacheFree(ctxt->cache);
      xmlDictFree(ctxt->dict);
  #ifdef WITH_XSLT_DEBUG
      xsltGenericDebug(xsltGenericDebugContext,
                       "freeing transformation dictionary\n");
  #endif
      memset(ctxt, -1, sizeof(xsltTransformContext));
      xmlFree(ctxt);
  }
  
  /************************************************************************
   *									*
   *			Copy of Nodes in an XSLT fashion		*
   *									*
   ************************************************************************/
  
  /**
   * xsltAddChild:
   * @parent:  the parent node
   * @cur:  the child node
   *
   * Wrapper version of xmlAddChild with a more consistent behaviour on
   * error. One expect the use to be child = xsltAddChild(parent, child);
   * and the routine will take care of not leaking on errors or node merge
   *
   * Returns the child is successfully attached or NULL if merged or freed
   */
  static xmlNodePtr
  xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) {
     xmlNodePtr ret;
  
     if (cur == NULL)
         return(NULL);
     if (parent == NULL) {
         xmlFreeNode(cur);
         return(NULL);
     }
     ret = xmlAddChild(parent, cur);
  
     return(ret);
  }
  
  /**
   * xsltAddTextString:
   * @ctxt:  a XSLT process context
   * @target:  the text node where the text will be attached
   * @string:  the text string
   * @len:  the string length in byte
   *
   * Extend the current text node with the new string, it handles coalescing
   *
   * Returns: the text node
   */
  static xmlNodePtr
  xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
  		  const xmlChar *string, int len) {
      /*
       * optimization
       */
      if ((len <= 0) || (string == NULL) || (target == NULL))
          return(target);
  
      if (ctxt->lasttext == target->content) {
          int minSize;
  
          /* Check for integer overflow accounting for NUL terminator. */
          if (len >= INT_MAX - ctxt->lasttuse) {
              xsltTransformError(ctxt, NULL, target,
                  "xsltCopyText: text allocation failed\n");
              return(NULL);
          }
          minSize = ctxt->lasttuse + len + 1;
  
          if (ctxt->lasttsize < minSize) {
  	    xmlChar *newbuf;
  	    int size;
              int extra;
  
              /* Double buffer size but increase by at least 100 bytes. */
              extra = minSize < 100 ? 100 : minSize;
  
              /* Check for integer overflow. */
              if (extra > INT_MAX - ctxt->lasttsize) {
                  size = INT_MAX;
              }
              else {
                  size = ctxt->lasttsize + extra;
              }
  
  	    newbuf = (xmlChar *) xmlRealloc(target->content,size);
  	    if (newbuf == NULL) {
  		xsltTransformError(ctxt, NULL, target,
  		 "xsltCopyText: text allocation failed\n");
  		return(NULL);
  	    }
  	    ctxt->lasttsize = size;
  	    ctxt->lasttext = newbuf;
  	    target->content = newbuf;
  	}
  	memcpy(&(target->content[ctxt->lasttuse]), string, len);
  	ctxt->lasttuse += len;
  	target->content[ctxt->lasttuse] = 0;
      } else {
  	xmlNodeAddContent(target, string);
  	ctxt->lasttext = target->content;
  	len = xmlStrlen(target->content);
  	ctxt->lasttsize = len;
  	ctxt->lasttuse = len;
      }
      return(target);
  }
  
  /**
   * xsltCopyTextString:
   * @ctxt:  a XSLT process context
   * @target:  the element where the text will be attached
   * @string:  the text string
   * @noescape:  should disable-escaping be activated for this text node.
   *
   * Adds @string to a newly created or an existent text node child of
   * @target.
   *
   * Returns: the text node, where the text content of @cur is copied to.
   *          NULL in case of API or internal errors.
   */
  xmlNodePtr
  xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
  	           const xmlChar *string, int noescape)
  {
      xmlNodePtr copy;
      int len;
  
      if (string == NULL)
  	return(NULL);
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
  		     "xsltCopyTextString: copy text %s\n",
  		     string));
  #endif
  
      /*
      * Play safe and reset the merging mechanism for every new
      * target node.
      */
      if ((target == NULL) || (target->children == NULL)) {
  	ctxt->lasttext = NULL;
      }
  
      /* handle coalescing of text nodes here */
      len = xmlStrlen(string);
      if ((ctxt->type == XSLT_OUTPUT_XML) &&
  	(ctxt->style->cdataSection != NULL) &&
  	(target != NULL) &&
  	(target->type == XML_ELEMENT_NODE) &&
  	(((target->ns == NULL) &&
  	  (xmlHashLookup2(ctxt->style->cdataSection,
  		          target->name, NULL) != NULL)) ||
  	 ((target->ns != NULL) &&
  	  (xmlHashLookup2(ctxt->style->cdataSection,
  	                  target->name, target->ns->href) != NULL))))
      {
  	/*
  	* Process "cdata-section-elements".
  	*/
  	if ((target->last != NULL) &&
  	    (target->last->type == XML_CDATA_SECTION_NODE))
  	{
  	    return(xsltAddTextString(ctxt, target->last, string, len));
  	}
  	copy = xmlNewCDataBlock(ctxt->output, string, len);
      } else if (noescape) {
  	/*
  	* Process "disable-output-escaping".
  	*/
  	if ((target != NULL) && (target->last != NULL) &&
  	    (target->last->type == XML_TEXT_NODE) &&
  	    (target->last->name == xmlStringTextNoenc))
  	{
  	    return(xsltAddTextString(ctxt, target->last, string, len));
  	}
  	copy = xmlNewTextLen(string, len);
  	if (copy != NULL)
  	    copy->name = xmlStringTextNoenc;
      } else {
  	/*
  	* Default processing.
  	*/
  	if ((target != NULL) && (target->last != NULL) &&
  	    (target->last->type == XML_TEXT_NODE) &&
  	    (target->last->name == xmlStringText)) {
  	    return(xsltAddTextString(ctxt, target->last, string, len));
  	}
  	copy = xmlNewTextLen(string, len);
      }
      if (copy != NULL && target != NULL)
  	copy = xsltAddChild(target, copy);
      if (copy != NULL) {
  	ctxt->lasttext = copy->content;
  	ctxt->lasttsize = len;
  	ctxt->lasttuse = len;
      } else {
  	xsltTransformError(ctxt, NULL, target,
  			 "xsltCopyTextString: text copy failed\n");
  	ctxt->lasttext = NULL;
      }
      return(copy);
  }
  
  /**
   * xsltCopyText:
   * @ctxt:  a XSLT process context
   * @target:  the element where the text will be attached
   * @cur:  the text or CDATA node
   * @interned:  the string is in the target doc dictionary
   *
   * Copy the text content of @cur and append it to @target's children.
   *
   * Returns: the text node, where the text content of @cur is copied to.
   *          NULL in case of API or internal errors.
   */
  static xmlNodePtr
  xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target,
  	     xmlNodePtr cur, int interned)
  {
      xmlNodePtr copy;
  
      if ((cur->type != XML_TEXT_NODE) &&
  	(cur->type != XML_CDATA_SECTION_NODE))
  	return(NULL);
      if (cur->content == NULL)
  	return(NULL);
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      if (cur->type == XML_CDATA_SECTION_NODE) {
  	XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
  			 "xsltCopyText: copy CDATA text %s\n",
  			 cur->content));
      } else if (cur->name == xmlStringTextNoenc) {
  	XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
  		     "xsltCopyText: copy unescaped text %s\n",
  			 cur->content));
      } else {
  	XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
  			 "xsltCopyText: copy text %s\n",
  			 cur->content));
      }
  #endif
  
      /*
      * Play save and reset the merging mechanism for every new
      * target node.
      */
      if ((target == NULL) || (target->children == NULL)) {
  	ctxt->lasttext = NULL;
      }
  
      if ((ctxt->style->cdataSection != NULL) &&
  	(ctxt->type == XSLT_OUTPUT_XML) &&
  	(target != NULL) &&
  	(target->type == XML_ELEMENT_NODE) &&
  	(((target->ns == NULL) &&
  	  (xmlHashLookup2(ctxt->style->cdataSection,
  		          target->name, NULL) != NULL)) ||
  	 ((target->ns != NULL) &&
  	  (xmlHashLookup2(ctxt->style->cdataSection,
  	                  target->name, target->ns->href) != NULL))))
      {
  	/*
  	* Process "cdata-section-elements".
  	*/
  	/*
  	* OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
  	*/
  	/*
  	* TODO: Since this doesn't merge adjacent CDATA-section nodes,
  	* we'll get: <![CDATA[x]]><!CDATA[y]]>.
  	* TODO: Reported in #321505.
  	*/
  	if ((target->last != NULL) &&
  	     (target->last->type == XML_CDATA_SECTION_NODE))
  	{
  	    /*
  	    * Append to existing CDATA-section node.
  	    */
  	    copy = xsltAddTextString(ctxt, target->last, cur->content,
  		xmlStrlen(cur->content));
  	    goto exit;
  	} else {
  	    unsigned int len;
  
  	    len = xmlStrlen(cur->content);
  	    copy = xmlNewCDataBlock(ctxt->output, cur->content, len);
  	    if (copy == NULL)
  		goto exit;
  	    ctxt->lasttext = copy->content;
  	    ctxt->lasttsize = len;
  	    ctxt->lasttuse = len;
  	}
      } else if ((target != NULL) &&
  	(target->last != NULL) &&
  	/* both escaped or both non-escaped text-nodes */
  	(((target->last->type == XML_TEXT_NODE) &&
  	(target->last->name == cur->name)) ||
          /* non-escaped text nodes and CDATA-section nodes */
  	(((target->last->type == XML_CDATA_SECTION_NODE) &&
  	(cur->name == xmlStringTextNoenc)))))
      {
  	/*
  	 * we are appending to an existing text node
  	 */
  	copy = xsltAddTextString(ctxt, target->last, cur->content,
  	    xmlStrlen(cur->content));
  	goto exit;
      } else if ((interned) && (target != NULL) &&
  	(target->doc != NULL) &&
  	(target->doc->dict == ctxt->dict))
      {
  	/*
  	* TODO: DO we want to use this also for "text" output?
  	*/
          copy = xmlNewTextLen(NULL, 0);
  	if (copy == NULL)
  	    goto exit;
  	if (cur->name == xmlStringTextNoenc)
  	    copy->name = xmlStringTextNoenc;
  
  	/*
  	 * Must confirm that content is in dict (bug 302821)
  	 * TODO: This check should be not needed for text coming
  	 * from the stylesheets
  	 */
  	if (xmlDictOwns(ctxt->dict, cur->content))
  	    copy->content = cur->content;
  	else {
  	    if ((copy->content = xmlStrdup(cur->content)) == NULL)
  		return NULL;
  	}
  
  	ctxt->lasttext = NULL;
      } else {
          /*
  	 * normal processing. keep counters to extend the text node
  	 * in xsltAddTextString if needed.
  	 */
          unsigned int len;
  
  	len = xmlStrlen(cur->content);
  	copy = xmlNewTextLen(cur->content, len);
  	if (copy == NULL)
  	    goto exit;
  	if (cur->name == xmlStringTextNoenc)
  	    copy->name = xmlStringTextNoenc;
  	ctxt->lasttext = copy->content;
  	ctxt->lasttsize = len;
  	ctxt->lasttuse = len;
      }
      if (copy != NULL) {
  	if (target != NULL) {
  	    copy->doc = target->doc;
  	    /*
  	    * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
  	    *  to ensure that the optimized text-merging mechanism
  	    *  won't interfere with normal node-merging in any case.
  	    */
  	    copy = xsltAddChild(target, copy);
  	}
      } else {
  	xsltTransformError(ctxt, NULL, target,
  			 "xsltCopyText: text copy failed\n");
      }
  
  exit:
      if ((copy == NULL) || (copy->content == NULL)) {
  	xsltTransformError(ctxt, NULL, target,
  	    "Internal error in xsltCopyText(): "
  	    "Failed to copy the string.\n");
  	ctxt->state = XSLT_STATE_STOPPED;
      }
      return(copy);
  }
  
  /**
   * xsltShallowCopyAttr:
   * @ctxt:  a XSLT process context
   * @invocNode: responsible node in the stylesheet; used for error reports
   * @target:  the element where the attribute will be grafted
   * @attr: the attribute to be copied
   *
   * Do a copy of an attribute.
   * Called by:
   *  - xsltCopyTree()
   *  - xsltCopyOf()
   *  - xsltCopy()
   *
   * Returns: a new xmlAttrPtr, or NULL in case of error.
   */
  static xmlAttrPtr
  xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
  	     xmlNodePtr target, xmlAttrPtr attr)
  {
      xmlAttrPtr copy;
      xmlChar *value;
  
      if (attr == NULL)
  	return(NULL);
  
      if (target->type != XML_ELEMENT_NODE) {
  	xsltTransformError(ctxt, NULL, invocNode,
  	    "Cannot add an attribute node to a non-element node.\n");
  	return(NULL);
      }
  
      if (target->children != NULL) {
  	xsltTransformError(ctxt, NULL, invocNode,
  	    "Attribute nodes must be added before "
  	    "any child nodes to an element.\n");
  	return(NULL);
      }
  
      value = xmlNodeListGetString(attr->doc, attr->children, 1);
      if (attr->ns != NULL) {
  	xmlNsPtr ns;
  
  	ns = xsltGetSpecialNamespace(ctxt, invocNode,
  	    attr->ns->href, attr->ns->prefix, target);
  	if (ns == NULL) {
  	    xsltTransformError(ctxt, NULL, invocNode,
  		"Namespace fixup error: Failed to acquire an in-scope "
  		"namespace binding of the copied attribute '{%s}%s'.\n",
  		attr->ns->href, attr->name);
  	    /*
  	    * TODO: Should we just stop here?
  	    */
  	}
  	/*
  	* Note that xmlSetNsProp() will take care of duplicates
  	* and assigns the new namespace even to a duplicate.
  	*/
  	copy = xmlSetNsProp(target, ns, attr->name, value);
      } else {
  	copy = xmlSetNsProp(target, NULL, attr->name, value);
      }
      if (value != NULL)
  	xmlFree(value);
  
      if (copy == NULL)
  	return(NULL);
  
  #if 0
      /*
      * NOTE: This was optimized according to bug #342695.
      * TODO: Can this further be optimized, if source and target
      *  share the same dict and attr->children is just 1 text node
      *  which is in the dict? How probable is such a case?
      */
      /*
      * TODO: Do we need to create an empty text node if the value
      *  is the empty string?
      */
      value = xmlNodeListGetString(attr->doc, attr->children, 1);
      if (value != NULL) {
  	txtNode = xmlNewDocText(target->doc, NULL);
  	if (txtNode == NULL)
  	    return(NULL);
  	if ((target->doc != NULL) &&
  	    (target->doc->dict != NULL))
  	{
  	    txtNode->content =
  		(xmlChar *) xmlDictLookup(target->doc->dict,
  		    BAD_CAST value, -1);
  	    xmlFree(value);
  	} else
  	    txtNode->content = value;
  	copy->children = txtNode;
      }
  #endif
  
      return(copy);
  }
  
  /**
   * xsltCopyAttrListNoOverwrite:
   * @ctxt:  a XSLT process context
   * @invocNode: responsible node in the stylesheet; used for error reports
   * @target:  the element where the new attributes will be grafted
   * @attr:  the first attribute in the list to be copied
   *
   * Copies a list of attribute nodes, starting with @attr, over to the
   * @target element node.
   *
   * Called by:
   *  - xsltCopyTree()
   *
   * Returns 0 on success and -1 on errors and internal errors.
   */
  static int
  xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt,
  			    xmlNodePtr invocNode,
  			    xmlNodePtr target, xmlAttrPtr attr)
  {
      xmlAttrPtr copy;
      xmlNsPtr origNs = NULL, copyNs = NULL;
      xmlChar *value;
  
      /*
      * Don't use xmlCopyProp() here, since it will try to
      * reconciliate namespaces.
      */
      while (attr != NULL) {
  	/*
  	* Find a namespace node in the tree of @target.
  	* Avoid searching for the same ns.
  	*/
  	if (attr->ns != origNs) {
  	    origNs = attr->ns;
  	    if (attr->ns != NULL) {
  		copyNs = xsltGetSpecialNamespace(ctxt, invocNode,
  		    attr->ns->href, attr->ns->prefix, target);
  		if (copyNs == NULL)
  		    return(-1);
  	    } else
  		copyNs = NULL;
  	}
  	/*
  	 * If attribute has a value, we need to copy it (watching out
  	 * for possible entities)
  	 */
  	if ((attr->children) && (attr->children->type == XML_TEXT_NODE) &&
              (attr->children->next == NULL)) {
              copy = xmlNewNsProp(target, copyNs, attr->name,
                                  attr->children->content);
          } else if (attr->children != NULL) {
  	    value = xmlNodeListGetString(attr->doc, attr->children, 1);
              copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value);
  	    xmlFree(value);
          } else {
              copy = xmlNewNsProp(target, copyNs, attr->name, NULL);
          }
  
  	if (copy == NULL)
  	    return(-1);
  
  	attr = attr->next;
      }
      return(0);
  }
  
  /**
   * xsltShallowCopyElem:
   * @ctxt:  the XSLT process context
   * @node:  the element node in the source tree
   *         or the Literal Result Element
   * @insert:  the parent in the result tree
   * @isLRE: if @node is a Literal Result Element
   *
   * Make a copy of the element node @node
   * and insert it as last child of @insert.
   *
   * URGENT TODO: The problem with this one (for the non-refactored code)
   * is that it is used for both, Literal Result Elements *and*
   * copying input nodes.
   *
   * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
   *
   * Called from:
   *   xsltApplySequenceConstructor()
   *    (for Literal Result Elements - which is a problem)
   *   xsltCopy() (for shallow-copying elements via xsl:copy)
   *
   * Returns a pointer to the new node, or NULL in case of error
   */
  static xmlNodePtr
  xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
  		    xmlNodePtr insert, int isLRE)
  {
      xmlNodePtr copy;
  
      if ((node->type == XML_DTD_NODE) || (insert == NULL))
  	return(NULL);
      if ((node->type == XML_TEXT_NODE) ||
  	(node->type == XML_CDATA_SECTION_NODE))
  	return(xsltCopyText(ctxt, insert, node, 0));
  
      copy = xmlDocCopyNode(node, insert->doc, 0);
      if (copy != NULL) {
  	copy->doc = ctxt->output;
  	copy = xsltAddChild(insert, copy);
          if (copy == NULL) {
               xsltTransformError(ctxt, NULL, node,
                  "xsltShallowCopyElem: copy failed\n");
               return (copy);
          }
  
  	if (node->type == XML_ELEMENT_NODE) {
  	    /*
  	     * Add namespaces as they are needed
  	     */
  	    if (node->nsDef != NULL) {
  		/*
  		* TODO: Remove the LRE case in the refactored code
  		* gets enabled.
  		*/
  		if (isLRE)
  		    xsltCopyNamespaceList(ctxt, copy, node->nsDef);
  		else
  		    xsltCopyNamespaceListInternal(copy, node->nsDef);
  	    }
  
  	    /*
  	    * URGENT TODO: The problem with this is that it does not
  	    *  copy over all namespace nodes in scope.
  	    *  The damn thing about this is, that we would need to
  	    *  use the xmlGetNsList(), for every single node; this is
  	    *  also done in xsltCopyTree(), but only for the top node.
  	    */
  	    if (node->ns != NULL) {
  		if (isLRE) {
  		    /*
  		    * REVISIT TODO: Since the non-refactored code still does
  		    *  ns-aliasing, we need to call xsltGetNamespace() here.
  		    *  Remove this when ready.
  		    */
  		    copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
  		} else {
  		    copy->ns = xsltGetSpecialNamespace(ctxt,
  			node, node->ns->href, node->ns->prefix, copy);
  
  		}
  	    } else if ((insert->type == XML_ELEMENT_NODE) &&
  		       (insert->ns != NULL))
  	    {
  		/*
  		* "Undeclare" the default namespace.
  		*/
  		xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy);
  	    }
  	}
      } else {
  	xsltTransformError(ctxt, NULL, node,
  		"xsltShallowCopyElem: copy %s failed\n", node->name);
      }
      return(copy);
  }
  
  /**
   * xsltCopyTreeList:
   * @ctxt:  a XSLT process context
   * @invocNode: responsible node in the stylesheet; used for error reports
   * @list:  the list of element nodes in the source tree.
   * @insert:  the parent in the result tree.
   * @isLRE:  is this a literal result element list
   * @topElemVisited: indicates if a top-most element was already processed
   *
   * Make a copy of the full list of tree @list
   * and insert it as last children of @insert
   *
   * NOTE: Not to be used for Literal Result Elements.
   *
   * Used by:
   *  - xsltCopyOf()
   *
   * Returns a pointer to the new list, or NULL in case of error
   */
  static xmlNodePtr
  xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
  		 xmlNodePtr list,
  		 xmlNodePtr insert, int isLRE, int topElemVisited)
  {
      xmlNodePtr copy, ret = NULL;
  
      while (list != NULL) {
  	copy = xsltCopyTree(ctxt, invocNode,
  	    list, insert, isLRE, topElemVisited);
  	if (copy != NULL) {
  	    if (ret == NULL) {
  		ret = copy;
  	    }
  	}
  	list = list->next;
      }
      return(ret);
  }
  
  /**
   * xsltCopyNamespaceListInternal:
   * @node:  the target node
   * @cur:  the first namespace
   *
   * Do a copy of a namespace list. If @node is non-NULL the
   * new namespaces are added automatically.
   * Called by:
   *   xsltCopyTree()
   *
   * QUESTION: What is the exact difference between this function
   *  and xsltCopyNamespaceList() in "namespaces.c"?
   * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
   *
   * Returns: a new xmlNsPtr, or NULL in case of error.
   */
  static xmlNsPtr
  xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) {
      xmlNsPtr ret = NULL;
      xmlNsPtr p = NULL, q, luNs;
  
      if (ns == NULL)
  	return(NULL);
      /*
       * One can add namespaces only on element nodes
       */
      if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
  	elem = NULL;
  
      do {
  	if (ns->type != XML_NAMESPACE_DECL)
  	    break;
  	/*
  	 * Avoid duplicating namespace declarations on the tree.
  	 */
  	if (elem != NULL) {
  	    if ((elem->ns != NULL) &&
  		xmlStrEqual(elem->ns->prefix, ns->prefix) &&
  		xmlStrEqual(elem->ns->href, ns->href))
  	    {
  		ns = ns->next;
  		continue;
  	    }
  	    luNs = xmlSearchNs(elem->doc, elem, ns->prefix);
  	    if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href)))
  	    {
  		ns = ns->next;
  		continue;
  	    }
  	}
  	q = xmlNewNs(elem, ns->href, ns->prefix);
  	if (p == NULL) {
  	    ret = p = q;
  	} else if (q != NULL) {
  	    p->next = q;
  	    p = q;
  	}
  	ns = ns->next;
      } while (ns != NULL);
      return(ret);
  }
  
  /**
   * xsltShallowCopyNsNode:
   * @ctxt:  the XSLT transformation context
   * @invocNode: responsible node in the stylesheet; used for error reports
   * @insert:  the target element node in the result tree
   * @ns: the namespace node
   *
   * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
   *
   * Returns a new/existing ns-node, or NULL.
   */
  static xmlNsPtr
  xsltShallowCopyNsNode(xsltTransformContextPtr ctxt,
  		      xmlNodePtr invocNode,
  		      xmlNodePtr insert,
  		      xmlNsPtr ns)
  {
      /*
       * TODO: Contrary to header comments, this is declared as int.
       * be modified to return a node pointer, or NULL if any error
       */
      xmlNsPtr tmpns;
  
      if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))
  	return(NULL);
  
      if (insert->children != NULL) {
  	xsltTransformError(ctxt, NULL, invocNode,
  	    "Namespace nodes must be added before "
  	    "any child nodes are added to an element.\n");
  	return(NULL);
      }
      /*
       * BIG NOTE: Xalan-J simply overwrites any ns-decls with
       * an equal prefix. We definitively won't do that.
       *
       * MSXML 4.0 and the .NET ignores ns-decls for which an
       * equal prefix is already in use.
       *
       * Saxon raises an error like:
       * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
       * nodes with the same name".
       *
       * NOTE: We'll currently follow MSXML here.
       * REVISIT TODO: Check if it's better to follow Saxon here.
       */
      if (ns->prefix == NULL) {
  	/*
  	* If we are adding ns-nodes to an element using e.g.
  	* <xsl:copy-of select="/foo/namespace::*">, then we need
  	* to ensure that we don't incorrectly declare a default
  	* namespace on an element in no namespace, which otherwise
  	* would move the element incorrectly into a namespace, if
  	* the node tree is serialized.
  	*/
  	if (insert->ns == NULL)
  	    goto occupied;
      } else if ((ns->prefix[0] == 'x') &&
  	xmlStrEqual(ns->prefix, BAD_CAST "xml"))
      {
  	/*
  	* The XML namespace is built in.
  	*/
  	return(NULL);
      }
  
      if (insert->nsDef != NULL) {
  	tmpns = insert->nsDef;
  	do {
  	    if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) {
  		if ((tmpns->prefix == ns->prefix) ||
  		    xmlStrEqual(tmpns->prefix, ns->prefix))
  		{
  		    /*
  		    * Same prefix.
  		    */
  		    if (xmlStrEqual(tmpns->href, ns->href))
  			return(NULL);
  		    goto occupied;
  		}
  	    }
  	    tmpns = tmpns->next;
  	} while (tmpns != NULL);
      }
      tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);
      if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))
  	return(NULL);
      /*
      * Declare a new namespace.
      * TODO: The problem (wrt efficiency) with this xmlNewNs() is
      * that it will again search the already declared namespaces
      * for a duplicate :-/
      */
      return(xmlNewNs(insert, ns->href, ns->prefix));
  
  occupied:
      /*
      * TODO: We could as well raise an error here (like Saxon does),
      * or at least generate a warning.
      */
      return(NULL);
  }
  
  /**
   * xsltCopyTree:
   * @ctxt:  the XSLT transformation context
   * @invocNode: responsible node in the stylesheet; used for error reports
   * @node:  the element node in the source tree
   * @insert:  the parent in the result tree
   * @isLRE:  indicates if @node is a Literal Result Element
   * @topElemVisited: indicates if a top-most element was already processed
   *
   * Make a copy of the full tree under the element node @node
   * and insert it as last child of @insert
   *
   * NOTE: Not to be used for Literal Result Elements.
   *
   * Used by:
   *  - xsltCopyOf()
   *
   * Returns a pointer to the new tree, or NULL in case of error
   */
  static xmlNodePtr
  xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
  	     xmlNodePtr node, xmlNodePtr insert, int isLRE,
  	     int topElemVisited)
  {
      xmlNodePtr copy;
  
      if (node == NULL)
  	return(NULL);
      switch (node->type) {
          case XML_ELEMENT_NODE:
          case XML_ENTITY_REF_NODE:
          case XML_ENTITY_NODE:
          case XML_PI_NODE:
          case XML_COMMENT_NODE:
          case XML_DOCUMENT_NODE:
          case XML_HTML_DOCUMENT_NODE:
  #ifdef LIBXML_DOCB_ENABLED
          case XML_DOCB_DOCUMENT_NODE:
  #endif
  	    break;
          case XML_TEXT_NODE: {
  	    int noenc = (node->name == xmlStringTextNoenc);
  	    return(xsltCopyTextString(ctxt, insert, node->content, noenc));
  	    }
          case XML_CDATA_SECTION_NODE:
  	    return(xsltCopyTextString(ctxt, insert, node->content, 0));
          case XML_ATTRIBUTE_NODE:
  	    return((xmlNodePtr)
  		xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node));
          case XML_NAMESPACE_DECL:
  	    return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode,
  		insert, (xmlNsPtr) node));
  
          case XML_DOCUMENT_TYPE_NODE:
          case XML_DOCUMENT_FRAG_NODE:
          case XML_NOTATION_NODE:
          case XML_DTD_NODE:
          case XML_ELEMENT_DECL:
          case XML_ATTRIBUTE_DECL:
          case XML_ENTITY_DECL:
          case XML_XINCLUDE_START:
          case XML_XINCLUDE_END:
              return(NULL);
      }
      if (XSLT_IS_RES_TREE_FRAG(node)) {
  	if (node->children != NULL)
  	    copy = xsltCopyTreeList(ctxt, invocNode,
  		node->children, insert, 0, 0);
  	else
  	    copy = NULL;
  	return(copy);
      }
      copy = xmlDocCopyNode(node, insert->doc, 0);
      if (copy != NULL) {
  	copy->doc = ctxt->output;
  	copy = xsltAddChild(insert, copy);
          if (copy == NULL) {
              xsltTransformError(ctxt, NULL, invocNode,
              "xsltCopyTree: Copying of '%s' failed.\n", node->name);
              return (copy);
          }
  	/*
  	 * The node may have been coalesced into another text node.
  	 */
  	if (insert->last != copy)
  	    return(insert->last);
  	copy->next = NULL;
  
  	if (node->type == XML_ELEMENT_NODE) {
  	    /*
  	    * Copy in-scope namespace nodes.
  	    *
  	    * REVISIT: Since we try to reuse existing in-scope ns-decls by
  	    *  using xmlSearchNsByHref(), this will eventually change
  	    *  the prefix of an original ns-binding; thus it might
  	    *  break QNames in element/attribute content.
  	    * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
  	    *  context, plus a ns-lookup function, which writes directly
  	    *  to a given list, then we wouldn't need to create/free the
  	    *  nsList every time.
  	    */
  	    if ((topElemVisited == 0) &&
  		(node->parent != NULL) &&
  		(node->parent->type != XML_DOCUMENT_NODE) &&
  		(node->parent->type != XML_HTML_DOCUMENT_NODE))
  	    {
  		xmlNsPtr *nsList, *curns, ns;
  
  		/*
  		* If this is a top-most element in a tree to be
  		* copied, then we need to ensure that all in-scope
  		* namespaces are copied over. For nodes deeper in the
  		* tree, it is sufficient to reconcile only the ns-decls
  		* (node->nsDef entries).
  		*/
  
  		nsList = xmlGetNsList(node->doc, node);
  		if (nsList != NULL) {
  		    curns = nsList;
  		    do {
  			/*
  			* Search by prefix first in order to break as less
  			* QNames in element/attribute content as possible.
  			*/
  			ns = xmlSearchNs(insert->doc, insert,
  			    (*curns)->prefix);
  
  			if ((ns == NULL) ||
  			    (! xmlStrEqual(ns->href, (*curns)->href)))
  			{
  			    ns = NULL;
  			    /*
  			    * Search by namespace name.
  			    * REVISIT TODO: Currently disabled.
  			    */
  #if 0
  			    ns = xmlSearchNsByHref(insert->doc,
  				insert, (*curns)->href);
  #endif
  			}
  			if (ns == NULL) {
  			    /*
  			    * Declare a new namespace on the copied element.
  			    */
  			    ns = xmlNewNs(copy, (*curns)->href,
  				(*curns)->prefix);
  			    /* TODO: Handle errors */
  			}
  			if (node->ns == *curns) {
  			    /*
  			    * If this was the original's namespace then set
  			    * the generated counterpart on the copy.
  			    */
  			    copy->ns = ns;
  			}
  			curns++;
  		    } while (*curns != NULL);
  		    xmlFree(nsList);
  		}
  	    } else if (node->nsDef != NULL) {
  		/*
  		* Copy over all namespace declaration attributes.
  		*/
  		if (node->nsDef != NULL) {
  		    if (isLRE)
  			xsltCopyNamespaceList(ctxt, copy, node->nsDef);
  		    else
  			xsltCopyNamespaceListInternal(copy, node->nsDef);
  		}
  	    }
  	    /*
  	    * Set the namespace.
  	    */
  	    if (node->ns != NULL) {
  		if (copy->ns == NULL) {
  		    /*
  		    * This will map copy->ns to one of the newly created
  		    * in-scope ns-decls, OR create a new ns-decl on @copy.
  		    */
  		    copy->ns = xsltGetSpecialNamespace(ctxt, invocNode,
  			node->ns->href, node->ns->prefix, copy);
  		}
  	    } else if ((insert->type == XML_ELEMENT_NODE) &&
  		(insert->ns != NULL))
  	    {
  		/*
  		* "Undeclare" the default namespace on @copy with xmlns="".
  		*/
  		xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy);
  	    }
  	    /*
  	    * Copy attribute nodes.
  	    */
  	    if (node->properties != NULL) {
  		xsltCopyAttrListNoOverwrite(ctxt, invocNode,
  		    copy, node->properties);
  	    }
  	    if (topElemVisited == 0)
  		topElemVisited = 1;
  	}
  	/*
  	* Copy the subtree.
  	*/
  	if (node->children != NULL) {
  	    xsltCopyTreeList(ctxt, invocNode,
  		node->children, copy, isLRE, topElemVisited);
  	}
      } else {
  	xsltTransformError(ctxt, NULL, invocNode,
  	    "xsltCopyTree: Copying of '%s' failed.\n", node->name);
      }
      return(copy);
  }
  
  /************************************************************************
   *									*
   *		Error/fallback processing				*
   *									*
   ************************************************************************/
  
  /**
   * xsltApplyFallbacks:
   * @ctxt:  a XSLT process context
   * @node:  the node in the source tree.
   * @inst:  the node generating the error
   *
   * Process possible xsl:fallback nodes present under @inst
   *
   * Returns the number of xsl:fallback element found and processed
   */
  static int
  xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node,
  	           xmlNodePtr inst) {
  
      xmlNodePtr child;
      int ret = 0;
  
      if ((ctxt == NULL) || (node == NULL) || (inst == NULL) ||
  	(inst->children == NULL))
  	return(0);
  
      child = inst->children;
      while (child != NULL) {
          if ((IS_XSLT_ELEM(child)) &&
              (xmlStrEqual(child->name, BAD_CAST "fallback"))) {
  #ifdef WITH_XSLT_DEBUG_PARSING
  	    xsltGenericDebug(xsltGenericDebugContext,
  			     "applying xsl:fallback\n");
  #endif
  	    ret++;
  	    xsltApplySequenceConstructor(ctxt, node, child->children,
  		NULL);
  	}
  	child = child->next;
      }
      return(ret);
  }
  
  /************************************************************************
   *									*
   *			Default processing				*
   *									*
   ************************************************************************/
  
  /**
   * xsltDefaultProcessOneNode:
   * @ctxt:  a XSLT process context
   * @node:  the node in the source tree.
   * @params: extra parameters passed to the template if any
   *
   * Process the source node with the default built-in template rule:
   * <xsl:template match="*|/">
   *   <xsl:apply-templates/>
   * </xsl:template>
   *
   * and
   *
   * <xsl:template match="text()|@*">
   *   <xsl:value-of select="."/>
   * </xsl:template>
   *
   * Note also that namespace declarations are copied directly:
   *
   * the built-in template rule is the only template rule that is applied
   * for namespace nodes.
   */
  static void
  xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
  			  xsltStackElemPtr params) {
      xmlNodePtr copy;
      xmlNodePtr delete = NULL, cur;
      int nbchild = 0, oldSize;
      int childno = 0, oldPos;
      xsltTemplatePtr template;
  
      CHECK_STOPPED;
      /*
       * Handling of leaves
       */
      switch (node->type) {
  	case XML_DOCUMENT_NODE:
  	case XML_HTML_DOCUMENT_NODE:
  	case XML_ELEMENT_NODE:
  	    break;
  	case XML_CDATA_SECTION_NODE:
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltDefaultProcessOneNode: copy CDATA %s\n",
  		node->content));
  #endif
  	    copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
  	    if (copy == NULL) {
  		xsltTransformError(ctxt, NULL, node,
  		 "xsltDefaultProcessOneNode: cdata copy failed\n");
  	    }
  	    return;
  	case XML_TEXT_NODE:
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	    if (node->content == NULL) {
  		XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  		 "xsltDefaultProcessOneNode: copy empty text\n"));
  		return;
  	    } else {
  		XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  		 "xsltDefaultProcessOneNode: copy text %s\n",
  			node->content));
              }
  #endif
  	    copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
  	    if (copy == NULL) {
  		xsltTransformError(ctxt, NULL, node,
  		 "xsltDefaultProcessOneNode: text copy failed\n");
  	    }
  	    return;
  	case XML_ATTRIBUTE_NODE:
  	    cur = node->children;
  	    while ((cur != NULL) && (cur->type != XML_TEXT_NODE))
  		cur = cur->next;
  	    if (cur == NULL) {
  		xsltTransformError(ctxt, NULL, node,
  		 "xsltDefaultProcessOneNode: no text for attribute\n");
  	    } else {
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		if (cur->content == NULL) {
  		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  		     "xsltDefaultProcessOneNode: copy empty text\n"));
  		} else {
  		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  		     "xsltDefaultProcessOneNode: copy text %s\n",
  			cur->content));
                  }
  #endif
  		copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
  		if (copy == NULL) {
  		    xsltTransformError(ctxt, NULL, node,
  		     "xsltDefaultProcessOneNode: text copy failed\n");
  		}
  	    }
  	    return;
  	default:
  	    return;
      }
      /*
       * Handling of Elements: first pass, cleanup and counting
       */
      cur = node->children;
      while (cur != NULL) {
  	switch (cur->type) {
  	    case XML_TEXT_NODE:
  	    case XML_CDATA_SECTION_NODE:
  	    case XML_DOCUMENT_NODE:
  	    case XML_HTML_DOCUMENT_NODE:
  	    case XML_ELEMENT_NODE:
  	    case XML_PI_NODE:
  	    case XML_COMMENT_NODE:
  		nbchild++;
  		break;
              case XML_DTD_NODE:
  		/* Unlink the DTD, it's still reachable using doc->intSubset */
  		if (cur->next != NULL)
  		    cur->next->prev = cur->prev;
  		if (cur->prev != NULL)
  		    cur->prev->next = cur->next;
  		break;
  	    default:
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  		 "xsltDefaultProcessOneNode: skipping node type %d\n",
  		                 cur->type));
  #endif
  		delete = cur;
  	}
  	cur = cur->next;
  	if (delete != NULL) {
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  		 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
  #endif
  	    xmlUnlinkNode(delete);
  	    xmlFreeNode(delete);
  	    delete = NULL;
  	}
      }
      if (delete != NULL) {
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
  #endif
  	xmlUnlinkNode(delete);
  	xmlFreeNode(delete);
  	delete = NULL;
      }
  
      /*
       * Handling of Elements: second pass, actual processing
       *
       * Note that params are passed to the next template. This matches
       * XSLT 2.0 behavior but doesn't conform to XSLT 1.0.
       */
      oldSize = ctxt->xpathCtxt->contextSize;
      oldPos = ctxt->xpathCtxt->proximityPosition;
      cur = node->children;
      while (cur != NULL) {
  	childno++;
  	switch (cur->type) {
  	    case XML_DOCUMENT_NODE:
  	    case XML_HTML_DOCUMENT_NODE:
  	    case XML_ELEMENT_NODE:
  		ctxt->xpathCtxt->contextSize = nbchild;
  		ctxt->xpathCtxt->proximityPosition = childno;
  		xsltProcessOneNode(ctxt, cur, params);
  		break;
  	    case XML_CDATA_SECTION_NODE:
  		template = xsltGetTemplate(ctxt, cur, NULL);
  		if (template) {
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  		 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
  				     cur->content));
  #endif
  		    /*
  		    * Instantiate the xsl:template.
  		    */
  		    xsltApplyXSLTTemplate(ctxt, cur, template->content,
  			template, params);
  		} else /* if (ctxt->mode == NULL) */ {
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  		     "xsltDefaultProcessOneNode: copy CDATA %s\n",
  				     cur->content));
  #endif
  		    copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
  		    if (copy == NULL) {
  			xsltTransformError(ctxt, NULL, cur,
  			    "xsltDefaultProcessOneNode: cdata copy failed\n");
  		    }
  		}
  		break;
  	    case XML_TEXT_NODE:
  		template = xsltGetTemplate(ctxt, cur, NULL);
  		if (template) {
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltDefaultProcessOneNode: applying template for text %s\n",
  				     cur->content));
  #endif
  		    ctxt->xpathCtxt->contextSize = nbchild;
  		    ctxt->xpathCtxt->proximityPosition = childno;
  		    /*
  		    * Instantiate the xsl:template.
  		    */
  		    xsltApplyXSLTTemplate(ctxt, cur, template->content,
  			template, params);
  		} else /* if (ctxt->mode == NULL) */ {
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		    if (cur->content == NULL) {
  			XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  			 "xsltDefaultProcessOneNode: copy empty text\n"));
  		    } else {
  			XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  		     "xsltDefaultProcessOneNode: copy text %s\n",
  					 cur->content));
                      }
  #endif
  		    copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
  		    if (copy == NULL) {
  			xsltTransformError(ctxt, NULL, cur,
  			    "xsltDefaultProcessOneNode: text copy failed\n");
  		    }
  		}
  		break;
  	    case XML_PI_NODE:
  	    case XML_COMMENT_NODE:
  		template = xsltGetTemplate(ctxt, cur, NULL);
  		if (template) {
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		    if (cur->type == XML_PI_NODE) {
  			XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  		     "xsltDefaultProcessOneNode: template found for PI %s\n",
  			                 cur->name));
  		    } else if (cur->type == XML_COMMENT_NODE) {
  			XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  		     "xsltDefaultProcessOneNode: template found for comment\n"));
                      }
  #endif
  		    ctxt->xpathCtxt->contextSize = nbchild;
  		    ctxt->xpathCtxt->proximityPosition = childno;
  		    /*
  		    * Instantiate the xsl:template.
  		    */
  		    xsltApplyXSLTTemplate(ctxt, cur, template->content,
  			template, params);
  		}
  		break;
  	    default:
  		break;
  	}
  	cur = cur->next;
      }
      ctxt->xpathCtxt->contextSize = oldSize;
      ctxt->xpathCtxt->proximityPosition = oldPos;
  }
  
  /**
   * xsltProcessOneNode:
   * @ctxt:  a XSLT process context
   * @contextNode:  the "current node" in the source tree
   * @withParams:  extra parameters (e.g. xsl:with-param) passed to the
   *               template if any
   *
   * Process the source node.
   */
  void
  xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
  	           xsltStackElemPtr withParams)
  {
      xsltTemplatePtr templ;
      xmlNodePtr oldNode;
  
      templ = xsltGetTemplate(ctxt, contextNode, NULL);
      /*
       * If no template is found, apply the default rule.
       */
      if (templ == NULL) {
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	if (contextNode->type == XML_DOCUMENT_NODE) {
  	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltProcessOneNode: no template found for /\n"));
  	} else if (contextNode->type == XML_CDATA_SECTION_NODE) {
  	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltProcessOneNode: no template found for CDATA\n"));
  	} else if (contextNode->type == XML_ATTRIBUTE_NODE) {
  	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltProcessOneNode: no template found for attribute %s\n",
  	                     ((xmlAttrPtr) contextNode)->name));
  	} else  {
  	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltProcessOneNode: no template found for %s\n", contextNode->name));
          }
  #endif
  	oldNode = ctxt->node;
  	ctxt->node = contextNode;
  	xsltDefaultProcessOneNode(ctxt, contextNode, withParams);
  	ctxt->node = oldNode;
  	return;
      }
  
      if (contextNode->type == XML_ATTRIBUTE_NODE) {
  	xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
  	/*
  	* Set the "current template rule".
  	*/
  	ctxt->currentTemplateRule = templ;
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltProcessOneNode: applying template '%s' for attribute %s\n",
  	                 templ->match, contextNode->name));
  #endif
  	xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
  
  	ctxt->currentTemplateRule = oldCurTempRule;
      } else {
  	xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
  	/*
  	* Set the "current template rule".
  	*/
  	ctxt->currentTemplateRule = templ;
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	if (contextNode->type == XML_DOCUMENT_NODE) {
  	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltProcessOneNode: applying template '%s' for /\n",
  	                     templ->match));
  	} else {
  	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltProcessOneNode: applying template '%s' for %s\n",
  	                     templ->match, contextNode->name));
          }
  #endif
  	xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
  
  	ctxt->currentTemplateRule = oldCurTempRule;
      }
  }
  
  #ifdef WITH_DEBUGGER
  static xmlNodePtr
  xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt,
  				     xmlNodePtr contextNode,
  				     xmlNodePtr list,
  				     xsltTemplatePtr templ,
  				     int *addCallResult)
  {
      xmlNodePtr debugedNode = NULL;
  
      if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
          if (templ) {
              *addCallResult = xslAddCall(templ, templ->elem);
          } else {
              *addCallResult = xslAddCall(NULL, list);
          }
          switch (ctxt->debugStatus) {
              case XSLT_DEBUG_RUN_RESTART:
              case XSLT_DEBUG_QUIT:
                  if (*addCallResult)
                      xslDropCall();
                  return(NULL);
          }
          if (templ) {
              xslHandleDebugger(templ->elem, contextNode, templ, ctxt);
              debugedNode = templ->elem;
          } else if (list) {
              xslHandleDebugger(list, contextNode, templ, ctxt);
              debugedNode = list;
          } else if (ctxt->inst) {
              xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt);
              debugedNode = ctxt->inst;
          }
      }
      return(debugedNode);
  }
  #endif /* WITH_DEBUGGER */
  
  /**
   * xsltLocalVariablePush:
   * @ctxt: the transformation context
   * @variable: variable to be pushed to the variable stack
   * @level: new value for variable's level
   *
   * Places the variable onto the local variable stack
   *
   * Returns: 0 for success, -1 for any error
   * **NOTE:**
   * This is an internal routine and should not be called by users!
   */
  int
  xsltLocalVariablePush(xsltTransformContextPtr ctxt,
  		      xsltStackElemPtr variable,
  		      int level)
  {
      if (ctxt->varsMax == 0) {
  	ctxt->varsMax = 10;
  	ctxt->varsTab =
  	    (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
  	    sizeof(ctxt->varsTab[0]));
  	if (ctxt->varsTab == NULL) {
  	    xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
  	    return (-1);
  	}
      }
      if (ctxt->varsNr >= ctxt->varsMax) {
  	ctxt->varsMax *= 2;
  	ctxt->varsTab =
  	    (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
  	    ctxt->varsMax *
  	    sizeof(ctxt->varsTab[0]));
  	if (ctxt->varsTab == NULL) {
  	    xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
  	    return (-1);
  	}
      }
      ctxt->varsTab[ctxt->varsNr++] = variable;
      ctxt->vars = variable;
      variable->level = level;
      return(0);
  }
  
  /**
   * xsltReleaseLocalRVTs:
   *
   * Fragments which are results of extension instructions
   * are preserved; all other fragments are freed/cached.
   */
  static void
  xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
  {
      xmlDocPtr cur = ctxt->localRVT, tmp;
  
      if (cur == base)
          return;
      if (cur->prev != NULL)
          xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n");
  
      /* Reset localRVT early because some RVTs might be registered again. */
      ctxt->localRVT = base;
      if (base != NULL)
          base->prev = NULL;
  
      do {
          tmp = cur;
          cur = (xmlDocPtr) cur->next;
          if (tmp->psvi == XSLT_RVT_LOCAL) {
              xsltReleaseRVT(ctxt, tmp);
          } else if (tmp->psvi == XSLT_RVT_GLOBAL) {
              xsltRegisterPersistRVT(ctxt, tmp);
          } else if (tmp->psvi == XSLT_RVT_FUNC_RESULT) {
              /*
               * This will either register the RVT again or move it to the
               * context variable.
               */
              xsltRegisterLocalRVT(ctxt, tmp);
              tmp->psvi = XSLT_RVT_FUNC_RESULT;
          } else {
              xmlGenericError(xmlGenericErrorContext,
                      "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n",
                      tmp->psvi);
          }
      } while (cur != base);
  }
  
  /**
   * xsltApplySequenceConstructor:
   * @ctxt:  a XSLT process context
   * @contextNode:  the "current node" in the source tree
   * @list:  the nodes of a sequence constructor;
   *         (plus leading xsl:param elements)
   * @templ: the compiled xsl:template (optional)
   *
   * Processes a sequence constructor.
   *
   * NOTE: ctxt->currentTemplateRule was introduced to reflect the
   * semantics of "current template rule". I.e. the field ctxt->templ
   * is not intended to reflect this, thus always pushed onto the
   * template stack.
   */
  static void
  xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
  			     xmlNodePtr contextNode, xmlNodePtr list,
  			     xsltTemplatePtr templ)
  {
      xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;
      xmlNodePtr cur, insert, copy = NULL;
      int level = 0, oldVarsNr;
      xmlDocPtr oldLocalFragmentTop;
  
  #ifdef XSLT_REFACTORED
      xsltStylePreCompPtr info;
  #endif
  
  #ifdef WITH_DEBUGGER
      int addCallResult = 0;
      xmlNodePtr debuggedNode = NULL;
  #endif
  
      if (ctxt == NULL)
  	return;
  
  #ifdef WITH_DEBUGGER
      if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
  	debuggedNode =
  	    xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
  		list, templ, &addCallResult);
  	if (debuggedNode == NULL)
  	    return;
      }
  #endif
  
      if (list == NULL)
          return;
      CHECK_STOPPED;
  
      /*
      * Check for infinite recursion: stop if the maximum of nested templates
      * is excceeded. Adjust xsltMaxDepth if you need more.
      */
      if (ctxt->depth >= ctxt->maxTemplateDepth) {
          xsltTransformError(ctxt, NULL, list,
  	    "xsltApplySequenceConstructor: A potential infinite template "
              "recursion was detected.\n"
  	    "You can adjust xsltMaxDepth (--maxdepth) in order to "
  	    "raise the maximum number of nested template calls and "
  	    "variables/params (currently set to %d).\n",
  	    ctxt->maxTemplateDepth);
          xsltDebug(ctxt, contextNode, list, NULL);
  	ctxt->state = XSLT_STATE_STOPPED;
          return;
      }
      ctxt->depth++;
  
      oldLocalFragmentTop = ctxt->localRVT;
      oldInsert = insert = ctxt->insert;
      oldInst = oldCurInst = ctxt->inst;
      oldContextNode = ctxt->node;
      /*
      * Save current number of variables on the stack; new vars are popped when
      * exiting.
      */
      oldVarsNr = ctxt->varsNr;
      /*
      * Process the sequence constructor.
      */
      cur = list;
      while (cur != NULL) {
          if (ctxt->opLimit != 0) {
              if (ctxt->opCount >= ctxt->opLimit) {
  		xsltTransformError(ctxt, NULL, cur,
  		    "xsltApplySequenceConstructor: "
                      "Operation limit exceeded\n");
  	        ctxt->state = XSLT_STATE_STOPPED;
                  goto error;
              }
              ctxt->opCount += 1;
          }
  
          ctxt->inst = cur;
  
  #ifdef WITH_DEBUGGER
          switch (ctxt->debugStatus) {
              case XSLT_DEBUG_RUN_RESTART:
              case XSLT_DEBUG_QUIT:
                  break;
  
          }
  #endif
          /*
           * Test; we must have a valid insertion point.
           */
          if (insert == NULL) {
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
              XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
  		"xsltApplySequenceConstructor: insert == NULL !\n"));
  #endif
              goto error;
          }
  
  #ifdef WITH_DEBUGGER
          if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur))
              xslHandleDebugger(cur, contextNode, templ, ctxt);
  #endif
  
  #ifdef XSLT_REFACTORED
  	if (cur->type == XML_ELEMENT_NODE) {
  	    info = (xsltStylePreCompPtr) cur->psvi;
  	    /*
  	    * We expect a compiled representation on:
  	    * 1) XSLT instructions of this XSLT version (1.0)
  	    *    (with a few exceptions)
  	    * 2) Literal result elements
  	    * 3) Extension instructions
  	    * 4) XSLT instructions of future XSLT versions
  	    *    (forwards-compatible mode).
  	    */
  	    if (info == NULL) {
  		/*
  		* Handle the rare cases where we don't expect a compiled
  		* representation on an XSLT element.
  		*/
  		if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) {
  		    xsltMessage(ctxt, contextNode, cur);
  		    goto skip_children;
  		}
  		/*
  		* Something really went wrong:
  		*/
  		xsltTransformError(ctxt, NULL, cur,
  		    "Internal error in xsltApplySequenceConstructor(): "
  		    "The element '%s' in the stylesheet has no compiled "
  		    "representation.\n",
  		    cur->name);
                  goto skip_children;
              }
  
  	    if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) {
  		xsltStyleItemLRElementInfoPtr lrInfo =
  		    (xsltStyleItemLRElementInfoPtr) info;
  		/*
  		* Literal result elements
  		* --------------------------------------------------------
  		*/
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
  		    xsltGenericDebug(xsltGenericDebugContext,
  		    "xsltApplySequenceConstructor: copy literal result "
  		    "element '%s'\n", cur->name));
  #endif
  		/*
  		* Copy the raw element-node.
  		* OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
  		*     == NULL)
  		*   goto error;
  		*/
  		copy = xmlDocCopyNode(cur, insert->doc, 0);
  		if (copy == NULL) {
  		    xsltTransformError(ctxt, NULL, cur,
  			"Internal error in xsltApplySequenceConstructor(): "
  			"Failed to copy literal result element '%s'.\n",
  			cur->name);
  		    goto error;
  		} else {
  		    /*
  		    * Add the element-node to the result tree.
  		    */
  		    copy->doc = ctxt->output;
  		    copy = xsltAddChild(insert, copy);
  		    /*
  		    * Create effective namespaces declarations.
  		    * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
  		    */
  		    if (lrInfo->effectiveNs != NULL) {
  			xsltEffectiveNsPtr effNs = lrInfo->effectiveNs;
  			xmlNsPtr ns, lastns = NULL;
  
  			while (effNs != NULL) {
  			    /*
  			    * Avoid generating redundant namespace
  			    * declarations; thus lookup if there is already
  			    * such a ns-decl in the result.
  			    */
  			    ns = xmlSearchNs(copy->doc, copy, effNs->prefix);
  			    if ((ns != NULL) &&
  				(xmlStrEqual(ns->href, effNs->nsName)))
  			    {
  				effNs = effNs->next;
  				continue;
  			    }
  			    ns = xmlNewNs(copy, effNs->nsName, effNs->prefix);
  			    if (ns == NULL) {
  				xsltTransformError(ctxt, NULL, cur,
  				    "Internal error in "
  				    "xsltApplySequenceConstructor(): "
  				    "Failed to copy a namespace "
  				    "declaration.\n");
  				goto error;
  			    }
  
  			    if (lastns == NULL)
  				copy->nsDef = ns;
  			    else
  				lastns->next =ns;
  			    lastns = ns;
  
  			    effNs = effNs->next;
  			}
  
  		    }
  		    /*
  		    * NOTE that we don't need to apply ns-alising: this was
  		    *  already done at compile-time.
  		    */
  		    if (cur->ns != NULL) {
  			/*
  			* If there's no such ns-decl in the result tree,
  			* then xsltGetSpecialNamespace() will
  			* create a ns-decl on the copied node.
  			*/
  			copy->ns = xsltGetSpecialNamespace(ctxt, cur,
  			    cur->ns->href, cur->ns->prefix, copy);
  		    } else {
  			/*
  			* Undeclare the default namespace if needed.
  			* This can be skipped, if the result element has
  			*  no ns-decls, in which case the result element
  			*  obviously does not declare a default namespace;
  			*  AND there's either no parent, or the parent
  			*  element is in no namespace; this means there's no
  			*  default namespace is scope to care about.
  			*
  			* REVISIT: This might result in massive
  			*  generation of ns-decls if nodes in a default
  			*  namespaces are mixed with nodes in no namespace.
  			*
  			*/
  			if (copy->nsDef ||
  			    ((insert != NULL) &&
  			     (insert->type == XML_ELEMENT_NODE) &&
  			     (insert->ns != NULL)))
  			{
  			    xsltGetSpecialNamespace(ctxt, cur,
  				NULL, NULL, copy);
  			}
  		    }
  		}
  		/*
  		* SPEC XSLT 2.0 "Each attribute of the literal result
  		*  element, other than an attribute in the XSLT namespace,
  		*  is processed to produce an attribute for the element in
  		*  the result tree."
  		* NOTE: See bug #341325.
  		*/
  		if (cur->properties != NULL) {
  		    xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
  		}
  	    } else if (IS_XSLT_ELEM_FAST(cur)) {
  		/*
  		* XSLT instructions
  		* --------------------------------------------------------
  		*/
  		if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) {
  		    /*
  		    * We hit an unknown XSLT element.
  		    * Try to apply one of the fallback cases.
  		    */
  		    ctxt->insert = insert;
  		    if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
  			xsltTransformError(ctxt, NULL, cur,
  			    "The is no fallback behaviour defined for "
  			    "the unknown XSLT element '%s'.\n",
  			    cur->name);
  		    }
  		    ctxt->insert = oldInsert;
  		} else if (info->func != NULL) {
  		    /*
  		    * Execute the XSLT instruction.
  		    */
  		    ctxt->insert = insert;
  
  		    info->func(ctxt, contextNode, cur,
  			(xsltElemPreCompPtr) info);
  
  		    /*
  		    * Cleanup temporary tree fragments.
  		    */
  		    if (oldLocalFragmentTop != ctxt->localRVT)
  			xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
  
  		    ctxt->insert = oldInsert;
  		} else if (info->type == XSLT_FUNC_VARIABLE) {
  		    xsltStackElemPtr tmpvar = ctxt->vars;
  
  		    xsltParseStylesheetVariable(ctxt, cur);
  
  		    if (tmpvar != ctxt->vars) {
  			/*
  			* TODO: Using a @tmpvar is an annoying workaround, but
  			*  the current mechanisms do not provide any other way
  			*  of knowing if the var was really pushed onto the
  			*  stack.
  			*/
  			ctxt->vars->level = level;
  		    }
  		} else if (info->type == XSLT_FUNC_MESSAGE) {
  		    /*
  		    * TODO: Won't be hit, since we don't compile xsl:message.
  		    */
  		    xsltMessage(ctxt, contextNode, cur);
  		} else {
  		    xsltTransformError(ctxt, NULL, cur,
  			"Unexpected XSLT element '%s'.\n", cur->name);
  		}
  		goto skip_children;
  
  	    } else {
  		xsltTransformFunction func;
  		/*
  		* Extension intructions (elements)
  		* --------------------------------------------------------
  		*/
  		if (cur->psvi == xsltExtMarker) {
  		    /*
  		    * The xsltExtMarker was set during the compilation
  		    * of extension instructions if there was no registered
  		    * handler for this specific extension function at
  		    * compile-time.
  		    * Libxslt will now lookup if a handler is
  		    * registered in the context of this transformation.
  		    */
  		    func = xsltExtElementLookup(ctxt, cur->name,
                                                  cur->ns->href);
  		} else
  		    func = ((xsltElemPreCompPtr) cur->psvi)->func;
  
  		if (func == NULL) {
  		    /*
  		    * No handler available.
  		    * Try to execute fallback behaviour via xsl:fallback.
  		    */
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		    XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
  			xsltGenericDebug(xsltGenericDebugContext,
  			    "xsltApplySequenceConstructor: unknown extension %s\n",
  			    cur->name));
  #endif
  		    ctxt->insert = insert;
  		    if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
  			xsltTransformError(ctxt, NULL, cur,
  			    "Unknown extension instruction '{%s}%s'.\n",
  			    cur->ns->href, cur->name);
  		    }
  		    ctxt->insert = oldInsert;
  		} else {
  		    /*
  		    * Execute the handler-callback.
  		    */
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		    XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
  			"xsltApplySequenceConstructor: extension construct %s\n",
  			cur->name));
  #endif
                      /*
                       * Disable the xsltCopyTextString optimization for
                       * extension elements. Extensions could append text using
                       * xmlAddChild which will free the buffer pointed to by
                       * 'lasttext'. This buffer could later be reallocated with
                       * a different size than recorded in 'lasttsize'. See bug
                       * #777432.
                       */
                      if (cur->psvi == xsltExtMarker) {
                          ctxt->lasttext = NULL;
                      }
  
  		    ctxt->insert = insert;
  
  		    func(ctxt, contextNode, cur, cur->psvi);
  
  		    /*
  		    * Cleanup temporary tree fragments.
  		    */
  		    if (oldLocalFragmentTop != ctxt->localRVT)
  			xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
  
  		    ctxt->insert = oldInsert;
  		}
  		goto skip_children;
  	    }
  
  	} else if (XSLT_IS_TEXT_NODE(cur)) {
  	    /*
  	    * Text
  	    * ------------------------------------------------------------
  	    */
  #ifdef WITH_XSLT_DEBUG_PROCESS
              if (cur->name == xmlStringTextNoenc) {
                  XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
  		    xsltGenericDebug(xsltGenericDebugContext,
  		    "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
  		    cur->content));
              } else {
                  XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
  		    xsltGenericDebug(xsltGenericDebugContext,
  		    "xsltApplySequenceConstructor: copy text '%s'\n",
  		    cur->content));
              }
  #endif
              if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
  		goto error;
  	}
  
  #else /* XSLT_REFACTORED */
  
          if (IS_XSLT_ELEM(cur)) {
              /*
               * This is an XSLT node
               */
              xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi;
  
              if (info == NULL) {
                  if (IS_XSLT_NAME(cur, "message")) {
                      xsltMessage(ctxt, contextNode, cur);
                  } else {
                      /*
                       * That's an error try to apply one of the fallback cases
                       */
                      ctxt->insert = insert;
                      if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
                          xsltGenericError(xsltGenericErrorContext,
  			    "xsltApplySequenceConstructor: %s was not compiled\n",
  			    cur->name);
                      }
                      ctxt->insert = oldInsert;
                  }
                  goto skip_children;
              }
  
              if (info->func != NULL) {
  		oldCurInst = ctxt->inst;
  		ctxt->inst = cur;
                  ctxt->insert = insert;
  
                  info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info);
  
  		/*
  		* Cleanup temporary tree fragments.
  		*/
  		if (oldLocalFragmentTop != ctxt->localRVT)
  		    xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
  
                  ctxt->insert = oldInsert;
  		ctxt->inst = oldCurInst;
                  goto skip_children;
              }
  
              if (IS_XSLT_NAME(cur, "variable")) {
  		xsltStackElemPtr tmpvar = ctxt->vars;
  
  		oldCurInst = ctxt->inst;
  		ctxt->inst = cur;
  
  		xsltParseStylesheetVariable(ctxt, cur);
  
  		ctxt->inst = oldCurInst;
  
  		if (tmpvar != ctxt->vars) {
  		    /*
  		    * TODO: Using a @tmpvar is an annoying workaround, but
  		    *  the current mechanisms do not provide any other way
  		    *  of knowing if the var was really pushed onto the
  		    *  stack.
  		    */
  		    ctxt->vars->level = level;
  		}
              } else if (IS_XSLT_NAME(cur, "message")) {
                  xsltMessage(ctxt, contextNode, cur);
              } else {
  		xsltTransformError(ctxt, NULL, cur,
  		    "Unexpected XSLT element '%s'.\n", cur->name);
              }
              goto skip_children;
          } else if ((cur->type == XML_TEXT_NODE) ||
                     (cur->type == XML_CDATA_SECTION_NODE)) {
  
              /*
               * This text comes from the stylesheet
               * For stylesheets, the set of whitespace-preserving
               * element names consists of just xsl:text.
               */
  #ifdef WITH_XSLT_DEBUG_PROCESS
              if (cur->type == XML_CDATA_SECTION_NODE) {
                  XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
                                   "xsltApplySequenceConstructor: copy CDATA text %s\n",
                                   cur->content));
              } else if (cur->name == xmlStringTextNoenc) {
                  XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
                                   "xsltApplySequenceConstructor: copy unescaped text %s\n",
                                   cur->content));
              } else {
                  XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
                                   "xsltApplySequenceConstructor: copy text %s\n",
                                   cur->content));
              }
  #endif
              if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
  		goto error;
          } else if ((cur->type == XML_ELEMENT_NODE) &&
                     (cur->ns != NULL) && (cur->psvi != NULL)) {
              xsltTransformFunction function;
  
  	    oldCurInst = ctxt->inst;
  	    ctxt->inst = cur;
              /*
               * Flagged as an extension element
               */
              if (cur->psvi == xsltExtMarker)
                  function = xsltExtElementLookup(ctxt, cur->name,
                                                  cur->ns->href);
              else
                  function = ((xsltElemPreCompPtr) cur->psvi)->func;
  
              if (function == NULL) {
                  xmlNodePtr child;
                  int found = 0;
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
                  XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
  		    "xsltApplySequenceConstructor: unknown extension %s\n",
                      cur->name));
  #endif
                  /*
                   * Search if there are fallbacks
                   */
                  ctxt->insert = insert;
                  child = cur->children;
                  while (child != NULL) {
                      if ((IS_XSLT_ELEM(child)) &&
                          (IS_XSLT_NAME(child, "fallback")))
  		    {
                          found = 1;
                          xsltApplySequenceConstructor(ctxt, contextNode,
  			    child->children, NULL);
                      }
                      child = child->next;
                  }
                  ctxt->insert = oldInsert;
  
                  if (!found) {
                      xsltTransformError(ctxt, NULL, cur,
  			"xsltApplySequenceConstructor: failed to find extension %s\n",
  			cur->name);
                  }
              } else {
  #ifdef WITH_XSLT_DEBUG_PROCESS
                  XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
  		    "xsltApplySequenceConstructor: extension construct %s\n",
                      cur->name));
  #endif
  
                  /*
                   * Disable the xsltCopyTextString optimization for
                   * extension elements. Extensions could append text using
                   * xmlAddChild which will free the buffer pointed to by
                   * 'lasttext'. This buffer could later be reallocated with
                   * a different size than recorded in 'lasttsize'. See bug
                   * #777432.
                   */
                  if (cur->psvi == xsltExtMarker) {
  	            ctxt->lasttext = NULL;
                  }
  
                  ctxt->insert = insert;
  
                  function(ctxt, contextNode, cur, cur->psvi);
  		/*
  		* Cleanup temporary tree fragments.
  		*/
  		if (oldLocalFragmentTop != ctxt->localRVT)
  		    xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
  
                  ctxt->insert = oldInsert;
  
              }
  	    ctxt->inst = oldCurInst;
              goto skip_children;
          } else if (cur->type == XML_ELEMENT_NODE) {
  #ifdef WITH_XSLT_DEBUG_PROCESS
              XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
  		"xsltApplySequenceConstructor: copy node %s\n",
                  cur->name));
  #endif
  	    oldCurInst = ctxt->inst;
  	    ctxt->inst = cur;
  
              if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)
  		goto error;
              /*
               * Add extra namespaces inherited from the current template
               * if we are in the first level children and this is a
  	     * "real" template.
               */
              if ((templ != NULL) && (oldInsert == insert) &&
                  (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) {
                  int i;
                  xmlNsPtr ns, ret;
  
                  for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
  		    const xmlChar *URI = NULL;
  		    xsltStylesheetPtr style;
                      ns = ctxt->templ->inheritedNs[i];
  
  		    /* Note that the XSLT namespace was already excluded
  		    * in xsltGetInheritedNsList().
  		    */
  #if 0
  		    if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
  			continue;
  #endif
  		    style = ctxt->style;
  		    while (style != NULL) {
  			if (style->nsAliases != NULL)
  			    URI = (const xmlChar *)
  				xmlHashLookup(style->nsAliases, ns->href);
  			if (URI != NULL)
  			    break;
  
  			style = xsltNextImport(style);
  		    }
  		    if (URI == UNDEFINED_DEFAULT_NS)
  			continue;
  		    if (URI == NULL)
  			URI = ns->href;
  		    /*
  		    * TODO: The following will still be buggy for the
  		    * non-refactored code.
  		    */
  		    ret = xmlSearchNs(copy->doc, copy, ns->prefix);
  		    if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))
  		    {
  			xmlNewNs(copy, URI, ns->prefix);
  		    }
                  }
  		if (copy->ns != NULL) {
  		    /*
  		     * Fix the node namespace if needed
  		     */
  		    copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);
  		}
              }
  	    /*
               * all the attributes are directly inherited
               */
              if (cur->properties != NULL) {
                  xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
              }
  	    ctxt->inst = oldCurInst;
          }
  #endif /* else of XSLT_REFACTORED */
  
          /*
           * Descend into content in document order.
           */
          if (cur->children != NULL) {
              if (cur->children->type != XML_ENTITY_DECL) {
                  cur = cur->children;
  		level++;
                  if (copy != NULL)
                      insert = copy;
                  continue;
              }
          }
  
  skip_children:
  	/*
  	* If xslt:message was just processed, we might have hit a
  	* terminate='yes'; if so, then break the loop and clean up.
  	* TODO: Do we need to check this also before trying to descend
  	*  into the content?
  	*/
  	if (ctxt->state == XSLT_STATE_STOPPED)
  	    break;
          if (cur->next != NULL) {
              cur = cur->next;
              continue;
          }
  
          do {
              cur = cur->parent;
  	    level--;
  	    /*
  	    * Pop variables/params (xsl:variable and xsl:param).
  	    */
  	    if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) {
  		xsltLocalVariablePop(ctxt, oldVarsNr, level);
  	    }
  
              insert = insert->parent;
              if (cur == NULL)
                  break;
              if (cur == list->parent) {
                  cur = NULL;
                  break;
              }
              if (cur->next != NULL) {
                  cur = cur->next;
                  break;
              }
          } while (cur != NULL);
      }
  
  error:
      /*
      * In case of errors: pop remaining variables.
      */
      if (ctxt->varsNr > oldVarsNr)
  	xsltLocalVariablePop(ctxt, oldVarsNr, -1);
  
      ctxt->node = oldContextNode;
      ctxt->inst = oldInst;
      ctxt->insert = oldInsert;
  
      ctxt->depth--;
  
  #ifdef WITH_DEBUGGER
      if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
          xslDropCall();
      }
  #endif
  }
  
  /*
  * xsltApplyXSLTTemplate:
  * @ctxt:  a XSLT transformation context
  * @contextNode:  the node in the source tree.
  * @list:  the nodes of a sequence constructor;
  *         (plus leading xsl:param elements)
  * @templ: the compiled xsl:template declaration;
  *         NULL if a sequence constructor
  * @withParams:  a set of caller-parameters (xsl:with-param) or NULL
  *
  * Called by:
  * - xsltApplyImports()
  * - xsltCallTemplate()
  * - xsltDefaultProcessOneNode()
  * - xsltProcessOneNode()
  */
  static void
  xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
  		      xmlNodePtr contextNode,
  		      xmlNodePtr list,
  		      xsltTemplatePtr templ,
  		      xsltStackElemPtr withParams)
  {
      int oldVarsBase = 0;
      xmlNodePtr cur;
      xsltStackElemPtr tmpParam = NULL;
      xmlDocPtr oldUserFragmentTop;
  #ifdef WITH_PROFILER
      long start = 0;
  #endif
  
  #ifdef XSLT_REFACTORED
      xsltStyleItemParamPtr iparam;
  #else
      xsltStylePreCompPtr iparam;
  #endif
  
  #ifdef WITH_DEBUGGER
      int addCallResult = 0;
  #endif
  
      if (ctxt == NULL)
  	return;
      if (templ == NULL) {
  	xsltTransformError(ctxt, NULL, list,
  	    "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
  	return;
      }
  
  #ifdef WITH_DEBUGGER
      if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
  	if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
  		list, templ, &addCallResult) == NULL)
  	    return;
      }
  #endif
  
      if (list == NULL)
          return;
      CHECK_STOPPED;
  
      if (ctxt->varsNr >= ctxt->maxTemplateVars)
  	{
          xsltTransformError(ctxt, NULL, list,
  	    "xsltApplyXSLTTemplate: A potential infinite template recursion "
  	    "was detected.\n"
  	    "You can adjust maxTemplateVars (--maxvars) in order to "
  	    "raise the maximum number of variables/params (currently set to %d).\n",
  	    ctxt->maxTemplateVars);
          xsltDebug(ctxt, contextNode, list, NULL);
  	ctxt->state = XSLT_STATE_STOPPED;
          return;
  	}
  
      oldUserFragmentTop = ctxt->tmpRVT;
      ctxt->tmpRVT = NULL;
  
      /*
      * Initiate a distinct scope of local params/variables.
      */
      oldVarsBase = ctxt->varsBase;
      ctxt->varsBase = ctxt->varsNr;
  
      ctxt->node = contextNode;
  
  #ifdef WITH_PROFILER
      if (ctxt->profile) {
  	templ->nbCalls++;
  	start = xsltTimestamp();
  	profPush(ctxt, 0);
  	profCallgraphAdd(templ, ctxt->templ);
      }
  #endif
  
      /*
      * Push the xsl:template declaration onto the stack.
      */
      templPush(ctxt, templ);
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      if (templ->name != NULL)
  	XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
  	"applying xsl:template '%s'\n", templ->name));
  #endif
      /*
      * Process xsl:param instructions and skip those elements for
      * further processing.
      */
      cur = list;
      do {
  	if (cur->type == XML_TEXT_NODE) {
  	    cur = cur->next;
  	    continue;
  	}
  	if ((cur->type != XML_ELEMENT_NODE) ||
  	    (cur->name[0] != 'p') ||
  	    (cur->psvi == NULL) ||
  	    (! xmlStrEqual(cur->name, BAD_CAST "param")) ||
  	    (! IS_XSLT_ELEM(cur)))
  	{
  	    break;
  	}
  
  	list = cur->next;
  
  #ifdef XSLT_REFACTORED
  	iparam = (xsltStyleItemParamPtr) cur->psvi;
  #else
  	iparam = (xsltStylePreCompPtr) cur->psvi;
  #endif
  
  	/*
  	* Substitute xsl:param for a given xsl:with-param.
  	* Since the XPath expression will reference the params/vars
  	* by index, we need to slot the xsl:with-params in the
  	* order of encountered xsl:params to keep the sequence of
  	* params/variables in the stack exactly as it was at
  	* compile time,
  	*/
  	tmpParam = NULL;
  	if (withParams) {
  	    tmpParam = withParams;
  	    do {
  		if ((tmpParam->name == (iparam->name)) &&
  		    (tmpParam->nameURI == (iparam->ns)))
  		{
  		    /*
  		    * Push the caller-parameter.
  		    */
  		    xsltLocalVariablePush(ctxt, tmpParam, -1);
  		    break;
  		}
  		tmpParam = tmpParam->next;
  	    } while (tmpParam != NULL);
  	}
  	/*
  	* Push the xsl:param.
  	*/
  	if (tmpParam == NULL) {
  	    /*
  	    * Note that we must assume that the added parameter
  	    * has a @depth of 0.
  	    */
  	    xsltParseStylesheetParam(ctxt, cur);
  	}
  	cur = cur->next;
      } while (cur != NULL);
      /*
      * Process the sequence constructor.
      */
      xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
  
      /*
      * Remove remaining xsl:param and xsl:with-param items from
      * the stack. Don't free xsl:with-param items.
      */
      if (ctxt->varsNr > ctxt->varsBase)
  	xsltTemplateParamsCleanup(ctxt);
      ctxt->varsBase = oldVarsBase;
  
      /*
      * Release user-created fragments stored in the scope
      * of xsl:template. Note that this mechanism is deprecated:
      * user code should now use xsltRegisterLocalRVT() instead
      * of the obsolete xsltRegisterTmpRVT().
      */
      if (ctxt->tmpRVT) {
  	xmlDocPtr curdoc = ctxt->tmpRVT, tmp;
  
  	while (curdoc != NULL) {
  	    tmp = curdoc;
  	    curdoc = (xmlDocPtr) curdoc->next;
  	    xsltReleaseRVT(ctxt, tmp);
  	}
      }
      ctxt->tmpRVT = oldUserFragmentTop;
  
      /*
      * Pop the xsl:template declaration from the stack.
      */
      templPop(ctxt);
  
  #ifdef WITH_PROFILER
      if (ctxt->profile) {
  	long spent, child, total, end;
  
  	end = xsltTimestamp();
  	child = profPop(ctxt);
  	total = end - start;
  	spent = total - child;
  	if (spent <= 0) {
  	    /*
  	    * Not possible unless the original calibration failed
  	    * we can try to correct it on the fly.
  	    */
  	    xsltCalibrateAdjust(spent);
  	    spent = 0;
  	}
  
  	templ->time += spent;
  	if (ctxt->profNr > 0)
  	    ctxt->profTab[ctxt->profNr - 1] += total;
      }
  #endif
  
  #ifdef WITH_DEBUGGER
      if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
          xslDropCall();
      }
  #endif
  }
  
  
  /**
   * xsltApplyOneTemplate:
   * @ctxt:  a XSLT process context
   * @contextNode:  the node in the source tree.
   * @list:  the nodes of a sequence constructor
   * @templ: not used
   * @params:  a set of parameters (xsl:param) or NULL
   *
   * Processes a sequence constructor on the current node in the source tree.
   *
   * @params are the already computed variable stack items; this function
   * pushes them on the variable stack, and pops them before exiting; it's
   * left to the caller to free or reuse @params afterwards. The initial
   * states of the variable stack will always be restored before this
   * function exits.
   * NOTE that this does *not* initiate a new distinct variable scope; i.e.
   * variables already on the stack are visible to the process. The caller's
   * side needs to start a new variable scope if needed (e.g. in exsl:function).
   *
   * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
   * provide a @templ); a non-NULL @templ might raise an error in the future.
   *
   * BIG NOTE: This function is not intended to process the content of an
   * xsl:template; it does not expect xsl:param instructions in @list and
   * will report errors if found.
   *
   * Called by:
   *  - xsltEvalVariable() (variables.c)
   *  - exsltFuncFunctionFunction() (libexsl/functions.c)
   */
  void
  xsltApplyOneTemplate(xsltTransformContextPtr ctxt,
  		     xmlNodePtr contextNode,
                       xmlNodePtr list,
  		     xsltTemplatePtr templ ATTRIBUTE_UNUSED,
                       xsltStackElemPtr params)
  {
      if ((ctxt == NULL) || (list == NULL))
  	return;
      CHECK_STOPPED;
  
      if (params) {
  	/*
  	 * This code should be obsolete - was previously used
  	 * by libexslt/functions.c, but due to bug 381319 the
  	 * logic there was changed.
  	 */
  	int oldVarsNr = ctxt->varsNr;
  
  	/*
  	* Push the given xsl:param(s) onto the variable stack.
  	*/
  	while (params != NULL) {
  	    xsltLocalVariablePush(ctxt, params, -1);
  	    params = params->next;
  	}
  	xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
  	/*
  	* Pop the given xsl:param(s) from the stack but don't free them.
  	*/
  	xsltLocalVariablePop(ctxt, oldVarsNr, -2);
      } else
  	xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
  }
  
  /************************************************************************
   *									*
   *		    XSLT-1.1 extensions					*
   *									*
   ************************************************************************/
  
  /**
   * xsltDocumentElem:
   * @ctxt:  an XSLT processing context
   * @node:  The current node
   * @inst:  the instruction in the stylesheet
   * @castedComp:  precomputed information
   *
   * Process an EXSLT/XSLT-1.1 document element
   */
  void
  xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
                   xmlNodePtr inst, xsltElemPreCompPtr castedComp)
  {
  #ifdef XSLT_REFACTORED
      xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp;
  #else
      xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
  #endif
      xsltStylesheetPtr style = NULL;
      int ret;
      xmlChar *filename = NULL, *prop, *elements;
      xmlChar *element, *end;
      xmlDocPtr res = NULL;
      xmlDocPtr oldOutput;
      xmlNodePtr oldInsert, root;
      const char *oldOutputFile;
      xsltOutputType oldType;
      xmlChar *URL = NULL;
      const xmlChar *method;
      const xmlChar *doctypePublic;
      const xmlChar *doctypeSystem;
      const xmlChar *version;
      const xmlChar *encoding;
      int redirect_write_append = 0;
  
      if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
          return;
  
      if (comp->filename == NULL) {
  
          if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
  	    /*
  	    * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
  	    *   (http://icl.com/saxon)
  	    * The @file is in no namespace.
  	    */
  #ifdef WITH_XSLT_DEBUG_EXTRA
              xsltGenericDebug(xsltGenericDebugContext,
                               "Found saxon:output extension\n");
  #endif
              URL = xsltEvalAttrValueTemplate(ctxt, inst,
                                                   (const xmlChar *) "file",
                                                   XSLT_SAXON_NAMESPACE);
  
  	    if (URL == NULL)
  		URL = xsltEvalAttrValueTemplate(ctxt, inst,
                                                   (const xmlChar *) "href",
                                                   XSLT_SAXON_NAMESPACE);
          } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
  #ifdef WITH_XSLT_DEBUG_EXTRA
              xsltGenericDebug(xsltGenericDebugContext,
                               "Found xalan:write extension\n");
  #endif
              URL = xsltEvalAttrValueTemplate(ctxt, inst,
                                                   (const xmlChar *)
                                                   "select",
                                                   XSLT_XALAN_NAMESPACE);
  	    if (URL != NULL) {
  		xmlXPathCompExprPtr cmp;
  		xmlChar *val;
  
  		/*
  		 * Trying to handle bug #59212
  		 * The value of the "select" attribute is an
  		 * XPath expression.
  		 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
  		 */
  		cmp = xmlXPathCtxtCompile(ctxt->xpathCtxt, URL);
                  val = xsltEvalXPathString(ctxt, cmp);
  		xmlXPathFreeCompExpr(cmp);
  		xmlFree(URL);
  		URL = val;
  	    }
  	    if (URL == NULL)
  		URL = xsltEvalAttrValueTemplate(ctxt, inst,
  						     (const xmlChar *)
  						     "file",
  						     XSLT_XALAN_NAMESPACE);
  	    if (URL == NULL)
  		URL = xsltEvalAttrValueTemplate(ctxt, inst,
  						     (const xmlChar *)
  						     "href",
  						     XSLT_XALAN_NAMESPACE);
          } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
              URL = xsltEvalAttrValueTemplate(ctxt, inst,
                                                   (const xmlChar *) "href",
                                                   NULL);
          }
  
      } else {
          URL = xmlStrdup(comp->filename);
      }
  
      if (URL == NULL) {
  	xsltTransformError(ctxt, NULL, inst,
  		         "xsltDocumentElem: href/URI-Reference not found\n");
  	return;
      }
  
      /*
       * If the computation failed, it's likely that the URL wasn't escaped
       */
      filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile);
      if (filename == NULL) {
  	xmlChar *escURL;
  
  	escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,");
  	if (escURL != NULL) {
  	    filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile);
  	    xmlFree(escURL);
  	}
      }
  
      if (filename == NULL) {
  	xsltTransformError(ctxt, NULL, inst,
  		         "xsltDocumentElem: URL computation failed for %s\n",
  			 URL);
  	xmlFree(URL);
  	return;
      }
  
      /*
       * Security checking: can we write to this resource
       */
      if (ctxt->sec != NULL) {
  	ret = xsltCheckWrite(ctxt->sec, ctxt, filename);
  	if (ret <= 0) {
              if (ret == 0)
                  xsltTransformError(ctxt, NULL, inst,
                       "xsltDocumentElem: write rights for %s denied\n",
                                   filename);
  	    xmlFree(URL);
  	    xmlFree(filename);
  	    return;
  	}
      }
  
      oldOutputFile = ctxt->outputFile;
      oldOutput = ctxt->output;
      oldInsert = ctxt->insert;
      oldType = ctxt->type;
      ctxt->outputFile = (const char *) filename;
  
      style = xsltNewStylesheet();
      if (style == NULL) {
  	xsltTransformError(ctxt, NULL, inst,
                           "xsltDocumentElem: out of memory\n");
          goto error;
      }
  
      /*
       * Version described in 1.1 draft allows full parameterization
       * of the output.
       */
      prop = xsltEvalAttrValueTemplate(ctxt, inst,
  				     (const xmlChar *) "version",
  				     NULL);
      if (prop != NULL) {
  	if (style->version != NULL)
  	    xmlFree(style->version);
  	style->version = prop;
      }
      prop = xsltEvalAttrValueTemplate(ctxt, inst,
  				     (const xmlChar *) "encoding",
  				     NULL);
      if (prop != NULL) {
  	if (style->encoding != NULL)
  	    xmlFree(style->encoding);
  	style->encoding = prop;
      }
      prop = xsltEvalAttrValueTemplate(ctxt, inst,
  				     (const xmlChar *) "method",
  				     NULL);
      if (prop != NULL) {
  	const xmlChar *URI;
  
  	if (style->method != NULL)
  	    xmlFree(style->method);
  	style->method = NULL;
  	if (style->methodURI != NULL)
  	    xmlFree(style->methodURI);
  	style->methodURI = NULL;
  
  	URI = xsltGetQNameURI(inst, &prop);
  	if (prop == NULL) {
  	    if (style != NULL) style->errors++;
  	} else if (URI == NULL) {
  	    if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
  		(xmlStrEqual(prop, (const xmlChar *) "html")) ||
  		(xmlStrEqual(prop, (const xmlChar *) "text"))) {
  		style->method = prop;
  	    } else {
  		xsltTransformError(ctxt, NULL, inst,
  				 "invalid value for method: %s\n", prop);
  		if (style != NULL) style->warnings++;
  	    }
  	} else {
  	    style->method = prop;
  	    style->methodURI = xmlStrdup(URI);
  	}
      }
      prop = xsltEvalAttrValueTemplate(ctxt, inst,
  				     (const xmlChar *)
  				     "doctype-system", NULL);
      if (prop != NULL) {
  	if (style->doctypeSystem != NULL)
  	    xmlFree(style->doctypeSystem);
  	style->doctypeSystem = prop;
      }
      prop = xsltEvalAttrValueTemplate(ctxt, inst,
  				     (const xmlChar *)
  				     "doctype-public", NULL);
      if (prop != NULL) {
  	if (style->doctypePublic != NULL)
  	    xmlFree(style->doctypePublic);
  	style->doctypePublic = prop;
      }
      prop = xsltEvalAttrValueTemplate(ctxt, inst,
  				     (const xmlChar *) "standalone",
  				     NULL);
      if (prop != NULL) {
  	if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
  	    style->standalone = 1;
  	} else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
  	    style->standalone = 0;
  	} else {
  	    xsltTransformError(ctxt, NULL, inst,
  			     "invalid value for standalone: %s\n",
  			     prop);
  	    if (style != NULL) style->warnings++;
  	}
  	xmlFree(prop);
      }
  
      prop = xsltEvalAttrValueTemplate(ctxt, inst,
  				     (const xmlChar *) "indent",
  				     NULL);
      if (prop != NULL) {
  	if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
  	    style->indent = 1;
  	} else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
  	    style->indent = 0;
  	} else {
  	    xsltTransformError(ctxt, NULL, inst,
  			     "invalid value for indent: %s\n", prop);
  	    if (style != NULL) style->warnings++;
  	}
  	xmlFree(prop);
      }
  
      prop = xsltEvalAttrValueTemplate(ctxt, inst,
  				     (const xmlChar *)
  				     "omit-xml-declaration",
  				     NULL);
      if (prop != NULL) {
  	if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
  	    style->omitXmlDeclaration = 1;
  	} else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
  	    style->omitXmlDeclaration = 0;
  	} else {
  	    xsltTransformError(ctxt, NULL, inst,
  			     "invalid value for omit-xml-declaration: %s\n",
  			     prop);
  	    if (style != NULL) style->warnings++;
  	}
  	xmlFree(prop);
      }
  
      elements = xsltEvalAttrValueTemplate(ctxt, inst,
  					 (const xmlChar *)
  					 "cdata-section-elements",
  					 NULL);
      if (elements != NULL) {
  	if (style->stripSpaces == NULL)
  	    style->stripSpaces = xmlHashCreate(10);
  	if (style->stripSpaces == NULL)
  	    return;
  
  	element = elements;
  	while (*element != 0) {
  	    while (IS_BLANK_CH(*element))
  		element++;
  	    if (*element == 0)
  		break;
  	    end = element;
  	    while ((*end != 0) && (!IS_BLANK_CH(*end)))
  		end++;
  	    element = xmlStrndup(element, end - element);
  	    if (element) {
  		const xmlChar *URI;
  
  #ifdef WITH_XSLT_DEBUG_PARSING
  		xsltGenericDebug(xsltGenericDebugContext,
  				 "add cdata section output element %s\n",
  				 element);
  #endif
                  URI = xsltGetQNameURI(inst, &element);
  
  		xmlHashAddEntry2(style->stripSpaces, element, URI,
  			        (xmlChar *) "cdata");
  		xmlFree(element);
  	    }
  	    element = end;
  	}
  	xmlFree(elements);
      }
  
      /*
       * Create a new document tree and process the element template
       */
      XSLT_GET_IMPORT_PTR(method, style, method)
      XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
      XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
      XSLT_GET_IMPORT_PTR(version, style, version)
      XSLT_GET_IMPORT_PTR(encoding, style, encoding)
  
      if ((method != NULL) &&
  	(!xmlStrEqual(method, (const xmlChar *) "xml"))) {
  	if (xmlStrEqual(method, (const xmlChar *) "html")) {
  	    ctxt->type = XSLT_OUTPUT_HTML;
  	    if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
  		res = htmlNewDoc(doctypeSystem, doctypePublic);
  	    else {
  		if (version != NULL) {
  #ifdef XSLT_GENERATE_HTML_DOCTYPE
  		    xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
  #endif
                  }
  		res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
  	    }
  	    if (res == NULL)
  		goto error;
  	    res->dict = ctxt->dict;
  	    xmlDictReference(res->dict);
  	} else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
  	    xsltTransformError(ctxt, NULL, inst,
  	     "xsltDocumentElem: unsupported method xhtml\n");
  	    ctxt->type = XSLT_OUTPUT_HTML;
  	    res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
  	    if (res == NULL)
  		goto error;
  	    res->dict = ctxt->dict;
  	    xmlDictReference(res->dict);
  	} else if (xmlStrEqual(method, (const xmlChar *) "text")) {
  	    ctxt->type = XSLT_OUTPUT_TEXT;
  	    res = xmlNewDoc(style->version);
  	    if (res == NULL)
  		goto error;
  	    res->dict = ctxt->dict;
  	    xmlDictReference(res->dict);
  #ifdef WITH_XSLT_DEBUG
  	    xsltGenericDebug(xsltGenericDebugContext,
                       "reusing transformation dict for output\n");
  #endif
  	} else {
  	    xsltTransformError(ctxt, NULL, inst,
  			     "xsltDocumentElem: unsupported method (%s)\n",
  		             method);
  	    goto error;
  	}
      } else {
  	ctxt->type = XSLT_OUTPUT_XML;
  	res = xmlNewDoc(style->version);
  	if (res == NULL)
  	    goto error;
  	res->dict = ctxt->dict;
  	xmlDictReference(res->dict);
  #ifdef WITH_XSLT_DEBUG
  	xsltGenericDebug(xsltGenericDebugContext,
                       "reusing transformation dict for output\n");
  #endif
      }
      res->charset = XML_CHAR_ENCODING_UTF8;
      if (encoding != NULL)
  	res->encoding = xmlStrdup(encoding);
      ctxt->output = res;
      ctxt->insert = (xmlNodePtr) res;
      xsltApplySequenceConstructor(ctxt, node, inst->children, NULL);
  
      /*
       * Do some post processing work depending on the generated output
       */
      root = xmlDocGetRootElement(res);
      if (root != NULL) {
          const xmlChar *doctype = NULL;
  
          if ((root->ns != NULL) && (root->ns->prefix != NULL))
  	    doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
  	if (doctype == NULL)
  	    doctype = root->name;
  
          /*
           * Apply the default selection of the method
           */
          if ((method == NULL) &&
              (root->ns == NULL) &&
              (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
              xmlNodePtr tmp;
  
              tmp = res->children;
              while ((tmp != NULL) && (tmp != root)) {
                  if (tmp->type == XML_ELEMENT_NODE)
                      break;
                  if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
                      break;
  		tmp = tmp->next;
              }
              if (tmp == root) {
                  ctxt->type = XSLT_OUTPUT_HTML;
                  res->type = XML_HTML_DOCUMENT_NODE;
                  if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
                      res->intSubset = xmlCreateIntSubset(res, doctype,
                                                          doctypePublic,
                                                          doctypeSystem);
  #ifdef XSLT_GENERATE_HTML_DOCTYPE
  		} else if (version != NULL) {
                      xsltGetHTMLIDs(version, &doctypePublic,
                                     &doctypeSystem);
                      if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
                          res->intSubset =
                              xmlCreateIntSubset(res, doctype,
                                                 doctypePublic,
                                                 doctypeSystem);
  #endif
                  }
              }
  
          }
          if (ctxt->type == XSLT_OUTPUT_XML) {
              XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
                  XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
                  if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
                  res->intSubset = xmlCreateIntSubset(res, doctype,
                                                      doctypePublic,
                                                      doctypeSystem);
          }
      }
  
      /*
       * Calls to redirect:write also take an optional attribute append.
       * Attribute append="true|yes" which will attempt to simply append
       * to an existing file instead of always opening a new file. The
       * default behavior of always overwriting the file still happens
       * if we do not specify append.
       * Note that append use will forbid use of remote URI target.
       */
      prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"append",
  				     NULL);
      if (prop != NULL) {
  	if (xmlStrEqual(prop, (const xmlChar *) "true") ||
  	    xmlStrEqual(prop, (const xmlChar *) "yes")) {
  	    style->omitXmlDeclaration = 1;
  	    redirect_write_append = 1;
  	} else
  	    style->omitXmlDeclaration = 0;
  	xmlFree(prop);
      }
  
      if (redirect_write_append) {
          FILE *f;
  
  	f = fopen((const char *) filename, "ab");
  	if (f == NULL) {
  	    ret = -1;
  	} else {
  	    ret = xsltSaveResultToFile(f, res, style);
  	    fclose(f);
  	}
      } else {
  	ret = xsltSaveResultToFilename((const char *) filename, res, style, 0);
      }
      if (ret < 0) {
  	xsltTransformError(ctxt, NULL, inst,
                           "xsltDocumentElem: unable to save to %s\n",
                           filename);
  #ifdef WITH_XSLT_DEBUG_EXTRA
      } else {
          xsltGenericDebug(xsltGenericDebugContext,
                           "Wrote %d bytes to %s\n", ret, filename);
  #endif
      }
  
    error:
      ctxt->output = oldOutput;
      ctxt->insert = oldInsert;
      ctxt->type = oldType;
      ctxt->outputFile = oldOutputFile;
      if (URL != NULL)
          xmlFree(URL);
      if (filename != NULL)
          xmlFree(filename);
      if (style != NULL)
          xsltFreeStylesheet(style);
      if (res != NULL)
          xmlFreeDoc(res);
  }
  
  /************************************************************************
   *									*
   *		Most of the XSLT-1.0 transformations			*
   *									*
   ************************************************************************/
  
  /**
   * xsltSort:
   * @ctxt:  a XSLT process context
   * @node:  the node in the source tree.
   * @inst:  the xslt sort node
   * @comp:  precomputed information
   *
   * function attached to xsl:sort nodes, but this should not be
   * called directly
   */
  void
  xsltSort(xsltTransformContextPtr ctxt,
  	xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
  	xsltElemPreCompPtr comp) {
      if (comp == NULL) {
  	xsltTransformError(ctxt, NULL, inst,
  	     "xsl:sort : compilation failed\n");
  	return;
      }
      xsltTransformError(ctxt, NULL, inst,
  	 "xsl:sort : improper use this should not be reached\n");
  }
  
  /**
   * xsltCopy:
   * @ctxt:  an XSLT process context
   * @node:  the node in the source tree
   * @inst:  the element node of the XSLT-copy instruction
   * @castedComp:  computed information of the XSLT-copy instruction
   *
   * Execute the XSLT-copy instruction on the source node.
   */
  void
  xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
  	 xmlNodePtr inst, xsltElemPreCompPtr castedComp)
  {
  #ifdef XSLT_REFACTORED
      xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;
  #else
      xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
  #endif
      xmlNodePtr copy, oldInsert;
  
      oldInsert = ctxt->insert;
      if (ctxt->insert != NULL) {
  	switch (node->type) {
  	    case XML_TEXT_NODE:
  	    case XML_CDATA_SECTION_NODE:
  		/*
  		 * This text comes from the stylesheet
  		 * For stylesheets, the set of whitespace-preserving
  		 * element names consists of just xsl:text.
  		 */
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		if (node->type == XML_CDATA_SECTION_NODE) {
  		    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
  			 "xsltCopy: CDATA text %s\n", node->content));
  		} else {
  		    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
  			 "xsltCopy: text %s\n", node->content));
                  }
  #endif
  		xsltCopyText(ctxt, ctxt->insert, node, 0);
  		break;
  	    case XML_DOCUMENT_NODE:
  	    case XML_HTML_DOCUMENT_NODE:
  		break;
  	    case XML_ELEMENT_NODE:
  		/*
  		* REVISIT NOTE: The "fake" is a doc-node, not an element node.
  		* REMOVED:
  		*   if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
  		*    return;
  		*/
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
  				 "xsltCopy: node %s\n", node->name));
  #endif
  		copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);
  		ctxt->insert = copy;
  		if (comp->use != NULL) {
  		    xsltApplyAttributeSet(ctxt, node, inst, comp->use);
  		}
  		break;
  	    case XML_ATTRIBUTE_NODE: {
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
  				 "xsltCopy: attribute %s\n", node->name));
  #endif
  		/*
  		* REVISIT: We could also raise an error if the parent is not
  		* an element node.
  		* OPTIMIZE TODO: Can we set the value/children of the
  		* attribute without an intermediate copy of the string value?
  		*/
  		xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node);
  		break;
  	    }
  	    case XML_PI_NODE:
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
  				 "xsltCopy: PI %s\n", node->name));
  #endif
  		copy = xmlNewDocPI(ctxt->insert->doc, node->name,
  		                   node->content);
  		copy = xsltAddChild(ctxt->insert, copy);
  		break;
  	    case XML_COMMENT_NODE:
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
  				 "xsltCopy: comment\n"));
  #endif
  		copy = xmlNewComment(node->content);
  		copy = xsltAddChild(ctxt->insert, copy);
  		break;
  	    case XML_NAMESPACE_DECL:
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
  				 "xsltCopy: namespace declaration\n"));
  #endif
  		xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node);
  		break;
  	    default:
  		break;
  
  	}
      }
  
      switch (node->type) {
  	case XML_DOCUMENT_NODE:
  	case XML_HTML_DOCUMENT_NODE:
  	case XML_ELEMENT_NODE:
  	    xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
  		NULL);
  	    break;
  	default:
  	    break;
      }
      ctxt->insert = oldInsert;
  }
  
  /**
   * xsltText:
   * @ctxt:  a XSLT process context
   * @node:  the node in the source tree.
   * @inst:  the xslt text node
   * @comp:  precomputed information
   *
   * Process the xslt text node on the source node
   */
  void
  xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
  	    xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
      if ((inst->children != NULL) && (comp != NULL)) {
  	xmlNodePtr text = inst->children;
  	xmlNodePtr copy;
  
  	while (text != NULL) {
  	    if ((text->type != XML_TEXT_NODE) &&
  	         (text->type != XML_CDATA_SECTION_NODE)) {
  		xsltTransformError(ctxt, NULL, inst,
  				 "xsl:text content problem\n");
  		break;
  	    }
  	    copy = xmlNewDocText(ctxt->output, text->content);
  	    if (text->type != XML_CDATA_SECTION_NODE) {
  #ifdef WITH_XSLT_DEBUG_PARSING
  		xsltGenericDebug(xsltGenericDebugContext,
  		     "Disable escaping: %s\n", text->content);
  #endif
  		copy->name = xmlStringTextNoenc;
  	    }
  	    copy = xsltAddChild(ctxt->insert, copy);
  	    text = text->next;
  	}
      }
  }
  
  /**
   * xsltElement:
   * @ctxt:  a XSLT process context
   * @node:  the node in the source tree.
   * @inst:  the xslt element node
   * @castedComp:  precomputed information
   *
   * Process the xslt element node on the source node
   */
  void
  xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
  	    xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
  #ifdef XSLT_REFACTORED
      xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp;
  #else
      xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
  #endif
      xmlChar *prop = NULL;
      const xmlChar *name, *prefix = NULL, *nsName = NULL;
      xmlNodePtr copy;
      xmlNodePtr oldInsert;
  
      if (ctxt->insert == NULL)
  	return;
  
      /*
      * A comp->has_name == 0 indicates that we need to skip this instruction,
      * since it was evaluated to be invalid already during compilation.
      */
      if (!comp->has_name)
          return;
  
      /*
       * stack and saves
       */
      oldInsert = ctxt->insert;
  
      if (comp->name == NULL) {
  	/* TODO: fix attr acquisition wrt to the XSLT namespace */
          prop = xsltEvalAttrValueTemplate(ctxt, inst,
  	    (const xmlChar *) "name", XSLT_NAMESPACE);
          if (prop == NULL) {
              xsltTransformError(ctxt, NULL, inst,
  		"xsl:element: The attribute 'name' is missing.\n");
              goto error;
          }
  	if (xmlValidateQName(prop, 0)) {
  	    xsltTransformError(ctxt, NULL, inst,
  		"xsl:element: The effective name '%s' is not a "
  		"valid QName.\n", prop);
  	    /* we fall through to catch any further errors, if possible */
  	}
  	name = xsltSplitQName(ctxt->dict, prop, &prefix);
  	xmlFree(prop);
      } else {
  	/*
  	* The "name" value was static.
  	*/
  #ifdef XSLT_REFACTORED
  	prefix = comp->nsPrefix;
  	name = comp->name;
  #else
  	name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
  #endif
      }
  
      /*
       * Create the new element
       */
      if (ctxt->output->dict == ctxt->dict) {
  	copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL);
      } else {
  	copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL);
      }
      if (copy == NULL) {
  	xsltTransformError(ctxt, NULL, inst,
  	    "xsl:element : creation of %s failed\n", name);
  	return;
      }
      copy = xsltAddChild(ctxt->insert, copy);
      if (copy == NULL) {
          xsltTransformError(ctxt, NULL, inst,
              "xsl:element : xsltAddChild failed\n");
          return;
      }
  
      /*
      * Namespace
      * ---------
      */
      if (comp->has_ns) {
  	if (comp->ns != NULL) {
  	    /*
  	    * No AVT; just plain text for the namespace name.
  	    */
  	    if (comp->ns[0] != 0)
  		nsName = comp->ns;
  	} else {
  	    xmlChar *tmpNsName;
  	    /*
  	    * Eval the AVT.
  	    */
  	    /* TODO: check attr acquisition wrt to the XSLT namespace */
  	    tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
  		(const xmlChar *) "namespace", XSLT_NAMESPACE);
  	    /*
  	    * SPEC XSLT 1.0:
  	    *  "If the string is empty, then the expanded-name of the
  	    *  attribute has a null namespace URI."
  	    */
  	    if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
  		nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
  	    xmlFree(tmpNsName);
  	}
  
          if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
              xsltTransformError(ctxt, NULL, inst,
                  "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
                  "forbidden.\n");
              goto error;
          }
          if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
              prefix = BAD_CAST "xml";
          } else if (xmlStrEqual(prefix, BAD_CAST "xml")) {
              prefix = NULL;
          }
      } else {
  	xmlNsPtr ns;
  	/*
  	* SPEC XSLT 1.0:
  	*  "If the namespace attribute is not present, then the QName is
  	*  expanded into an expanded-name using the namespace declarations
  	*  in effect for the xsl:element element, including any default
  	*  namespace declaration.
  	*/
  	ns = xmlSearchNs(inst->doc, inst, prefix);
  	if (ns == NULL) {
  	    /*
  	    * TODO: Check this in the compilation layer in case it's a
  	    * static value.
  	    */
              if (prefix != NULL) {
                  xsltTransformError(ctxt, NULL, inst,
                      "xsl:element: The QName '%s:%s' has no "
                      "namespace binding in scope in the stylesheet; "
                      "this is an error, since the namespace was not "
                      "specified by the instruction itself.\n", prefix, name);
              }
  	} else
  	    nsName = ns->href;
      }
      /*
      * Find/create a matching ns-decl in the result tree.
      */
      if (nsName != NULL) {
  	if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
              /* Don't use a prefix of "xmlns" */
  	    xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");
  
  	    copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, copy);
  
  	    xmlFree(pref);
  	} else {
  	    copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix,
  		copy);
  	}
      } else if ((copy->parent != NULL) &&
  	(copy->parent->type == XML_ELEMENT_NODE) &&
  	(copy->parent->ns != NULL))
      {
  	/*
  	* "Undeclare" the default namespace.
  	*/
  	xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);
      }
  
      ctxt->insert = copy;
  
      if (comp->has_use) {
  	if (comp->use != NULL) {
  	    xsltApplyAttributeSet(ctxt, node, inst, comp->use);
  	} else {
  	    xmlChar *attrSets = NULL;
  	    /*
  	    * BUG TODO: use-attribute-sets is not a value template.
  	    *  use-attribute-sets = qnames
  	    */
  	    attrSets = xsltEvalAttrValueTemplate(ctxt, inst,
  		(const xmlChar *)"use-attribute-sets", NULL);
  	    if (attrSets != NULL) {
  		xsltApplyAttributeSet(ctxt, node, inst, attrSets);
  		xmlFree(attrSets);
  	    }
  	}
      }
      /*
      * Instantiate the sequence constructor.
      */
      if (inst->children != NULL)
  	xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
  	    NULL);
  
  error:
      ctxt->insert = oldInsert;
      return;
  }
  
  
  /**
   * xsltComment:
   * @ctxt:  a XSLT process context
   * @node:  the node in the source tree.
   * @inst:  the xslt comment node
   * @comp:  precomputed information
   *
   * Process the xslt comment node on the source node
   */
  void
  xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node,
  	           xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
      xmlChar *value = NULL;
      xmlNodePtr commentNode;
      int len;
  
      value = xsltEvalTemplateString(ctxt, node, inst);
      /* TODO: use or generate the compiled form */
      len = xmlStrlen(value);
      if (len > 0) {
          if ((value[len-1] == '-') ||
  	    (xmlStrstr(value, BAD_CAST "--"))) {
  	    xsltTransformError(ctxt, NULL, inst,
  		    "xsl:comment : '--' or ending '-' not allowed in comment\n");
  	    /* fall through to try to catch further errors */
  	}
      }
  #ifdef WITH_XSLT_DEBUG_PROCESS
      if (value == NULL) {
  	XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltComment: empty\n"));
      } else {
  	XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltComment: content %s\n", value));
      }
  #endif
  
      commentNode = xmlNewComment(value);
      commentNode = xsltAddChild(ctxt->insert, commentNode);
  
      if (value != NULL)
  	xmlFree(value);
  }
  
  /**
   * xsltProcessingInstruction:
   * @ctxt:  a XSLT process context
   * @node:  the node in the source tree.
   * @inst:  the xslt processing-instruction node
   * @castedComp:  precomputed information
   *
   * Process the xslt processing-instruction node on the source node
   */
  void
  xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node,
  	           xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
  #ifdef XSLT_REFACTORED
      xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp;
  #else
      xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
  #endif
      const xmlChar *name;
      xmlChar *value = NULL;
      xmlNodePtr pi;
  
  
      if (ctxt->insert == NULL)
  	return;
      if (comp->has_name == 0)
  	return;
      if (comp->name == NULL) {
  	name = xsltEvalAttrValueTemplate(ctxt, inst,
  			    (const xmlChar *)"name", NULL);
  	if (name == NULL) {
  	    xsltTransformError(ctxt, NULL, inst,
  		 "xsl:processing-instruction : name is missing\n");
  	    goto error;
  	}
      } else {
  	name = comp->name;
      }
      /* TODO: check that it's both an an NCName and a PITarget. */
  
  
      value = xsltEvalTemplateString(ctxt, node, inst);
      if (xmlStrstr(value, BAD_CAST "?>") != NULL) {
  	xsltTransformError(ctxt, NULL, inst,
  	     "xsl:processing-instruction: '?>' not allowed within PI content\n");
  	goto error;
      }
  #ifdef WITH_XSLT_DEBUG_PROCESS
      if (value == NULL) {
  	XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltProcessingInstruction: %s empty\n", name));
      } else {
  	XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltProcessingInstruction: %s content %s\n", name, value));
      }
  #endif
  
      pi = xmlNewDocPI(ctxt->insert->doc, name, value);
      pi = xsltAddChild(ctxt->insert, pi);
  
  error:
      if ((name != NULL) && (name != comp->name))
          xmlFree((xmlChar *) name);
      if (value != NULL)
  	xmlFree(value);
  }
  
  /**
   * xsltCopyOf:
   * @ctxt:  an XSLT transformation context
   * @node:  the current node in the source tree
   * @inst:  the element node of the XSLT copy-of instruction
   * @castedComp:  precomputed information of the XSLT copy-of instruction
   *
   * Process the XSLT copy-of instruction.
   */
  void
  xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
  	           xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
  #ifdef XSLT_REFACTORED
      xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp;
  #else
      xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
  #endif
      xmlXPathObjectPtr res = NULL;
      xmlNodeSetPtr list = NULL;
      int i;
  
      if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
  	return;
      if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
  	xsltTransformError(ctxt, NULL, inst,
  	     "xsl:copy-of : compilation failed\n");
  	return;
      }
  
       /*
      * SPEC XSLT 1.0:
      *  "The xsl:copy-of element can be used to insert a result tree
      *  fragment into the result tree, without first converting it to
      *  a string as xsl:value-of does (see [7.6.1 Generating Text with
      *  xsl:value-of]). The required select attribute contains an
      *  expression. When the result of evaluating the expression is a
      *  result tree fragment, the complete fragment is copied into the
      *  result tree. When the result is a node-set, all the nodes in the
      *  set are copied in document order into the result tree; copying
      *  an element node copies the attribute nodes, namespace nodes and
      *  children of the element node as well as the element node itself;
      *  a root node is copied by copying its children. When the result
      *  is neither a node-set nor a result tree fragment, the result is
      *  converted to a string and then inserted into the result tree,
      *  as with xsl:value-of.
      */
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
  	 "xsltCopyOf: select %s\n", comp->select));
  #endif
  
      /*
      * Evaluate the "select" expression.
      */
      res = xsltPreCompEval(ctxt, node, comp);
  
      if (res != NULL) {
  	if (res->type == XPATH_NODESET) {
  	    /*
  	    * Node-set
  	    * --------
  	    */
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
  		 "xsltCopyOf: result is a node set\n"));
  #endif
  	    list = res->nodesetval;
  	    if (list != NULL) {
  		xmlNodePtr cur;
  		/*
  		* The list is already sorted in document order by XPath.
  		* Append everything in this order under ctxt->insert.
  		*/
  		for (i = 0;i < list->nodeNr;i++) {
  		    cur = list->nodeTab[i];
  		    if (cur == NULL)
  			continue;
  		    if ((cur->type == XML_DOCUMENT_NODE) ||
  			(cur->type == XML_HTML_DOCUMENT_NODE))
  		    {
  			xsltCopyTreeList(ctxt, inst,
  			    cur->children, ctxt->insert, 0, 0);
  		    } else if (cur->type == XML_ATTRIBUTE_NODE) {
  			xsltShallowCopyAttr(ctxt, inst,
  			    ctxt->insert, (xmlAttrPtr) cur);
  		    } else {
  			xsltCopyTree(ctxt, inst, cur, ctxt->insert, 0, 0);
  		    }
  		}
  	    }
  	} else if (res->type == XPATH_XSLT_TREE) {
  	    /*
  	    * Result tree fragment
  	    * --------------------
  	    * E.g. via <xsl:variable ...><foo/></xsl:variable>
  	    * Note that the root node of such trees is an xmlDocPtr in Libxslt.
  	    */
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
  		 "xsltCopyOf: result is a result tree fragment\n"));
  #endif
  	    list = res->nodesetval;
  	    if ((list != NULL) && (list->nodeTab != NULL) &&
  		(list->nodeTab[0] != NULL) &&
  		(IS_XSLT_REAL_NODE(list->nodeTab[0])))
  	    {
  		xsltCopyTreeList(ctxt, inst,
  		    list->nodeTab[0]->children, ctxt->insert, 0, 0);
  	    }
  	} else {
  	    xmlChar *value = NULL;
  	    /*
  	    * Convert to a string.
  	    */
  	    value = xmlXPathCastToString(res);
  	    if (value == NULL) {
  		xsltTransformError(ctxt, NULL, inst,
  		    "Internal error in xsltCopyOf(): "
  		    "failed to cast an XPath object to string.\n");
  		ctxt->state = XSLT_STATE_STOPPED;
  	    } else {
  		if (value[0] != 0) {
  		    /*
  		    * Append content as text node.
  		    */
  		    xsltCopyTextString(ctxt, ctxt->insert, value, 0);
  		}
  		xmlFree(value);
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
  		    "xsltCopyOf: result %s\n", res->stringval));
  #endif
  	    }
  	}
      } else {
  	ctxt->state = XSLT_STATE_STOPPED;
      }
  
      if (res != NULL)
  	xmlXPathFreeObject(res);
  }
  
  /**
   * xsltValueOf:
   * @ctxt:  a XSLT process context
   * @node:  the node in the source tree.
   * @inst:  the xslt value-of node
   * @castedComp:  precomputed information
   *
   * Process the xslt value-of node on the source node
   */
  void
  xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
  	           xmlNodePtr inst, xsltElemPreCompPtr castedComp)
  {
  #ifdef XSLT_REFACTORED
      xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp;
  #else
      xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
  #endif
      xmlXPathObjectPtr res = NULL;
      xmlChar *value = NULL;
  
      if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
  	return;
  
      if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
  	xsltTransformError(ctxt, NULL, inst,
  	    "Internal error in xsltValueOf(): "
  	    "The XSLT 'value-of' instruction was not compiled.\n");
  	return;
      }
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
  	 "xsltValueOf: select %s\n", comp->select));
  #endif
  
      res = xsltPreCompEval(ctxt, node, comp);
  
      /*
      * Cast the XPath object to string.
      */
      if (res != NULL) {
  	value = xmlXPathCastToString(res);
  	if (value == NULL) {
  	    xsltTransformError(ctxt, NULL, inst,
  		"Internal error in xsltValueOf(): "
  		"failed to cast an XPath object to string.\n");
  	    ctxt->state = XSLT_STATE_STOPPED;
  	    goto error;
  	}
  	if (value[0] != 0) {
  	    xsltCopyTextString(ctxt, ctxt->insert, value, comp->noescape);
  	}
      } else {
  	xsltTransformError(ctxt, NULL, inst,
  	    "XPath evaluation returned no result.\n");
  	ctxt->state = XSLT_STATE_STOPPED;
  	goto error;
      }
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      if (value) {
  	XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltValueOf: result '%s'\n", value));
      }
  #endif
  
  error:
      if (value != NULL)
  	xmlFree(value);
      if (res != NULL)
  	xmlXPathFreeObject(res);
  }
  
  /**
   * xsltNumber:
   * @ctxt:  a XSLT process context
   * @node:  the node in the source tree.
   * @inst:  the xslt number node
   * @castedComp:  precomputed information
   *
   * Process the xslt number node on the source node
   */
  void
  xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node,
  	   xmlNodePtr inst, xsltElemPreCompPtr castedComp)
  {
  #ifdef XSLT_REFACTORED
      xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp;
  #else
      xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
  #endif
      xmlXPathContextPtr xpctxt;
      xmlNsPtr *oldXPNamespaces;
      int oldXPNsNr;
  
      if (comp == NULL) {
  	xsltTransformError(ctxt, NULL, inst,
  	     "xsl:number : compilation failed\n");
  	return;
      }
  
      if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
  	return;
  
      comp->numdata.doc = inst->doc;
      comp->numdata.node = inst;
  
      xpctxt = ctxt->xpathCtxt;
      oldXPNsNr = xpctxt->nsNr;
      oldXPNamespaces = xpctxt->namespaces;
  
  #ifdef XSLT_REFACTORED
      if (comp->inScopeNs != NULL) {
          xpctxt->namespaces = comp->inScopeNs->list;
          xpctxt->nsNr = comp->inScopeNs->xpathNumber;
      } else {
          xpctxt->namespaces = NULL;
          xpctxt->nsNr = 0;
      }
  #else
      xpctxt->namespaces = comp->nsList;
      xpctxt->nsNr = comp->nsNr;
  #endif
  
      xsltNumberFormat(ctxt, &comp->numdata, node);
  
      xpctxt->nsNr = oldXPNsNr;
      xpctxt->namespaces = oldXPNamespaces;
  }
  
  /**
   * xsltApplyImports:
   * @ctxt:  an XSLT transformation context
   * @contextNode:  the current node in the source tree.
   * @inst:  the element node of the XSLT 'apply-imports' instruction
   * @comp:  the compiled instruction
   *
   * Process the XSLT apply-imports element.
   */
  void
  xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
  	         xmlNodePtr inst,
  		 xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
  {
      xsltTemplatePtr templ;
  
      if ((ctxt == NULL) || (inst == NULL))
  	return;
  
      if (comp == NULL) {
  	xsltTransformError(ctxt, NULL, inst,
  	    "Internal error in xsltApplyImports(): "
  	    "The XSLT 'apply-imports' instruction was not compiled.\n");
  	return;
      }
      /*
      * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
      * same; the former is the "Current Template Rule" as defined by the
      * XSLT spec, the latter is simply the template struct being
      * currently processed.
      */
      if (ctxt->currentTemplateRule == NULL) {
  	/*
  	* SPEC XSLT 2.0:
  	* "[ERR XTDE0560] It is a non-recoverable dynamic error if
  	*  xsl:apply-imports or xsl:next-match is evaluated when the
  	*  current template rule is null."
  	*/
  	xsltTransformError(ctxt, NULL, inst,
  	     "It is an error to call 'apply-imports' "
  	     "when there's no current template rule.\n");
  	return;
      }
      /*
      * TODO: Check if this is correct.
      */
      templ = xsltGetTemplate(ctxt, contextNode,
  	ctxt->currentTemplateRule->style);
  
      if (templ != NULL) {
  	xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule;
  	/*
  	* Set the current template rule.
  	*/
  	ctxt->currentTemplateRule = templ;
  	/*
  	* URGENT TODO: Need xsl:with-param be handled somehow here?
  	*/
  	xsltApplyXSLTTemplate(ctxt, contextNode, templ->content,
  	    templ, NULL);
  
  	ctxt->currentTemplateRule = oldCurTemplRule;
      }
      else {
          /* Use built-in templates. */
          xsltDefaultProcessOneNode(ctxt, contextNode, NULL);
      }
  }
  
  /**
   * xsltCallTemplate:
   * @ctxt:  a XSLT transformation context
   * @node:  the "current node" in the source tree
   * @inst:  the XSLT 'call-template' instruction
   * @castedComp:  the compiled information of the instruction
   *
   * Processes the XSLT call-template instruction on the source node.
   */
  void
  xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
  	           xmlNodePtr inst, xsltElemPreCompPtr castedComp)
  {
  #ifdef XSLT_REFACTORED
      xsltStyleItemCallTemplatePtr comp =
  	(xsltStyleItemCallTemplatePtr) castedComp;
  #else
      xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
  #endif
      xsltStackElemPtr withParams = NULL;
  
      if (ctxt->insert == NULL)
  	return;
      if (comp == NULL) {
  	xsltTransformError(ctxt, NULL, inst,
  	     "The XSLT 'call-template' instruction was not compiled.\n");
  	return;
      }
  
      /*
       * The template must have been precomputed
       */
      if (comp->templ == NULL) {
  	comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);
  	if (comp->templ == NULL) {
  	    if (comp->ns != NULL) {
  	        xsltTransformError(ctxt, NULL, inst,
  			"The called template '{%s}%s' was not found.\n",
  			comp->ns, comp->name);
  	    } else {
  	        xsltTransformError(ctxt, NULL, inst,
  			"The called template '%s' was not found.\n",
  			comp->name);
  	    }
  	    return;
  	}
      }
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      if ((comp != NULL) && (comp->name != NULL))
  	XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
  			 "call-template: name %s\n", comp->name));
  #endif
  
      if (inst->children) {
  	xmlNodePtr cur;
  	xsltStackElemPtr param;
  
  	cur = inst->children;
  	while (cur != NULL) {
  #ifdef WITH_DEBUGGER
  	    if (ctxt->debugStatus != XSLT_DEBUG_NONE)
  		xslHandleDebugger(cur, node, comp->templ, ctxt);
  #endif
  	    if (ctxt->state == XSLT_STATE_STOPPED) break;
  	    /*
  	    * TODO: The "with-param"s could be part of the "call-template"
  	    *   structure. Avoid to "search" for params dynamically
  	    *   in the XML tree every time.
  	    */
  	    if (IS_XSLT_ELEM(cur)) {
  		if (IS_XSLT_NAME(cur, "with-param")) {
  		    param = xsltParseStylesheetCallerParam(ctxt, cur);
  		    if (param != NULL) {
  			param->next = withParams;
  			withParams = param;
  		    }
  		} else {
  		    xsltGenericError(xsltGenericErrorContext,
  			"xsl:call-template: misplaced xsl:%s\n", cur->name);
  		}
  	    } else {
  		xsltGenericError(xsltGenericErrorContext,
  		    "xsl:call-template: misplaced %s element\n", cur->name);
  	    }
  	    cur = cur->next;
  	}
      }
      /*
       * Create a new frame using the params first
       */
      xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ,
  	withParams);
      if (withParams != NULL)
  	xsltFreeStackElemList(withParams);
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      if ((comp != NULL) && (comp->name != NULL))
  	XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
  			 "call-template returned: name %s\n", comp->name));
  #endif
  }
  
  /**
   * xsltApplyTemplates:
   * @ctxt:  a XSLT transformation context
   * @node:  the 'current node' in the source tree
   * @inst:  the element node of an XSLT 'apply-templates' instruction
   * @castedComp:  the compiled instruction
   *
   * Processes the XSLT 'apply-templates' instruction on the current node.
   */
  void
  xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
  	           xmlNodePtr inst, xsltElemPreCompPtr castedComp)
  {
  #ifdef XSLT_REFACTORED
      xsltStyleItemApplyTemplatesPtr comp =
  	(xsltStyleItemApplyTemplatesPtr) castedComp;
  #else
      xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
  #endif
      int i;
      xmlNodePtr cur, delNode = NULL, oldContextNode;
      xmlNodeSetPtr list = NULL, oldList;
      xsltStackElemPtr withParams = NULL;
      int oldXPProximityPosition, oldXPContextSize;
      const xmlChar *oldMode, *oldModeURI;
      xmlDocPtr oldXPDoc;
      xsltDocumentPtr oldDocInfo;
      xmlXPathContextPtr xpctxt;
  
      if (comp == NULL) {
  	xsltTransformError(ctxt, NULL, inst,
  	     "xsl:apply-templates : compilation failed\n");
  	return;
      }
      if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
  	return;
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      if ((node != NULL) && (node->name != NULL))
  	XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltApplyTemplates: node: '%s'\n", node->name));
  #endif
  
      xpctxt = ctxt->xpathCtxt;
      /*
      * Save context states.
      */
      oldContextNode = ctxt->node;
      oldMode = ctxt->mode;
      oldModeURI = ctxt->modeURI;
      oldDocInfo = ctxt->document;
      oldList = ctxt->nodeList;
  
      /*
       * The xpath context size and proximity position, as
       * well as the xpath and context documents, may be changed
       * so we save their initial state and will restore on exit
       */
      oldXPContextSize = xpctxt->contextSize;
      oldXPProximityPosition = xpctxt->proximityPosition;
      oldXPDoc = xpctxt->doc;
  
      /*
      * Set up contexts.
      */
      ctxt->mode = comp->mode;
      ctxt->modeURI = comp->modeURI;
  
      if (comp->select != NULL) {
  	xmlXPathObjectPtr res = NULL;
  
  	if (comp->comp == NULL) {
  	    xsltTransformError(ctxt, NULL, inst,
  		 "xsl:apply-templates : compilation failed\n");
  	    goto error;
  	}
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltApplyTemplates: select %s\n", comp->select));
  #endif
  
  	res = xsltPreCompEval(ctxt, node, comp);
  
  	if (res != NULL) {
  	    if (res->type == XPATH_NODESET) {
  		list = res->nodesetval; /* consume the node set */
  		res->nodesetval = NULL;
  	    } else {
  		xsltTransformError(ctxt, NULL, inst,
  		    "The 'select' expression did not evaluate to a "
  		    "node set.\n");
  		ctxt->state = XSLT_STATE_STOPPED;
  		xmlXPathFreeObject(res);
  		goto error;
  	    }
  	    xmlXPathFreeObject(res);
  	    /*
  	    * Note: An xsl:apply-templates with a 'select' attribute,
  	    * can change the current source doc.
  	    */
  	} else {
  	    xsltTransformError(ctxt, NULL, inst,
  		"Failed to evaluate the 'select' expression.\n");
  	    ctxt->state = XSLT_STATE_STOPPED;
  	    goto error;
  	}
  	if (list == NULL) {
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	    XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
  		"xsltApplyTemplates: select didn't evaluate to a node list\n"));
  #endif
  	    goto exit;
  	}
  	/*
  	*
  	* NOTE: Previously a document info (xsltDocument) was
  	* created and attached to the Result Tree Fragment.
  	* But such a document info is created on demand in
  	* xsltKeyFunction() (functions.c), so we need to create
  	* it here beforehand.
  	* In order to take care of potential keys we need to
  	* do some extra work for the case when a Result Tree Fragment
  	* is converted into a nodeset (e.g. exslt:node-set()) :
  	* We attach a "pseudo-doc" (xsltDocument) to _private.
  	* This xsltDocument, together with the keyset, will be freed
  	* when the Result Tree Fragment is freed.
  	*
  	*/
  #if 0
  	if ((ctxt->nbKeys > 0) &&
  	    (list->nodeNr != 0) &&
  	    (list->nodeTab[0]->doc != NULL) &&
  	    XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc))
  	{
  	    /*
  	    * NOTE that it's also OK if @effectiveDocInfo will be
  	    * set to NULL.
  	    */
  	    isRTF = 1;
  	    effectiveDocInfo = list->nodeTab[0]->doc->_private;
  	}
  #endif
      } else {
  	/*
  	 * Build an XPath node set with the children
  	 */
  	list = xmlXPathNodeSetCreate(NULL);
  	if (list == NULL)
  	    goto error;
  	if (node->type != XML_NAMESPACE_DECL)
  	    cur = node->children;
  	else
  	    cur = NULL;
  	while (cur != NULL) {
  	    switch (cur->type) {
  		case XML_TEXT_NODE:
  		    if ((IS_BLANK_NODE(cur)) &&
  			(cur->parent != NULL) &&
  			(cur->parent->type == XML_ELEMENT_NODE) &&
  			(ctxt->style->stripSpaces != NULL)) {
  			const xmlChar *val;
  
  			if (cur->parent->ns != NULL) {
  			    val = (const xmlChar *)
  				  xmlHashLookup2(ctxt->style->stripSpaces,
  						 cur->parent->name,
  						 cur->parent->ns->href);
  			    if (val == NULL) {
  				val = (const xmlChar *)
  				  xmlHashLookup2(ctxt->style->stripSpaces,
  						 BAD_CAST "*",
  						 cur->parent->ns->href);
  			    }
  			} else {
  			    val = (const xmlChar *)
  				  xmlHashLookup2(ctxt->style->stripSpaces,
  						 cur->parent->name, NULL);
  			}
  			if ((val != NULL) &&
  			    (xmlStrEqual(val, (xmlChar *) "strip"))) {
  			    delNode = cur;
  			    break;
  			}
  		    }
  		    /* Intentional fall-through */
  		case XML_ELEMENT_NODE:
  		case XML_DOCUMENT_NODE:
  		case XML_HTML_DOCUMENT_NODE:
  		case XML_CDATA_SECTION_NODE:
  		case XML_PI_NODE:
  		case XML_COMMENT_NODE:
  		    xmlXPathNodeSetAddUnique(list, cur);
  		    break;
  		case XML_DTD_NODE:
  		    /* Unlink the DTD, it's still reachable
  		     * using doc->intSubset */
  		    if (cur->next != NULL)
  			cur->next->prev = cur->prev;
  		    if (cur->prev != NULL)
  			cur->prev->next = cur->next;
  		    break;
  		case XML_NAMESPACE_DECL:
  		    break;
  		default:
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		    XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
  		     "xsltApplyTemplates: skipping cur type %d\n",
  				     cur->type));
  #endif
  		    delNode = cur;
  	    }
  	    cur = cur->next;
  	    if (delNode != NULL) {
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
  		     "xsltApplyTemplates: removing ignorable blank cur\n"));
  #endif
  		xmlUnlinkNode(delNode);
  		xmlFreeNode(delNode);
  		delNode = NULL;
  	    }
  	}
      }
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      if (list != NULL)
      XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
  	"xsltApplyTemplates: list of %d nodes\n", list->nodeNr));
  #endif
  
      if ((list == NULL) || (list->nodeNr == 0))
  	goto exit;
  
      /*
      * Set the context's node set and size; this is also needed for
      * for xsltDoSortFunction().
      */
      ctxt->nodeList = list;
      /*
      * Process xsl:with-param and xsl:sort instructions.
      * (The code became so verbose just to avoid the
      *  xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
      * BUG TODO: We are not using namespaced potentially defined on the
      * xsl:sort or xsl:with-param elements; XPath expression might fail.
      */
      if (inst->children) {
  	xsltStackElemPtr param;
  
  	cur = inst->children;
  	while (cur) {
  
  #ifdef WITH_DEBUGGER
  	    if (ctxt->debugStatus != XSLT_DEBUG_NONE)
  		xslHandleDebugger(cur, node, NULL, ctxt);
  #endif
  	    if (ctxt->state == XSLT_STATE_STOPPED)
  		break;
  	    if (cur->type == XML_TEXT_NODE) {
  		cur = cur->next;
  		continue;
  	    }
  	    if (! IS_XSLT_ELEM(cur))
  		break;
  	    if (IS_XSLT_NAME(cur, "with-param")) {
  		param = xsltParseStylesheetCallerParam(ctxt, cur);
  		if (param != NULL) {
  		    param->next = withParams;
  		    withParams = param;
  		}
  	    }
  	    if (IS_XSLT_NAME(cur, "sort")) {
  		xsltTemplatePtr oldCurTempRule =
  		    ctxt->currentTemplateRule;
  		int nbsorts = 0;
  		xmlNodePtr sorts[XSLT_MAX_SORT];
  
  		sorts[nbsorts++] = cur;
  
  		while (cur) {
  
  #ifdef WITH_DEBUGGER
  		    if (ctxt->debugStatus != XSLT_DEBUG_NONE)
  			xslHandleDebugger(cur, node, NULL, ctxt);
  #endif
  		    if (ctxt->state == XSLT_STATE_STOPPED)
  			break;
  
  		    if (cur->type == XML_TEXT_NODE) {
  			cur = cur->next;
  			continue;
  		    }
  
  		    if (! IS_XSLT_ELEM(cur))
  			break;
  		    if (IS_XSLT_NAME(cur, "with-param")) {
  			param = xsltParseStylesheetCallerParam(ctxt, cur);
  			if (param != NULL) {
  			    param->next = withParams;
  			    withParams = param;
  			}
  		    }
  		    if (IS_XSLT_NAME(cur, "sort")) {
  			if (nbsorts >= XSLT_MAX_SORT) {
  			    xsltTransformError(ctxt, NULL, cur,
  				"The number (%d) of xsl:sort instructions exceeds the "
  				"maximum allowed by this processor's settings.\n",
  				nbsorts);
  			    ctxt->state = XSLT_STATE_STOPPED;
  			    break;
  			} else {
  			    sorts[nbsorts++] = cur;
  			}
  		    }
  		    cur = cur->next;
  		}
  		/*
  		* The "current template rule" is cleared for xsl:sort.
  		*/
  		ctxt->currentTemplateRule = NULL;
  		/*
  		* Sort.
  		*/
  		xsltDoSortFunction(ctxt, sorts, nbsorts);
  		ctxt->currentTemplateRule = oldCurTempRule;
  		break;
  	    }
  	    cur = cur->next;
  	}
      }
      xpctxt->contextSize = list->nodeNr;
      /*
      * Apply templates for all selected source nodes.
      */
      for (i = 0; i < list->nodeNr; i++) {
  	cur = list->nodeTab[i];
  	/*
  	* The node becomes the "current node".
  	*/
  	ctxt->node = cur;
  	/*
  	* An xsl:apply-templates can change the current context doc.
  	* OPTIMIZE TODO: Get rid of the need to set the context doc.
  	*/
  	if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
  	    xpctxt->doc = cur->doc;
  
  	xpctxt->proximityPosition = i + 1;
  	/*
  	* Find and apply a template for this node.
  	*/
  	xsltProcessOneNode(ctxt, cur, withParams);
      }
  
  exit:
  error:
      /*
      * Free the parameter list.
      */
      if (withParams != NULL)
  	xsltFreeStackElemList(withParams);
      if (list != NULL)
  	xmlXPathFreeNodeSet(list);
      /*
      * Restore context states.
      */
      xpctxt->doc = oldXPDoc;
      xpctxt->contextSize = oldXPContextSize;
      xpctxt->proximityPosition = oldXPProximityPosition;
  
      ctxt->document = oldDocInfo;
      ctxt->nodeList = oldList;
      ctxt->node = oldContextNode;
      ctxt->mode = oldMode;
      ctxt->modeURI = oldModeURI;
  }
  
  
  /**
   * xsltChoose:
   * @ctxt:  a XSLT process context
   * @contextNode:  the current node in the source tree
   * @inst:  the xsl:choose instruction
   * @comp:  compiled information of the instruction
   *
   * Processes the xsl:choose instruction on the source node.
   */
  void
  xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
  	   xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
  {
      xmlNodePtr cur;
  
      if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
  	return;
  
      /*
      * TODO: Content model checks should be done only at compilation
      * time.
      */
      cur = inst->children;
      if (cur == NULL) {
  	xsltTransformError(ctxt, NULL, inst,
  	    "xsl:choose: The instruction has no content.\n");
  	return;
      }
  
  #ifdef XSLT_REFACTORED
      /*
      * We don't check the content model during transformation.
      */
  #else
      if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) {
  	xsltTransformError(ctxt, NULL, inst,
  	     "xsl:choose: xsl:when expected first\n");
  	return;
      }
  #endif
  
      {
  	int testRes = 0, res = 0;
  
  #ifdef XSLT_REFACTORED
  	xsltStyleItemWhenPtr wcomp = NULL;
  #else
  	xsltStylePreCompPtr wcomp = NULL;
  #endif
  
  	/*
  	* Process xsl:when ---------------------------------------------------
  	*/
  	while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) {
  	    wcomp = cur->psvi;
  
  	    if ((wcomp == NULL) || (wcomp->test == NULL) ||
  		(wcomp->comp == NULL))
  	    {
  		xsltTransformError(ctxt, NULL, cur,
  		    "Internal error in xsltChoose(): "
  		    "The XSLT 'when' instruction was not compiled.\n");
  		goto error;
  	    }
  
  
  #ifdef WITH_DEBUGGER
  	    if (xslDebugStatus != XSLT_DEBUG_NONE) {
  		/*
  		* TODO: Isn't comp->templ always NULL for xsl:choose?
  		*/
  		xslHandleDebugger(cur, contextNode, NULL, ctxt);
  	    }
  #endif
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	    XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
  		"xsltChoose: test %s\n", wcomp->test));
  #endif
  
  #ifdef XSLT_FAST_IF
  	    res = xsltPreCompEvalToBoolean(ctxt, contextNode, wcomp);
  
  	    if (res == -1) {
  		ctxt->state = XSLT_STATE_STOPPED;
  		goto error;
  	    }
  	    testRes = (res == 1) ? 1 : 0;
  
  #else /* XSLT_FAST_IF */
  
  	    res = xsltPreCompEval(ctxt, cotextNode, wcomp);
  
  	    if (res != NULL) {
  		if (res->type != XPATH_BOOLEAN)
  		    res = xmlXPathConvertBoolean(res);
  		if (res->type == XPATH_BOOLEAN)
  		    testRes = res->boolval;
  		else {
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		    XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
  			"xsltChoose: test didn't evaluate to a boolean\n"));
  #endif
  		    goto error;
  		}
  		xmlXPathFreeObject(res);
  		res = NULL;
  	    } else {
  		ctxt->state = XSLT_STATE_STOPPED;
  		goto error;
  	    }
  
  #endif /* else of XSLT_FAST_IF */
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	    XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
  		"xsltChoose: test evaluate to %d\n", testRes));
  #endif
  	    if (testRes)
  		goto test_is_true;
  
  	    cur = cur->next;
  	}
  
  	/*
  	* Process xsl:otherwise ----------------------------------------------
  	*/
  	if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) {
  
  #ifdef WITH_DEBUGGER
  	    if (xslDebugStatus != XSLT_DEBUG_NONE)
  		xslHandleDebugger(cur, contextNode, NULL, ctxt);
  #endif
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	    XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
  		"evaluating xsl:otherwise\n"));
  #endif
  	    goto test_is_true;
  	}
  	goto exit;
  
  test_is_true:
  
  	goto process_sequence;
      }
  
  process_sequence:
  
      /*
      * Instantiate the sequence constructor.
      */
      xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children,
  	NULL);
  
  exit:
  error:
      return;
  }
  
  /**
   * xsltIf:
   * @ctxt:  a XSLT process context
   * @contextNode:  the current node in the source tree
   * @inst:  the xsl:if instruction
   * @castedComp:  compiled information of the instruction
   *
   * Processes the xsl:if instruction on the source node.
   */
  void
  xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
  	           xmlNodePtr inst, xsltElemPreCompPtr castedComp)
  {
      int res = 0;
  
  #ifdef XSLT_REFACTORED
      xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp;
  #else
      xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
  #endif
  
      if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
  	return;
      if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) {
  	xsltTransformError(ctxt, NULL, inst,
  	    "Internal error in xsltIf(): "
  	    "The XSLT 'if' instruction was not compiled.\n");
  	return;
      }
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
  	 "xsltIf: test %s\n", comp->test));
  #endif
  
  #ifdef XSLT_FAST_IF
      {
  	xmlDocPtr oldLocalFragmentTop = ctxt->localRVT;
  
  	res = xsltPreCompEvalToBoolean(ctxt, contextNode, comp);
  
  	/*
  	* Cleanup fragments created during evaluation of the
  	* "select" expression.
  	*/
  	if (oldLocalFragmentTop != ctxt->localRVT)
  	    xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
      }
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
  	"xsltIf: test evaluate to %d\n", res));
  #endif
  
      if (res == -1) {
  	ctxt->state = XSLT_STATE_STOPPED;
  	goto error;
      }
      if (res == 1) {
  	/*
  	* Instantiate the sequence constructor of xsl:if.
  	*/
  	xsltApplySequenceConstructor(ctxt,
  	    contextNode, inst->children, NULL);
      }
  
  #else /* XSLT_FAST_IF */
      {
  	/*
  	* OLD CODE:
  	*/
  	xmlXPathObjectPtr xpobj = xsltPreCompEval(ctxt, contextNode, comp);
  	if (xpobj != NULL) {
  	    if (xpobj->type != XPATH_BOOLEAN)
  		xpobj = xmlXPathConvertBoolean(xpobj);
  	    if (xpobj->type == XPATH_BOOLEAN) {
  		res = xpobj->boolval;
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
  		    "xsltIf: test evaluate to %d\n", res));
  #endif
  		if (res) {
  		    xsltApplySequenceConstructor(ctxt,
  			contextNode, inst->children, NULL);
  		}
  	    } else {
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		XSLT_TRACE(ctxt, XSLT_TRACE_IF,
  		    xsltGenericDebug(xsltGenericDebugContext,
  		    "xsltIf: test didn't evaluate to a boolean\n"));
  #endif
  		ctxt->state = XSLT_STATE_STOPPED;
  	    }
  	    xmlXPathFreeObject(xpobj);
  	} else {
  	    ctxt->state = XSLT_STATE_STOPPED;
  	}
      }
  #endif /* else of XSLT_FAST_IF */
  
  error:
      return;
  }
  
  /**
   * xsltForEach:
   * @ctxt:  an XSLT transformation context
   * @contextNode:  the "current node" in the source tree
   * @inst:  the element node of the xsl:for-each instruction
   * @castedComp:  the compiled information of the instruction
   *
   * Process the xslt for-each node on the source node
   */
  void
  xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
  	    xmlNodePtr inst, xsltElemPreCompPtr castedComp)
  {
  #ifdef XSLT_REFACTORED
      xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp;
  #else
      xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
  #endif
      int i;
      xmlXPathObjectPtr res = NULL;
      xmlNodePtr cur, curInst;
      xmlNodeSetPtr list = NULL;
      xmlNodeSetPtr oldList;
      int oldXPProximityPosition, oldXPContextSize;
      xmlNodePtr oldContextNode;
      xsltTemplatePtr oldCurTemplRule;
      xmlDocPtr oldXPDoc;
      xsltDocumentPtr oldDocInfo;
      xmlXPathContextPtr xpctxt;
  
      if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) {
  	xsltGenericError(xsltGenericErrorContext,
  	    "xsltForEach(): Bad arguments.\n");
  	return;
      }
  
      if (comp == NULL) {
          xsltTransformError(ctxt, NULL, inst,
  	    "Internal error in xsltForEach(): "
  	    "The XSLT 'for-each' instruction was not compiled.\n");
          return;
      }
      if ((comp->select == NULL) || (comp->comp == NULL)) {
  	xsltTransformError(ctxt, NULL, inst,
  	    "Internal error in xsltForEach(): "
  	    "The selecting expression of the XSLT 'for-each' "
  	    "instruction was not compiled correctly.\n");
  	return;
      }
      xpctxt = ctxt->xpathCtxt;
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
  	 "xsltForEach: select %s\n", comp->select));
  #endif
  
      /*
      * Save context states.
      */
      oldDocInfo = ctxt->document;
      oldList = ctxt->nodeList;
      oldContextNode = ctxt->node;
      /*
      * The "current template rule" is cleared for the instantiation of
      * xsl:for-each.
      */
      oldCurTemplRule = ctxt->currentTemplateRule;
      ctxt->currentTemplateRule = NULL;
  
      oldXPDoc = xpctxt->doc;
      oldXPProximityPosition = xpctxt->proximityPosition;
      oldXPContextSize = xpctxt->contextSize;
  
      /*
      * Evaluate the 'select' expression.
      */
      res = xsltPreCompEval(ctxt, contextNode, comp);
  
      if (res != NULL) {
  	if (res->type == XPATH_NODESET)
  	    list = res->nodesetval;
  	else {
  	    xsltTransformError(ctxt, NULL, inst,
  		"The 'select' expression does not evaluate to a node set.\n");
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
  	    XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
  		"xsltForEach: select didn't evaluate to a node list\n"));
  #endif
  	    goto error;
  	}
      } else {
  	xsltTransformError(ctxt, NULL, inst,
  	    "Failed to evaluate the 'select' expression.\n");
  	ctxt->state = XSLT_STATE_STOPPED;
  	goto error;
      }
  
      if ((list == NULL) || (list->nodeNr <= 0))
  	goto exit;
  
  #ifdef WITH_XSLT_DEBUG_PROCESS
      XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
  	"xsltForEach: select evaluates to %d nodes\n", list->nodeNr));
  #endif
  
      /*
      * Set the list; this has to be done already here for xsltDoSortFunction().
      */
      ctxt->nodeList = list;
      /*
      * Handle xsl:sort instructions and skip them for further processing.
      * BUG TODO: We are not using namespaced potentially defined on the
      * xsl:sort element; XPath expression might fail.
      */
      curInst = inst->children;
      if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
  	int nbsorts = 0;
  	xmlNodePtr sorts[XSLT_MAX_SORT];
  
  	sorts[nbsorts++] = curInst;
  
  #ifdef WITH_DEBUGGER
  	if (xslDebugStatus != XSLT_DEBUG_NONE)
  	    xslHandleDebugger(curInst, contextNode, NULL, ctxt);
  #endif
  
  	curInst = curInst->next;
  	while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
  	    if (nbsorts >= XSLT_MAX_SORT) {
  		xsltTransformError(ctxt, NULL, curInst,
  		    "The number of xsl:sort instructions exceeds the "
  		    "maximum (%d) allowed by this processor.\n",
  		    XSLT_MAX_SORT);
  		goto error;
  	    } else {
  		sorts[nbsorts++] = curInst;
  	    }
  
  #ifdef WITH_DEBUGGER
  	    if (xslDebugStatus != XSLT_DEBUG_NONE)
  		xslHandleDebugger(curInst, contextNode, NULL, ctxt);
  #endif
  	    curInst = curInst->next;
  	}
  	xsltDoSortFunction(ctxt, sorts, nbsorts);
      }
      xpctxt->contextSize = list->nodeNr;
      /*
      * Instantiate the sequence constructor for each selected node.
      */
      for (i = 0; i < list->nodeNr; i++) {
  	cur = list->nodeTab[i];
  	/*
  	* The selected node becomes the "current node".
  	*/
  	ctxt->node = cur;
  	/*
  	* An xsl:for-each can change the current context doc.
  	* OPTIMIZE TODO: Get rid of the need to set the context doc.
  	*/
  	if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
  	    xpctxt->doc = cur->doc;
  
  	xpctxt->proximityPosition = i + 1;
  
  	xsltApplySequenceConstructor(ctxt, cur, curInst, NULL);
      }
  
  exit:
  error:
      if (res != NULL)
  	xmlXPathFreeObject(res);
      /*
      * Restore old states.
      */
      ctxt->document = oldDocInfo;
      ctxt->nodeList = oldList;
      ctxt->node = oldContextNode;
      ctxt->currentTemplateRule = oldCurTemplRule;
  
      xpctxt->doc = oldXPDoc;
      xpctxt->contextSize = oldXPContextSize;
      xpctxt->proximityPosition = oldXPProximityPosition;
  }
  
  /************************************************************************
   *									*
   *			Generic interface				*
   *									*
   ************************************************************************/
  
  #ifdef XSLT_GENERATE_HTML_DOCTYPE
  typedef struct xsltHTMLVersion {
      const char *version;
      const char *public;
      const char *system;
  } xsltHTMLVersion;
  
  static xsltHTMLVersion xsltHTMLVersions[] = {
      { "5", NULL, "about:legacy-compat" },
      { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
        "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
      { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
        "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
      { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
        "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
      { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
        "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
      { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
        "http://www.w3.org/TR/html4/strict.dtd"},
      { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
        "http://www.w3.org/TR/html4/loose.dtd"},
      { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
        "http://www.w3.org/TR/html4/frameset.dtd"},
      { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
        "http://www.w3.org/TR/html4/loose.dtd"},
      { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL }
  };
  
  /**
   * xsltGetHTMLIDs:
   * @version:  the version string
   * @publicID:  used to return the public ID
   * @systemID:  used to return the system ID
   *
   * Returns -1 if not found, 0 otherwise and the system and public
   *         Identifier for this given verion of HTML
   */
  static int
  xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
  	            const xmlChar **systemID) {
      unsigned int i;
      if (version == NULL)
  	return(-1);
      for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1]));
  	 i++) {
  	if (!xmlStrcasecmp(version,
  		           (const xmlChar *) xsltHTMLVersions[i].version)) {
  	    if (publicID != NULL)
  		*publicID = (const xmlChar *) xsltHTMLVersions[i].public;
  	    if (systemID != NULL)
  		*systemID = (const xmlChar *) xsltHTMLVersions[i].system;
  	    return(0);
  	}
      }
      return(-1);
  }
  #endif
  
  /**
   * xsltApplyStripSpaces:
   * @ctxt:  a XSLT process context
   * @node:  the root of the XML tree
   *
   * Strip the unwanted ignorable spaces from the input tree
   */
  void
  xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) {
      xmlNodePtr current;
  #ifdef WITH_XSLT_DEBUG_PROCESS
      int nb = 0;
  #endif
  
  
      current = node;
      while (current != NULL) {
  	/*
  	 * Cleanup children empty nodes if asked for
  	 */
  	if ((IS_XSLT_REAL_NODE(current)) &&
  	    (current->children != NULL) &&
  	    (xsltFindElemSpaceHandling(ctxt, current))) {
  	    xmlNodePtr delete = NULL, cur = current->children;
  
  	    while (cur != NULL) {
  		if (IS_BLANK_NODE(cur))
  		    delete = cur;
  
  		cur = cur->next;
  		if (delete != NULL) {
  		    xmlUnlinkNode(delete);
  		    xmlFreeNode(delete);
  		    delete = NULL;
  #ifdef WITH_XSLT_DEBUG_PROCESS
  		    nb++;
  #endif
  		}
  	    }
  	}
  
  	/*
  	 * Skip to next node in document order.
  	 */
  	if (node->type == XML_ENTITY_REF_NODE) {
  	    /* process deep in entities */
  	    xsltApplyStripSpaces(ctxt, node->children);
  	}
  	if ((current->children != NULL) &&
              (current->type != XML_ENTITY_REF_NODE)) {
  	    current = current->children;
  	} else if (current->next != NULL) {
  	    current = current->next;
  	} else {
  	    do {
  		current = current->parent;
  		if (current == NULL)
  		    break;
  		if (current == node)
  		    goto done;
  		if (current->next != NULL) {
  		    current = current->next;
  		    break;
  		}
  	    } while (current != NULL);
  	}
      }
  
  done:
  #ifdef WITH_XSLT_DEBUG_PROCESS
      XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext,
  	     "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb));
  #endif
      return;
  }
  
  static int
  xsltCountKeys(xsltTransformContextPtr ctxt)
  {
      xsltStylesheetPtr style;
      xsltKeyDefPtr keyd;
  
      if (ctxt == NULL)
  	return(-1);
  
      /*
      * Do we have those nastly templates with a key() in the match pattern?
      */
      ctxt->hasTemplKeyPatterns = 0;
      style = ctxt->style;
      while (style != NULL) {
  	if (style->keyMatch != NULL) {
  	    ctxt->hasTemplKeyPatterns = 1;
  	    break;
  	}
  	style = xsltNextImport(style);
      }
      /*
      * Count number of key declarations.
      */
      ctxt->nbKeys = 0;
      style = ctxt->style;
      while (style != NULL) {
  	keyd = style->keys;
  	while (keyd) {
  	    ctxt->nbKeys++;
  	    keyd = keyd->next;
  	}
  	style = xsltNextImport(style);
      }
      return(ctxt->nbKeys);
  }
  
  /**
   * xsltApplyStylesheetInternal:
   * @style:  a parsed XSLT stylesheet
   * @doc:  a parsed XML document
   * @params:  a NULL terminated array of parameters names/values tuples
   * @output:  the targetted output
   * @profile:  profile FILE * output or NULL
   * @user:  user provided parameter
   *
   * Apply the stylesheet to the document
   * NOTE: This may lead to a non-wellformed output XML wise !
   *
   * Returns the result document or NULL in case of error
   */
  static xmlDocPtr
  xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
                              const char **params, const char *output,
                              FILE * profile, xsltTransformContextPtr userCtxt)
  {
      xmlDocPtr res = NULL;
      xsltTransformContextPtr ctxt = NULL;
      xmlNodePtr root, node;
      const xmlChar *method;
      const xmlChar *doctypePublic;
      const xmlChar *doctypeSystem;
      const xmlChar *version;
      const xmlChar *encoding;
      xsltStackElemPtr variables;
      xsltStackElemPtr vptr;
  
      xsltInitGlobals();
  
      if ((style == NULL) || (doc == NULL))
          return (NULL);
  
      if (style->internalized == 0) {
  #ifdef WITH_XSLT_DEBUG
  	xsltGenericDebug(xsltGenericDebugContext,
  			 "Stylesheet was not fully internalized !\n");
  #endif
      }
      if (doc->intSubset != NULL) {
  	/*
  	 * Avoid hitting the DTD when scanning nodes
  	 * but keep it linked as doc->intSubset
  	 */
  	xmlNodePtr cur = (xmlNodePtr) doc->intSubset;
  	if (cur->next != NULL)
  	    cur->next->prev = cur->prev;
  	if (cur->prev != NULL)
  	    cur->prev->next = cur->next;
  	if (doc->children == cur)
  	    doc->children = cur->next;
  	if (doc->last == cur)
  	    doc->last = cur->prev;
  	cur->prev = cur->next = NULL;
      }
  
      /*
       * Check for XPath document order availability
       */
      root = xmlDocGetRootElement(doc);
      if (root != NULL) {
  	if (((ptrdiff_t) root->content >= 0) &&
              (xslDebugStatus == XSLT_DEBUG_NONE))
  	    xmlXPathOrderDocElems(doc);
      }
  
      if (userCtxt != NULL)
  	ctxt = userCtxt;
      else
  	ctxt = xsltNewTransformContext(style, doc);
  
      if (ctxt == NULL)
          return (NULL);
  
      ctxt->initialContextDoc = doc;
      ctxt->initialContextNode = (xmlNodePtr) doc;
  
      if (profile != NULL) {
  #ifdef WITH_PROFILER
          ctxt->profile = 1;
  #else
          xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
                  "xsltApplyStylesheetInternal: "
                  "libxslt compiled without profiler\n");
          goto error;
  #endif
      }
  
      if (output != NULL)
          ctxt->outputFile = output;
      else
          ctxt->outputFile = NULL;
  
      /*
       * internalize the modes if needed
       */
      if (ctxt->dict != NULL) {
          if (ctxt->mode != NULL)
  	    ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1);
          if (ctxt->modeURI != NULL)
  	    ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1);
      }
  
      XSLT_GET_IMPORT_PTR(method, style, method)
      XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
      XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
      XSLT_GET_IMPORT_PTR(version, style, version)
      XSLT_GET_IMPORT_PTR(encoding, style, encoding)
  
      if ((method != NULL) &&
  	(!xmlStrEqual(method, (const xmlChar *) "xml")))
      {
          if (xmlStrEqual(method, (const xmlChar *) "html")) {
              ctxt->type = XSLT_OUTPUT_HTML;
              if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
                  res = htmlNewDoc(doctypeSystem, doctypePublic);
  	    } else {
                  if (version == NULL) {
  		    xmlDtdPtr dtd;
  
  		    res = htmlNewDoc(NULL, NULL);
  		    /*
  		    * Make sure no DTD node is generated in this case
  		    */
  		    if (res != NULL) {
  			dtd = xmlGetIntSubset(res);
  			if (dtd != NULL) {
  			    xmlUnlinkNode((xmlNodePtr) dtd);
  			    xmlFreeDtd(dtd);
  			}
  			res->intSubset = NULL;
  			res->extSubset = NULL;
  		    }
  		} else {
  
  #ifdef XSLT_GENERATE_HTML_DOCTYPE
  		    xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
  #endif
  		    res = htmlNewDoc(doctypeSystem, doctypePublic);
  		}
              }
              if (res == NULL)
                  goto error;
  	    res->dict = ctxt->dict;
  	    xmlDictReference(res->dict);
  
  #ifdef WITH_XSLT_DEBUG
  	    xsltGenericDebug(xsltGenericDebugContext,
  		"reusing transformation dict for output\n");
  #endif
          } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
  	    xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
  		"xsltApplyStylesheetInternal: unsupported method xhtml, using html\n");
              ctxt->type = XSLT_OUTPUT_HTML;
              res = htmlNewDoc(doctypeSystem, doctypePublic);
              if (res == NULL)
                  goto error;
  	    res->dict = ctxt->dict;
  	    xmlDictReference(res->dict);
  
  #ifdef WITH_XSLT_DEBUG
  	    xsltGenericDebug(xsltGenericDebugContext,
  		"reusing transformation dict for output\n");
  #endif
          } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
              ctxt->type = XSLT_OUTPUT_TEXT;
              res = xmlNewDoc(style->version);
              if (res == NULL)
                  goto error;
  	    res->dict = ctxt->dict;
  	    xmlDictReference(res->dict);
  
  #ifdef WITH_XSLT_DEBUG
  	    xsltGenericDebug(xsltGenericDebugContext,
  		"reusing transformation dict for output\n");
  #endif
          } else {
  	    xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
  		"xsltApplyStylesheetInternal: unsupported method (%s)\n",
  		method);
              goto error;
          }
      } else {
          ctxt->type = XSLT_OUTPUT_XML;
          res = xmlNewDoc(style->version);
          if (res == NULL)
              goto error;
  	res->dict = ctxt->dict;
  	xmlDictReference(ctxt->dict);
  #ifdef WITH_XSLT_DEBUG
  	xsltGenericDebug(xsltGenericDebugContext,
  			 "reusing transformation dict for output\n");
  #endif
      }
      res->charset = XML_CHAR_ENCODING_UTF8;
      if (encoding != NULL)
          res->encoding = xmlStrdup(encoding);
      variables = style->variables;
  
      ctxt->node = (xmlNodePtr) doc;
      ctxt->output = res;
  
      ctxt->xpathCtxt->contextSize = 1;
      ctxt->xpathCtxt->proximityPosition = 1;
      ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */
  
      /*
       * Start the evaluation, evaluate the params, the stylesheets globals
       * and start by processing the top node.
       */
      if (xsltNeedElemSpaceHandling(ctxt))
  	xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
      /*
      * Evaluate global params and user-provided params.
      */
      if (ctxt->globalVars == NULL)
  	ctxt->globalVars = xmlHashCreate(20);
      if (params != NULL) {
          xsltEvalUserParams(ctxt, params);
      }
  
      /* need to be called before evaluating global variables */
      xsltCountKeys(ctxt);
  
      xsltEvalGlobalVariables(ctxt);
  
      /* Clean up any unused RVTs. */
      xsltReleaseLocalRVTs(ctxt, NULL);
  
      ctxt->insert = (xmlNodePtr) res;
      ctxt->varsBase = ctxt->varsNr - 1;
  
      /*
      * Start processing the source tree -----------------------------------
      */
      xsltProcessOneNode(ctxt, ctxt->node, NULL);
      /*
      * Remove all remaining vars from the stack.
      */
      xsltLocalVariablePop(ctxt, 0, -2);
      xsltShutdownCtxtExts(ctxt);
  
      xsltCleanupTemplates(style); /* TODO: <- style should be read only */
  
      /*
       * Now cleanup our variables so stylesheet can be re-used
       *
       * TODO: this is not needed anymore global variables are copied
       *       and not evaluated directly anymore, keep this as a check
       */
      if (style->variables != variables) {
          vptr = style->variables;
          while (vptr->next != variables)
              vptr = vptr->next;
          vptr->next = NULL;
          xsltFreeStackElemList(style->variables);
          style->variables = variables;
      }
      vptr = style->variables;
      while (vptr != NULL) {
          if (vptr->computed) {
              if (vptr->value != NULL) {
                  xmlXPathFreeObject(vptr->value);
                  vptr->value = NULL;
                  vptr->computed = 0;
              }
          }
          vptr = vptr->next;
      }
  #if 0
      /*
       * code disabled by wmb; awaiting kb's review
       * problem is that global variable(s) may contain xpath objects
       * from doc associated with RVT, so can't be freed at this point.
       * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
       * I assume this shouldn't be required at this point.
       */
      /*
      * Free all remaining tree fragments.
      */
      xsltFreeRVTs(ctxt);
  #endif
      /*
       * Do some post processing work depending on the generated output
       */
      root = xmlDocGetRootElement(res);
      if (root != NULL) {
          const xmlChar *doctype = NULL;
  
          if ((root->ns != NULL) && (root->ns->prefix != NULL))
  	    doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
  	if (doctype == NULL)
  	    doctype = root->name;
  
          /*
           * Apply the default selection of the method
           */
          if ((method == NULL) &&
              (root->ns == NULL) &&
              (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
              xmlNodePtr tmp;
  
              tmp = res->children;
              while ((tmp != NULL) && (tmp != root)) {
                  if (tmp->type == XML_ELEMENT_NODE)
                      break;
                  if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
                      break;
  		tmp = tmp->next;
              }
              if (tmp == root) {
                  ctxt->type = XSLT_OUTPUT_HTML;
  		/*
  		* REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
  		*  transformation on the doc, but functions like
  		*/
                  res->type = XML_HTML_DOCUMENT_NODE;
                  if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
                      res->intSubset = xmlCreateIntSubset(res, doctype,
                                                          doctypePublic,
                                                          doctypeSystem);
  #ifdef XSLT_GENERATE_HTML_DOCTYPE
  		} else if (version != NULL) {
                      xsltGetHTMLIDs(version, &doctypePublic,
                                     &doctypeSystem);
                      if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
                          res->intSubset =
                              xmlCreateIntSubset(res, doctype,
                                                 doctypePublic,
                                                 doctypeSystem);
  #endif
                  }
              }
  
          }
          if (ctxt->type == XSLT_OUTPUT_XML) {
              XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
              XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
              if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
  	        xmlNodePtr last;
  		/* Need a small "hack" here to assure DTD comes before
  		   possible comment nodes */
  		node = res->children;
  		last = res->last;
  		res->children = NULL;
  		res->last = NULL;
                  res->intSubset = xmlCreateIntSubset(res, doctype,
                                                      doctypePublic,
                                                      doctypeSystem);
  		if (res->children != NULL) {
  		    res->children->next = node;
  		    node->prev = res->children;
  		    res->last = last;
  		} else {
  		    res->children = node;
  		    res->last = last;
  		}
  	    }
          }
      }
      xmlXPathFreeNodeSet(ctxt->nodeList);
  
  #ifdef WITH_PROFILER
      if (profile != NULL) {
          xsltSaveProfiling(ctxt, profile);
      }
  #endif
  
      /*
       * Be pedantic.
       */
      if ((ctxt != NULL) && (ctxt->state != XSLT_STATE_OK)) {
  	xmlFreeDoc(res);
  	res = NULL;
      }
      if ((res != NULL) && (ctxt != NULL) && (output != NULL)) {
  	int ret;
  
  	ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output);
  	if (ret == 0) {
  	    xsltTransformError(ctxt, NULL, NULL,
  		     "xsltApplyStylesheet: forbidden to save to %s\n",
  			       output);
  	} else if (ret < 0) {
  	    xsltTransformError(ctxt, NULL, NULL,
  		     "xsltApplyStylesheet: saving to %s may not be possible\n",
  			       output);
  	}
      }
  
  #ifdef XSLT_DEBUG_PROFILE_CACHE
      printf("# Cache:\n");
      printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
      printf("# Reused variables     : %d\n", ctxt->cache->dbgReusedVars);
  #endif
  
      if ((ctxt != NULL) && (userCtxt == NULL))
  	xsltFreeTransformContext(ctxt);
  
      return (res);
  
  error:
      if (res != NULL)
          xmlFreeDoc(res);
  
  #ifdef XSLT_DEBUG_PROFILE_CACHE
      printf("# Cache:\n");
      printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
      printf("# Reused variables     : %d\n", ctxt->cache->dbgReusedVars);
  #endif
  
      if ((ctxt != NULL) && (userCtxt == NULL))
          xsltFreeTransformContext(ctxt);
      return (NULL);
  }
  
  /**
   * xsltApplyStylesheet:
   * @style:  a parsed XSLT stylesheet
   * @doc:  a parsed XML document
   * @params:  a NULL terminated arry of parameters names/values tuples
   *
   * Apply the stylesheet to the document
   * NOTE: This may lead to a non-wellformed output XML wise !
   *
   * Returns the result document or NULL in case of error
   */
  xmlDocPtr
  xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
                      const char **params)
  {
      return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL));
  }
  
  /**
   * xsltProfileStylesheet:
   * @style:  a parsed XSLT stylesheet
   * @doc:  a parsed XML document
   * @params:  a NULL terminated arry of parameters names/values tuples
   * @output:  a FILE * for the profiling output
   *
   * Apply the stylesheet to the document and dump the profiling to
   * the given output.
   *
   * Returns the result document or NULL in case of error
   */
  xmlDocPtr
  xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
                        const char **params, FILE * output)
  {
      xmlDocPtr res;
  
      res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL);
      return (res);
  }
  
  /**
   * xsltApplyStylesheetUser:
   * @style:  a parsed XSLT stylesheet
   * @doc:  a parsed XML document
   * @params:  a NULL terminated array of parameters names/values tuples
   * @output:  the targetted output
   * @profile:  profile FILE * output or NULL
   * @userCtxt:  user provided transform context
   *
   * Apply the stylesheet to the document and allow the user to provide
   * its own transformation context.
   *
   * Returns the result document or NULL in case of error
   */
  xmlDocPtr
  xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
                              const char **params, const char *output,
                              FILE * profile, xsltTransformContextPtr userCtxt)
  {
      xmlDocPtr res;
  
      res = xsltApplyStylesheetInternal(style, doc, params, output,
  	                              profile, userCtxt);
      return (res);
  }
  
  /**
   * xsltRunStylesheetUser:
   * @style:  a parsed XSLT stylesheet
   * @doc:  a parsed XML document
   * @params:  a NULL terminated array of parameters names/values tuples
   * @output:  the URL/filename ot the generated resource if available
   * @SAX:  a SAX handler for progressive callback output (not implemented yet)
   * @IObuf:  an output buffer for progressive output (not implemented yet)
   * @profile:  profile FILE * output or NULL
   * @userCtxt:  user provided transform context
   *
   * Apply the stylesheet to the document and generate the output according
   * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
   *
   * NOTE: This may lead to a non-wellformed output XML wise !
   * NOTE: This may also result in multiple files being generated
   * NOTE: using IObuf, the result encoding used will be the one used for
   *       creating the output buffer, use the following macro to read it
   *       from the stylesheet
   *       XSLT_GET_IMPORT_PTR(encoding, style, encoding)
   * NOTE: using SAX, any encoding specified in the stylesheet will be lost
   *       since the interface uses only UTF8
   *
   * Returns the number of by written to the main resource or -1 in case of
   *         error.
   */
  int
  xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
                    const char **params, const char *output,
                    xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf,
  		  FILE * profile, xsltTransformContextPtr userCtxt)
  {
      xmlDocPtr tmp;
      int ret;
  
      if ((output == NULL) && (SAX == NULL) && (IObuf == NULL))
          return (-1);
      if ((SAX != NULL) && (IObuf != NULL))
          return (-1);
  
      /* unsupported yet */
      if (SAX != NULL) {
          XSLT_TODO   /* xsltRunStylesheet xmlSAXHandlerPtr SAX */
  	return (-1);
      }
  
      tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile,
  	                              userCtxt);
      if (tmp == NULL) {
  	xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
                           "xsltRunStylesheet : run failed\n");
          return (-1);
      }
      if (IObuf != NULL) {
          /* TODO: incomplete, IObuf output not progressive */
          ret = xsltSaveResultTo(IObuf, tmp, style);
      } else {
          ret = xsltSaveResultToFilename(output, tmp, style, 0);
      }
      xmlFreeDoc(tmp);
      return (ret);
  }
  
  /**
   * xsltRunStylesheet:
   * @style:  a parsed XSLT stylesheet
   * @doc:  a parsed XML document
   * @params:  a NULL terminated array of parameters names/values tuples
   * @output:  the URL/filename ot the generated resource if available
   * @SAX:  a SAX handler for progressive callback output (not implemented yet)
   * @IObuf:  an output buffer for progressive output (not implemented yet)
   *
   * Apply the stylesheet to the document and generate the output according
   * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
   *
   * NOTE: This may lead to a non-wellformed output XML wise !
   * NOTE: This may also result in multiple files being generated
   * NOTE: using IObuf, the result encoding used will be the one used for
   *       creating the output buffer, use the following macro to read it
   *       from the stylesheet
   *       XSLT_GET_IMPORT_PTR(encoding, style, encoding)
   * NOTE: using SAX, any encoding specified in the stylesheet will be lost
   *       since the interface uses only UTF8
   *
   * Returns the number of bytes written to the main resource or -1 in case of
   *         error.
   */
  int
  xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
                    const char **params, const char *output,
                    xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf)
  {
      return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf,
  		                 NULL, NULL));
  }
  
  static void
  xsltMessageWrapper(xsltTransformContextPtr ctxt, xmlNodePtr node,
                     xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
      xsltMessage(ctxt, node, inst);
  }
  
  /**
   * xsltRegisterAllElement:
   * @ctxt:  the XPath context
   *
   * Registers all default XSLT elements in this context
   */
  void
  xsltRegisterAllElement(xsltTransformContextPtr ctxt)
  {
      xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates",
                             XSLT_NAMESPACE,
  			   xsltApplyTemplates);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports",
                             XSLT_NAMESPACE,
  			   xsltApplyImports);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template",
                             XSLT_NAMESPACE,
  			   xsltCallTemplate);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "element",
                             XSLT_NAMESPACE,
  			   xsltElement);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute",
                             XSLT_NAMESPACE,
  			   xsltAttribute);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "text",
                             XSLT_NAMESPACE,
  			   xsltText);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction",
                             XSLT_NAMESPACE,
  			   xsltProcessingInstruction);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "comment",
                             XSLT_NAMESPACE,
  			   xsltComment);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "copy",
                             XSLT_NAMESPACE,
  			   xsltCopy);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of",
                             XSLT_NAMESPACE,
  			   xsltValueOf);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "number",
                             XSLT_NAMESPACE,
  			   xsltNumber);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each",
                             XSLT_NAMESPACE,
  			   xsltForEach);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "if",
                             XSLT_NAMESPACE,
  			   xsltIf);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "choose",
                             XSLT_NAMESPACE,
  			   xsltChoose);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "sort",
                             XSLT_NAMESPACE,
  			   xsltSort);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of",
                             XSLT_NAMESPACE,
  			   xsltCopyOf);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "message",
                             XSLT_NAMESPACE,
  			   xsltMessageWrapper);
  
      /*
       * Those don't have callable entry points but are registered anyway
       */
      xsltRegisterExtElement(ctxt, (const xmlChar *) "variable",
                             XSLT_NAMESPACE,
  			   xsltDebug);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "param",
                             XSLT_NAMESPACE,
  			   xsltDebug);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param",
                             XSLT_NAMESPACE,
  			   xsltDebug);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format",
                             XSLT_NAMESPACE,
  			   xsltDebug);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "when",
                             XSLT_NAMESPACE,
  			   xsltDebug);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise",
                             XSLT_NAMESPACE,
  			   xsltDebug);
      xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback",
                             XSLT_NAMESPACE,
  			   xsltDebug);
  
  }
  