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         xsltTransformError(ctxt, NULL, inst,
3498          "xsltDocumentElem: write rights for %s denied\n",
3499                  filename);
3500         xmlFree(URL);
3501         xmlFree(filename);
3502         return;
3503     }
3504     }
3505 
3506     oldOutputFile = ctxt->outputFile;
3507     oldOutput = ctxt->output;
3508     oldInsert = ctxt->insert;
3509     oldType = ctxt->type;
3510     ctxt->outputFile = (const char *) filename;
3511 
3512     style = xsltNewStylesheet();
3513     if (style == NULL) {
3514     xsltTransformError(ctxt, NULL, inst,
3515                          "xsltDocumentElem: out of memory\n");
3516         goto error;
3517     }
3518 
3519     /*
3520      * Version described in 1.1 draft allows full parameterization
3521      * of the output.
3522      */
3523     prop = xsltEvalAttrValueTemplate(ctxt, inst,
3524                      (const xmlChar *) "version",
3525                      NULL);
3526     if (prop != NULL) {
3527     if (style->version != NULL)
3528         xmlFree(style->version);
3529     style->version = prop;
3530     }
3531     prop = xsltEvalAttrValueTemplate(ctxt, inst,
3532                      (const xmlChar *) "encoding",
3533                      NULL);
3534     if (prop != NULL) {
3535     if (style->encoding != NULL)
3536         xmlFree(style->encoding);
3537     style->encoding = prop;
3538     }
3539     prop = xsltEvalAttrValueTemplate(ctxt, inst,
3540                      (const xmlChar *) "method",
3541                      NULL);
3542     if (prop != NULL) {
3543     const xmlChar *URI;
3544 
3545     if (style->method != NULL)
3546         xmlFree(style->method);
3547     style->method = NULL;
3548     if (style->methodURI != NULL)
3549         xmlFree(style->methodURI);
3550     style->methodURI = NULL;
3551 
3552     URI = xsltGetQNameURI(inst, &prop);
3553     if (prop == NULL) {
3554         if (style != NULL) style->errors++;
3555     } else if (URI == NULL) {
3556         if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
3557         (xmlStrEqual(prop, (const xmlChar *) "html")) ||
3558         (xmlStrEqual(prop, (const xmlChar *) "text"))) {
3559         style->method = prop;
3560         } else {
3561         xsltTransformError(ctxt, NULL, inst,
3562                  "invalid value for method: %s\n", prop);
3563         if (style != NULL) style->warnings++;
3564         }
3565     } else {
3566         style->method = prop;
3567         style->methodURI = xmlStrdup(URI);
3568     }
3569     }
3570     prop = xsltEvalAttrValueTemplate(ctxt, inst,
3571                      (const xmlChar *)
3572                      "doctype-system", NULL);
3573     if (prop != NULL) {
3574     if (style->doctypeSystem != NULL)
3575         xmlFree(style->doctypeSystem);
3576     style->doctypeSystem = prop;
3577     }
3578     prop = xsltEvalAttrValueTemplate(ctxt, inst,
3579                      (const xmlChar *)
3580                      "doctype-public", NULL);
3581     if (prop != NULL) {
3582     if (style->doctypePublic != NULL)
3583         xmlFree(style->doctypePublic);
3584     style->doctypePublic = prop;
3585     }
3586     prop = xsltEvalAttrValueTemplate(ctxt, inst,
3587                      (const xmlChar *) "standalone",
3588                      NULL);
3589     if (prop != NULL) {
3590     if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3591         style->standalone = 1;
3592     } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3593         style->standalone = 0;
3594     } else {
3595         xsltTransformError(ctxt, NULL, inst,
3596                  "invalid value for standalone: %s\n",
3597                  prop);
3598         if (style != NULL) style->warnings++;
3599     }
3600     xmlFree(prop);
3601     }
3602 
3603     prop = xsltEvalAttrValueTemplate(ctxt, inst,
3604                      (const xmlChar *) "indent",
3605                      NULL);
3606     if (prop != NULL) {
3607     if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3608         style->indent = 1;
3609     } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3610         style->indent = 0;
3611     } else {
3612         xsltTransformError(ctxt, NULL, inst,
3613                  "invalid value for indent: %s\n", prop);
3614         if (style != NULL) style->warnings++;
3615     }
3616     xmlFree(prop);
3617     }
3618 
3619     prop = xsltEvalAttrValueTemplate(ctxt, inst,
3620                      (const xmlChar *)
3621                      "omit-xml-declaration",
3622                      NULL);
3623     if (prop != NULL) {
3624     if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
3625         style->omitXmlDeclaration = 1;
3626     } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
3627         style->omitXmlDeclaration = 0;
3628     } else {
3629         xsltTransformError(ctxt, NULL, inst,
3630                  "invalid value for omit-xml-declaration: %s\n",
3631                  prop);
3632         if (style != NULL) style->warnings++;
3633     }
3634     xmlFree(prop);
3635     }
3636 
3637     elements = xsltEvalAttrValueTemplate(ctxt, inst,
3638                      (const xmlChar *)
3639                      "cdata-section-elements",
3640                      NULL);
3641     if (elements != NULL) {
3642     if (style->stripSpaces == NULL)
3643         style->stripSpaces = xmlHashCreate(10);
3644     if (style->stripSpaces == NULL)
3645         return;
3646 
3647     element = elements;
3648     while (*element != 0) {
3649         while (IS_BLANK_CH(*element))
3650         element++;
3651         if (*element == 0)
3652         break;
3653         end = element;
3654         while ((*end != 0) && (!IS_BLANK_CH(*end)))
3655         end++;
3656         element = xmlStrndup(element, end - element);
3657         if (element) {
3658         const xmlChar *URI;
3659 
3660 #ifdef WITH_XSLT_DEBUG_PARSING
3661         xsltGenericDebug(xsltGenericDebugContext,
3662                  "add cdata section output element %s\n",
3663                  element);
3664 #endif
3665                 URI = xsltGetQNameURI(inst, &element);
3666 
3667         xmlHashAddEntry2(style->stripSpaces, element, URI,
3668                     (xmlChar *) "cdata");
3669         xmlFree(element);
3670         }
3671         element = end;
3672     }
3673     xmlFree(elements);
3674     }
3675 
3676     /*
3677      * Create a new document tree and process the element template
3678      */
3679     XSLT_GET_IMPORT_PTR(method, style, method)
3680     XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3681     XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3682     XSLT_GET_IMPORT_PTR(version, style, version)
3683     XSLT_GET_IMPORT_PTR(encoding, style, encoding)
3684 
3685     if ((method != NULL) &&
3686     (!xmlStrEqual(method, (const xmlChar *) "xml"))) {
3687     if (xmlStrEqual(method, (const xmlChar *) "html")) {
3688         ctxt->type = XSLT_OUTPUT_HTML;
3689         if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3690         res = htmlNewDoc(doctypeSystem, doctypePublic);
3691         else {
3692         if (version != NULL) {
3693 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3694             xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
3695 #endif
3696                 }
3697         res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3698         }
3699         if (res == NULL)
3700         goto error;
3701         res->dict = ctxt->dict;
3702         xmlDictReference(res->dict);
3703     } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
3704         xsltTransformError(ctxt, NULL, inst,
3705          "xsltDocumentElem: unsupported method xhtml\n");
3706         ctxt->type = XSLT_OUTPUT_HTML;
3707         res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
3708         if (res == NULL)
3709         goto error;
3710         res->dict = ctxt->dict;
3711         xmlDictReference(res->dict);
3712     } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
3713         ctxt->type = XSLT_OUTPUT_TEXT;
3714         res = xmlNewDoc(style->version);
3715         if (res == NULL)
3716         goto error;
3717         res->dict = ctxt->dict;
3718         xmlDictReference(res->dict);
3719 #ifdef WITH_XSLT_DEBUG
3720         xsltGenericDebug(xsltGenericDebugContext,
3721                      "reusing transformation dict for output\n");
3722 #endif
3723     } else {
3724         xsltTransformError(ctxt, NULL, inst,
3725                  "xsltDocumentElem: unsupported method (%s)\n",
3726                      method);
3727         goto error;
3728     }
3729     } else {
3730     ctxt->type = XSLT_OUTPUT_XML;
3731     res = xmlNewDoc(style->version);
3732     if (res == NULL)
3733         goto error;
3734     res->dict = ctxt->dict;
3735     xmlDictReference(res->dict);
3736 #ifdef WITH_XSLT_DEBUG
3737     xsltGenericDebug(xsltGenericDebugContext,
3738                      "reusing transformation dict for output\n");
3739 #endif
3740     }
3741     res->charset = XML_CHAR_ENCODING_UTF8;
3742     if (encoding != NULL)
3743     res->encoding = xmlStrdup(encoding);
3744     ctxt->output = res;
3745     ctxt->insert = (xmlNodePtr) res;
3746     xsltApplySequenceConstructor(ctxt, node, inst->children, NULL);
3747 
3748     /*
3749      * Do some post processing work depending on the generated output
3750      */
3751     root = xmlDocGetRootElement(res);
3752     if (root != NULL) {
3753         const xmlChar *doctype = NULL;
3754 
3755         if ((root->ns != NULL) && (root->ns->prefix != NULL))
3756         doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
3757     if (doctype == NULL)
3758         doctype = root->name;
3759 
3760         /*
3761          * Apply the default selection of the method
3762          */
3763         if ((method == NULL) &&
3764             (root->ns == NULL) &&
3765             (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
3766             xmlNodePtr tmp;
3767 
3768             tmp = res->children;
3769             while ((tmp != NULL) && (tmp != root)) {
3770                 if (tmp->type == XML_ELEMENT_NODE)
3771                     break;
3772                 if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
3773                     break;
3774         tmp = tmp->next;
3775             }
3776             if (tmp == root) {
3777                 ctxt->type = XSLT_OUTPUT_HTML;
3778                 res->type = XML_HTML_DOCUMENT_NODE;
3779                 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
3780                     res->intSubset = xmlCreateIntSubset(res, doctype,
3781                                                         doctypePublic,
3782                                                         doctypeSystem);
3783 #ifdef XSLT_GENERATE_HTML_DOCTYPE
3784         } else if (version != NULL) {
3785                     xsltGetHTMLIDs(version, &doctypePublic,
3786                                    &doctypeSystem);
3787                     if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3788                         res->intSubset =
3789                             xmlCreateIntSubset(res, doctype,
3790                                                doctypePublic,
3791                                                doctypeSystem);
3792 #endif
3793                 }
3794             }
3795 
3796         }
3797         if (ctxt->type == XSLT_OUTPUT_XML) {
3798             XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
3799                 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
3800                 if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
3801                 res->intSubset = xmlCreateIntSubset(res, doctype,
3802                                                     doctypePublic,
3803                                                     doctypeSystem);
3804         }
3805     }
3806 
3807     /*
3808      * Calls to redirect:write also take an optional attribute append.
3809      * Attribute append="true|yes" which will attempt to simply append
3810      * to an existing file instead of always opening a new file. The
3811      * default behavior of always overwriting the file still happens
3812      * if we do not specify append.
3813      * Note that append use will forbid use of remote URI target.
3814      */
3815     prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"append",
3816                      NULL);
3817     if (prop != NULL) {
3818     if (xmlStrEqual(prop, (const xmlChar *) "true") ||
3819         xmlStrEqual(prop, (const xmlChar *) "yes")) {
3820         style->omitXmlDeclaration = 1;
3821         redirect_write_append = 1;
3822     } else
3823         style->omitXmlDeclaration = 0;
3824     xmlFree(prop);
3825     }
3826 
3827     if (redirect_write_append) {
3828         FILE *f;
3829 
3830     f = fopen((const char *) filename, "ab");
3831     if (f == NULL) {
3832         ret = -1;
3833     } else {
3834         ret = xsltSaveResultToFile(f, res, style);
3835         fclose(f);
3836     }
3837     } else {
3838     ret = xsltSaveResultToFilename((const char *) filename, res, style, 0);
3839     }
3840     if (ret < 0) {
3841     xsltTransformError(ctxt, NULL, inst,
3842                          "xsltDocumentElem: unable to save to %s\n",
3843                          filename);
3844 #ifdef WITH_XSLT_DEBUG_EXTRA
3845     } else {
3846         xsltGenericDebug(xsltGenericDebugContext,
3847                          "Wrote %d bytes to %s\n", ret, filename);
3848 #endif
3849     }
3850 
3851   error:
3852     ctxt->output = oldOutput;
3853     ctxt->insert = oldInsert;
3854     ctxt->type = oldType;
3855     ctxt->outputFile = oldOutputFile;
3856     if (URL != NULL)
3857         xmlFree(URL);
3858     if (filename != NULL)
3859         xmlFree(filename);
3860     if (style != NULL)
3861         xsltFreeStylesheet(style);
3862     if (res != NULL)
3863         xmlFreeDoc(res);
3864 }
3865 
3866 /************************************************************************
3867  *                                  *
3868  *      Most of the XSLT-1.0 transformations            *
3869  *                                  *
3870  ************************************************************************/
3871 
3872 /**
3873  * xsltSort:
3874  * @ctxt:  a XSLT process context
3875  * @node:  the node in the source tree.
3876  * @inst:  the xslt sort node
3877  * @comp:  precomputed information
3878  *
3879  * function attached to xsl:sort nodes, but this should not be
3880  * called directly
3881  */
3882 void
3883 xsltSort(xsltTransformContextPtr ctxt,
3884     xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
3885     xsltElemPreCompPtr comp) {
3886     if (comp == NULL) {
3887     xsltTransformError(ctxt, NULL, inst,
3888          "xsl:sort : compilation failed\n");
3889     return;
3890     }
3891     xsltTransformError(ctxt, NULL, inst,
3892      "xsl:sort : improper use this should not be reached\n");
3893 }
3894 
3895 /**
3896  * xsltCopy:
3897  * @ctxt:  an XSLT process context
3898  * @node:  the node in the source tree
3899  * @inst:  the element node of the XSLT-copy instruction
3900  * @castedComp:  computed information of the XSLT-copy instruction
3901  *
3902  * Execute the XSLT-copy instruction on the source node.
3903  */
3904 void
3905 xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
3906      xmlNodePtr inst, xsltElemPreCompPtr castedComp)
3907 {
3908 #ifdef XSLT_REFACTORED
3909     xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;
3910 #else
3911     xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
3912 #endif
3913     xmlNodePtr copy, oldInsert;
3914 
3915     oldInsert = ctxt->insert;
3916     if (ctxt->insert != NULL) {
3917     switch (node->type) {
3918         case XML_TEXT_NODE:
3919         case XML_CDATA_SECTION_NODE:
3920         /*
3921          * This text comes from the stylesheet
3922          * For stylesheets, the set of whitespace-preserving
3923          * element names consists of just xsl:text.
3924          */
3925 #ifdef WITH_XSLT_DEBUG_PROCESS
3926         if (node->type == XML_CDATA_SECTION_NODE) {
3927             XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3928              "xsltCopy: CDATA text %s\n", node->content));
3929         } else {
3930             XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3931              "xsltCopy: text %s\n", node->content));
3932                 }
3933 #endif
3934         xsltCopyText(ctxt, ctxt->insert, node, 0);
3935         break;
3936         case XML_DOCUMENT_NODE:
3937         case XML_HTML_DOCUMENT_NODE:
3938         break;
3939         case XML_ELEMENT_NODE:
3940         /*
3941         * REVISIT NOTE: The "fake" is a doc-node, not an element node.
3942         * REMOVED:
3943         *   if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
3944         *    return;
3945         */
3946 
3947 #ifdef WITH_XSLT_DEBUG_PROCESS
3948         XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3949                  "xsltCopy: node %s\n", node->name));
3950 #endif
3951         copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);
3952         ctxt->insert = copy;
3953         if (comp->use != NULL) {
3954             xsltApplyAttributeSet(ctxt, node, inst, comp->use);
3955         }
3956         break;
3957         case XML_ATTRIBUTE_NODE: {
3958 #ifdef WITH_XSLT_DEBUG_PROCESS
3959         XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3960                  "xsltCopy: attribute %s\n", node->name));
3961 #endif
3962         /*
3963         * REVISIT: We could also raise an error if the parent is not
3964         * an element node.
3965         * OPTIMIZE TODO: Can we set the value/children of the
3966         * attribute without an intermediate copy of the string value?
3967         */
3968         xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node);
3969         break;
3970         }
3971         case XML_PI_NODE:
3972 #ifdef WITH_XSLT_DEBUG_PROCESS
3973         XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3974                  "xsltCopy: PI %s\n", node->name));
3975 #endif
3976         copy = xmlNewDocPI(ctxt->insert->doc, node->name,
3977                            node->content);
3978         copy = xsltAddChild(ctxt->insert, copy);
3979         break;
3980         case XML_COMMENT_NODE:
3981 #ifdef WITH_XSLT_DEBUG_PROCESS
3982         XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3983                  "xsltCopy: comment\n"));
3984 #endif
3985         copy = xmlNewComment(node->content);
3986         copy = xsltAddChild(ctxt->insert, copy);
3987         break;
3988         case XML_NAMESPACE_DECL:
3989 #ifdef WITH_XSLT_DEBUG_PROCESS
3990         XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
3991                  "xsltCopy: namespace declaration\n"));
3992 #endif
3993         xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node);
3994         break;
3995         default:
3996         break;
3997 
3998     }
3999     }
4000 
4001     switch (node->type) {
4002     case XML_DOCUMENT_NODE:
4003     case XML_HTML_DOCUMENT_NODE:
4004     case XML_ELEMENT_NODE:
4005         xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
4006         NULL);
4007         break;
4008     default:
4009         break;
4010     }
4011     ctxt->insert = oldInsert;
4012 }
4013 
4014 /**
4015  * xsltText:
4016  * @ctxt:  a XSLT process context
4017  * @node:  the node in the source tree.
4018  * @inst:  the xslt text node
4019  * @comp:  precomputed information
4020  *
4021  * Process the xslt text node on the source node
4022  */
4023 void
4024 xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
4025         xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
4026     if ((inst->children != NULL) && (comp != NULL)) {
4027     xmlNodePtr text = inst->children;
4028     xmlNodePtr copy;
4029 
4030     while (text != NULL) {
4031         if ((text->type != XML_TEXT_NODE) &&
4032              (text->type != XML_CDATA_SECTION_NODE)) {
4033         xsltTransformError(ctxt, NULL, inst,
4034                  "xsl:text content problem\n");
4035         break;
4036         }
4037         copy = xmlNewDocText(ctxt->output, text->content);
4038         if (text->type != XML_CDATA_SECTION_NODE) {
4039 #ifdef WITH_XSLT_DEBUG_PARSING
4040         xsltGenericDebug(xsltGenericDebugContext,
4041              "Disable escaping: %s\n", text->content);
4042 #endif
4043         copy->name = xmlStringTextNoenc;
4044         }
4045         copy = xsltAddChild(ctxt->insert, copy);
4046         text = text->next;
4047     }
4048     }
4049 }
4050 
4051 /**
4052  * xsltElement:
4053  * @ctxt:  a XSLT process context
4054  * @node:  the node in the source tree.
4055  * @inst:  the xslt element node
4056  * @castedComp:  precomputed information
4057  *
4058  * Process the xslt element node on the source node
4059  */
4060 void
4061 xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
4062         xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4063 #ifdef XSLT_REFACTORED
4064     xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp;
4065 #else
4066     xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4067 #endif
4068     xmlChar *prop = NULL;
4069     const xmlChar *name, *prefix = NULL, *nsName = NULL;
4070     xmlNodePtr copy;
4071     xmlNodePtr oldInsert;
4072 
4073     if (ctxt->insert == NULL)
4074     return;
4075 
4076     /*
4077     * A comp->has_name == 0 indicates that we need to skip this instruction,
4078     * since it was evaluated to be invalid already during compilation.
4079     */
4080     if (!comp->has_name)
4081         return;
4082 
4083     /*
4084      * stack and saves
4085      */
4086     oldInsert = ctxt->insert;
4087 
4088     if (comp->name == NULL) {
4089     /* TODO: fix attr acquisition wrt to the XSLT namespace */
4090         prop = xsltEvalAttrValueTemplate(ctxt, inst,
4091         (const xmlChar *) "name", XSLT_NAMESPACE);
4092         if (prop == NULL) {
4093             xsltTransformError(ctxt, NULL, inst,
4094         "xsl:element: The attribute 'name' is missing.\n");
4095             goto error;
4096         }
4097     if (xmlValidateQName(prop, 0)) {
4098         xsltTransformError(ctxt, NULL, inst,
4099         "xsl:element: The effective name '%s' is not a "
4100         "valid QName.\n", prop);
4101         /* we fall through to catch any further errors, if possible */
4102     }
4103     name = xsltSplitQName(ctxt->dict, prop, &prefix);
4104     xmlFree(prop);
4105     } else {
4106     /*
4107     * The "name" value was static.
4108     */
4109 #ifdef XSLT_REFACTORED
4110     prefix = comp->nsPrefix;
4111     name = comp->name;
4112 #else
4113     name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
4114 #endif
4115     }
4116 
4117     /*
4118      * Create the new element
4119      */
4120     if (ctxt->output->dict == ctxt->dict) {
4121     copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL);
4122     } else {
4123     copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL);
4124     }
4125     if (copy == NULL) {
4126     xsltTransformError(ctxt, NULL, inst,
4127         "xsl:element : creation of %s failed\n", name);
4128     return;
4129     }
4130     copy = xsltAddChild(ctxt->insert, copy);
4131     if (copy == NULL) {
4132         xsltTransformError(ctxt, NULL, inst,
4133             "xsl:element : xsltAddChild failed\n");
4134         return;
4135     }
4136 
4137     /*
4138     * Namespace
4139     * ---------
4140     */
4141     if (comp->has_ns) {
4142     if (comp->ns != NULL) {
4143         /*
4144         * No AVT; just plain text for the namespace name.
4145         */
4146         if (comp->ns[0] != 0)
4147         nsName = comp->ns;
4148     } else {
4149         xmlChar *tmpNsName;
4150         /*
4151         * Eval the AVT.
4152         */
4153         /* TODO: check attr acquisition wrt to the XSLT namespace */
4154         tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
4155         (const xmlChar *) "namespace", XSLT_NAMESPACE);
4156         /*
4157         * SPEC XSLT 1.0:
4158         *  "If the string is empty, then the expanded-name of the
4159         *  attribute has a null namespace URI."
4160         */
4161         if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
4162         nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
4163         xmlFree(tmpNsName);
4164     }
4165 
4166         if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
4167             xsltTransformError(ctxt, NULL, inst,
4168                 "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
4169                 "forbidden.\n");
4170             goto error;
4171         }
4172         if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
4173             prefix = BAD_CAST "xml";
4174         } else if (xmlStrEqual(prefix, BAD_CAST "xml")) {
4175             prefix = NULL;
4176         }
4177     } else {
4178     xmlNsPtr ns;
4179     /*
4180     * SPEC XSLT 1.0:
4181     *  "If the namespace attribute is not present, then the QName is
4182     *  expanded into an expanded-name using the namespace declarations
4183     *  in effect for the xsl:element element, including any default
4184     *  namespace declaration.
4185     */
4186     ns = xmlSearchNs(inst->doc, inst, prefix);
4187     if (ns == NULL) {
4188         /*
4189         * TODO: Check this in the compilation layer in case it's a
4190         * static value.
4191         */
4192             if (prefix != NULL) {
4193                 xsltTransformError(ctxt, NULL, inst,
4194                     "xsl:element: The QName '%s:%s' has no "
4195                     "namespace binding in scope in the stylesheet; "
4196                     "this is an error, since the namespace was not "
4197                     "specified by the instruction itself.\n", prefix, name);
4198             }
4199     } else
4200         nsName = ns->href;
4201     }
4202     /*
4203     * Find/create a matching ns-decl in the result tree.
4204     */
4205     if (nsName != NULL) {
4206     if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
4207             /* Don't use a prefix of "xmlns" */
4208         xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");
4209 
4210         copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, copy);
4211 
4212         xmlFree(pref);
4213     } else {
4214         copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix,
4215         copy);
4216     }
4217     } else if ((copy->parent != NULL) &&
4218     (copy->parent->type == XML_ELEMENT_NODE) &&
4219     (copy->parent->ns != NULL))
4220     {
4221     /*
4222     * "Undeclare" the default namespace.
4223     */
4224     xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);
4225     }
4226 
4227     ctxt->insert = copy;
4228 
4229     if (comp->has_use) {
4230     if (comp->use != NULL) {
4231         xsltApplyAttributeSet(ctxt, node, inst, comp->use);
4232     } else {
4233         xmlChar *attrSets = NULL;
4234         /*
4235         * BUG TODO: use-attribute-sets is not a value template.
4236         *  use-attribute-sets = qnames
4237         */
4238         attrSets = xsltEvalAttrValueTemplate(ctxt, inst,
4239         (const xmlChar *)"use-attribute-sets", NULL);
4240         if (attrSets != NULL) {
4241         xsltApplyAttributeSet(ctxt, node, inst, attrSets);
4242         xmlFree(attrSets);
4243         }
4244     }
4245     }
4246     /*
4247     * Instantiate the sequence constructor.
4248     */
4249     if (inst->children != NULL)
4250     xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
4251         NULL);
4252 
4253 error:
4254     ctxt->insert = oldInsert;
4255     return;
4256 }
4257 
4258 
4259 /**
4260  * xsltComment:
4261  * @ctxt:  a XSLT process context
4262  * @node:  the node in the source tree.
4263  * @inst:  the xslt comment node
4264  * @comp:  precomputed information
4265  *
4266  * Process the xslt comment node on the source node
4267  */
4268 void
4269 xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node,
4270                xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
4271     xmlChar *value = NULL;
4272     xmlNodePtr commentNode;
4273     int len;
4274 
4275     value = xsltEvalTemplateString(ctxt, node, inst);
4276     /* TODO: use or generate the compiled form */
4277     len = xmlStrlen(value);
4278     if (len > 0) {
4279         if ((value[len-1] == '-') ||
4280         (xmlStrstr(value, BAD_CAST "--"))) {
4281         xsltTransformError(ctxt, NULL, inst,
4282             "xsl:comment : '--' or ending '-' not allowed in comment\n");
4283         /* fall through to try to catch further errors */
4284     }
4285     }
4286 #ifdef WITH_XSLT_DEBUG_PROCESS
4287     if (value == NULL) {
4288     XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
4289          "xsltComment: empty\n"));
4290     } else {
4291     XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
4292          "xsltComment: content %s\n", value));
4293     }
4294 #endif
4295 
4296     commentNode = xmlNewComment(value);
4297     commentNode = xsltAddChild(ctxt->insert, commentNode);
4298 
4299     if (value != NULL)
4300     xmlFree(value);
4301 }
4302 
4303 /**
4304  * xsltProcessingInstruction:
4305  * @ctxt:  a XSLT process context
4306  * @node:  the node in the source tree.
4307  * @inst:  the xslt processing-instruction node
4308  * @castedComp:  precomputed information
4309  *
4310  * Process the xslt processing-instruction node on the source node
4311  */
4312 void
4313 xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node,
4314                xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4315 #ifdef XSLT_REFACTORED
4316     xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp;
4317 #else
4318     xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4319 #endif
4320     const xmlChar *name;
4321     xmlChar *value = NULL;
4322     xmlNodePtr pi;
4323 
4324 
4325     if (ctxt->insert == NULL)
4326     return;
4327     if (comp->has_name == 0)
4328     return;
4329     if (comp->name == NULL) {
4330     name = xsltEvalAttrValueTemplate(ctxt, inst,
4331                 (const xmlChar *)"name", NULL);
4332     if (name == NULL) {
4333         xsltTransformError(ctxt, NULL, inst,
4334          "xsl:processing-instruction : name is missing\n");
4335         goto error;
4336     }
4337     } else {
4338     name = comp->name;
4339     }
4340     /* TODO: check that it's both an an NCName and a PITarget. */
4341 
4342 
4343     value = xsltEvalTemplateString(ctxt, node, inst);
4344     if (xmlStrstr(value, BAD_CAST "?>") != NULL) {
4345     xsltTransformError(ctxt, NULL, inst,
4346          "xsl:processing-instruction: '?>' not allowed within PI content\n");
4347     goto error;
4348     }
4349 #ifdef WITH_XSLT_DEBUG_PROCESS
4350     if (value == NULL) {
4351     XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
4352          "xsltProcessingInstruction: %s empty\n", name));
4353     } else {
4354     XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
4355          "xsltProcessingInstruction: %s content %s\n", name, value));
4356     }
4357 #endif
4358 
4359     pi = xmlNewDocPI(ctxt->insert->doc, name, value);
4360     pi = xsltAddChild(ctxt->insert, pi);
4361 
4362 error:
4363     if ((name != NULL) && (name != comp->name))
4364         xmlFree((xmlChar *) name);
4365     if (value != NULL)
4366     xmlFree(value);
4367 }
4368 
4369 /**
4370  * xsltCopyOf:
4371  * @ctxt:  an XSLT transformation context
4372  * @node:  the current node in the source tree
4373  * @inst:  the element node of the XSLT copy-of instruction
4374  * @castedComp:  precomputed information of the XSLT copy-of instruction
4375  *
4376  * Process the XSLT copy-of instruction.
4377  */
4378 void
4379 xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
4380                xmlNodePtr inst, xsltElemPreCompPtr castedComp) {
4381 #ifdef XSLT_REFACTORED
4382     xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp;
4383 #else
4384     xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4385 #endif
4386     xmlXPathObjectPtr res = NULL;
4387     xmlNodeSetPtr list = NULL;
4388     int i;
4389 
4390     if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4391     return;
4392     if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4393     xsltTransformError(ctxt, NULL, inst,
4394          "xsl:copy-of : compilation failed\n");
4395     return;
4396     }
4397 
4398      /*
4399     * SPEC XSLT 1.0:
4400     *  "The xsl:copy-of element can be used to insert a result tree
4401     *  fragment into the result tree, without first converting it to
4402     *  a string as xsl:value-of does (see [7.6.1 Generating Text with
4403     *  xsl:value-of]). The required select attribute contains an
4404     *  expression. When the result of evaluating the expression is a
4405     *  result tree fragment, the complete fragment is copied into the
4406     *  result tree. When the result is a node-set, all the nodes in the
4407     *  set are copied in document order into the result tree; copying
4408     *  an element node copies the attribute nodes, namespace nodes and
4409     *  children of the element node as well as the element node itself;
4410     *  a root node is copied by copying its children. When the result
4411     *  is neither a node-set nor a result tree fragment, the result is
4412     *  converted to a string and then inserted into the result tree,
4413     *  as with xsl:value-of.
4414     */
4415 
4416 #ifdef WITH_XSLT_DEBUG_PROCESS
4417     XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4418      "xsltCopyOf: select %s\n", comp->select));
4419 #endif
4420 
4421     /*
4422     * Evaluate the "select" expression.
4423     */
4424     res = xsltPreCompEval(ctxt, node, comp);
4425 
4426     if (res != NULL) {
4427     if (res->type == XPATH_NODESET) {
4428         /*
4429         * Node-set
4430         * --------
4431         */
4432 #ifdef WITH_XSLT_DEBUG_PROCESS
4433         XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4434          "xsltCopyOf: result is a node set\n"));
4435 #endif
4436         list = res->nodesetval;
4437         if (list != NULL) {
4438         xmlNodePtr cur;
4439         /*
4440         * The list is already sorted in document order by XPath.
4441         * Append everything in this order under ctxt->insert.
4442         */
4443         for (i = 0;i < list->nodeNr;i++) {
4444             cur = list->nodeTab[i];
4445             if (cur == NULL)
4446             continue;
4447             if ((cur->type == XML_DOCUMENT_NODE) ||
4448             (cur->type == XML_HTML_DOCUMENT_NODE))
4449             {
4450             xsltCopyTreeList(ctxt, inst,
4451                 cur->children, ctxt->insert, 0, 0);
4452             } else if (cur->type == XML_ATTRIBUTE_NODE) {
4453             xsltShallowCopyAttr(ctxt, inst,
4454                 ctxt->insert, (xmlAttrPtr) cur);
4455             } else {
4456             xsltCopyTree(ctxt, inst, cur, ctxt->insert, 0, 0);
4457             }
4458         }
4459         }
4460     } else if (res->type == XPATH_XSLT_TREE) {
4461         /*
4462         * Result tree fragment
4463         * --------------------
4464         * E.g. via <xsl:variable ...><foo/></xsl:variable>
4465         * Note that the root node of such trees is an xmlDocPtr in Libxslt.
4466         */
4467 #ifdef WITH_XSLT_DEBUG_PROCESS
4468         XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4469          "xsltCopyOf: result is a result tree fragment\n"));
4470 #endif
4471         list = res->nodesetval;
4472         if ((list != NULL) && (list->nodeTab != NULL) &&
4473         (list->nodeTab[0] != NULL) &&
4474         (IS_XSLT_REAL_NODE(list->nodeTab[0])))
4475         {
4476         xsltCopyTreeList(ctxt, inst,
4477             list->nodeTab[0]->children, ctxt->insert, 0, 0);
4478         }
4479     } else {
4480         xmlChar *value = NULL;
4481         /*
4482         * Convert to a string.
4483         */
4484         value = xmlXPathCastToString(res);
4485         if (value == NULL) {
4486         xsltTransformError(ctxt, NULL, inst,
4487             "Internal error in xsltCopyOf(): "
4488             "failed to cast an XPath object to string.\n");
4489         ctxt->state = XSLT_STATE_STOPPED;
4490         } else {
4491         if (value[0] != 0) {
4492             /*
4493             * Append content as text node.
4494             */
4495             xsltCopyTextString(ctxt, ctxt->insert, value, 0);
4496         }
4497         xmlFree(value);
4498 
4499 #ifdef WITH_XSLT_DEBUG_PROCESS
4500         XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
4501             "xsltCopyOf: result %s\n", res->stringval));
4502 #endif
4503         }
4504     }
4505     } else {
4506     ctxt->state = XSLT_STATE_STOPPED;
4507     }
4508 
4509     if (res != NULL)
4510     xmlXPathFreeObject(res);
4511 }
4512 
4513 /**
4514  * xsltValueOf:
4515  * @ctxt:  a XSLT process context
4516  * @node:  the node in the source tree.
4517  * @inst:  the xslt value-of node
4518  * @castedComp:  precomputed information
4519  *
4520  * Process the xslt value-of node on the source node
4521  */
4522 void
4523 xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
4524                xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4525 {
4526 #ifdef XSLT_REFACTORED
4527     xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp;
4528 #else
4529     xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4530 #endif
4531     xmlXPathObjectPtr res = NULL;
4532     xmlChar *value = NULL;
4533 
4534     if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
4535     return;
4536 
4537     if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
4538     xsltTransformError(ctxt, NULL, inst,
4539         "Internal error in xsltValueOf(): "
4540         "The XSLT 'value-of' instruction was not compiled.\n");
4541     return;
4542     }
4543 
4544 #ifdef WITH_XSLT_DEBUG_PROCESS
4545     XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
4546      "xsltValueOf: select %s\n", comp->select));
4547 #endif
4548 
4549     res = xsltPreCompEval(ctxt, node, comp);
4550 
4551     /*
4552     * Cast the XPath object to string.
4553     */
4554     if (res != NULL) {
4555     value = xmlXPathCastToString(res);
4556     if (value == NULL) {
4557         xsltTransformError(ctxt, NULL, inst,
4558         "Internal error in xsltValueOf(): "
4559         "failed to cast an XPath object to string.\n");
4560         ctxt->state = XSLT_STATE_STOPPED;
4561         goto error;
4562     }
4563     if (value[0] != 0) {
4564         xsltCopyTextString(ctxt, ctxt->insert, value, comp->noescape);
4565     }
4566     } else {
4567     xsltTransformError(ctxt, NULL, inst,
4568         "XPath evaluation returned no result.\n");
4569     ctxt->state = XSLT_STATE_STOPPED;
4570     goto error;
4571     }
4572 
4573 #ifdef WITH_XSLT_DEBUG_PROCESS
4574     if (value) {
4575     XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
4576          "xsltValueOf: result '%s'\n", value));
4577     }
4578 #endif
4579 
4580 error:
4581     if (value != NULL)
4582     xmlFree(value);
4583     if (res != NULL)
4584     xmlXPathFreeObject(res);
4585 }
4586 
4587 /**
4588  * xsltNumber:
4589  * @ctxt:  a XSLT process context
4590  * @node:  the node in the source tree.
4591  * @inst:  the xslt number node
4592  * @castedComp:  precomputed information
4593  *
4594  * Process the xslt number node on the source node
4595  */
4596 void
4597 xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node,
4598        xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4599 {
4600 #ifdef XSLT_REFACTORED
4601     xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp;
4602 #else
4603     xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4604 #endif
4605     xmlXPathContextPtr xpctxt;
4606     xmlNsPtr *oldXPNamespaces;
4607     int oldXPNsNr;
4608 
4609     if (comp == NULL) {
4610     xsltTransformError(ctxt, NULL, inst,
4611          "xsl:number : compilation failed\n");
4612     return;
4613     }
4614 
4615     if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4616     return;
4617 
4618     comp->numdata.doc = inst->doc;
4619     comp->numdata.node = inst;
4620 
4621     xpctxt = ctxt->xpathCtxt;
4622     oldXPNsNr = xpctxt->nsNr;
4623     oldXPNamespaces = xpctxt->namespaces;
4624 
4625 #ifdef XSLT_REFACTORED
4626     if (comp->inScopeNs != NULL) {
4627         xpctxt->namespaces = comp->inScopeNs->list;
4628         xpctxt->nsNr = comp->inScopeNs->xpathNumber;
4629     } else {
4630         xpctxt->namespaces = NULL;
4631         xpctxt->nsNr = 0;
4632     }
4633 #else
4634     xpctxt->namespaces = comp->nsList;
4635     xpctxt->nsNr = comp->nsNr;
4636 #endif
4637 
4638     xsltNumberFormat(ctxt, &comp->numdata, node);
4639 
4640     xpctxt->nsNr = oldXPNsNr;
4641     xpctxt->namespaces = oldXPNamespaces;
4642 }
4643 
4644 /**
4645  * xsltApplyImports:
4646  * @ctxt:  an XSLT transformation context
4647  * @contextNode:  the current node in the source tree.
4648  * @inst:  the element node of the XSLT 'apply-imports' instruction
4649  * @comp:  the compiled instruction
4650  *
4651  * Process the XSLT apply-imports element.
4652  */
4653 void
4654 xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
4655              xmlNodePtr inst,
4656          xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
4657 {
4658     xsltTemplatePtr templ;
4659 
4660     if ((ctxt == NULL) || (inst == NULL))
4661     return;
4662 
4663     if (comp == NULL) {
4664     xsltTransformError(ctxt, NULL, inst,
4665         "Internal error in xsltApplyImports(): "
4666         "The XSLT 'apply-imports' instruction was not compiled.\n");
4667     return;
4668     }
4669     /*
4670     * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
4671     * same; the former is the "Current Template Rule" as defined by the
4672     * XSLT spec, the latter is simply the template struct being
4673     * currently processed.
4674     */
4675     if (ctxt->currentTemplateRule == NULL) {
4676     /*
4677     * SPEC XSLT 2.0:
4678     * "[ERR XTDE0560] It is a non-recoverable dynamic error if
4679     *  xsl:apply-imports or xsl:next-match is evaluated when the
4680     *  current template rule is null."
4681     */
4682     xsltTransformError(ctxt, NULL, inst,
4683          "It is an error to call 'apply-imports' "
4684          "when there's no current template rule.\n");
4685     return;
4686     }
4687     /*
4688     * TODO: Check if this is correct.
4689     */
4690     templ = xsltGetTemplate(ctxt, contextNode,
4691     ctxt->currentTemplateRule->style);
4692 
4693     if (templ != NULL) {
4694     xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule;
4695     /*
4696     * Set the current template rule.
4697     */
4698     ctxt->currentTemplateRule = templ;
4699     /*
4700     * URGENT TODO: Need xsl:with-param be handled somehow here?
4701     */
4702     xsltApplyXSLTTemplate(ctxt, contextNode, templ->content,
4703         templ, NULL);
4704 
4705     ctxt->currentTemplateRule = oldCurTemplRule;
4706     }
4707     else {
4708         /* Use built-in templates. */
4709         xsltDefaultProcessOneNode(ctxt, contextNode, NULL);
4710     }
4711 }
4712 
4713 /**
4714  * xsltCallTemplate:
4715  * @ctxt:  a XSLT transformation context
4716  * @node:  the "current node" in the source tree
4717  * @inst:  the XSLT 'call-template' instruction
4718  * @castedComp:  the compiled information of the instruction
4719  *
4720  * Processes the XSLT call-template instruction on the source node.
4721  */
4722 void
4723 xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
4724                xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4725 {
4726 #ifdef XSLT_REFACTORED
4727     xsltStyleItemCallTemplatePtr comp =
4728     (xsltStyleItemCallTemplatePtr) castedComp;
4729 #else
4730     xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4731 #endif
4732     xsltStackElemPtr withParams = NULL;
4733 
4734     if (ctxt->insert == NULL)
4735     return;
4736     if (comp == NULL) {
4737     xsltTransformError(ctxt, NULL, inst,
4738          "The XSLT 'call-template' instruction was not compiled.\n");
4739     return;
4740     }
4741 
4742     /*
4743      * The template must have been precomputed
4744      */
4745     if (comp->templ == NULL) {
4746     comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);
4747     if (comp->templ == NULL) {
4748         if (comp->ns != NULL) {
4749             xsltTransformError(ctxt, NULL, inst,
4750             "The called template '{%s}%s' was not found.\n",
4751             comp->ns, comp->name);
4752         } else {
4753             xsltTransformError(ctxt, NULL, inst,
4754             "The called template '%s' was not found.\n",
4755             comp->name);
4756         }
4757         return;
4758     }
4759     }
4760 
4761 #ifdef WITH_XSLT_DEBUG_PROCESS
4762     if ((comp != NULL) && (comp->name != NULL))
4763     XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
4764              "call-template: name %s\n", comp->name));
4765 #endif
4766 
4767     if (inst->children) {
4768     xmlNodePtr cur;
4769     xsltStackElemPtr param;
4770 
4771     cur = inst->children;
4772     while (cur != NULL) {
4773 #ifdef WITH_DEBUGGER
4774         if (ctxt->debugStatus != XSLT_DEBUG_NONE)
4775         xslHandleDebugger(cur, node, comp->templ, ctxt);
4776 #endif
4777         if (ctxt->state == XSLT_STATE_STOPPED) break;
4778         /*
4779         * TODO: The "with-param"s could be part of the "call-template"
4780         *   structure. Avoid to "search" for params dynamically
4781         *   in the XML tree every time.
4782         */
4783         if (IS_XSLT_ELEM(cur)) {
4784         if (IS_XSLT_NAME(cur, "with-param")) {
4785             param = xsltParseStylesheetCallerParam(ctxt, cur);
4786             if (param != NULL) {
4787             param->next = withParams;
4788             withParams = param;
4789             }
4790         } else {
4791             xsltGenericError(xsltGenericErrorContext,
4792             "xsl:call-template: misplaced xsl:%s\n", cur->name);
4793         }
4794         } else {
4795         xsltGenericError(xsltGenericErrorContext,
4796             "xsl:call-template: misplaced %s element\n", cur->name);
4797         }
4798         cur = cur->next;
4799     }
4800     }
4801     /*
4802      * Create a new frame using the params first
4803      */
4804     xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ,
4805     withParams);
4806     if (withParams != NULL)
4807     xsltFreeStackElemList(withParams);
4808 
4809 #ifdef WITH_XSLT_DEBUG_PROCESS
4810     if ((comp != NULL) && (comp->name != NULL))
4811     XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
4812              "call-template returned: name %s\n", comp->name));
4813 #endif
4814 }
4815 
4816 /**
4817  * xsltApplyTemplates:
4818  * @ctxt:  a XSLT transformation context
4819  * @node:  the 'current node' in the source tree
4820  * @inst:  the element node of an XSLT 'apply-templates' instruction
4821  * @castedComp:  the compiled instruction
4822  *
4823  * Processes the XSLT 'apply-templates' instruction on the current node.
4824  */
4825 void
4826 xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
4827                xmlNodePtr inst, xsltElemPreCompPtr castedComp)
4828 {
4829 #ifdef XSLT_REFACTORED
4830     xsltStyleItemApplyTemplatesPtr comp =
4831     (xsltStyleItemApplyTemplatesPtr) castedComp;
4832 #else
4833     xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
4834 #endif
4835     int i;
4836     xmlNodePtr cur, delNode = NULL, oldContextNode;
4837     xmlNodeSetPtr list = NULL, oldList;
4838     xsltStackElemPtr withParams = NULL;
4839     int oldXPProximityPosition, oldXPContextSize;
4840     const xmlChar *oldMode, *oldModeURI;
4841     xmlDocPtr oldXPDoc;
4842     xsltDocumentPtr oldDocInfo;
4843     xmlXPathContextPtr xpctxt;
4844 
4845     if (comp == NULL) {
4846     xsltTransformError(ctxt, NULL, inst,
4847          "xsl:apply-templates : compilation failed\n");
4848     return;
4849     }
4850     if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
4851     return;
4852 
4853 #ifdef WITH_XSLT_DEBUG_PROCESS
4854     if ((node != NULL) && (node->name != NULL))
4855     XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4856          "xsltApplyTemplates: node: '%s'\n", node->name));
4857 #endif
4858 
4859     xpctxt = ctxt->xpathCtxt;
4860     /*
4861     * Save context states.
4862     */
4863     oldContextNode = ctxt->node;
4864     oldMode = ctxt->mode;
4865     oldModeURI = ctxt->modeURI;
4866     oldDocInfo = ctxt->document;
4867     oldList = ctxt->nodeList;
4868 
4869     /*
4870      * The xpath context size and proximity position, as
4871      * well as the xpath and context documents, may be changed
4872      * so we save their initial state and will restore on exit
4873      */
4874     oldXPContextSize = xpctxt->contextSize;
4875     oldXPProximityPosition = xpctxt->proximityPosition;
4876     oldXPDoc = xpctxt->doc;
4877 
4878     /*
4879     * Set up contexts.
4880     */
4881     ctxt->mode = comp->mode;
4882     ctxt->modeURI = comp->modeURI;
4883 
4884     if (comp->select != NULL) {
4885     xmlXPathObjectPtr res = NULL;
4886 
4887     if (comp->comp == NULL) {
4888         xsltTransformError(ctxt, NULL, inst,
4889          "xsl:apply-templates : compilation failed\n");
4890         goto error;
4891     }
4892 #ifdef WITH_XSLT_DEBUG_PROCESS
4893     XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4894          "xsltApplyTemplates: select %s\n", comp->select));
4895 #endif
4896 
4897     res = xsltPreCompEval(ctxt, node, comp);
4898 
4899     if (res != NULL) {
4900         if (res->type == XPATH_NODESET) {
4901         list = res->nodesetval; /* consume the node set */
4902         res->nodesetval = NULL;
4903         } else {
4904         xsltTransformError(ctxt, NULL, inst,
4905             "The 'select' expression did not evaluate to a "
4906             "node set.\n");
4907         ctxt->state = XSLT_STATE_STOPPED;
4908         xmlXPathFreeObject(res);
4909         goto error;
4910         }
4911         xmlXPathFreeObject(res);
4912         /*
4913         * Note: An xsl:apply-templates with a 'select' attribute,
4914         * can change the current source doc.
4915         */
4916     } else {
4917         xsltTransformError(ctxt, NULL, inst,
4918         "Failed to evaluate the 'select' expression.\n");
4919         ctxt->state = XSLT_STATE_STOPPED;
4920         goto error;
4921     }
4922     if (list == NULL) {
4923 #ifdef WITH_XSLT_DEBUG_PROCESS
4924         XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
4925         "xsltApplyTemplates: select didn't evaluate to a node list\n"));
4926 #endif
4927         goto exit;
4928     }
4929     /*
4930     *
4931     * NOTE: Previously a document info (xsltDocument) was
4932     * created and attached to the Result Tree Fragment.
4933     * But such a document info is created on demand in
4934     * xsltKeyFunction() (functions.c), so we need to create
4935     * it here beforehand.
4936     * In order to take care of potential keys we need to
4937     * do some extra work for the case when a Result Tree Fragment
4938     * is converted into a nodeset (e.g. exslt:node-set()) :
4939     * We attach a "pseudo-doc" (xsltDocument) to _private.
4940     * This xsltDocument, together with the keyset, will be freed
4941     * when the Result Tree Fragment is freed.
4942     *
4943     */
4944 #if 0
4945     if ((ctxt->nbKeys > 0) &&
4946         (list->nodeNr != 0) &&
4947         (list->nodeTab[0]->doc != NULL) &&
4948         XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc))
4949     {
4950         /*
4951         * NOTE that it's also OK if @effectiveDocInfo will be
4952         * set to NULL.
4953         */
4954         isRTF = 1;
4955         effectiveDocInfo = list->nodeTab[0]->doc->_private;
4956     }
4957 #endif
4958     } else {
4959     /*
4960      * Build an XPath node set with the children
4961      */
4962     list = xmlXPathNodeSetCreate(NULL);
4963     if (list == NULL)
4964         goto error;
4965     if (node->type != XML_NAMESPACE_DECL)
4966         cur = node->children;
4967     else
4968         cur = NULL;
4969     while (cur != NULL) {
4970         switch (cur->type) {
4971         case XML_TEXT_NODE:
4972             if ((IS_BLANK_NODE(cur)) &&
4973             (cur->parent != NULL) &&
4974             (cur->parent->type == XML_ELEMENT_NODE) &&
4975             (ctxt->style->stripSpaces != NULL)) {
4976             const xmlChar *val;
4977 
4978             if (cur->parent->ns != NULL) {
4979                 val = (const xmlChar *)
4980                   xmlHashLookup2(ctxt->style->stripSpaces,
4981                          cur->parent->name,
4982                          cur->parent->ns->href);
4983                 if (val == NULL) {
4984                 val = (const xmlChar *)
4985                   xmlHashLookup2(ctxt->style->stripSpaces,
4986                          BAD_CAST "*",
4987                          cur->parent->ns->href);
4988                 }
4989             } else {
4990                 val = (const xmlChar *)
4991                   xmlHashLookup2(ctxt->style->stripSpaces,
4992                          cur->parent->name, NULL);
4993             }
4994             if ((val != NULL) &&
4995                 (xmlStrEqual(val, (xmlChar *) "strip"))) {
4996                 delNode = cur;
4997                 break;
4998             }
4999             }
5000             /* no break on purpose */
5001         case XML_ELEMENT_NODE:
5002         case XML_DOCUMENT_NODE:
5003         case XML_HTML_DOCUMENT_NODE:
5004         case XML_CDATA_SECTION_NODE:
5005         case XML_PI_NODE:
5006         case XML_COMMENT_NODE:
5007             xmlXPathNodeSetAddUnique(list, cur);
5008             break;
5009         case XML_DTD_NODE:
5010             /* Unlink the DTD, it's still reachable
5011              * using doc->intSubset */
5012             if (cur->next != NULL)
5013             cur->next->prev = cur->prev;
5014             if (cur->prev != NULL)
5015             cur->prev->next = cur->next;
5016             break;
5017         case XML_NAMESPACE_DECL:
5018             break;
5019         default:
5020 #ifdef WITH_XSLT_DEBUG_PROCESS
5021             XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
5022              "xsltApplyTemplates: skipping cur type %d\n",
5023                      cur->type));
5024 #endif
5025             delNode = cur;
5026         }
5027         cur = cur->next;
5028         if (delNode != NULL) {
5029 #ifdef WITH_XSLT_DEBUG_PROCESS
5030         XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
5031              "xsltApplyTemplates: removing ignorable blank cur\n"));
5032 #endif
5033         xmlUnlinkNode(delNode);
5034         xmlFreeNode(delNode);
5035         delNode = NULL;
5036         }
5037     }
5038     }
5039 
5040 #ifdef WITH_XSLT_DEBUG_PROCESS
5041     if (list != NULL)
5042     XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
5043     "xsltApplyTemplates: list of %d nodes\n", list->nodeNr));
5044 #endif
5045 
5046     if ((list == NULL) || (list->nodeNr == 0))
5047     goto exit;
5048 
5049     /*
5050     * Set the context's node set and size; this is also needed for
5051     * for xsltDoSortFunction().
5052     */
5053     ctxt->nodeList = list;
5054     /*
5055     * Process xsl:with-param and xsl:sort instructions.
5056     * (The code became so verbose just to avoid the
5057     *  xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
5058     * BUG TODO: We are not using namespaced potentially defined on the
5059     * xsl:sort or xsl:with-param elements; XPath expression might fail.
5060     */
5061     if (inst->children) {
5062     xsltStackElemPtr param;
5063 
5064     cur = inst->children;
5065     while (cur) {
5066 
5067 #ifdef WITH_DEBUGGER
5068         if (ctxt->debugStatus != XSLT_DEBUG_NONE)
5069         xslHandleDebugger(cur, node, NULL, ctxt);
5070 #endif
5071         if (ctxt->state == XSLT_STATE_STOPPED)
5072         break;
5073         if (cur->type == XML_TEXT_NODE) {
5074         cur = cur->next;
5075         continue;
5076         }
5077         if (! IS_XSLT_ELEM(cur))
5078         break;
5079         if (IS_XSLT_NAME(cur, "with-param")) {
5080         param = xsltParseStylesheetCallerParam(ctxt, cur);
5081         if (param != NULL) {
5082             param->next = withParams;
5083             withParams = param;
5084         }
5085         }
5086         if (IS_XSLT_NAME(cur, "sort")) {
5087         xsltTemplatePtr oldCurTempRule =
5088             ctxt->currentTemplateRule;
5089         int nbsorts = 0;
5090         xmlNodePtr sorts[XSLT_MAX_SORT];
5091 
5092         sorts[nbsorts++] = cur;
5093 
5094         while (cur) {
5095 
5096 #ifdef WITH_DEBUGGER
5097             if (ctxt->debugStatus != XSLT_DEBUG_NONE)
5098             xslHandleDebugger(cur, node, NULL, ctxt);
5099 #endif
5100             if (ctxt->state == XSLT_STATE_STOPPED)
5101             break;
5102 
5103             if (cur->type == XML_TEXT_NODE) {
5104             cur = cur->next;
5105             continue;
5106             }
5107 
5108             if (! IS_XSLT_ELEM(cur))
5109             break;
5110             if (IS_XSLT_NAME(cur, "with-param")) {
5111             param = xsltParseStylesheetCallerParam(ctxt, cur);
5112             if (param != NULL) {
5113                 param->next = withParams;
5114                 withParams = param;
5115             }
5116             }
5117             if (IS_XSLT_NAME(cur, "sort")) {
5118             if (nbsorts >= XSLT_MAX_SORT) {
5119                 xsltTransformError(ctxt, NULL, cur,
5120                 "The number (%d) of xsl:sort instructions exceeds the "
5121                 "maximum allowed by this processor's settings.\n",
5122                 nbsorts);
5123                 ctxt->state = XSLT_STATE_STOPPED;
5124                 break;
5125             } else {
5126                 sorts[nbsorts++] = cur;
5127             }
5128             }
5129             cur = cur->next;
5130         }
5131         /*
5132         * The "current template rule" is cleared for xsl:sort.
5133         */
5134         ctxt->currentTemplateRule = NULL;
5135         /*
5136         * Sort.
5137         */
5138         xsltDoSortFunction(ctxt, sorts, nbsorts);
5139         ctxt->currentTemplateRule = oldCurTempRule;
5140         break;
5141         }
5142         cur = cur->next;
5143     }
5144     }
5145     xpctxt->contextSize = list->nodeNr;
5146     /*
5147     * Apply templates for all selected source nodes.
5148     */
5149     for (i = 0; i < list->nodeNr; i++) {
5150     cur = list->nodeTab[i];
5151     /*
5152     * The node becomes the "current node".
5153     */
5154     ctxt->node = cur;
5155     /*
5156     * An xsl:apply-templates can change the current context doc.
5157     * OPTIMIZE TODO: Get rid of the need to set the context doc.
5158     */
5159     if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
5160         xpctxt->doc = cur->doc;
5161 
5162     xpctxt->proximityPosition = i + 1;
5163     /*
5164     * Find and apply a template for this node.
5165     */
5166     xsltProcessOneNode(ctxt, cur, withParams);
5167     }
5168 
5169 exit:
5170 error:
5171     /*
5172     * Free the parameter list.
5173     */
5174     if (withParams != NULL)
5175     xsltFreeStackElemList(withParams);
5176     if (list != NULL)
5177     xmlXPathFreeNodeSet(list);
5178     /*
5179     * Restore context states.
5180     */
5181     xpctxt->doc = oldXPDoc;
5182     xpctxt->contextSize = oldXPContextSize;
5183     xpctxt->proximityPosition = oldXPProximityPosition;
5184 
5185     ctxt->document = oldDocInfo;
5186     ctxt->nodeList = oldList;
5187     ctxt->node = oldContextNode;
5188     ctxt->mode = oldMode;
5189     ctxt->modeURI = oldModeURI;
5190 }
5191 
5192 
5193 /**
5194  * xsltChoose:
5195  * @ctxt:  a XSLT process context
5196  * @contextNode:  the current node in the source tree
5197  * @inst:  the xsl:choose instruction
5198  * @comp:  compiled information of the instruction
5199  *
5200  * Processes the xsl:choose instruction on the source node.
5201  */
5202 void
5203 xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5204        xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
5205 {
5206     xmlNodePtr cur;
5207 
5208     if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
5209     return;
5210 
5211     /*
5212     * TODO: Content model checks should be done only at compilation
5213     * time.
5214     */
5215     cur = inst->children;
5216     if (cur == NULL) {
5217     xsltTransformError(ctxt, NULL, inst,
5218         "xsl:choose: The instruction has no content.\n");
5219     return;
5220     }
5221 
5222 #ifdef XSLT_REFACTORED
5223     /*
5224     * We don't check the content model during transformation.
5225     */
5226 #else
5227     if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) {
5228     xsltTransformError(ctxt, NULL, inst,
5229          "xsl:choose: xsl:when expected first\n");
5230     return;
5231     }
5232 #endif
5233 
5234     {
5235     int testRes = 0, res = 0;
5236 
5237 #ifdef XSLT_REFACTORED
5238     xsltStyleItemWhenPtr wcomp = NULL;
5239 #else
5240     xsltStylePreCompPtr wcomp = NULL;
5241 #endif
5242 
5243     /*
5244     * Process xsl:when ---------------------------------------------------
5245     */
5246     while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) {
5247         wcomp = cur->psvi;
5248 
5249         if ((wcomp == NULL) || (wcomp->test == NULL) ||
5250         (wcomp->comp == NULL))
5251         {
5252         xsltTransformError(ctxt, NULL, cur,
5253             "Internal error in xsltChoose(): "
5254             "The XSLT 'when' instruction was not compiled.\n");
5255         goto error;
5256         }
5257 
5258 
5259 #ifdef WITH_DEBUGGER
5260         if (xslDebugStatus != XSLT_DEBUG_NONE) {
5261         /*
5262         * TODO: Isn't comp->templ always NULL for xsl:choose?
5263         */
5264         xslHandleDebugger(cur, contextNode, NULL, ctxt);
5265         }
5266 #endif
5267 #ifdef WITH_XSLT_DEBUG_PROCESS
5268         XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5269         "xsltChoose: test %s\n", wcomp->test));
5270 #endif
5271 
5272 #ifdef XSLT_FAST_IF
5273         res = xsltPreCompEvalToBoolean(ctxt, contextNode, wcomp);
5274 
5275         if (res == -1) {
5276         ctxt->state = XSLT_STATE_STOPPED;
5277         goto error;
5278         }
5279         testRes = (res == 1) ? 1 : 0;
5280 
5281 #else /* XSLT_FAST_IF */
5282 
5283         res = xsltPreCompEval(ctxt, cotextNode, wcomp);
5284 
5285         if (res != NULL) {
5286         if (res->type != XPATH_BOOLEAN)
5287             res = xmlXPathConvertBoolean(res);
5288         if (res->type == XPATH_BOOLEAN)
5289             testRes = res->boolval;
5290         else {
5291 #ifdef WITH_XSLT_DEBUG_PROCESS
5292             XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5293             "xsltChoose: test didn't evaluate to a boolean\n"));
5294 #endif
5295             goto error;
5296         }
5297         xmlXPathFreeObject(res);
5298         res = NULL;
5299         } else {
5300         ctxt->state = XSLT_STATE_STOPPED;
5301         goto error;
5302         }
5303 
5304 #endif /* else of XSLT_FAST_IF */
5305 
5306 #ifdef WITH_XSLT_DEBUG_PROCESS
5307         XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5308         "xsltChoose: test evaluate to %d\n", testRes));
5309 #endif
5310         if (testRes)
5311         goto test_is_true;
5312 
5313         cur = cur->next;
5314     }
5315 
5316     /*
5317     * Process xsl:otherwise ----------------------------------------------
5318     */
5319     if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) {
5320 
5321 #ifdef WITH_DEBUGGER
5322         if (xslDebugStatus != XSLT_DEBUG_NONE)
5323         xslHandleDebugger(cur, contextNode, NULL, ctxt);
5324 #endif
5325 
5326 #ifdef WITH_XSLT_DEBUG_PROCESS
5327         XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
5328         "evaluating xsl:otherwise\n"));
5329 #endif
5330         goto test_is_true;
5331     }
5332     goto exit;
5333 
5334 test_is_true:
5335 
5336     goto process_sequence;
5337     }
5338 
5339 process_sequence:
5340 
5341     /*
5342     * Instantiate the sequence constructor.
5343     */
5344     xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children,
5345     NULL);
5346 
5347 exit:
5348 error:
5349     return;
5350 }
5351 
5352 /**
5353  * xsltIf:
5354  * @ctxt:  a XSLT process context
5355  * @contextNode:  the current node in the source tree
5356  * @inst:  the xsl:if instruction
5357  * @castedComp:  compiled information of the instruction
5358  *
5359  * Processes the xsl:if instruction on the source node.
5360  */
5361 void
5362 xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5363                xmlNodePtr inst, xsltElemPreCompPtr castedComp)
5364 {
5365     int res = 0;
5366 
5367 #ifdef XSLT_REFACTORED
5368     xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp;
5369 #else
5370     xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
5371 #endif
5372 
5373     if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
5374     return;
5375     if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) {
5376     xsltTransformError(ctxt, NULL, inst,
5377         "Internal error in xsltIf(): "
5378         "The XSLT 'if' instruction was not compiled.\n");
5379     return;
5380     }
5381 
5382 #ifdef WITH_XSLT_DEBUG_PROCESS
5383     XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5384      "xsltIf: test %s\n", comp->test));
5385 #endif
5386 
5387 #ifdef XSLT_FAST_IF
5388     {
5389     xmlDocPtr oldLocalFragmentTop = ctxt->localRVT;
5390 
5391     res = xsltPreCompEvalToBoolean(ctxt, contextNode, comp);
5392 
5393     /*
5394     * Cleanup fragments created during evaluation of the
5395     * "select" expression.
5396     */
5397     if (oldLocalFragmentTop != ctxt->localRVT)
5398         xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
5399     }
5400 
5401 #ifdef WITH_XSLT_DEBUG_PROCESS
5402     XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5403     "xsltIf: test evaluate to %d\n", res));
5404 #endif
5405 
5406     if (res == -1) {
5407     ctxt->state = XSLT_STATE_STOPPED;
5408     goto error;
5409     }
5410     if (res == 1) {
5411     /*
5412     * Instantiate the sequence constructor of xsl:if.
5413     */
5414     xsltApplySequenceConstructor(ctxt,
5415         contextNode, inst->children, NULL);
5416     }
5417 
5418 #else /* XSLT_FAST_IF */
5419     {
5420     /*
5421     * OLD CODE:
5422     */
5423     xmlXPathObjectPtr xpobj = xsltPreCompEval(ctxt, contextNode, comp);
5424     if (xpobj != NULL) {
5425         if (xpobj->type != XPATH_BOOLEAN)
5426         xpobj = xmlXPathConvertBoolean(xpobj);
5427         if (xpobj->type == XPATH_BOOLEAN) {
5428         res = xpobj->boolval;
5429 
5430 #ifdef WITH_XSLT_DEBUG_PROCESS
5431         XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
5432             "xsltIf: test evaluate to %d\n", res));
5433 #endif
5434         if (res) {
5435             xsltApplySequenceConstructor(ctxt,
5436             contextNode, inst->children, NULL);
5437         }
5438         } else {
5439 
5440 #ifdef WITH_XSLT_DEBUG_PROCESS
5441         XSLT_TRACE(ctxt, XSLT_TRACE_IF,
5442             xsltGenericDebug(xsltGenericDebugContext,
5443             "xsltIf: test didn't evaluate to a boolean\n"));
5444 #endif
5445         ctxt->state = XSLT_STATE_STOPPED;
5446         }
5447         xmlXPathFreeObject(xpobj);
5448     } else {
5449         ctxt->state = XSLT_STATE_STOPPED;
5450     }
5451     }
5452 #endif /* else of XSLT_FAST_IF */
5453 
5454 error:
5455     return;
5456 }
5457 
5458 /**
5459  * xsltForEach:
5460  * @ctxt:  an XSLT transformation context
5461  * @contextNode:  the "current node" in the source tree
5462  * @inst:  the element node of the xsl:for-each instruction
5463  * @castedComp:  the compiled information of the instruction
5464  *
5465  * Process the xslt for-each node on the source node
5466  */
5467 void
5468 xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
5469         xmlNodePtr inst, xsltElemPreCompPtr castedComp)
5470 {
5471 #ifdef XSLT_REFACTORED
5472     xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp;
5473 #else
5474     xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp;
5475 #endif
5476     int i;
5477     xmlXPathObjectPtr res = NULL;
5478     xmlNodePtr cur, curInst;
5479     xmlNodeSetPtr list = NULL;
5480     xmlNodeSetPtr oldList;
5481     int oldXPProximityPosition, oldXPContextSize;
5482     xmlNodePtr oldContextNode;
5483     xsltTemplatePtr oldCurTemplRule;
5484     xmlDocPtr oldXPDoc;
5485     xsltDocumentPtr oldDocInfo;
5486     xmlXPathContextPtr xpctxt;
5487 
5488     if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) {
5489     xsltGenericError(xsltGenericErrorContext,
5490         "xsltForEach(): Bad arguments.\n");
5491     return;
5492     }
5493 
5494     if (comp == NULL) {
5495         xsltTransformError(ctxt, NULL, inst,
5496         "Internal error in xsltForEach(): "
5497         "The XSLT 'for-each' instruction was not compiled.\n");
5498         return;
5499     }
5500     if ((comp->select == NULL) || (comp->comp == NULL)) {
5501     xsltTransformError(ctxt, NULL, inst,
5502         "Internal error in xsltForEach(): "
5503         "The selecting expression of the XSLT 'for-each' "
5504         "instruction was not compiled correctly.\n");
5505     return;
5506     }
5507     xpctxt = ctxt->xpathCtxt;
5508 
5509 #ifdef WITH_XSLT_DEBUG_PROCESS
5510     XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5511      "xsltForEach: select %s\n", comp->select));
5512 #endif
5513 
5514     /*
5515     * Save context states.
5516     */
5517     oldDocInfo = ctxt->document;
5518     oldList = ctxt->nodeList;
5519     oldContextNode = ctxt->node;
5520     /*
5521     * The "current template rule" is cleared for the instantiation of
5522     * xsl:for-each.
5523     */
5524     oldCurTemplRule = ctxt->currentTemplateRule;
5525     ctxt->currentTemplateRule = NULL;
5526 
5527     oldXPDoc = xpctxt->doc;
5528     oldXPProximityPosition = xpctxt->proximityPosition;
5529     oldXPContextSize = xpctxt->contextSize;
5530 
5531     /*
5532     * Evaluate the 'select' expression.
5533     */
5534     res = xsltPreCompEval(ctxt, contextNode, comp);
5535 
5536     if (res != NULL) {
5537     if (res->type == XPATH_NODESET)
5538         list = res->nodesetval;
5539     else {
5540         xsltTransformError(ctxt, NULL, inst,
5541         "The 'select' expression does not evaluate to a node set.\n");
5542 
5543 #ifdef WITH_XSLT_DEBUG_PROCESS
5544         XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5545         "xsltForEach: select didn't evaluate to a node list\n"));
5546 #endif
5547         goto error;
5548     }
5549     } else {
5550     xsltTransformError(ctxt, NULL, inst,
5551         "Failed to evaluate the 'select' expression.\n");
5552     ctxt->state = XSLT_STATE_STOPPED;
5553     goto error;
5554     }
5555 
5556     if ((list == NULL) || (list->nodeNr <= 0))
5557     goto exit;
5558 
5559 #ifdef WITH_XSLT_DEBUG_PROCESS
5560     XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
5561     "xsltForEach: select evaluates to %d nodes\n", list->nodeNr));
5562 #endif
5563 
5564     /*
5565     * Set the list; this has to be done already here for xsltDoSortFunction().
5566     */
5567     ctxt->nodeList = list;
5568     /*
5569     * Handle xsl:sort instructions and skip them for further processing.
5570     * BUG TODO: We are not using namespaced potentially defined on the
5571     * xsl:sort element; XPath expression might fail.
5572     */
5573     curInst = inst->children;
5574     if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
5575     int nbsorts = 0;
5576     xmlNodePtr sorts[XSLT_MAX_SORT];
5577 
5578     sorts[nbsorts++] = curInst;
5579 
5580 #ifdef WITH_DEBUGGER
5581     if (xslDebugStatus != XSLT_DEBUG_NONE)
5582         xslHandleDebugger(curInst, contextNode, NULL, ctxt);
5583 #endif
5584 
5585     curInst = curInst->next;
5586     while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
5587         if (nbsorts >= XSLT_MAX_SORT) {
5588         xsltTransformError(ctxt, NULL, curInst,
5589             "The number of xsl:sort instructions exceeds the "
5590             "maximum (%d) allowed by this processor.\n",
5591             XSLT_MAX_SORT);
5592         goto error;
5593         } else {
5594         sorts[nbsorts++] = curInst;
5595         }
5596 
5597 #ifdef WITH_DEBUGGER
5598         if (xslDebugStatus != XSLT_DEBUG_NONE)
5599         xslHandleDebugger(curInst, contextNode, NULL, ctxt);
5600 #endif
5601         curInst = curInst->next;
5602     }
5603     xsltDoSortFunction(ctxt, sorts, nbsorts);
5604     }
5605     xpctxt->contextSize = list->nodeNr;
5606     /*
5607     * Instantiate the sequence constructor for each selected node.
5608     */
5609     for (i = 0; i < list->nodeNr; i++) {
5610     cur = list->nodeTab[i];
5611     /*
5612     * The selected node becomes the "current node".
5613     */
5614     ctxt->node = cur;
5615     /*
5616     * An xsl:for-each can change the current context doc.
5617     * OPTIMIZE TODO: Get rid of the need to set the context doc.
5618     */
5619     if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
5620         xpctxt->doc = cur->doc;
5621 
5622     xpctxt->proximityPosition = i + 1;
5623 
5624     xsltApplySequenceConstructor(ctxt, cur, curInst, NULL);
5625     }
5626 
5627 exit:
5628 error:
5629     if (res != NULL)
5630     xmlXPathFreeObject(res);
5631     /*
5632     * Restore old states.
5633     */
5634     ctxt->document = oldDocInfo;
5635     ctxt->nodeList = oldList;
5636     ctxt->node = oldContextNode;
5637     ctxt->currentTemplateRule = oldCurTemplRule;
5638 
5639     xpctxt->doc = oldXPDoc;
5640     xpctxt->contextSize = oldXPContextSize;
5641     xpctxt->proximityPosition = oldXPProximityPosition;
5642 }
5643 
5644 /************************************************************************
5645  *                                  *
5646  *          Generic interface               *
5647  *                                  *
5648  ************************************************************************/
5649 
5650 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5651 typedef struct xsltHTMLVersion {
5652     const char *version;
5653     const char *public;
5654     const char *system;
5655 } xsltHTMLVersion;
5656 
5657 static xsltHTMLVersion xsltHTMLVersions[] = {
5658     { "5", NULL, "about:legacy-compat" },
5659     { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5660       "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
5661     { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
5662       "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
5663     { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5664       "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5665     { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
5666       "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
5667     { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
5668       "http://www.w3.org/TR/html4/strict.dtd"},
5669     { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
5670       "http://www.w3.org/TR/html4/loose.dtd"},
5671     { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
5672       "http://www.w3.org/TR/html4/frameset.dtd"},
5673     { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
5674       "http://www.w3.org/TR/html4/loose.dtd"},
5675     { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL }
5676 };
5677 
5678 /**
5679  * xsltGetHTMLIDs:
5680  * @version:  the version string
5681  * @publicID:  used to return the public ID
5682  * @systemID:  used to return the system ID
5683  *
5684  * Returns -1 if not found, 0 otherwise and the system and public
5685  *         Identifier for this given verion of HTML
5686  */
5687 static int
5688 xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
5689                 const xmlChar **systemID) {
5690     unsigned int i;
5691     if (version == NULL)
5692     return(-1);
5693     for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1]));
5694      i++) {
5695     if (!xmlStrcasecmp(version,
5696                    (const xmlChar *) xsltHTMLVersions[i].version)) {
5697         if (publicID != NULL)
5698         *publicID = (const xmlChar *) xsltHTMLVersions[i].public;
5699         if (systemID != NULL)
5700         *systemID = (const xmlChar *) xsltHTMLVersions[i].system;
5701         return(0);
5702     }
5703     }
5704     return(-1);
5705 }
5706 #endif
5707 
5708 /**
5709  * xsltApplyStripSpaces:
5710  * @ctxt:  a XSLT process context
5711  * @node:  the root of the XML tree
5712  *
5713  * Strip the unwanted ignorable spaces from the input tree
5714  */
5715 void
5716 xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) {
5717     xmlNodePtr current;
5718 #ifdef WITH_XSLT_DEBUG_PROCESS
5719     int nb = 0;
5720 #endif
5721 
5722 
5723     current = node;
5724     while (current != NULL) {
5725     /*
5726      * Cleanup children empty nodes if asked for
5727      */
5728     if ((IS_XSLT_REAL_NODE(current)) &&
5729         (current->children != NULL) &&
5730         (xsltFindElemSpaceHandling(ctxt, current))) {
5731         xmlNodePtr delete = NULL, cur = current->children;
5732 
5733         while (cur != NULL) {
5734         if (IS_BLANK_NODE(cur))
5735             delete = cur;
5736 
5737         cur = cur->next;
5738         if (delete != NULL) {
5739             xmlUnlinkNode(delete);
5740             xmlFreeNode(delete);
5741             delete = NULL;
5742 #ifdef WITH_XSLT_DEBUG_PROCESS
5743             nb++;
5744 #endif
5745         }
5746         }
5747     }
5748 
5749     /*
5750      * Skip to next node in document order.
5751      */
5752     if (node->type == XML_ENTITY_REF_NODE) {
5753         /* process deep in entities */
5754         xsltApplyStripSpaces(ctxt, node->children);
5755     }
5756     if ((current->children != NULL) &&
5757             (current->type != XML_ENTITY_REF_NODE)) {
5758         current = current->children;
5759     } else if (current->next != NULL) {
5760         current = current->next;
5761     } else {
5762         do {
5763         current = current->parent;
5764         if (current == NULL)
5765             break;
5766         if (current == node)
5767             goto done;
5768         if (current->next != NULL) {
5769             current = current->next;
5770             break;
5771         }
5772         } while (current != NULL);
5773     }
5774     }
5775 
5776 done:
5777 #ifdef WITH_XSLT_DEBUG_PROCESS
5778     XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext,
5779          "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb));
5780 #endif
5781     return;
5782 }
5783 
5784 static int
5785 xsltCountKeys(xsltTransformContextPtr ctxt)
5786 {
5787     xsltStylesheetPtr style;
5788     xsltKeyDefPtr keyd;
5789 
5790     if (ctxt == NULL)
5791     return(-1);
5792 
5793     /*
5794     * Do we have those nastly templates with a key() in the match pattern?
5795     */
5796     ctxt->hasTemplKeyPatterns = 0;
5797     style = ctxt->style;
5798     while (style != NULL) {
5799     if (style->keyMatch != NULL) {
5800         ctxt->hasTemplKeyPatterns = 1;
5801         break;
5802     }
5803     style = xsltNextImport(style);
5804     }
5805     /*
5806     * Count number of key declarations.
5807     */
5808     ctxt->nbKeys = 0;
5809     style = ctxt->style;
5810     while (style != NULL) {
5811     keyd = style->keys;
5812     while (keyd) {
5813         ctxt->nbKeys++;
5814         keyd = keyd->next;
5815     }
5816     style = xsltNextImport(style);
5817     }
5818     return(ctxt->nbKeys);
5819 }
5820 
5821 /**
5822  * xsltApplyStylesheetInternal:
5823  * @style:  a parsed XSLT stylesheet
5824  * @doc:  a parsed XML document
5825  * @params:  a NULL terminated array of parameters names/values tuples
5826  * @output:  the targetted output
5827  * @profile:  profile FILE * output or NULL
5828  * @user:  user provided parameter
5829  *
5830  * Apply the stylesheet to the document
5831  * NOTE: This may lead to a non-wellformed output XML wise !
5832  *
5833  * Returns the result document or NULL in case of error
5834  */
5835 static xmlDocPtr
5836 xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
5837                             const char **params, const char *output,
5838                             FILE * profile, xsltTransformContextPtr userCtxt)
5839 {
5840     xmlDocPtr res = NULL;
5841     xsltTransformContextPtr ctxt = NULL;
5842     xmlNodePtr root, node;
5843     const xmlChar *method;
5844     const xmlChar *doctypePublic;
5845     const xmlChar *doctypeSystem;
5846     const xmlChar *version;
5847     const xmlChar *encoding;
5848     xsltStackElemPtr variables;
5849     xsltStackElemPtr vptr;
5850 
5851     xsltInitGlobals();
5852 
5853     if ((style == NULL) || (doc == NULL))
5854         return (NULL);
5855 
5856     if (style->internalized == 0) {
5857 #ifdef WITH_XSLT_DEBUG
5858     xsltGenericDebug(xsltGenericDebugContext,
5859              "Stylesheet was not fully internalized !\n");
5860 #endif
5861     }
5862     if (doc->intSubset != NULL) {
5863     /*
5864      * Avoid hitting the DTD when scanning nodes
5865      * but keep it linked as doc->intSubset
5866      */
5867     xmlNodePtr cur = (xmlNodePtr) doc->intSubset;
5868     if (cur->next != NULL)
5869         cur->next->prev = cur->prev;
5870     if (cur->prev != NULL)
5871         cur->prev->next = cur->next;
5872     if (doc->children == cur)
5873         doc->children = cur->next;
5874     if (doc->last == cur)
5875         doc->last = cur->prev;
5876     cur->prev = cur->next = NULL;
5877     }
5878 
5879     /*
5880      * Check for XPath document order availability
5881      */
5882     root = xmlDocGetRootElement(doc);
5883     if (root != NULL) {
5884     if (((ptrdiff_t) root->content >= 0) &&
5885             (xslDebugStatus == XSLT_DEBUG_NONE))
5886         xmlXPathOrderDocElems(doc);
5887     }
5888 
5889     if (userCtxt != NULL)
5890     ctxt = userCtxt;
5891     else
5892     ctxt = xsltNewTransformContext(style, doc);
5893 
5894     if (ctxt == NULL)
5895         return (NULL);
5896 
5897     ctxt->initialContextDoc = doc;
5898     ctxt->initialContextNode = (xmlNodePtr) doc;
5899 
5900     if (profile != NULL)
5901         ctxt->profile = 1;
5902 
5903     if (output != NULL)
5904         ctxt->outputFile = output;
5905     else
5906         ctxt->outputFile = NULL;
5907 
5908     /*
5909      * internalize the modes if needed
5910      */
5911     if (ctxt->dict != NULL) {
5912         if (ctxt->mode != NULL)
5913         ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1);
5914         if (ctxt->modeURI != NULL)
5915         ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1);
5916     }
5917 
5918     XSLT_GET_IMPORT_PTR(method, style, method)
5919     XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
5920     XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
5921     XSLT_GET_IMPORT_PTR(version, style, version)
5922     XSLT_GET_IMPORT_PTR(encoding, style, encoding)
5923 
5924     if ((method != NULL) &&
5925     (!xmlStrEqual(method, (const xmlChar *) "xml")))
5926     {
5927         if (xmlStrEqual(method, (const xmlChar *) "html")) {
5928             ctxt->type = XSLT_OUTPUT_HTML;
5929             if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
5930                 res = htmlNewDoc(doctypeSystem, doctypePublic);
5931         } else {
5932                 if (version == NULL) {
5933             xmlDtdPtr dtd;
5934 
5935             res = htmlNewDoc(NULL, NULL);
5936             /*
5937             * Make sure no DTD node is generated in this case
5938             */
5939             if (res != NULL) {
5940             dtd = xmlGetIntSubset(res);
5941             if (dtd != NULL) {
5942                 xmlUnlinkNode((xmlNodePtr) dtd);
5943                 xmlFreeDtd(dtd);
5944             }
5945             res->intSubset = NULL;
5946             res->extSubset = NULL;
5947             }
5948         } else {
5949 
5950 #ifdef XSLT_GENERATE_HTML_DOCTYPE
5951             xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
5952 #endif
5953             res = htmlNewDoc(doctypeSystem, doctypePublic);
5954         }
5955             }
5956             if (res == NULL)
5957                 goto error;
5958         res->dict = ctxt->dict;
5959         xmlDictReference(res->dict);
5960 
5961 #ifdef WITH_XSLT_DEBUG
5962         xsltGenericDebug(xsltGenericDebugContext,
5963         "reusing transformation dict for output\n");
5964 #endif
5965         } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
5966         xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5967         "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n");
5968             ctxt->type = XSLT_OUTPUT_HTML;
5969             res = htmlNewDoc(doctypeSystem, doctypePublic);
5970             if (res == NULL)
5971                 goto error;
5972         res->dict = ctxt->dict;
5973         xmlDictReference(res->dict);
5974 
5975 #ifdef WITH_XSLT_DEBUG
5976         xsltGenericDebug(xsltGenericDebugContext,
5977         "reusing transformation dict for output\n");
5978 #endif
5979         } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
5980             ctxt->type = XSLT_OUTPUT_TEXT;
5981             res = xmlNewDoc(style->version);
5982             if (res == NULL)
5983                 goto error;
5984         res->dict = ctxt->dict;
5985         xmlDictReference(res->dict);
5986 
5987 #ifdef WITH_XSLT_DEBUG
5988         xsltGenericDebug(xsltGenericDebugContext,
5989         "reusing transformation dict for output\n");
5990 #endif
5991         } else {
5992         xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
5993         "xsltApplyStylesheetInternal: unsupported method (%s)\n",
5994         method);
5995             goto error;
5996         }
5997     } else {
5998         ctxt->type = XSLT_OUTPUT_XML;
5999         res = xmlNewDoc(style->version);
6000         if (res == NULL)
6001             goto error;
6002     res->dict = ctxt->dict;
6003     xmlDictReference(ctxt->dict);
6004 #ifdef WITH_XSLT_DEBUG
6005     xsltGenericDebug(xsltGenericDebugContext,
6006              "reusing transformation dict for output\n");
6007 #endif
6008     }
6009     res->charset = XML_CHAR_ENCODING_UTF8;
6010     if (encoding != NULL)
6011         res->encoding = xmlStrdup(encoding);
6012     variables = style->variables;
6013 
6014     /*
6015      * Start the evaluation, evaluate the params, the stylesheets globals
6016      * and start by processing the top node.
6017      */
6018     if (xsltNeedElemSpaceHandling(ctxt))
6019     xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
6020     /*
6021     * Evaluate global params and user-provided params.
6022     */
6023     ctxt->node = (xmlNodePtr) doc;
6024     if (ctxt->globalVars == NULL)
6025     ctxt->globalVars = xmlHashCreate(20);
6026     if (params != NULL) {
6027         xsltEvalUserParams(ctxt, params);
6028     }
6029 
6030     /* need to be called before evaluating global variables */
6031     xsltCountKeys(ctxt);
6032 
6033     xsltEvalGlobalVariables(ctxt);
6034 
6035     /* Clean up any unused RVTs. */
6036     xsltReleaseLocalRVTs(ctxt, NULL);
6037 
6038     ctxt->node = (xmlNodePtr) doc;
6039     ctxt->output = res;
6040     ctxt->insert = (xmlNodePtr) res;
6041     ctxt->varsBase = ctxt->varsNr - 1;
6042 
6043     ctxt->xpathCtxt->contextSize = 1;
6044     ctxt->xpathCtxt->proximityPosition = 1;
6045     ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */
6046     /*
6047     * Start processing the source tree -----------------------------------
6048     */
6049     xsltProcessOneNode(ctxt, ctxt->node, NULL);
6050     /*
6051     * Remove all remaining vars from the stack.
6052     */
6053     xsltLocalVariablePop(ctxt, 0, -2);
6054     xsltShutdownCtxtExts(ctxt);
6055 
6056     xsltCleanupTemplates(style); /* TODO: <- style should be read only */
6057 
6058     /*
6059      * Now cleanup our variables so stylesheet can be re-used
6060      *
6061      * TODO: this is not needed anymore global variables are copied
6062      *       and not evaluated directly anymore, keep this as a check
6063      */
6064     if (style->variables != variables) {
6065         vptr = style->variables;
6066         while (vptr->next != variables)
6067             vptr = vptr->next;
6068         vptr->next = NULL;
6069         xsltFreeStackElemList(style->variables);
6070         style->variables = variables;
6071     }
6072     vptr = style->variables;
6073     while (vptr != NULL) {
6074         if (vptr->computed) {
6075             if (vptr->value != NULL) {
6076                 xmlXPathFreeObject(vptr->value);
6077                 vptr->value = NULL;
6078                 vptr->computed = 0;
6079             }
6080         }
6081         vptr = vptr->next;
6082     }
6083 #if 0
6084     /*
6085      * code disabled by wmb; awaiting kb's review
6086      * problem is that global variable(s) may contain xpath objects
6087      * from doc associated with RVT, so can't be freed at this point.
6088      * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
6089      * I assume this shouldn't be required at this point.
6090      */
6091     /*
6092     * Free all remaining tree fragments.
6093     */
6094     xsltFreeRVTs(ctxt);
6095 #endif
6096     /*
6097      * Do some post processing work depending on the generated output
6098      */
6099     root = xmlDocGetRootElement(res);
6100     if (root != NULL) {
6101         const xmlChar *doctype = NULL;
6102 
6103         if ((root->ns != NULL) && (root->ns->prefix != NULL))
6104         doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
6105     if (doctype == NULL)
6106         doctype = root->name;
6107 
6108         /*
6109          * Apply the default selection of the method
6110          */
6111         if ((method == NULL) &&
6112             (root->ns == NULL) &&
6113             (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
6114             xmlNodePtr tmp;
6115 
6116             tmp = res->children;
6117             while ((tmp != NULL) && (tmp != root)) {
6118                 if (tmp->type == XML_ELEMENT_NODE)
6119                     break;
6120                 if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
6121                     break;
6122         tmp = tmp->next;
6123             }
6124             if (tmp == root) {
6125                 ctxt->type = XSLT_OUTPUT_HTML;
6126         /*
6127         * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
6128         *  transformation on the doc, but functions like
6129         */
6130                 res->type = XML_HTML_DOCUMENT_NODE;
6131                 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
6132                     res->intSubset = xmlCreateIntSubset(res, doctype,
6133                                                         doctypePublic,
6134                                                         doctypeSystem);
6135 #ifdef XSLT_GENERATE_HTML_DOCTYPE
6136         } else if (version != NULL) {
6137                     xsltGetHTMLIDs(version, &doctypePublic,
6138                                    &doctypeSystem);
6139                     if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
6140                         res->intSubset =
6141                             xmlCreateIntSubset(res, doctype,
6142                                                doctypePublic,
6143                                                doctypeSystem);
6144 #endif
6145                 }
6146             }
6147 
6148         }
6149         if (ctxt->type == XSLT_OUTPUT_XML) {
6150             XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
6151             XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
6152             if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
6153             xmlNodePtr last;
6154         /* Need a small "hack" here to assure DTD comes before
6155            possible comment nodes */
6156         node = res->children;
6157         last = res->last;
6158         res->children = NULL;
6159         res->last = NULL;
6160                 res->intSubset = xmlCreateIntSubset(res, doctype,
6161                                                     doctypePublic,
6162                                                     doctypeSystem);
6163         if (res->children != NULL) {
6164             res->children->next = node;
6165             node->prev = res->children;
6166             res->last = last;
6167         } else {
6168             res->children = node;
6169             res->last = last;
6170         }
6171         }
6172         }
6173     }
6174     xmlXPathFreeNodeSet(ctxt->nodeList);
6175     if (profile != NULL) {
6176         xsltSaveProfiling(ctxt, profile);
6177     }
6178 
6179     /*
6180      * Be pedantic.
6181      */
6182     if ((ctxt != NULL) && (ctxt->state != XSLT_STATE_OK)) {
6183     xmlFreeDoc(res);
6184     res = NULL;
6185     }
6186     if ((res != NULL) && (ctxt != NULL) && (output != NULL)) {
6187     int ret;
6188 
6189     ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output);
6190     if (ret == 0) {
6191         xsltTransformError(ctxt, NULL, NULL,
6192              "xsltApplyStylesheet: forbidden to save to %s\n",
6193                    output);
6194     } else if (ret < 0) {
6195         xsltTransformError(ctxt, NULL, NULL,
6196              "xsltApplyStylesheet: saving to %s may not be possible\n",
6197                    output);
6198     }
6199     }
6200 
6201 #ifdef XSLT_DEBUG_PROFILE_CACHE
6202     printf("# Cache:\n");
6203     printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
6204     printf("# Reused variables     : %d\n", ctxt->cache->dbgReusedVars);
6205 #endif
6206 
6207     if ((ctxt != NULL) && (userCtxt == NULL))
6208     xsltFreeTransformContext(ctxt);
6209 
6210     return (res);
6211 
6212 error:
6213     if (res != NULL)
6214         xmlFreeDoc(res);
6215 
6216 #ifdef XSLT_DEBUG_PROFILE_CACHE
6217     printf("# Cache:\n");
6218     printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
6219     printf("# Reused variables     : %d\n", ctxt->cache->dbgReusedVars);
6220 #endif
6221 
6222     if ((ctxt != NULL) && (userCtxt == NULL))
6223         xsltFreeTransformContext(ctxt);
6224     return (NULL);
6225 }
6226 
6227 /**
6228  * xsltApplyStylesheet:
6229  * @style:  a parsed XSLT stylesheet
6230  * @doc:  a parsed XML document
6231  * @params:  a NULL terminated arry of parameters names/values tuples
6232  *
6233  * Apply the stylesheet to the document
6234  * NOTE: This may lead to a non-wellformed output XML wise !
6235  *
6236  * Returns the result document or NULL in case of error
6237  */
6238 xmlDocPtr
6239 xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6240                     const char **params)
6241 {
6242     return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL));
6243 }
6244 
6245 /**
6246  * xsltProfileStylesheet:
6247  * @style:  a parsed XSLT stylesheet
6248  * @doc:  a parsed XML document
6249  * @params:  a NULL terminated arry of parameters names/values tuples
6250  * @output:  a FILE * for the profiling output
6251  *
6252  * Apply the stylesheet to the document and dump the profiling to
6253  * the given output.
6254  *
6255  * Returns the result document or NULL in case of error
6256  */
6257 xmlDocPtr
6258 xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6259                       const char **params, FILE * output)
6260 {
6261     xmlDocPtr res;
6262 
6263     res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL);
6264     return (res);
6265 }
6266 
6267 /**
6268  * xsltApplyStylesheetUser:
6269  * @style:  a parsed XSLT stylesheet
6270  * @doc:  a parsed XML document
6271  * @params:  a NULL terminated array of parameters names/values tuples
6272  * @output:  the targetted output
6273  * @profile:  profile FILE * output or NULL
6274  * @userCtxt:  user provided transform context
6275  *
6276  * Apply the stylesheet to the document and allow the user to provide
6277  * its own transformation context.
6278  *
6279  * Returns the result document or NULL in case of error
6280  */
6281 xmlDocPtr
6282 xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
6283                             const char **params, const char *output,
6284                             FILE * profile, xsltTransformContextPtr userCtxt)
6285 {
6286     xmlDocPtr res;
6287 
6288     res = xsltApplyStylesheetInternal(style, doc, params, output,
6289                                   profile, userCtxt);
6290     return (res);
6291 }
6292 
6293 /**
6294  * xsltRunStylesheetUser:
6295  * @style:  a parsed XSLT stylesheet
6296  * @doc:  a parsed XML document
6297  * @params:  a NULL terminated array of parameters names/values tuples
6298  * @output:  the URL/filename ot the generated resource if available
6299  * @SAX:  a SAX handler for progressive callback output (not implemented yet)
6300  * @IObuf:  an output buffer for progressive output (not implemented yet)
6301  * @profile:  profile FILE * output or NULL
6302  * @userCtxt:  user provided transform context
6303  *
6304  * Apply the stylesheet to the document and generate the output according
6305  * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6306  *
6307  * NOTE: This may lead to a non-wellformed output XML wise !
6308  * NOTE: This may also result in multiple files being generated
6309  * NOTE: using IObuf, the result encoding used will be the one used for
6310  *       creating the output buffer, use the following macro to read it
6311  *       from the stylesheet
6312  *       XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6313  * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6314  *       since the interface uses only UTF8
6315  *
6316  * Returns the number of by written to the main resource or -1 in case of
6317  *         error.
6318  */
6319 int
6320 xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
6321                   const char **params, const char *output,
6322                   xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf,
6323           FILE * profile, xsltTransformContextPtr userCtxt)
6324 {
6325     xmlDocPtr tmp;
6326     int ret;
6327 
6328     if ((output == NULL) && (SAX == NULL) && (IObuf == NULL))
6329         return (-1);
6330     if ((SAX != NULL) && (IObuf != NULL))
6331         return (-1);
6332 
6333     /* unsupported yet */
6334     if (SAX != NULL) {
6335         XSLT_TODO   /* xsltRunStylesheet xmlSAXHandlerPtr SAX */
6336     return (-1);
6337     }
6338 
6339     tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile,
6340                                   userCtxt);
6341     if (tmp == NULL) {
6342     xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
6343                          "xsltRunStylesheet : run failed\n");
6344         return (-1);
6345     }
6346     if (IObuf != NULL) {
6347         /* TODO: incomplete, IObuf output not progressive */
6348         ret = xsltSaveResultTo(IObuf, tmp, style);
6349     } else {
6350         ret = xsltSaveResultToFilename(output, tmp, style, 0);
6351     }
6352     xmlFreeDoc(tmp);
6353     return (ret);
6354 }
6355 
6356 /**
6357  * xsltRunStylesheet:
6358  * @style:  a parsed XSLT stylesheet
6359  * @doc:  a parsed XML document
6360  * @params:  a NULL terminated array of parameters names/values tuples
6361  * @output:  the URL/filename ot the generated resource if available
6362  * @SAX:  a SAX handler for progressive callback output (not implemented yet)
6363  * @IObuf:  an output buffer for progressive output (not implemented yet)
6364  *
6365  * Apply the stylesheet to the document and generate the output according
6366  * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
6367  *
6368  * NOTE: This may lead to a non-wellformed output XML wise !
6369  * NOTE: This may also result in multiple files being generated
6370  * NOTE: using IObuf, the result encoding used will be the one used for
6371  *       creating the output buffer, use the following macro to read it
6372  *       from the stylesheet
6373  *       XSLT_GET_IMPORT_PTR(encoding, style, encoding)
6374  * NOTE: using SAX, any encoding specified in the stylesheet will be lost
6375  *       since the interface uses only UTF8
6376  *
6377  * Returns the number of bytes written to the main resource or -1 in case of
6378  *         error.
6379  */
6380 int
6381 xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
6382                   const char **params, const char *output,
6383                   xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf)
6384 {
6385     return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf,
6386                          NULL, NULL));
6387 }
6388 
6389 static void
6390 xsltMessageWrapper(xsltTransformContextPtr ctxt, xmlNodePtr node,
6391                    xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) {
6392     xsltMessage(ctxt, node, inst);
6393 }
6394 
6395 /**
6396  * xsltRegisterAllElement:
6397  * @ctxt:  the XPath context
6398  *
6399  * Registers all default XSLT elements in this context
6400  */
6401 void
6402 xsltRegisterAllElement(xsltTransformContextPtr ctxt)
6403 {
6404     xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates",
6405                            XSLT_NAMESPACE,
6406                xsltApplyTemplates);
6407     xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports",
6408                            XSLT_NAMESPACE,
6409                xsltApplyImports);
6410     xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template",
6411                            XSLT_NAMESPACE,
6412                xsltCallTemplate);
6413     xsltRegisterExtElement(ctxt, (const xmlChar *) "element",
6414                            XSLT_NAMESPACE,
6415                xsltElement);
6416     xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute",
6417                            XSLT_NAMESPACE,
6418                xsltAttribute);
6419     xsltRegisterExtElement(ctxt, (const xmlChar *) "text",
6420                            XSLT_NAMESPACE,
6421                xsltText);
6422     xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction",
6423                            XSLT_NAMESPACE,
6424                xsltProcessingInstruction);
6425     xsltRegisterExtElement(ctxt, (const xmlChar *) "comment",
6426                            XSLT_NAMESPACE,
6427                xsltComment);
6428     xsltRegisterExtElement(ctxt, (const xmlChar *) "copy",
6429                            XSLT_NAMESPACE,
6430                xsltCopy);
6431     xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of",
6432                            XSLT_NAMESPACE,
6433                xsltValueOf);
6434     xsltRegisterExtElement(ctxt, (const xmlChar *) "number",
6435                            XSLT_NAMESPACE,
6436                xsltNumber);
6437     xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each",
6438                            XSLT_NAMESPACE,
6439                xsltForEach);
6440     xsltRegisterExtElement(ctxt, (const xmlChar *) "if",
6441                            XSLT_NAMESPACE,
6442                xsltIf);
6443     xsltRegisterExtElement(ctxt, (const xmlChar *) "choose",
6444                            XSLT_NAMESPACE,
6445                xsltChoose);
6446     xsltRegisterExtElement(ctxt, (const xmlChar *) "sort",
6447                            XSLT_NAMESPACE,
6448                xsltSort);
6449     xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of",
6450                            XSLT_NAMESPACE,
6451                xsltCopyOf);
6452     xsltRegisterExtElement(ctxt, (const xmlChar *) "message",
6453                            XSLT_NAMESPACE,
6454                xsltMessageWrapper);
6455 
6456     /*
6457      * Those don't have callable entry points but are registered anyway
6458      */
6459     xsltRegisterExtElement(ctxt, (const xmlChar *) "variable",
6460                            XSLT_NAMESPACE,
6461                xsltDebug);
6462     xsltRegisterExtElement(ctxt, (const xmlChar *) "param",
6463                            XSLT_NAMESPACE,
6464                xsltDebug);
6465     xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param",
6466                            XSLT_NAMESPACE,
6467                xsltDebug);
6468     xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format",
6469                            XSLT_NAMESPACE,
6470                xsltDebug);
6471     xsltRegisterExtElement(ctxt, (const xmlChar *) "when",
6472                            XSLT_NAMESPACE,
6473                xsltDebug);
6474     xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise",
6475                            XSLT_NAMESPACE,
6476                xsltDebug);
6477     xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback",
6478                            XSLT_NAMESPACE,
6479                xsltDebug);
6480 
6481 }