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