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