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