1 /*
   2  * xslt.c: Implemetation of an XSL Transformation 1.0 engine
   3  *
   4  * Reference:
   5  *   XSLT specification
   6  *   http://www.w3.org/TR/1999/REC-xslt-19991116
   7  *
   8  *   Associating Style Sheets with XML documents
   9  *   http://www.w3.org/1999/06/REC-xml-stylesheet-19990629
  10  *
  11  * See Copyright for the status of this software.
  12  *
  13  * daniel@veillard.com
  14  */
  15 
  16 #define IN_LIBXSLT
  17 #include "libxslt.h"
  18 
  19 #include <string.h>
  20 
  21 #include <libxml/xmlmemory.h>
  22 #include <libxml/parser.h>
  23 #include <libxml/tree.h>
  24 #include <libxml/valid.h>
  25 #include <libxml/hash.h>
  26 #include <libxml/uri.h>
  27 #include <libxml/xmlerror.h>
  28 #include <libxml/parserInternals.h>
  29 #include <libxml/xpathInternals.h>
  30 #include <libxml/xpath.h>
  31 #include "xslt.h"
  32 #include "xsltInternals.h"
  33 #include "pattern.h"
  34 #include "variables.h"
  35 #include "namespaces.h"
  36 #include "attributes.h"
  37 #include "xsltutils.h"
  38 #include "imports.h"
  39 #include "keys.h"
  40 #include "documents.h"
  41 #include "extensions.h"
  42 #include "preproc.h"
  43 #include "extra.h"
  44 #include "security.h"
  45 #include "xsltlocale.h"
  46 
  47 #ifdef WITH_XSLT_DEBUG
  48 #define WITH_XSLT_DEBUG_PARSING
  49 /* #define WITH_XSLT_DEBUG_BLANKS */
  50 #endif
  51 
  52 const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA;
  53 const int xsltLibxsltVersion = LIBXSLT_VERSION;
  54 const int xsltLibxmlVersion = LIBXML_VERSION;
  55 
  56 #ifdef XSLT_REFACTORED
  57 
  58 const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE;
  59 
  60 #define XSLT_ELEMENT_CATEGORY_XSLT 0
  61 #define XSLT_ELEMENT_CATEGORY_EXTENSION 1
  62 #define XSLT_ELEMENT_CATEGORY_LRE 2
  63 
  64 /*
  65 * xsltLiteralResultMarker:
  66 * Marker for Literal result elements, in order to avoid multiple attempts
  67 * to recognize such elements in the stylesheet's tree.
  68 * This marker is set on node->psvi during the initial traversal
  69 * of a stylesheet's node tree.
  70 *
  71 const xmlChar *xsltLiteralResultMarker =
  72     (const xmlChar *) "Literal Result Element";
  73 */
  74 
  75 /*
  76 * xsltXSLTTextMarker:
  77 * Marker for xsl:text elements. Used to recognize xsl:text elements
  78 * for post-processing of the stylesheet's tree, where those
  79 * elements are removed from the tree.
  80 */
  81 const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
  82 
  83 /*
  84 * xsltXSLTAttrMarker:
  85 * Marker for XSLT attribute on Literal Result Elements.
  86 */
  87 const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
  88 
  89 #endif
  90 
  91 #ifdef XSLT_LOCALE_WINAPI
  92 extern xmlRMutexPtr xsltLocaleMutex;
  93 #endif
  94 /*
  95  * Harmless but avoiding a problem when compiling against a
  96  * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
  97  */
  98 #ifndef LIBXML_DEBUG_ENABLED
  99 double xmlXPathStringEvalNumber(const xmlChar *str);
 100 #endif
 101 /*
 102  * Useful macros
 103  */
 104 
 105 #ifdef  IS_BLANK
 106 #undef  IS_BLANK
 107 #endif
 108 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||  \
 109                      ((c) == 0x0D))
 110 
 111 #ifdef  IS_BLANK_NODE
 112 #undef  IS_BLANK_NODE
 113 #endif
 114 #define IS_BLANK_NODE(n)                        \
 115     (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
 116 
 117 /**
 118  * xsltParseContentError:
 119  *
 120  * @style: the stylesheet
 121  * @node: the node where the error occured
 122  *
 123  * Compile-time error function.
 124  */
 125 static void
 126 xsltParseContentError(xsltStylesheetPtr style,
 127                xmlNodePtr node)
 128 {
 129     if ((style == NULL) || (node == NULL))
 130     return;
 131 
 132     if (IS_XSLT_ELEM(node))
 133     xsltTransformError(NULL, style, node,
 134         "The XSLT-element '%s' is not allowed at this position.\n",
 135         node->name);
 136     else
 137     xsltTransformError(NULL, style, node,
 138         "The element '%s' is not allowed at this position.\n",
 139         node->name);
 140     style->errors++;
 141 }
 142 
 143 #ifdef XSLT_REFACTORED
 144 #else
 145 /**
 146  * exclPrefixPush:
 147  * @style: the transformation stylesheet
 148  * @value:  the excluded namespace name to push on the stack
 149  *
 150  * Push an excluded namespace name on the stack
 151  *
 152  * Returns the new index in the stack or -1 if already present or
 153  * in case of error
 154  */
 155 static int
 156 exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)
 157 {
 158     int i;
 159 
 160     if (style->exclPrefixMax == 0) {
 161         style->exclPrefixMax = 4;
 162         style->exclPrefixTab =
 163             (xmlChar * *)xmlMalloc(style->exclPrefixMax *
 164                                    sizeof(style->exclPrefixTab[0]));
 165         if (style->exclPrefixTab == NULL) {
 166             xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
 167             return (-1);
 168         }
 169     }
 170     /* do not push duplicates */
 171     for (i = 0;i < style->exclPrefixNr;i++) {
 172         if (xmlStrEqual(style->exclPrefixTab[i], value))
 173         return(-1);
 174     }
 175     if (style->exclPrefixNr >= style->exclPrefixMax) {
 176         style->exclPrefixMax *= 2;
 177         style->exclPrefixTab =
 178             (xmlChar * *)xmlRealloc(style->exclPrefixTab,
 179                                     style->exclPrefixMax *
 180                                     sizeof(style->exclPrefixTab[0]));
 181         if (style->exclPrefixTab == NULL) {
 182             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
 183             return (-1);
 184         }
 185     }
 186     style->exclPrefixTab[style->exclPrefixNr] = value;
 187     style->exclPrefix = value;
 188     return (style->exclPrefixNr++);
 189 }
 190 /**
 191  * exclPrefixPop:
 192  * @style: the transformation stylesheet
 193  *
 194  * Pop an excluded prefix value from the stack
 195  *
 196  * Returns the stored excluded prefix value
 197  */
 198 static xmlChar *
 199 exclPrefixPop(xsltStylesheetPtr style)
 200 {
 201     xmlChar *ret;
 202 
 203     if (style->exclPrefixNr <= 0)
 204         return (0);
 205     style->exclPrefixNr--;
 206     if (style->exclPrefixNr > 0)
 207         style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
 208     else
 209         style->exclPrefix = NULL;
 210     ret = style->exclPrefixTab[style->exclPrefixNr];
 211     style->exclPrefixTab[style->exclPrefixNr] = 0;
 212     return (ret);
 213 }
 214 #endif
 215 
 216 /************************************************************************
 217  *                                  *
 218  *          Helper functions                *
 219  *                                  *
 220  ************************************************************************/
 221 
 222 static int initialized = 0;
 223 /**
 224  * xsltInit:
 225  *
 226  * Initializes the processor (e.g. registers built-in extensions,
 227  * etc.)
 228  */
 229 void
 230 xsltInit (void) {
 231     if (initialized == 0) {
 232     initialized = 1;
 233 #ifdef XSLT_LOCALE_WINAPI
 234     xsltLocaleMutex = xmlNewRMutex();
 235 #endif
 236         xsltRegisterAllExtras();
 237     }
 238 }
 239 
 240 /**
 241  * xsltUninit:
 242  *
 243  * Uninitializes the processor.
 244  */
 245 void
 246 xsltUninit (void) {
 247 #ifdef XSLT_LOCALE_WINAPI
 248     xmlFreeRMutex(xsltLocaleMutex);
 249     xsltLocaleMutex = NULL;
 250 #endif
 251     initialized = 0;
 252 }
 253 
 254 /**
 255  * xsltIsBlank:
 256  * @str:  a string
 257  *
 258  * Check if a string is ignorable
 259  *
 260  * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
 261  */
 262 int
 263 xsltIsBlank(xmlChar *str) {
 264     if (str == NULL)
 265     return(1);
 266     while (*str != 0) {
 267     if (!(IS_BLANK(*str))) return(0);
 268     str++;
 269     }
 270     return(1);
 271 }
 272 
 273 /************************************************************************
 274  *                                  *
 275  *      Routines to handle XSLT data structures         *
 276  *                                  *
 277  ************************************************************************/
 278 static xsltDecimalFormatPtr
 279 xsltNewDecimalFormat(const xmlChar *nsUri, xmlChar *name)
 280 {
 281     xsltDecimalFormatPtr self;
 282     /* UTF-8 for 0x2030 */
 283     static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};
 284 
 285     self = xmlMalloc(sizeof(xsltDecimalFormat));
 286     if (self != NULL) {
 287     self->next = NULL;
 288         self->nsUri = nsUri;
 289     self->name = name;
 290 
 291     /* Default values */
 292     self->digit = xmlStrdup(BAD_CAST("#"));
 293     self->patternSeparator = xmlStrdup(BAD_CAST(";"));
 294     self->decimalPoint = xmlStrdup(BAD_CAST("."));
 295     self->grouping = xmlStrdup(BAD_CAST(","));
 296     self->percent = xmlStrdup(BAD_CAST("%"));
 297     self->permille = xmlStrdup(BAD_CAST(permille));
 298     self->zeroDigit = xmlStrdup(BAD_CAST("0"));
 299     self->minusSign = xmlStrdup(BAD_CAST("-"));
 300     self->infinity = xmlStrdup(BAD_CAST("Infinity"));
 301     self->noNumber = xmlStrdup(BAD_CAST("NaN"));
 302     }
 303     return self;
 304 }
 305 
 306 static void
 307 xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
 308 {
 309     if (self != NULL) {
 310     if (self->digit)
 311         xmlFree(self->digit);
 312     if (self->patternSeparator)
 313         xmlFree(self->patternSeparator);
 314     if (self->decimalPoint)
 315         xmlFree(self->decimalPoint);
 316     if (self->grouping)
 317         xmlFree(self->grouping);
 318     if (self->percent)
 319         xmlFree(self->percent);
 320     if (self->permille)
 321         xmlFree(self->permille);
 322     if (self->zeroDigit)
 323         xmlFree(self->zeroDigit);
 324     if (self->minusSign)
 325         xmlFree(self->minusSign);
 326     if (self->infinity)
 327         xmlFree(self->infinity);
 328     if (self->noNumber)
 329         xmlFree(self->noNumber);
 330     if (self->name)
 331         xmlFree(self->name);
 332     xmlFree(self);
 333     }
 334 }
 335 
 336 static void
 337 xsltFreeDecimalFormatList(xsltStylesheetPtr self)
 338 {
 339     xsltDecimalFormatPtr iter;
 340     xsltDecimalFormatPtr tmp;
 341 
 342     if (self == NULL)
 343     return;
 344 
 345     iter = self->decimalFormat;
 346     while (iter != NULL) {
 347     tmp = iter->next;
 348     xsltFreeDecimalFormat(iter);
 349     iter = tmp;
 350     }
 351 }
 352 
 353 /**
 354  * xsltDecimalFormatGetByName:
 355  * @style: the XSLT stylesheet
 356  * @name: the decimal-format name to find
 357  *
 358  * Find decimal-format by name
 359  *
 360  * Returns the xsltDecimalFormatPtr
 361  */
 362 xsltDecimalFormatPtr
 363 xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
 364 {
 365     xsltDecimalFormatPtr result = NULL;
 366 
 367     if (name == NULL)
 368     return style->decimalFormat;
 369 
 370     while (style != NULL) {
 371     for (result = style->decimalFormat->next;
 372          result != NULL;
 373          result = result->next) {
 374         if ((result->nsUri == NULL) && xmlStrEqual(name, result->name))
 375         return result;
 376     }
 377     style = xsltNextImport(style);
 378     }
 379     return result;
 380 }
 381 
 382 /**
 383  * xsltDecimalFormatGetByQName:
 384  * @style: the XSLT stylesheet
 385  * @nsUri: the namespace URI of the QName
 386  * @name: the local part of the QName
 387  *
 388  * Find decimal-format by QName
 389  *
 390  * Returns the xsltDecimalFormatPtr
 391  */
 392 xsltDecimalFormatPtr
 393 xsltDecimalFormatGetByQName(xsltStylesheetPtr style, const xmlChar *nsUri,
 394                             const xmlChar *name)
 395 {
 396     xsltDecimalFormatPtr result = NULL;
 397 
 398     if (name == NULL)
 399     return style->decimalFormat;
 400 
 401     while (style != NULL) {
 402     for (result = style->decimalFormat->next;
 403          result != NULL;
 404          result = result->next) {
 405         if (xmlStrEqual(nsUri, result->nsUri) &&
 406                 xmlStrEqual(name, result->name))
 407         return result;
 408     }
 409     style = xsltNextImport(style);
 410     }
 411     return result;
 412 }
 413 
 414 
 415 /**
 416  * xsltNewTemplate:
 417  *
 418  * Create a new XSLT Template
 419  *
 420  * Returns the newly allocated xsltTemplatePtr or NULL in case of error
 421  */
 422 static xsltTemplatePtr
 423 xsltNewTemplate(void) {
 424     xsltTemplatePtr cur;
 425 
 426     cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
 427     if (cur == NULL) {
 428     xsltTransformError(NULL, NULL, NULL,
 429         "xsltNewTemplate : malloc failed\n");
 430     return(NULL);
 431     }
 432     memset(cur, 0, sizeof(xsltTemplate));
 433     cur->priority = XSLT_PAT_NO_PRIORITY;
 434     return(cur);
 435 }
 436 
 437 /**
 438  * xsltFreeTemplate:
 439  * @template:  an XSLT template
 440  *
 441  * Free up the memory allocated by @template
 442  */
 443 static void
 444 xsltFreeTemplate(xsltTemplatePtr template) {
 445     if (template == NULL)
 446     return;
 447     if (template->match) xmlFree(template->match);
 448 /*
 449 *   NOTE: @name and @nameURI are put into the string dict now.
 450 *   if (template->name) xmlFree(template->name);
 451 *   if (template->nameURI) xmlFree(template->nameURI);
 452 */
 453 /*
 454     if (template->mode) xmlFree(template->mode);
 455     if (template->modeURI) xmlFree(template->modeURI);
 456  */
 457     if (template->inheritedNs) xmlFree(template->inheritedNs);
 458 
 459     /* free profiling data */
 460     if (template->templCalledTab) xmlFree(template->templCalledTab);
 461     if (template->templCountTab) xmlFree(template->templCountTab);
 462 
 463     memset(template, -1, sizeof(xsltTemplate));
 464     xmlFree(template);
 465 }
 466 
 467 /**
 468  * xsltFreeTemplateList:
 469  * @template:  an XSLT template list
 470  *
 471  * Free up the memory allocated by all the elements of @template
 472  */
 473 static void
 474 xsltFreeTemplateList(xsltTemplatePtr template) {
 475     xsltTemplatePtr cur;
 476 
 477     while (template != NULL) {
 478     cur = template;
 479     template = template->next;
 480     xsltFreeTemplate(cur);
 481     }
 482 }
 483 
 484 #ifdef XSLT_REFACTORED
 485 
 486 static void
 487 xsltFreeNsAliasList(xsltNsAliasPtr item)
 488 {
 489     xsltNsAliasPtr tmp;
 490 
 491     while (item) {
 492     tmp = item;
 493     item = item->next;
 494     xmlFree(tmp);
 495     }
 496     return;
 497 }
 498 
 499 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
 500 static void
 501 xsltFreeNamespaceMap(xsltNsMapPtr item)
 502 {
 503     xsltNsMapPtr tmp;
 504 
 505     while (item) {
 506     tmp = item;
 507     item = item->next;
 508     xmlFree(tmp);
 509     }
 510     return;
 511 }
 512 
 513 static xsltNsMapPtr
 514 xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
 515             xmlDocPtr doc,
 516             xmlNsPtr ns,
 517             xmlNodePtr elem)
 518 {
 519     xsltNsMapPtr ret;
 520 
 521     if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
 522     return(NULL);
 523 
 524     ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
 525     if (ret == NULL) {
 526     xsltTransformError(NULL, cctxt->style, elem,
 527         "Internal error: (xsltNewNamespaceMapItem) "
 528         "memory allocation failed.\n");
 529     return(NULL);
 530     }
 531     memset(ret, 0, sizeof(xsltNsMap));
 532     ret->doc = doc;
 533     ret->ns = ns;
 534     ret->origNsName = ns->href;
 535     /*
 536     * Store the item at current stylesheet-level.
 537     */
 538     if (cctxt->psData->nsMap != NULL)
 539     ret->next = cctxt->psData->nsMap;
 540     cctxt->psData->nsMap = ret;
 541 
 542     return(ret);
 543 }
 544 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
 545 
 546 /**
 547  * xsltCompilerVarInfoFree:
 548  * @cctxt: the compilation context
 549  *
 550  * Frees the list of information for vars/params.
 551  */
 552 static void
 553 xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)
 554 {
 555     xsltVarInfoPtr ivar = cctxt->ivars, ivartmp;
 556 
 557     while (ivar) {
 558     ivartmp = ivar;
 559     ivar = ivar->next;
 560     xmlFree(ivartmp);
 561     }
 562 }
 563 
 564 /**
 565  * xsltCompilerCtxtFree:
 566  *
 567  * Free an XSLT compiler context.
 568  */
 569 static void
 570 xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
 571 {
 572     if (cctxt == NULL)
 573     return;
 574 #ifdef WITH_XSLT_DEBUG_PARSING
 575     xsltGenericDebug(xsltGenericDebugContext,
 576     "Freeing compilation context\n");
 577     xsltGenericDebug(xsltGenericDebugContext,
 578     "### Max inodes: %d\n", cctxt->maxNodeInfos);
 579     xsltGenericDebug(xsltGenericDebugContext,
 580     "### Max LREs  : %d\n", cctxt->maxLREs);
 581 #endif
 582     /*
 583     * Free node-infos.
 584     */
 585     if (cctxt->inodeList != NULL) {
 586     xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
 587     while (cur != NULL) {
 588         tmp = cur;
 589         cur = cur->next;
 590         xmlFree(tmp);
 591     }
 592     }
 593     if (cctxt->tmpList != NULL)
 594     xsltPointerListFree(cctxt->tmpList);
 595 #ifdef XSLT_REFACTORED_XPATHCOMP
 596     if (cctxt->xpathCtxt != NULL)
 597     xmlXPathFreeContext(cctxt->xpathCtxt);
 598 #endif
 599     if (cctxt->nsAliases != NULL)
 600     xsltFreeNsAliasList(cctxt->nsAliases);
 601 
 602     if (cctxt->ivars)
 603     xsltCompilerVarInfoFree(cctxt);
 604 
 605     xmlFree(cctxt);
 606 }
 607 
 608 /**
 609  * xsltCompilerCreate:
 610  *
 611  * Creates an XSLT compiler context.
 612  *
 613  * Returns the pointer to the created xsltCompilerCtxt or
 614  *         NULL in case of an internal error.
 615  */
 616 static xsltCompilerCtxtPtr
 617 xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
 618     xsltCompilerCtxtPtr ret;
 619 
 620     ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
 621     if (ret == NULL) {
 622     xsltTransformError(NULL, style, NULL,
 623         "xsltCompilerCreate: allocation of compiler "
 624         "context failed.\n");
 625     return(NULL);
 626     }
 627     memset(ret, 0, sizeof(xsltCompilerCtxt));
 628 
 629     ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
 630     ret->tmpList = xsltPointerListCreate(20);
 631     if (ret->tmpList == NULL) {
 632     goto internal_err;
 633     }
 634 #ifdef XSLT_REFACTORED_XPATHCOMP
 635     /*
 636     * Create the XPath compilation context in order
 637     * to speed up precompilation of XPath expressions.
 638     */
 639     ret->xpathCtxt = xmlXPathNewContext(NULL);
 640     if (ret->xpathCtxt == NULL)
 641     goto internal_err;
 642 #endif
 643 
 644     return(ret);
 645 
 646 internal_err:
 647     xsltCompilationCtxtFree(ret);
 648     return(NULL);
 649 }
 650 
 651 static void
 652 xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
 653 {
 654     xsltEffectiveNsPtr tmp;
 655 
 656     while (first != NULL) {
 657     tmp = first;
 658     first = first->nextInStore;
 659     xmlFree(tmp);
 660     }
 661 }
 662 
 663 static void
 664 xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
 665 {
 666     if (data == NULL)
 667     return;
 668 
 669     if (data->inScopeNamespaces != NULL) {
 670     int i;
 671     xsltNsListContainerPtr nsi;
 672     xsltPointerListPtr list =
 673         (xsltPointerListPtr) data->inScopeNamespaces;
 674 
 675     for (i = 0; i < list->number; i++) {
 676         /*
 677         * REVISIT TODO: Free info of in-scope namespaces.
 678         */
 679         nsi = (xsltNsListContainerPtr) list->items[i];
 680         if (nsi->list != NULL)
 681         xmlFree(nsi->list);
 682         xmlFree(nsi);
 683     }
 684     xsltPointerListFree(list);
 685     data->inScopeNamespaces = NULL;
 686     }
 687 
 688     if (data->exclResultNamespaces != NULL) {
 689     int i;
 690     xsltPointerListPtr list = (xsltPointerListPtr)
 691         data->exclResultNamespaces;
 692 
 693     for (i = 0; i < list->number; i++)
 694         xsltPointerListFree((xsltPointerListPtr) list->items[i]);
 695 
 696     xsltPointerListFree(list);
 697     data->exclResultNamespaces = NULL;
 698     }
 699 
 700     if (data->extElemNamespaces != NULL) {
 701     xsltPointerListPtr list = (xsltPointerListPtr)
 702         data->extElemNamespaces;
 703     int i;
 704 
 705     for (i = 0; i < list->number; i++)
 706         xsltPointerListFree((xsltPointerListPtr) list->items[i]);
 707 
 708     xsltPointerListFree(list);
 709     data->extElemNamespaces = NULL;
 710     }
 711     if (data->effectiveNs) {
 712     xsltLREEffectiveNsNodesFree(data->effectiveNs);
 713     data->effectiveNs = NULL;
 714     }
 715 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
 716     xsltFreeNamespaceMap(data->nsMap);
 717 #endif
 718     xmlFree(data);
 719 }
 720 
 721 static xsltPrincipalStylesheetDataPtr
 722 xsltNewPrincipalStylesheetData(void)
 723 {
 724     xsltPrincipalStylesheetDataPtr ret;
 725 
 726     ret = (xsltPrincipalStylesheetDataPtr)
 727     xmlMalloc(sizeof(xsltPrincipalStylesheetData));
 728     if (ret == NULL) {
 729     xsltTransformError(NULL, NULL, NULL,
 730         "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
 731     return(NULL);
 732     }
 733     memset(ret, 0, sizeof(xsltPrincipalStylesheetData));
 734 
 735     /*
 736     * Global list of in-scope namespaces.
 737     */
 738     ret->inScopeNamespaces = xsltPointerListCreate(-1);
 739     if (ret->inScopeNamespaces == NULL)
 740     goto internal_err;
 741     /*
 742     * Global list of excluded result ns-decls.
 743     */
 744     ret->exclResultNamespaces = xsltPointerListCreate(-1);
 745     if (ret->exclResultNamespaces == NULL)
 746     goto internal_err;
 747     /*
 748     * Global list of extension instruction namespace names.
 749     */
 750     ret->extElemNamespaces = xsltPointerListCreate(-1);
 751     if (ret->extElemNamespaces == NULL)
 752     goto internal_err;
 753 
 754     return(ret);
 755 
 756 internal_err:
 757 
 758     return(NULL);
 759 }
 760 
 761 #endif
 762 
 763 /**
 764  * xsltNewStylesheet:
 765  *
 766  * Create a new XSLT Stylesheet
 767  *
 768  * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
 769  */
 770 xsltStylesheetPtr
 771 xsltNewStylesheet(void) {
 772     xsltStylesheetPtr ret = NULL;
 773 
 774     ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
 775     if (ret == NULL) {
 776     xsltTransformError(NULL, NULL, NULL,
 777         "xsltNewStylesheet : malloc failed\n");
 778     goto internal_err;
 779     }
 780     memset(ret, 0, sizeof(xsltStylesheet));
 781 
 782     ret->omitXmlDeclaration = -1;
 783     ret->standalone = -1;
 784     ret->decimalFormat = xsltNewDecimalFormat(NULL, NULL);
 785     ret->indent = -1;
 786     ret->errors = 0;
 787     ret->warnings = 0;
 788     ret->exclPrefixNr = 0;
 789     ret->exclPrefixMax = 0;
 790     ret->exclPrefixTab = NULL;
 791     ret->extInfos = NULL;
 792     ret->extrasNr = 0;
 793     ret->internalized = 1;
 794     ret->literal_result = 0;
 795     ret->forwards_compatible = 0;
 796     ret->dict = xmlDictCreate();
 797 #ifdef WITH_XSLT_DEBUG
 798     xsltGenericDebug(xsltGenericDebugContext,
 799     "creating dictionary for stylesheet\n");
 800 #endif
 801 
 802     xsltInit();
 803 
 804     return(ret);
 805 
 806 internal_err:
 807     if (ret != NULL)
 808     xsltFreeStylesheet(ret);
 809     return(NULL);
 810 }
 811 
 812 /**
 813  * xsltAllocateExtra:
 814  * @style:  an XSLT stylesheet
 815  *
 816  * Allocate an extra runtime information slot statically while compiling
 817  * the stylesheet and return its number
 818  *
 819  * Returns the number of the slot
 820  */
 821 int
 822 xsltAllocateExtra(xsltStylesheetPtr style)
 823 {
 824     return(style->extrasNr++);
 825 }
 826 
 827 /**
 828  * xsltAllocateExtraCtxt:
 829  * @ctxt:  an XSLT transformation context
 830  *
 831  * Allocate an extra runtime information slot at run-time
 832  * and return its number
 833  * This make sure there is a slot ready in the transformation context
 834  *
 835  * Returns the number of the slot
 836  */
 837 int
 838 xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
 839 {
 840     if (ctxt->extrasNr >= ctxt->extrasMax) {
 841     int i;
 842     if (ctxt->extrasNr == 0) {
 843         ctxt->extrasMax = 20;
 844         ctxt->extras = (xsltRuntimeExtraPtr)
 845         xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
 846         if (ctxt->extras == NULL) {
 847         xsltTransformError(ctxt, NULL, NULL,
 848             "xsltAllocateExtraCtxt: out of memory\n");
 849         return(0);
 850         }
 851         for (i = 0;i < ctxt->extrasMax;i++) {
 852         ctxt->extras[i].info = NULL;
 853         ctxt->extras[i].deallocate = NULL;
 854         ctxt->extras[i].val.ptr = NULL;
 855         }
 856 
 857     } else {
 858         xsltRuntimeExtraPtr tmp;
 859 
 860         ctxt->extrasMax += 100;
 861         tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
 862                     ctxt->extrasMax * sizeof(xsltRuntimeExtra));
 863         if (tmp == NULL) {
 864         xsltTransformError(ctxt, NULL, NULL,
 865             "xsltAllocateExtraCtxt: out of memory\n");
 866         return(0);
 867         }
 868         ctxt->extras = tmp;
 869         for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
 870         ctxt->extras[i].info = NULL;
 871         ctxt->extras[i].deallocate = NULL;
 872         ctxt->extras[i].val.ptr = NULL;
 873         }
 874     }
 875     }
 876     return(ctxt->extrasNr++);
 877 }
 878 
 879 /**
 880  * xsltFreeStylesheetList:
 881  * @style:  an XSLT stylesheet list
 882  *
 883  * Free up the memory allocated by the list @style
 884  */
 885 static void
 886 xsltFreeStylesheetList(xsltStylesheetPtr style) {
 887     xsltStylesheetPtr next;
 888 
 889     while (style != NULL) {
 890     next = style->next;
 891     xsltFreeStylesheet(style);
 892     style = next;
 893     }
 894 }
 895 
 896 /**
 897  * xsltCleanupStylesheetTree:
 898  *
 899  * @doc: the document-node
 900  * @node: the element where the stylesheet is rooted at
 901  *
 902  * Actually @node need not be the document-element, but
 903  * currently Libxslt does not support embedded stylesheets.
 904  *
 905  * Returns 0 if OK, -1 on API or internal errors.
 906  */
 907 static int
 908 xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED,
 909               xmlNodePtr rootElem ATTRIBUTE_UNUSED)
 910 {
 911 #if 0 /* TODO: Currently disabled, since probably not needed. */
 912     xmlNodePtr cur;
 913 
 914     if ((doc == NULL) || (rootElem == NULL) ||
 915     (rootElem->type != XML_ELEMENT_NODE) ||
 916     (doc != rootElem->doc))
 917     return(-1);
 918 
 919     /*
 920     * Cleanup was suggested by Aleksey Sanin:
 921     * Clear the PSVI field to avoid problems if the
 922     * node-tree of the stylesheet is intended to be used for
 923     * further processing by the user (e.g. for compiling it
 924     * once again - although not recommended).
 925     */
 926 
 927     cur = rootElem;
 928     while (cur != NULL) {
 929     if (cur->type == XML_ELEMENT_NODE) {
 930         /*
 931         * Clear the PSVI field.
 932         */
 933         cur->psvi = NULL;
 934         if (cur->children) {
 935         cur = cur->children;
 936         continue;
 937         }
 938     }
 939 
 940 leave_node:
 941     if (cur == rootElem)
 942         break;
 943     if (cur->next != NULL)
 944         cur = cur->next;
 945     else {
 946         cur = cur->parent;
 947         if (cur == NULL)
 948         break;
 949         goto leave_node;
 950     }
 951     }
 952 #endif /* #if 0 */
 953     return(0);
 954 }
 955 
 956 /**
 957  * xsltFreeStylesheet:
 958  * @style:  an XSLT stylesheet
 959  *
 960  * Free up the memory allocated by @style
 961  */
 962 void
 963 xsltFreeStylesheet(xsltStylesheetPtr style)
 964 {
 965     if (style == NULL)
 966         return;
 967 
 968 #ifdef XSLT_REFACTORED
 969     /*
 970     * Start with a cleanup of the main stylesheet's doc.
 971     */
 972     if ((style->principal == style) && (style->doc))
 973     xsltCleanupStylesheetTree(style->doc,
 974         xmlDocGetRootElement(style->doc));
 975 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
 976     /*
 977     * Restore changed ns-decls before freeing the document.
 978     */
 979     if ((style->doc != NULL) &&
 980     XSLT_HAS_INTERNAL_NSMAP(style))
 981     {
 982     xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
 983         style->doc);
 984     }
 985 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
 986 #else
 987     /*
 988     * Start with a cleanup of the main stylesheet's doc.
 989     */
 990     if ((style->parent == NULL) && (style->doc))
 991     xsltCleanupStylesheetTree(style->doc,
 992         xmlDocGetRootElement(style->doc));
 993 #endif /* XSLT_REFACTORED */
 994 
 995     xsltFreeKeys(style);
 996     xsltFreeExts(style);
 997     xsltFreeTemplateHashes(style);
 998     xsltFreeDecimalFormatList(style);
 999     xsltFreeTemplateList(style->templates);
1000     xsltFreeAttributeSetsHashes(style);
1001     xsltFreeNamespaceAliasHashes(style);
1002     xsltFreeStylePreComps(style);
1003     /*
1004     * Free documents of all included stylsheet modules of this
1005     * stylesheet level.
1006     */
1007     xsltFreeStyleDocuments(style);
1008     /*
1009     * TODO: Best time to shutdown extension stuff?
1010     */
1011     xsltShutdownExts(style);
1012 
1013     if (style->variables != NULL)
1014         xsltFreeStackElemList(style->variables);
1015     if (style->cdataSection != NULL)
1016         xmlHashFree(style->cdataSection, NULL);
1017     if (style->stripSpaces != NULL)
1018         xmlHashFree(style->stripSpaces, NULL);
1019     if (style->nsHash != NULL)
1020         xmlHashFree(style->nsHash, NULL);
1021     if (style->exclPrefixTab != NULL)
1022         xmlFree(style->exclPrefixTab);
1023     if (style->method != NULL)
1024         xmlFree(style->method);
1025     if (style->methodURI != NULL)
1026         xmlFree(style->methodURI);
1027     if (style->version != NULL)
1028         xmlFree(style->version);
1029     if (style->encoding != NULL)
1030         xmlFree(style->encoding);
1031     if (style->doctypePublic != NULL)
1032         xmlFree(style->doctypePublic);
1033     if (style->doctypeSystem != NULL)
1034         xmlFree(style->doctypeSystem);
1035     if (style->mediaType != NULL)
1036         xmlFree(style->mediaType);
1037     if (style->attVTs)
1038         xsltFreeAVTList(style->attVTs);
1039     if (style->imports != NULL)
1040         xsltFreeStylesheetList(style->imports);
1041 
1042 #ifdef XSLT_REFACTORED
1043     /*
1044     * If this is the principal stylesheet, then
1045     * free its internal data.
1046     */
1047     if (style->principal == style) {
1048     if (style->principalData) {
1049         xsltFreePrincipalStylesheetData(style->principalData);
1050         style->principalData = NULL;
1051     }
1052     }
1053 #endif
1054     /*
1055     * Better to free the main document of this stylesheet level
1056     * at the end - so here.
1057     */
1058     if (style->doc != NULL) {
1059         xmlFreeDoc(style->doc);
1060     }
1061 
1062 #ifdef WITH_XSLT_DEBUG
1063     xsltGenericDebug(xsltGenericDebugContext,
1064                      "freeing dictionary from stylesheet\n");
1065 #endif
1066     xmlDictFree(style->dict);
1067 
1068     memset(style, -1, sizeof(xsltStylesheet));
1069     xmlFree(style);
1070 }
1071 
1072 /************************************************************************
1073  *                                  *
1074  *      Parsing of an XSLT Stylesheet               *
1075  *                                  *
1076  ************************************************************************/
1077 
1078 #ifdef XSLT_REFACTORED
1079     /*
1080     * This is now performed in an optimized way in xsltParseXSLTTemplate.
1081     */
1082 #else
1083 /**
1084  * xsltGetInheritedNsList:
1085  * @style:  the stylesheet
1086  * @template: the template
1087  * @node:  the current node
1088  *
1089  * Search all the namespace applying to a given element except the ones
1090  * from excluded output prefixes currently in scope. Initialize the
1091  * template inheritedNs list with it.
1092  *
1093  * Returns the number of entries found
1094  */
1095 static int
1096 xsltGetInheritedNsList(xsltStylesheetPtr style,
1097                    xsltTemplatePtr template,
1098                    xmlNodePtr node)
1099 {
1100     xmlNsPtr cur;
1101     xmlNsPtr *ret = NULL;
1102     int nbns = 0;
1103     int maxns = 10;
1104     int i;
1105 
1106     if ((style == NULL) || (template == NULL) || (node == NULL) ||
1107     (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
1108     return(0);
1109     while (node != NULL) {
1110         if (node->type == XML_ELEMENT_NODE) {
1111             cur = node->nsDef;
1112             while (cur != NULL) {
1113         if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
1114             goto skip_ns;
1115 
1116         if ((cur->prefix != NULL) &&
1117             (xsltCheckExtPrefix(style, cur->prefix)))
1118             goto skip_ns;
1119         /*
1120         * Check if this namespace was excluded.
1121         * Note that at this point only the exclusions defined
1122         * on the topmost stylesheet element are in the exclusion-list.
1123         */
1124         for (i = 0;i < style->exclPrefixNr;i++) {
1125             if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
1126             goto skip_ns;
1127         }
1128                 if (ret == NULL) {
1129                     ret =
1130                         (xmlNsPtr *) xmlMalloc((maxns + 1) *
1131                                                sizeof(xmlNsPtr));
1132                     if (ret == NULL) {
1133                         xmlGenericError(xmlGenericErrorContext,
1134                                         "xsltGetInheritedNsList : out of memory!\n");
1135                         return(0);
1136                     }
1137                     ret[nbns] = NULL;
1138                 }
1139         /*
1140         * Skip shadowed namespace bindings.
1141         */
1142                 for (i = 0; i < nbns; i++) {
1143                     if ((cur->prefix == ret[i]->prefix) ||
1144                         (xmlStrEqual(cur->prefix, ret[i]->prefix)))
1145                         break;
1146                 }
1147                 if (i >= nbns) {
1148                     if (nbns >= maxns) {
1149                         maxns *= 2;
1150                         ret = (xmlNsPtr *) xmlRealloc(ret,
1151                                                       (maxns +
1152                                                        1) *
1153                                                       sizeof(xmlNsPtr));
1154                         if (ret == NULL) {
1155                             xmlGenericError(xmlGenericErrorContext,
1156                                             "xsltGetInheritedNsList : realloc failed!\n");
1157                             return(0);
1158                         }
1159                     }
1160                     ret[nbns++] = cur;
1161                     ret[nbns] = NULL;
1162                 }
1163 skip_ns:
1164                 cur = cur->next;
1165             }
1166         }
1167         node = node->parent;
1168     }
1169     if (nbns != 0) {
1170 #ifdef WITH_XSLT_DEBUG_PARSING
1171         xsltGenericDebug(xsltGenericDebugContext,
1172                          "template has %d inherited namespaces\n", nbns);
1173 #endif
1174     template->inheritedNsNr = nbns;
1175     template->inheritedNs = ret;
1176     }
1177     return (nbns);
1178 }
1179 #endif /* else of XSLT_REFACTORED */
1180 
1181 /**
1182  * xsltParseStylesheetOutput:
1183  * @style:  the XSLT stylesheet
1184  * @cur:  the "output" element
1185  *
1186  * parse an XSLT stylesheet output element and record
1187  * information related to the stylesheet output
1188  */
1189 
1190 void
1191 xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
1192 {
1193     xmlChar *elements,
1194      *prop;
1195     xmlChar *element,
1196      *end;
1197 
1198     if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1199         return;
1200 
1201     prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
1202     if (prop != NULL) {
1203         if (style->version != NULL)
1204             xmlFree(style->version);
1205         style->version = prop;
1206     }
1207 
1208     prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
1209     if (prop != NULL) {
1210         if (style->encoding != NULL)
1211             xmlFree(style->encoding);
1212         style->encoding = prop;
1213     }
1214 
1215     /* relaxed to support xt:document
1216     * TODO KB: What does "relaxed to support xt:document" mean?
1217     */
1218     prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL);
1219     if (prop != NULL) {
1220         const xmlChar *URI;
1221 
1222         if (style->method != NULL)
1223             xmlFree(style->method);
1224         style->method = NULL;
1225         if (style->methodURI != NULL)
1226             xmlFree(style->methodURI);
1227         style->methodURI = NULL;
1228 
1229     /*
1230     * TODO: Don't use xsltGetQNameURI().
1231     */
1232     URI = xsltGetQNameURI(cur, &prop);
1233     if (prop == NULL) {
1234         if (style != NULL) style->errors++;
1235     } else if (URI == NULL) {
1236             if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
1237                 (xmlStrEqual(prop, (const xmlChar *) "html")) ||
1238                 (xmlStrEqual(prop, (const xmlChar *) "text"))) {
1239                 style->method = prop;
1240             } else {
1241         xsltTransformError(NULL, style, cur,
1242                                  "invalid value for method: %s\n", prop);
1243                 if (style != NULL) style->warnings++;
1244                 xmlFree(prop);
1245             }
1246     } else {
1247         style->method = prop;
1248         style->methodURI = xmlStrdup(URI);
1249     }
1250     }
1251 
1252     prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
1253     if (prop != NULL) {
1254         if (style->doctypeSystem != NULL)
1255             xmlFree(style->doctypeSystem);
1256         style->doctypeSystem = prop;
1257     }
1258 
1259     prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
1260     if (prop != NULL) {
1261         if (style->doctypePublic != NULL)
1262             xmlFree(style->doctypePublic);
1263         style->doctypePublic = prop;
1264     }
1265 
1266     prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL);
1267     if (prop != NULL) {
1268         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1269             style->standalone = 1;
1270         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1271             style->standalone = 0;
1272         } else {
1273         xsltTransformError(NULL, style, cur,
1274                              "invalid value for standalone: %s\n", prop);
1275             style->errors++;
1276         }
1277         xmlFree(prop);
1278     }
1279 
1280     prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL);
1281     if (prop != NULL) {
1282         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1283             style->indent = 1;
1284         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1285             style->indent = 0;
1286         } else {
1287         xsltTransformError(NULL, style, cur,
1288                              "invalid value for indent: %s\n", prop);
1289             style->errors++;
1290         }
1291         xmlFree(prop);
1292     }
1293 
1294     prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL);
1295     if (prop != NULL) {
1296         if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
1297             style->omitXmlDeclaration = 1;
1298         } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
1299             style->omitXmlDeclaration = 0;
1300         } else {
1301         xsltTransformError(NULL, style, cur,
1302                              "invalid value for omit-xml-declaration: %s\n",
1303                              prop);
1304             style->errors++;
1305         }
1306         xmlFree(prop);
1307     }
1308 
1309     elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
1310     NULL);
1311     if (elements != NULL) {
1312         if (style->cdataSection == NULL)
1313             style->cdataSection = xmlHashCreate(10);
1314         if (style->cdataSection == NULL)
1315             return;
1316 
1317         element = elements;
1318         while (*element != 0) {
1319             while (IS_BLANK(*element))
1320                 element++;
1321             if (*element == 0)
1322                 break;
1323             end = element;
1324             while ((*end != 0) && (!IS_BLANK(*end)))
1325                 end++;
1326             element = xmlStrndup(element, end - element);
1327             if (element) {
1328 #ifdef WITH_XSLT_DEBUG_PARSING
1329                 xsltGenericDebug(xsltGenericDebugContext,
1330                                  "add cdata section output element %s\n",
1331                                  element);
1332 #endif
1333         if (xmlValidateQName(BAD_CAST element, 0) != 0) {
1334             xsltTransformError(NULL, style, cur,
1335             "Attribute 'cdata-section-elements': The value "
1336             "'%s' is not a valid QName.\n", element);
1337             xmlFree(element);
1338             style->errors++;
1339         } else {
1340             const xmlChar *URI;
1341 
1342             /*
1343             * TODO: Don't use xsltGetQNameURI().
1344             */
1345             URI = xsltGetQNameURI(cur, &element);
1346             if (element == NULL) {
1347             /*
1348             * TODO: We'll report additionally an error
1349             *  via the stylesheet's error handling.
1350             */
1351             xsltTransformError(NULL, style, cur,
1352                 "Attribute 'cdata-section-elements': The value "
1353                 "'%s' is not a valid QName.\n", element);
1354             style->errors++;
1355             } else {
1356             xmlNsPtr ns;
1357 
1358             /*
1359             * XSLT-1.0 "Each QName is expanded into an
1360             *  expanded-name using the namespace declarations in
1361             *  effect on the xsl:output element in which the QName
1362             *  occurs; if there is a default namespace, it is used
1363             *  for QNames that do not have a prefix"
1364             * NOTE: Fix of bug #339570.
1365             */
1366             if (URI == NULL) {
1367                 ns = xmlSearchNs(style->doc, cur, NULL);
1368                 if (ns != NULL)
1369                 URI = ns->href;
1370             }
1371             xmlHashAddEntry2(style->cdataSection, element, URI,
1372                 (void *) "cdata");
1373             xmlFree(element);
1374             }
1375         }
1376             }
1377             element = end;
1378         }
1379         xmlFree(elements);
1380     }
1381 
1382     prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
1383     if (prop != NULL) {
1384     if (style->mediaType)
1385         xmlFree(style->mediaType);
1386     style->mediaType = prop;
1387     }
1388     if (cur->children != NULL) {
1389     xsltParseContentError(style, cur->children);
1390     }
1391 }
1392 
1393 /**
1394  * xsltParseStylesheetDecimalFormat:
1395  * @style:  the XSLT stylesheet
1396  * @cur:  the "decimal-format" element
1397  *
1398  * <!-- Category: top-level-element -->
1399  * <xsl:decimal-format
1400  *   name = qname, decimal-separator = char, grouping-separator = char,
1401  *   infinity = string, minus-sign = char, NaN = string, percent = char
1402  *   per-mille = char, zero-digit = char, digit = char,
1403  * pattern-separator = char />
1404  *
1405  * parse an XSLT stylesheet decimal-format element and
1406  * and record the formatting characteristics
1407  */
1408 static void
1409 xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
1410 {
1411     xmlChar *prop;
1412     xsltDecimalFormatPtr format;
1413     xsltDecimalFormatPtr iter;
1414 
1415     if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1416     return;
1417 
1418     format = style->decimalFormat;
1419 
1420     prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
1421     if (prop != NULL) {
1422         const xmlChar *nsUri;
1423 
1424         if (xmlValidateQName(prop, 0) != 0) {
1425             xsltTransformError(NULL, style, cur,
1426                 "xsl:decimal-format: Invalid QName '%s'.\n", prop);
1427         style->warnings++;
1428             xmlFree(prop);
1429             return;
1430         }
1431         /*
1432         * TODO: Don't use xsltGetQNameURI().
1433         */
1434         nsUri = xsltGetQNameURI(cur, &prop);
1435         if (prop == NULL) {
1436         style->warnings++;
1437             return;
1438         }
1439     format = xsltDecimalFormatGetByQName(style, nsUri, prop);
1440     if (format != NULL) {
1441         xsltTransformError(NULL, style, cur,
1442      "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
1443         style->warnings++;
1444             xmlFree(prop);
1445         return;
1446     }
1447     format = xsltNewDecimalFormat(nsUri, prop);
1448     if (format == NULL) {
1449         xsltTransformError(NULL, style, cur,
1450      "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
1451         style->errors++;
1452             xmlFree(prop);
1453         return;
1454     }
1455     /* Append new decimal-format structure */
1456     for (iter = style->decimalFormat; iter->next; iter = iter->next)
1457         ;
1458     if (iter)
1459         iter->next = format;
1460     }
1461 
1462     prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
1463     if (prop != NULL) {
1464     if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
1465     format->decimalPoint  = prop;
1466     }
1467 
1468     prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
1469     if (prop != NULL) {
1470     if (format->grouping != NULL) xmlFree(format->grouping);
1471     format->grouping  = prop;
1472     }
1473 
1474     prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
1475     if (prop != NULL) {
1476     if (format->infinity != NULL) xmlFree(format->infinity);
1477     format->infinity  = prop;
1478     }
1479 
1480     prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
1481     if (prop != NULL) {
1482     if (format->minusSign != NULL) xmlFree(format->minusSign);
1483     format->minusSign  = prop;
1484     }
1485 
1486     prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
1487     if (prop != NULL) {
1488     if (format->noNumber != NULL) xmlFree(format->noNumber);
1489     format->noNumber  = prop;
1490     }
1491 
1492     prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
1493     if (prop != NULL) {
1494     if (format->percent != NULL) xmlFree(format->percent);
1495     format->percent  = prop;
1496     }
1497 
1498     prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
1499     if (prop != NULL) {
1500     if (format->permille != NULL) xmlFree(format->permille);
1501     format->permille  = prop;
1502     }
1503 
1504     prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
1505     if (prop != NULL) {
1506     if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
1507     format->zeroDigit  = prop;
1508     }
1509 
1510     prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
1511     if (prop != NULL) {
1512     if (format->digit != NULL) xmlFree(format->digit);
1513     format->digit  = prop;
1514     }
1515 
1516     prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
1517     if (prop != NULL) {
1518     if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
1519     format->patternSeparator  = prop;
1520     }
1521     if (cur->children != NULL) {
1522     xsltParseContentError(style, cur->children);
1523     }
1524 }
1525 
1526 /**
1527  * xsltParseStylesheetPreserveSpace:
1528  * @style:  the XSLT stylesheet
1529  * @cur:  the "preserve-space" element
1530  *
1531  * parse an XSLT stylesheet preserve-space element and record
1532  * elements needing preserving
1533  */
1534 
1535 static void
1536 xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1537     xmlChar *elements;
1538     xmlChar *element, *end;
1539 
1540     if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1541     return;
1542 
1543     elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1544     if (elements == NULL) {
1545     xsltTransformError(NULL, style, cur,
1546         "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
1547     if (style != NULL) style->warnings++;
1548     return;
1549     }
1550 
1551     if (style->stripSpaces == NULL)
1552     style->stripSpaces = xmlHashCreate(10);
1553     if (style->stripSpaces == NULL)
1554     return;
1555 
1556     element = elements;
1557     while (*element != 0) {
1558     while (IS_BLANK(*element)) element++;
1559     if (*element == 0)
1560         break;
1561         end = element;
1562     while ((*end != 0) && (!IS_BLANK(*end))) end++;
1563     element = xmlStrndup(element, end - element);
1564     if (element) {
1565 #ifdef WITH_XSLT_DEBUG_PARSING
1566         xsltGenericDebug(xsltGenericDebugContext,
1567         "add preserved space element %s\n", element);
1568 #endif
1569         if (xmlStrEqual(element, (const xmlChar *)"*")) {
1570         style->stripAll = -1;
1571         } else {
1572         const xmlChar *URI;
1573 
1574         /*
1575         * TODO: Don't use xsltGetQNameURI().
1576         */
1577                 URI = xsltGetQNameURI(cur, &element);
1578 
1579         xmlHashAddEntry2(style->stripSpaces, element, URI,
1580                 (xmlChar *) "preserve");
1581         }
1582         xmlFree(element);
1583     }
1584     element = end;
1585     }
1586     xmlFree(elements);
1587     if (cur->children != NULL) {
1588     xsltParseContentError(style, cur->children);
1589     }
1590 }
1591 
1592 #ifdef XSLT_REFACTORED
1593 #else
1594 /**
1595  * xsltParseStylesheetExtPrefix:
1596  * @style:  the XSLT stylesheet
1597  * @template:  the "extension-element-prefixes" prefix
1598  *
1599  * parse an XSLT stylesheet's "extension-element-prefix" attribute value
1600  * and register the namespaces of extension instruction.
1601  * SPEC "A namespace is designated as an extension namespace by using
1602  *   an extension-element-prefixes attribute on:
1603  *   1) an xsl:stylesheet element
1604  *   2) an xsl:extension-element-prefixes attribute on a
1605  *      literal result element
1606  *   3) an extension instruction."
1607  */
1608 static void
1609 xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,
1610                  int isXsltElem) {
1611     xmlChar *prefixes;
1612     xmlChar *prefix, *end;
1613 
1614     if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1615     return;
1616 
1617     if (isXsltElem) {
1618     /* For xsl:stylesheet/xsl:transform. */
1619     prefixes = xmlGetNsProp(cur,
1620         (const xmlChar *)"extension-element-prefixes", NULL);
1621     } else {
1622     /* For literal result elements and extension instructions. */
1623     prefixes = xmlGetNsProp(cur,
1624         (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
1625     }
1626     if (prefixes == NULL) {
1627     return;
1628     }
1629 
1630     prefix = prefixes;
1631     while (*prefix != 0) {
1632     while (IS_BLANK(*prefix)) prefix++;
1633     if (*prefix == 0)
1634         break;
1635         end = prefix;
1636     while ((*end != 0) && (!IS_BLANK(*end))) end++;
1637     prefix = xmlStrndup(prefix, end - prefix);
1638     if (prefix) {
1639         xmlNsPtr ns;
1640 
1641         if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1642         ns = xmlSearchNs(style->doc, cur, NULL);
1643         else
1644         ns = xmlSearchNs(style->doc, cur, prefix);
1645         if (ns == NULL) {
1646         xsltTransformError(NULL, style, cur,
1647         "xsl:extension-element-prefix : undefined namespace %s\n",
1648                              prefix);
1649         if (style != NULL) style->warnings++;
1650         } else {
1651 #ifdef WITH_XSLT_DEBUG_PARSING
1652         xsltGenericDebug(xsltGenericDebugContext,
1653             "add extension prefix %s\n", prefix);
1654 #endif
1655         xsltRegisterExtPrefix(style, prefix, ns->href);
1656         }
1657         xmlFree(prefix);
1658     }
1659     prefix = end;
1660     }
1661     xmlFree(prefixes);
1662 }
1663 #endif /* else of XSLT_REFACTORED */
1664 
1665 /**
1666  * xsltParseStylesheetStripSpace:
1667  * @style:  the XSLT stylesheet
1668  * @cur:  the "strip-space" element
1669  *
1670  * parse an XSLT stylesheet's strip-space element and record
1671  * the elements needing stripping
1672  */
1673 
1674 static void
1675 xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
1676     xmlChar *elements;
1677     xmlChar *element, *end;
1678 
1679     if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1680     return;
1681 
1682     elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
1683     if (elements == NULL) {
1684     xsltTransformError(NULL, style, cur,
1685         "xsltParseStylesheetStripSpace: missing elements attribute\n");
1686     if (style != NULL) style->warnings++;
1687     return;
1688     }
1689 
1690     if (style->stripSpaces == NULL)
1691     style->stripSpaces = xmlHashCreate(10);
1692     if (style->stripSpaces == NULL)
1693     return;
1694 
1695     element = elements;
1696     while (*element != 0) {
1697     while (IS_BLANK(*element)) element++;
1698     if (*element == 0)
1699         break;
1700         end = element;
1701     while ((*end != 0) && (!IS_BLANK(*end))) end++;
1702     element = xmlStrndup(element, end - element);
1703     if (element) {
1704 #ifdef WITH_XSLT_DEBUG_PARSING
1705         xsltGenericDebug(xsltGenericDebugContext,
1706         "add stripped space element %s\n", element);
1707 #endif
1708         if (xmlStrEqual(element, (const xmlChar *)"*")) {
1709         style->stripAll = 1;
1710         } else {
1711         const xmlChar *URI;
1712 
1713         /*
1714         * TODO: Don't use xsltGetQNameURI().
1715         */
1716                 URI = xsltGetQNameURI(cur, &element);
1717 
1718         xmlHashAddEntry2(style->stripSpaces, element, URI,
1719                     (xmlChar *) "strip");
1720         }
1721         xmlFree(element);
1722     }
1723     element = end;
1724     }
1725     xmlFree(elements);
1726     if (cur->children != NULL) {
1727     xsltParseContentError(style, cur->children);
1728     }
1729 }
1730 
1731 #ifdef XSLT_REFACTORED
1732 #else
1733 /**
1734  * xsltParseStylesheetExcludePrefix:
1735  * @style:  the XSLT stylesheet
1736  * @cur:  the current point in the stylesheet
1737  *
1738  * parse an XSLT stylesheet exclude prefix and record
1739  * namespaces needing stripping
1740  *
1741  * Returns the number of Excluded prefixes added at that level
1742  */
1743 
1744 static int
1745 xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur,
1746                  int isXsltElem)
1747 {
1748     int nb = 0;
1749     xmlChar *prefixes;
1750     xmlChar *prefix, *end;
1751 
1752     if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
1753     return(0);
1754 
1755     if (isXsltElem)
1756     prefixes = xmlGetNsProp(cur,
1757         (const xmlChar *)"exclude-result-prefixes", NULL);
1758     else
1759     prefixes = xmlGetNsProp(cur,
1760         (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);
1761 
1762     if (prefixes == NULL) {
1763     return(0);
1764     }
1765 
1766     prefix = prefixes;
1767     while (*prefix != 0) {
1768     while (IS_BLANK(*prefix)) prefix++;
1769     if (*prefix == 0)
1770         break;
1771         end = prefix;
1772     while ((*end != 0) && (!IS_BLANK(*end))) end++;
1773     prefix = xmlStrndup(prefix, end - prefix);
1774     if (prefix) {
1775         xmlNsPtr ns;
1776 
1777         if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
1778         ns = xmlSearchNs(style->doc, cur, NULL);
1779         else
1780         ns = xmlSearchNs(style->doc, cur, prefix);
1781         if (ns == NULL) {
1782         xsltTransformError(NULL, style, cur,
1783         "xsl:exclude-result-prefixes : undefined namespace %s\n",
1784                              prefix);
1785         if (style != NULL) style->warnings++;
1786         } else {
1787         if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) {
1788 #ifdef WITH_XSLT_DEBUG_PARSING
1789             xsltGenericDebug(xsltGenericDebugContext,
1790             "exclude result prefix %s\n", prefix);
1791 #endif
1792             nb++;
1793         }
1794         }
1795         xmlFree(prefix);
1796     }
1797     prefix = end;
1798     }
1799     xmlFree(prefixes);
1800     return(nb);
1801 }
1802 #endif /* else of XSLT_REFACTORED */
1803 
1804 #ifdef XSLT_REFACTORED
1805 
1806 /*
1807 * xsltTreeEnsureXMLDecl:
1808 * @doc: the doc
1809 *
1810 * BIG NOTE:
1811 *  This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
1812 * Ensures that there is an XML namespace declaration on the doc.
1813 *
1814 * Returns the XML ns-struct or NULL on API and internal errors.
1815 */
1816 static xmlNsPtr
1817 xsltTreeEnsureXMLDecl(xmlDocPtr doc)
1818 {
1819     if (doc == NULL)
1820     return (NULL);
1821     if (doc->oldNs != NULL)
1822     return (doc->oldNs);
1823     {
1824     xmlNsPtr ns;
1825     ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1826     if (ns == NULL) {
1827         xmlGenericError(xmlGenericErrorContext,
1828         "xsltTreeEnsureXMLDecl: Failed to allocate "
1829         "the XML namespace.\n");
1830         return (NULL);
1831     }
1832     memset(ns, 0, sizeof(xmlNs));
1833     ns->type = XML_LOCAL_NAMESPACE;
1834     /*
1835     * URGENT TODO: revisit this.
1836     */
1837 #ifdef LIBXML_NAMESPACE_DICT
1838     if (doc->dict)
1839         ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
1840     else
1841         ns->href = xmlStrdup(XML_XML_NAMESPACE);
1842 #else
1843     ns->href = xmlStrdup(XML_XML_NAMESPACE);
1844 #endif
1845     ns->prefix = xmlStrdup((const xmlChar *)"xml");
1846     doc->oldNs = ns;
1847     return (ns);
1848     }
1849 }
1850 
1851 /*
1852 * xsltTreeAcquireStoredNs:
1853 * @doc: the doc
1854 * @nsName: the namespace name
1855 * @prefix: the prefix
1856 *
1857 * BIG NOTE:
1858 *  This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
1859 * Creates or reuses an xmlNs struct on doc->oldNs with
1860 * the given prefix and namespace name.
1861 *
1862 * Returns the aquired ns struct or NULL in case of an API
1863 *         or internal error.
1864 */
1865 static xmlNsPtr
1866 xsltTreeAcquireStoredNs(xmlDocPtr doc,
1867             const xmlChar *nsName,
1868             const xmlChar *prefix)
1869 {
1870     xmlNsPtr ns;
1871 
1872     if (doc == NULL)
1873     return (NULL);
1874     if (doc->oldNs != NULL)
1875     ns = doc->oldNs;
1876     else
1877     ns = xsltTreeEnsureXMLDecl(doc);
1878     if (ns == NULL)
1879     return (NULL);
1880     if (ns->next != NULL) {
1881     /* Reuse. */
1882     ns = ns->next;
1883     while (ns != NULL) {
1884         if ((ns->prefix == NULL) != (prefix == NULL)) {
1885         /* NOP */
1886         } else if (prefix == NULL) {
1887         if (xmlStrEqual(ns->href, nsName))
1888             return (ns);
1889         } else {
1890         if ((ns->prefix[0] == prefix[0]) &&
1891              xmlStrEqual(ns->prefix, prefix) &&
1892              xmlStrEqual(ns->href, nsName))
1893             return (ns);
1894 
1895         }
1896         if (ns->next == NULL)
1897         break;
1898         ns = ns->next;
1899     }
1900     }
1901     /* Create. */
1902     ns->next = xmlNewNs(NULL, nsName, prefix);
1903     return (ns->next);
1904 }
1905 
1906 /**
1907  * xsltLREBuildEffectiveNs:
1908  *
1909  * Apply ns-aliasing on the namespace of the given @elem and
1910  * its attributes.
1911  */
1912 static int
1913 xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
1914             xmlNodePtr elem)
1915 {
1916     xmlNsPtr ns;
1917     xsltNsAliasPtr alias;
1918 
1919     if ((cctxt == NULL) || (elem == NULL))
1920     return(-1);
1921     if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
1922     return(0);
1923 
1924     alias = cctxt->nsAliases;
1925     while (alias != NULL) {
1926     if ( /* If both namespaces are NULL... */
1927         ( (elem->ns == NULL) &&
1928         ((alias->literalNs == NULL) ||
1929         (alias->literalNs->href == NULL)) ) ||
1930         /* ... or both namespace are equal */
1931         ( (elem->ns != NULL) &&
1932         (alias->literalNs != NULL) &&
1933         xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
1934     {
1935         if ((alias->targetNs != NULL) &&
1936         (alias->targetNs->href != NULL))
1937         {
1938         /*
1939         * Convert namespace.
1940         */
1941         if (elem->doc == alias->docOfTargetNs) {
1942             /*
1943             * This is the nice case: same docs.
1944             * This will eventually assign a ns-decl which
1945             * is shadowed, but this has no negative effect on
1946             * the generation of the result tree.
1947             */
1948             elem->ns = alias->targetNs;
1949         } else {
1950             /*
1951             * This target xmlNs originates from a different
1952             * stylesheet tree. Try to locate it in the
1953             * in-scope namespaces.
1954             * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
1955             */
1956             ns = xmlSearchNs(elem->doc, elem,
1957             alias->targetNs->prefix);
1958             /*
1959             * If no matching ns-decl found, then assign a
1960             * ns-decl stored in xmlDoc.
1961             */
1962             if ((ns == NULL) ||
1963             (! xmlStrEqual(ns->href, alias->targetNs->href)))
1964             {
1965             /*
1966             * BIG NOTE: The use of xsltTreeAcquireStoredNs()
1967             *  is not very efficient, but currently I don't
1968             *  see an other way of *safely* changing a node's
1969             *  namespace, since the xmlNs struct in
1970             *  alias->targetNs might come from an other
1971             *  stylesheet tree. So we need to anchor it in the
1972             *  current document, without adding it to the tree,
1973             *  which would otherwise change the in-scope-ns
1974             *  semantic of the tree.
1975             */
1976             ns = xsltTreeAcquireStoredNs(elem->doc,
1977                 alias->targetNs->href,
1978                 alias->targetNs->prefix);
1979 
1980             if (ns == NULL) {
1981                 xsltTransformError(NULL, cctxt->style, elem,
1982                 "Internal error in "
1983                 "xsltLREBuildEffectiveNs(): "
1984                 "failed to acquire a stored "
1985                 "ns-declaration.\n");
1986                 cctxt->style->errors++;
1987                 return(-1);
1988 
1989             }
1990             }
1991             elem->ns = ns;
1992         }
1993         } else {
1994         /*
1995         * Move into or leave in the NULL namespace.
1996         */
1997         elem->ns = NULL;
1998         }
1999         break;
2000     }
2001     alias = alias->next;
2002     }
2003     /*
2004     * Same with attributes of literal result elements.
2005     */
2006     if (elem->properties != NULL) {
2007     xmlAttrPtr attr = elem->properties;
2008 
2009     while (attr != NULL) {
2010         if (attr->ns == NULL) {
2011         attr = attr->next;
2012         continue;
2013         }
2014         alias = cctxt->nsAliases;
2015         while (alias != NULL) {
2016         if ( /* If both namespaces are NULL... */
2017             ( (elem->ns == NULL) &&
2018             ((alias->literalNs == NULL) ||
2019             (alias->literalNs->href == NULL)) ) ||
2020             /* ... or both namespace are equal */
2021             ( (elem->ns != NULL) &&
2022             (alias->literalNs != NULL) &&
2023             xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
2024         {
2025             if ((alias->targetNs != NULL) &&
2026             (alias->targetNs->href != NULL))
2027             {
2028             if (elem->doc == alias->docOfTargetNs) {
2029                 elem->ns = alias->targetNs;
2030             } else {
2031                 ns = xmlSearchNs(elem->doc, elem,
2032                 alias->targetNs->prefix);
2033                 if ((ns == NULL) ||
2034                 (! xmlStrEqual(ns->href, alias->targetNs->href)))
2035                 {
2036                 ns = xsltTreeAcquireStoredNs(elem->doc,
2037                     alias->targetNs->href,
2038                     alias->targetNs->prefix);
2039 
2040                 if (ns == NULL) {
2041                     xsltTransformError(NULL, cctxt->style, elem,
2042                     "Internal error in "
2043                     "xsltLREBuildEffectiveNs(): "
2044                     "failed to acquire a stored "
2045                     "ns-declaration.\n");
2046                     cctxt->style->errors++;
2047                     return(-1);
2048 
2049                 }
2050                 }
2051                 elem->ns = ns;
2052             }
2053             } else {
2054             /*
2055             * Move into or leave in the NULL namespace.
2056             */
2057             elem->ns = NULL;
2058             }
2059             break;
2060         }
2061         alias = alias->next;
2062         }
2063 
2064         attr = attr->next;
2065     }
2066     }
2067     return(0);
2068 }
2069 
2070 /**
2071  * xsltLREBuildEffectiveNsNodes:
2072  *
2073  * Computes the effective namespaces nodes for a literal result
2074  * element.
2075  * @effectiveNs is the set of effective ns-nodes
2076  *  on the literal result element, which will be added to the result
2077  *  element if not already existing in the result tree.
2078  *  This means that excluded namespaces (via exclude-result-prefixes,
2079  *  extension-element-prefixes and the XSLT namespace) not added
2080  *  to the set.
2081  *  Namespace-aliasing was applied on the @effectiveNs.
2082  */
2083 static int
2084 xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
2085                  xsltStyleItemLRElementInfoPtr item,
2086                  xmlNodePtr elem,
2087                  int isLRE)
2088 {
2089     xmlNsPtr ns, tmpns;
2090     xsltEffectiveNsPtr effNs, lastEffNs = NULL;
2091     int i, j, holdByElem;
2092     xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
2093     xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
2094 
2095     if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
2096     (item == NULL) || (item->effectiveNs != NULL))
2097     return(-1);
2098 
2099     if (item->inScopeNs == NULL)
2100     return(0);
2101 
2102     extElemNs = cctxt->inode->extElemNs;
2103     exclResultNs = cctxt->inode->exclResultNs;
2104 
2105     for (i = 0; i < item->inScopeNs->totalNumber; i++) {
2106     ns = item->inScopeNs->list[i];
2107     /*
2108     * Skip namespaces designated as excluded namespaces
2109     * -------------------------------------------------
2110     *
2111     * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
2112     *  which are target namespaces of namespace-aliases
2113     *  regardless if designated as excluded.
2114     *
2115     * Exclude the XSLT namespace.
2116     */
2117     if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
2118         goto skip_ns;
2119 
2120     /*
2121     * Apply namespace aliasing
2122     * ------------------------
2123     *
2124     * SPEC XSLT 2.0
2125     *  "- A namespace node whose string value is a literal namespace
2126     *     URI is not copied to the result tree.
2127     *   - A namespace node whose string value is a target namespace URI
2128     *     is copied to the result tree, whether or not the URI
2129     *     identifies an excluded namespace."
2130     *
2131     * NOTE: The ns-aliasing machanism is non-cascading.
2132     *  (checked with Saxon, Xalan and MSXML .NET).
2133     * URGENT TODO: is style->nsAliases the effective list of
2134     *  ns-aliases, or do we need to lookup the whole
2135     *  import-tree?
2136     * TODO: Get rid of import-tree lookup.
2137     */
2138     if (cctxt->hasNsAliases) {
2139         xsltNsAliasPtr alias;
2140         /*
2141         * First check for being a target namespace.
2142         */
2143         alias = cctxt->nsAliases;
2144         do {
2145         /*
2146         * TODO: Is xmlns="" handled already?
2147         */
2148         if ((alias->targetNs != NULL) &&
2149             (xmlStrEqual(alias->targetNs->href, ns->href)))
2150         {
2151             /*
2152             * Recognized as a target namespace; use it regardless
2153             * if excluded otherwise.
2154             */
2155             goto add_effective_ns;
2156         }
2157         alias = alias->next;
2158         } while (alias != NULL);
2159 
2160         alias = cctxt->nsAliases;
2161         do {
2162         /*
2163         * TODO: Is xmlns="" handled already?
2164         */
2165         if ((alias->literalNs != NULL) &&
2166             (xmlStrEqual(alias->literalNs->href, ns->href)))
2167         {
2168             /*
2169             * Recognized as an namespace alias; do not use it.
2170             */
2171             goto skip_ns;
2172         }
2173         alias = alias->next;
2174         } while (alias != NULL);
2175     }
2176 
2177     /*
2178     * Exclude excluded result namespaces.
2179     */
2180     if (exclResultNs) {
2181         for (j = 0; j < exclResultNs->number; j++)
2182         if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
2183             goto skip_ns;
2184     }
2185     /*
2186     * Exclude extension-element namespaces.
2187     */
2188     if (extElemNs) {
2189         for (j = 0; j < extElemNs->number; j++)
2190         if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
2191             goto skip_ns;
2192     }
2193 
2194 add_effective_ns:
2195     /*
2196     * OPTIMIZE TODO: This information may not be needed.
2197     */
2198     if (isLRE && (elem->nsDef != NULL)) {
2199         holdByElem = 0;
2200         tmpns = elem->nsDef;
2201         do {
2202         if (tmpns == ns) {
2203             holdByElem = 1;
2204             break;
2205         }
2206         tmpns = tmpns->next;
2207         } while (tmpns != NULL);
2208     } else
2209         holdByElem = 0;
2210 
2211 
2212     /*
2213     * Add the effective namespace declaration.
2214     */
2215     effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
2216     if (effNs == NULL) {
2217         xsltTransformError(NULL, cctxt->style, elem,
2218         "Internal error in xsltLREBuildEffectiveNs(): "
2219         "failed to allocate memory.\n");
2220         cctxt->style->errors++;
2221         return(-1);
2222     }
2223     if (cctxt->psData->effectiveNs == NULL) {
2224         cctxt->psData->effectiveNs = effNs;
2225         effNs->nextInStore = NULL;
2226     } else {
2227         effNs->nextInStore = cctxt->psData->effectiveNs;
2228         cctxt->psData->effectiveNs = effNs;
2229     }
2230 
2231     effNs->next = NULL;
2232     effNs->prefix = ns->prefix;
2233     effNs->nsName = ns->href;
2234     effNs->holdByElem = holdByElem;
2235 
2236     if (lastEffNs == NULL)
2237         item->effectiveNs = effNs;
2238     else
2239         lastEffNs->next = effNs;
2240     lastEffNs = effNs;
2241 
2242 skip_ns:
2243     {}
2244     }
2245     return(0);
2246 }
2247 
2248 
2249 /**
2250  * xsltLREInfoCreate:
2251  *
2252  * @isLRE: indicates if the given @elem is a literal result element
2253  *
2254  * Creates a new info for a literal result element.
2255  */
2256 static int
2257 xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
2258           xmlNodePtr elem,
2259           int isLRE)
2260 {
2261     xsltStyleItemLRElementInfoPtr item;
2262 
2263     if ((cctxt == NULL) || (cctxt->inode == NULL))
2264     return(-1);
2265 
2266     item = (xsltStyleItemLRElementInfoPtr)
2267     xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
2268     if (item == NULL) {
2269     xsltTransformError(NULL, cctxt->style, NULL,
2270         "Internal error in xsltLREInfoCreate(): "
2271         "memory allocation failed.\n");
2272     cctxt->style->errors++;
2273     return(-1);
2274     }
2275     memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
2276     item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
2277     /*
2278     * Store it in the stylesheet.
2279     */
2280     item->next = cctxt->style->preComps;
2281     cctxt->style->preComps = (xsltElemPreCompPtr) item;
2282     /*
2283     * @inScopeNs are used for execution of XPath expressions
2284     *  in AVTs.
2285     */
2286     item->inScopeNs = cctxt->inode->inScopeNs;
2287 
2288     if (elem)
2289     xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);
2290 
2291     cctxt->inode->litResElemInfo = item;
2292     cctxt->inode->nsChanged = 0;
2293     cctxt->maxLREs++;
2294     return(0);
2295 }
2296 
2297 /**
2298  * xsltCompilerVarInfoPush:
2299  * @cctxt: the compilation context
2300  *
2301  * Pushes a new var/param info onto the stack.
2302  *
2303  * Returns the acquired variable info.
2304  */
2305 static xsltVarInfoPtr
2306 xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,
2307                   xmlNodePtr inst,
2308                   const xmlChar *name,
2309                   const xmlChar *nsName)
2310 {
2311     xsltVarInfoPtr ivar;
2312 
2313     if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) {
2314     ivar = cctxt->ivar->next;
2315     } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) {
2316     ivar = cctxt->ivars;
2317     } else {
2318     ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo));
2319     if (ivar == NULL) {
2320         xsltTransformError(NULL, cctxt->style, inst,
2321         "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
2322         cctxt->style->errors++;
2323         return(NULL);
2324     }
2325     /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
2326     if (cctxt->ivars == NULL) {
2327         cctxt->ivars = ivar;
2328         ivar->prev = NULL;
2329     } else {
2330         cctxt->ivar->next = ivar;
2331         ivar->prev = cctxt->ivar;
2332     }
2333     cctxt->ivar = ivar;
2334     ivar->next = NULL;
2335     }
2336     ivar->depth = cctxt->depth;
2337     ivar->name = name;
2338     ivar->nsName = nsName;
2339     return(ivar);
2340 }
2341 
2342 /**
2343  * xsltCompilerVarInfoPop:
2344  * @cctxt: the compilation context
2345  *
2346  * Pops all var/param infos from the stack, which
2347  * have the current depth.
2348  */
2349 static void
2350 xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)
2351 {
2352 
2353     while ((cctxt->ivar != NULL) &&
2354     (cctxt->ivar->depth > cctxt->depth))
2355     {
2356     cctxt->ivar = cctxt->ivar->prev;
2357     }
2358 }
2359 
2360 /*
2361 * xsltCompilerNodePush:
2362 *
2363 * @cctxt: the compilation context
2364 * @node: the node to be pushed (this can also be the doc-node)
2365 *
2366 *
2367 *
2368 * Returns the current node info structure or
2369 *         NULL in case of an internal error.
2370 */
2371 static xsltCompilerNodeInfoPtr
2372 xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2373 {
2374     xsltCompilerNodeInfoPtr inode, iprev;
2375 
2376     if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {
2377     inode = cctxt->inode->next;
2378     } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {
2379     inode = cctxt->inodeList;
2380     } else {
2381     /*
2382     * Create a new node-info.
2383     */
2384     inode = (xsltCompilerNodeInfoPtr)
2385         xmlMalloc(sizeof(xsltCompilerNodeInfo));
2386     if (inode == NULL) {
2387         xsltTransformError(NULL, cctxt->style, NULL,
2388         "xsltCompilerNodePush: malloc failed.\n");
2389         return(NULL);
2390     }
2391     memset(inode, 0, sizeof(xsltCompilerNodeInfo));
2392     if (cctxt->inodeList == NULL)
2393         cctxt->inodeList = inode;
2394     else {
2395         cctxt->inodeLast->next = inode;
2396         inode->prev = cctxt->inodeLast;
2397     }
2398     cctxt->inodeLast = inode;
2399     cctxt->maxNodeInfos++;
2400     if (cctxt->inode == NULL) {
2401         cctxt->inode = inode;
2402         /*
2403         * Create an initial literal result element info for
2404         * the root of the stylesheet.
2405         */
2406         xsltLREInfoCreate(cctxt, NULL, 0);
2407     }
2408     }
2409     cctxt->depth++;
2410     cctxt->inode = inode;
2411     /*
2412     * REVISIT TODO: Keep the reset always complete.
2413     * NOTE: Be carefull with the @node, since it might be
2414     *  a doc-node.
2415     */
2416     inode->node = node;
2417     inode->depth = cctxt->depth;
2418     inode->templ = NULL;
2419     inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
2420     inode->type = 0;
2421     inode->item = NULL;
2422     inode->curChildType = 0;
2423     inode->extContentHandled = 0;
2424     inode->isRoot = 0;
2425 
2426     if (inode->prev != NULL) {
2427     iprev = inode->prev;
2428     /*
2429     * Inherit the following information:
2430     * ---------------------------------
2431     *
2432     * In-scope namespaces
2433     */
2434     inode->inScopeNs = iprev->inScopeNs;
2435     /*
2436     * Info for literal result elements
2437     */
2438     inode->litResElemInfo = iprev->litResElemInfo;
2439     inode->nsChanged = iprev->nsChanged;
2440     /*
2441     * Excluded result namespaces
2442     */
2443     inode->exclResultNs = iprev->exclResultNs;
2444     /*
2445     * Extension instruction namespaces
2446     */
2447     inode->extElemNs = iprev->extElemNs;
2448     /*
2449     * Whitespace preservation
2450     */
2451     inode->preserveWhitespace = iprev->preserveWhitespace;
2452     /*
2453     * Forwards-compatible mode
2454     */
2455     inode->forwardsCompat = iprev->forwardsCompat;
2456     } else {
2457     inode->inScopeNs = NULL;
2458     inode->exclResultNs = NULL;
2459     inode->extElemNs = NULL;
2460     inode->preserveWhitespace = 0;
2461     inode->forwardsCompat = 0;
2462     }
2463 
2464     return(inode);
2465 }
2466 
2467 /*
2468 * xsltCompilerNodePop:
2469 *
2470 * @cctxt: the compilation context
2471 * @node: the node to be pushed (this can also be the doc-node)
2472 *
2473 * Pops the current node info.
2474 */
2475 static void
2476 xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2477 {
2478     if (cctxt->inode == NULL) {
2479     xmlGenericError(xmlGenericErrorContext,
2480         "xsltCompilerNodePop: Top-node mismatch.\n");
2481     return;
2482     }
2483     /*
2484     * NOTE: Be carefull with the @node, since it might be
2485     *  a doc-node.
2486     */
2487     if (cctxt->inode->node != node) {
2488     xmlGenericError(xmlGenericErrorContext,
2489     "xsltCompilerNodePop: Node mismatch.\n");
2490     goto mismatch;
2491     }
2492     if (cctxt->inode->depth != cctxt->depth) {
2493     xmlGenericError(xmlGenericErrorContext,
2494     "xsltCompilerNodePop: Depth mismatch.\n");
2495     goto mismatch;
2496     }
2497     cctxt->depth--;
2498     /*
2499     * Pop information of variables.
2500     */
2501     if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))
2502     xsltCompilerVarInfoPop(cctxt);
2503 
2504     cctxt->inode = cctxt->inode->prev;
2505     if (cctxt->inode != NULL)
2506     cctxt->inode->curChildType = 0;
2507     return;
2508 
2509 mismatch:
2510     {
2511     const xmlChar *nsName = NULL, *name = NULL;
2512     const xmlChar *infnsName = NULL, *infname = NULL;
2513 
2514     if (node) {
2515         if (node->type == XML_ELEMENT_NODE) {
2516         name = node->name;
2517         if (node->ns != NULL)
2518             nsName = node->ns->href;
2519         else
2520             nsName = BAD_CAST "";
2521         } else {
2522         name = BAD_CAST "#document";
2523         nsName = BAD_CAST "";
2524         }
2525     } else
2526         name = BAD_CAST "Not given";
2527 
2528     if (cctxt->inode->node) {
2529         if (node->type == XML_ELEMENT_NODE) {
2530         infname = cctxt->inode->node->name;
2531         if (cctxt->inode->node->ns != NULL)
2532             infnsName = cctxt->inode->node->ns->href;
2533         else
2534             infnsName = BAD_CAST "";
2535         } else {
2536         infname = BAD_CAST "#document";
2537         infnsName = BAD_CAST "";
2538         }
2539     } else
2540         infname = BAD_CAST "Not given";
2541 
2542 
2543     xmlGenericError(xmlGenericErrorContext,
2544         "xsltCompilerNodePop: Given   : '%s' URI '%s'\n",
2545         name, nsName);
2546     xmlGenericError(xmlGenericErrorContext,
2547         "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
2548         infname, infnsName);
2549     }
2550 }
2551 
2552 /*
2553 * xsltCompilerBuildInScopeNsList:
2554 *
2555 * Create and store the list of in-scope namespaces for the given
2556 * node in the stylesheet. If there are no changes in the in-scope
2557 * namespaces then the last ns-info of the ancestor axis will be returned.
2558 * Compilation-time only.
2559 *
2560 * Returns the ns-info or NULL if there are no namespaces in scope.
2561 */
2562 static xsltNsListContainerPtr
2563 xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
2564 {
2565     xsltNsListContainerPtr nsi = NULL;
2566     xmlNsPtr *list = NULL, ns;
2567     int i, maxns = 5;
2568     /*
2569     * Create a new ns-list for this position in the node-tree.
2570     * xmlGetNsList() will return NULL, if there are no ns-decls in the
2571     * tree. Note that the ns-decl for the XML namespace is not added
2572     * to the resulting list; the XPath module handles the XML namespace
2573     * internally.
2574     */
2575     while (node != NULL) {
2576         if (node->type == XML_ELEMENT_NODE) {
2577             ns = node->nsDef;
2578             while (ns != NULL) {
2579                 if (nsi == NULL) {
2580             nsi = (xsltNsListContainerPtr)
2581             xmlMalloc(sizeof(xsltNsListContainer));
2582             if (nsi == NULL) {
2583             xsltTransformError(NULL, cctxt->style, NULL,
2584                 "xsltCompilerBuildInScopeNsList: "
2585                 "malloc failed!\n");
2586             goto internal_err;
2587             }
2588             memset(nsi, 0, sizeof(xsltNsListContainer));
2589                     nsi->list =
2590                         (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
2591                     if (nsi->list == NULL) {
2592             xsltTransformError(NULL, cctxt->style, NULL,
2593                 "xsltCompilerBuildInScopeNsList: "
2594                 "malloc failed!\n");
2595             goto internal_err;
2596                     }
2597                     nsi->list[0] = NULL;
2598                 }
2599         /*
2600         * Skip shadowed namespace bindings.
2601         */
2602                 for (i = 0; i < nsi->totalNumber; i++) {
2603                     if ((ns->prefix == nsi->list[i]->prefix) ||
2604                         (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
2605             break;
2606                 }
2607                 if (i >= nsi->totalNumber) {
2608                     if (nsi->totalNumber +1 >= maxns) {
2609                         maxns *= 2;
2610             nsi->list =
2611                 (xmlNsPtr *) xmlRealloc(nsi->list,
2612                 maxns * sizeof(xmlNsPtr));
2613                         if (nsi->list == NULL) {
2614                             xsltTransformError(NULL, cctxt->style, NULL,
2615                 "xsltCompilerBuildInScopeNsList: "
2616                 "realloc failed!\n");
2617                 goto internal_err;
2618                         }
2619                     }
2620                     nsi->list[nsi->totalNumber++] = ns;
2621                     nsi->list[nsi->totalNumber] = NULL;
2622                 }
2623 
2624                 ns = ns->next;
2625             }
2626         }
2627         node = node->parent;
2628     }
2629     if (nsi == NULL)
2630     return(NULL);
2631     /*
2632     * Move the default namespace to last position.
2633     */
2634     nsi->xpathNumber = nsi->totalNumber;
2635     for (i = 0; i < nsi->totalNumber; i++) {
2636     if (nsi->list[i]->prefix == NULL) {
2637         ns = nsi->list[i];
2638         nsi->list[i] = nsi->list[nsi->totalNumber-1];
2639         nsi->list[nsi->totalNumber-1] = ns;
2640         nsi->xpathNumber--;
2641         break;
2642     }
2643     }
2644     /*
2645     * Store the ns-list in the stylesheet.
2646     */
2647     if (xsltPointerListAddSize(
2648     (xsltPointerListPtr)cctxt->psData->inScopeNamespaces,
2649     (void *) nsi, 5) == -1)
2650     {
2651     xmlFree(nsi);
2652     nsi = NULL;
2653     xsltTransformError(NULL, cctxt->style, NULL,
2654         "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
2655     goto internal_err;
2656     }
2657     /*
2658     * Notify of change in status wrt namespaces.
2659     */
2660     if (cctxt->inode != NULL)
2661     cctxt->inode->nsChanged = 1;
2662 
2663     return(nsi);
2664 
2665 internal_err:
2666     if (list != NULL)
2667     xmlFree(list);
2668     cctxt->style->errors++;
2669     return(NULL);
2670 }
2671 
2672 static int
2673 xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
2674               xsltPointerListPtr list,
2675               xmlNodePtr node,
2676               const xmlChar *value)
2677 {
2678     xmlChar *cur, *end;
2679     xmlNsPtr ns;
2680 
2681     if ((cctxt == NULL) || (value == NULL) || (list == NULL))
2682     return(-1);
2683 
2684     list->number = 0;
2685 
2686     cur = (xmlChar *) value;
2687     while (*cur != 0) {
2688     while (IS_BLANK(*cur)) cur++;
2689     if (*cur == 0)
2690         break;
2691     end = cur;
2692     while ((*end != 0) && (!IS_BLANK(*end))) end++;
2693     cur = xmlStrndup(cur, end - cur);
2694     if (cur == NULL) {
2695         cur = end;
2696         continue;
2697     }
2698     /*
2699     * TODO: Export and use xmlSearchNsByPrefixStrict()
2700     *   in Libxml2, tree.c, since xmlSearchNs() is in most
2701     *   cases not efficient and in some cases not correct.
2702     *
2703     * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
2704     */
2705     if ((cur[0] == '#') &&
2706         xmlStrEqual(cur, (const xmlChar *)"#default"))
2707         ns = xmlSearchNs(cctxt->style->doc, node, NULL);
2708     else
2709         ns = xmlSearchNs(cctxt->style->doc, node, cur);
2710 
2711     if (ns == NULL) {
2712         /*
2713         * TODO: Better to report the attr-node, otherwise
2714         *  the user won't know which attribute was invalid.
2715         */
2716         xsltTransformError(NULL, cctxt->style, node,
2717         "No namespace binding in scope for prefix '%s'.\n", cur);
2718         /*
2719         * XSLT-1.0: "It is an error if there is no namespace
2720         *  bound to the prefix on the element bearing the
2721         *  exclude-result-prefixes or xsl:exclude-result-prefixes
2722         *  attribute."
2723         */
2724         cctxt->style->errors++;
2725     } else {
2726 #ifdef WITH_XSLT_DEBUG_PARSING
2727         xsltGenericDebug(xsltGenericDebugContext,
2728         "resolved prefix '%s'\n", cur);
2729 #endif
2730         /*
2731         * Note that we put the namespace name into the dict.
2732         */
2733         if (xsltPointerListAddSize(list,
2734         (void *) xmlDictLookup(cctxt->style->dict,
2735         ns->href, -1), 5) == -1)
2736         {
2737         xmlFree(cur);
2738         goto internal_err;
2739         }
2740     }
2741     xmlFree(cur);
2742 
2743     cur = end;
2744     }
2745     return(0);
2746 
2747 internal_err:
2748     cctxt->style->errors++;
2749     return(-1);
2750 }
2751 
2752 /**
2753  * xsltCompilerUtilsCreateMergedList:
2754  * @dest: the destination list (optional)
2755  * @first: the first list
2756  * @second: the second list (optional)
2757  *
2758  * Appends the content of @second to @first into @destination.
2759  * If @destination is NULL a new list will be created.
2760  *
2761  * Returns the merged list of items or NULL if there's nothing to merge.
2762  */
2763 static xsltPointerListPtr
2764 xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,
2765                 xsltPointerListPtr second)
2766 {
2767     xsltPointerListPtr ret;
2768     size_t num;
2769 
2770     if (first)
2771     num = first->number;
2772     else
2773     num = 0;
2774     if (second)
2775     num += second->number;
2776     if (num == 0)
2777     return(NULL);
2778     ret = xsltPointerListCreate(num);
2779     if (ret == NULL)
2780     return(NULL);
2781     /*
2782     * Copy contents.
2783     */
2784     if ((first != NULL) &&  (first->number != 0)) {
2785     memcpy(ret->items, first->items,
2786         first->number * sizeof(void *));
2787     if ((second != NULL) && (second->number != 0))
2788         memcpy(ret->items + first->number, second->items,
2789         second->number * sizeof(void *));
2790     } else if ((second != NULL) && (second->number != 0))
2791     memcpy(ret->items, (void *) second->items,
2792         second->number * sizeof(void *));
2793     ret->number = num;
2794     return(ret);
2795 }
2796 
2797 /*
2798 * xsltParseExclResultPrefixes:
2799 *
2800 * Create and store the list of in-scope namespaces for the given
2801 * node in the stylesheet. If there are no changes in the in-scope
2802 * namespaces then the last ns-info of the ancestor axis will be returned.
2803 * Compilation-time only.
2804 *
2805 * Returns the ns-info or NULL if there are no namespaces in scope.
2806 */
2807 static xsltPointerListPtr
2808 xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2809                 xsltPointerListPtr def,
2810                 int instrCategory)
2811 {
2812     xsltPointerListPtr list = NULL;
2813     xmlChar *value;
2814     xmlAttrPtr attr;
2815 
2816     if ((cctxt == NULL) || (node == NULL))
2817     return(NULL);
2818 
2819     if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2820     attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
2821     else
2822     attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
2823         XSLT_NAMESPACE);
2824     if (attr == NULL)
2825     return(def);
2826 
2827     if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2828     /*
2829     * Mark the XSLT attr.
2830     */
2831     attr->psvi = (void *) xsltXSLTAttrMarker;
2832     }
2833 
2834     if ((attr->children != NULL) &&
2835     (attr->children->content != NULL))
2836     value = attr->children->content;
2837     else {
2838     xsltTransformError(NULL, cctxt->style, node,
2839         "Attribute 'exclude-result-prefixes': Invalid value.\n");
2840     cctxt->style->errors++;
2841     return(def);
2842     }
2843 
2844     if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2845     BAD_CAST value) != 0)
2846     goto exit;
2847     if (cctxt->tmpList->number == 0)
2848     goto exit;
2849     /*
2850     * Merge the list with the inherited list.
2851     */
2852     list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2853     if (list == NULL)
2854     goto exit;
2855     /*
2856     * Store the list in the stylesheet/compiler context.
2857     */
2858     if (xsltPointerListAddSize(
2859     cctxt->psData->exclResultNamespaces, list, 5) == -1)
2860     {
2861     xsltPointerListFree(list);
2862     list = NULL;
2863     goto exit;
2864     }
2865     /*
2866     * Notify of change in status wrt namespaces.
2867     */
2868     if (cctxt->inode != NULL)
2869     cctxt->inode->nsChanged = 1;
2870 
2871 exit:
2872     if (list != NULL)
2873     return(list);
2874     else
2875     return(def);
2876 }
2877 
2878 /*
2879 * xsltParseExtElemPrefixes:
2880 *
2881 * Create and store the list of in-scope namespaces for the given
2882 * node in the stylesheet. If there are no changes in the in-scope
2883 * namespaces then the last ns-info of the ancestor axis will be returned.
2884 * Compilation-time only.
2885 *
2886 * Returns the ns-info or NULL if there are no namespaces in scope.
2887 */
2888 static xsltPointerListPtr
2889 xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2890              xsltPointerListPtr def,
2891              int instrCategory)
2892 {
2893     xsltPointerListPtr list = NULL;
2894     xmlAttrPtr attr;
2895     xmlChar *value;
2896     int i;
2897 
2898     if ((cctxt == NULL) || (node == NULL))
2899     return(NULL);
2900 
2901     if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2902     attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
2903     else
2904     attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
2905         XSLT_NAMESPACE);
2906     if (attr == NULL)
2907     return(def);
2908 
2909     if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
2910     /*
2911     * Mark the XSLT attr.
2912     */
2913     attr->psvi = (void *) xsltXSLTAttrMarker;
2914     }
2915 
2916     if ((attr->children != NULL) &&
2917     (attr->children->content != NULL))
2918     value = attr->children->content;
2919     else {
2920     xsltTransformError(NULL, cctxt->style, node,
2921         "Attribute 'extension-element-prefixes': Invalid value.\n");
2922     cctxt->style->errors++;
2923     return(def);
2924     }
2925 
2926 
2927     if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
2928     BAD_CAST value) != 0)
2929     goto exit;
2930 
2931     if (cctxt->tmpList->number == 0)
2932     goto exit;
2933     /*
2934     * REVISIT: Register the extension namespaces.
2935     */
2936     for (i = 0; i < cctxt->tmpList->number; i++)
2937     xsltRegisterExtPrefix(cctxt->style, NULL,
2938     BAD_CAST cctxt->tmpList->items[i]);
2939     /*
2940     * Merge the list with the inherited list.
2941     */
2942     list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
2943     if (list == NULL)
2944     goto exit;
2945     /*
2946     * Store the list in the stylesheet.
2947     */
2948     if (xsltPointerListAddSize(
2949     cctxt->psData->extElemNamespaces, list, 5) == -1)
2950     {
2951     xsltPointerListFree(list);
2952     list = NULL;
2953     goto exit;
2954     }
2955     /*
2956     * Notify of change in status wrt namespaces.
2957     */
2958     if (cctxt->inode != NULL)
2959     cctxt->inode->nsChanged = 1;
2960 
2961 exit:
2962     if (list != NULL)
2963     return(list);
2964     else
2965     return(def);
2966 }
2967 
2968 /*
2969 * xsltParseAttrXSLTVersion:
2970 *
2971 * @cctxt: the compilation context
2972 * @node: the element-node
2973 * @isXsltElem: whether this is an XSLT element
2974 *
2975 * Parses the attribute xsl:version.
2976 *
2977 * Returns 1 if there was such an attribute, 0 if not and
2978 *         -1 if an internal or API error occured.
2979 */
2980 static int
2981 xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
2982              int instrCategory)
2983 {
2984     xmlChar *value;
2985     xmlAttrPtr attr;
2986 
2987     if ((cctxt == NULL) || (node == NULL))
2988     return(-1);
2989 
2990     if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
2991     attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
2992     else
2993     attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
2994 
2995     if (attr == NULL)
2996     return(0);
2997 
2998     attr->psvi = (void *) xsltXSLTAttrMarker;
2999 
3000     if ((attr->children != NULL) &&
3001     (attr->children->content != NULL))
3002     value = attr->children->content;
3003     else {
3004     xsltTransformError(NULL, cctxt->style, node,
3005         "Attribute 'version': Invalid value.\n");
3006     cctxt->style->errors++;
3007     return(1);
3008     }
3009 
3010     if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
3011     cctxt->inode->forwardsCompat = 1;
3012     /*
3013     * TODO: To what extent do we support the
3014     *  forwards-compatible mode?
3015     */
3016     /*
3017     * Report this only once per compilation episode.
3018     */
3019     if (! cctxt->hasForwardsCompat) {
3020         cctxt->hasForwardsCompat = 1;
3021         cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;
3022         xsltTransformError(NULL, cctxt->style, node,
3023         "Warning: the attribute xsl:version specifies a value "
3024         "different from '1.0'. Switching to forwards-compatible "
3025         "mode. Only features of XSLT 1.0 are supported by this "
3026         "processor.\n");
3027         cctxt->style->warnings++;
3028         cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
3029     }
3030     } else {
3031     cctxt->inode->forwardsCompat = 0;
3032     }
3033 
3034     if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
3035     /*
3036     * Set a marker on XSLT attributes.
3037     */
3038     attr->psvi = (void *) xsltXSLTAttrMarker;
3039     }
3040     return(1);
3041 }
3042 
3043 static int
3044 xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
3045 {
3046     xmlNodePtr deleteNode, cur, txt, textNode = NULL;
3047     xmlDocPtr doc;
3048     xsltStylesheetPtr style;
3049     int internalize = 0, findSpaceAttr;
3050     int xsltStylesheetElemDepth;
3051     xmlAttrPtr attr;
3052     xmlChar *value;
3053     const xmlChar *name, *nsNameXSLT = NULL;
3054     int strictWhitespace, inXSLText = 0;
3055 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3056     xsltNsMapPtr nsMapItem;
3057 #endif
3058 
3059     if ((cctxt == NULL) || (cctxt->style == NULL) ||
3060     (node == NULL) || (node->type != XML_ELEMENT_NODE))
3061         return(-1);
3062 
3063     doc = node->doc;
3064     if (doc == NULL)
3065     goto internal_err;
3066 
3067     style = cctxt->style;
3068     if ((style->dict != NULL) && (doc->dict == style->dict))
3069     internalize = 1;
3070     else
3071         style->internalized = 0;
3072 
3073     /*
3074     * Init value of xml:space. Since this might be an embedded
3075     * stylesheet, this is needed to be performed on the element
3076     * where the stylesheet is rooted at, taking xml:space of
3077     * ancestors into account.
3078     */
3079     if (! cctxt->simplified)
3080     xsltStylesheetElemDepth = cctxt->depth +1;
3081     else
3082     xsltStylesheetElemDepth = 0;
3083 
3084     if (xmlNodeGetSpacePreserve(node) != 1)
3085     cctxt->inode->preserveWhitespace = 0;
3086     else
3087     cctxt->inode->preserveWhitespace = 1;
3088 
3089     /*
3090     * Eval if we should keep the old incorrect behaviour.
3091     */
3092     strictWhitespace = (cctxt->strict != 0) ? 1 : 0;
3093 
3094     nsNameXSLT = xsltConstNamespaceNameXSLT;
3095 
3096     deleteNode = NULL;
3097     cur = node;
3098     while (cur != NULL) {
3099     if (deleteNode != NULL) {
3100 
3101 #ifdef WITH_XSLT_DEBUG_BLANKS
3102         xsltGenericDebug(xsltGenericDebugContext,
3103          "xsltParsePreprocessStylesheetTree: removing node\n");
3104 #endif
3105         xmlUnlinkNode(deleteNode);
3106         xmlFreeNode(deleteNode);
3107         deleteNode = NULL;
3108     }
3109     if (cur->type == XML_ELEMENT_NODE) {
3110 
3111         /*
3112         * Clear the PSVI field.
3113         */
3114         cur->psvi = NULL;
3115 
3116         xsltCompilerNodePush(cctxt, cur);
3117 
3118         inXSLText = 0;
3119         textNode = NULL;
3120         findSpaceAttr = 1;
3121         cctxt->inode->stripWhitespace = 0;
3122         /*
3123         * TODO: I'd love to use a string pointer comparison here :-/
3124         */
3125         if (IS_XSLT_ELEM(cur)) {
3126 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3127         if (cur->ns->href != nsNameXSLT) {
3128             nsMapItem = xsltNewNamespaceMapItem(cctxt,
3129             doc, cur->ns, cur);
3130             if (nsMapItem == NULL)
3131             goto internal_err;
3132             cur->ns->href = nsNameXSLT;
3133         }
3134 #endif
3135 
3136         if (cur->name == NULL)
3137             goto process_attributes;
3138         /*
3139         * Mark the XSLT element for later recognition.
3140         * TODO: Using the marker is still too dangerous, since if
3141         *   the parsing mechanism leaves out an XSLT element, then
3142         *   this might hit the transformation-mechanism, which
3143         *   will break if it doesn't expect such a marker.
3144         */
3145         /* cur->psvi = (void *) xsltXSLTElemMarker; */
3146 
3147         /*
3148         * XSLT 2.0: "Any whitespace text node whose parent is
3149         * one of the following elements is removed from the "
3150         * tree, regardless of any xml:space attributes:..."
3151         * xsl:apply-imports,
3152         * xsl:apply-templates,
3153         * xsl:attribute-set,
3154         * xsl:call-template,
3155         * xsl:choose,
3156         * xsl:stylesheet, xsl:transform.
3157         * XSLT 2.0: xsl:analyze-string,
3158         *           xsl:character-map,
3159         *           xsl:next-match
3160         *
3161         * TODO: I'd love to use a string pointer comparison here :-/
3162         */
3163         name = cur->name;
3164         switch (*name) {
3165             case 't':
3166             if ((name[0] == 't') && (name[1] == 'e') &&
3167                 (name[2] == 'x') && (name[3] == 't') &&
3168                 (name[4] == 0))
3169             {
3170                 /*
3171                 * Process the xsl:text element.
3172                 * ----------------------------
3173                 * Mark it for later recognition.
3174                 */
3175                 cur->psvi = (void *) xsltXSLTTextMarker;
3176                 /*
3177                 * For stylesheets, the set of
3178                 * whitespace-preserving element names
3179                 * consists of just xsl:text.
3180                 */
3181                 findSpaceAttr = 0;
3182                 cctxt->inode->preserveWhitespace = 1;
3183                 inXSLText = 1;
3184             }
3185             break;
3186             case 'c':
3187             if (xmlStrEqual(name, BAD_CAST "choose") ||
3188                 xmlStrEqual(name, BAD_CAST "call-template"))
3189                 cctxt->inode->stripWhitespace = 1;
3190             break;
3191             case 'a':
3192             if (xmlStrEqual(name, BAD_CAST "apply-templates") ||
3193                 xmlStrEqual(name, BAD_CAST "apply-imports") ||
3194                 xmlStrEqual(name, BAD_CAST "attribute-set"))
3195 
3196                 cctxt->inode->stripWhitespace = 1;
3197             break;
3198             default:
3199             if (xsltStylesheetElemDepth == cctxt->depth) {
3200                 /*
3201                 * This is a xsl:stylesheet/xsl:transform.
3202                 */
3203                 cctxt->inode->stripWhitespace = 1;
3204                 break;
3205             }
3206 
3207             if ((cur->prev != NULL) &&
3208                 (cur->prev->type == XML_TEXT_NODE))
3209             {
3210                 /*
3211                 * XSLT 2.0 : "Any whitespace text node whose
3212                 *  following-sibling node is an xsl:param or
3213                 *  xsl:sort element is removed from the tree,
3214                 *  regardless of any xml:space attributes."
3215                 */
3216                 if (((*name == 'p') || (*name == 's')) &&
3217                 (xmlStrEqual(name, BAD_CAST "param") ||
3218                  xmlStrEqual(name, BAD_CAST "sort")))
3219                 {
3220                 do {
3221                     if (IS_BLANK_NODE(cur->prev)) {
3222                     txt = cur->prev;
3223                     xmlUnlinkNode(txt);
3224                     xmlFreeNode(txt);
3225                     } else {
3226                     /*
3227                     * This will result in a content
3228                     * error, when hitting the parsing
3229                     * functions.
3230                     */
3231                     break;
3232                     }
3233                 } while (cur->prev);
3234                 }
3235             }
3236             break;
3237         }
3238         }
3239 
3240 process_attributes:
3241         /*
3242         * Process attributes.
3243         * ------------------
3244         */
3245         if (cur->properties != NULL) {
3246         if (cur->children == NULL)
3247             findSpaceAttr = 0;
3248         attr = cur->properties;
3249         do {
3250 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
3251             if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
3252             xmlStrEqual(attr->ns->href, nsNameXSLT))
3253             {
3254             nsMapItem = xsltNewNamespaceMapItem(cctxt,
3255                 doc, attr->ns, cur);
3256             if (nsMapItem == NULL)
3257                 goto internal_err;
3258             attr->ns->href = nsNameXSLT;
3259             }
3260 #endif
3261             if (internalize) {
3262             /*
3263             * Internalize the attribute's value; the goal is to
3264             * speed up operations and minimize used space by
3265             * compiled stylesheets.
3266             */
3267             txt = attr->children;
3268             /*
3269             * NOTE that this assumes only one
3270             *  text-node in the attribute's content.
3271             */
3272             if ((txt != NULL) && (txt->content != NULL) &&
3273                 (!xmlDictOwns(style->dict, txt->content)))
3274             {
3275                 value = (xmlChar *) xmlDictLookup(style->dict,
3276                 txt->content, -1);
3277                 xmlNodeSetContent(txt, NULL);
3278                 txt->content = value;
3279             }
3280             }
3281             /*
3282             * Process xml:space attributes.
3283             * ----------------------------
3284             */
3285             if ((findSpaceAttr != 0) &&
3286             (attr->ns != NULL) &&
3287             (attr->name != NULL) &&
3288             (attr->name[0] == 's') &&
3289             (attr->ns->prefix != NULL) &&
3290             (attr->ns->prefix[0] == 'x') &&
3291             (attr->ns->prefix[1] == 'm') &&
3292             (attr->ns->prefix[2] == 'l') &&
3293             (attr->ns->prefix[3] == 0))
3294             {
3295             value = xmlGetNsProp(cur, BAD_CAST "space",
3296                 XML_XML_NAMESPACE);
3297             if (value != NULL) {
3298                 if (xmlStrEqual(value, BAD_CAST "preserve")) {
3299                 cctxt->inode->preserveWhitespace = 1;
3300                 } else if (xmlStrEqual(value, BAD_CAST "default")) {
3301                 cctxt->inode->preserveWhitespace = 0;
3302                 } else {
3303                 /* Invalid value for xml:space. */
3304                 xsltTransformError(NULL, style, cur,
3305                     "Attribute xml:space: Invalid value.\n");
3306                 cctxt->style->warnings++;
3307                 }
3308                 findSpaceAttr = 0;
3309                 xmlFree(value);
3310             }
3311 
3312             }
3313             attr = attr->next;
3314         } while (attr != NULL);
3315         }
3316         /*
3317         * We'll descend into the children of element nodes only.
3318         */
3319         if (cur->children != NULL) {
3320         cur = cur->children;
3321         continue;
3322         }
3323     } else if ((cur->type == XML_TEXT_NODE) ||
3324         (cur->type == XML_CDATA_SECTION_NODE))
3325     {
3326         /*
3327         * Merge adjacent text/CDATA-section-nodes
3328         * ---------------------------------------
3329         * In order to avoid breaking of existing stylesheets,
3330         * if the old behaviour is wanted (strictWhitespace == 0),
3331         * then we *won't* merge adjacent text-nodes
3332         * (except in xsl:text); this will ensure that whitespace-only
3333         * text nodes are (incorrectly) not stripped in some cases.
3334         *
3335         * Example:               : <foo>  <!-- bar -->zoo</foo>
3336         * Corrent (strict) result: <foo>  zoo</foo>
3337         * Incorrect (old) result : <foo>zoo</foo>
3338         *
3339         * NOTE that we *will* merge adjacent text-nodes if
3340         * they are in xsl:text.
3341         * Example, the following:
3342         * <xsl:text>  <!-- bar -->zoo<xsl:text>
3343         * will result in both cases in:
3344         * <xsl:text>  zoo<xsl:text>
3345         */
3346         cur->type = XML_TEXT_NODE;
3347         if ((strictWhitespace != 0) || (inXSLText != 0)) {
3348         /*
3349         * New behaviour; merge nodes.
3350         */
3351         if (textNode == NULL)
3352             textNode = cur;
3353         else {
3354             if (cur->content != NULL)
3355             xmlNodeAddContent(textNode, cur->content);
3356             deleteNode = cur;
3357         }
3358         if ((cur->next == NULL) ||
3359             (cur->next->type == XML_ELEMENT_NODE))
3360             goto end_of_text;
3361         else
3362             goto next_sibling;
3363         } else {
3364         /*
3365         * Old behaviour.
3366         */
3367         if (textNode == NULL)
3368             textNode = cur;
3369         goto end_of_text;
3370         }
3371     } else if ((cur->type == XML_COMMENT_NODE) ||
3372         (cur->type == XML_PI_NODE))
3373     {
3374         /*
3375         * Remove processing instructions and comments.
3376         */
3377         deleteNode = cur;
3378         if ((cur->next == NULL) ||
3379         (cur->next->type == XML_ELEMENT_NODE))
3380         goto end_of_text;
3381         else
3382         goto next_sibling;
3383     } else {
3384         textNode = NULL;
3385         /*
3386         * Invalid node-type for this data-model.
3387         */
3388         xsltTransformError(NULL, style, cur,
3389         "Invalid type of node for the XSLT data model.\n");
3390         cctxt->style->errors++;
3391         goto next_sibling;
3392     }
3393 
3394 end_of_text:
3395     if (textNode) {
3396         value = textNode->content;
3397         /*
3398         * At this point all adjacent text/CDATA-section nodes
3399         * have been merged.
3400         *
3401         * Strip whitespace-only text-nodes.
3402         * (cctxt->inode->stripWhitespace)
3403         */
3404         if ((value == NULL) || (*value == 0) ||
3405         (((cctxt->inode->stripWhitespace) ||
3406           (! cctxt->inode->preserveWhitespace)) &&
3407          IS_BLANK(*value) &&
3408          xsltIsBlank(value)))
3409         {
3410         if (textNode != cur) {
3411             xmlUnlinkNode(textNode);
3412             xmlFreeNode(textNode);
3413         } else
3414             deleteNode = textNode;
3415         textNode = NULL;
3416         goto next_sibling;
3417         }
3418         /*
3419         * Convert CDATA-section nodes to text-nodes.
3420         * TODO: Can this produce problems?
3421         */
3422         if (textNode->type != XML_TEXT_NODE) {
3423         textNode->type = XML_TEXT_NODE;
3424         textNode->name = xmlStringText;
3425         }
3426         if (internalize &&
3427         (textNode->content != NULL) &&
3428         (!xmlDictOwns(style->dict, textNode->content)))
3429         {
3430         /*
3431         * Internalize the string.
3432         */
3433         value = (xmlChar *) xmlDictLookup(style->dict,
3434             textNode->content, -1);
3435         xmlNodeSetContent(textNode, NULL);
3436         textNode->content = value;
3437         }
3438         textNode = NULL;
3439         /*
3440         * Note that "disable-output-escaping" of the xsl:text
3441         * element will be applied at a later level, when
3442         * XSLT elements are processed.
3443         */
3444     }
3445 
3446 next_sibling:
3447     if (cur->type == XML_ELEMENT_NODE) {
3448         xsltCompilerNodePop(cctxt, cur);
3449     }
3450     if (cur == node)
3451         break;
3452     if (cur->next != NULL) {
3453         cur = cur->next;
3454     } else {
3455         cur = cur->parent;
3456         inXSLText = 0;
3457         goto next_sibling;
3458     };
3459     }
3460     if (deleteNode != NULL) {
3461 #ifdef WITH_XSLT_DEBUG_PARSING
3462     xsltGenericDebug(xsltGenericDebugContext,
3463      "xsltParsePreprocessStylesheetTree: removing node\n");
3464 #endif
3465     xmlUnlinkNode(deleteNode);
3466     xmlFreeNode(deleteNode);
3467     }
3468     return(0);
3469 
3470 internal_err:
3471     return(-1);
3472 }
3473 
3474 #endif /* XSLT_REFACTORED */
3475 
3476 #ifdef XSLT_REFACTORED
3477 #else
3478 static void
3479 xsltPreprocessStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
3480 {
3481     xmlNodePtr deleteNode, styleelem;
3482     int internalize = 0;
3483 
3484     if ((style == NULL) || (cur == NULL))
3485         return;
3486 
3487     if ((cur->doc != NULL) && (style->dict != NULL) &&
3488         (cur->doc->dict == style->dict))
3489     internalize = 1;
3490     else
3491         style->internalized = 0;
3492 
3493     if ((cur != NULL) && (IS_XSLT_ELEM(cur)) &&
3494         (IS_XSLT_NAME(cur, "stylesheet"))) {
3495     styleelem = cur;
3496     } else {
3497         styleelem = NULL;
3498     }
3499 
3500     /*
3501      * This content comes from the stylesheet
3502      * For stylesheets, the set of whitespace-preserving
3503      * element names consists of just xsl:text.
3504      */
3505     deleteNode = NULL;
3506     while (cur != NULL) {
3507     if (deleteNode != NULL) {
3508 #ifdef WITH_XSLT_DEBUG_BLANKS
3509         xsltGenericDebug(xsltGenericDebugContext,
3510          "xsltPreprocessStylesheet: removing ignorable blank node\n");
3511 #endif
3512         xmlUnlinkNode(deleteNode);
3513         xmlFreeNode(deleteNode);
3514         deleteNode = NULL;
3515     }
3516     if (cur->type == XML_ELEMENT_NODE) {
3517         int exclPrefixes;
3518         /*
3519          * Internalize attributes values.
3520          */
3521         if ((internalize) && (cur->properties != NULL)) {
3522             xmlAttrPtr attr = cur->properties;
3523         xmlNodePtr txt;
3524 
3525         while (attr != NULL) {
3526             txt = attr->children;
3527             if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
3528                 (txt->content != NULL) &&
3529             (!xmlDictOwns(style->dict, txt->content)))
3530             {
3531             xmlChar *tmp;
3532 
3533             /*
3534              * internalize the text string, goal is to speed
3535              * up operations and minimize used space by compiled
3536              * stylesheets.
3537              */
3538             tmp = (xmlChar *) xmlDictLookup(style->dict,
3539                                             txt->content, -1);
3540             if (tmp != txt->content) {
3541                 xmlNodeSetContent(txt, NULL);
3542                 txt->content = tmp;
3543             }
3544             }
3545             attr = attr->next;
3546         }
3547         }
3548         if (IS_XSLT_ELEM(cur)) {
3549         exclPrefixes = 0;
3550         if (IS_XSLT_NAME(cur, "text")) {
3551             for (;exclPrefixes > 0;exclPrefixes--)
3552             exclPrefixPop(style);
3553             goto skip_children;
3554         }
3555         } else {
3556         exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
3557         }
3558 
3559         if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
3560         xmlNsPtr ns = cur->nsDef, prev = NULL, next;
3561         xmlNodePtr root = NULL;
3562         int i, moved;
3563 
3564         root = xmlDocGetRootElement(cur->doc);
3565         if ((root != NULL) && (root != cur)) {
3566             while (ns != NULL) {
3567             moved = 0;
3568             next = ns->next;
3569             for (i = 0;i < style->exclPrefixNr;i++) {
3570                 if ((ns->prefix != NULL) &&
3571                     (xmlStrEqual(ns->href,
3572                          style->exclPrefixTab[i]))) {
3573                 /*
3574                  * Move the namespace definition on the root
3575                  * element to avoid duplicating it without
3576                  * loosing it.
3577                  */
3578                 if (prev == NULL) {
3579                     cur->nsDef = ns->next;
3580                 } else {
3581                     prev->next = ns->next;
3582                 }
3583                 ns->next = root->nsDef;
3584                 root->nsDef = ns;
3585                 moved = 1;
3586                 break;
3587                 }
3588             }
3589             if (moved == 0)
3590                 prev = ns;
3591             ns = next;
3592             }
3593         }
3594         }
3595         /*
3596          * If we have prefixes locally, recurse and pop them up when
3597          * going back
3598          */
3599         if (exclPrefixes > 0) {
3600         xsltPreprocessStylesheet(style, cur->children);
3601         for (;exclPrefixes > 0;exclPrefixes--)
3602             exclPrefixPop(style);
3603         goto skip_children;
3604         }
3605     } else if (cur->type == XML_TEXT_NODE) {
3606         if (IS_BLANK_NODE(cur)) {
3607         if (xmlNodeGetSpacePreserve(cur->parent) != 1) {
3608             deleteNode = cur;
3609         }
3610         } else if ((cur->content != NULL) && (internalize) &&
3611                    (!xmlDictOwns(style->dict, cur->content))) {
3612         xmlChar *tmp;
3613 
3614         /*
3615          * internalize the text string, goal is to speed
3616          * up operations and minimize used space by compiled
3617          * stylesheets.
3618          */
3619         tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
3620         xmlNodeSetContent(cur, NULL);
3621         cur->content = tmp;
3622         }
3623     } else if ((cur->type != XML_ELEMENT_NODE) &&
3624            (cur->type != XML_CDATA_SECTION_NODE)) {
3625         deleteNode = cur;
3626         goto skip_children;
3627     }
3628 
3629     /*
3630      * Skip to next node. In case of a namespaced element children of
3631      * the stylesheet and not in the XSLT namespace and not an extension
3632      * element, ignore its content.
3633      */
3634     if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) &&
3635         (styleelem != NULL) && (cur->parent == styleelem) &&
3636         (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) &&
3637         (!xsltCheckExtURI(style, cur->ns->href))) {
3638         goto skip_children;
3639     } else if (cur->children != NULL) {
3640         if ((cur->children->type != XML_ENTITY_DECL) &&
3641         (cur->children->type != XML_ENTITY_REF_NODE) &&
3642         (cur->children->type != XML_ENTITY_NODE)) {
3643         cur = cur->children;
3644         continue;
3645         }
3646     }
3647 
3648 skip_children:
3649     if (cur->next != NULL) {
3650         cur = cur->next;
3651         continue;
3652     }
3653     do {
3654 
3655         cur = cur->parent;
3656         if (cur == NULL)
3657         break;
3658         if (cur == (xmlNodePtr) style->doc) {
3659         cur = NULL;
3660         break;
3661         }
3662         if (cur->next != NULL) {
3663         cur = cur->next;
3664         break;
3665         }
3666     } while (cur != NULL);
3667     }
3668     if (deleteNode != NULL) {
3669 #ifdef WITH_XSLT_DEBUG_PARSING
3670     xsltGenericDebug(xsltGenericDebugContext,
3671      "xsltPreprocessStylesheet: removing ignorable blank node\n");
3672 #endif
3673     xmlUnlinkNode(deleteNode);
3674     xmlFreeNode(deleteNode);
3675     }
3676 }
3677 #endif /* end of else XSLT_REFACTORED */
3678 
3679 /**
3680  * xsltGatherNamespaces:
3681  * @style:  the XSLT stylesheet
3682  *
3683  * Browse the stylesheet and build the namspace hash table which
3684  * will be used for XPath interpretation. If needed do a bit of normalization
3685  */
3686 
3687 static void
3688 xsltGatherNamespaces(xsltStylesheetPtr style) {
3689     xmlNodePtr cur;
3690     const xmlChar *URI;
3691 
3692     if (style == NULL)
3693         return;
3694     /*
3695      * TODO: basically if the stylesheet uses the same prefix for different
3696      *       patterns, well they may be in problem, hopefully they will get
3697      *       a warning first.
3698      */
3699     /*
3700     * TODO: Eliminate the use of the hash for XPath expressions.
3701     *   An expression should be evaluated in the context of the in-scope
3702     *   namespaces; eliminate the restriction of an XML document to contain
3703     *   no duplicate prefixes for different namespace names.
3704     *
3705     */
3706     cur = xmlDocGetRootElement(style->doc);
3707     while (cur != NULL) {
3708     if (cur->type == XML_ELEMENT_NODE) {
3709         xmlNsPtr ns = cur->nsDef;
3710         while (ns != NULL) {
3711         if (ns->prefix != NULL) {
3712             if (style->nsHash == NULL) {
3713             style->nsHash = xmlHashCreate(10);
3714             if (style->nsHash == NULL) {
3715                 xsltTransformError(NULL, style, cur,
3716          "xsltGatherNamespaces: failed to create hash table\n");
3717                 style->errors++;
3718                 return;
3719             }
3720             }
3721             URI = xmlHashLookup(style->nsHash, ns->prefix);
3722             if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
3723             xsltTransformError(NULL, style, cur,
3724          "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
3725             style->warnings++;
3726             } else if (URI == NULL) {
3727             xmlHashUpdateEntry(style->nsHash, ns->prefix,
3728                 (void *) ns->href, NULL);
3729 
3730 #ifdef WITH_XSLT_DEBUG_PARSING
3731             xsltGenericDebug(xsltGenericDebugContext,
3732          "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
3733 #endif
3734             }
3735         }
3736         ns = ns->next;
3737         }
3738     }
3739 
3740     /*
3741      * Skip to next node
3742      */
3743     if (cur->children != NULL) {
3744         if (cur->children->type != XML_ENTITY_DECL) {
3745         cur = cur->children;
3746         continue;
3747         }
3748     }
3749     if (cur->next != NULL) {
3750         cur = cur->next;
3751         continue;
3752     }
3753 
3754     do {
3755         cur = cur->parent;
3756         if (cur == NULL)
3757         break;
3758         if (cur == (xmlNodePtr) style->doc) {
3759         cur = NULL;
3760         break;
3761         }
3762         if (cur->next != NULL) {
3763         cur = cur->next;
3764         break;
3765         }
3766     } while (cur != NULL);
3767     }
3768 }
3769 
3770 #ifdef XSLT_REFACTORED
3771 
3772 static xsltStyleType
3773 xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
3774                  xmlNodePtr node)
3775 {
3776     if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
3777     (node->name == NULL))
3778     return(0);
3779 
3780     if (node->name[0] == 'a') {
3781     if (IS_XSLT_NAME(node, "apply-templates"))
3782         return(XSLT_FUNC_APPLYTEMPLATES);
3783     else if (IS_XSLT_NAME(node, "attribute"))
3784         return(XSLT_FUNC_ATTRIBUTE);
3785     else if (IS_XSLT_NAME(node, "apply-imports"))
3786         return(XSLT_FUNC_APPLYIMPORTS);
3787     else if (IS_XSLT_NAME(node, "attribute-set"))
3788         return(0);
3789 
3790     } else if (node->name[0] == 'c') {
3791     if (IS_XSLT_NAME(node, "choose"))
3792         return(XSLT_FUNC_CHOOSE);
3793     else if (IS_XSLT_NAME(node, "copy"))
3794         return(XSLT_FUNC_COPY);
3795     else if (IS_XSLT_NAME(node, "copy-of"))
3796         return(XSLT_FUNC_COPYOF);
3797     else if (IS_XSLT_NAME(node, "call-template"))
3798         return(XSLT_FUNC_CALLTEMPLATE);
3799     else if (IS_XSLT_NAME(node, "comment"))
3800         return(XSLT_FUNC_COMMENT);
3801 
3802     } else if (node->name[0] == 'd') {
3803     if (IS_XSLT_NAME(node, "document"))
3804         return(XSLT_FUNC_DOCUMENT);
3805     else if (IS_XSLT_NAME(node, "decimal-format"))
3806         return(0);
3807 
3808     } else if (node->name[0] == 'e') {
3809     if (IS_XSLT_NAME(node, "element"))
3810         return(XSLT_FUNC_ELEMENT);
3811 
3812     } else if (node->name[0] == 'f') {
3813     if (IS_XSLT_NAME(node, "for-each"))
3814         return(XSLT_FUNC_FOREACH);
3815     else if (IS_XSLT_NAME(node, "fallback"))
3816         return(XSLT_FUNC_FALLBACK);
3817 
3818     } else if (*(node->name) == 'i') {
3819     if (IS_XSLT_NAME(node, "if"))
3820         return(XSLT_FUNC_IF);
3821     else if (IS_XSLT_NAME(node, "include"))
3822         return(0);
3823     else if (IS_XSLT_NAME(node, "import"))
3824         return(0);
3825 
3826     } else if (*(node->name) == 'k') {
3827     if (IS_XSLT_NAME(node, "key"))
3828         return(0);
3829 
3830     } else if (*(node->name) == 'm') {
3831     if (IS_XSLT_NAME(node, "message"))
3832         return(XSLT_FUNC_MESSAGE);
3833 
3834     } else if (*(node->name) == 'n') {
3835     if (IS_XSLT_NAME(node, "number"))
3836         return(XSLT_FUNC_NUMBER);
3837     else if (IS_XSLT_NAME(node, "namespace-alias"))
3838         return(0);
3839 
3840     } else if (*(node->name) == 'o') {
3841     if (IS_XSLT_NAME(node, "otherwise"))
3842         return(XSLT_FUNC_OTHERWISE);
3843     else if (IS_XSLT_NAME(node, "output"))
3844         return(0);
3845 
3846     } else if (*(node->name) == 'p') {
3847     if (IS_XSLT_NAME(node, "param"))
3848         return(XSLT_FUNC_PARAM);
3849     else if (IS_XSLT_NAME(node, "processing-instruction"))
3850         return(XSLT_FUNC_PI);
3851     else if (IS_XSLT_NAME(node, "preserve-space"))
3852         return(0);
3853 
3854     } else if (*(node->name) == 's') {
3855     if (IS_XSLT_NAME(node, "sort"))
3856         return(XSLT_FUNC_SORT);
3857     else if (IS_XSLT_NAME(node, "strip-space"))
3858         return(0);
3859     else if (IS_XSLT_NAME(node, "stylesheet"))
3860         return(0);
3861 
3862     } else if (node->name[0] == 't') {
3863     if (IS_XSLT_NAME(node, "text"))
3864         return(XSLT_FUNC_TEXT);
3865     else if (IS_XSLT_NAME(node, "template"))
3866         return(0);
3867     else if (IS_XSLT_NAME(node, "transform"))
3868         return(0);
3869 
3870     } else if (*(node->name) == 'v') {
3871     if (IS_XSLT_NAME(node, "value-of"))
3872         return(XSLT_FUNC_VALUEOF);
3873     else if (IS_XSLT_NAME(node, "variable"))
3874         return(XSLT_FUNC_VARIABLE);
3875 
3876     } else if (*(node->name) == 'w') {
3877     if (IS_XSLT_NAME(node, "when"))
3878         return(XSLT_FUNC_WHEN);
3879     if (IS_XSLT_NAME(node, "with-param"))
3880         return(XSLT_FUNC_WITHPARAM);
3881     }
3882     return(0);
3883 }
3884 
3885 /**
3886  * xsltParseAnyXSLTElem:
3887  *
3888  * @cctxt: the compilation context
3889  * @elem: the element node of the XSLT instruction
3890  *
3891  * Parses, validates the content models and compiles XSLT instructions.
3892  *
3893  * Returns 0 if everything's fine;
3894  *         -1 on API or internal errors.
3895  */
3896 int
3897 xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
3898 {
3899     if ((cctxt == NULL) || (elem == NULL) ||
3900     (elem->type != XML_ELEMENT_NODE))
3901     return(-1);
3902 
3903     elem->psvi = NULL;
3904 
3905     if (! (IS_XSLT_ELEM_FAST(elem)))
3906     return(-1);
3907     /*
3908     * Detection of handled content of extension instructions.
3909     */
3910     if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
3911     cctxt->inode->extContentHandled = 1;
3912     }
3913 
3914     xsltCompilerNodePush(cctxt, elem);
3915     /*
3916     * URGENT TODO: Find a way to speed up this annoying redundant
3917     *  textual node-name and namespace comparison.
3918     */
3919     if (cctxt->inode->prev->curChildType != 0)
3920     cctxt->inode->type = cctxt->inode->prev->curChildType;
3921     else
3922     cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem);
3923     /*
3924     * Update the in-scope namespaces if needed.
3925     */
3926     if (elem->nsDef != NULL)
3927     cctxt->inode->inScopeNs =
3928         xsltCompilerBuildInScopeNsList(cctxt, elem);
3929     /*
3930     * xsltStylePreCompute():
3931     *  This will compile the information found on the current
3932     *  element's attributes. NOTE that this won't process the
3933     *  children of the instruction.
3934     */
3935     xsltStylePreCompute(cctxt->style, elem);
3936     /*
3937     * TODO: How to react on errors in xsltStylePreCompute() ?
3938     */
3939 
3940     /*
3941     * Validate the content model of the XSLT-element.
3942     */
3943     switch (cctxt->inode->type) {
3944     case XSLT_FUNC_APPLYIMPORTS:
3945         /* EMPTY */
3946         goto empty_content;
3947     case XSLT_FUNC_APPLYTEMPLATES:
3948         /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
3949         goto apply_templates;
3950     case XSLT_FUNC_ATTRIBUTE:
3951         /* <!-- Content: template --> */
3952         goto sequence_constructor;
3953     case XSLT_FUNC_CALLTEMPLATE:
3954         /* <!-- Content: xsl:with-param* --> */
3955         goto call_template;
3956     case XSLT_FUNC_CHOOSE:
3957         /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
3958         goto choose;
3959     case XSLT_FUNC_COMMENT:
3960         /* <!-- Content: template --> */
3961         goto sequence_constructor;
3962     case XSLT_FUNC_COPY:
3963         /* <!-- Content: template --> */
3964         goto sequence_constructor;
3965     case XSLT_FUNC_COPYOF:
3966         /* EMPTY */
3967         goto empty_content;
3968     case XSLT_FUNC_DOCUMENT: /* Extra one */
3969         /* ?? template ?? */
3970         goto sequence_constructor;
3971     case XSLT_FUNC_ELEMENT:
3972         /* <!-- Content: template --> */
3973         goto sequence_constructor;
3974     case XSLT_FUNC_FALLBACK:
3975         /* <!-- Content: template --> */
3976         goto sequence_constructor;
3977     case XSLT_FUNC_FOREACH:
3978         /* <!-- Content: (xsl:sort*, template) --> */
3979         goto for_each;
3980     case XSLT_FUNC_IF:
3981         /* <!-- Content: template --> */
3982         goto sequence_constructor;
3983     case XSLT_FUNC_OTHERWISE:
3984         /* <!-- Content: template --> */
3985         goto sequence_constructor;
3986     case XSLT_FUNC_MESSAGE:
3987         /* <!-- Content: template --> */
3988         goto sequence_constructor;
3989     case XSLT_FUNC_NUMBER:
3990         /* EMPTY */
3991         goto empty_content;
3992     case XSLT_FUNC_PARAM:
3993         /*
3994         * Check for redefinition.
3995         */
3996         if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
3997         xsltVarInfoPtr ivar = cctxt->ivar;
3998 
3999         do {
4000             if ((ivar->name ==
4001              ((xsltStyleItemParamPtr) elem->psvi)->name) &&
4002             (ivar->nsName ==
4003              ((xsltStyleItemParamPtr) elem->psvi)->ns))
4004             {
4005             elem->psvi = NULL;
4006             xsltTransformError(NULL, cctxt->style, elem,
4007                 "Redefinition of variable or parameter '%s'.\n",
4008                 ivar->name);
4009             cctxt->style->errors++;
4010             goto error;
4011             }
4012             ivar = ivar->prev;
4013         } while (ivar != NULL);
4014         }
4015         /*  <!-- Content: template --> */
4016         goto sequence_constructor;
4017     case XSLT_FUNC_PI:
4018         /*  <!-- Content: template --> */
4019         goto sequence_constructor;
4020     case XSLT_FUNC_SORT:
4021         /* EMPTY */
4022         goto empty_content;
4023     case XSLT_FUNC_TEXT:
4024         /* <!-- Content: #PCDATA --> */
4025         goto text;
4026     case XSLT_FUNC_VALUEOF:
4027         /* EMPTY */
4028         goto empty_content;
4029     case XSLT_FUNC_VARIABLE:
4030         /*
4031         * Check for redefinition.
4032         */
4033         if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
4034         xsltVarInfoPtr ivar = cctxt->ivar;
4035 
4036         do {
4037             if ((ivar->name ==
4038              ((xsltStyleItemVariablePtr) elem->psvi)->name) &&
4039             (ivar->nsName ==
4040              ((xsltStyleItemVariablePtr) elem->psvi)->ns))
4041             {
4042             elem->psvi = NULL;
4043             xsltTransformError(NULL, cctxt->style, elem,
4044                 "Redefinition of variable or parameter '%s'.\n",
4045                 ivar->name);
4046             cctxt->style->errors++;
4047             goto error;
4048             }
4049             ivar = ivar->prev;
4050         } while (ivar != NULL);
4051         }
4052         /* <!-- Content: template --> */
4053         goto sequence_constructor;
4054     case XSLT_FUNC_WHEN:
4055         /* <!-- Content: template --> */
4056         goto sequence_constructor;
4057     case XSLT_FUNC_WITHPARAM:
4058         /* <!-- Content: template --> */
4059         goto sequence_constructor;
4060     default:
4061 #ifdef WITH_XSLT_DEBUG_PARSING
4062         xsltGenericDebug(xsltGenericDebugContext,
4063         "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
4064         elem->name);
4065 #endif
4066         xsltTransformError(NULL, cctxt->style, elem,
4067         "xsltParseXSLTNode: Internal error; "
4068         "unhandled XSLT element '%s'.\n", elem->name);
4069         cctxt->style->errors++;
4070         goto internal_err;
4071     }
4072 
4073 apply_templates:
4074     /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
4075     if (elem->children != NULL) {
4076     xmlNodePtr child = elem->children;
4077     do {
4078         if (child->type == XML_ELEMENT_NODE) {
4079         if (IS_XSLT_ELEM_FAST(child)) {
4080             if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
4081             cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4082             xsltParseAnyXSLTElem(cctxt, child);
4083             } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
4084             cctxt->inode->curChildType = XSLT_FUNC_SORT;
4085             xsltParseAnyXSLTElem(cctxt, child);
4086             } else
4087             xsltParseContentError(cctxt->style, child);
4088         } else
4089             xsltParseContentError(cctxt->style, child);
4090         }
4091         child = child->next;
4092     } while (child != NULL);
4093     }
4094     goto exit;
4095 
4096 call_template:
4097     /* <!-- Content: xsl:with-param* --> */
4098     if (elem->children != NULL) {
4099     xmlNodePtr child = elem->children;
4100     do {
4101         if (child->type == XML_ELEMENT_NODE) {
4102         if (IS_XSLT_ELEM_FAST(child)) {
4103             xsltStyleType type;
4104 
4105             type = xsltGetXSLTElementTypeByNode(cctxt, child);
4106             if (type == XSLT_FUNC_WITHPARAM) {
4107             cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
4108             xsltParseAnyXSLTElem(cctxt, child);
4109             } else {
4110             xsltParseContentError(cctxt->style, child);
4111             }
4112         } else
4113             xsltParseContentError(cctxt->style, child);
4114         }
4115         child = child->next;
4116     } while (child != NULL);
4117     }
4118     goto exit;
4119 
4120 text:
4121     if (elem->children != NULL) {
4122     xmlNodePtr child = elem->children;
4123     do {
4124         if ((child->type != XML_TEXT_NODE) &&
4125         (child->type != XML_CDATA_SECTION_NODE))
4126         {
4127         xsltTransformError(NULL, cctxt->style, elem,
4128             "The XSLT 'text' element must have only character "
4129             "data as content.\n");
4130         }
4131         child = child->next;
4132     } while (child != NULL);
4133     }
4134     goto exit;
4135 
4136 empty_content:
4137     if (elem->children != NULL) {
4138     xmlNodePtr child = elem->children;
4139     /*
4140     * Relaxed behaviour: we will allow whitespace-only text-nodes.
4141     */
4142     do {
4143         if (((child->type != XML_TEXT_NODE) &&
4144          (child->type != XML_CDATA_SECTION_NODE)) ||
4145         (! IS_BLANK_NODE(child)))
4146         {
4147         xsltTransformError(NULL, cctxt->style, elem,
4148             "This XSLT element must have no content.\n");
4149         cctxt->style->errors++;
4150         break;
4151         }
4152         child = child->next;
4153     } while (child != NULL);
4154     }
4155     goto exit;
4156 
4157 choose:
4158     /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
4159     /*
4160     * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
4161     *   The old behaviour did not check this.
4162     * NOTE: In XSLT 2.0 they are stripped beforehand
4163     *  if whitespace-only (regardless of xml:space).
4164     */
4165     if (elem->children != NULL) {
4166     xmlNodePtr child = elem->children;
4167     int nbWhen = 0, nbOtherwise = 0, err = 0;
4168     do {
4169         if (child->type == XML_ELEMENT_NODE) {
4170         if (IS_XSLT_ELEM_FAST(child)) {
4171             xsltStyleType type;
4172 
4173             type = xsltGetXSLTElementTypeByNode(cctxt, child);
4174             if (type == XSLT_FUNC_WHEN) {
4175             nbWhen++;
4176             if (nbOtherwise) {
4177                 xsltParseContentError(cctxt->style, child);
4178                 err = 1;
4179                 break;
4180             }
4181             cctxt->inode->curChildType = XSLT_FUNC_WHEN;
4182             xsltParseAnyXSLTElem(cctxt, child);
4183             } else if (type == XSLT_FUNC_OTHERWISE) {
4184             if (! nbWhen) {
4185                 xsltParseContentError(cctxt->style, child);
4186                 err = 1;
4187                 break;
4188             }
4189             if (nbOtherwise) {
4190                 xsltTransformError(NULL, cctxt->style, elem,
4191                 "The XSLT 'choose' element must not contain "
4192                 "more than one XSLT 'otherwise' element.\n");
4193                 cctxt->style->errors++;
4194                 err = 1;
4195                 break;
4196             }
4197             nbOtherwise++;
4198             cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;
4199             xsltParseAnyXSLTElem(cctxt, child);
4200             } else
4201             xsltParseContentError(cctxt->style, child);
4202         } else
4203             xsltParseContentError(cctxt->style, child);
4204         }
4205         /*
4206         else
4207             xsltParseContentError(cctxt, child);
4208         */
4209         child = child->next;
4210     } while (child != NULL);
4211     if ((! err) && (! nbWhen)) {
4212         xsltTransformError(NULL, cctxt->style, elem,
4213         "The XSLT element 'choose' must contain at least one "
4214         "XSLT element 'when'.\n");
4215         cctxt->style->errors++;
4216     }
4217     }
4218     goto exit;
4219 
4220 for_each:
4221     /* <!-- Content: (xsl:sort*, template) --> */
4222     /*
4223     * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
4224     *   The old behaviour did not allow this, but it catched this
4225     *   only at transformation-time.
4226     *   In XSLT 2.0 they are stripped beforehand if whitespace-only
4227     *   (regardless of xml:space).
4228     */
4229     if (elem->children != NULL) {
4230     xmlNodePtr child = elem->children;
4231     /*
4232     * Parse xsl:sort first.
4233     */
4234     do {
4235         if ((child->type == XML_ELEMENT_NODE) &&
4236         IS_XSLT_ELEM_FAST(child))
4237         {
4238         if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
4239             XSLT_FUNC_SORT)
4240         {
4241             cctxt->inode->curChildType = XSLT_FUNC_SORT;
4242             xsltParseAnyXSLTElem(cctxt, child);
4243         } else
4244             break;
4245         } else
4246         break;
4247         child = child->next;
4248     } while (child != NULL);
4249     /*
4250     * Parse the sequece constructor.
4251     */
4252     if (child != NULL)
4253         xsltParseSequenceConstructor(cctxt, child);
4254     }
4255     goto exit;
4256 
4257 sequence_constructor:
4258     /*
4259     * Parse the sequence constructor.
4260     */
4261     if (elem->children != NULL)
4262     xsltParseSequenceConstructor(cctxt, elem->children);
4263 
4264     /*
4265     * Register information for vars/params. Only needed if there
4266     * are any following siblings.
4267     */
4268     if ((elem->next != NULL) &&
4269     ((cctxt->inode->type == XSLT_FUNC_VARIABLE) ||
4270      (cctxt->inode->type == XSLT_FUNC_PARAM)))
4271     {
4272     if ((elem->psvi != NULL) &&
4273         (((xsltStyleBasicItemVariablePtr) elem->psvi)->name))
4274     {
4275         xsltCompilerVarInfoPush(cctxt, elem,
4276         ((xsltStyleBasicItemVariablePtr) elem->psvi)->name,
4277         ((xsltStyleBasicItemVariablePtr) elem->psvi)->ns);
4278     }
4279     }
4280 
4281 error:
4282 exit:
4283     xsltCompilerNodePop(cctxt, elem);
4284     return(0);
4285 
4286 internal_err:
4287     xsltCompilerNodePop(cctxt, elem);
4288     return(-1);
4289 }
4290 
4291 /**
4292  * xsltForwardsCompatUnkownItemCreate:
4293  *
4294  * @cctxt: the compilation context
4295  *
4296  * Creates a compiled representation of the unknown
4297  * XSLT instruction.
4298  *
4299  * Returns the compiled representation.
4300  */
4301 static xsltStyleItemUknownPtr
4302 xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
4303 {
4304     xsltStyleItemUknownPtr item;
4305 
4306     item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
4307     if (item == NULL) {
4308     xsltTransformError(NULL, cctxt->style, NULL,
4309         "Internal error in xsltForwardsCompatUnkownItemCreate(): "
4310         "Failed to allocate memory.\n");
4311     cctxt->style->errors++;
4312     return(NULL);
4313     }
4314     memset(item, 0, sizeof(xsltStyleItemUknown));
4315     item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
4316     /*
4317     * Store it in the stylesheet.
4318     */
4319     item->next = cctxt->style->preComps;
4320     cctxt->style->preComps = (xsltElemPreCompPtr) item;
4321     return(item);
4322 }
4323 
4324 /**
4325  * xsltParseUnknownXSLTElem:
4326  *
4327  * @cctxt: the compilation context
4328  * @node: the element of the unknown XSLT instruction
4329  *
4330  * Parses an unknown XSLT element.
4331  * If forwards compatible mode is enabled this will allow
4332  * such an unknown XSLT and; otherwise it is rejected.
4333  *
4334  * Returns 1 in the unknown XSLT instruction is rejected,
4335  *         0 if everything's fine and
4336  *         -1 on API or internal errors.
4337  */
4338 static int
4339 xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
4340                 xmlNodePtr node)
4341 {
4342     if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
4343     return(-1);
4344 
4345     /*
4346     * Detection of handled content of extension instructions.
4347     */
4348     if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4349     cctxt->inode->extContentHandled = 1;
4350     }
4351     if (cctxt->inode->forwardsCompat == 0) {
4352     /*
4353     * We are not in forwards-compatible mode, so raise an error.
4354     */
4355     xsltTransformError(NULL, cctxt->style, node,
4356         "Unknown XSLT element '%s'.\n", node->name);
4357     cctxt->style->errors++;
4358     return(1);
4359     }
4360     /*
4361     * Forwards-compatible mode.
4362     * ------------------------
4363     *
4364     * Parse/compile xsl:fallback elements.
4365     *
4366     * QUESTION: Do we have to raise an error if there's no xsl:fallback?
4367     * ANSWER: No, since in the stylesheet the fallback behaviour might
4368     *  also be provided by using the XSLT function "element-available".
4369     */
4370     if (cctxt->unknownItem == NULL) {
4371     /*
4372     * Create a singleton for all unknown XSLT instructions.
4373     */
4374     cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
4375     if (cctxt->unknownItem == NULL) {
4376         node->psvi = NULL;
4377         return(-1);
4378     }
4379     }
4380     node->psvi = cctxt->unknownItem;
4381     if (node->children == NULL)
4382     return(0);
4383     else {
4384     xmlNodePtr child = node->children;
4385 
4386     xsltCompilerNodePush(cctxt, node);
4387     /*
4388     * Update the in-scope namespaces if needed.
4389     */
4390     if (node->nsDef != NULL)
4391         cctxt->inode->inScopeNs =
4392         xsltCompilerBuildInScopeNsList(cctxt, node);
4393     /*
4394     * Parse all xsl:fallback children.
4395     */
4396     do {
4397         if ((child->type == XML_ELEMENT_NODE) &&
4398         IS_XSLT_ELEM_FAST(child) &&
4399         IS_XSLT_NAME(child, "fallback"))
4400         {
4401         cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
4402         xsltParseAnyXSLTElem(cctxt, child);
4403         }
4404         child = child->next;
4405     } while (child != NULL);
4406 
4407     xsltCompilerNodePop(cctxt, node);
4408     }
4409     return(0);
4410 }
4411 
4412 /**
4413  * xsltParseSequenceConstructor:
4414  *
4415  * @cctxt: the compilation context
4416  * @cur: the start-node of the content to be parsed
4417  *
4418  * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
4419  * This will additionally remove xsl:text elements from the tree.
4420  */
4421 void
4422 xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
4423 {
4424     xsltStyleType type;
4425     xmlNodePtr deleteNode = NULL;
4426 
4427     if (cctxt == NULL) {
4428     xmlGenericError(xmlGenericErrorContext,
4429         "xsltParseSequenceConstructor: Bad arguments\n");
4430     cctxt->style->errors++;
4431     return;
4432     }
4433     /*
4434     * Detection of handled content of extension instructions.
4435     */
4436     if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4437     cctxt->inode->extContentHandled = 1;
4438     }
4439     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
4440     return;
4441     /*
4442     * This is the content reffered to as a "template".
4443     * E.g. an xsl:element has such content model:
4444     * <xsl:element
4445     *   name = { qname }
4446     *   namespace = { uri-reference }
4447     *   use-attribute-sets = qnames>
4448     * <!-- Content: template -->
4449     *
4450     * NOTE that in XSLT-2 the term "template" was abandoned due to
4451     *  confusion with xsl:template and the term "sequence constructor"
4452     *  was introduced instead.
4453     *
4454     * The following XSLT-instructions are allowed to appear:
4455     *  xsl:apply-templates, xsl:call-template, xsl:apply-imports,
4456     *  xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
4457     *  xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
4458     *  xsl:message, xsl:fallback,
4459     *  xsl:processing-instruction, xsl:comment, xsl:element
4460     *  xsl:attribute.
4461     * Additional allowed content:
4462     * 1) extension instructions
4463     * 2) literal result elements
4464     * 3) PCDATA
4465     *
4466     * NOTE that this content model does *not* allow xsl:param.
4467     */
4468     while (cur != NULL) {
4469     if (deleteNode != NULL) {
4470 #ifdef WITH_XSLT_DEBUG_BLANKS
4471         xsltGenericDebug(xsltGenericDebugContext,
4472          "xsltParseSequenceConstructor: removing xsl:text element\n");
4473 #endif
4474         xmlUnlinkNode(deleteNode);
4475         xmlFreeNode(deleteNode);
4476         deleteNode = NULL;
4477     }
4478     if (cur->type == XML_ELEMENT_NODE) {
4479 
4480         if (cur->psvi == xsltXSLTTextMarker) {
4481         /*
4482         * xsl:text elements
4483         * --------------------------------------------------------
4484         */
4485         xmlNodePtr tmp;
4486 
4487         cur->psvi = NULL;
4488         /*
4489         * Mark the xsl:text element for later deletion.
4490         */
4491         deleteNode = cur;
4492         /*
4493         * Validate content.
4494         */
4495         tmp = cur->children;
4496         if (tmp) {
4497             /*
4498             * We don't expect more than one text-node in the
4499             * content, since we already merged adjacent
4500             * text/CDATA-nodes and eliminated PI/comment-nodes.
4501             */
4502             if ((tmp->type == XML_TEXT_NODE) ||
4503             (tmp->next == NULL))
4504             {
4505             /*
4506             * Leave the contained text-node in the tree.
4507             */
4508             xmlUnlinkNode(tmp);
4509             xmlAddPrevSibling(cur, tmp);
4510             } else {
4511             tmp = NULL;
4512             xsltTransformError(NULL, cctxt->style, cur,
4513                 "Element 'xsl:text': Invalid type "
4514                 "of node found in content.\n");
4515             cctxt->style->errors++;
4516             }
4517         }
4518         if (cur->properties) {
4519             xmlAttrPtr attr;
4520             /*
4521             * TODO: We need to report errors for
4522             *  invalid attrs.
4523             */
4524             attr = cur->properties;
4525             do {
4526             if ((attr->ns == NULL) &&
4527                 (attr->name != NULL) &&
4528                 (attr->name[0] == 'd') &&
4529                 xmlStrEqual(attr->name,
4530                 BAD_CAST "disable-output-escaping"))
4531             {
4532                 /*
4533                 * Attr "disable-output-escaping".
4534                 * XSLT-2: This attribute is deprecated.
4535                 */
4536                 if ((attr->children != NULL) &&
4537                 xmlStrEqual(attr->children->content,
4538                 BAD_CAST "yes"))
4539                 {
4540                 /*
4541                 * Disable output escaping for this
4542                 * text node.
4543                 */
4544                 if (tmp)
4545                     tmp->name = xmlStringTextNoenc;
4546                 } else if ((attr->children == NULL) ||
4547                 (attr->children->content == NULL) ||
4548                 (!xmlStrEqual(attr->children->content,
4549                 BAD_CAST "no")))
4550                 {
4551                 xsltTransformError(NULL, cctxt->style,
4552                     cur,
4553                     "Attribute 'disable-output-escaping': "
4554                     "Invalid value. Expected is "
4555                     "'yes' or 'no'.\n");
4556                 cctxt->style->errors++;
4557                 }
4558                 break;
4559             }
4560             attr = attr->next;
4561             } while (attr != NULL);
4562         }
4563         } else if (IS_XSLT_ELEM_FAST(cur)) {
4564         /*
4565         * TODO: Using the XSLT-marker is still not stable yet.
4566         */
4567         /* if (cur->psvi == xsltXSLTElemMarker) { */
4568         /*
4569         * XSLT instructions
4570         * --------------------------------------------------------
4571         */
4572         cur->psvi = NULL;
4573         type = xsltGetXSLTElementTypeByNode(cctxt, cur);
4574         switch (type) {
4575             case XSLT_FUNC_APPLYIMPORTS:
4576             case XSLT_FUNC_APPLYTEMPLATES:
4577             case XSLT_FUNC_ATTRIBUTE:
4578             case XSLT_FUNC_CALLTEMPLATE:
4579             case XSLT_FUNC_CHOOSE:
4580             case XSLT_FUNC_COMMENT:
4581             case XSLT_FUNC_COPY:
4582             case XSLT_FUNC_COPYOF:
4583             case XSLT_FUNC_DOCUMENT: /* Extra one */
4584             case XSLT_FUNC_ELEMENT:
4585             case XSLT_FUNC_FALLBACK:
4586             case XSLT_FUNC_FOREACH:
4587             case XSLT_FUNC_IF:
4588             case XSLT_FUNC_MESSAGE:
4589             case XSLT_FUNC_NUMBER:
4590             case XSLT_FUNC_PI:
4591             case XSLT_FUNC_TEXT:
4592             case XSLT_FUNC_VALUEOF:
4593             case XSLT_FUNC_VARIABLE:
4594             /*
4595             * Parse the XSLT element.
4596             */
4597             cctxt->inode->curChildType = type;
4598             xsltParseAnyXSLTElem(cctxt, cur);
4599             break;
4600             default:
4601             xsltParseUnknownXSLTElem(cctxt, cur);
4602             cur = cur->next;
4603             continue;
4604         }
4605         } else {
4606         /*
4607         * Non-XSLT elements
4608         * -----------------
4609         */
4610         xsltCompilerNodePush(cctxt, cur);
4611         /*
4612         * Update the in-scope namespaces if needed.
4613         */
4614         if (cur->nsDef != NULL)
4615             cctxt->inode->inScopeNs =
4616             xsltCompilerBuildInScopeNsList(cctxt, cur);
4617         /*
4618         * The current element is either a literal result element
4619         * or an extension instruction.
4620         *
4621         * Process attr "xsl:extension-element-prefixes".
4622         * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
4623         * processed by the implementor of the extension function;
4624         * i.e., it won't be handled by the XSLT processor.
4625         */
4626         /* SPEC 1.0:
4627         *   "exclude-result-prefixes" is only allowed on literal
4628         *   result elements and "xsl:exclude-result-prefixes"
4629         *   on xsl:stylesheet/xsl:transform.
4630         * SPEC 2.0:
4631         *   "There are a number of standard attributes
4632         *   that may appear on any XSLT element: specifically
4633         *   version, exclude-result-prefixes,
4634         *   extension-element-prefixes, xpath-default-namespace,
4635         *   default-collation, and use-when."
4636         *
4637         * SPEC 2.0:
4638         *   For literal result elements:
4639         *   "xsl:version, xsl:exclude-result-prefixes,
4640         *    xsl:extension-element-prefixes,
4641         *    xsl:xpath-default-namespace,
4642         *    xsl:default-collation, or xsl:use-when."
4643         */
4644         if (cur->properties)
4645             cctxt->inode->extElemNs =
4646             xsltParseExtElemPrefixes(cctxt,
4647                 cur, cctxt->inode->extElemNs,
4648                 XSLT_ELEMENT_CATEGORY_LRE);
4649         /*
4650         * Eval if we have an extension instruction here.
4651         */
4652         if ((cur->ns != NULL) &&
4653             (cctxt->inode->extElemNs != NULL) &&
4654             (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
4655         {
4656             /*
4657             * Extension instructions
4658             * ----------------------------------------------------
4659             * Mark the node information.
4660             */
4661             cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
4662             cctxt->inode->extContentHandled = 0;
4663             if (cur->psvi != NULL) {
4664             cur->psvi = NULL;
4665             /*
4666             * TODO: Temporary sanity check.
4667             */
4668             xsltTransformError(NULL, cctxt->style, cur,
4669                 "Internal error in xsltParseSequenceConstructor(): "
4670                 "Occupied PSVI field.\n");
4671             cctxt->style->errors++;
4672             cur = cur->next;
4673             continue;
4674             }
4675             cur->psvi = (void *)
4676             xsltPreComputeExtModuleElement(cctxt->style, cur);
4677 
4678             if (cur->psvi == NULL) {
4679             /*
4680             * OLD COMMENT: "Unknown element, maybe registered
4681             *  at the context level. Mark it for later
4682             *  recognition."
4683             * QUESTION: What does the xsltExtMarker mean?
4684             *  ANSWER: It is used in
4685             *   xsltApplySequenceConstructor() at
4686             *   transformation-time to look out for extension
4687             *   registered in the transformation context.
4688             */
4689             cur->psvi = (void *) xsltExtMarker;
4690             }
4691             /*
4692             * BIG NOTE: Now the ugly part. In previous versions
4693             *  of Libxslt (until 1.1.16), all the content of an
4694             *  extension instruction was processed and compiled without
4695             *  the need of the extension-author to explicitely call
4696             *  such a processing;.We now need to mimic this old
4697             *  behaviour in order to avoid breaking old code
4698             *  on the extension-author's side.
4699             * The mechanism:
4700             *  1) If the author does *not* set the
4701             *    compile-time-flag @extContentHandled, then we'll
4702             *    parse the content assuming that it's a "template"
4703             *    (or "sequence constructor in XSLT 2.0 terms).
4704             *    NOTE: If the extension is registered at
4705             *    transformation-time only, then there's no way of
4706             *    knowing that content shall be valid, and we'll
4707             *    process the content the same way.
4708             *  2) If the author *does* set the flag, then we'll assume
4709             *   that the author has handled the parsing him/herself
4710             *   (e.g. called xsltParseSequenceConstructor(), etc.
4711             *   explicitely in his/her code).
4712             */
4713             if ((cur->children != NULL) &&
4714             (cctxt->inode->extContentHandled == 0))
4715             {
4716             /*
4717             * Default parsing of the content using the
4718             * sequence-constructor model.
4719             */
4720             xsltParseSequenceConstructor(cctxt, cur->children);
4721             }
4722         } else {
4723             /*
4724             * Literal result element
4725             * ----------------------------------------------------
4726             * Allowed XSLT attributes:
4727             *  xsl:extension-element-prefixes CDATA #IMPLIED
4728             *  xsl:exclude-result-prefixes CDATA #IMPLIED
4729             *  TODO: xsl:use-attribute-sets %qnames; #IMPLIED
4730             *  xsl:version NMTOKEN #IMPLIED
4731             */
4732             cur->psvi = NULL;
4733             cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
4734             if (cur->properties != NULL) {
4735             xmlAttrPtr attr = cur->properties;
4736             /*
4737             * Attribute "xsl:exclude-result-prefixes".
4738             */
4739             cctxt->inode->exclResultNs =
4740                 xsltParseExclResultPrefixes(cctxt, cur,
4741                 cctxt->inode->exclResultNs,
4742                 XSLT_ELEMENT_CATEGORY_LRE);
4743             /*
4744             * Attribute "xsl:version".
4745             */
4746             xsltParseAttrXSLTVersion(cctxt, cur,
4747                 XSLT_ELEMENT_CATEGORY_LRE);
4748             /*
4749             * Report invalid XSLT attributes.
4750             * For XSLT 1.0 only xsl:use-attribute-sets is allowed
4751             * next to xsl:version, xsl:exclude-result-prefixes and
4752             * xsl:extension-element-prefixes.
4753             *
4754             * Mark all XSLT attributes, in order to skip such
4755             * attributes when instantiating the LRE.
4756             */
4757             do {
4758                 if ((attr->psvi != xsltXSLTAttrMarker) &&
4759                 IS_XSLT_ATTR_FAST(attr))
4760                 {
4761                 if (! xmlStrEqual(attr->name,
4762                     BAD_CAST "use-attribute-sets"))
4763                 {
4764                     xsltTransformError(NULL, cctxt->style,
4765                     cur,
4766                     "Unknown XSLT attribute '%s'.\n",
4767                     attr->name);
4768                     cctxt->style->errors++;
4769                 } else {
4770                     /*
4771                     * XSLT attr marker.
4772                     */
4773                     attr->psvi = (void *) xsltXSLTAttrMarker;
4774                 }
4775                 }
4776                 attr = attr->next;
4777             } while (attr != NULL);
4778             }
4779             /*
4780             * Create/reuse info for the literal result element.
4781             */
4782             if (cctxt->inode->nsChanged)
4783             xsltLREInfoCreate(cctxt, cur, 1);
4784             cur->psvi = cctxt->inode->litResElemInfo;
4785             /*
4786             * Apply ns-aliasing on the element and on its attributes.
4787             */
4788             if (cctxt->hasNsAliases)
4789             xsltLREBuildEffectiveNs(cctxt, cur);
4790             /*
4791             * Compile attribute value templates (AVT).
4792             */
4793             if (cur->properties) {
4794             xmlAttrPtr attr = cur->properties;
4795 
4796             while (attr != NULL) {
4797                 xsltCompileAttr(cctxt->style, attr);
4798                 attr = attr->next;
4799             }
4800             }
4801             /*
4802             * Parse the content, which is defined to be a "template"
4803             * (or "sequence constructor" in XSLT 2.0 terms).
4804             */
4805             if (cur->children != NULL) {
4806             xsltParseSequenceConstructor(cctxt, cur->children);
4807             }
4808         }
4809         /*
4810         * Leave the non-XSLT element.
4811         */
4812         xsltCompilerNodePop(cctxt, cur);
4813         }
4814     }
4815     cur = cur->next;
4816     }
4817     if (deleteNode != NULL) {
4818 #ifdef WITH_XSLT_DEBUG_BLANKS
4819     xsltGenericDebug(xsltGenericDebugContext,
4820         "xsltParseSequenceConstructor: removing xsl:text element\n");
4821 #endif
4822     xmlUnlinkNode(deleteNode);
4823     xmlFreeNode(deleteNode);
4824     deleteNode = NULL;
4825     }
4826 }
4827 
4828 /**
4829  * xsltParseTemplateContent:
4830  * @style:  the XSLT stylesheet
4831  * @templ:  the node containing the content to be parsed
4832  *
4833  * Parses and compiles the content-model of an xsl:template element.
4834  * Note that this is *not* the "template" content model (or "sequence
4835  *  constructor" in XSLT 2.0); it it allows addional xsl:param
4836  *  elements as immediate children of @templ.
4837  *
4838  * Called by:
4839  *   exsltFuncFunctionComp() (EXSLT, functions.c)
4840  *   So this is intended to be called from extension functions.
4841  */
4842 void
4843 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
4844     if ((style == NULL) || (templ == NULL) ||
4845         (templ->type == XML_NAMESPACE_DECL))
4846     return;
4847 
4848     /*
4849     * Detection of handled content of extension instructions.
4850     */
4851     if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
4852     XSLT_CCTXT(style)->inode->extContentHandled = 1;
4853     }
4854 
4855     if (templ->children != NULL) {
4856     xmlNodePtr child = templ->children;
4857     /*
4858     * Process xsl:param elements, which can only occur as the
4859     * immediate children of xsl:template (well, and of any
4860     * user-defined extension instruction if needed).
4861     */
4862     do {
4863         if ((child->type == XML_ELEMENT_NODE) &&
4864         IS_XSLT_ELEM_FAST(child) &&
4865         IS_XSLT_NAME(child, "param"))
4866         {
4867         XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
4868         xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
4869         } else
4870         break;
4871         child = child->next;
4872     } while (child != NULL);
4873     /*
4874     * Parse the content and register the pattern.
4875     */
4876     xsltParseSequenceConstructor(XSLT_CCTXT(style), child);
4877     }
4878 }
4879 
4880 #else /* XSLT_REFACTORED */
4881 
4882 /**
4883  * xsltParseTemplateContent:
4884  * @style:  the XSLT stylesheet
4885  * @templ:  the container node (can be a document for literal results)
4886  *
4887  * parse a template content-model
4888  * Clean-up the template content from unwanted ignorable blank nodes
4889  * and process xslt:text
4890  */
4891 void
4892 xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
4893     xmlNodePtr cur, delete;
4894 
4895     if ((style == NULL) || (templ == NULL) ||
4896         (templ->type == XML_NAMESPACE_DECL)) return;
4897 
4898     /*
4899      * This content comes from the stylesheet
4900      * For stylesheets, the set of whitespace-preserving
4901      * element names consists of just xsl:text.
4902      */
4903     cur = templ->children;
4904     delete = NULL;
4905     while (cur != NULL) {
4906     if (delete != NULL) {
4907 #ifdef WITH_XSLT_DEBUG_BLANKS
4908         xsltGenericDebug(xsltGenericDebugContext,
4909          "xsltParseTemplateContent: removing text\n");
4910 #endif
4911         xmlUnlinkNode(delete);
4912         xmlFreeNode(delete);
4913         delete = NULL;
4914     }
4915     if (IS_XSLT_ELEM(cur)) {
4916             xsltStylePreCompute(style, cur);
4917 
4918         if (IS_XSLT_NAME(cur, "text")) {
4919         /*
4920         * TODO: Processing of xsl:text should be moved to
4921         *   xsltPreprocessStylesheet(), since otherwise this
4922         *   will be performed for every multiply included
4923         *   stylesheet; i.e. this here is not skipped with
4924         *   the use of the style->nopreproc flag.
4925         */
4926         if (cur->children != NULL) {
4927             xmlChar *prop;
4928             xmlNodePtr text = cur->children, next;
4929             int noesc = 0;
4930 
4931             prop = xmlGetNsProp(cur,
4932             (const xmlChar *)"disable-output-escaping",
4933             NULL);
4934             if (prop != NULL) {
4935 #ifdef WITH_XSLT_DEBUG_PARSING
4936             xsltGenericDebug(xsltGenericDebugContext,
4937                  "Disable escaping: %s\n", text->content);
4938 #endif
4939             if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
4940                 noesc = 1;
4941             } else if (!xmlStrEqual(prop,
4942                         (const xmlChar *)"no")){
4943                 xsltTransformError(NULL, style, cur,
4944          "xsl:text: disable-output-escaping allows only yes or no\n");
4945                 style->warnings++;
4946 
4947             }
4948             xmlFree(prop);
4949             }
4950 
4951             while (text != NULL) {
4952             if (text->type == XML_COMMENT_NODE) {
4953                 text = text->next;
4954                 continue;
4955             }
4956             if ((text->type != XML_TEXT_NODE) &&
4957                  (text->type != XML_CDATA_SECTION_NODE)) {
4958                 xsltTransformError(NULL, style, cur,
4959          "xsltParseTemplateContent: xslt:text content problem\n");
4960                 style->errors++;
4961                 break;
4962             }
4963             if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
4964                 text->name = xmlStringTextNoenc;
4965             text = text->next;
4966             }
4967 
4968             /*
4969              * replace xsl:text by the list of childs
4970              */
4971             if (text == NULL) {
4972             text = cur->children;
4973             while (text != NULL) {
4974                 if ((style->internalized) &&
4975                     (text->content != NULL) &&
4976                     (!xmlDictOwns(style->dict, text->content))) {
4977 
4978                 /*
4979                  * internalize the text string
4980                  */
4981                 if (text->doc->dict != NULL) {
4982                     const xmlChar *tmp;
4983 
4984                     tmp = xmlDictLookup(text->doc->dict,
4985                                         text->content, -1);
4986                     if (tmp != text->content) {
4987                         xmlNodeSetContent(text, NULL);
4988                     text->content = (xmlChar *) tmp;
4989                     }
4990                 }
4991                 }
4992 
4993                 next = text->next;
4994                 xmlUnlinkNode(text);
4995                 xmlAddPrevSibling(cur, text);
4996                 text = next;
4997             }
4998             }
4999         }
5000         delete = cur;
5001         goto skip_children;
5002         }
5003     }
5004     else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
5005         (xsltCheckExtPrefix(style, cur->ns->prefix)))
5006     {
5007         /*
5008          * okay this is an extension element compile it too
5009          */
5010         xsltStylePreCompute(style, cur);
5011     }
5012     else if (cur->type == XML_ELEMENT_NODE)
5013     {
5014         /*
5015          * This is an element which will be output as part of the
5016          * template exectution, precompile AVT if found.
5017          */
5018         if ((cur->ns == NULL) && (style->defaultAlias != NULL)) {
5019         cur->ns = xmlSearchNsByHref(cur->doc, cur,
5020             style->defaultAlias);
5021         }
5022         if (cur->properties != NULL) {
5023             xmlAttrPtr attr = cur->properties;
5024 
5025         while (attr != NULL) {
5026             xsltCompileAttr(style, attr);
5027             attr = attr->next;
5028         }
5029         }
5030     }
5031     /*
5032      * Skip to next node
5033      */
5034     if (cur->children != NULL) {
5035         if (cur->children->type != XML_ENTITY_DECL) {
5036         cur = cur->children;
5037         continue;
5038         }
5039     }
5040 skip_children:
5041     if (cur->next != NULL) {
5042         cur = cur->next;
5043         continue;
5044     }
5045 
5046     do {
5047         cur = cur->parent;
5048         if (cur == NULL)
5049         break;
5050         if (cur == templ) {
5051         cur = NULL;
5052         break;
5053         }
5054         if (cur->next != NULL) {
5055         cur = cur->next;
5056         break;
5057         }
5058     } while (cur != NULL);
5059     }
5060     if (delete != NULL) {
5061 #ifdef WITH_XSLT_DEBUG_PARSING
5062     xsltGenericDebug(xsltGenericDebugContext,
5063      "xsltParseTemplateContent: removing text\n");
5064 #endif
5065     xmlUnlinkNode(delete);
5066     xmlFreeNode(delete);
5067     delete = NULL;
5068     }
5069 
5070     /*
5071      * Skip the first params
5072      */
5073     cur = templ->children;
5074     while (cur != NULL) {
5075     if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
5076         break;
5077     cur = cur->next;
5078     }
5079 
5080     /*
5081      * Browse the remainder of the template
5082      */
5083     while (cur != NULL) {
5084     if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
5085         xmlNodePtr param = cur;
5086 
5087         xsltTransformError(NULL, style, cur,
5088         "xsltParseTemplateContent: ignoring misplaced param element\n");
5089         if (style != NULL) style->warnings++;
5090             cur = cur->next;
5091         xmlUnlinkNode(param);
5092         xmlFreeNode(param);
5093     } else
5094         break;
5095     }
5096 }
5097 
5098 #endif /* else XSLT_REFACTORED */
5099 
5100 /**
5101  * xsltParseStylesheetKey:
5102  * @style:  the XSLT stylesheet
5103  * @key:  the "key" element
5104  *
5105  * <!-- Category: top-level-element -->
5106  * <xsl:key name = qname, match = pattern, use = expression />
5107  *
5108  * parse an XSLT stylesheet key definition and register it
5109  */
5110 
5111 static void
5112 xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
5113     xmlChar *prop = NULL;
5114     xmlChar *use = NULL;
5115     xmlChar *match = NULL;
5116     xmlChar *name = NULL;
5117     xmlChar *nameURI = NULL;
5118 
5119     if ((style == NULL) || (key == NULL) || (key->type != XML_ELEMENT_NODE))
5120     return;
5121 
5122     /*
5123      * Get arguments
5124      */
5125     prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
5126     if (prop != NULL) {
5127         const xmlChar *URI;
5128 
5129     /*
5130     * TODO: Don't use xsltGetQNameURI().
5131     */
5132     URI = xsltGetQNameURI(key, &prop);
5133     if (prop == NULL) {
5134         if (style != NULL) style->errors++;
5135         goto error;
5136     } else {
5137         name = prop;
5138         if (URI != NULL)
5139         nameURI = xmlStrdup(URI);
5140     }
5141 #ifdef WITH_XSLT_DEBUG_PARSING
5142     xsltGenericDebug(xsltGenericDebugContext,
5143          "xsltParseStylesheetKey: name %s\n", name);
5144 #endif
5145     } else {
5146     xsltTransformError(NULL, style, key,
5147         "xsl:key : error missing name\n");
5148     if (style != NULL) style->errors++;
5149     goto error;
5150     }
5151 
5152     match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
5153     if (match == NULL) {
5154     xsltTransformError(NULL, style, key,
5155         "xsl:key : error missing match\n");
5156     if (style != NULL) style->errors++;
5157     goto error;
5158     }
5159 
5160     use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
5161     if (use == NULL) {
5162     xsltTransformError(NULL, style, key,
5163         "xsl:key : error missing use\n");
5164     if (style != NULL) style->errors++;
5165     goto error;
5166     }
5167 
5168     /*
5169      * register the keys
5170      */
5171     xsltAddKey(style, name, nameURI, match, use, key);
5172 
5173 
5174 error:
5175     if (use != NULL)
5176     xmlFree(use);
5177     if (match != NULL)
5178     xmlFree(match);
5179     if (name != NULL)
5180     xmlFree(name);
5181     if (nameURI != NULL)
5182     xmlFree(nameURI);
5183 
5184     if (key->children != NULL) {
5185     xsltParseContentError(style, key->children);
5186     }
5187 }
5188 
5189 #ifdef XSLT_REFACTORED
5190 /**
5191  * xsltParseXSLTTemplate:
5192  * @style:  the XSLT stylesheet
5193  * @template:  the "template" element
5194  *
5195  * parse an XSLT stylesheet template building the associated structures
5196  * TODO: Is @style ever expected to be NULL?
5197  *
5198  * Called from:
5199  *   xsltParseXSLTStylesheet()
5200  *   xsltParseStylesheetTop()
5201  */
5202 
5203 static void
5204 xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
5205     xsltTemplatePtr templ;
5206     xmlChar *prop;
5207     double  priority;
5208 
5209     if ((cctxt == NULL) || (templNode == NULL) ||
5210         (templNode->type != XML_ELEMENT_NODE))
5211     return;
5212 
5213     /*
5214      * Create and link the structure
5215      */
5216     templ = xsltNewTemplate();
5217     if (templ == NULL)
5218     return;
5219 
5220     xsltCompilerNodePush(cctxt, templNode);
5221     if (templNode->nsDef != NULL)
5222     cctxt->inode->inScopeNs =
5223         xsltCompilerBuildInScopeNsList(cctxt, templNode);
5224 
5225     templ->next = cctxt->style->templates;
5226     cctxt->style->templates = templ;
5227     templ->style = cctxt->style;
5228 
5229     /*
5230     * Attribute "mode".
5231     */
5232     prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);
5233     if (prop != NULL) {
5234         const xmlChar *modeURI;
5235 
5236     /*
5237     * TODO: We need a standardized function for extraction
5238     *  of namespace names and local names from QNames.
5239     *  Don't use xsltGetQNameURI() as it cannot channe�
5240     *  reports through the context.
5241     */
5242     modeURI = xsltGetQNameURI(templNode, &prop);
5243     if (prop == NULL) {
5244         cctxt->style->errors++;
5245         goto error;
5246     }
5247     templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);
5248     xmlFree(prop);
5249     prop = NULL;
5250     if (xmlValidateNCName(templ->mode, 0)) {
5251         xsltTransformError(NULL, cctxt->style, templNode,
5252         "xsl:template: Attribute 'mode': The local part '%s' "
5253         "of the value is not a valid NCName.\n", templ->name);
5254         cctxt->style->errors++;
5255         goto error;
5256     }
5257     if (modeURI != NULL)
5258         templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);
5259 #ifdef WITH_XSLT_DEBUG_PARSING
5260     xsltGenericDebug(xsltGenericDebugContext,
5261          "xsltParseXSLTTemplate: mode %s\n", templ->mode);
5262 #endif
5263     }
5264     /*
5265     * Attribute "match".
5266     */
5267     prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);
5268     if (prop != NULL) {
5269     templ->match  = prop;
5270     prop = NULL;
5271     }
5272     /*
5273     * Attribute "priority".
5274     */
5275     prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);
5276     if (prop != NULL) {
5277     priority = xmlXPathStringEvalNumber(prop);
5278     templ->priority = (float) priority;
5279     xmlFree(prop);
5280     prop = NULL;
5281     }
5282     /*
5283     * Attribute "name".
5284     */
5285     prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);
5286     if (prop != NULL) {
5287         const xmlChar *nameURI;
5288     xsltTemplatePtr curTempl;
5289 
5290     /*
5291     * TODO: Don't use xsltGetQNameURI().
5292     */
5293     nameURI = xsltGetQNameURI(templNode, &prop);
5294     if (prop == NULL) {
5295         cctxt->style->errors++;
5296         goto error;
5297     }
5298     templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);
5299     xmlFree(prop);
5300     prop = NULL;
5301     if (xmlValidateNCName(templ->name, 0)) {
5302         xsltTransformError(NULL, cctxt->style, templNode,
5303         "xsl:template: Attribute 'name': The local part '%s' of "
5304         "the value is not a valid NCName.\n", templ->name);
5305         cctxt->style->errors++;
5306         goto error;
5307     }
5308     if (nameURI != NULL)
5309         templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);
5310     curTempl = templ->next;
5311     while (curTempl != NULL) {
5312         if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&
5313         xmlStrEqual(curTempl->nameURI, nameURI) ) ||
5314         (nameURI == NULL && curTempl->nameURI == NULL &&
5315         xmlStrEqual(curTempl->name, templ->name)))
5316         {
5317         xsltTransformError(NULL, cctxt->style, templNode,
5318             "xsl:template: error duplicate name '%s'\n", templ->name);
5319         cctxt->style->errors++;
5320         goto error;
5321         }
5322         curTempl = curTempl->next;
5323     }
5324     }
5325     if (templNode->children != NULL) {
5326     xsltParseTemplateContent(cctxt->style, templNode);
5327     /*
5328     * MAYBE TODO: Custom behaviour: In order to stay compatible with
5329     * Xalan and MSXML(.NET), we could allow whitespace
5330     * to appear before an xml:param element; this whitespace
5331     * will additionally become part of the "template".
5332     * NOTE that this is totally deviates from the spec, but
5333     * is the de facto behaviour of Xalan and MSXML(.NET).
5334     * Personally I wouldn't allow this, since if we have:
5335     * <xsl:template ...xml:space="preserve">
5336     *   <xsl:param name="foo"/>
5337     *   <xsl:param name="bar"/>
5338     *   <xsl:param name="zoo"/>
5339     * ... the whitespace between every xsl:param would be
5340     * added to the result tree.
5341     */
5342     }
5343 
5344     templ->elem = templNode;
5345     templ->content = templNode->children;
5346     xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI);
5347 
5348 error:
5349     xsltCompilerNodePop(cctxt, templNode);
5350     return;
5351 }
5352 
5353 #else /* XSLT_REFACTORED */
5354 
5355 /**
5356  * xsltParseStylesheetTemplate:
5357  * @style:  the XSLT stylesheet
5358  * @template:  the "template" element
5359  *
5360  * parse an XSLT stylesheet template building the associated structures
5361  */
5362 
5363 static void
5364 xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
5365     xsltTemplatePtr ret;
5366     xmlChar *prop;
5367     xmlChar *mode = NULL;
5368     xmlChar *modeURI = NULL;
5369     double  priority;
5370 
5371     if ((style == NULL) || (template == NULL) ||
5372         (template->type != XML_ELEMENT_NODE))
5373     return;
5374 
5375     /*
5376      * Create and link the structure
5377      */
5378     ret = xsltNewTemplate();
5379     if (ret == NULL)
5380     return;
5381     ret->next = style->templates;
5382     style->templates = ret;
5383     ret->style = style;
5384 
5385     /*
5386      * Get inherited namespaces
5387      */
5388     /*
5389     * TODO: Apply the optimized in-scope-namespace mechanism
5390     *   as for the other XSLT instructions.
5391     */
5392     xsltGetInheritedNsList(style, ret, template);
5393 
5394     /*
5395      * Get arguments
5396      */
5397     prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);
5398     if (prop != NULL) {
5399         const xmlChar *URI;
5400 
5401     /*
5402     * TODO: Don't use xsltGetQNameURI().
5403     */
5404     URI = xsltGetQNameURI(template, &prop);
5405     if (prop == NULL) {
5406         if (style != NULL) style->errors++;
5407         goto error;
5408     } else {
5409         mode = prop;
5410         if (URI != NULL)
5411         modeURI = xmlStrdup(URI);
5412     }
5413     ret->mode = xmlDictLookup(style->dict, mode, -1);
5414     ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);
5415 #ifdef WITH_XSLT_DEBUG_PARSING
5416     xsltGenericDebug(xsltGenericDebugContext,
5417          "xsltParseStylesheetTemplate: mode %s\n", mode);
5418 #endif
5419         if (mode != NULL) xmlFree(mode);
5420     if (modeURI != NULL) xmlFree(modeURI);
5421     }
5422     prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);
5423     if (prop != NULL) {
5424     if (ret->match != NULL) xmlFree(ret->match);
5425     ret->match  = prop;
5426     }
5427 
5428     prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);
5429     if (prop != NULL) {
5430     priority = xmlXPathStringEvalNumber(prop);
5431     ret->priority = (float) priority;
5432     xmlFree(prop);
5433     }
5434 
5435     prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);
5436     if (prop != NULL) {
5437         const xmlChar *URI;
5438 
5439     /*
5440     * TODO: Don't use xsltGetQNameURI().
5441     */
5442     URI = xsltGetQNameURI(template, &prop);
5443     if (prop == NULL) {
5444         if (style != NULL) style->errors++;
5445         goto error;
5446     } else {
5447         if (xmlValidateNCName(prop,0)) {
5448             xsltTransformError(NULL, style, template,
5449                 "xsl:template : error invalid name '%s'\n", prop);
5450         if (style != NULL) style->errors++;
5451                 xmlFree(prop);
5452         goto error;
5453         }
5454         ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
5455         xmlFree(prop);
5456         prop = NULL;
5457         if (URI != NULL)
5458         ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);
5459         else
5460         ret->nameURI = NULL;
5461     }
5462     }
5463 
5464     /*
5465      * parse the content and register the pattern
5466      */
5467     xsltParseTemplateContent(style, template);
5468     ret->elem = template;
5469     ret->content = template->children;
5470     xsltAddTemplate(style, ret, ret->mode, ret->modeURI);
5471 
5472 error:
5473     return;
5474 }
5475 
5476 #endif /* else XSLT_REFACTORED */
5477 
5478 #ifdef XSLT_REFACTORED
5479 
5480 /**
5481  * xsltIncludeComp:
5482  * @cctxt: the compilation contenxt
5483  * @node:  the xsl:include node
5484  *
5485  * Process the xslt include node on the source node
5486  */
5487 static xsltStyleItemIncludePtr
5488 xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) {
5489     xsltStyleItemIncludePtr item;
5490 
5491     if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
5492     return(NULL);
5493 
5494     node->psvi = NULL;
5495     item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude));
5496     if (item == NULL) {
5497     xsltTransformError(NULL, cctxt->style, node,
5498         "xsltIncludeComp : malloc failed\n");
5499     cctxt->style->errors++;
5500     return(NULL);
5501     }
5502     memset(item, 0, sizeof(xsltStyleItemInclude));
5503 
5504     node->psvi = item;
5505     item->inst = node;
5506     item->type = XSLT_FUNC_INCLUDE;
5507 
5508     item->next = cctxt->style->preComps;
5509     cctxt->style->preComps = (xsltElemPreCompPtr) item;
5510 
5511     return(item);
5512 }
5513 
5514 /**
5515  * xsltParseFindTopLevelElem:
5516  */
5517 static int
5518 xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,
5519                   xmlNodePtr cur,
5520                   const xmlChar *name,
5521                   const xmlChar *namespaceURI,
5522                   int breakOnOtherElem,
5523                   xmlNodePtr *resultNode)
5524 {
5525     if (name == NULL)
5526     return(-1);
5527 
5528     *resultNode = NULL;
5529     while (cur != NULL) {
5530     if (cur->type == XML_ELEMENT_NODE) {
5531         if ((cur->ns != NULL) && (cur->name != NULL)) {
5532         if ((*(cur->name) == *name) &&
5533             xmlStrEqual(cur->name, name) &&
5534             xmlStrEqual(cur->ns->href, namespaceURI))
5535         {
5536             *resultNode = cur;
5537             return(1);
5538         }
5539         }
5540         if (breakOnOtherElem)
5541         break;
5542     }
5543     cur = cur->next;
5544     }
5545     *resultNode = cur;
5546     return(0);
5547 }
5548 
5549 static int
5550 xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,
5551               xmlNodePtr node,
5552               xsltStyleType type)
5553 {
5554     int ret = 0;
5555 
5556     /*
5557     * TODO: The reason why this function exists:
5558     *  due to historical reasons some of the
5559     *  top-level declarations are processed by functions
5560     *  in other files. Since we need still to set
5561     *  up the node-info and generate information like
5562     *  in-scope namespaces, this is a wrapper around
5563     *  those old parsing functions.
5564     */
5565     xsltCompilerNodePush(cctxt, node);
5566     if (node->nsDef != NULL)
5567     cctxt->inode->inScopeNs =
5568         xsltCompilerBuildInScopeNsList(cctxt, node);
5569     cctxt->inode->type = type;
5570 
5571     switch (type) {
5572     case XSLT_FUNC_INCLUDE:
5573         {
5574         int oldIsInclude;
5575 
5576         if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL)
5577             goto exit;
5578         /*
5579         * Mark this stylesheet tree as being currently included.
5580         */
5581         oldIsInclude = cctxt->isInclude;
5582         cctxt->isInclude = 1;
5583 
5584         if (xsltParseStylesheetInclude(cctxt->style, node) != 0) {
5585             cctxt->style->errors++;
5586         }
5587         cctxt->isInclude = oldIsInclude;
5588         }
5589         break;
5590     case XSLT_FUNC_PARAM:
5591         xsltStylePreCompute(cctxt->style, node);
5592         xsltParseGlobalParam(cctxt->style, node);
5593         break;
5594     case XSLT_FUNC_VARIABLE:
5595         xsltStylePreCompute(cctxt->style, node);
5596         xsltParseGlobalVariable(cctxt->style, node);
5597         break;
5598     case XSLT_FUNC_ATTRSET:
5599         xsltParseStylesheetAttributeSet(cctxt->style, node);
5600         break;
5601     default:
5602         xsltTransformError(NULL, cctxt->style, node,
5603         "Internal error: (xsltParseTopLevelXSLTElem) "
5604         "Cannot handle this top-level declaration.\n");
5605         cctxt->style->errors++;
5606         ret = -1;
5607     }
5608 
5609 exit:
5610     xsltCompilerNodePop(cctxt, node);
5611 
5612     return(ret);
5613 }
5614 
5615 #if 0
5616 static int
5617 xsltParseRemoveWhitespace(xmlNodePtr node)
5618 {
5619     if ((node == NULL) || (node->children == NULL))
5620     return(0);
5621     else {
5622     xmlNodePtr delNode = NULL, child = node->children;
5623 
5624     do {
5625         if (delNode) {
5626         xmlUnlinkNode(delNode);
5627         xmlFreeNode(delNode);
5628         delNode = NULL;
5629         }
5630         if (((child->type == XML_TEXT_NODE) ||
5631          (child->type == XML_CDATA_SECTION_NODE)) &&
5632         (IS_BLANK_NODE(child)))
5633         delNode = child;
5634         child = child->next;
5635     } while (child != NULL);
5636     if (delNode) {
5637         xmlUnlinkNode(delNode);
5638         xmlFreeNode(delNode);
5639         delNode = NULL;
5640     }
5641     }
5642     return(0);
5643 }
5644 #endif
5645 
5646 static int
5647 xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
5648 {
5649 #ifdef WITH_XSLT_DEBUG_PARSING
5650     int templates = 0;
5651 #endif
5652     xmlNodePtr cur, start = NULL;
5653     xsltStylesheetPtr style;
5654 
5655     if ((cctxt == NULL) || (node == NULL) ||
5656     (node->type != XML_ELEMENT_NODE))
5657     return(-1);
5658 
5659     style = cctxt->style;
5660     /*
5661     * At this stage all import declarations of all stylesheet modules
5662     * with the same stylesheet level have been processed.
5663     * Now we can safely parse the rest of the declarations.
5664     */
5665     if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include"))
5666     {
5667     xsltDocumentPtr include;
5668     /*
5669     * URGENT TODO: Make this work with simplified stylesheets!
5670     *   I.e., when we won't find an xsl:stylesheet element.
5671     */
5672     /*
5673     * This is as include declaration.
5674     */
5675     include = ((xsltStyleItemIncludePtr) node->psvi)->include;
5676     if (include == NULL) {
5677         /* TODO: raise error? */
5678         return(-1);
5679     }
5680     /*
5681     * TODO: Actually an xsl:include should locate an embedded
5682     *  stylesheet as well; so the document-element won't always
5683     *  be the element where the actual stylesheet is rooted at.
5684     *  But such embedded stylesheets are not supported by Libxslt yet.
5685     */
5686     node = xmlDocGetRootElement(include->doc);
5687     if (node == NULL) {
5688         return(-1);
5689     }
5690     }
5691 
5692     if (node->children == NULL)
5693     return(0);
5694     /*
5695     * Push the xsl:stylesheet/xsl:transform element.
5696     */
5697     xsltCompilerNodePush(cctxt, node);
5698     cctxt->inode->isRoot = 1;
5699     cctxt->inode->nsChanged = 0;
5700     /*
5701     * Start with the naked dummy info for literal result elements.
5702     */
5703     cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;
5704 
5705     /*
5706     * In every case, we need to have
5707     * the in-scope namespaces of the element, where the
5708     * stylesheet is rooted at, regardless if it's an XSLT
5709     * instruction or a literal result instruction (or if
5710     * this is an embedded stylesheet).
5711     */
5712     cctxt->inode->inScopeNs =
5713     xsltCompilerBuildInScopeNsList(cctxt, node);
5714 
5715     /*
5716     * Process attributes of xsl:stylesheet/xsl:transform.
5717     * --------------------------------------------------
5718     * Allowed are:
5719     *  id = id
5720     *  extension-element-prefixes = tokens
5721     *  exclude-result-prefixes = tokens
5722     *  version = number (mandatory)
5723     */
5724     if (xsltParseAttrXSLTVersion(cctxt, node,
5725     XSLT_ELEMENT_CATEGORY_XSLT) == 0)
5726     {
5727     /*
5728     * Attribute "version".
5729     * XSLT 1.0: "An xsl:stylesheet element *must* have a version
5730     *  attribute, indicating the version of XSLT that the
5731     *  stylesheet requires".
5732     * The root element of a simplified stylesheet must also have
5733     * this attribute.
5734     */
5735 #ifdef XSLT_REFACTORED_MANDATORY_VERSION
5736     if (isXsltElem)
5737         xsltTransformError(NULL, cctxt->style, node,
5738         "The attribute 'version' is missing.\n");
5739     cctxt->style->errors++;
5740 #else
5741     /* OLD behaviour. */
5742     xsltTransformError(NULL, cctxt->style, node,
5743         "xsl:version is missing: document may not be a stylesheet\n");
5744     cctxt->style->warnings++;
5745 #endif
5746     }
5747     /*
5748     * The namespaces declared by the attributes
5749     *  "extension-element-prefixes" and
5750     *  "exclude-result-prefixes" are local to *this*
5751     *  stylesheet tree; i.e., they are *not* visible to
5752     *  other stylesheet-modules, whether imported or included.
5753     *
5754     * Attribute "extension-element-prefixes".
5755     */
5756     cctxt->inode->extElemNs =
5757     xsltParseExtElemPrefixes(cctxt, node, NULL,
5758         XSLT_ELEMENT_CATEGORY_XSLT);
5759     /*
5760     * Attribute "exclude-result-prefixes".
5761     */
5762     cctxt->inode->exclResultNs =
5763     xsltParseExclResultPrefixes(cctxt, node, NULL,
5764         XSLT_ELEMENT_CATEGORY_XSLT);
5765     /*
5766     * Create/reuse info for the literal result element.
5767     */
5768     if (cctxt->inode->nsChanged)
5769     xsltLREInfoCreate(cctxt, node, 0);
5770     /*
5771     * Processed top-level elements:
5772     * ----------------------------
5773     *  xsl:variable, xsl:param (QName, in-scope ns,
5774     *    expression (vars allowed))
5775     *  xsl:attribute-set (QName, in-scope ns)
5776     *  xsl:strip-space, xsl:preserve-space (XPath NameTests,
5777     *    in-scope ns)
5778     *    I *think* global scope, merge with includes
5779     *  xsl:output (QName, in-scope ns)
5780     *  xsl:key (QName, in-scope ns, pattern,
5781     *    expression (vars *not* allowed))
5782     *  xsl:decimal-format (QName, needs in-scope ns)
5783     *  xsl:namespace-alias (in-scope ns)
5784     *    global scope, merge with includes
5785     *  xsl:template (last, QName, pattern)
5786     *
5787     * (whitespace-only text-nodes have *not* been removed
5788     *  yet; this will be done in xsltParseSequenceConstructor)
5789     *
5790     * Report misplaced child-nodes first.
5791     */
5792     cur = node->children;
5793     while (cur != NULL) {
5794     if (cur->type == XML_TEXT_NODE) {
5795         xsltTransformError(NULL, style, cur,
5796         "Misplaced text node (content: '%s').\n",
5797         (cur->content != NULL) ? cur->content : BAD_CAST "");
5798         style->errors++;
5799     } else if (cur->type != XML_ELEMENT_NODE) {
5800         xsltTransformError(NULL, style, cur, "Misplaced node.\n");
5801         style->errors++;
5802     }
5803     cur = cur->next;
5804     }
5805     /*
5806     * Skip xsl:import elements; they have been processed
5807     * already.
5808     */
5809     cur = node->children;
5810     while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur,
5811         BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
5812     cur = cur->next;
5813     if (cur == NULL)
5814     goto exit;
5815 
5816     start = cur;
5817     /*
5818     * Process all top-level xsl:param elements.
5819     */
5820     while ((cur != NULL) &&
5821     xsltParseFindTopLevelElem(cctxt, cur,
5822     BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1)
5823     {
5824     xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM);
5825     cur = cur->next;
5826     }
5827     /*
5828     * Process all top-level xsl:variable elements.
5829     */
5830     cur = start;
5831     while ((cur != NULL) &&
5832     xsltParseFindTopLevelElem(cctxt, cur,
5833     BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1)
5834     {
5835     xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE);
5836     cur = cur->next;
5837     }
5838     /*
5839     * Process all the rest of top-level elements.
5840     */
5841     cur = start;
5842     while (cur != NULL) {
5843     /*
5844     * Process element nodes.
5845     */
5846     if (cur->type == XML_ELEMENT_NODE) {
5847         if (cur->ns == NULL) {
5848         xsltTransformError(NULL, style, cur,
5849             "Unexpected top-level element in no namespace.\n");
5850         style->errors++;
5851         cur = cur->next;
5852         continue;
5853         }
5854         /*
5855         * Process all XSLT elements.
5856         */
5857         if (IS_XSLT_ELEM_FAST(cur)) {
5858         /*
5859         * xsl:import is only allowed at the beginning.
5860         */
5861         if (IS_XSLT_NAME(cur, "import")) {
5862             xsltTransformError(NULL, style, cur,
5863             "Misplaced xsl:import element.\n");
5864             style->errors++;
5865             cur = cur->next;
5866             continue;
5867         }
5868         /*
5869         * TODO: Change the return type of the parsing functions
5870         *  to int.
5871         */
5872         if (IS_XSLT_NAME(cur, "template")) {
5873 #ifdef WITH_XSLT_DEBUG_PARSING
5874             templates++;
5875 #endif
5876             /*
5877             * TODO: Is the position of xsl:template in the
5878             *  tree significant? If not it would be easier to
5879             *  parse them at a later stage.
5880             */
5881             xsltParseXSLTTemplate(cctxt, cur);
5882         } else if (IS_XSLT_NAME(cur, "variable")) {
5883             /* NOP; done already */
5884         } else if (IS_XSLT_NAME(cur, "param")) {
5885             /* NOP; done already */
5886         } else if (IS_XSLT_NAME(cur, "include")) {
5887             if (cur->psvi != NULL)
5888             xsltParseXSLTStylesheetElemCore(cctxt, cur);
5889             else {
5890             xsltTransformError(NULL, style, cur,
5891                 "Internal error: "
5892                 "(xsltParseXSLTStylesheetElemCore) "
5893                 "The xsl:include element was not compiled.\n");
5894             style->errors++;
5895             }
5896         } else if (IS_XSLT_NAME(cur, "strip-space")) {
5897             /* No node info needed. */
5898             xsltParseStylesheetStripSpace(style, cur);
5899         } else if (IS_XSLT_NAME(cur, "preserve-space")) {
5900             /* No node info needed. */
5901             xsltParseStylesheetPreserveSpace(style, cur);
5902         } else if (IS_XSLT_NAME(cur, "output")) {
5903             /* No node-info needed. */
5904             xsltParseStylesheetOutput(style, cur);
5905         } else if (IS_XSLT_NAME(cur, "key")) {
5906             /* TODO: node-info needed for expressions ? */
5907             xsltParseStylesheetKey(style, cur);
5908         } else if (IS_XSLT_NAME(cur, "decimal-format")) {
5909             /* No node-info needed. */
5910             xsltParseStylesheetDecimalFormat(style, cur);
5911         } else if (IS_XSLT_NAME(cur, "attribute-set")) {
5912             xsltParseTopLevelXSLTElem(cctxt, cur,
5913             XSLT_FUNC_ATTRSET);
5914         } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
5915             /* NOP; done already */
5916         } else {
5917             if (cctxt->inode->forwardsCompat) {
5918             /*
5919             * Forwards-compatible mode:
5920             *
5921             * XSLT-1: "if it is a top-level element and
5922             *  XSLT 1.0 does not allow such elements as top-level
5923             *  elements, then the element must be ignored along
5924             *  with its content;"
5925             */
5926             /*
5927             * TODO: I don't think we should generate a warning.
5928             */
5929             xsltTransformError(NULL, style, cur,
5930                 "Forwards-compatible mode: Ignoring unknown XSLT "
5931                 "element '%s'.\n", cur->name);
5932             style->warnings++;
5933             } else {
5934             xsltTransformError(NULL, style, cur,
5935                 "Unknown XSLT element '%s'.\n", cur->name);
5936             style->errors++;
5937             }
5938         }
5939         } else {
5940         xsltTopLevelFunction function;
5941 
5942         /*
5943         * Process non-XSLT elements, which are in a
5944         *  non-NULL namespace.
5945         */
5946         /*
5947         * QUESTION: What does xsltExtModuleTopLevelLookup()
5948         *  do exactly?
5949         */
5950         function = xsltExtModuleTopLevelLookup(cur->name,
5951             cur->ns->href);
5952         if (function != NULL)
5953             function(style, cur);
5954 #ifdef WITH_XSLT_DEBUG_PARSING
5955         xsltGenericDebug(xsltGenericDebugContext,
5956             "xsltParseXSLTStylesheetElemCore : User-defined "
5957             "data element '%s'.\n", cur->name);
5958 #endif
5959         }
5960     }
5961     cur = cur->next;
5962     }
5963 
5964 exit:
5965 
5966 #ifdef WITH_XSLT_DEBUG_PARSING
5967     xsltGenericDebug(xsltGenericDebugContext,
5968     "### END of parsing top-level elements of doc '%s'.\n",
5969     node->doc->URL);
5970     xsltGenericDebug(xsltGenericDebugContext,
5971     "### Templates: %d\n", templates);
5972 #ifdef XSLT_REFACTORED
5973     xsltGenericDebug(xsltGenericDebugContext,
5974     "### Max inodes: %d\n", cctxt->maxNodeInfos);
5975     xsltGenericDebug(xsltGenericDebugContext,
5976     "### Max LREs  : %d\n", cctxt->maxLREs);
5977 #endif /* XSLT_REFACTORED */
5978 #endif /* WITH_XSLT_DEBUG_PARSING */
5979 
5980     xsltCompilerNodePop(cctxt, node);
5981     return(0);
5982 }
5983 
5984 /**
5985  * xsltParseXSLTStylesheet:
5986  * @cctxt: the compiler context
5987  * @node: the xsl:stylesheet/xsl:transform element-node
5988  *
5989  * Parses the xsl:stylesheet and xsl:transform element.
5990  *
5991  * <xsl:stylesheet
5992  *  id = id
5993  *  extension-element-prefixes = tokens
5994  *  exclude-result-prefixes = tokens
5995  *  version = number>
5996  *  <!-- Content: (xsl:import*, top-level-elements) -->
5997  * </xsl:stylesheet>
5998  *
5999  * BIG TODO: The xsl:include stuff.
6000  *
6001  * Called by xsltParseStylesheetTree()
6002  *
6003  * Returns 0 on success, a positive result on errors and
6004  *         -1 on API or internal errors.
6005  */
6006 static int
6007 xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
6008 {
6009     xmlNodePtr cur, start;
6010 
6011     if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
6012     return(-1);
6013 
6014     if (node->children == NULL)
6015     goto exit;
6016 
6017     /*
6018     * Process top-level elements:
6019     *  xsl:import (must be first)
6020     *  xsl:include (this is just a pre-processing)
6021     */
6022     cur = node->children;
6023     /*
6024     * Process xsl:import elements.
6025     * XSLT 1.0: "The xsl:import element children must precede all
6026     *  other element children of an xsl:stylesheet element,
6027     *  including any xsl:include element children."
6028     */
6029     while ((cur != NULL) &&
6030     xsltParseFindTopLevelElem(cctxt, cur,
6031         BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
6032     {
6033     if (xsltParseStylesheetImport(cctxt->style, cur) != 0) {
6034         cctxt->style->errors++;
6035     }
6036     cur = cur->next;
6037     }
6038     if (cur == NULL)
6039     goto exit;
6040     start = cur;
6041     /*
6042     * Pre-process all xsl:include elements.
6043     */
6044     cur = start;
6045     while ((cur != NULL) &&
6046     xsltParseFindTopLevelElem(cctxt, cur,
6047         BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1)
6048     {
6049     xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE);
6050     cur = cur->next;
6051     }
6052     /*
6053     * Pre-process all xsl:namespace-alias elements.
6054     * URGENT TODO: This won't work correctly: the order of included
6055     *  aliases and aliases defined here is significant.
6056     */
6057     cur = start;
6058     while ((cur != NULL) &&
6059     xsltParseFindTopLevelElem(cctxt, cur,
6060         BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1)
6061     {
6062     xsltNamespaceAlias(cctxt->style, cur);
6063     cur = cur->next;
6064     }
6065 
6066     if (cctxt->isInclude) {
6067     /*
6068     * If this stylesheet is intended for inclusion, then
6069     * we will process only imports and includes.
6070     */
6071     goto exit;
6072     }
6073     /*
6074     * Now parse the rest of the top-level elements.
6075     */
6076     xsltParseXSLTStylesheetElemCore(cctxt, node);
6077 exit:
6078 
6079     return(0);
6080 }
6081 
6082 #else /* XSLT_REFACTORED */
6083 
6084 /**
6085  * xsltParseStylesheetTop:
6086  * @style:  the XSLT stylesheet
6087  * @top:  the top level "stylesheet" or "transform" element
6088  *
6089  * scan the top level elements of an XSL stylesheet
6090  */
6091 static void
6092 xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
6093     xmlNodePtr cur;
6094     xmlChar *prop;
6095 #ifdef WITH_XSLT_DEBUG_PARSING
6096     int templates = 0;
6097 #endif
6098 
6099     if ((top == NULL) || (top->type != XML_ELEMENT_NODE))
6100     return;
6101 
6102     prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL);
6103     if (prop == NULL) {
6104     xsltTransformError(NULL, style, top,
6105         "xsl:version is missing: document may not be a stylesheet\n");
6106     if (style != NULL) style->warnings++;
6107     } else {
6108     if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
6109             (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
6110         xsltTransformError(NULL, style, top,
6111         "xsl:version: only 1.1 features are supported\n");
6112         if (style != NULL) {
6113                 style->forwards_compatible = 1;
6114                 style->warnings++;
6115             }
6116     }
6117     xmlFree(prop);
6118     }
6119 
6120     /*
6121      * process xsl:import elements
6122      */
6123     cur = top->children;
6124     while (cur != NULL) {
6125         if (IS_BLANK_NODE(cur)) {
6126             cur = cur->next;
6127             continue;
6128         }
6129         if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
6130             if (xsltParseStylesheetImport(style, cur) != 0)
6131                 if (style != NULL) style->errors++;
6132         } else
6133             break;
6134         cur = cur->next;
6135     }
6136 
6137     /*
6138      * process other top-level elements
6139      */
6140     while (cur != NULL) {
6141     if (IS_BLANK_NODE(cur)) {
6142         cur = cur->next;
6143         continue;
6144     }
6145     if (cur->type == XML_TEXT_NODE) {
6146         if (cur->content != NULL) {
6147         xsltTransformError(NULL, style, cur,
6148             "misplaced text node: '%s'\n", cur->content);
6149         }
6150         if (style != NULL) style->errors++;
6151             cur = cur->next;
6152         continue;
6153     }
6154     if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
6155         xsltGenericError(xsltGenericErrorContext,
6156              "Found a top-level element %s with null namespace URI\n",
6157              cur->name);
6158         if (style != NULL) style->errors++;
6159         cur = cur->next;
6160         continue;
6161     }
6162     if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
6163         xsltTopLevelFunction function;
6164 
6165         function = xsltExtModuleTopLevelLookup(cur->name,
6166                            cur->ns->href);
6167         if (function != NULL)
6168         function(style, cur);
6169 
6170 #ifdef WITH_XSLT_DEBUG_PARSING
6171         xsltGenericDebug(xsltGenericDebugContext,
6172             "xsltParseStylesheetTop : found foreign element %s\n",
6173             cur->name);
6174 #endif
6175             cur = cur->next;
6176         continue;
6177     }
6178     if (IS_XSLT_NAME(cur, "import")) {
6179         xsltTransformError(NULL, style, cur,
6180             "xsltParseStylesheetTop: ignoring misplaced import element\n");
6181         if (style != NULL) style->errors++;
6182         } else if (IS_XSLT_NAME(cur, "include")) {
6183         if (xsltParseStylesheetInclude(style, cur) != 0)
6184         if (style != NULL) style->errors++;
6185         } else if (IS_XSLT_NAME(cur, "strip-space")) {
6186         xsltParseStylesheetStripSpace(style, cur);
6187         } else if (IS_XSLT_NAME(cur, "preserve-space")) {
6188         xsltParseStylesheetPreserveSpace(style, cur);
6189         } else if (IS_XSLT_NAME(cur, "output")) {
6190         xsltParseStylesheetOutput(style, cur);
6191         } else if (IS_XSLT_NAME(cur, "key")) {
6192         xsltParseStylesheetKey(style, cur);
6193         } else if (IS_XSLT_NAME(cur, "decimal-format")) {
6194         xsltParseStylesheetDecimalFormat(style, cur);
6195         } else if (IS_XSLT_NAME(cur, "attribute-set")) {
6196         xsltParseStylesheetAttributeSet(style, cur);
6197         } else if (IS_XSLT_NAME(cur, "variable")) {
6198         xsltParseGlobalVariable(style, cur);
6199         } else if (IS_XSLT_NAME(cur, "param")) {
6200         xsltParseGlobalParam(style, cur);
6201         } else if (IS_XSLT_NAME(cur, "template")) {
6202 #ifdef WITH_XSLT_DEBUG_PARSING
6203         templates++;
6204 #endif
6205         xsltParseStylesheetTemplate(style, cur);
6206         } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
6207         xsltNamespaceAlias(style, cur);
6208     } else {
6209             if ((style != NULL) && (style->forwards_compatible == 0)) {
6210             xsltTransformError(NULL, style, cur,
6211             "xsltParseStylesheetTop: unknown %s element\n",
6212             cur->name);
6213             if (style != NULL) style->errors++;
6214         }
6215     }
6216     cur = cur->next;
6217     }
6218 #ifdef WITH_XSLT_DEBUG_PARSING
6219     xsltGenericDebug(xsltGenericDebugContext,
6220             "parsed %d templates\n", templates);
6221 #endif
6222 }
6223 
6224 #endif /* else of XSLT_REFACTORED */
6225 
6226 #ifdef XSLT_REFACTORED
6227 /**
6228  * xsltParseSimplifiedStylesheetTree:
6229  *
6230  * @style: the stylesheet (TODO: Change this to the compiler context)
6231  * @doc: the document containing the stylesheet.
6232  * @node: the node where the stylesheet is rooted at
6233  *
6234  * Returns 0 in case of success, a positive result if an error occurred
6235  *         and -1 on API and internal errors.
6236  */
6237 static int
6238 xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt,
6239                   xmlDocPtr doc,
6240                   xmlNodePtr node)
6241 {
6242     xsltTemplatePtr templ;
6243 
6244     if ((cctxt == NULL) || (node == NULL))
6245     return(-1);
6246 
6247     if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE)
6248     {
6249     /*
6250     * TODO: Adjust report, since this might be an
6251     * embedded stylesheet.
6252     */
6253     xsltTransformError(NULL, cctxt->style, node,
6254         "The attribute 'xsl:version' is missing; cannot identify "
6255         "this document as an XSLT stylesheet document.\n");
6256     cctxt->style->errors++;
6257     return(1);
6258     }
6259 
6260 #ifdef WITH_XSLT_DEBUG_PARSING
6261     xsltGenericDebug(xsltGenericDebugContext,
6262     "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
6263 #endif
6264 
6265     /*
6266     * Create and link the template
6267     */
6268     templ = xsltNewTemplate();
6269     if (templ == NULL) {
6270     return(-1);
6271     }
6272     templ->next = cctxt->style->templates;
6273     cctxt->style->templates = templ;
6274     templ->match = xmlStrdup(BAD_CAST "/");
6275 
6276     /*
6277     * Note that we push the document-node in this special case.
6278     */
6279     xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
6280     /*
6281     * In every case, we need to have
6282     * the in-scope namespaces of the element, where the
6283     * stylesheet is rooted at, regardless if it's an XSLT
6284     * instruction or a literal result instruction (or if
6285     * this is an embedded stylesheet).
6286     */
6287     cctxt->inode->inScopeNs =
6288     xsltCompilerBuildInScopeNsList(cctxt, node);
6289     /*
6290     * Parse the content and register the match-pattern.
6291     */
6292     xsltParseSequenceConstructor(cctxt, node);
6293     xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
6294 
6295     templ->elem = (xmlNodePtr) doc;
6296     templ->content = node;
6297     xsltAddTemplate(cctxt->style, templ, NULL, NULL);
6298     cctxt->style->literal_result = 1;
6299     return(0);
6300 }
6301 
6302 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6303 /**
6304  * xsltRestoreDocumentNamespaces:
6305  * @ns: map of namespaces
6306  * @doc: the document
6307  *
6308  * Restore the namespaces for the document
6309  *
6310  * Returns 0 in case of success, -1 in case of failure
6311  */
6312 int
6313 xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc)
6314 {
6315     if (doc == NULL)
6316     return(-1);
6317     /*
6318     * Revert the changes we have applied to the namespace-URIs of
6319     * ns-decls.
6320     */
6321     while (ns != NULL) {
6322     if ((ns->doc == doc) && (ns->ns != NULL)) {
6323         ns->ns->href = ns->origNsName;
6324         ns->origNsName = NULL;
6325         ns->ns = NULL;
6326     }
6327     ns = ns->next;
6328     }
6329     return(0);
6330 }
6331 #endif /* XSLT_REFACTORED_XSLT_NSCOMP */
6332 
6333 /**
6334  * xsltParseStylesheetProcess:
6335  * @style:  the XSLT stylesheet (the current stylesheet-level)
6336  * @doc:  and xmlDoc parsed XML
6337  *
6338  * Parses an XSLT stylesheet, adding the associated structures.
6339  * Called by:
6340  *  xsltParseStylesheetImportedDoc() (xslt.c)
6341  *  xsltParseStylesheetInclude() (imports.c)
6342  *
6343  * Returns the value of the @style parameter if everything
6344  * went right, NULL if something went amiss.
6345  */
6346 xsltStylesheetPtr
6347 xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc)
6348 {
6349     xsltCompilerCtxtPtr cctxt;
6350     xmlNodePtr cur;
6351     int oldIsSimplifiedStylesheet;
6352 
6353     xsltInitGlobals();
6354 
6355     if ((style == NULL) || (doc == NULL))
6356     return(NULL);
6357 
6358     cctxt = XSLT_CCTXT(style);
6359 
6360     cur = xmlDocGetRootElement(doc);
6361     if (cur == NULL) {
6362     xsltTransformError(NULL, style, (xmlNodePtr) doc,
6363         "xsltParseStylesheetProcess : empty stylesheet\n");
6364     return(NULL);
6365     }
6366     oldIsSimplifiedStylesheet = cctxt->simplified;
6367 
6368     if ((IS_XSLT_ELEM(cur)) &&
6369     ((IS_XSLT_NAME(cur, "stylesheet")) ||
6370      (IS_XSLT_NAME(cur, "transform")))) {
6371 #ifdef WITH_XSLT_DEBUG_PARSING
6372     xsltGenericDebug(xsltGenericDebugContext,
6373         "xsltParseStylesheetProcess : found stylesheet\n");
6374 #endif
6375     cctxt->simplified = 0;
6376     style->literal_result = 0;
6377     } else {
6378     cctxt->simplified = 1;
6379     style->literal_result = 1;
6380     }
6381     /*
6382     * Pre-process the stylesheet if not already done before.
6383     *  This will remove PIs and comments, merge adjacent
6384     *  text nodes, internalize strings, etc.
6385     */
6386     if (! style->nopreproc)
6387     xsltParsePreprocessStylesheetTree(cctxt, cur);
6388     /*
6389     * Parse and compile the stylesheet.
6390     */
6391     if (style->literal_result == 0) {
6392     if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0)
6393         return(NULL);
6394     } else {
6395     if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0)
6396         return(NULL);
6397     }
6398 
6399     cctxt->simplified = oldIsSimplifiedStylesheet;
6400 
6401     return(style);
6402 }
6403 
6404 #else /* XSLT_REFACTORED */
6405 
6406 /**
6407  * xsltParseStylesheetProcess:
6408  * @ret:  the XSLT stylesheet (the current stylesheet-level)
6409  * @doc:  and xmlDoc parsed XML
6410  *
6411  * Parses an XSLT stylesheet, adding the associated structures.
6412  * Called by:
6413  *  xsltParseStylesheetImportedDoc() (xslt.c)
6414  *  xsltParseStylesheetInclude() (imports.c)
6415  *
6416  * Returns the value of the @style parameter if everything
6417  * went right, NULL if something went amiss.
6418  */
6419 xsltStylesheetPtr
6420 xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
6421     xmlNodePtr cur;
6422 
6423     xsltInitGlobals();
6424 
6425     if (doc == NULL)
6426     return(NULL);
6427     if (ret == NULL)
6428     return(ret);
6429 
6430     /*
6431      * First steps, remove blank nodes,
6432      * locate the xsl:stylesheet element and the
6433      * namespace declaration.
6434      */
6435     cur = xmlDocGetRootElement(doc);
6436     if (cur == NULL) {
6437     xsltTransformError(NULL, ret, (xmlNodePtr) doc,
6438         "xsltParseStylesheetProcess : empty stylesheet\n");
6439     return(NULL);
6440     }
6441 
6442     if ((IS_XSLT_ELEM(cur)) &&
6443     ((IS_XSLT_NAME(cur, "stylesheet")) ||
6444      (IS_XSLT_NAME(cur, "transform")))) {
6445 #ifdef WITH_XSLT_DEBUG_PARSING
6446     xsltGenericDebug(xsltGenericDebugContext,
6447         "xsltParseStylesheetProcess : found stylesheet\n");
6448 #endif
6449     ret->literal_result = 0;
6450     xsltParseStylesheetExcludePrefix(ret, cur, 1);
6451     xsltParseStylesheetExtPrefix(ret, cur, 1);
6452     } else {
6453     xsltParseStylesheetExcludePrefix(ret, cur, 0);
6454     xsltParseStylesheetExtPrefix(ret, cur, 0);
6455     ret->literal_result = 1;
6456     }
6457     if (!ret->nopreproc) {
6458     xsltPreprocessStylesheet(ret, cur);
6459     }
6460     if (ret->literal_result == 0) {
6461     xsltParseStylesheetTop(ret, cur);
6462     } else {
6463     xmlChar *prop;
6464     xsltTemplatePtr template;
6465 
6466     /*
6467      * the document itself might be the template, check xsl:version
6468      */
6469     prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
6470     if (prop == NULL) {
6471         xsltTransformError(NULL, ret, cur,
6472         "xsltParseStylesheetProcess : document is not a stylesheet\n");
6473         return(NULL);
6474     }
6475 
6476 #ifdef WITH_XSLT_DEBUG_PARSING
6477         xsltGenericDebug(xsltGenericDebugContext,
6478         "xsltParseStylesheetProcess : document is stylesheet\n");
6479 #endif
6480 
6481     if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
6482             (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
6483         xsltTransformError(NULL, ret, cur,
6484         "xsl:version: only 1.1 features are supported\n");
6485             ret->forwards_compatible = 1;
6486         ret->warnings++;
6487     }
6488     xmlFree(prop);
6489 
6490     /*
6491      * Create and link the template
6492      */
6493     template = xsltNewTemplate();
6494     if (template == NULL) {
6495         return(NULL);
6496     }
6497     template->next = ret->templates;
6498     ret->templates = template;
6499     template->match = xmlStrdup((const xmlChar *)"/");
6500 
6501     /*
6502      * parse the content and register the pattern
6503      */
6504     xsltParseTemplateContent(ret, (xmlNodePtr) doc);
6505     template->elem = (xmlNodePtr) doc;
6506     template->content = doc->children;
6507     xsltAddTemplate(ret, template, NULL, NULL);
6508     ret->literal_result = 1;
6509     }
6510 
6511     return(ret);
6512 }
6513 
6514 #endif /* else of XSLT_REFACTORED */
6515 
6516 /**
6517  * xsltParseStylesheetImportedDoc:
6518  * @doc:  an xmlDoc parsed XML
6519  * @parentStyle: pointer to the parent stylesheet (if it exists)
6520  *
6521  * parse an XSLT stylesheet building the associated structures
6522  * except the processing not needed for imported documents.
6523  *
6524  * Returns a new XSLT stylesheet structure.
6525  */
6526 
6527 xsltStylesheetPtr
6528 xsltParseStylesheetImportedDoc(xmlDocPtr doc,
6529                    xsltStylesheetPtr parentStyle) {
6530     xsltStylesheetPtr retStyle;
6531 
6532     if (doc == NULL)
6533     return(NULL);
6534 
6535     retStyle = xsltNewStylesheet();
6536     if (retStyle == NULL)
6537     return(NULL);
6538     /*
6539     * Set the importing stylesheet module; also used to detect recursion.
6540     */
6541     retStyle->parent = parentStyle;
6542     /*
6543     * Adjust the string dict.
6544     */
6545     if (doc->dict != NULL) {
6546         xmlDictFree(retStyle->dict);
6547     retStyle->dict = doc->dict;
6548 #ifdef WITH_XSLT_DEBUG
6549         xsltGenericDebug(xsltGenericDebugContext,
6550         "reusing dictionary from %s for stylesheet\n",
6551         doc->URL);
6552 #endif
6553     xmlDictReference(retStyle->dict);
6554     }
6555 
6556     /*
6557     * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
6558     *  the stylesheet to containt distinct namespace prefixes.
6559     */
6560     xsltGatherNamespaces(retStyle);
6561 
6562 #ifdef XSLT_REFACTORED
6563     {
6564     xsltCompilerCtxtPtr cctxt;
6565     xsltStylesheetPtr oldCurSheet;
6566 
6567     if (parentStyle == NULL) {
6568         xsltPrincipalStylesheetDataPtr principalData;
6569         /*
6570         * Principal stylesheet
6571         * --------------------
6572         */
6573         retStyle->principal = retStyle;
6574         /*
6575         * Create extra data for the principal stylesheet.
6576         */
6577         principalData = xsltNewPrincipalStylesheetData();
6578         if (principalData == NULL) {
6579         xsltFreeStylesheet(retStyle);
6580         return(NULL);
6581         }
6582         retStyle->principalData = principalData;
6583         /*
6584         * Create the compilation context
6585         * ------------------------------
6586         * (only once; for the principal stylesheet).
6587         * This is currently the only function where the
6588         * compilation context is created.
6589         */
6590         cctxt = xsltCompilationCtxtCreate(retStyle);
6591         if (cctxt == NULL) {
6592         xsltFreeStylesheet(retStyle);
6593         return(NULL);
6594         }
6595         retStyle->compCtxt = (void *) cctxt;
6596         cctxt->style = retStyle;
6597         cctxt->dict = retStyle->dict;
6598         cctxt->psData = principalData;
6599         /*
6600         * Push initial dummy node info.
6601         */
6602         cctxt->depth = -1;
6603         xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
6604     } else {
6605         /*
6606         * Imported stylesheet.
6607         */
6608         retStyle->principal = parentStyle->principal;
6609         cctxt = parentStyle->compCtxt;
6610         retStyle->compCtxt = cctxt;
6611     }
6612     /*
6613     * Save the old and set the current stylesheet structure in the
6614     * compilation context.
6615     */
6616     oldCurSheet = cctxt->style;
6617     cctxt->style = retStyle;
6618 
6619     retStyle->doc = doc;
6620     xsltParseStylesheetProcess(retStyle, doc);
6621 
6622     cctxt->style = oldCurSheet;
6623     if (parentStyle == NULL) {
6624         /*
6625         * Pop the initial dummy node info.
6626         */
6627         xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
6628     } else {
6629         /*
6630         * Clear the compilation context of imported
6631         * stylesheets.
6632         * TODO: really?
6633         */
6634         /* retStyle->compCtxt = NULL; */
6635     }
6636     /*
6637     * Free the stylesheet if there were errors.
6638     */
6639     if (retStyle != NULL) {
6640         if (retStyle->errors != 0) {
6641 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
6642         /*
6643         * Restore all changes made to namespace URIs of ns-decls.
6644         */
6645         if (cctxt->psData->nsMap)
6646             xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
6647 #endif
6648         /*
6649         * Detach the doc from the stylesheet; otherwise the doc
6650         * will be freed in xsltFreeStylesheet().
6651         */
6652         retStyle->doc = NULL;
6653         /*
6654         * Cleanup the doc if its the main stylesheet.
6655         */
6656         if (parentStyle == NULL) {
6657             xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
6658             if (retStyle->compCtxt != NULL) {
6659             xsltCompilationCtxtFree(retStyle->compCtxt);
6660             retStyle->compCtxt = NULL;
6661             }
6662         }
6663 
6664         xsltFreeStylesheet(retStyle);
6665         retStyle = NULL;
6666         }
6667     }
6668     }
6669 
6670 #else /* XSLT_REFACTORED */
6671     /*
6672     * Old behaviour.
6673     */
6674     retStyle->doc = doc;
6675     if (xsltParseStylesheetProcess(retStyle, doc) == NULL) {
6676         retStyle->doc = NULL;
6677         xsltFreeStylesheet(retStyle);
6678         retStyle = NULL;
6679     }
6680     if (retStyle != NULL) {
6681     if (retStyle->errors != 0) {
6682         retStyle->doc = NULL;
6683         if (parentStyle == NULL)
6684         xsltCleanupStylesheetTree(doc,
6685             xmlDocGetRootElement(doc));
6686         xsltFreeStylesheet(retStyle);
6687         retStyle = NULL;
6688     }
6689     }
6690 #endif /* else of XSLT_REFACTORED */
6691 
6692     return(retStyle);
6693 }
6694 
6695 /**
6696  * xsltParseStylesheetDoc:
6697  * @doc:  and xmlDoc parsed XML
6698  *
6699  * parse an XSLT stylesheet, building the associated structures.  doc
6700  * is kept as a reference within the returned stylesheet, so changes
6701  * to doc after the parsing will be reflected when the stylesheet
6702  * is applied, and the doc is automatically freed when the
6703  * stylesheet is closed.
6704  *
6705  * Returns a new XSLT stylesheet structure.
6706  */
6707 
6708 xsltStylesheetPtr
6709 xsltParseStylesheetDoc(xmlDocPtr doc) {
6710     xsltStylesheetPtr ret;
6711 
6712     xsltInitGlobals();
6713 
6714     ret = xsltParseStylesheetImportedDoc(doc, NULL);
6715     if (ret == NULL)
6716     return(NULL);
6717 
6718     xsltResolveStylesheetAttributeSet(ret);
6719 #ifdef XSLT_REFACTORED
6720     /*
6721     * Free the compilation context.
6722     * TODO: Check if it's better to move this cleanup to
6723     *   xsltParseStylesheetImportedDoc().
6724     */
6725     if (ret->compCtxt != NULL) {
6726     xsltCompilationCtxtFree(XSLT_CCTXT(ret));
6727     ret->compCtxt = NULL;
6728     }
6729 #endif
6730     return(ret);
6731 }
6732 
6733 /**
6734  * xsltParseStylesheetFile:
6735  * @filename:  the filename/URL to the stylesheet
6736  *
6737  * Load and parse an XSLT stylesheet
6738  *
6739  * Returns a new XSLT stylesheet structure.
6740  */
6741 
6742 xsltStylesheetPtr
6743 xsltParseStylesheetFile(const xmlChar* filename) {
6744     xsltSecurityPrefsPtr sec;
6745     xsltStylesheetPtr ret;
6746     xmlDocPtr doc;
6747 
6748     xsltInitGlobals();
6749 
6750     if (filename == NULL)
6751     return(NULL);
6752 
6753 #ifdef WITH_XSLT_DEBUG_PARSING
6754     xsltGenericDebug(xsltGenericDebugContext,
6755         "xsltParseStylesheetFile : parse %s\n", filename);
6756 #endif
6757 
6758     /*
6759      * Security framework check
6760      */
6761     sec = xsltGetDefaultSecurityPrefs();
6762     if (sec != NULL) {
6763     int res;
6764 
6765     res = xsltCheckRead(sec, NULL, filename);
6766     if (res == 0) {
6767         xsltTransformError(NULL, NULL, NULL,
6768          "xsltParseStylesheetFile: read rights for %s denied\n",
6769                  filename);
6770         return(NULL);
6771     }
6772     }
6773 
6774     doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,
6775                                NULL, XSLT_LOAD_START);
6776     if (doc == NULL) {
6777     xsltTransformError(NULL, NULL, NULL,
6778         "xsltParseStylesheetFile : cannot parse %s\n", filename);
6779     return(NULL);
6780     }
6781     ret = xsltParseStylesheetDoc(doc);
6782     if (ret == NULL) {
6783     xmlFreeDoc(doc);
6784     return(NULL);
6785     }
6786 
6787     return(ret);
6788 }
6789 
6790 /************************************************************************
6791  *                                  *
6792  *          Handling of Stylesheet PI           *
6793  *                                  *
6794  ************************************************************************/
6795 
6796 #define CUR (*cur)
6797 #define SKIP(val) cur += (val)
6798 #define NXT(val) cur[(val)]
6799 #define SKIP_BLANKS                     \
6800     while (IS_BLANK(CUR)) NEXT
6801 #define NEXT ((*cur) ?  cur++ : cur)
6802 
6803 /**
6804  * xsltParseStylesheetPI:
6805  * @value: the value of the PI
6806  *
6807  * This function checks that the type is text/xml and extracts
6808  * the URI-Reference for the stylesheet
6809  *
6810  * Returns the URI-Reference for the stylesheet or NULL (it need to
6811  *         be freed by the caller)
6812  */
6813 static xmlChar *
6814 xsltParseStylesheetPI(const xmlChar *value) {
6815     const xmlChar *cur;
6816     const xmlChar *start;
6817     xmlChar *val;
6818     xmlChar tmp;
6819     xmlChar *href = NULL;
6820     int isXml = 0;
6821 
6822     if (value == NULL)
6823     return(NULL);
6824 
6825     cur = value;
6826     while (CUR != 0) {
6827     SKIP_BLANKS;
6828     if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
6829         (NXT(3) == 'e')) {
6830         SKIP(4);
6831         SKIP_BLANKS;
6832         if (CUR != '=')
6833         continue;
6834         NEXT;
6835         if ((CUR != '\'') && (CUR != '"'))
6836         continue;
6837         tmp = CUR;
6838         NEXT;
6839         start = cur;
6840         while ((CUR != 0) && (CUR != tmp))
6841         NEXT;
6842         if (CUR != tmp)
6843         continue;
6844         val = xmlStrndup(start, cur - start);
6845         NEXT;
6846         if (val == NULL)
6847         return(NULL);
6848         if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
6849         (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
6850                 xmlFree(val);
6851         break;
6852         }
6853         isXml = 1;
6854         xmlFree(val);
6855     } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
6856         (NXT(3) == 'f')) {
6857         SKIP(4);
6858         SKIP_BLANKS;
6859         if (CUR != '=')
6860         continue;
6861         NEXT;
6862         if ((CUR != '\'') && (CUR != '"'))
6863         continue;
6864         tmp = CUR;
6865         NEXT;
6866         start = cur;
6867         while ((CUR != 0) && (CUR != tmp))
6868         NEXT;
6869         if (CUR != tmp)
6870         continue;
6871         if (href == NULL)
6872         href = xmlStrndup(start, cur - start);
6873         NEXT;
6874     } else {
6875         while ((CUR != 0) && (!IS_BLANK(CUR)))
6876         NEXT;
6877     }
6878 
6879     }
6880 
6881     if (!isXml) {
6882     if (href != NULL)
6883         xmlFree(href);
6884     href = NULL;
6885     }
6886     return(href);
6887 }
6888 
6889 /**
6890  * xsltLoadStylesheetPI:
6891  * @doc:  a document to process
6892  *
6893  * This function tries to locate the stylesheet PI in the given document
6894  * If found, and if contained within the document, it will extract
6895  * that subtree to build the stylesheet to process @doc (doc itself will
6896  * be modified). If found but referencing an external document it will
6897  * attempt to load it and generate a stylesheet from it. In both cases,
6898  * the resulting stylesheet and the document need to be freed once the
6899  * transformation is done.
6900  *
6901  * Returns a new XSLT stylesheet structure or NULL if not found.
6902  */
6903 xsltStylesheetPtr
6904 xsltLoadStylesheetPI(xmlDocPtr doc) {
6905     xmlNodePtr child;
6906     xsltStylesheetPtr ret = NULL;
6907     xmlChar *href = NULL;
6908     xmlURIPtr URI;
6909 
6910     xsltInitGlobals();
6911 
6912     if (doc == NULL)
6913     return(NULL);
6914 
6915     /*
6916      * Find the text/xml stylesheet PI id any before the root
6917      */
6918     child = doc->children;
6919     while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
6920     if ((child->type == XML_PI_NODE) &&
6921         (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
6922         href = xsltParseStylesheetPI(child->content);
6923         if (href != NULL)
6924         break;
6925     }
6926     child = child->next;
6927     }
6928 
6929     /*
6930      * If found check the href to select processing
6931      */
6932     if (href != NULL) {
6933 #ifdef WITH_XSLT_DEBUG_PARSING
6934     xsltGenericDebug(xsltGenericDebugContext,
6935         "xsltLoadStylesheetPI : found PI href=%s\n", href);
6936 #endif
6937     URI = xmlParseURI((const char *) href);
6938     if (URI == NULL) {
6939         xsltTransformError(NULL, NULL, child,
6940             "xml-stylesheet : href %s is not valid\n", href);
6941         xmlFree(href);
6942         return(NULL);
6943     }
6944     if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
6945             (URI->opaque == NULL) && (URI->authority == NULL) &&
6946             (URI->server == NULL) && (URI->user == NULL) &&
6947             (URI->path == NULL) && (URI->query == NULL)) {
6948         xmlAttrPtr ID;
6949 
6950 #ifdef WITH_XSLT_DEBUG_PARSING
6951         xsltGenericDebug(xsltGenericDebugContext,
6952             "xsltLoadStylesheetPI : Reference to ID %s\n", href);
6953 #endif
6954         if (URI->fragment[0] == '#')
6955         ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
6956         else
6957         ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
6958         if (ID == NULL) {
6959         xsltTransformError(NULL, NULL, child,
6960             "xml-stylesheet : no ID %s found\n", URI->fragment);
6961         } else {
6962         xmlDocPtr fake;
6963         xmlNodePtr subtree, newtree;
6964         xmlNsPtr ns;
6965 
6966 #ifdef WITH_XSLT_DEBUG
6967         xsltGenericDebug(xsltGenericDebugContext,
6968             "creating new document from %s for embedded stylesheet\n",
6969             doc->URL);
6970 #endif
6971         /*
6972          * move the subtree in a new document passed to
6973          * the stylesheet analyzer
6974          */
6975         subtree = ID->parent;
6976         fake = xmlNewDoc(NULL);
6977         if (fake != NULL) {
6978             /*
6979             * Should the dictionary still be shared even though
6980             * the nodes are being copied rather than moved?
6981             */
6982             fake->dict = doc->dict;
6983             xmlDictReference(doc->dict);
6984 #ifdef WITH_XSLT_DEBUG
6985             xsltGenericDebug(xsltGenericDebugContext,
6986             "reusing dictionary from %s for embedded stylesheet\n",
6987             doc->URL);
6988 #endif
6989 
6990             newtree = xmlDocCopyNode(subtree, fake, 1);
6991 
6992             fake->URL = xmlNodeGetBase(doc, subtree->parent);
6993 #ifdef WITH_XSLT_DEBUG
6994             xsltGenericDebug(xsltGenericDebugContext,
6995             "set base URI for embedded stylesheet as %s\n",
6996             fake->URL);
6997 #endif
6998 
6999             /*
7000             * Add all namespaces in scope of embedded stylesheet to
7001             * root element of newly created stylesheet document
7002             */
7003             while ((subtree = subtree->parent) != (xmlNodePtr)doc) {
7004             for (ns = subtree->ns; ns; ns = ns->next) {
7005                 xmlNewNs(newtree,  ns->href, ns->prefix);
7006             }
7007             }
7008 
7009             xmlAddChild((xmlNodePtr)fake, newtree);
7010             ret = xsltParseStylesheetDoc(fake);
7011             if (ret == NULL)
7012             xmlFreeDoc(fake);
7013         }
7014         }
7015     } else {
7016         xmlChar *URL, *base;
7017 
7018         /*
7019          * Reference to an external stylesheet
7020          */
7021 
7022         base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
7023         URL = xmlBuildURI(href, base);
7024         if (URL != NULL) {
7025 #ifdef WITH_XSLT_DEBUG_PARSING
7026         xsltGenericDebug(xsltGenericDebugContext,
7027             "xsltLoadStylesheetPI : fetching %s\n", URL);
7028 #endif
7029         ret = xsltParseStylesheetFile(URL);
7030         xmlFree(URL);
7031         } else {
7032 #ifdef WITH_XSLT_DEBUG_PARSING
7033         xsltGenericDebug(xsltGenericDebugContext,
7034             "xsltLoadStylesheetPI : fetching %s\n", href);
7035 #endif
7036         ret = xsltParseStylesheetFile(href);
7037         }
7038         if (base != NULL)
7039         xmlFree(base);
7040     }
7041     xmlFreeURI(URI);
7042     xmlFree(href);
7043     }
7044     return(ret);
7045 }