root/third_party/libxslt/libxslt/xslt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xsltParseContentError
  2. exclPrefixPush
  3. exclPrefixPop
  4. xsltInit
  5. xsltUninit
  6. xsltIsBlank
  7. xsltNewDecimalFormat
  8. xsltFreeDecimalFormat
  9. xsltFreeDecimalFormatList
  10. xsltDecimalFormatGetByName
  11. xsltNewTemplate
  12. xsltFreeTemplate
  13. xsltFreeTemplateList
  14. xsltFreeNsAliasList
  15. xsltFreeNamespaceMap
  16. xsltNewNamespaceMapItem
  17. xsltCompilerVarInfoFree
  18. xsltCompilationCtxtFree
  19. xsltCompilationCtxtCreate
  20. xsltLREEffectiveNsNodesFree
  21. xsltFreePrincipalStylesheetData
  22. xsltNewPrincipalStylesheetData
  23. xsltNewStylesheet
  24. xsltAllocateExtra
  25. xsltAllocateExtraCtxt
  26. xsltFreeStylesheetList
  27. xsltCleanupStylesheetTree
  28. xsltFreeStylesheet
  29. xsltGetInheritedNsList
  30. xsltParseStylesheetOutput
  31. xsltParseStylesheetDecimalFormat
  32. xsltParseStylesheetPreserveSpace
  33. xsltParseStylesheetExtPrefix
  34. xsltParseStylesheetStripSpace
  35. xsltParseStylesheetExcludePrefix
  36. xsltTreeEnsureXMLDecl
  37. xsltTreeAcquireStoredNs
  38. xsltLREBuildEffectiveNs
  39. xsltLREBuildEffectiveNsNodes
  40. xsltLREInfoCreate
  41. xsltCompilerVarInfoPush
  42. xsltCompilerVarInfoPop
  43. xsltCompilerNodePush
  44. xsltCompilerNodePop
  45. xsltCompilerBuildInScopeNsList
  46. xsltParseNsPrefixList
  47. xsltCompilerUtilsCreateMergedList
  48. xsltParseExclResultPrefixes
  49. xsltParseExtElemPrefixes
  50. xsltParseAttrXSLTVersion
  51. xsltParsePreprocessStylesheetTree
  52. xsltPrecomputeStylesheet
  53. xsltGatherNamespaces
  54. xsltGetXSLTElementTypeByNode
  55. xsltParseAnyXSLTElem
  56. xsltForwardsCompatUnkownItemCreate
  57. xsltParseUnknownXSLTElem
  58. xsltParseSequenceConstructor
  59. xsltParseTemplateContent
  60. xsltParseTemplateContent
  61. xsltParseStylesheetKey
  62. xsltParseXSLTTemplate
  63. xsltParseStylesheetTemplate
  64. xsltCompileXSLTIncludeElem
  65. xsltParseFindTopLevelElem
  66. xsltParseTopLevelXSLTElem
  67. xsltParseRemoveWhitespace
  68. xsltParseXSLTStylesheetElemCore
  69. xsltParseXSLTStylesheetElem
  70. xsltParseStylesheetTop
  71. xsltParseSimplifiedStylesheetTree
  72. xsltRestoreDocumentNamespaces
  73. xsltParseStylesheetProcess
  74. xsltParseStylesheetProcess
  75. xsltParseStylesheetImportedDoc
  76. xsltParseStylesheetDoc
  77. xsltParseStylesheetFile
  78. xsltParseStylesheetPI
  79. xsltLoadStylesheetPI

/*
 * xslt.c: Implemetation of an XSL Transformation 1.0 engine
 *
 * Reference:
 *   XSLT specification
 *   http://www.w3.org/TR/1999/REC-xslt-19991116
 *
 *   Associating Style Sheets with XML documents
 *   http://www.w3.org/1999/06/REC-xml-stylesheet-19990629
 *
 * See Copyright for the status of this software.
 *
 * daniel@veillard.com
 */

#define IN_LIBXSLT
#include "libxslt.h"

#include <string.h>

#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/valid.h>
#include <libxml/hash.h>
#include <libxml/uri.h>
#include <libxml/xmlerror.h>
#include <libxml/parserInternals.h>
#include <libxml/xpathInternals.h>
#include <libxml/xpath.h>
#include "xslt.h"
#include "xsltInternals.h"
#include "pattern.h"
#include "variables.h"
#include "namespaces.h"
#include "attributes.h"
#include "xsltutils.h"
#include "imports.h"
#include "keys.h"
#include "documents.h"
#include "extensions.h"
#include "preproc.h"
#include "extra.h"
#include "security.h"

#ifdef WITH_XSLT_DEBUG
#define WITH_XSLT_DEBUG_PARSING
/* #define WITH_XSLT_DEBUG_BLANKS */
#endif

const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA;
const int xsltLibxsltVersion = LIBXSLT_VERSION;
const int xsltLibxmlVersion = LIBXML_VERSION;

#ifdef XSLT_REFACTORED

const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE;

#define XSLT_ELEMENT_CATEGORY_XSLT 0
#define XSLT_ELEMENT_CATEGORY_EXTENSION 1
#define XSLT_ELEMENT_CATEGORY_LRE 2

/*
* xsltLiteralResultMarker:
* Marker for Literal result elements, in order to avoid multiple attempts
* to recognize such elements in the stylesheet's tree.
* This marker is set on node->psvi during the initial traversal
* of a stylesheet's node tree.
*
const xmlChar *xsltLiteralResultMarker =
    (const xmlChar *) "Literal Result Element";
*/

/*
* xsltXSLTTextMarker:
* Marker for xsl:text elements. Used to recognize xsl:text elements
* for post-processing of the stylesheet's tree, where those
* elements are removed from the tree.
*/
const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";

/*
* xsltXSLTAttrMarker:
* Marker for XSLT attribute on Literal Result Elements.
*/
const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";

#endif

#ifdef XSLT_LOCALE_WINAPI
extern xmlRMutexPtr xsltLocaleMutex;
#endif
/*
 * Harmless but avoiding a problem when compiling against a
 * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
 */
#ifndef LIBXML_DEBUG_ENABLED
double xmlXPathStringEvalNumber(const xmlChar *str);
#endif
/*
 * Useful macros
 */

#ifdef  IS_BLANK
#undef  IS_BLANK
#endif
#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||  \
                     ((c) == 0x0D))

#ifdef  IS_BLANK_NODE
#undef  IS_BLANK_NODE
#endif
#define IS_BLANK_NODE(n)                                                \
    (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))

/**
 * xsltParseContentError:
 *
 * @style: the stylesheet
 * @node: the node where the error occured
 *
 * Compile-time error function.
 */
static void
xsltParseContentError(xsltStylesheetPtr style,
                       xmlNodePtr node)
{
    if ((style == NULL) || (node == NULL))
        return;

    if (IS_XSLT_ELEM(node))
        xsltTransformError(NULL, style, node,
            "The XSLT-element '%s' is not allowed at this position.\n",
            node->name);
    else
        xsltTransformError(NULL, style, node,
            "The element '%s' is not allowed at this position.\n",
            node->name);
    style->errors++;
}

#ifdef XSLT_REFACTORED
#else
/**
 * exclPrefixPush:
 * @style: the transformation stylesheet
 * @value:  the excluded namespace name to push on the stack
 *
 * Push an excluded namespace name on the stack
 *
 * Returns the new index in the stack or -1 if already present or
 * in case of error
 */
static int
exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)
{
    int i;

    if (style->exclPrefixMax == 0) {
        style->exclPrefixMax = 4;
        style->exclPrefixTab =
            (xmlChar * *)xmlMalloc(style->exclPrefixMax *
                                   sizeof(style->exclPrefixTab[0]));
        if (style->exclPrefixTab == NULL) {
            xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
            return (-1);
        }
    }
    /* do not push duplicates */
    for (i = 0;i < style->exclPrefixNr;i++) {
        if (xmlStrEqual(style->exclPrefixTab[i], value))
            return(-1);
    }
    if (style->exclPrefixNr >= style->exclPrefixMax) {
        style->exclPrefixMax *= 2;
        style->exclPrefixTab =
            (xmlChar * *)xmlRealloc(style->exclPrefixTab,
                                    style->exclPrefixMax *
                                    sizeof(style->exclPrefixTab[0]));
        if (style->exclPrefixTab == NULL) {
            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
            return (-1);
        }
    }
    style->exclPrefixTab[style->exclPrefixNr] = value;
    style->exclPrefix = value;
    return (style->exclPrefixNr++);
}
/**
 * exclPrefixPop:
 * @style: the transformation stylesheet
 *
 * Pop an excluded prefix value from the stack
 *
 * Returns the stored excluded prefix value
 */
static xmlChar *
exclPrefixPop(xsltStylesheetPtr style)
{
    xmlChar *ret;

    if (style->exclPrefixNr <= 0)
        return (0);
    style->exclPrefixNr--;
    if (style->exclPrefixNr > 0)
        style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
    else
        style->exclPrefix = NULL;
    ret = style->exclPrefixTab[style->exclPrefixNr];
    style->exclPrefixTab[style->exclPrefixNr] = 0;
    return (ret);
}
#endif

/************************************************************************
 *                                                                      *
 *                      Helper functions                                *
 *                                                                      *
 ************************************************************************/

static int initialized = 0;
/**
 * xsltInit:
 *
 * Initializes the processor (e.g. registers built-in extensions,
 * etc.)
 */
void
xsltInit (void) {
    if (initialized == 0) {
        initialized = 1;
#ifdef XSLT_LOCALE_WINAPI
        xsltLocaleMutex = xmlNewRMutex();
#endif
        xsltRegisterAllExtras();
    }
}

/**
 * xsltUninit:
 *
 * Uninitializes the processor.
 */
void
xsltUninit (void) {
    initialized = 0;
}

/**
 * xsltIsBlank:
 * @str:  a string
 *
 * Check if a string is ignorable
 *
 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
 */
int
xsltIsBlank(xmlChar *str) {
    if (str == NULL)
        return(1);
    while (*str != 0) {
        if (!(IS_BLANK(*str))) return(0);
        str++;
    }
    return(1);
}

/************************************************************************
 *                                                                      *
 *              Routines to handle XSLT data structures                 *
 *                                                                      *
 ************************************************************************/
static xsltDecimalFormatPtr
xsltNewDecimalFormat(xmlChar *name)
{
    xsltDecimalFormatPtr self;
    /* UTF-8 for 0x2030 */
    static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};

    self = xmlMalloc(sizeof(xsltDecimalFormat));
    if (self != NULL) {
        self->next = NULL;
        self->name = name;
        
        /* Default values */
        self->digit = xmlStrdup(BAD_CAST("#"));
        self->patternSeparator = xmlStrdup(BAD_CAST(";"));
        self->decimalPoint = xmlStrdup(BAD_CAST("."));
        self->grouping = xmlStrdup(BAD_CAST(","));
        self->percent = xmlStrdup(BAD_CAST("%"));
        self->permille = xmlStrdup(BAD_CAST(permille));
        self->zeroDigit = xmlStrdup(BAD_CAST("0"));
        self->minusSign = xmlStrdup(BAD_CAST("-"));
        self->infinity = xmlStrdup(BAD_CAST("Infinity"));
        self->noNumber = xmlStrdup(BAD_CAST("NaN"));
    }
    return self;
}

static void
xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
{
    if (self != NULL) {
        if (self->digit)
            xmlFree(self->digit);
        if (self->patternSeparator)
            xmlFree(self->patternSeparator);
        if (self->decimalPoint)
            xmlFree(self->decimalPoint);
        if (self->grouping)
            xmlFree(self->grouping);
        if (self->percent)
            xmlFree(self->percent);
        if (self->permille)
            xmlFree(self->permille);
        if (self->zeroDigit)
            xmlFree(self->zeroDigit);
        if (self->minusSign)
            xmlFree(self->minusSign);
        if (self->infinity)
            xmlFree(self->infinity);
        if (self->noNumber)
            xmlFree(self->noNumber);
        if (self->name)
            xmlFree(self->name);
        xmlFree(self);
    }
}

static void
xsltFreeDecimalFormatList(xsltStylesheetPtr self)
{
    xsltDecimalFormatPtr iter;
    xsltDecimalFormatPtr tmp;

    if (self == NULL)
        return;
    
    iter = self->decimalFormat;
    while (iter != NULL) {
        tmp = iter->next;
        xsltFreeDecimalFormat(iter);
        iter = tmp;
    }
}

/**
 * xsltDecimalFormatGetByName:
 * @style: the XSLT stylesheet
 * @name: the decimal-format name to find
 *
 * Find decimal-format by name
 *
 * Returns the xsltDecimalFormatPtr
 */
xsltDecimalFormatPtr
xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
{
    xsltDecimalFormatPtr result = NULL;

    if (name == NULL)
        return style->decimalFormat;

    while (style != NULL) {
        for (result = style->decimalFormat->next;
             result != NULL;
             result = result->next) {
            if (xmlStrEqual(name, result->name))
                return result;
        }
        style = xsltNextImport(style);
    }
    return result;
}


/**
 * xsltNewTemplate:
 *
 * Create a new XSLT Template
 *
 * Returns the newly allocated xsltTemplatePtr or NULL in case of error
 */
static xsltTemplatePtr
xsltNewTemplate(void) {
    xsltTemplatePtr cur;

    cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
    if (cur == NULL) {
        xsltTransformError(NULL, NULL, NULL,
                "xsltNewTemplate : malloc failed\n");
        return(NULL);
    }
    memset(cur, 0, sizeof(xsltTemplate));
    cur->priority = XSLT_PAT_NO_PRIORITY;
    return(cur);
}

/**
 * xsltFreeTemplate:
 * @template:  an XSLT template
 *
 * Free up the memory allocated by @template
 */
static void
xsltFreeTemplate(xsltTemplatePtr template) {
    if (template == NULL)
        return;
    if (template->match) xmlFree(template->match);
/*
*   NOTE: @name and @nameURI are put into the string dict now.
*   if (template->name) xmlFree(template->name);
*   if (template->nameURI) xmlFree(template->nameURI);
*/
/*
    if (template->mode) xmlFree(template->mode);
    if (template->modeURI) xmlFree(template->modeURI);
 */
    if (template->inheritedNs) xmlFree(template->inheritedNs);
    memset(template, -1, sizeof(xsltTemplate));
    xmlFree(template);
}

/**
 * xsltFreeTemplateList:
 * @template:  an XSLT template list
 *
 * Free up the memory allocated by all the elements of @template
 */
static void
xsltFreeTemplateList(xsltTemplatePtr template) {
    xsltTemplatePtr cur;

    while (template != NULL) {
        cur = template;
        template = template->next;
        xsltFreeTemplate(cur);
    }
}

#ifdef XSLT_REFACTORED

static void
xsltFreeNsAliasList(xsltNsAliasPtr item)
{
    xsltNsAliasPtr tmp;
    
    while (item) {
        tmp = item;
        item = item->next;
        xmlFree(tmp);
    } 
    return;
}

#ifdef XSLT_REFACTORED_XSLT_NSCOMP
static void
xsltFreeNamespaceMap(xsltNsMapPtr item)
{
    xsltNsMapPtr tmp;
    
    while (item) {
        tmp = item;
        item = item->next;
        xmlFree(tmp);
    } 
    return;
}

static xsltNsMapPtr
xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
                        xmlDocPtr doc,
                        xmlNsPtr ns,
                        xmlNodePtr elem)
{
    xsltNsMapPtr ret;

    if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
        return(NULL);

    ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
    if (ret == NULL) {
        xsltTransformError(NULL, cctxt->style, elem,
            "Internal error: (xsltNewNamespaceMapItem) "
            "memory allocation failed.\n");
        return(NULL);
    }
    memset(ret, 0, sizeof(xsltNsMap));
    ret->doc = doc;
    ret->ns = ns;
    ret->origNsName = ns->href;
    /*
    * Store the item at current stylesheet-level.
    */
    if (cctxt->psData->nsMap != NULL)
        ret->next = cctxt->psData->nsMap;
    cctxt->psData->nsMap = ret;

    return(ret);
}
#endif /* XSLT_REFACTORED_XSLT_NSCOMP */

/**
 * xsltCompilerVarInfoFree: 
 * @cctxt: the compilation context
 * 
 * Frees the list of information for vars/params.
 */
static void
xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)
{
    xsltVarInfoPtr ivar = cctxt->ivars, ivartmp;    

    while (ivar) {
        ivartmp = ivar;
        ivar = ivar->next;
        xmlFree(ivartmp);
    }
}

/**
 * xsltCompilerCtxtFree:
 *
 * Free an XSLT compiler context. 
 */
static void
xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
{    
    if (cctxt == NULL)
        return;
#ifdef WITH_XSLT_DEBUG_PARSING
    xsltGenericDebug(xsltGenericDebugContext,
        "Freeing compilation context\n");
    xsltGenericDebug(xsltGenericDebugContext,
        "### Max inodes: %d\n", cctxt->maxNodeInfos);
    xsltGenericDebug(xsltGenericDebugContext,
        "### Max LREs  : %d\n", cctxt->maxLREs);
#endif
    /*
    * Free node-infos.
    */
    if (cctxt->inodeList != NULL) {
        xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
        while (cur != NULL) {
            tmp = cur;
            cur = cur->next;
            xmlFree(tmp);
        }
    }
    if (cctxt->tmpList != NULL)
        xsltPointerListFree(cctxt->tmpList);
#ifdef XSLT_REFACTORED_XPATHCOMP
    if (cctxt->xpathCtxt != NULL)
        xmlXPathFreeContext(cctxt->xpathCtxt);
#endif
    if (cctxt->nsAliases != NULL)
        xsltFreeNsAliasList(cctxt->nsAliases);

    if (cctxt->ivars)
        xsltCompilerVarInfoFree(cctxt);

    xmlFree(cctxt);
}

/**
 * xsltCompilerCreate:
 *
 * Creates an XSLT compiler context.
 *
 * Returns the pointer to the created xsltCompilerCtxt or
 *         NULL in case of an internal error.
 */
static xsltCompilerCtxtPtr
xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
    xsltCompilerCtxtPtr ret;

    ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
    if (ret == NULL) {
        xsltTransformError(NULL, style, NULL,
            "xsltCompilerCreate: allocation of compiler "
            "context failed.\n");
        return(NULL);
    }
    memset(ret, 0, sizeof(xsltCompilerCtxt));

    ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
    ret->tmpList = xsltPointerListCreate(20);
    if (ret->tmpList == NULL) {
        goto internal_err;
    }
#ifdef XSLT_REFACTORED_XPATHCOMP
    /*
    * Create the XPath compilation context in order
    * to speed up precompilation of XPath expressions.
    */
    ret->xpathCtxt = xmlXPathNewContext(NULL);
    if (ret->xpathCtxt == NULL)
        goto internal_err;
#endif
    
    return(ret);

internal_err:
    xsltCompilationCtxtFree(ret);
    return(NULL);
}

static void
xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
{
    xsltEffectiveNsPtr tmp;

    while (first != NULL) {
        tmp = first;
        first = first->nextInStore;
        xmlFree(tmp);
    }
}

static void
xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
{
    if (data == NULL)
        return;

    if (data->inScopeNamespaces != NULL) {
        int i;
        xsltNsListContainerPtr nsi;
        xsltPointerListPtr list =
            (xsltPointerListPtr) data->inScopeNamespaces;

        for (i = 0; i < list->number; i++) {
            /*
            * REVISIT TODO: Free info of in-scope namespaces.
            */
            nsi = (xsltNsListContainerPtr) list->items[i];
            if (nsi->list != NULL)
                xmlFree(nsi->list);
            xmlFree(nsi);
        }
        xsltPointerListFree(list);
        data->inScopeNamespaces = NULL;
    }

    if (data->exclResultNamespaces != NULL) {
        int i;
        xsltPointerListPtr list = (xsltPointerListPtr)
            data->exclResultNamespaces; 
        
        for (i = 0; i < list->number; i++)
            xsltPointerListFree((xsltPointerListPtr) list->items[i]);
        
        xsltPointerListFree(list);
        data->exclResultNamespaces = NULL;
    }

    if (data->extElemNamespaces != NULL) {
        xsltPointerListPtr list = (xsltPointerListPtr)
            data->extElemNamespaces;
        int i;

        for (i = 0; i < list->number; i++)
            xsltPointerListFree((xsltPointerListPtr) list->items[i]);

        xsltPointerListFree(list);
        data->extElemNamespaces = NULL;
    }
    if (data->effectiveNs) {
        xsltLREEffectiveNsNodesFree(data->effectiveNs);
        data->effectiveNs = NULL;
    }
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
    xsltFreeNamespaceMap(data->nsMap);
#endif
    xmlFree(data);
}

static xsltPrincipalStylesheetDataPtr
xsltNewPrincipalStylesheetData(void)
{
    xsltPrincipalStylesheetDataPtr ret;

    ret = (xsltPrincipalStylesheetDataPtr)
        xmlMalloc(sizeof(xsltPrincipalStylesheetData));
    if (ret == NULL) {
        xsltTransformError(NULL, NULL, NULL,
            "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
        return(NULL);
    }
    memset(ret, 0, sizeof(xsltPrincipalStylesheetData));
    
    /*
    * Global list of in-scope namespaces.
    */    
    ret->inScopeNamespaces = xsltPointerListCreate(-1);
    if (ret->inScopeNamespaces == NULL)
        goto internal_err;
    /*
    * Global list of excluded result ns-decls.
    */
    ret->exclResultNamespaces = xsltPointerListCreate(-1);
    if (ret->exclResultNamespaces == NULL)
        goto internal_err;
    /*
    * Global list of extension instruction namespace names.
    */    
    ret->extElemNamespaces = xsltPointerListCreate(-1);
    if (ret->extElemNamespaces == NULL)
        goto internal_err;

    return(ret);

internal_err:

    return(NULL);
}

#endif

/**
 * xsltNewStylesheet:
 *
 * Create a new XSLT Stylesheet
 *
 * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
 */
xsltStylesheetPtr
xsltNewStylesheet(void) {
    xsltStylesheetPtr ret = NULL;    

    ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
    if (ret == NULL) {
        xsltTransformError(NULL, NULL, NULL,
                "xsltNewStylesheet : malloc failed\n");
        goto internal_err;
    }
    memset(ret, 0, sizeof(xsltStylesheet));

    ret->omitXmlDeclaration = -1;
    ret->standalone = -1;
    ret->decimalFormat = xsltNewDecimalFormat(NULL);
    ret->indent = -1;
    ret->errors = 0;
    ret->warnings = 0;
    ret->exclPrefixNr = 0;
    ret->exclPrefixMax = 0;
    ret->exclPrefixTab = NULL;
    ret->extInfos = NULL;
    ret->extrasNr = 0;
    ret->internalized = 1;
    ret->literal_result = 0;
    ret->dict = xmlDictCreate();
#ifdef WITH_XSLT_DEBUG
    xsltGenericDebug(xsltGenericDebugContext,
        "creating dictionary for stylesheet\n");
#endif

    xsltInit();

    return(ret);

internal_err:
    if (ret != NULL)
        xsltFreeStylesheet(ret);
    return(NULL);
}

/**
 * xsltAllocateExtra:
 * @style:  an XSLT stylesheet
 *
 * Allocate an extra runtime information slot statically while compiling
 * the stylesheet and return its number
 *
 * Returns the number of the slot
 */
int
xsltAllocateExtra(xsltStylesheetPtr style)
{
    return(style->extrasNr++);
}

/**
 * xsltAllocateExtraCtxt:
 * @ctxt:  an XSLT transformation context
 *
 * Allocate an extra runtime information slot at run-time
 * and return its number
 * This make sure there is a slot ready in the transformation context
 *
 * Returns the number of the slot
 */
int
xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
{
    if (ctxt->extrasNr >= ctxt->extrasMax) {
        int i;
        if (ctxt->extrasNr == 0) {
            ctxt->extrasMax = 20;
            ctxt->extras = (xsltRuntimeExtraPtr)
                xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
            if (ctxt->extras == NULL) {
                xmlGenericError(xmlGenericErrorContext,
                        "xsltAllocateExtraCtxt: out of memory\n");
                ctxt->state = XSLT_STATE_ERROR;
                return(0);
            }
            for (i = 0;i < ctxt->extrasMax;i++) {
                ctxt->extras[i].info = NULL;
                ctxt->extras[i].deallocate = NULL;
                ctxt->extras[i].val.ptr = NULL;
            }

        } else {
            xsltRuntimeExtraPtr tmp;

            ctxt->extrasMax += 100;
            tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
                            ctxt->extrasMax * sizeof(xsltRuntimeExtra));
            if (tmp == NULL) {
                xmlGenericError(xmlGenericErrorContext,
                        "xsltAllocateExtraCtxt: out of memory\n");
                ctxt->state = XSLT_STATE_ERROR;
                return(0);
            }
            ctxt->extras = tmp;
            for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
                ctxt->extras[i].info = NULL;
                ctxt->extras[i].deallocate = NULL;
                ctxt->extras[i].val.ptr = NULL;
            }
        }
    }
    return(ctxt->extrasNr++);
}

/**
 * xsltFreeStylesheetList:
 * @style:  an XSLT stylesheet list
 *
 * Free up the memory allocated by the list @style
 */
static void
xsltFreeStylesheetList(xsltStylesheetPtr style) {
    xsltStylesheetPtr next;

    while (style != NULL) {
        next = style->next;
        xsltFreeStylesheet(style);
        style = next;
    }
}

/**
 * xsltCleanupStylesheetTree:
 *
 * @doc: the document-node
 * @node: the element where the stylesheet is rooted at
 *
 * Actually @node need not be the document-element, but
 * currently Libxslt does not support embedded stylesheets.
 *
 * Returns 0 if OK, -1 on API or internal errors.
 */
static int
xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED,
                          xmlNodePtr rootElem ATTRIBUTE_UNUSED)
{    
#if 0 /* TODO: Currently disabled, since probably not needed. */
    xmlNodePtr cur;

    if ((doc == NULL) || (rootElem == NULL) ||
        (rootElem->type != XML_ELEMENT_NODE) ||
        (doc != rootElem->doc))
        return(-1);

    /*
    * Cleanup was suggested by Aleksey Sanin:
    * Clear the PSVI field to avoid problems if the
    * node-tree of the stylesheet is intended to be used for
    * further processing by the user (e.g. for compiling it
    * once again - although not recommended).
    */

    cur = rootElem;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            /*
            * Clear the PSVI field.
            */
            cur->psvi = NULL;
            if (cur->children) {
                cur = cur->children;
                continue;
            }
        }

leave_node:
        if (cur == rootElem)
            break;
        if (cur->next != NULL)
            cur = cur->next;
        else {
            cur = cur->parent;
            if (cur == NULL)
                break;
            goto leave_node;
        }
    }
#endif /* #if 0 */
    return(0);
}

/**
 * xsltFreeStylesheet:
 * @style:  an XSLT stylesheet
 *
 * Free up the memory allocated by @style
 */
void
xsltFreeStylesheet(xsltStylesheetPtr style)
{
    if (style == NULL)
        return;
    
#ifdef XSLT_REFACTORED
    /*
    * Start with a cleanup of the main stylesheet's doc.
    */
    if ((style->principal == style) && (style->doc))
        xsltCleanupStylesheetTree(style->doc,
            xmlDocGetRootElement(style->doc));
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
    /*
    * Restore changed ns-decls before freeing the document.
    */
    if ((style->doc != NULL) &&
        XSLT_HAS_INTERNAL_NSMAP(style))
    {
        xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
            style->doc);        
    }
#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
#else
    /*
    * Start with a cleanup of the main stylesheet's doc.
    */
    if ((style->parent == NULL) && (style->doc))
        xsltCleanupStylesheetTree(style->doc,
            xmlDocGetRootElement(style->doc));
#endif /* XSLT_REFACTORED */

    xsltFreeKeys(style);
    xsltFreeExts(style);
    xsltFreeTemplateHashes(style);
    xsltFreeDecimalFormatList(style);
    xsltFreeTemplateList(style->templates);
    xsltFreeAttributeSetsHashes(style);
    xsltFreeNamespaceAliasHashes(style);
    xsltFreeStylePreComps(style);
    /*
    * Free documents of all included stylsheet modules of this
    * stylesheet level.
    */
    xsltFreeStyleDocuments(style);
    /*
    * TODO: Best time to shutdown extension stuff?
    */
    xsltShutdownExts(style);
       
    if (style->variables != NULL)
        xsltFreeStackElemList(style->variables);
    if (style->cdataSection != NULL)
        xmlHashFree(style->cdataSection, NULL);
    if (style->stripSpaces != NULL)
        xmlHashFree(style->stripSpaces, NULL);
    if (style->nsHash != NULL)
        xmlHashFree(style->nsHash, NULL);
    if (style->exclPrefixTab != NULL)
        xmlFree(style->exclPrefixTab);
    if (style->method != NULL)
        xmlFree(style->method);
    if (style->methodURI != NULL)
        xmlFree(style->methodURI);
    if (style->version != NULL)
        xmlFree(style->version);
    if (style->encoding != NULL)
        xmlFree(style->encoding);
    if (style->doctypePublic != NULL)
        xmlFree(style->doctypePublic);
    if (style->doctypeSystem != NULL)
        xmlFree(style->doctypeSystem);
    if (style->mediaType != NULL)
        xmlFree(style->mediaType);
    if (style->attVTs)
        xsltFreeAVTList(style->attVTs);
    if (style->imports != NULL)
        xsltFreeStylesheetList(style->imports);

#ifdef XSLT_REFACTORED
    /*
    * If this is the principal stylesheet, then
    * free its internal data.
    */
    if (style->principal == style) {
        if (style->principalData) {
            xsltFreePrincipalStylesheetData(style->principalData);
            style->principalData = NULL;
        }
    }    
#endif
    /*
    * Better to free the main document of this stylesheet level
    * at the end - so here.
    */
    if (style->doc != NULL) {   
        xmlFreeDoc(style->doc);
    }

#ifdef WITH_XSLT_DEBUG
    xsltGenericDebug(xsltGenericDebugContext,
                     "freeing dictionary from stylesheet\n");
#endif
    xmlDictFree(style->dict);

    memset(style, -1, sizeof(xsltStylesheet));
    xmlFree(style);
}

/************************************************************************
 *                                                                      *
 *              Parsing of an XSLT Stylesheet                           *
 *                                                                      *
 ************************************************************************/

#ifdef XSLT_REFACTORED
    /*
    * This is now performed in an optimized way in xsltParseXSLTTemplate.
    */
#else
/**
 * xsltGetInheritedNsList:
 * @style:  the stylesheet
 * @template: the template
 * @node:  the current node
 *
 * Search all the namespace applying to a given element except the ones 
 * from excluded output prefixes currently in scope. Initialize the
 * template inheritedNs list with it.
 *
 * Returns the number of entries found
 */
static int
xsltGetInheritedNsList(xsltStylesheetPtr style,
                       xsltTemplatePtr template,
                       xmlNodePtr node)
{
    xmlNsPtr cur;
    xmlNsPtr *ret = NULL;
    int nbns = 0;
    int maxns = 10;
    int i;    

    if ((style == NULL) || (template == NULL) || (node == NULL) ||
        (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
        return(0);
    while (node != NULL) {
        if (node->type == XML_ELEMENT_NODE) {
            cur = node->nsDef;
            while (cur != NULL) {
                if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
                    goto skip_ns;

                if ((cur->prefix != NULL) &&
                    (xsltCheckExtPrefix(style, cur->prefix)))
                    goto skip_ns;
                /*
                * Check if this namespace was excluded.
                * Note that at this point only the exclusions defined
                * on the topmost stylesheet element are in the exclusion-list.
                */
                for (i = 0;i < style->exclPrefixNr;i++) {
                    if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
                        goto skip_ns;
                }
                if (ret == NULL) {
                    ret =
                        (xmlNsPtr *) xmlMalloc((maxns + 1) *
                                               sizeof(xmlNsPtr));
                    if (ret == NULL) {
                        xmlGenericError(xmlGenericErrorContext,
                                        "xsltGetInheritedNsList : out of memory!\n");
                        return(0);
                    }
                    ret[nbns] = NULL;
                }
                /*
                * Skip shadowed namespace bindings.
                */
                for (i = 0; i < nbns; i++) {
                    if ((cur->prefix == ret[i]->prefix) ||
                        (xmlStrEqual(cur->prefix, ret[i]->prefix)))
                        break;
                }
                if (i >= nbns) {
                    if (nbns >= maxns) {
                        maxns *= 2;
                        ret = (xmlNsPtr *) xmlRealloc(ret,
                                                      (maxns +
                                                       1) *
                                                      sizeof(xmlNsPtr));
                        if (ret == NULL) {
                            xmlGenericError(xmlGenericErrorContext,
                                            "xsltGetInheritedNsList : realloc failed!\n");
                            return(0);
                        }
                    }
                    ret[nbns++] = cur;
                    ret[nbns] = NULL;
                }
skip_ns:
                cur = cur->next;
            }
        }
        node = node->parent;
    }
    if (nbns != 0) {
#ifdef WITH_XSLT_DEBUG_PARSING
        xsltGenericDebug(xsltGenericDebugContext,
                         "template has %d inherited namespaces\n", nbns);
#endif
        template->inheritedNsNr = nbns;
        template->inheritedNs = ret;
    }
    return (nbns);
}
#endif /* else of XSLT_REFACTORED */

/**
 * xsltParseStylesheetOutput:
 * @style:  the XSLT stylesheet
 * @cur:  the "output" element
 *
 * parse an XSLT stylesheet output element and record
 * information related to the stylesheet output
 */

void
xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
{
    xmlChar *elements,
     *prop;
    xmlChar *element,
     *end;

    if ((cur == NULL) || (style == NULL))
        return;
   
    prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
    if (prop != NULL) {
        if (style->version != NULL)
            xmlFree(style->version);
        style->version = prop;
    }

    prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
    if (prop != NULL) {
        if (style->encoding != NULL)
            xmlFree(style->encoding);
        style->encoding = prop;
    }

    /* relaxed to support xt:document
    * TODO KB: What does "relaxed to support xt:document" mean?
    */
    prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL);
    if (prop != NULL) {
        const xmlChar *URI;

        if (style->method != NULL)
            xmlFree(style->method);
        style->method = NULL;
        if (style->methodURI != NULL)
            xmlFree(style->methodURI);
        style->methodURI = NULL;

        /*
        * TODO: Don't use xsltGetQNameURI().
        */
        URI = xsltGetQNameURI(cur, &prop);
        if (prop == NULL) {
            if (style != NULL) style->errors++;
        } else if (URI == NULL) {
            if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
                (xmlStrEqual(prop, (const xmlChar *) "html")) ||
                (xmlStrEqual(prop, (const xmlChar *) "text"))) {
                style->method = prop;
            } else {
                xsltTransformError(NULL, style, cur,
                                 "invalid value for method: %s\n", prop);
                if (style != NULL) style->warnings++;
            }
        } else {
            style->method = prop;
            style->methodURI = xmlStrdup(URI);
        }
    }

    prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
    if (prop != NULL) {
        if (style->doctypeSystem != NULL)
            xmlFree(style->doctypeSystem);
        style->doctypeSystem = prop;
    }

    prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
    if (prop != NULL) {
        if (style->doctypePublic != NULL)
            xmlFree(style->doctypePublic);
        style->doctypePublic = prop;
    }

    prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL);
    if (prop != NULL) {
        if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
            style->standalone = 1;
        } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
            style->standalone = 0;
        } else {
            xsltTransformError(NULL, style, cur,
                             "invalid value for standalone: %s\n", prop);
            style->errors++;
        }
        xmlFree(prop);
    }

    prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL);
    if (prop != NULL) {
        if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
            style->indent = 1;
        } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
            style->indent = 0;
        } else {
            xsltTransformError(NULL, style, cur,
                             "invalid value for indent: %s\n", prop);
            style->errors++;
        }
        xmlFree(prop);
    }

    prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL);
    if (prop != NULL) {
        if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
            style->omitXmlDeclaration = 1;
        } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
            style->omitXmlDeclaration = 0;
        } else {
            xsltTransformError(NULL, style, cur,
                             "invalid value for omit-xml-declaration: %s\n",
                             prop);
            style->errors++;
        }
        xmlFree(prop);
    }

    elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
        NULL);
    if (elements != NULL) {
        if (style->cdataSection == NULL)
            style->cdataSection = xmlHashCreate(10);
        if (style->cdataSection == NULL)
            return;

        element = elements;
        while (*element != 0) {
            while (IS_BLANK(*element))
                element++;
            if (*element == 0)
                break;
            end = element;
            while ((*end != 0) && (!IS_BLANK(*end)))
                end++;
            element = xmlStrndup(element, end - element);
            if (element) {              
#ifdef WITH_XSLT_DEBUG_PARSING
                xsltGenericDebug(xsltGenericDebugContext,
                                 "add cdata section output element %s\n",
                                 element);
#endif
                if (xmlValidateQName(BAD_CAST element, 0) != 0) {
                    xsltTransformError(NULL, style, cur,
                        "Attribute 'cdata-section-elements': The value "
                        "'%s' is not a valid QName.\n", element);
                    xmlFree(element);
                    style->errors++;
                } else {
                    const xmlChar *URI;

                    /*
                    * TODO: Don't use xsltGetQNameURI().
                    */
                    URI = xsltGetQNameURI(cur, &element);
                    if (element == NULL) {
                        /*
                        * TODO: We'll report additionally an error
                        *  via the stylesheet's error handling.                 
                        */
                        xsltTransformError(NULL, style, cur,
                            "Attribute 'cdata-section-elements': The value "
                            "'%s' is not a valid QName.\n", element);
                        style->errors++;
                    } else {
                        xmlNsPtr ns;
                        
                        /*
                        * XSLT-1.0 "Each QName is expanded into an
                        *  expanded-name using the namespace declarations in
                        *  effect on the xsl:output element in which the QName
                        *  occurs; if there is a default namespace, it is used
                        *  for QNames that do not have a prefix"
                        * NOTE: Fix of bug #339570.
                        */
                        if (URI == NULL) {
                            ns = xmlSearchNs(style->doc, cur, NULL);
                            if (ns != NULL)
                                URI = ns->href;
                        }                  
                        xmlHashAddEntry2(style->cdataSection, element, URI,
                            (void *) "cdata");
                        xmlFree(element);
                    }
                }
            }
            element = end;
        }
        xmlFree(elements);
    }

    prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
    if (prop != NULL) {
        if (style->mediaType)
            xmlFree(style->mediaType);
        style->mediaType = prop;
    }
    if (cur->children != NULL) {
        xsltParseContentError(style, cur->children);
    }
}

/**
 * xsltParseStylesheetDecimalFormat:
 * @style:  the XSLT stylesheet
 * @cur:  the "decimal-format" element
 *
 * <!-- Category: top-level-element -->
 * <xsl:decimal-format
 *   name = qname, decimal-separator = char, grouping-separator = char,
 *   infinity = string, minus-sign = char, NaN = string, percent = char
 *   per-mille = char, zero-digit = char, digit = char,
 * pattern-separator = char />
 *
 * parse an XSLT stylesheet decimal-format element and
 * and record the formatting characteristics
 */
static void
xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
{
    xmlChar *prop;
    xsltDecimalFormatPtr format;
    xsltDecimalFormatPtr iter;
    
    if ((cur == NULL) || (style == NULL))
        return;

    format = style->decimalFormat;
    
    prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
    if (prop != NULL) {
        format = xsltDecimalFormatGetByName(style, prop);
        if (format != NULL) {
            xsltTransformError(NULL, style, cur,
         "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
            if (style != NULL) style->warnings++;
            return;
        }
        format = xsltNewDecimalFormat(prop);
        if (format == NULL) {
            xsltTransformError(NULL, style, cur,
     "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
            if (style != NULL) style->errors++;
            return;
        }
        /* Append new decimal-format structure */
        for (iter = style->decimalFormat; iter->next; iter = iter->next)
            ;
        if (iter)
            iter->next = format;
    }

    prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
    if (prop != NULL) {
        if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
        format->decimalPoint  = prop;
    }
    
    prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
    if (prop != NULL) {
        if (format->grouping != NULL) xmlFree(format->grouping);
        format->grouping  = prop;
    }

    prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
    if (prop != NULL) {
        if (format->infinity != NULL) xmlFree(format->infinity);
        format->infinity  = prop;
    }
    
    prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
    if (prop != NULL) {
        if (format->minusSign != NULL) xmlFree(format->minusSign);
        format->minusSign  = prop;
    }
    
    prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
    if (prop != NULL) {
        if (format->noNumber != NULL) xmlFree(format->noNumber);
        format->noNumber  = prop;
    }
    
    prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
    if (prop != NULL) {
        if (format->percent != NULL) xmlFree(format->percent);
        format->percent  = prop;
    }
    
    prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
    if (prop != NULL) {
        if (format->permille != NULL) xmlFree(format->permille);
        format->permille  = prop;
    }
    
    prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
    if (prop != NULL) {
        if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
        format->zeroDigit  = prop;
    }
    
    prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
    if (prop != NULL) {
        if (format->digit != NULL) xmlFree(format->digit);
        format->digit  = prop;
    }
    
    prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
    if (prop != NULL) {
        if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
        format->patternSeparator  = prop;
    }
    if (cur->children != NULL) {
        xsltParseContentError(style, cur->children);
    }
}

/**
 * xsltParseStylesheetPreserveSpace:
 * @style:  the XSLT stylesheet
 * @cur:  the "preserve-space" element
 *
 * parse an XSLT stylesheet preserve-space element and record
 * elements needing preserving
 */

static void
xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
    xmlChar *elements;
    xmlChar *element, *end;

    if ((cur == NULL) || (style == NULL))
        return;

    elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
    if (elements == NULL) {
        xsltTransformError(NULL, style, cur,
            "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
        if (style != NULL) style->warnings++;
        return;
    }

    if (style->stripSpaces == NULL)
        style->stripSpaces = xmlHashCreate(10);
    if (style->stripSpaces == NULL)
        return;

    element = elements;
    while (*element != 0) {
        while (IS_BLANK(*element)) element++;
        if (*element == 0)
            break;
        end = element;
        while ((*end != 0) && (!IS_BLANK(*end))) end++;
        element = xmlStrndup(element, end - element);
        if (element) {
#ifdef WITH_XSLT_DEBUG_PARSING
            xsltGenericDebug(xsltGenericDebugContext,
                "add preserved space element %s\n", element);
#endif
            if (xmlStrEqual(element, (const xmlChar *)"*")) {
                style->stripAll = -1;
            } else {
                const xmlChar *URI;

                /*
                * TODO: Don't use xsltGetQNameURI().
                */
                URI = xsltGetQNameURI(cur, &element);

                xmlHashAddEntry2(style->stripSpaces, element, URI,
                                (xmlChar *) "preserve");
            }
            xmlFree(element);
        }
        element = end;
    }
    xmlFree(elements);
    if (cur->children != NULL) {
        xsltParseContentError(style, cur->children);
    }
}

#ifdef XSLT_REFACTORED
#else
/**
 * xsltParseStylesheetExtPrefix:
 * @style:  the XSLT stylesheet
 * @template:  the "extension-element-prefixes" prefix
 *
 * parse an XSLT stylesheet's "extension-element-prefix" attribute value
 * and register the namespaces of extension instruction.
 * SPEC "A namespace is designated as an extension namespace by using
 *   an extension-element-prefixes attribute on:
 *   1) an xsl:stylesheet element
 *   2) an xsl:extension-element-prefixes attribute on a
 *      literal result element 
 *   3) an extension instruction."
 */
static void
xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,
                             int isXsltElem) {
    xmlChar *prefixes;
    xmlChar *prefix, *end;

    if ((cur == NULL) || (style == NULL))
        return;

    if (isXsltElem) {
        /* For xsl:stylesheet/xsl:transform. */
        prefixes = xmlGetNsProp(cur,
            (const xmlChar *)"extension-element-prefixes", NULL);
    } else {
        /* For literal result elements and extension instructions. */
        prefixes = xmlGetNsProp(cur,
            (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
    }
    if (prefixes == NULL) {
        return;
    }

    prefix = prefixes;
    while (*prefix != 0) {
        while (IS_BLANK(*prefix)) prefix++;
        if (*prefix == 0)
            break;
        end = prefix;
        while ((*end != 0) && (!IS_BLANK(*end))) end++;
        prefix = xmlStrndup(prefix, end - prefix);
        if (prefix) {
            xmlNsPtr ns;

            if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
                ns = xmlSearchNs(style->doc, cur, NULL);
            else
                ns = xmlSearchNs(style->doc, cur, prefix);
            if (ns == NULL) {
                xsltTransformError(NULL, style, cur,
            "xsl:extension-element-prefix : undefined namespace %s\n",
                                 prefix);
                if (style != NULL) style->warnings++;
            } else {
#ifdef WITH_XSLT_DEBUG_PARSING
                xsltGenericDebug(xsltGenericDebugContext,
                    "add extension prefix %s\n", prefix);
#endif
                xsltRegisterExtPrefix(style, prefix, ns->href);
            }
            xmlFree(prefix);
        }
        prefix = end;
    }
    xmlFree(prefixes);
}
#endif /* else of XSLT_REFACTORED */

/**
 * xsltParseStylesheetStripSpace:
 * @style:  the XSLT stylesheet
 * @cur:  the "strip-space" element
 *
 * parse an XSLT stylesheet's strip-space element and record
 * the elements needing stripping
 */

static void
xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
    xmlChar *elements;
    xmlChar *element, *end;

    if ((cur == NULL) || (style == NULL))
        return;

    elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
    if (elements == NULL) {
        xsltTransformError(NULL, style, cur,
            "xsltParseStylesheetStripSpace: missing elements attribute\n");
        if (style != NULL) style->warnings++;
        return;
    }

    if (style->stripSpaces == NULL)
        style->stripSpaces = xmlHashCreate(10);
    if (style->stripSpaces == NULL)
        return;

    element = elements;
    while (*element != 0) {
        while (IS_BLANK(*element)) element++;
        if (*element == 0)
            break;
        end = element;
        while ((*end != 0) && (!IS_BLANK(*end))) end++;
        element = xmlStrndup(element, end - element);
        if (element) {
#ifdef WITH_XSLT_DEBUG_PARSING
            xsltGenericDebug(xsltGenericDebugContext,
                "add stripped space element %s\n", element);
#endif
            if (xmlStrEqual(element, (const xmlChar *)"*")) {
                style->stripAll = 1;
            } else {
                const xmlChar *URI;

                /*
                * TODO: Don't use xsltGetQNameURI().
                */
                URI = xsltGetQNameURI(cur, &element);

                xmlHashAddEntry2(style->stripSpaces, element, URI,
                                (xmlChar *) "strip");
            }
            xmlFree(element);
        }
        element = end;
    }
    xmlFree(elements);
    if (cur->children != NULL) {
        xsltParseContentError(style, cur->children);
    }
}

#ifdef XSLT_REFACTORED
#else
/**
 * xsltParseStylesheetExcludePrefix:
 * @style:  the XSLT stylesheet
 * @cur:  the current point in the stylesheet
 *
 * parse an XSLT stylesheet exclude prefix and record
 * namespaces needing stripping
 *
 * Returns the number of Excluded prefixes added at that level
 */

static int
xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur,
                                 int isXsltElem)
{
    int nb = 0;
    xmlChar *prefixes;
    xmlChar *prefix, *end;

    if ((cur == NULL) || (style == NULL))
        return(0);

    if (isXsltElem)
        prefixes = xmlGetNsProp(cur,
            (const xmlChar *)"exclude-result-prefixes", NULL);
    else
        prefixes = xmlGetNsProp(cur,
            (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);

    if (prefixes == NULL) {
        return(0);
    }

    prefix = prefixes;
    while (*prefix != 0) {
        while (IS_BLANK(*prefix)) prefix++;
        if (*prefix == 0)
            break;
        end = prefix;
        while ((*end != 0) && (!IS_BLANK(*end))) end++;
        prefix = xmlStrndup(prefix, end - prefix);
        if (prefix) {
            xmlNsPtr ns;

            if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
                ns = xmlSearchNs(style->doc, cur, NULL);
            else
                ns = xmlSearchNs(style->doc, cur, prefix);
            if (ns == NULL) {
                xsltTransformError(NULL, style, cur,
            "xsl:exclude-result-prefixes : undefined namespace %s\n",
                                 prefix);
                if (style != NULL) style->warnings++;
            } else {
                if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) {
#ifdef WITH_XSLT_DEBUG_PARSING
                    xsltGenericDebug(xsltGenericDebugContext,
                        "exclude result prefix %s\n", prefix);
#endif
                    nb++;
                }
            }
            xmlFree(prefix);
        }
        prefix = end;
    }
    xmlFree(prefixes);
    return(nb);
}
#endif /* else of XSLT_REFACTORED */

#ifdef XSLT_REFACTORED

/*
* xsltTreeEnsureXMLDecl:
* @doc: the doc
* 
* BIG NOTE:
*  This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
* Ensures that there is an XML namespace declaration on the doc.
* 
* Returns the XML ns-struct or NULL on API and internal errors.
*/
static xmlNsPtr
xsltTreeEnsureXMLDecl(xmlDocPtr doc)
{
    if (doc == NULL)
        return (NULL);
    if (doc->oldNs != NULL)
        return (doc->oldNs);
    {
        xmlNsPtr ns;
        ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
        if (ns == NULL) {
            xmlGenericError(xmlGenericErrorContext,
                "xsltTreeEnsureXMLDecl: Failed to allocate "
                "the XML namespace.\n");        
            return (NULL);
        }
        memset(ns, 0, sizeof(xmlNs));
        ns->type = XML_LOCAL_NAMESPACE;
        /*
        * URGENT TODO: revisit this.
        */
#ifdef LIBXML_NAMESPACE_DICT
        if (doc->dict)
            ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
        else
            ns->href = xmlStrdup(XML_XML_NAMESPACE);
#else
        ns->href = xmlStrdup(XML_XML_NAMESPACE); 
#endif
        ns->prefix = xmlStrdup((const xmlChar *)"xml");
        doc->oldNs = ns;
        return (ns);
    }
}

/*
* xsltTreeAcquireStoredNs:
* @doc: the doc
* @nsName: the namespace name
* @prefix: the prefix
* 
* BIG NOTE:
*  This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
* Creates or reuses an xmlNs struct on doc->oldNs with
* the given prefix and namespace name.
* 
* Returns the aquired ns struct or NULL in case of an API
*         or internal error.
*/
static xmlNsPtr
xsltTreeAcquireStoredNs(xmlDocPtr doc,
                        const xmlChar *nsName,
                        const xmlChar *prefix)
{
    xmlNsPtr ns;

    if (doc == NULL)
        return (NULL);
    if (doc->oldNs != NULL)
        ns = doc->oldNs;
    else
        ns = xsltTreeEnsureXMLDecl(doc);
    if (ns == NULL)
        return (NULL);
    if (ns->next != NULL) {
        /* Reuse. */
        ns = ns->next;
        while (ns != NULL) {
            if ((ns->prefix == NULL) != (prefix == NULL)) {
                /* NOP */
            } else if (prefix == NULL) {
                if (xmlStrEqual(ns->href, nsName))
                    return (ns);
            } else {
                if ((ns->prefix[0] == prefix[0]) &&
                     xmlStrEqual(ns->prefix, prefix) &&
                     xmlStrEqual(ns->href, nsName))
                    return (ns);
                
            }
            if (ns->next == NULL)
                break;
            ns = ns->next;
        }
    }
    /* Create. */
    ns->next = xmlNewNs(NULL, nsName, prefix);
    return (ns->next);
}

/**
 * xsltLREBuildEffectiveNs:
 *
 * Apply ns-aliasing on the namespace of the given @elem and
 * its attributes.
 */
static int
xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
                        xmlNodePtr elem)
{
    xmlNsPtr ns;
    xsltNsAliasPtr alias;

    if ((cctxt == NULL) || (elem == NULL))
        return(-1);
    if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
        return(0);

    alias = cctxt->nsAliases;                   
    while (alias != NULL) {
        if ( /* If both namespaces are NULL... */
            ( (elem->ns == NULL) &&
            ((alias->literalNs == NULL) ||
            (alias->literalNs->href == NULL)) ) ||
            /* ... or both namespace are equal */
            ( (elem->ns != NULL) &&
            (alias->literalNs != NULL) &&
            xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
        {
            if ((alias->targetNs != NULL) &&
                (alias->targetNs->href != NULL))
            {
                /*
                * Convert namespace.
                */
                if (elem->doc == alias->docOfTargetNs) {
                    /*
                    * This is the nice case: same docs.
                    * This will eventually assign a ns-decl which
                    * is shadowed, but this has no negative effect on
                    * the generation of the result tree.
                    */
                    elem->ns = alias->targetNs;
                } else {
                    /*
                    * This target xmlNs originates from a different
                    * stylesheet tree. Try to locate it in the
                    * in-scope namespaces.
                    * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
                    */
                    ns = xmlSearchNs(elem->doc, elem,
                        alias->targetNs->prefix);                   
                    /*
                    * If no matching ns-decl found, then assign a
                    * ns-decl stored in xmlDoc.
                    */
                    if ((ns == NULL) ||
                        (! xmlStrEqual(ns->href, alias->targetNs->href)))
                    {
                        /*
                        * BIG NOTE: The use of xsltTreeAcquireStoredNs()
                        *  is not very efficient, but currently I don't
                        *  see an other way of *safely* changing a node's
                        *  namespace, since the xmlNs struct in
                        *  alias->targetNs might come from an other
                        *  stylesheet tree. So we need to anchor it in the
                        *  current document, without adding it to the tree,
                        *  which would otherwise change the in-scope-ns
                        *  semantic of the tree.
                        */
                        ns = xsltTreeAcquireStoredNs(elem->doc,
                            alias->targetNs->href,
                            alias->targetNs->prefix);
                        
                        if (ns == NULL) {
                            xsltTransformError(NULL, cctxt->style, elem,
                                "Internal error in "
                                "xsltLREBuildEffectiveNs(): "
                                "failed to acquire a stored "
                                "ns-declaration.\n");
                            cctxt->style->errors++;
                            return(-1);
                            
                        }
                    }
                    elem->ns = ns;
                }                  
            } else {
                /*
                * Move into or leave in the NULL namespace.
                */
                elem->ns = NULL;
            }
            break;
        }
        alias = alias->next;
    }
    /*
    * Same with attributes of literal result elements.
    */
    if (elem->properties != NULL) {
        xmlAttrPtr attr = elem->properties;
        
        while (attr != NULL) {
            if (attr->ns == NULL) {
                attr = attr->next;
                continue;
            }
            alias = cctxt->nsAliases;
            while (alias != NULL) {
                if ( /* If both namespaces are NULL... */
                    ( (elem->ns == NULL) &&
                    ((alias->literalNs == NULL) ||
                    (alias->literalNs->href == NULL)) ) ||
                    /* ... or both namespace are equal */
                    ( (elem->ns != NULL) &&
                    (alias->literalNs != NULL) &&
                    xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
                {
                    if ((alias->targetNs != NULL) &&
                        (alias->targetNs->href != NULL))
                    {               
                        if (elem->doc == alias->docOfTargetNs) {
                            elem->ns = alias->targetNs;
                        } else {
                            ns = xmlSearchNs(elem->doc, elem,
                                alias->targetNs->prefix);
                            if ((ns == NULL) ||
                                (! xmlStrEqual(ns->href, alias->targetNs->href)))
                            {
                                ns = xsltTreeAcquireStoredNs(elem->doc,
                                    alias->targetNs->href,
                                    alias->targetNs->prefix);
                                
                                if (ns == NULL) {
                                    xsltTransformError(NULL, cctxt->style, elem,
                                        "Internal error in "
                                        "xsltLREBuildEffectiveNs(): "
                                        "failed to acquire a stored "
                                        "ns-declaration.\n");
                                    cctxt->style->errors++;
                                    return(-1);
                                    
                                }
                            }
                            elem->ns = ns;
                        }
                    } else {
                    /*
                    * Move into or leave in the NULL namespace.
                        */
                        elem->ns = NULL;
                    }
                    break;
                }
                alias = alias->next;
            }
            
            attr = attr->next;
        }
    }
    return(0);
}

/**
 * xsltLREBuildEffectiveNsNodes:
 *
 * Computes the effective namespaces nodes for a literal result
 * element.
 * @effectiveNs is the set of effective ns-nodes
 *  on the literal result element, which will be added to the result
 *  element if not already existing in the result tree.
 *  This means that excluded namespaces (via exclude-result-prefixes,
 *  extension-element-prefixes and the XSLT namespace) not added
 *  to the set.
 *  Namespace-aliasing was applied on the @effectiveNs.
 */
static int
xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
                             xsltStyleItemLRElementInfoPtr item,
                             xmlNodePtr elem,
                             int isLRE)
{
    xmlNsPtr ns, tmpns;
    xsltEffectiveNsPtr effNs, lastEffNs = NULL;
    int i, j, holdByElem;
    xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
    xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;

    if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
        (item == NULL) || (item->effectiveNs != NULL))
        return(-1);

    if (item->inScopeNs == NULL)    
        return(0);

    extElemNs = cctxt->inode->extElemNs;
    exclResultNs = cctxt->inode->exclResultNs;

    for (i = 0; i < item->inScopeNs->totalNumber; i++) {
        ns = item->inScopeNs->list[i];
        /*
        * Skip namespaces designated as excluded namespaces
        * -------------------------------------------------
        *
        * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
        *  which are target namespaces of namespace-aliases
        *  regardless if designated as excluded.
        *
        * Exclude the XSLT namespace.
        */
        if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
            goto skip_ns;

        /*
        * Apply namespace aliasing
        * ------------------------
        *
        * SPEC XSLT 2.0
        *  "- A namespace node whose string value is a literal namespace
        *     URI is not copied to the result tree.
        *   - A namespace node whose string value is a target namespace URI
        *     is copied to the result tree, whether or not the URI
        *     identifies an excluded namespace."
        * 
        * NOTE: The ns-aliasing machanism is non-cascading.
        *  (checked with Saxon, Xalan and MSXML .NET).
        * URGENT TODO: is style->nsAliases the effective list of
        *  ns-aliases, or do we need to lookup the whole
        *  import-tree?
        * TODO: Get rid of import-tree lookup.
        */
        if (cctxt->hasNsAliases) {
            xsltNsAliasPtr alias;
            /*
            * First check for being a target namespace.
            */
            alias = cctxt->nsAliases;
            do {
                /*
                * TODO: Is xmlns="" handled already?
                */
                if ((alias->targetNs != NULL) &&
                    (xmlStrEqual(alias->targetNs->href, ns->href)))
                {
                    /*
                    * Recognized as a target namespace; use it regardless
                    * if excluded otherwise.
                    */
                    goto add_effective_ns;
                }
                alias = alias->next;
            } while (alias != NULL);

            alias = cctxt->nsAliases;
            do {
                /*
                * TODO: Is xmlns="" handled already?
                */
                if ((alias->literalNs != NULL) &&
                    (xmlStrEqual(alias->literalNs->href, ns->href)))
                {
                    /*
                    * Recognized as an namespace alias; do not use it.
                    */
                    goto skip_ns;
                }
                alias = alias->next;
            } while (alias != NULL);
        }
        
        /*
        * Exclude excluded result namespaces.
        */
        if (exclResultNs) {
            for (j = 0; j < exclResultNs->number; j++)
                if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
                    goto skip_ns;
        }
        /*
        * Exclude extension-element namespaces.
        */
        if (extElemNs) {
            for (j = 0; j < extElemNs->number; j++)
                if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
                    goto skip_ns;
        }

add_effective_ns:
        /*
        * OPTIMIZE TODO: This information may not be needed.
        */
        if (isLRE && (elem->nsDef != NULL)) {
            holdByElem = 0;
            tmpns = elem->nsDef;
            do {
                if (tmpns == ns) {
                    holdByElem = 1;
                    break;
                }
                tmpns = tmpns->next;
            } while (tmpns != NULL);        
        } else
            holdByElem = 0;
        
        
        /*
        * Add the effective namespace declaration.
        */
        effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
        if (effNs == NULL) {
            xsltTransformError(NULL, cctxt->style, elem,
                "Internal error in xsltLREBuildEffectiveNs(): "
                "failed to allocate memory.\n");
            cctxt->style->errors++;
            return(-1);
        }
        if (cctxt->psData->effectiveNs == NULL) {
            cctxt->psData->effectiveNs = effNs;
            effNs->nextInStore = NULL;   
        } else {
            effNs->nextInStore = cctxt->psData->effectiveNs;
            cctxt->psData->effectiveNs = effNs;
        }

        effNs->next = NULL;
        effNs->prefix = ns->prefix;
        effNs->nsName = ns->href;
        effNs->holdByElem = holdByElem;
        
        if (lastEffNs == NULL)
            item->effectiveNs = effNs;
        else
            lastEffNs->next = effNs;
        lastEffNs = effNs;
        
skip_ns:
        {}
    }
    return(0);
}


/**
 * xsltLREInfoCreate:
 *
 * @isLRE: indicates if the given @elem is a literal result element
 *
 * Creates a new info for a literal result element.
 */
static int
xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
                  xmlNodePtr elem,
                  int isLRE)
{
    xsltStyleItemLRElementInfoPtr item;

    if ((cctxt == NULL) || (cctxt->inode == NULL))
        return(-1);

    item = (xsltStyleItemLRElementInfoPtr)
        xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
    if (item == NULL) {
        xsltTransformError(NULL, cctxt->style, NULL,
            "Internal error in xsltLREInfoCreate(): "
            "memory allocation failed.\n");
        cctxt->style->errors++;
        return(-1);
    }
    memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
    item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
    /*
    * Store it in the stylesheet.
    */
    item->next = cctxt->style->preComps;
    cctxt->style->preComps = (xsltElemPreCompPtr) item;
    /*
    * @inScopeNs are used for execution of XPath expressions
    *  in AVTs.
    */
    item->inScopeNs = cctxt->inode->inScopeNs;
    
    if (elem)
        xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);

    cctxt->inode->litResElemInfo = item;
    cctxt->inode->nsChanged = 0;
    cctxt->maxLREs++;
    return(0);
}

/**
 * xsltCompilerVarInfoPush: 
 * @cctxt: the compilation context
 * 
 * Pushes a new var/param info onto the stack.
 *
 * Returns the acquired variable info.
 */ 
static xsltVarInfoPtr
xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,
                                  xmlNodePtr inst,
                                  const xmlChar *name,
                                  const xmlChar *nsName)
{
    xsltVarInfoPtr ivar;

    if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) {
        ivar = cctxt->ivar->next;
    } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) {
        ivar = cctxt->ivars;
    } else {
        ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo));
        if (ivar == NULL) {
            xsltTransformError(NULL, cctxt->style, inst,
                "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
            cctxt->style->errors++;
            return(NULL);
        }
        /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
        if (cctxt->ivars == NULL) {
            cctxt->ivars = ivar;
            ivar->prev = NULL;
        } else {
            cctxt->ivar->next = ivar;
            ivar->prev = cctxt->ivar;
        }
        cctxt->ivar = ivar;
        ivar->next = NULL;
    }
    ivar->depth = cctxt->depth;
    ivar->name = name;
    ivar->nsName = nsName;
    return(ivar);
}

/**
 * xsltCompilerVarInfoPop: 
 * @cctxt: the compilation context
 * 
 * Pops all var/param infos from the stack, which
 * have the current depth.
 */ 
static void
xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)
{

    while ((cctxt->ivar != NULL) &&
        (cctxt->ivar->depth > cctxt->depth))
    {
        cctxt->ivar = cctxt->ivar->prev;
    }
}

/*
* xsltCompilerNodePush:
*
* @cctxt: the compilation context
* @node: the node to be pushed (this can also be the doc-node)
*
* 
*
* Returns the current node info structure or
*         NULL in case of an internal error.
*/
static xsltCompilerNodeInfoPtr
xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
{    
    xsltCompilerNodeInfoPtr inode, iprev;

    if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {       
        inode = cctxt->inode->next;
    } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {
        inode = cctxt->inodeList;       
    } else {
        /*
        * Create a new node-info.
        */
        inode = (xsltCompilerNodeInfoPtr)
            xmlMalloc(sizeof(xsltCompilerNodeInfo));
        if (inode == NULL) {
            xsltTransformError(NULL, cctxt->style, NULL,
                "xsltCompilerNodePush: malloc failed.\n");
            return(NULL);
        }
        memset(inode, 0, sizeof(xsltCompilerNodeInfo));
        if (cctxt->inodeList == NULL)
            cctxt->inodeList = inode;
        else {
            cctxt->inodeLast->next = inode;
            inode->prev = cctxt->inodeLast;
        }
        cctxt->inodeLast = inode;
        cctxt->maxNodeInfos++;  
        if (cctxt->inode == NULL) {
            cctxt->inode = inode;
            /*
            * Create an initial literal result element info for
            * the root of the stylesheet.
            */
            xsltLREInfoCreate(cctxt, NULL, 0);
        } 
    }       
    cctxt->depth++;
    cctxt->inode = inode;
    /*
    * REVISIT TODO: Keep the reset always complete.    
    * NOTE: Be carefull with the @node, since it might be
    *  a doc-node.
    */
    inode->node = node;
    inode->depth = cctxt->depth;
    inode->templ = NULL;
    inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
    inode->type = 0;
    inode->item = NULL;
    inode->curChildType = 0;
    inode->extContentHandled = 0;
    inode->isRoot = 0;
    
    if (inode->prev != NULL) {
        iprev = inode->prev;
        /*
        * Inherit the following information:
        * ---------------------------------
        *
        * In-scope namespaces
        */
        inode->inScopeNs = iprev->inScopeNs;
        /*
        * Info for literal result elements
        */
        inode->litResElemInfo = iprev->litResElemInfo;
        inode->nsChanged = iprev->nsChanged;
        /*
        * Excluded result namespaces
        */
        inode->exclResultNs = iprev->exclResultNs;
        /*
        * Extension instruction namespaces
        */
        inode->extElemNs = iprev->extElemNs;
        /*
        * Whitespace preservation
        */
        inode->preserveWhitespace = iprev->preserveWhitespace;
        /*
        * Forwards-compatible mode
        */
        inode->forwardsCompat = iprev->forwardsCompat;  
    } else {
        inode->inScopeNs = NULL;
        inode->exclResultNs = NULL;
        inode->extElemNs = NULL;
        inode->preserveWhitespace = 0;
        inode->forwardsCompat = 0;
    }
    
    return(inode);
}

/*
* xsltCompilerNodePop:
*
* @cctxt: the compilation context
* @node: the node to be pushed (this can also be the doc-node)
*
* Pops the current node info.
*/
static void
xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
{    
    if (cctxt->inode == NULL) {
        xmlGenericError(xmlGenericErrorContext,
            "xsltCompilerNodePop: Top-node mismatch.\n");
        return;
    }
    /*
    * NOTE: Be carefull with the @node, since it might be
    *  a doc-node.
    */
    if (cctxt->inode->node != node) {
        xmlGenericError(xmlGenericErrorContext,
        "xsltCompilerNodePop: Node mismatch.\n");
        goto mismatch;
    }
    if (cctxt->inode->depth != cctxt->depth) {
        xmlGenericError(xmlGenericErrorContext,
        "xsltCompilerNodePop: Depth mismatch.\n");
        goto mismatch;
    }
    /*
    * Pop information of variables.
    */
    if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))
        xsltCompilerVarInfoPop(cctxt);

    cctxt->depth--;
    cctxt->inode = cctxt->inode->prev;
    if (cctxt->inode != NULL)
        cctxt->inode->curChildType = 0;
    return;

mismatch:
    {
        const xmlChar *nsName = NULL, *name = NULL;
        const xmlChar *infnsName = NULL, *infname = NULL;
        
        if (node) {
            if (node->type == XML_ELEMENT_NODE) {
                name = node->name;
                if (node->ns != NULL)
                    nsName = node->ns->href;
                else
                    nsName = BAD_CAST "";
            } else {
                name = BAD_CAST "#document";
                nsName = BAD_CAST "";
            }
        } else
            name = BAD_CAST "Not given";

        if (cctxt->inode->node) {
            if (node->type == XML_ELEMENT_NODE) {
                infname = cctxt->inode->node->name;
                if (cctxt->inode->node->ns != NULL)
                    infnsName = cctxt->inode->node->ns->href;
                else
                    infnsName = BAD_CAST "";
            } else {
                infname = BAD_CAST "#document";
                infnsName = BAD_CAST "";
            }
        } else
            infname = BAD_CAST "Not given";

        
        xmlGenericError(xmlGenericErrorContext,
            "xsltCompilerNodePop: Given   : '%s' URI '%s'\n",
            name, nsName);
        xmlGenericError(xmlGenericErrorContext,
            "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
            infname, infnsName);
    }
}

/*
* xsltCompilerBuildInScopeNsList:
*
* Create and store the list of in-scope namespaces for the given
* node in the stylesheet. If there are no changes in the in-scope
* namespaces then the last ns-info of the ancestor axis will be returned.
* Compilation-time only.
*
* Returns the ns-info or NULL if there are no namespaces in scope.
*/
static xsltNsListContainerPtr
xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
{
    xsltNsListContainerPtr nsi = NULL;
    xmlNsPtr *list = NULL, ns;
    int i, maxns = 5;
    /*
    * Create a new ns-list for this position in the node-tree.
    * xmlGetNsList() will return NULL, if there are no ns-decls in the
    * tree. Note that the ns-decl for the XML namespace is not added
    * to the resulting list; the XPath module handles the XML namespace
    * internally.
    */
    while (node != NULL) {
        if (node->type == XML_ELEMENT_NODE) {
            ns = node->nsDef;
            while (ns != NULL) {
                if (nsi == NULL) {
                    nsi = (xsltNsListContainerPtr)
                        xmlMalloc(sizeof(xsltNsListContainer));
                    if (nsi == NULL) {
                        xsltTransformError(NULL, cctxt->style, NULL,
                            "xsltCompilerBuildInScopeNsList: "
                            "malloc failed!\n");
                        goto internal_err;
                    }
                    memset(nsi, 0, sizeof(xsltNsListContainer));
                    nsi->list =
                        (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
                    if (nsi->list == NULL) {
                        xsltTransformError(NULL, cctxt->style, NULL,
                            "xsltCompilerBuildInScopeNsList: "
                            "malloc failed!\n");
                        goto internal_err;
                    }
                    nsi->list[0] = NULL;
                }
                /*
                * Skip shadowed namespace bindings.
                */
                for (i = 0; i < nsi->totalNumber; i++) {
                    if ((ns->prefix == nsi->list[i]->prefix) ||
                        (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
                    break;
                }
                if (i >= nsi->totalNumber) {
                    if (nsi->totalNumber +1 >= maxns) {
                        maxns *= 2;
                        nsi->list =
                            (xmlNsPtr *) xmlRealloc(nsi->list,
                                maxns * sizeof(xmlNsPtr));
                        if (nsi->list == NULL) {
                            xsltTransformError(NULL, cctxt->style, NULL,
                                "xsltCompilerBuildInScopeNsList: "
                                "realloc failed!\n");
                                goto internal_err;
                        }
                    }
                    nsi->list[nsi->totalNumber++] = ns;
                    nsi->list[nsi->totalNumber] = NULL;
                }

                ns = ns->next;
            }
        }
        node = node->parent;
    }
    if (nsi == NULL)
        return(NULL);
    /*
    * Move the default namespace to last position.
    */
    nsi->xpathNumber = nsi->totalNumber;
    for (i = 0; i < nsi->totalNumber; i++) {
        if (nsi->list[i]->prefix == NULL) {
            ns = nsi->list[i];
            nsi->list[i] = nsi->list[nsi->totalNumber-1];
            nsi->list[nsi->totalNumber-1] = ns;
            nsi->xpathNumber--;
            break;
        }
    }
    /*
    * Store the ns-list in the stylesheet.
    */
    if (xsltPointerListAddSize(
        (xsltPointerListPtr)cctxt->psData->inScopeNamespaces,
        (void *) nsi, 5) == -1)
    {   
        xmlFree(nsi);
        nsi = NULL;
        xsltTransformError(NULL, cctxt->style, NULL,
            "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
        goto internal_err;
    }
    /*
    * Notify of change in status wrt namespaces.
    */
    if (cctxt->inode != NULL)
        cctxt->inode->nsChanged = 1;

    return(nsi);

internal_err:
    if (list != NULL)
        xmlFree(list);    
    cctxt->style->errors++;
    return(NULL);
}

static int
xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
                      xsltPointerListPtr list,
                      xmlNodePtr node,
                      const xmlChar *value)
{
    xmlChar *cur, *end;
    xmlNsPtr ns;
    
    if ((cctxt == NULL) || (value == NULL) || (list == NULL))
        return(-1);

    list->number = 0;

    cur = (xmlChar *) value;
    while (*cur != 0) {
        while (IS_BLANK(*cur)) cur++;
        if (*cur == 0)
            break;
        end = cur;
        while ((*end != 0) && (!IS_BLANK(*end))) end++;
        cur = xmlStrndup(cur, end - cur);
        if (cur == NULL) {
            cur = end;
            continue;
        }               
        /*
        * TODO: Export and use xmlSearchNsByPrefixStrict()
        *   in Libxml2, tree.c, since xmlSearchNs() is in most
        *   cases not efficient and in some cases not correct.
        *
        * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
        */
        if ((cur[0] == '#') &&
            xmlStrEqual(cur, (const xmlChar *)"#default"))
            ns = xmlSearchNs(cctxt->style->doc, node, NULL);
        else
            ns = xmlSearchNs(cctxt->style->doc, node, cur);         

        if (ns == NULL) {
            /*
            * TODO: Better to report the attr-node, otherwise
            *  the user won't know which attribute was invalid.
            */
            xsltTransformError(NULL, cctxt->style, node,
                "No namespace binding in scope for prefix '%s'.\n", cur);
            /*
            * XSLT-1.0: "It is an error if there is no namespace
            *  bound to the prefix on the element bearing the
            *  exclude-result-prefixes or xsl:exclude-result-prefixes
            *  attribute."
            */
            cctxt->style->errors++;
        } else {
#ifdef WITH_XSLT_DEBUG_PARSING
            xsltGenericDebug(xsltGenericDebugContext,
                "resolved prefix '%s'\n", cur);
#endif
            /*
            * Note that we put the namespace name into the dict.
            */
            if (xsltPointerListAddSize(list,
                (void *) xmlDictLookup(cctxt->style->dict,
                ns->href, -1), 5) == -1)
            {
                xmlFree(cur);
                goto internal_err;
            }
        }
        xmlFree(cur);
                
        cur = end;
    }
    return(0);

internal_err:
    cctxt->style->errors++;
    return(-1);
}

/**
 * xsltCompilerUtilsCreateMergedList:
 * @dest: the destination list (optional)
 * @first: the first list
 * @second: the second list (optional)
 *
 * Appends the content of @second to @first into @destination.
 * If @destination is NULL a new list will be created.
 *
 * Returns the merged list of items or NULL if there's nothing to merge.
 */
static xsltPointerListPtr
xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,
                            xsltPointerListPtr second)
{
    xsltPointerListPtr ret;
    size_t num;

    if (first)
        num = first->number;
    else
        num = 0;
    if (second)
        num += second->number;    
    if (num == 0)
        return(NULL);
    ret = xsltPointerListCreate(num);
    if (ret == NULL)
        return(NULL);
    /*
    * Copy contents.
    */
    if ((first != NULL) &&  (first->number != 0)) {
        memcpy(ret->items, first->items,
            first->number * sizeof(void *));
        if ((second != NULL) && (second->number != 0))
            memcpy(ret->items + first->number, second->items,
                second->number * sizeof(void *));
    } else if ((second != NULL) && (second->number != 0))
        memcpy(ret->items, (void *) second->items,
            second->number * sizeof(void *));
    ret->number = num;
    return(ret);
}

/*
* xsltParseExclResultPrefixes:
*
* Create and store the list of in-scope namespaces for the given
* node in the stylesheet. If there are no changes in the in-scope
* namespaces then the last ns-info of the ancestor axis will be returned.
* Compilation-time only.
*
* Returns the ns-info or NULL if there are no namespaces in scope.
*/
static xsltPointerListPtr
xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
                            xsltPointerListPtr def,
                            int instrCategory)
{    
    xsltPointerListPtr list = NULL;
    xmlChar *value;
    xmlAttrPtr attr;

    if ((cctxt == NULL) || (node == NULL))
        return(NULL);

    if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
        attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
    else
        attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
            XSLT_NAMESPACE);
    if (attr == NULL)   
        return(def);

    if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
        /*
        * Mark the XSLT attr.
        */
        attr->psvi = (void *) xsltXSLTAttrMarker;
    }

    if ((attr->children != NULL) &&     
        (attr->children->content != NULL))
        value = attr->children->content;
    else {
        xsltTransformError(NULL, cctxt->style, node,
            "Attribute 'exclude-result-prefixes': Invalid value.\n");
        cctxt->style->errors++;
        return(def);
    }        

    if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
        BAD_CAST value) != 0)
        goto exit;
    if (cctxt->tmpList->number == 0)    
        goto exit;    
    /*
    * Merge the list with the inherited list.
    */
    list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
    if (list == NULL)
        goto exit;    
    /*
    * Store the list in the stylesheet/compiler context.
    */
    if (xsltPointerListAddSize(
        cctxt->psData->exclResultNamespaces, list, 5) == -1)
    {
        xsltPointerListFree(list);
        list = NULL;
        goto exit;
    }
    /*
    * Notify of change in status wrt namespaces.
    */
    if (cctxt->inode != NULL)
        cctxt->inode->nsChanged = 1;

exit:    
    if (list != NULL)
        return(list);
    else
        return(def);
}

/*
* xsltParseExtElemPrefixes:
*
* Create and store the list of in-scope namespaces for the given
* node in the stylesheet. If there are no changes in the in-scope
* namespaces then the last ns-info of the ancestor axis will be returned.
* Compilation-time only.
*
* Returns the ns-info or NULL if there are no namespaces in scope.
*/
static xsltPointerListPtr
xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
                         xsltPointerListPtr def,
                         int instrCategory)
{    
    xsltPointerListPtr list = NULL;
    xmlAttrPtr attr;
    xmlChar *value;
    int i;

    if ((cctxt == NULL) || (node == NULL))
        return(NULL);

    if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
        attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
    else
        attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
            XSLT_NAMESPACE);
    if (attr == NULL)   
        return(def);

    if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
        /*
        * Mark the XSLT attr.
        */
        attr->psvi = (void *) xsltXSLTAttrMarker;
    }

    if ((attr->children != NULL) &&     
        (attr->children->content != NULL))
        value = attr->children->content;
    else {
        xsltTransformError(NULL, cctxt->style, node,
            "Attribute 'extension-element-prefixes': Invalid value.\n");
        cctxt->style->errors++;
        return(def);
    }


    if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
        BAD_CAST value) != 0)
        goto exit;

    if (cctxt->tmpList->number == 0)
        goto exit;    
    /*
    * REVISIT: Register the extension namespaces.
    */
    for (i = 0; i < cctxt->tmpList->number; i++)
        xsltRegisterExtPrefix(cctxt->style, NULL,
        BAD_CAST cctxt->tmpList->items[i]);
    /*
    * Merge the list with the inherited list.
    */
    list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
    if (list == NULL)
        goto exit;
    /*
    * Store the list in the stylesheet.
    */
    if (xsltPointerListAddSize(
        cctxt->psData->extElemNamespaces, list, 5) == -1)
    {
        xsltPointerListFree(list);
        list = NULL;
        goto exit;
    }
    /*
    * Notify of change in status wrt namespaces.
    */
    if (cctxt->inode != NULL)
        cctxt->inode->nsChanged = 1;

exit:    
    if (list != NULL)
        return(list);
    else
        return(def);
}

/*
* xsltParseAttrXSLTVersion:
*
* @cctxt: the compilation context
* @node: the element-node
* @isXsltElem: whether this is an XSLT element
*
* Parses the attribute xsl:version.
*
* Returns 1 if there was such an attribute, 0 if not and
*         -1 if an internal or API error occured.
*/
static int
xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,                     
                         int instrCategory)
{
    xmlChar *value;
    xmlAttrPtr attr;

    if ((cctxt == NULL) || (node == NULL))
        return(-1);

    if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
        attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
    else
        attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);

    if (attr == NULL)   
        return(0);

    attr->psvi = (void *) xsltXSLTAttrMarker;

    if ((attr->children != NULL) &&     
        (attr->children->content != NULL))
        value = attr->children->content;
    else {
        xsltTransformError(NULL, cctxt->style, node,
            "Attribute 'version': Invalid value.\n");
        cctxt->style->errors++;
        return(1);
    }
    
    if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
        cctxt->inode->forwardsCompat = 1;
        /*
        * TODO: To what extent do we support the
        *  forwards-compatible mode?
        */
        /*
        * Report this only once per compilation episode.
        */
        if (! cctxt->hasForwardsCompat) {
            cctxt->hasForwardsCompat = 1;
            cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;
            xsltTransformError(NULL, cctxt->style, node,
                "Warning: the attribute xsl:version specifies a value "
                "different from '1.0'. Switching to forwards-compatible "
                "mode. Only features of XSLT 1.0 are supported by this "
                "processor.\n");
            cctxt->style->warnings++;
            cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
        }       
    } else {
        cctxt->inode->forwardsCompat = 0;
    }

    if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
        /*
        * Set a marker on XSLT attributes.
        */
        attr->psvi = (void *) xsltXSLTAttrMarker;
    }
    return(1);
}

static int
xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
{
    xmlNodePtr deleteNode, cur, txt, textNode = NULL;
    xmlDocPtr doc;
    xsltStylesheetPtr style;
    int internalize = 0, findSpaceAttr;
    int xsltStylesheetElemDepth;
    xmlAttrPtr attr;
    xmlChar *value;
    const xmlChar *name, *nsNameXSLT = NULL;
    int strictWhitespace, inXSLText = 0;
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
    xsltNsMapPtr nsMapItem;
#endif

    if ((cctxt == NULL) || (cctxt->style == NULL) ||
        (node == NULL) || (node->type != XML_ELEMENT_NODE))
        return(-1);

    doc = node->doc;
    if (doc == NULL)
        goto internal_err;

    style = cctxt->style;
    if ((style->dict != NULL) && (doc->dict == style->dict))
        internalize = 1;
    else
        style->internalized = 0;

    /*
    * Init value of xml:space. Since this might be an embedded
    * stylesheet, this is needed to be performed on the element
    * where the stylesheet is rooted at, taking xml:space of
    * ancestors into account.
    */
    if (! cctxt->simplified)
        xsltStylesheetElemDepth = cctxt->depth +1;
    else
        xsltStylesheetElemDepth = 0;

    if (xmlNodeGetSpacePreserve(node) != 1)
        cctxt->inode->preserveWhitespace = 0;
    else
        cctxt->inode->preserveWhitespace = 1; 
    
    /*
    * Eval if we should keep the old incorrect behaviour.
    */
    strictWhitespace = (cctxt->strict != 0) ? 1 : 0;

    nsNameXSLT = xsltConstNamespaceNameXSLT;

    deleteNode = NULL;
    cur = node;
    while (cur != NULL) {
        if (deleteNode != NULL) {

#ifdef WITH_XSLT_DEBUG_BLANKS
            xsltGenericDebug(xsltGenericDebugContext,
             "xsltParsePreprocessStylesheetTree: removing node\n");
#endif
            xmlUnlinkNode(deleteNode);
            xmlFreeNode(deleteNode);
            deleteNode = NULL;
        }
        if (cur->type == XML_ELEMENT_NODE) {
            
            /*
            * Clear the PSVI field.
            */
            cur->psvi = NULL;

            xsltCompilerNodePush(cctxt, cur);

            inXSLText = 0;
            textNode = NULL;        
            findSpaceAttr = 1;      
            cctxt->inode->stripWhitespace = 0;
            /*
            * TODO: I'd love to use a string pointer comparison here :-/
            */
            if (IS_XSLT_ELEM(cur)) {
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
                if (cur->ns->href != nsNameXSLT) {
                    nsMapItem = xsltNewNamespaceMapItem(cctxt,
                        doc, cur->ns, cur);
                    if (nsMapItem == NULL)
                        goto internal_err;
                    cur->ns->href = nsNameXSLT;
                }
#endif

                if (cur->name == NULL)
                    goto process_attributes;
                /*
                * Mark the XSLT element for later recognition.
                * TODO: Using the marker is still too dangerous, since if
                *   the parsing mechanism leaves out an XSLT element, then
                *   this might hit the transformation-mechanism, which
                *   will break if it doesn't expect such a marker.
                */
                /* cur->psvi = (void *) xsltXSLTElemMarker; */

                /*
                * XSLT 2.0: "Any whitespace text node whose parent is
                * one of the following elements is removed from the "
                * tree, regardless of any xml:space attributes:..."
                * xsl:apply-imports, 
                * xsl:apply-templates,
                * xsl:attribute-set,
                * xsl:call-template, 
                * xsl:choose,
                * xsl:stylesheet, xsl:transform.
                * XSLT 2.0: xsl:analyze-string,
                *           xsl:character-map,
                *           xsl:next-match              
                *
                * TODO: I'd love to use a string pointer comparison here :-/
                */              
                name = cur->name;
                switch (*name) {
                    case 't':
                        if ((name[0] == 't') && (name[1] == 'e') &&
                            (name[2] == 'x') && (name[3] == 't') &&
                            (name[4] == 0))
                        {
                            /*
                            * Process the xsl:text element.
                            * ----------------------------
                            * Mark it for later recognition.
                            */
                            cur->psvi = (void *) xsltXSLTTextMarker;
                            /*
                            * For stylesheets, the set of
                            * whitespace-preserving element names
                            * consists of just xsl:text.
                            */
                            findSpaceAttr = 0;
                            cctxt->inode->preserveWhitespace = 1;
                            inXSLText = 1;
                        }                           
                        break;
                    case 'c':
                        if (xmlStrEqual(name, BAD_CAST "choose") ||
                            xmlStrEqual(name, BAD_CAST "call-template"))
                            cctxt->inode->stripWhitespace = 1;
                        break;
                    case 'a':
                        if (xmlStrEqual(name, BAD_CAST "apply-templates") ||
                            xmlStrEqual(name, BAD_CAST "apply-imports") ||
                            xmlStrEqual(name, BAD_CAST "attribute-set"))

                            cctxt->inode->stripWhitespace = 1;
                        break;
                    default:
                        if (xsltStylesheetElemDepth == cctxt->depth) {
                            /*
                            * This is a xsl:stylesheet/xsl:transform.
                            */
                            cctxt->inode->stripWhitespace = 1;
                            break;
                        }

                        if ((cur->prev != NULL) &&
                            (cur->prev->type == XML_TEXT_NODE))
                        {
                            /*
                            * XSLT 2.0 : "Any whitespace text node whose
                            *  following-sibling node is an xsl:param or
                            *  xsl:sort element is removed from the tree,
                            *  regardless of any xml:space attributes."
                            */
                            if (((*name == 'p') || (*name == 's')) &&
                                (xmlStrEqual(name, BAD_CAST "param") ||
                                 xmlStrEqual(name, BAD_CAST "sort")))
                            {
                                do {
                                    if (IS_BLANK_NODE(cur->prev)) {
                                        txt = cur->prev;
                                        xmlUnlinkNode(txt);
                                        xmlFreeNode(txt);
                                    } else {
                                        /*
                                        * This will result in a content
                                        * error, when hitting the parsing
                                        * functions.
                                        */
                                        break;
                                    }
                                } while (cur->prev);                                
                            }
                        }
                        break;
                }
            }

process_attributes:
            /*
            * Process attributes.
            * ------------------
            */
            if (cur->properties != NULL) {
                if (cur->children == NULL)
                    findSpaceAttr = 0;
                attr = cur->properties;
                do {
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
                    if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
                        xmlStrEqual(attr->ns->href, nsNameXSLT))
                    {                   
                        nsMapItem = xsltNewNamespaceMapItem(cctxt,
                            doc, attr->ns, cur);
                        if (nsMapItem == NULL)
                            goto internal_err;
                        attr->ns->href = nsNameXSLT;
                    }               
#endif
                    if (internalize) {
                        /*
                        * Internalize the attribute's value; the goal is to
                        * speed up operations and minimize used space by
                        * compiled stylesheets.
                        */
                        txt = attr->children;
                        /*
                        * NOTE that this assumes only one
                        *  text-node in the attribute's content.
                        */
                        if ((txt != NULL) && (txt->content != NULL) &&
                            (!xmlDictOwns(style->dict, txt->content)))
                        {
                            value = (xmlChar *) xmlDictLookup(style->dict,
                                txt->content, -1);
                            xmlNodeSetContent(txt, NULL);
                            txt->content = value;
                        }
                    }
                    /*
                    * Process xml:space attributes.
                    * ----------------------------
                    */
                    if ((findSpaceAttr != 0) &&
                        (attr->ns != NULL) &&
                        (attr->name != NULL) &&
                        (attr->name[0] == 's') &&                       
                        (attr->ns->prefix != NULL) &&
                        (attr->ns->prefix[0] == 'x') &&
                        (attr->ns->prefix[1] == 'm') &&
                        (attr->ns->prefix[2] == 'l') &&
                        (attr->ns->prefix[3] == 0))
                    {
                        value = xmlGetNsProp(cur, BAD_CAST "space",
                            XML_XML_NAMESPACE);
                        if (value != NULL) {
                            if (xmlStrEqual(value, BAD_CAST "preserve")) {
                                cctxt->inode->preserveWhitespace = 1;                           
                            } else if (xmlStrEqual(value, BAD_CAST "default")) {
                                cctxt->inode->preserveWhitespace = 0;
                            } else {
                                /* Invalid value for xml:space. */
                                xsltTransformError(NULL, style, cur,
                                    "Attribute xml:space: Invalid value.\n");
                                cctxt->style->warnings++;
                            }
                            findSpaceAttr = 0;
                            xmlFree(value);
                        }
                        
                    }
                    attr = attr->next;
                } while (attr != NULL);
            }
            /*
            * We'll descend into the children of element nodes only.
            */
            if (cur->children != NULL) {
                cur = cur->children;
                continue;
            }
        } else if ((cur->type == XML_TEXT_NODE) ||
                (cur->type == XML_CDATA_SECTION_NODE))
        {
            /*
            * Merge adjacent text/CDATA-section-nodes
            * ---------------------------------------       
            * In order to avoid breaking of existing stylesheets,
            * if the old behaviour is wanted (strictWhitespace == 0),
            * then we *won't* merge adjacent text-nodes
            * (except in xsl:text); this will ensure that whitespace-only
            * text nodes are (incorrectly) not stripped in some cases.
            * 
            * Example:               : <foo>  <!-- bar -->zoo</foo>
            * Corrent (strict) result: <foo>  zoo</foo>
            * Incorrect (old) result : <foo>zoo</foo>
            *    
            * NOTE that we *will* merge adjacent text-nodes if
            * they are in xsl:text.
            * Example, the following:
            * <xsl:text>  <!-- bar -->zoo<xsl:text>
            * will result in both cases in:
            * <xsl:text>  zoo<xsl:text>
            */
            cur->type = XML_TEXT_NODE;
            if ((strictWhitespace != 0) || (inXSLText != 0)) {
                /*
                * New behaviour; merge nodes.
                */
                if (textNode == NULL)
                    textNode = cur;
                else {
                    if (cur->content != NULL)
                        xmlNodeAddContent(textNode, cur->content);
                    deleteNode = cur;
                }
                if ((cur->next == NULL) ||
                    (cur->next->type == XML_ELEMENT_NODE))
                    goto end_of_text;
                else
                    goto next_sibling;
            } else {
                /*
                * Old behaviour.
                */
                if (textNode == NULL)
                    textNode = cur;
                goto end_of_text;
            }              
        } else if ((cur->type == XML_COMMENT_NODE) ||
            (cur->type == XML_PI_NODE))
        {           
            /*
            * Remove processing instructions and comments.
            */
            deleteNode = cur;
            if ((cur->next == NULL) ||
                (cur->next->type == XML_ELEMENT_NODE))
                goto end_of_text;
            else
                goto next_sibling;
        } else {
            textNode = NULL;
            /*
            * Invalid node-type for this data-model.
            */
            xsltTransformError(NULL, style, cur,
                "Invalid type of node for the XSLT data model.\n");
            cctxt->style->errors++;
            goto next_sibling;
        }

end_of_text:
        if (textNode) {
            value = textNode->content;
            /*
            * At this point all adjacent text/CDATA-section nodes
            * have been merged.
            *
            * Strip whitespace-only text-nodes.
            * (cctxt->inode->stripWhitespace)
            */
            if ((value == NULL) || (*value == 0) ||
                (((cctxt->inode->stripWhitespace) ||
                  (! cctxt->inode->preserveWhitespace)) &&
                 IS_BLANK(*value) &&
                 xsltIsBlank(value)))
            {           
                if (textNode != cur) {
                    xmlUnlinkNode(textNode);
                    xmlFreeNode(textNode);
                } else
                    deleteNode = textNode;
                textNode = NULL;
                goto next_sibling;
            }
            /*
            * Convert CDATA-section nodes to text-nodes.
            * TODO: Can this produce problems?
            */
            if (textNode->type != XML_TEXT_NODE) {
                textNode->type = XML_TEXT_NODE;
                textNode->name = xmlStringText;
            }
            if (internalize &&
                (textNode->content != NULL) &&
                (!xmlDictOwns(style->dict, textNode->content)))
            {
                /*
                * Internalize the string.
                */
                value = (xmlChar *) xmlDictLookup(style->dict,
                    textNode->content, -1);
                xmlNodeSetContent(textNode, NULL);
                textNode->content = value;
            }
            textNode = NULL;
            /*
            * Note that "disable-output-escaping" of the xsl:text
            * element will be applied at a later level, when
            * XSLT elements are processed.
            */
        }

next_sibling:
        if (cur->type == XML_ELEMENT_NODE) {
            xsltCompilerNodePop(cctxt, cur);
        }
        if (cur == node)
            break;
        if (cur->next != NULL) {
            cur = cur->next;
        } else {
            cur = cur->parent;
            inXSLText = 0;
            goto next_sibling;
        };
    }
    if (deleteNode != NULL) {
#ifdef WITH_XSLT_DEBUG_PARSING
        xsltGenericDebug(xsltGenericDebugContext,
         "xsltParsePreprocessStylesheetTree: removing node\n");
#endif
        xmlUnlinkNode(deleteNode);
        xmlFreeNode(deleteNode);
    }
    return(0);

internal_err:
    return(-1);
}

#endif /* XSLT_REFACTORED */

#ifdef XSLT_REFACTORED
#else
static void
xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
{
    xmlNodePtr deleteNode, styleelem;
    int internalize = 0;

    if ((style == NULL) || (cur == NULL))
        return;

    if ((cur->doc != NULL) && (style->dict != NULL) &&
        (cur->doc->dict == style->dict))
        internalize = 1;
    else
        style->internalized = 0;

    if ((cur != NULL) && (IS_XSLT_ELEM(cur)) &&
        (IS_XSLT_NAME(cur, "stylesheet"))) {
        styleelem = cur;
    } else {
        styleelem = NULL;
    }

    /*
     * This content comes from the stylesheet
     * For stylesheets, the set of whitespace-preserving
     * element names consists of just xsl:text.
     */
    deleteNode = NULL;
    while (cur != NULL) {
        if (deleteNode != NULL) {
#ifdef WITH_XSLT_DEBUG_BLANKS
            xsltGenericDebug(xsltGenericDebugContext,
             "xsltPrecomputeStylesheet: removing ignorable blank node\n");
#endif
            xmlUnlinkNode(deleteNode);
            xmlFreeNode(deleteNode);
            deleteNode = NULL;
        }
        if (cur->type == XML_ELEMENT_NODE) {
            int exclPrefixes;
            /*
             * Internalize attributes values.
             */
            if ((internalize) && (cur->properties != NULL)) {
                xmlAttrPtr attr = cur->properties;
                xmlNodePtr txt;

                while (attr != NULL) {
                    txt = attr->children;
                    if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
                        (txt->content != NULL) &&
                        (!xmlDictOwns(style->dict, txt->content)))
                    {
                        xmlChar *tmp;

                        /*
                         * internalize the text string, goal is to speed
                         * up operations and minimize used space by compiled
                         * stylesheets.
                         */
                        tmp = (xmlChar *) xmlDictLookup(style->dict,
                                                        txt->content, -1);
                        if (tmp != txt->content) {
                            xmlNodeSetContent(txt, NULL);
                            txt->content = tmp;
                        }
                    }
                    attr = attr->next;
                }
            }
            if (IS_XSLT_ELEM(cur)) {
                exclPrefixes = 0;
                xsltStylePreCompute(style, cur);
                if (IS_XSLT_NAME(cur, "text")) {
                    for (;exclPrefixes > 0;exclPrefixes--)
                        exclPrefixPop(style);
                    goto skip_children;
                }
            } else {
                exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
            }
                     
            if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
                xmlNsPtr ns = cur->nsDef, prev = NULL, next;
                xmlNodePtr root = NULL;
                int i, moved;

                root = xmlDocGetRootElement(cur->doc);
                if ((root != NULL) && (root != cur)) {
                    while (ns != NULL) {
                        moved = 0;
                        next = ns->next;
                        for (i = 0;i < style->exclPrefixNr;i++) {
                            if ((ns->prefix != NULL) && 
                                (xmlStrEqual(ns->href,
                                             style->exclPrefixTab[i]))) {
                                /*
                                 * Move the namespace definition on the root
                                 * element to avoid duplicating it without
                                 * loosing it.
                                 */
                                if (prev == NULL) {
                                    cur->nsDef = ns->next;
                                } else {
                                    prev->next = ns->next;
                                }
                                ns->next = root->nsDef;
                                root->nsDef = ns;
                                moved = 1;
                                break;
                            }
                        }
                        if (moved == 0)
                            prev = ns;
                        ns = next;
                    }
                }
            }
            /*
             * If we have prefixes locally, recurse and pop them up when
             * going back
             */
            if (exclPrefixes > 0) {
                xsltPrecomputeStylesheet(style, cur->children);
                for (;exclPrefixes > 0;exclPrefixes--)
                    exclPrefixPop(style);
                goto skip_children;
            }
        } else if (cur->type == XML_TEXT_NODE) {
            if (IS_BLANK_NODE(cur)) {
                if (xmlNodeGetSpacePreserve(cur) != 1) {
                    deleteNode = cur;
                }
            } else if ((cur->content != NULL) && (internalize) &&
                       (!xmlDictOwns(style->dict, cur->content))) {
                xmlChar *tmp;

                /*
                 * internalize the text string, goal is to speed
                 * up operations and minimize used space by compiled
                 * stylesheets.
                 */
                tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
                xmlNodeSetContent(cur, NULL);
                cur->content = tmp;
            }
        } else if ((cur->type != XML_ELEMENT_NODE) &&
                   (cur->type != XML_CDATA_SECTION_NODE)) {
            deleteNode = cur;
            goto skip_children;
        }

        /*
         * Skip to next node. In case of a namespaced element children of
         * the stylesheet and not in the XSLT namespace and not an extension
         * element, ignore its content.
         */
        if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) &&
            (styleelem != NULL) && (cur->parent == styleelem) &&
            (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) &&
            (!xsltCheckExtURI(style, cur->ns->href))) {
            goto skip_children;
        } else if (cur->children != NULL) {
            if ((cur->children->type != XML_ENTITY_DECL) &&
                (cur->children->type != XML_ENTITY_REF_NODE) &&
                (cur->children->type != XML_ENTITY_NODE)) {
                cur = cur->children;
                continue;
            }
        }

skip_children:
        if (cur->next != NULL) {
            cur = cur->next;
            continue;
        }
        do {

            cur = cur->parent;
            if (cur == NULL)
                break;
            if (cur == (xmlNodePtr) style->doc) {
                cur = NULL;
                break;
            }
            if (cur->next != NULL) {
                cur = cur->next;
                break;
            }
        } while (cur != NULL);
    }
    if (deleteNode != NULL) {
#ifdef WITH_XSLT_DEBUG_PARSING
        xsltGenericDebug(xsltGenericDebugContext,
         "xsltPrecomputeStylesheet: removing ignorable blank node\n");
#endif
        xmlUnlinkNode(deleteNode);
        xmlFreeNode(deleteNode);
    }
}
#endif /* end of else XSLT_REFACTORED */

/**
 * xsltGatherNamespaces:
 * @style:  the XSLT stylesheet
 *
 * Browse the stylesheet and build the namspace hash table which
 * will be used for XPath interpretation. If needed do a bit of normalization
 */

static void
xsltGatherNamespaces(xsltStylesheetPtr style) {
    xmlNodePtr cur;
    const xmlChar *URI;

    if (style == NULL)
        return;
    /* 
     * TODO: basically if the stylesheet uses the same prefix for different
     *       patterns, well they may be in problem, hopefully they will get
     *       a warning first.
     */
    /*
    * TODO: Eliminate the use of the hash for XPath expressions.
    *   An expression should be evaluated in the context of the in-scope
    *   namespaces; eliminate the restriction of an XML document to contain
    *   no duplicate prefixes for different namespace names.
    * 
    */
    cur = xmlDocGetRootElement(style->doc);
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            xmlNsPtr ns = cur->nsDef;
            while (ns != NULL) {
                if (ns->prefix != NULL) {
                    if (style->nsHash == NULL) {
                        style->nsHash = xmlHashCreate(10);
                        if (style->nsHash == NULL) {
                            xsltTransformError(NULL, style, cur,
                 "xsltGatherNamespaces: failed to create hash table\n");
                            style->errors++;
                            return;
                        }
                    }
                    URI = xmlHashLookup(style->nsHash, ns->prefix);
                    if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
                        xsltTransformError(NULL, style, cur,
             "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
                        style->warnings++;
                    } else if (URI == NULL) {
                        xmlHashUpdateEntry(style->nsHash, ns->prefix,
                            (void *) ns->href, (xmlHashDeallocator)xmlFree);

#ifdef WITH_XSLT_DEBUG_PARSING
                        xsltGenericDebug(xsltGenericDebugContext,
                 "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
#endif
                    }
                }
                ns = ns->next;
            }
        }

        /*
         * Skip to next node
         */
        if (cur->children != NULL) {
            if (cur->children->type != XML_ENTITY_DECL) {
                cur = cur->children;
                continue;
            }
        }
        if (cur->next != NULL) {
            cur = cur->next;
            continue;
        }
        
        do {
            cur = cur->parent;
            if (cur == NULL)
                break;
            if (cur == (xmlNodePtr) style->doc) {
                cur = NULL;
                break;
            }
            if (cur->next != NULL) {
                cur = cur->next;
                break;
            }
        } while (cur != NULL);
    }
}

#ifdef XSLT_REFACTORED

static xsltStyleType
xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
                             xmlNodePtr node)
{
    if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
        (node->name == NULL))
        return(0);

    if (node->name[0] == 'a') {
        if (IS_XSLT_NAME(node, "apply-templates"))
            return(XSLT_FUNC_APPLYTEMPLATES);
        else if (IS_XSLT_NAME(node, "attribute"))
            return(XSLT_FUNC_ATTRIBUTE);
        else if (IS_XSLT_NAME(node, "apply-imports"))
            return(XSLT_FUNC_APPLYIMPORTS);
        else if (IS_XSLT_NAME(node, "attribute-set"))
            return(0);

    } else if (node->name[0] == 'c') {
        if (IS_XSLT_NAME(node, "choose"))
            return(XSLT_FUNC_CHOOSE);
        else if (IS_XSLT_NAME(node, "copy"))
            return(XSLT_FUNC_COPY);
        else if (IS_XSLT_NAME(node, "copy-of"))
            return(XSLT_FUNC_COPYOF);
        else if (IS_XSLT_NAME(node, "call-template"))
            return(XSLT_FUNC_CALLTEMPLATE);
        else if (IS_XSLT_NAME(node, "comment"))
            return(XSLT_FUNC_COMMENT);

    } else if (node->name[0] == 'd') {
        if (IS_XSLT_NAME(node, "document"))
            return(XSLT_FUNC_DOCUMENT);
        else if (IS_XSLT_NAME(node, "decimal-format"))
            return(0);

    } else if (node->name[0] == 'e') {
        if (IS_XSLT_NAME(node, "element"))
            return(XSLT_FUNC_ELEMENT);

    } else if (node->name[0] == 'f') {
        if (IS_XSLT_NAME(node, "for-each"))
            return(XSLT_FUNC_FOREACH);
        else if (IS_XSLT_NAME(node, "fallback"))
            return(XSLT_FUNC_FALLBACK);

    } else if (*(node->name) == 'i') {
        if (IS_XSLT_NAME(node, "if"))
            return(XSLT_FUNC_IF);
        else if (IS_XSLT_NAME(node, "include"))
            return(0);
        else if (IS_XSLT_NAME(node, "import"))
            return(0);

    } else if (*(node->name) == 'k') {
        if (IS_XSLT_NAME(node, "key"))
            return(0);

    } else if (*(node->name) == 'm') {
        if (IS_XSLT_NAME(node, "message"))
            return(XSLT_FUNC_MESSAGE);

    } else if (*(node->name) == 'n') {
        if (IS_XSLT_NAME(node, "number"))
            return(XSLT_FUNC_NUMBER);
        else if (IS_XSLT_NAME(node, "namespace-alias"))
            return(0);

    } else if (*(node->name) == 'o') {
        if (IS_XSLT_NAME(node, "otherwise"))
            return(XSLT_FUNC_OTHERWISE);
        else if (IS_XSLT_NAME(node, "output"))
            return(0);

    } else if (*(node->name) == 'p') {
        if (IS_XSLT_NAME(node, "param"))
            return(XSLT_FUNC_PARAM);
        else if (IS_XSLT_NAME(node, "processing-instruction"))
            return(XSLT_FUNC_PI);
        else if (IS_XSLT_NAME(node, "preserve-space"))
            return(0);

    } else if (*(node->name) == 's') {
        if (IS_XSLT_NAME(node, "sort"))
            return(XSLT_FUNC_SORT);
        else if (IS_XSLT_NAME(node, "strip-space"))
            return(0);
        else if (IS_XSLT_NAME(node, "stylesheet"))
            return(0);

    } else if (node->name[0] == 't') {
        if (IS_XSLT_NAME(node, "text"))
            return(XSLT_FUNC_TEXT);
        else if (IS_XSLT_NAME(node, "template"))
            return(0);
        else if (IS_XSLT_NAME(node, "transform"))
            return(0);

    } else if (*(node->name) == 'v') {
        if (IS_XSLT_NAME(node, "value-of"))
            return(XSLT_FUNC_VALUEOF);
        else if (IS_XSLT_NAME(node, "variable"))
            return(XSLT_FUNC_VARIABLE);

    } else if (*(node->name) == 'w') {
        if (IS_XSLT_NAME(node, "when"))
            return(XSLT_FUNC_WHEN);
        if (IS_XSLT_NAME(node, "with-param"))
            return(XSLT_FUNC_WITHPARAM);
    }
    return(0);
}

/**
 * xsltParseAnyXSLTElem:
 *
 * @cctxt: the compilation context
 * @elem: the element node of the XSLT instruction
 *
 * Parses, validates the content models and compiles XSLT instructions.
 *
 * Returns 0 if everything's fine;
 *         -1 on API or internal errors.
 */ 
int
xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
{
    if ((cctxt == NULL) || (elem == NULL) ||
        (elem->type != XML_ELEMENT_NODE))
        return(-1);

    elem->psvi = NULL;

    if (! (IS_XSLT_ELEM_FAST(elem)))
        return(-1);
    /*
    * Detection of handled content of extension instructions.
    */
    if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
        cctxt->inode->extContentHandled = 1;
    }
    
    xsltCompilerNodePush(cctxt, elem);
    /*
    * URGENT TODO: Find a way to speed up this annoying redundant
    *  textual node-name and namespace comparison.
    */
    if (cctxt->inode->prev->curChildType != 0)
        cctxt->inode->type = cctxt->inode->prev->curChildType;
    else
        cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem);    
    /*
    * Update the in-scope namespaces if needed.
    */
    if (elem->nsDef != NULL)
        cctxt->inode->inScopeNs =
            xsltCompilerBuildInScopeNsList(cctxt, elem);
    /*
    * xsltStylePreCompute():
    *  This will compile the information found on the current
    *  element's attributes. NOTE that this won't process the
    *  children of the instruction.
    */
    xsltStylePreCompute(cctxt->style, elem);
    /*
    * TODO: How to react on errors in xsltStylePreCompute() ?
    */

    /*
    * Validate the content model of the XSLT-element.
    */
    switch (cctxt->inode->type) {       
        case XSLT_FUNC_APPLYIMPORTS:
            /* EMPTY */
            goto empty_content;
        case XSLT_FUNC_APPLYTEMPLATES:
            /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
            goto apply_templates;           
        case XSLT_FUNC_ATTRIBUTE:           
            /* <!-- Content: template --> */
            goto sequence_constructor;
        case XSLT_FUNC_CALLTEMPLATE:
            /* <!-- Content: xsl:with-param* --> */
            goto call_template;
        case XSLT_FUNC_CHOOSE:      
            /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
            goto choose;
        case XSLT_FUNC_COMMENT:
            /* <!-- Content: template --> */
            goto sequence_constructor;      
        case XSLT_FUNC_COPY:
            /* <!-- Content: template --> */
            goto sequence_constructor;      
        case XSLT_FUNC_COPYOF:
            /* EMPTY */
            goto empty_content;    
        case XSLT_FUNC_DOCUMENT: /* Extra one */
            /* ?? template ?? */
            goto sequence_constructor;
        case XSLT_FUNC_ELEMENT:
            /* <!-- Content: template --> */
            goto sequence_constructor;
        case XSLT_FUNC_FALLBACK:
            /* <!-- Content: template --> */
            goto sequence_constructor;
        case XSLT_FUNC_FOREACH:
            /* <!-- Content: (xsl:sort*, template) --> */
            goto for_each;
        case XSLT_FUNC_IF:
            /* <!-- Content: template --> */
            goto sequence_constructor;
        case XSLT_FUNC_OTHERWISE:
            /* <!-- Content: template --> */
            goto sequence_constructor;
        case XSLT_FUNC_MESSAGE:
            /* <!-- Content: template --> */
            goto sequence_constructor;
        case XSLT_FUNC_NUMBER:
            /* EMPTY */
            goto empty_content;
        case XSLT_FUNC_PARAM:
            /*
            * Check for redefinition.
            */
            if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
                xsltVarInfoPtr ivar = cctxt->ivar;

                do {
                    if ((ivar->name ==
                         ((xsltStyleItemParamPtr) elem->psvi)->name) &&
                        (ivar->nsName ==
                         ((xsltStyleItemParamPtr) elem->psvi)->ns))
                    {
                        elem->psvi = NULL;
                        xsltTransformError(NULL, cctxt->style, elem,
                            "Redefinition of variable or parameter '%s'.\n",
                            ivar->name);
                        cctxt->style->errors++;
                        goto error;
                    }
                    ivar = ivar->prev;
                } while (ivar != NULL);
            }
            /*  <!-- Content: template --> */
            goto sequence_constructor;
        case XSLT_FUNC_PI:
            /*  <!-- Content: template --> */
            goto sequence_constructor;
        case XSLT_FUNC_SORT:
            /* EMPTY */
            goto empty_content;
        case XSLT_FUNC_TEXT:
            /* <!-- Content: #PCDATA --> */
            goto text;
        case XSLT_FUNC_VALUEOF:
            /* EMPTY */
            goto empty_content;
        case XSLT_FUNC_VARIABLE:
            /*
            * Check for redefinition.
            */
            if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
                xsltVarInfoPtr ivar = cctxt->ivar;              

                do {
                    if ((ivar->name ==
                         ((xsltStyleItemVariablePtr) elem->psvi)->name) &&
                        (ivar->nsName ==
                         ((xsltStyleItemVariablePtr) elem->psvi)->ns))
                    {
                        elem->psvi = NULL;
                        xsltTransformError(NULL, cctxt->style, elem,
                            "Redefinition of variable or parameter '%s'.\n",
                            ivar->name);
                        cctxt->style->errors++;
                        goto error;
                    }
                    ivar = ivar->prev;
                } while (ivar != NULL);
            }
            /* <!-- Content: template --> */
            goto sequence_constructor;
        case XSLT_FUNC_WHEN:
            /* <!-- Content: template --> */
            goto sequence_constructor;
        case XSLT_FUNC_WITHPARAM:
            /* <!-- Content: template --> */
            goto sequence_constructor;
        default:
#ifdef WITH_XSLT_DEBUG_PARSING
            xsltGenericDebug(xsltGenericDebugContext,
                "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
                elem->name);        
#endif
            xsltTransformError(NULL, cctxt->style, elem,
                "xsltParseXSLTNode: Internal error; "
                "unhandled XSLT element '%s'.\n", elem->name);
            cctxt->style->errors++;
            goto internal_err;
    }

apply_templates:
    /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
    if (elem->children != NULL) {
        xmlNodePtr child = elem->children;
        do {
            if (child->type == XML_ELEMENT_NODE) {
                if (IS_XSLT_ELEM_FAST(child)) {
                    if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
                        cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
                        xsltParseAnyXSLTElem(cctxt, child);
                    } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
                        cctxt->inode->curChildType = XSLT_FUNC_SORT;
                        xsltParseAnyXSLTElem(cctxt, child);
                    } else
                        xsltParseContentError(cctxt->style, child);
                } else
                    xsltParseContentError(cctxt->style, child);
            }
            child = child->next;
        } while (child != NULL);
    }    
    goto exit;

call_template:
    /* <!-- Content: xsl:with-param* --> */
    if (elem->children != NULL) {
        xmlNodePtr child = elem->children;
        do {
            if (child->type == XML_ELEMENT_NODE) {
                if (IS_XSLT_ELEM_FAST(child)) {
                    xsltStyleType type;

                    type = xsltGetXSLTElementTypeByNode(cctxt, child);
                    if (type == XSLT_FUNC_WITHPARAM) {
                        cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
                        xsltParseAnyXSLTElem(cctxt, child);
                    } else {
                        xsltParseContentError(cctxt->style, child);
                    }
                } else
                    xsltParseContentError(cctxt->style, child);
            }
            child = child->next;
        } while (child != NULL);
    }    
    goto exit;

text:
    if (elem->children != NULL) {
        xmlNodePtr child = elem->children;
        do {
            if ((child->type != XML_TEXT_NODE) &&
                (child->type != XML_CDATA_SECTION_NODE))
            {
                xsltTransformError(NULL, cctxt->style, elem,
                    "The XSLT 'text' element must have only character "
                    "data as content.\n");
            }
            child = child->next;
        } while (child != NULL);
    }
    goto exit;

empty_content:
    if (elem->children != NULL) {
        xmlNodePtr child = elem->children;
        /*
        * Relaxed behaviour: we will allow whitespace-only text-nodes.
        */
        do {
            if (((child->type != XML_TEXT_NODE) &&
                 (child->type != XML_CDATA_SECTION_NODE)) ||
                (! IS_BLANK_NODE(child)))
            {
                xsltTransformError(NULL, cctxt->style, elem,
                    "This XSLT element must have no content.\n");
                cctxt->style->errors++;
                break;
            }
            child = child->next;
        } while (child != NULL);                
    }
    goto exit;

choose:
    /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
    /*
    * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
    *   The old behaviour did not check this.
    * NOTE: In XSLT 2.0 they are stripped beforehand
    *  if whitespace-only (regardless of xml:space).
    */
    if (elem->children != NULL) {
        xmlNodePtr child = elem->children;
        int nbWhen = 0, nbOtherwise = 0, err = 0;
        do {
            if (child->type == XML_ELEMENT_NODE) {
                if (IS_XSLT_ELEM_FAST(child)) {
                    xsltStyleType type;
                
                    type = xsltGetXSLTElementTypeByNode(cctxt, child);
                    if (type == XSLT_FUNC_WHEN) {
                        nbWhen++;
                        if (nbOtherwise) {
                            xsltParseContentError(cctxt->style, child);
                            err = 1;
                            break;
                        }
                        cctxt->inode->curChildType = XSLT_FUNC_WHEN;
                        xsltParseAnyXSLTElem(cctxt, child);
                    } else if (type == XSLT_FUNC_OTHERWISE) {
                        if (! nbWhen) {
                            xsltParseContentError(cctxt->style, child);
                            err = 1;
                            break;
                        }                       
                        if (nbOtherwise) {
                            xsltTransformError(NULL, cctxt->style, elem,
                                "The XSLT 'choose' element must not contain "
                                "more than one XSLT 'otherwise' element.\n");
                            cctxt->style->errors++;
                            err = 1;
                            break;
                        }
                        nbOtherwise++;
                        cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;
                        xsltParseAnyXSLTElem(cctxt, child);
                    } else
                        xsltParseContentError(cctxt->style, child);
                } else
                    xsltParseContentError(cctxt->style, child);
            } 
            /*
                else
                    xsltParseContentError(cctxt, child);
            */
            child = child->next;
        } while (child != NULL);
        if ((! err) && (! nbWhen)) {
            xsltTransformError(NULL, cctxt->style, elem,
                "The XSLT element 'choose' must contain at least one "
                "XSLT element 'when'.\n");
                cctxt->style->errors++;
        }       
    }    
    goto exit;

for_each:
    /* <!-- Content: (xsl:sort*, template) --> */
    /*
    * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
    *   The old behaviour did not allow this, but it catched this
    *   only at transformation-time.
    *   In XSLT 2.0 they are stripped beforehand if whitespace-only
    *   (regardless of xml:space).
    */
    if (elem->children != NULL) {
        xmlNodePtr child = elem->children;
        /*
        * Parse xsl:sort first.
        */
        do {        
            if ((child->type == XML_ELEMENT_NODE) &&
                IS_XSLT_ELEM_FAST(child))
            {           
                if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
                    XSLT_FUNC_SORT)
                {               
                    cctxt->inode->curChildType = XSLT_FUNC_SORT;
                    xsltParseAnyXSLTElem(cctxt, child);
                } else
                    break;
            } else
                break;
            child = child->next;
        } while (child != NULL);
        /*
        * Parse the sequece constructor.
        */
        if (child != NULL)
            xsltParseSequenceConstructor(cctxt, child);
    }    
    goto exit;

sequence_constructor:
    /*
    * Parse the sequence constructor.
    */
    if (elem->children != NULL)
        xsltParseSequenceConstructor(cctxt, elem->children);

    /*
    * Register information for vars/params. Only needed if there
    * are any following siblings.
    */
    if ((elem->next != NULL) &&
        ((cctxt->inode->type == XSLT_FUNC_VARIABLE) ||
         (cctxt->inode->type == XSLT_FUNC_PARAM)))
    {   
        if ((elem->psvi != NULL) &&
            (((xsltStyleBasicItemVariablePtr) elem->psvi)->name))
        {       
            xsltCompilerVarInfoPush(cctxt, elem,
                ((xsltStyleBasicItemVariablePtr) elem->psvi)->name,
                ((xsltStyleBasicItemVariablePtr) elem->psvi)->ns);
        }
    }

error:
exit:
    xsltCompilerNodePop(cctxt, elem);
    return(0);

internal_err:
    xsltCompilerNodePop(cctxt, elem);
    return(-1);
}

/**
 * xsltForwardsCompatUnkownItemCreate:
 *
 * @cctxt: the compilation context 
 *
 * Creates a compiled representation of the unknown
 * XSLT instruction.
 *
 * Returns the compiled representation.
 */ 
static xsltStyleItemUknownPtr
xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
{
    xsltStyleItemUknownPtr item;

    item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
    if (item == NULL) {
        xsltTransformError(NULL, cctxt->style, NULL,
            "Internal error in xsltForwardsCompatUnkownItemCreate(): "
            "Failed to allocate memory.\n");
        cctxt->style->errors++;
        return(NULL);
    }
    memset(item, 0, sizeof(xsltStyleItemUknown));
    item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
    /*
    * Store it in the stylesheet.
    */
    item->next = cctxt->style->preComps;
    cctxt->style->preComps = (xsltElemPreCompPtr) item;
    return(item);
}

/**
 * xsltParseUnknownXSLTElem:
 *
 * @cctxt: the compilation context
 * @node: the element of the unknown XSLT instruction
 *
 * Parses an unknown XSLT element.
 * If forwards compatible mode is enabled this will allow
 * such an unknown XSLT and; otherwise it is rejected.
 *
 * Returns 1 in the unknown XSLT instruction is rejected,
 *         0 if everything's fine and
 *         -1 on API or internal errors.
 */ 
static int
xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
                            xmlNodePtr node)
{
    if ((cctxt == NULL) || (node == NULL))
        return(-1);

    /*
    * Detection of handled content of extension instructions.
    */
    if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
        cctxt->inode->extContentHandled = 1;
    }    
    if (cctxt->inode->forwardsCompat == 0) {    
        /*
        * We are not in forwards-compatible mode, so raise an error.
        */
        xsltTransformError(NULL, cctxt->style, node,
            "Unknown XSLT element '%s'.\n", node->name);
        cctxt->style->errors++;
        return(1);
    }
    /*
    * Forwards-compatible mode.
    * ------------------------
    *    
    * Parse/compile xsl:fallback elements.
    *
    * QUESTION: Do we have to raise an error if there's no xsl:fallback?
    * ANSWER: No, since in the stylesheet the fallback behaviour might
    *  also be provided by using the XSLT function "element-available".
    */
    if (cctxt->unknownItem == NULL) {
        /*
        * Create a singleton for all unknown XSLT instructions.
        */
        cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
        if (cctxt->unknownItem == NULL) {
            node->psvi = NULL;
            return(-1);
        }
    }
    node->psvi = cctxt->unknownItem;
    if (node->children == NULL)
        return(0);
    else {
        xmlNodePtr child = node->children;

        xsltCompilerNodePush(cctxt, node);
        /*
        * Update the in-scope namespaces if needed.
        */
        if (node->nsDef != NULL)
            cctxt->inode->inScopeNs =
                xsltCompilerBuildInScopeNsList(cctxt, node);
        /*
        * Parse all xsl:fallback children.
        */
        do {
            if ((child->type == XML_ELEMENT_NODE) &&
                IS_XSLT_ELEM_FAST(child) &&
                IS_XSLT_NAME(child, "fallback"))
            {
                cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
                xsltParseAnyXSLTElem(cctxt, child);
            }
            child = child->next;
        } while (child != NULL);
        
        xsltCompilerNodePop(cctxt, node);
    }
    return(0);
}

/**
 * xsltParseSequenceConstructor:
 *
 * @cctxt: the compilation context
 * @cur: the start-node of the content to be parsed
 *
 * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
 * This will additionally remove xsl:text elements from the tree.
 */ 
void
xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
{
    xsltStyleType type;
    xmlNodePtr deleteNode = NULL;

    if (cctxt == NULL) {
        xmlGenericError(xmlGenericErrorContext,
            "xsltParseSequenceConstructor: Bad arguments\n");
        cctxt->style->errors++;
        return;
    }
    /*
    * Detection of handled content of extension instructions.
    */
    if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
        cctxt->inode->extContentHandled = 1;
    }
    if (cur == NULL)
        return;
    /*
    * This is the content reffered to as a "template".
    * E.g. an xsl:element has such content model:
    * <xsl:element
    *   name = { qname }
    *   namespace = { uri-reference }
    *   use-attribute-sets = qnames>
    * <!-- Content: template -->
    *
    * NOTE that in XSLT-2 the term "template" was abandoned due to
    *  confusion with xsl:template and the term "sequence constructor"
    *  was introduced instead.
    *
    * The following XSLT-instructions are allowed to appear:
    *  xsl:apply-templates, xsl:call-template, xsl:apply-imports,
    *  xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
    *  xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
    *  xsl:message, xsl:fallback,
    *  xsl:processing-instruction, xsl:comment, xsl:element
    *  xsl:attribute. 
    * Additional allowed content:
    * 1) extension instructions
    * 2) literal result elements
    * 3) PCDATA
    *
    * NOTE that this content model does *not* allow xsl:param.
    */    
    while (cur != NULL) {
        if (deleteNode != NULL) {
#ifdef WITH_XSLT_DEBUG_BLANKS
            xsltGenericDebug(xsltGenericDebugContext,
             "xsltParseSequenceConstructor: removing xsl:text element\n");
#endif
            xmlUnlinkNode(deleteNode);
            xmlFreeNode(deleteNode);
            deleteNode = NULL;
        }
        if (cur->type == XML_ELEMENT_NODE) {        
            
            if (cur->psvi == xsltXSLTTextMarker) {
                /*
                * xsl:text elements
                * --------------------------------------------------------
                */
                xmlNodePtr tmp;

                cur->psvi = NULL;
                /*
                * Mark the xsl:text element for later deletion.
                */
                deleteNode = cur;
                /*
                * Validate content.
                */
                tmp = cur->children;
                if (tmp) {
                    /*
                    * We don't expect more than one text-node in the
                    * content, since we already merged adjacent
                    * text/CDATA-nodes and eliminated PI/comment-nodes.
                    */
                    if ((tmp->type == XML_TEXT_NODE) ||
                        (tmp->next == NULL))
                    {
                        /*
                        * Leave the contained text-node in the tree.
                        */
                        xmlUnlinkNode(tmp);
                        xmlAddPrevSibling(cur, tmp);
                    } else {
                        tmp = NULL;
                        xsltTransformError(NULL, cctxt->style, cur,
                            "Element 'xsl:text': Invalid type "
                            "of node found in content.\n");
                        cctxt->style->errors++;
                    } 
                }
                if (cur->properties) {
                    xmlAttrPtr attr;
                    /*
                    * TODO: We need to report errors for
                    *  invalid attrs.
                    */
                    attr = cur->properties;
                    do {
                        if ((attr->ns == NULL) &&
                            (attr->name != NULL) &&
                            (attr->name[0] == 'd') &&
                            xmlStrEqual(attr->name,
                            BAD_CAST "disable-output-escaping"))
                        {
                            /*
                            * Attr "disable-output-escaping".
                            * XSLT-2: This attribute is deprecated.
                            */
                            if ((attr->children != NULL) &&
                                xmlStrEqual(attr->children->content,
                                BAD_CAST "yes"))
                            {
                                /*
                                * Disable output escaping for this
                                * text node.
                                */
                                if (tmp)
                                    tmp->name = xmlStringTextNoenc;
                            } else if ((attr->children == NULL) ||
                                (attr->children->content == NULL) ||
                                (!xmlStrEqual(attr->children->content,
                                BAD_CAST "no")))
                            {
                                xsltTransformError(NULL, cctxt->style,
                                    cur,
                                    "Attribute 'disable-output-escaping': "
                                    "Invalid value. Expected is "
                                    "'yes' or 'no'.\n");
                                cctxt->style->errors++;
                            }
                            break;
                        }
                        attr = attr->next;
                    } while (attr != NULL);
                }
            } else if (IS_XSLT_ELEM_FAST(cur)) {
                /*
                * TODO: Using the XSLT-marker is still not stable yet.
                */
                /* if (cur->psvi == xsltXSLTElemMarker) { */        
                /*
                * XSLT instructions
                * --------------------------------------------------------
                */
                cur->psvi = NULL;
                type = xsltGetXSLTElementTypeByNode(cctxt, cur);
                switch (type) {
                    case XSLT_FUNC_APPLYIMPORTS:
                    case XSLT_FUNC_APPLYTEMPLATES:
                    case XSLT_FUNC_ATTRIBUTE:
                    case XSLT_FUNC_CALLTEMPLATE:
                    case XSLT_FUNC_CHOOSE:
                    case XSLT_FUNC_COMMENT:
                    case XSLT_FUNC_COPY:
                    case XSLT_FUNC_COPYOF:
                    case XSLT_FUNC_DOCUMENT: /* Extra one */
                    case XSLT_FUNC_ELEMENT:
                    case XSLT_FUNC_FALLBACK:
                    case XSLT_FUNC_FOREACH:
                    case XSLT_FUNC_IF:
                    case XSLT_FUNC_MESSAGE:
                    case XSLT_FUNC_NUMBER:
                    case XSLT_FUNC_PI:
                    case XSLT_FUNC_TEXT:
                    case XSLT_FUNC_VALUEOF:
                    case XSLT_FUNC_VARIABLE:
                        /*
                        * Parse the XSLT element.
                        */
                        cctxt->inode->curChildType = type;
                        xsltParseAnyXSLTElem(cctxt, cur);
                        break;
                    default:
                        xsltParseUnknownXSLTElem(cctxt, cur);                   
                        cur = cur->next;
                        continue;
                }
            } else {
                /*
                * Non-XSLT elements
                * -----------------
                */
                xsltCompilerNodePush(cctxt, cur);
                /*
                * Update the in-scope namespaces if needed.
                */
                if (cur->nsDef != NULL)
                    cctxt->inode->inScopeNs =
                        xsltCompilerBuildInScopeNsList(cctxt, cur);
                /*
                * The current element is either a literal result element
                * or an extension instruction.
                *
                * Process attr "xsl:extension-element-prefixes".
                * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
                * processed by the implementor of the extension function;
                * i.e., it won't be handled by the XSLT processor.
                */
                /* SPEC 1.0:
                *   "exclude-result-prefixes" is only allowed on literal
                *   result elements and "xsl:exclude-result-prefixes"
                *   on xsl:stylesheet/xsl:transform.
                * SPEC 2.0:
                *   "There are a number of standard attributes
                *   that may appear on any XSLT element: specifically
                *   version, exclude-result-prefixes,
                *   extension-element-prefixes, xpath-default-namespace,
                *   default-collation, and use-when."
                *
                * SPEC 2.0:
                *   For literal result elements:
                *   "xsl:version, xsl:exclude-result-prefixes,
                *    xsl:extension-element-prefixes,
                *    xsl:xpath-default-namespace,
                *    xsl:default-collation, or xsl:use-when."
                */
                if (cur->properties)
                    cctxt->inode->extElemNs =
                        xsltParseExtElemPrefixes(cctxt,
                            cur, cctxt->inode->extElemNs,
                            XSLT_ELEMENT_CATEGORY_LRE);
                /*
                * Eval if we have an extension instruction here.
                */
                if ((cur->ns != NULL) &&
                    (cctxt->inode->extElemNs != NULL) &&
                    (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
                {
                    /*
                    * Extension instructions
                    * ----------------------------------------------------
                    * Mark the node information.
                    */
                    cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
                    cctxt->inode->extContentHandled = 0;
                    if (cur->psvi != NULL) {
                        cur->psvi = NULL;
                        /*
                        * TODO: Temporary sanity check.
                        */
                        xsltTransformError(NULL, cctxt->style, cur,
                            "Internal error in xsltParseSequenceConstructor(): "
                            "Occupied PSVI field.\n");
                        cctxt->style->errors++;
                        cur = cur->next;
                        continue;
                    }
                    cur->psvi = (void *)
                        xsltPreComputeExtModuleElement(cctxt->style, cur);
                    
                    if (cur->psvi == NULL) {
                        /*
                        * OLD COMMENT: "Unknown element, maybe registered
                        *  at the context level. Mark it for later
                        *  recognition."
                        * QUESTION: What does the xsltExtMarker mean?
                        *  ANSWER: It is used in
                        *   xsltApplySequenceConstructor() at
                        *   transformation-time to look out for extension
                        *   registered in the transformation context.
                        */
                        cur->psvi = (void *) xsltExtMarker;
                    }
                    /*
                    * BIG NOTE: Now the ugly part. In previous versions
                    *  of Libxslt (until 1.1.16), all the content of an
                    *  extension instruction was processed and compiled without
                    *  the need of the extension-author to explicitely call
                    *  such a processing;.We now need to mimic this old
                    *  behaviour in order to avoid breaking old code
                    *  on the extension-author's side.
                    * The mechanism:
                    *  1) If the author does *not* set the
                    *    compile-time-flag @extContentHandled, then we'll
                    *    parse the content assuming that it's a "template"
                    *    (or "sequence constructor in XSLT 2.0 terms).
                    *    NOTE: If the extension is registered at
                    *    transformation-time only, then there's no way of
                    *    knowing that content shall be valid, and we'll
                    *    process the content the same way.
                    *  2) If the author *does* set the flag, then we'll assume
                    *   that the author has handled the parsing him/herself
                    *   (e.g. called xsltParseSequenceConstructor(), etc.
                    *   explicitely in his/her code).
                    */
                    if ((cur->children != NULL) &&
                        (cctxt->inode->extContentHandled == 0))
                    {
                        /*
                        * Default parsing of the content using the
                        * sequence-constructor model.
                        */
                        xsltParseSequenceConstructor(cctxt, cur->children);
                    }
                } else {
                    /*
                    * Literal result element
                    * ----------------------------------------------------
                    * Allowed XSLT attributes:
                    *  xsl:extension-element-prefixes CDATA #IMPLIED
                    *  xsl:exclude-result-prefixes CDATA #IMPLIED
                    *  TODO: xsl:use-attribute-sets %qnames; #IMPLIED
                    *  xsl:version NMTOKEN #IMPLIED
                    */
                    cur->psvi = NULL;
                    cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
                    if (cur->properties != NULL) {
                        xmlAttrPtr attr = cur->properties;
                        /*
                        * Attribute "xsl:exclude-result-prefixes".
                        */
                        cctxt->inode->exclResultNs =
                            xsltParseExclResultPrefixes(cctxt, cur,
                                cctxt->inode->exclResultNs,
                                XSLT_ELEMENT_CATEGORY_LRE);
                        /*
                        * Attribute "xsl:version".
                        */
                        xsltParseAttrXSLTVersion(cctxt, cur,
                            XSLT_ELEMENT_CATEGORY_LRE);
                        /*
                        * Report invalid XSLT attributes.                       
                        * For XSLT 1.0 only xsl:use-attribute-sets is allowed
                        * next to xsl:version, xsl:exclude-result-prefixes and
                        * xsl:extension-element-prefixes.
                        *
                        * Mark all XSLT attributes, in order to skip such
                        * attributes when instantiating the LRE.
                        */
                        do {
                            if ((attr->psvi != xsltXSLTAttrMarker) &&
                                IS_XSLT_ATTR_FAST(attr))
                            {                               
                                if (! xmlStrEqual(attr->name,
                                    BAD_CAST "use-attribute-sets"))
                                {                               
                                    xsltTransformError(NULL, cctxt->style,
                                        cur,
                                        "Unknown XSLT attribute '%s'.\n",
                                        attr->name);
                                    cctxt->style->errors++;
                                } else {
                                    /*
                                    * XSLT attr marker.
                                    */
                                    attr->psvi = (void *) xsltXSLTAttrMarker;
                                }
                            }
                            attr = attr->next;
                        } while (attr != NULL);
                    }
                    /*
                    * Create/reuse info for the literal result element.
                    */
                    if (cctxt->inode->nsChanged)
                        xsltLREInfoCreate(cctxt, cur, 1);
                    cur->psvi = cctxt->inode->litResElemInfo;
                    /*
                    * Apply ns-aliasing on the element and on its attributes.
                    */
                    if (cctxt->hasNsAliases)
                        xsltLREBuildEffectiveNs(cctxt, cur);
                    /*
                    * Compile attribute value templates (AVT).
                    */
                    if (cur->properties) {
                        xmlAttrPtr attr = cur->properties;
                        
                        while (attr != NULL) {
                            xsltCompileAttr(cctxt->style, attr);
                            attr = attr->next;
                        }
                    }
                    /*
                    * Parse the content, which is defined to be a "template"
                    * (or "sequence constructor" in XSLT 2.0 terms).
                    */
                    if (cur->children != NULL) {
                        xsltParseSequenceConstructor(cctxt, cur->children);
                    }
                }
                /*
                * Leave the non-XSLT element.
                */
                xsltCompilerNodePop(cctxt, cur);
            }
        }
        cur = cur->next;
    }
    if (deleteNode != NULL) {
#ifdef WITH_XSLT_DEBUG_BLANKS
        xsltGenericDebug(xsltGenericDebugContext,
            "xsltParseSequenceConstructor: removing xsl:text element\n");
#endif
        xmlUnlinkNode(deleteNode);
        xmlFreeNode(deleteNode);
        deleteNode = NULL;
    }
}

/**
 * xsltParseTemplateContent:
 * @style:  the XSLT stylesheet
 * @templ:  the node containing the content to be parsed
 *
 * Parses and compiles the content-model of an xsl:template element.
 * Note that this is *not* the "template" content model (or "sequence
 *  constructor" in XSLT 2.0); it it allows addional xsl:param
 *  elements as immediate children of @templ.
 *
 * Called by: 
 *   exsltFuncFunctionComp() (EXSLT, functions.c)
 *   So this is intended to be called from extension functions.
 */
void
xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
    if ((style == NULL) || (templ == NULL))
        return;

    /*
    * Detection of handled content of extension instructions.
    */
    if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
        XSLT_CCTXT(style)->inode->extContentHandled = 1;
    }

    if (templ->children != NULL) {      
        xmlNodePtr child = templ->children;
        /*
        * Process xsl:param elements, which can only occur as the
        * immediate children of xsl:template (well, and of any
        * user-defined extension instruction if needed).
        */      
        do {
            if ((child->type == XML_ELEMENT_NODE) &&
                IS_XSLT_ELEM_FAST(child) &&
                IS_XSLT_NAME(child, "param"))
            {
                XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
                xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
            } else
                break;
            child = child->next;
        } while (child != NULL);
        /*
        * Parse the content and register the pattern.
        */
        xsltParseSequenceConstructor(XSLT_CCTXT(style), child);
    }
}

#else /* XSLT_REFACTORED */

/**
 * xsltParseTemplateContent:
 * @style:  the XSLT stylesheet
 * @templ:  the container node (can be a document for literal results)
 *
 * parse a template content-model
 * Clean-up the template content from unwanted ignorable blank nodes
 * and process xslt:text
 */
void
xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
    xmlNodePtr cur, delete;
    /*
     * This content comes from the stylesheet
     * For stylesheets, the set of whitespace-preserving
     * element names consists of just xsl:text.
     */
    cur = templ->children;
    delete = NULL;
    while (cur != NULL) {
        if (delete != NULL) {
#ifdef WITH_XSLT_DEBUG_BLANKS
            xsltGenericDebug(xsltGenericDebugContext,
             "xsltParseTemplateContent: removing text\n");
#endif
            xmlUnlinkNode(delete);
            xmlFreeNode(delete);
            delete = NULL;
        }
        if (IS_XSLT_ELEM(cur)) {
            if (IS_XSLT_NAME(cur, "text")) {
                /*
                * TODO: Processing of xsl:text should be moved to
                *   xsltPrecomputeStylesheet(), since otherwise this
                *   will be performed for every multiply included
                *   stylesheet; i.e. this here is not skipped with
                *   the use of the style->nopreproc flag.
                */
                if (cur->children != NULL) {
                    xmlChar *prop;
                    xmlNodePtr text = cur->children, next;
                    int noesc = 0;
                        
                    prop = xmlGetNsProp(cur,
                        (const xmlChar *)"disable-output-escaping",
                        NULL);
                    if (prop != NULL) {
#ifdef WITH_XSLT_DEBUG_PARSING
                        xsltGenericDebug(xsltGenericDebugContext,
                             "Disable escaping: %s\n", text->content);
#endif
                        if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
                            noesc = 1;
                        } else if (!xmlStrEqual(prop,
                                                (const xmlChar *)"no")){
                            xsltTransformError(NULL, style, cur,
             "xsl:text: disable-output-escaping allows only yes or no\n");
                            style->warnings++;

                        }
                        xmlFree(prop);
                    }

                    while (text != NULL) {
                        if (text->type == XML_COMMENT_NODE) {
                            text = text->next;
                            continue;
                        }
                        if ((text->type != XML_TEXT_NODE) &&
                             (text->type != XML_CDATA_SECTION_NODE)) {
                            xsltTransformError(NULL, style, cur,
                 "xsltParseTemplateContent: xslt:text content problem\n");
                            style->errors++;
                            break;
                        }
                        if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
                            text->name = xmlStringTextNoenc;
                        text = text->next;
                    }

                    /*
                     * replace xsl:text by the list of childs
                     */
                    if (text == NULL) {
                        text = cur->children;
                        while (text != NULL) {
                            if ((style->internalized) &&
                                (text->content != NULL) &&
                                (!xmlDictOwns(style->dict, text->content))) {

                                /*
                                 * internalize the text string
                                 */
                                if (text->doc->dict != NULL) {
                                    const xmlChar *tmp;
                                    
                                    tmp = xmlDictLookup(text->doc->dict,
                                                        text->content, -1);
                                    if (tmp != text->content) {
                                        xmlNodeSetContent(text, NULL);
                                        text->content = (xmlChar *) tmp;
                                    }
                                }
                            }

                            next = text->next;
                            xmlUnlinkNode(text);
                            xmlAddPrevSibling(cur, text);
                            text = next;
                        }
                    }
                }
                delete = cur;
                goto skip_children;
            }
        }
        else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
            (xsltCheckExtPrefix(style, cur->ns->prefix)))
        {
            /*
             * okay this is an extension element compile it too
             */
            xsltStylePreCompute(style, cur);
        }
        else if (cur->type == XML_ELEMENT_NODE)
        {
            /*
             * This is an element which will be output as part of the
             * template exectution, precompile AVT if found.
             */
            if ((cur->ns == NULL) && (style->defaultAlias != NULL)) {
                cur->ns = xmlSearchNsByHref(cur->doc, cur,
                        style->defaultAlias);
            }
            if (cur->properties != NULL) {
                xmlAttrPtr attr = cur->properties;

                while (attr != NULL) {
                    xsltCompileAttr(style, attr);
                    attr = attr->next;
                }
            }
        }
        /*
         * Skip to next node
         */
        if (cur->children != NULL) {
            if (cur->children->type != XML_ENTITY_DECL) {
                cur = cur->children;
                continue;
            }
        }
skip_children:
        if (cur->next != NULL) {
            cur = cur->next;
            continue;
        }
        
        do {
            cur = cur->parent;
            if (cur == NULL)
                break;
            if (cur == templ) {
                cur = NULL;
                break;
            }
            if (cur->next != NULL) {
                cur = cur->next;
                break;
            }
        } while (cur != NULL);
    }
    if (delete != NULL) {
#ifdef WITH_XSLT_DEBUG_PARSING
        xsltGenericDebug(xsltGenericDebugContext,
         "xsltParseTemplateContent: removing text\n");
#endif
        xmlUnlinkNode(delete);
        xmlFreeNode(delete);
        delete = NULL;
    }

    /*
     * Skip the first params
     */
    cur = templ->children;
    while (cur != NULL) {
        if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
            break;
        cur = cur->next;
    }

    /*
     * Browse the remainder of the template
     */
    while (cur != NULL) {
        if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
            xmlNodePtr param = cur;

            xsltTransformError(NULL, style, cur,
                "xsltParseTemplateContent: ignoring misplaced param element\n");
            if (style != NULL) style->warnings++;
            cur = cur->next;
            xmlUnlinkNode(param);
            xmlFreeNode(param);
        } else
            break;
    }
}

#endif /* else XSLT_REFACTORED */

/**
 * xsltParseStylesheetKey:
 * @style:  the XSLT stylesheet
 * @key:  the "key" element
 *
 * <!-- Category: top-level-element -->
 * <xsl:key name = qname, match = pattern, use = expression />
 *
 * parse an XSLT stylesheet key definition and register it
 */

static void
xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
    xmlChar *prop = NULL;
    xmlChar *use = NULL;
    xmlChar *match = NULL;
    xmlChar *name = NULL;
    xmlChar *nameURI = NULL;

    if ((style == NULL) || (key == NULL))
        return;

    /*
     * Get arguments
     */
    prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
    if (prop != NULL) {
        const xmlChar *URI;

        /*
        * TODO: Don't use xsltGetQNameURI().
        */
        URI = xsltGetQNameURI(key, &prop);
        if (prop == NULL) {
            if (style != NULL) style->errors++;
            goto error;
        } else {
            name = prop;
            if (URI != NULL)
                nameURI = xmlStrdup(URI);
        }
#ifdef WITH_XSLT_DEBUG_PARSING
        xsltGenericDebug(xsltGenericDebugContext,
             "xsltParseStylesheetKey: name %s\n", name);
#endif
    } else {
        xsltTransformError(NULL, style, key,
            "xsl:key : error missing name\n");
        if (style != NULL) style->errors++;
        goto error;
    }

    match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
    if (match == NULL) {
        xsltTransformError(NULL, style, key,
            "xsl:key : error missing match\n");
        if (style != NULL) style->errors++;
        goto error;
    }

    use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
    if (use == NULL) {
        xsltTransformError(NULL, style, key,
            "xsl:key : error missing use\n");
        if (style != NULL) style->errors++;
        goto error;
    }

    /*
     * register the keys
     */
    xsltAddKey(style, name, nameURI, match, use, key);


error:
    if (use != NULL)
        xmlFree(use);
    if (match != NULL)
        xmlFree(match);
    if (name != NULL)
        xmlFree(name);
    if (nameURI != NULL)
        xmlFree(nameURI);

    if (key->children != NULL) {
        xsltParseContentError(style, key->children);
    }
}

#ifdef XSLT_REFACTORED
/**
 * xsltParseXSLTTemplate:
 * @style:  the XSLT stylesheet
 * @template:  the "template" element
 *
 * parse an XSLT stylesheet template building the associated structures
 * TODO: Is @style ever expected to be NULL?
 *
 * Called from:
 *   xsltParseXSLTStylesheet()
 *   xsltParseStylesheetTop()
 */

static void
xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
    xsltTemplatePtr templ;
    xmlChar *prop;    
    double  priority;    

    if ((cctxt == NULL) || (templNode == NULL))
        return;

    /*
     * Create and link the structure
     */
    templ = xsltNewTemplate();
    if (templ == NULL)
        return;

    xsltCompilerNodePush(cctxt, templNode);
    if (templNode->nsDef != NULL)
        cctxt->inode->inScopeNs =
            xsltCompilerBuildInScopeNsList(cctxt, templNode);

    templ->next = cctxt->style->templates;
    cctxt->style->templates = templ;
    templ->style = cctxt->style;  

    /*
    * Attribute "mode".
    */
    prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);
    if (prop != NULL) { 
        const xmlChar *modeURI;

        /*
        * TODO: We need a standardized function for extraction
        *  of namespace names and local names from QNames.
        *  Don't use xsltGetQNameURI() as it cannot channel
        *  reports through the context.
        */
        modeURI = xsltGetQNameURI(templNode, &prop);
        if (prop == NULL) {
            cctxt->style->errors++;
            goto error;
        }
        templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);
        xmlFree(prop);
        prop = NULL;
        if (xmlValidateNCName(templ->mode, 0)) {
            xsltTransformError(NULL, cctxt->style, templNode,
                "xsl:template: Attribute 'mode': The local part '%s' "
                "of the value is not a valid NCName.\n", templ->name);
            cctxt->style->errors++;
            goto error;
        }
        if (modeURI != NULL)
            templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);
#ifdef WITH_XSLT_DEBUG_PARSING
        xsltGenericDebug(xsltGenericDebugContext,
             "xsltParseXSLTTemplate: mode %s\n", templ->mode);
#endif
    }
    /*
    * Attribute "match".
    */
    prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);
    if (prop != NULL) {
        templ->match  = prop;
        prop = NULL;
    }
    /*
    * Attribute "priority".
    */
    prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);
    if (prop != NULL) {
        priority = xmlXPathStringEvalNumber(prop);
        templ->priority = (float) priority;
        xmlFree(prop);
        prop = NULL;
    }
    /*
    * Attribute "name".
    */
    prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);
    if (prop != NULL) {
        const xmlChar *nameURI;
        xsltTemplatePtr curTempl;
        
        /*
        * TODO: Don't use xsltGetQNameURI().
        */
        nameURI = xsltGetQNameURI(templNode, &prop);
        if (prop == NULL) {
            cctxt->style->errors++;
            goto error;
        }
        templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);
        xmlFree(prop);
        prop = NULL;
        if (xmlValidateNCName(templ->name, 0)) {
            xsltTransformError(NULL, cctxt->style, templNode,
                "xsl:template: Attribute 'name': The local part '%s' of "
                "the value is not a valid NCName.\n", templ->name);
            cctxt->style->errors++;
            goto error;
        }       
        if (nameURI != NULL)
            templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);
        curTempl = templ->next;
        while (curTempl != NULL) {
            if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&
                xmlStrEqual(curTempl->nameURI, nameURI) ) ||
                (nameURI == NULL && curTempl->nameURI == NULL &&
                xmlStrEqual(curTempl->name, templ->name)))
            {
                xsltTransformError(NULL, cctxt->style, templNode,
                    "xsl:template: error duplicate name '%s'\n", templ->name);
                cctxt->style->errors++;
                goto error;
            }
            curTempl = curTempl->next;
        }
    }
    if (templNode->children != NULL) {
        xsltParseTemplateContent(cctxt->style, templNode);      
        /*
        * MAYBE TODO: Custom behaviour: In order to stay compatible with
        * Xalan and MSXML(.NET), we could allow whitespace
        * to appear before an xml:param element; this whitespace
        * will additionally become part of the "template".
        * NOTE that this is totally deviates from the spec, but
        * is the de facto behaviour of Xalan and MSXML(.NET).
        * Personally I wouldn't allow this, since if we have:
        * <xsl:template ...xml:space="preserve">
        *   <xsl:param name="foo"/>
        *   <xsl:param name="bar"/>
        *   <xsl:param name="zoo"/>
        * ... the whitespace between every xsl:param would be
        * added to the result tree.
        */              
    }    
    
    templ->elem = templNode;
    templ->content = templNode->children;
    xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI);

error:
    xsltCompilerNodePop(cctxt, templNode);
    return;
}

#else /* XSLT_REFACTORED */

/**
 * xsltParseStylesheetTemplate:
 * @style:  the XSLT stylesheet
 * @template:  the "template" element
 *
 * parse an XSLT stylesheet template building the associated structures
 */

static void
xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
    xsltTemplatePtr ret;
    xmlChar *prop;
    xmlChar *mode = NULL;
    xmlChar *modeURI = NULL;
    double  priority;

    if (template == NULL)
        return;

    /*
     * Create and link the structure
     */
    ret = xsltNewTemplate();
    if (ret == NULL)
        return;
    ret->next = style->templates;
    style->templates = ret;
    ret->style = style;
   
    /*
     * Get inherited namespaces
     */
    /*
    * TODO: Apply the optimized in-scope-namespace mechanism
    *   as for the other XSLT instructions.
    */
    xsltGetInheritedNsList(style, ret, template);

    /*
     * Get arguments
     */
    prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);
    if (prop != NULL) {
        const xmlChar *URI;

        /*
        * TODO: Don't use xsltGetQNameURI().
        */
        URI = xsltGetQNameURI(template, &prop);
        if (prop == NULL) {
            if (style != NULL) style->errors++;
            goto error;
        } else {
            mode = prop;
            if (URI != NULL)
                modeURI = xmlStrdup(URI);
        }
        ret->mode = xmlDictLookup(style->dict, mode, -1);
        ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);
#ifdef WITH_XSLT_DEBUG_PARSING
        xsltGenericDebug(xsltGenericDebugContext,
             "xsltParseStylesheetTemplate: mode %s\n", mode);
#endif
        if (mode != NULL) xmlFree(mode);
        if (modeURI != NULL) xmlFree(modeURI);
    }
    prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);
    if (prop != NULL) {
        if (ret->match != NULL) xmlFree(ret->match);
        ret->match  = prop;
    }

    prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);
    if (prop != NULL) {
        priority = xmlXPathStringEvalNumber(prop);
        ret->priority = (float) priority;
        xmlFree(prop);
    }

    prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);
    if (prop != NULL) {
        const xmlChar *URI;
        xsltTemplatePtr cur;
        
        /*
        * TODO: Don't use xsltGetQNameURI().
        */
        URI = xsltGetQNameURI(template, &prop);
        if (prop == NULL) {
            if (style != NULL) style->errors++;
            goto error;
        } else {
            if (xmlValidateNCName(prop,0)) {
                xsltTransformError(NULL, style, template,
                    "xsl:template : error invalid name '%s'\n", prop);
                if (style != NULL) style->errors++;
                goto error;
            }
            ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
            xmlFree(prop);
            prop = NULL;
            if (URI != NULL)
                ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);
            else
                ret->nameURI = NULL;
            cur = ret->next;
            while (cur != NULL) {
                if ((URI != NULL && xmlStrEqual(cur->name, ret->name) &&
                                xmlStrEqual(cur->nameURI, URI) ) ||
                    (URI == NULL && cur->nameURI == NULL &&
                                xmlStrEqual(cur->name, ret->name))) {
                    xsltTransformError(NULL, style, template,
                        "xsl:template: error duplicate name '%s'\n", ret->name);
                    style->errors++;
                    goto error;
                }
                cur = cur->next;
            }
        }
    }

    /*
     * parse the content and register the pattern
     */
    xsltParseTemplateContent(style, template);
    ret->elem = template;
    ret->content = template->children;
    xsltAddTemplate(style, ret, ret->mode, ret->modeURI);

error:
    return;
}

#endif /* else XSLT_REFACTORED */

#ifdef XSLT_REFACTORED

/**
 * xsltIncludeComp:
 * @cctxt: the compilation contenxt
 * @node:  the xsl:include node
 *
 * Process the xslt include node on the source node
 */
static xsltStyleItemIncludePtr
xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) {
    xsltStyleItemIncludePtr item;

    if ((cctxt == NULL) || (node == NULL))
        return(NULL);

    node->psvi = NULL;
    item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude));
    if (item == NULL) {
        xsltTransformError(NULL, cctxt->style, node,
                "xsltIncludeComp : malloc failed\n");
        cctxt->style->errors++;
        return(NULL);
    }
    memset(item, 0, sizeof(xsltStyleItemInclude));

    node->psvi = item;
    item->inst = node;
    item->type = XSLT_FUNC_INCLUDE;

    item->next = cctxt->style->preComps;
    cctxt->style->preComps = (xsltElemPreCompPtr) item;

    return(item);
}

/**
 * xsltParseFindTopLevelElem:
 */
static int
xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,
                              xmlNodePtr cur,
                              const xmlChar *name,
                              const xmlChar *namespaceURI,
                              int breakOnOtherElem,                           
                              xmlNodePtr *resultNode)
{
    if (name == NULL)
        return(-1);

    *resultNode = NULL;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if ((cur->ns != NULL) && (cur->name != NULL)) {
                if ((*(cur->name) == *name) &&
                    xmlStrEqual(cur->name, name) &&
                    xmlStrEqual(cur->ns->href, namespaceURI))               
                {
                    *resultNode = cur;
                    return(1);
                }
            }
            if (breakOnOtherElem)
                break;
        }
        cur = cur->next;
    }
    *resultNode = cur;
    return(0);
}

static int
xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,
                          xmlNodePtr node,
                          xsltStyleType type)
{
    int ret = 0;

    /*
    * TODO: The reason why this function exists:
    *  due to historical reasons some of the
    *  top-level declarations are processed by functions
    *  in other files. Since we need still to set
    *  up the node-info and generate information like
    *  in-scope namespaces, this is a wrapper around
    *  those old parsing functions.
    */
    xsltCompilerNodePush(cctxt, node);
    if (node->nsDef != NULL)
        cctxt->inode->inScopeNs =
            xsltCompilerBuildInScopeNsList(cctxt, node);
    cctxt->inode->type = type;

    switch (type) {
        case XSLT_FUNC_INCLUDE:
            {
                int oldIsInclude;

                if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL)
                    goto exit;          
                /*
                * Mark this stylesheet tree as being currently included.
                */
                oldIsInclude = cctxt->isInclude;
                cctxt->isInclude = 1;
                                                
                if (xsltParseStylesheetInclude(cctxt->style, node) != 0) {
                    cctxt->style->errors++;
                }
                cctxt->isInclude = oldIsInclude;
            }
            break;
        case XSLT_FUNC_PARAM:
            xsltStylePreCompute(cctxt->style, node);
            xsltParseGlobalParam(cctxt->style, node);
            break;
        case XSLT_FUNC_VARIABLE:
            xsltStylePreCompute(cctxt->style, node);
            xsltParseGlobalVariable(cctxt->style, node);
            break;
        case XSLT_FUNC_ATTRSET:
            xsltParseStylesheetAttributeSet(cctxt->style, node);
            break;
        default:
            xsltTransformError(NULL, cctxt->style, node,
                "Internal error: (xsltParseTopLevelXSLTElem) "
                "Cannot handle this top-level declaration.\n");
            cctxt->style->errors++;
            ret = -1;
    }

exit:
    xsltCompilerNodePop(cctxt, node);

    return(ret);
}

#if 0
static int
xsltParseRemoveWhitespace(xmlNodePtr node)
{
    if ((node == NULL) || (node->children == NULL))
        return(0);
    else {
        xmlNodePtr delNode = NULL, child = node->children;

        do {
            if (delNode) {
                xmlUnlinkNode(delNode);
                xmlFreeNode(delNode);
                delNode = NULL;
            }
            if (((child->type == XML_TEXT_NODE) ||
                 (child->type == XML_CDATA_SECTION_NODE)) &&
                (IS_BLANK_NODE(child)))
                delNode = child;            
            child = child->next;
        } while (child != NULL);
        if (delNode) {
            xmlUnlinkNode(delNode);
            xmlFreeNode(delNode);
            delNode = NULL;
        }
    }
    return(0);
}
#endif

static int
xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
{
#ifdef WITH_XSLT_DEBUG_PARSING
    int templates = 0;
#endif
    xmlNodePtr cur, start = NULL;
    xsltStylesheetPtr style;

    if ((cctxt == NULL) || (node == NULL) ||
        (node->type != XML_ELEMENT_NODE))
        return(-1);    

    style = cctxt->style;    
    /*
    * At this stage all import declarations of all stylesheet modules
    * with the same stylesheet level have been processed.
    * Now we can safely parse the rest of the declarations.
    */
    if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include"))
    {
        xsltDocumentPtr include;
        /*
        * URGENT TODO: Make this work with simplified stylesheets!
        *   I.e., when we won't find an xsl:stylesheet element.
        */
        /*
        * This is as include declaration.
        */
        include = ((xsltStyleItemIncludePtr) node->psvi)->include;
        if (include == NULL) {
            /* TODO: raise error? */
            return(-1);
        }
        /*
        * TODO: Actually an xsl:include should locate an embedded
        *  stylesheet as well; so the document-element won't always
        *  be the element where the actual stylesheet is rooted at.
        *  But such embedded stylesheets are not supported by Libxslt yet.
        */
        node = xmlDocGetRootElement(include->doc);
        if (node == NULL) {
            return(-1);
        }
    }    
    
    if (node->children == NULL)
        return(0);
    /*
    * Push the xsl:stylesheet/xsl:transform element.
    */  
    xsltCompilerNodePush(cctxt, node);
    cctxt->inode->isRoot = 1;
    cctxt->inode->nsChanged = 0;
    /*
    * Start with the naked dummy info for literal result elements.
    */
    cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;

    /*
    * In every case, we need to have
    * the in-scope namespaces of the element, where the
    * stylesheet is rooted at, regardless if it's an XSLT
    * instruction or a literal result instruction (or if
    * this is an embedded stylesheet).
    */          
    cctxt->inode->inScopeNs =
        xsltCompilerBuildInScopeNsList(cctxt, node);

    /*
    * Process attributes of xsl:stylesheet/xsl:transform.
    * --------------------------------------------------
    * Allowed are:
    *  id = id
    *  extension-element-prefixes = tokens
    *  exclude-result-prefixes = tokens
    *  version = number (mandatory)    
    */
    if (xsltParseAttrXSLTVersion(cctxt, node,
        XSLT_ELEMENT_CATEGORY_XSLT) == 0)
    {    
        /*
        * Attribute "version".
        * XSLT 1.0: "An xsl:stylesheet element *must* have a version
        *  attribute, indicating the version of XSLT that the
        *  stylesheet requires".
        * The root element of a simplified stylesheet must also have
        * this attribute.
        */
#ifdef XSLT_REFACTORED_MANDATORY_VERSION
        if (isXsltElem)
            xsltTransformError(NULL, cctxt->style, node,
                "The attribute 'version' is missing.\n");
        cctxt->style->errors++; 
#else
        /* OLD behaviour. */
        xsltTransformError(NULL, cctxt->style, node,
            "xsl:version is missing: document may not be a stylesheet\n");
        cctxt->style->warnings++;
#endif
    }    
    /*
    * The namespaces declared by the attributes
    *  "extension-element-prefixes" and
    *  "exclude-result-prefixes" are local to *this*
    *  stylesheet tree; i.e., they are *not* visible to
    *  other stylesheet-modules, whether imported or included.
    * 
    * Attribute "extension-element-prefixes".
    */
    cctxt->inode->extElemNs =
        xsltParseExtElemPrefixes(cctxt, node, NULL,
            XSLT_ELEMENT_CATEGORY_XSLT);
    /*
    * Attribute "exclude-result-prefixes".
    */
    cctxt->inode->exclResultNs =
        xsltParseExclResultPrefixes(cctxt, node, NULL,
            XSLT_ELEMENT_CATEGORY_XSLT);
    /*
    * Create/reuse info for the literal result element.
    */
    if (cctxt->inode->nsChanged)
        xsltLREInfoCreate(cctxt, node, 0);
    /*
    * Processed top-level elements:
    * ----------------------------
    *  xsl:variable, xsl:param (QName, in-scope ns,
    *    expression (vars allowed))
    *  xsl:attribute-set (QName, in-scope ns)
    *  xsl:strip-space, xsl:preserve-space (XPath NameTests,
    *    in-scope ns)
    *    I *think* global scope, merge with includes
    *  xsl:output (QName, in-scope ns)
    *  xsl:key (QName, in-scope ns, pattern,
    *    expression (vars *not* allowed))
    *  xsl:decimal-format (QName, needs in-scope ns)
    *  xsl:namespace-alias (in-scope ns)
    *    global scope, merge with includes
    *  xsl:template (last, QName, pattern)
    *
    * (whitespace-only text-nodes have *not* been removed
    *  yet; this will be done in xsltParseSequenceConstructor)
    *
    * Report misplaced child-nodes first.
    */
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_TEXT_NODE) {
            xsltTransformError(NULL, style, cur,
                "Misplaced text node (content: '%s').\n",
                (cur->content != NULL) ? cur->content : BAD_CAST "");
            style->errors++;
        } else if (cur->type != XML_ELEMENT_NODE) {
            xsltTransformError(NULL, style, cur, "Misplaced node.\n");
            style->errors++;
        }
        cur = cur->next;
    }
    /*
    * Skip xsl:import elements; they have been processed
    * already.
    */
    cur = node->children;
    while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur,
            BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
        cur = cur->next;
    if (cur == NULL)
        goto exit;

    start = cur;
    /*
    * Process all top-level xsl:param elements.
    */
    while ((cur != NULL) &&
        xsltParseFindTopLevelElem(cctxt, cur,
        BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1)
    {
        xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM); 
        cur = cur->next;
    }  
    /*
    * Process all top-level xsl:variable elements.
    */
    cur = start;
    while ((cur != NULL) &&
        xsltParseFindTopLevelElem(cctxt, cur,
        BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1)
    {
        xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE);
        cur = cur->next;
    }   
    /*
    * Process all the rest of top-level elements.
    */
    cur = start;
    while (cur != NULL) {       
        /*
        * Process element nodes.
        */
        if (cur->type == XML_ELEMENT_NODE) {        
            if (cur->ns == NULL) {
                xsltTransformError(NULL, style, cur,
                    "Unexpected top-level element in no namespace.\n");
                style->errors++;
                cur = cur->next;
                continue;
            }
            /*
            * Process all XSLT elements.
            */
            if (IS_XSLT_ELEM_FAST(cur)) {
                /*
                * xsl:import is only allowed at the beginning.
                */
                if (IS_XSLT_NAME(cur, "import")) {
                    xsltTransformError(NULL, style, cur,
                        "Misplaced xsl:import element.\n");
                    style->errors++;
                    cur = cur->next;
                    continue;
                }
                /* 
                * TODO: Change the return type of the parsing functions
                *  to int.
                */
                if (IS_XSLT_NAME(cur, "template")) {
#ifdef WITH_XSLT_DEBUG_PARSING
                    templates++;
#endif
                    /*
                    * TODO: Is the position of xsl:template in the
                    *  tree significant? If not it would be easier to
                    *  parse them at a later stage.
                    */
                    xsltParseXSLTTemplate(cctxt, cur);
                } else if (IS_XSLT_NAME(cur, "variable")) {
                    /* NOP; done already */
                } else if (IS_XSLT_NAME(cur, "param")) {
                    /* NOP; done already */
                } else if (IS_XSLT_NAME(cur, "include")) {                  
                    if (cur->psvi != NULL)                  
                        xsltParseXSLTStylesheetElemCore(cctxt, cur);
                    else {
                        xsltTransformError(NULL, style, cur,
                            "Internal error: "
                            "(xsltParseXSLTStylesheetElemCore) "
                            "The xsl:include element was not compiled.\n");
                        style->errors++;
                    }
                } else if (IS_XSLT_NAME(cur, "strip-space")) {
                    /* No node info needed. */
                    xsltParseStylesheetStripSpace(style, cur);
                } else if (IS_XSLT_NAME(cur, "preserve-space")) {
                    /* No node info needed. */
                    xsltParseStylesheetPreserveSpace(style, cur);
                } else if (IS_XSLT_NAME(cur, "output")) {
                    /* No node-info needed. */
                    xsltParseStylesheetOutput(style, cur);
                } else if (IS_XSLT_NAME(cur, "key")) {
                    /* TODO: node-info needed for expressions ? */
                    xsltParseStylesheetKey(style, cur);
                } else if (IS_XSLT_NAME(cur, "decimal-format")) {
                    /* No node-info needed. */               
                    xsltParseStylesheetDecimalFormat(style, cur);
                } else if (IS_XSLT_NAME(cur, "attribute-set")) {                    
                    xsltParseTopLevelXSLTElem(cctxt, cur,
                        XSLT_FUNC_ATTRSET);             
                } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
                    /* NOP; done already */                 
                } else {
                    if (cctxt->inode->forwardsCompat) {
                        /*
                        * Forwards-compatible mode:
                        *
                        * XSLT-1: "if it is a top-level element and
                        *  XSLT 1.0 does not allow such elements as top-level
                        *  elements, then the element must be ignored along
                        *  with its content;"
                        */
                        /*
                        * TODO: I don't think we should generate a warning.
                        */
                        xsltTransformError(NULL, style, cur,
                            "Forwards-compatible mode: Ignoring unknown XSLT "
                            "element '%s'.\n", cur->name);
                        style->warnings++;
                    } else {
                        xsltTransformError(NULL, style, cur,
                            "Unknown XSLT element '%s'.\n", cur->name);
                        style->errors++;
                    }
                }
            } else {
                xsltTopLevelFunction function;

                /*
                * Process non-XSLT elements, which are in a
                *  non-NULL namespace.
                */
                /*
                * QUESTION: What does xsltExtModuleTopLevelLookup()
                *  do exactly?
                */
                function = xsltExtModuleTopLevelLookup(cur->name,
                    cur->ns->href);
                if (function != NULL)
                    function(style, cur);
#ifdef WITH_XSLT_DEBUG_PARSING
                xsltGenericDebug(xsltGenericDebugContext,
                    "xsltParseXSLTStylesheetElemCore : User-defined "
                    "data element '%s'.\n", cur->name);
#endif
            }
        }
        cur = cur->next;
    }

exit:

#ifdef WITH_XSLT_DEBUG_PARSING
    xsltGenericDebug(xsltGenericDebugContext,
        "### END of parsing top-level elements of doc '%s'.\n",
        node->doc->URL);
    xsltGenericDebug(xsltGenericDebugContext,
        "### Templates: %d\n", templates);
#ifdef XSLT_REFACTORED
    xsltGenericDebug(xsltGenericDebugContext,
        "### Max inodes: %d\n", cctxt->maxNodeInfos);
    xsltGenericDebug(xsltGenericDebugContext,
        "### Max LREs  : %d\n", cctxt->maxLREs);
#endif /* XSLT_REFACTORED */
#endif /* WITH_XSLT_DEBUG_PARSING */

    xsltCompilerNodePop(cctxt, node);
    return(0);
}

/**
 * xsltParseXSLTStylesheet:
 * @cctxt: the compiler context
 * @node: the xsl:stylesheet/xsl:transform element-node
 *
 * Parses the xsl:stylesheet and xsl:transform element. 
 *
 * <xsl:stylesheet
 *  id = id
 *  extension-element-prefixes = tokens
 *  exclude-result-prefixes = tokens
 *  version = number>
 *  <!-- Content: (xsl:import*, top-level-elements) -->
 * </xsl:stylesheet>
 *
 * BIG TODO: The xsl:include stuff.
 * 
 * Called by xsltParseStylesheetTree()
 *
 * Returns 0 on success, a positive result on errors and
 *         -1 on API or internal errors.
 */
static int
xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
{
    xmlNodePtr cur, start;

    if ((cctxt == NULL) || (node == NULL))
        return(-1);
    
    if (node->children == NULL)
        goto exit;

    /*
    * Process top-level elements:
    *  xsl:import (must be first)
    *  xsl:include (this is just a pre-processing)
    */
    cur = node->children;
    /*
    * Process xsl:import elements.
    * XSLT 1.0: "The xsl:import element children must precede all
    *  other element children of an xsl:stylesheet element,
    *  including any xsl:include element children."
    */    
    while ((cur != NULL) &&
        xsltParseFindTopLevelElem(cctxt, cur,
            BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
    {
        if (xsltParseStylesheetImport(cctxt->style, cur) != 0) {
            cctxt->style->errors++;
        }
        cur = cur->next;
    }
    if (cur == NULL)
        goto exit;
    start = cur;
    /*
    * Pre-process all xsl:include elements.
    */
    cur = start;
    while ((cur != NULL) &&
        xsltParseFindTopLevelElem(cctxt, cur,
            BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1)
    {
        xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE);
        cur = cur->next;
    }
    /*
    * Pre-process all xsl:namespace-alias elements.
    * URGENT TODO: This won't work correctly: the order of included
    *  aliases and aliases defined here is significant.
    */
    cur = start;
    while ((cur != NULL) &&
        xsltParseFindTopLevelElem(cctxt, cur,
            BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1)
    {
        xsltNamespaceAlias(cctxt->style, cur);
        cur = cur->next;
    }

    if (cctxt->isInclude) {
        /*
        * If this stylesheet is intended for inclusion, then
        * we will process only imports and includes. 
        */
        goto exit;
    } 
    /*
    * Now parse the rest of the top-level elements.
    */
    xsltParseXSLTStylesheetElemCore(cctxt, node);       
exit:

    return(0);
}

#else /* XSLT_REFACTORED */

/**
 * xsltParseStylesheetTop:
 * @style:  the XSLT stylesheet
 * @top:  the top level "stylesheet" or "transform" element
 *
 * scan the top level elements of an XSL stylesheet
 */
static void
xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
    xmlNodePtr cur;
    xmlChar *prop;
#ifdef WITH_XSLT_DEBUG_PARSING
    int templates = 0;
#endif

    if (top == NULL)
        return;

    prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL);
    if (prop == NULL) {
        xsltTransformError(NULL, style, top,
            "xsl:version is missing: document may not be a stylesheet\n");
        if (style != NULL) style->warnings++;
    } else {
        if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
            (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
            xsltTransformError(NULL, style, top,
                "xsl:version: only 1.0 features are supported\n");
             /* TODO set up compatibility when not XSLT 1.0 */
            if (style != NULL) style->warnings++;
        }
        xmlFree(prop);
    }

    /*
     * process xsl:import elements
     */
    cur = top->children;
    while (cur != NULL) {
            if (IS_BLANK_NODE(cur)) {
                    cur = cur->next;
                    continue;
            }
            if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
                    if (xsltParseStylesheetImport(style, cur) != 0)
                            if (style != NULL) style->errors++;
            } else
                    break;
            cur = cur->next;
    }

    /*
     * process other top-level elements
     */
    while (cur != NULL) {
        if (IS_BLANK_NODE(cur)) {
            cur = cur->next;
            continue;
        }
        if (cur->type == XML_TEXT_NODE) {
            if (cur->content != NULL) {
                xsltTransformError(NULL, style, cur,
                    "misplaced text node: '%s'\n", cur->content);
            }
            if (style != NULL) style->errors++;
            cur = cur->next;
            continue;
        }
        if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
            xsltGenericError(xsltGenericErrorContext,
                     "Found a top-level element %s with null namespace URI\n",
                     cur->name);
            if (style != NULL) style->errors++;
            cur = cur->next;
            continue;
        }
        if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
            xsltTopLevelFunction function;

            function = xsltExtModuleTopLevelLookup(cur->name,
                                                   cur->ns->href);
            if (function != NULL)
                function(style, cur);

#ifdef WITH_XSLT_DEBUG_PARSING
            xsltGenericDebug(xsltGenericDebugContext,
                    "xsltParseStylesheetTop : found foreign element %s\n",
                    cur->name);
#endif
            cur = cur->next;
            continue;
        }
        if (IS_XSLT_NAME(cur, "import")) {
            xsltTransformError(NULL, style, cur,
                        "xsltParseStylesheetTop: ignoring misplaced import element\n");
            if (style != NULL) style->errors++;
    } else if (IS_XSLT_NAME(cur, "include")) {
            if (xsltParseStylesheetInclude(style, cur) != 0)
                if (style != NULL) style->errors++;
    } else if (IS_XSLT_NAME(cur, "strip-space")) {
            xsltParseStylesheetStripSpace(style, cur);
    } else if (IS_XSLT_NAME(cur, "preserve-space")) {
            xsltParseStylesheetPreserveSpace(style, cur);
    } else if (IS_XSLT_NAME(cur, "output")) {
            xsltParseStylesheetOutput(style, cur);
    } else if (IS_XSLT_NAME(cur, "key")) {
            xsltParseStylesheetKey(style, cur);
    } else if (IS_XSLT_NAME(cur, "decimal-format")) {
            xsltParseStylesheetDecimalFormat(style, cur);
    } else if (IS_XSLT_NAME(cur, "attribute-set")) {
            xsltParseStylesheetAttributeSet(style, cur);
    } else if (IS_XSLT_NAME(cur, "variable")) {
            xsltParseGlobalVariable(style, cur);
    } else if (IS_XSLT_NAME(cur, "param")) {
            xsltParseGlobalParam(style, cur);
    } else if (IS_XSLT_NAME(cur, "template")) {
#ifdef WITH_XSLT_DEBUG_PARSING
            templates++;
#endif
            xsltParseStylesheetTemplate(style, cur);
    } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
            xsltNamespaceAlias(style, cur);
        } else {
            /*
            * BUG TODO: The version of the *doc* is irrelevant for
            *  the forwards-compatible mode.
            */
            if ((style != NULL) && (style->doc->version != NULL) &&
                (!strncmp((const char *) style->doc->version, "1.0", 3))) {
                xsltTransformError(NULL, style, cur,
                        "xsltParseStylesheetTop: unknown %s element\n",
                        cur->name);
                if (style != NULL) style->errors++;
            }
            else {
                /* do Forwards-Compatible Processing */
                xsltTransformError(NULL, style, cur,
                        "xsltParseStylesheetTop: ignoring unknown %s element\n",
                        cur->name);
                if (style != NULL) style->warnings++;
            }
        }
        cur = cur->next;
    }
#ifdef WITH_XSLT_DEBUG_PARSING
    xsltGenericDebug(xsltGenericDebugContext,
                    "parsed %d templates\n", templates);
#endif
}

#endif /* else of XSLT_REFACTORED */

#ifdef XSLT_REFACTORED
/**
 * xsltParseSimplifiedStylesheetTree:
 *
 * @style: the stylesheet (TODO: Change this to the compiler context)
 * @doc: the document containing the stylesheet.
 * @node: the node where the stylesheet is rooted at
 *
 * Returns 0 in case of success, a positive result if an error occurred
 *         and -1 on API and internal errors.
 */
static int
xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt,
                                  xmlDocPtr doc,
                                  xmlNodePtr node)
{
    xsltTemplatePtr templ;
    
    if ((cctxt == NULL) || (node == NULL))
        return(-1);

    if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE)
    {
        /*
        * TODO: Adjust report, since this might be an
        * embedded stylesheet.
        */
        xsltTransformError(NULL, cctxt->style, node,
            "The attribute 'xsl:version' is missing; cannot identify "
            "this document as an XSLT stylesheet document.\n");
        cctxt->style->errors++;
        return(1);
    }
    
#ifdef WITH_XSLT_DEBUG_PARSING
    xsltGenericDebug(xsltGenericDebugContext,
        "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
#endif        
    
    /*
    * Create and link the template
    */
    templ = xsltNewTemplate();
    if (templ == NULL) {
        return(-1);
    }
    templ->next = cctxt->style->templates;
    cctxt->style->templates = templ;
    templ->match = xmlStrdup(BAD_CAST "/");

    /*
    * Note that we push the document-node in this special case.
    */
    xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
    /*
    * In every case, we need to have
    * the in-scope namespaces of the element, where the
    * stylesheet is rooted at, regardless if it's an XSLT
    * instruction or a literal result instruction (or if
    * this is an embedded stylesheet).
    */
    cctxt->inode->inScopeNs =
        xsltCompilerBuildInScopeNsList(cctxt, node);
    /*
    * Parse the content and register the match-pattern.
    */
    xsltParseSequenceConstructor(cctxt, node);
    xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);

    templ->elem = (xmlNodePtr) doc;
    templ->content = node;
    xsltAddTemplate(cctxt->style, templ, NULL, NULL);
    cctxt->style->literal_result = 1;
    return(0);
}

#ifdef XSLT_REFACTORED_XSLT_NSCOMP
/**
 * xsltRestoreDocumentNamespaces:
 * @ns: map of namespaces
 * @doc: the document
 *
 * Restore the namespaces for the document
 *
 * Returns 0 in case of success, -1 in case of failure
 */
int
xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc)
{
    if (doc == NULL)
        return(-1);
    /*
    * Revert the changes we have applied to the namespace-URIs of
    * ns-decls.
    */    
    while (ns != NULL) {
        if ((ns->doc == doc) && (ns->ns != NULL)) {
            ns->ns->href = ns->origNsName;
            ns->origNsName = NULL;
            ns->ns = NULL;          
        }
        ns = ns->next;
    }
    return(0);
}
#endif /* XSLT_REFACTORED_XSLT_NSCOMP */

/**
 * xsltParseStylesheetProcess:
 * @style:  the XSLT stylesheet (the current stylesheet-level)
 * @doc:  and xmlDoc parsed XML
 *
 * Parses an XSLT stylesheet, adding the associated structures.
 * Called by:
 *  xsltParseStylesheetImportedDoc() (xslt.c)
 *  xsltParseStylesheetInclude() (imports.c)
 *
 * Returns the value of the @style parameter if everything
 * went right, NULL if something went amiss.
 */
xsltStylesheetPtr
xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc)
{
    xsltCompilerCtxtPtr cctxt;
    xmlNodePtr cur;
    int oldIsSimplifiedStylesheet;

    xsltInitGlobals();

    if ((style == NULL) || (doc == NULL))
        return(NULL);

    cctxt = XSLT_CCTXT(style);

    cur = xmlDocGetRootElement(doc);
    if (cur == NULL) {
        xsltTransformError(NULL, style, (xmlNodePtr) doc,
                "xsltParseStylesheetProcess : empty stylesheet\n");
        return(NULL);
    }
    oldIsSimplifiedStylesheet = cctxt->simplified;

    if ((IS_XSLT_ELEM(cur)) && 
        ((IS_XSLT_NAME(cur, "stylesheet")) ||
         (IS_XSLT_NAME(cur, "transform")))) {   
#ifdef WITH_XSLT_DEBUG_PARSING
        xsltGenericDebug(xsltGenericDebugContext,
                "xsltParseStylesheetProcess : found stylesheet\n");
#endif
        cctxt->simplified = 0;
        style->literal_result = 0;
    } else {
        cctxt->simplified = 1;
        style->literal_result = 1;
    }
    /*
    * Pre-process the stylesheet if not already done before.
    *  This will remove PIs and comments, merge adjacent
    *  text nodes, internalize strings, etc.
    */
    if (! style->nopreproc)
        xsltParsePreprocessStylesheetTree(cctxt, cur);
    /*
    * Parse and compile the stylesheet.
    */
    if (style->literal_result == 0) {
        if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0)
            return(NULL);
    } else {
        if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0)
            return(NULL);
    }    

    cctxt->simplified = oldIsSimplifiedStylesheet;

    return(style);
}

#else /* XSLT_REFACTORED */

/**
 * xsltParseStylesheetProcess:
 * @ret:  the XSLT stylesheet (the current stylesheet-level)
 * @doc:  and xmlDoc parsed XML
 *
 * Parses an XSLT stylesheet, adding the associated structures.
 * Called by:
 *  xsltParseStylesheetImportedDoc() (xslt.c)
 *  xsltParseStylesheetInclude() (imports.c)
 *
 * Returns the value of the @style parameter if everything
 * went right, NULL if something went amiss.
 */
xsltStylesheetPtr
xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
    xmlNodePtr cur;

    xsltInitGlobals();

    if (doc == NULL)
        return(NULL);
    if (ret == NULL)
        return(ret);
    
    /*
     * First steps, remove blank nodes,
     * locate the xsl:stylesheet element and the
     * namespace declaration.
     */
    cur = xmlDocGetRootElement(doc);
    if (cur == NULL) {
        xsltTransformError(NULL, ret, (xmlNodePtr) doc,
                "xsltParseStylesheetProcess : empty stylesheet\n");
        return(NULL);
    }

    if ((IS_XSLT_ELEM(cur)) && 
        ((IS_XSLT_NAME(cur, "stylesheet")) ||
         (IS_XSLT_NAME(cur, "transform")))) {   
#ifdef WITH_XSLT_DEBUG_PARSING
        xsltGenericDebug(xsltGenericDebugContext,
                "xsltParseStylesheetProcess : found stylesheet\n");
#endif
        ret->literal_result = 0;
        xsltParseStylesheetExcludePrefix(ret, cur, 1);
        xsltParseStylesheetExtPrefix(ret, cur, 1);
    } else {
        xsltParseStylesheetExcludePrefix(ret, cur, 0);
        xsltParseStylesheetExtPrefix(ret, cur, 0);
        ret->literal_result = 1;
    }
    if (!ret->nopreproc) {
        xsltPrecomputeStylesheet(ret, cur);
    }
    if (ret->literal_result == 0) {
        xsltParseStylesheetTop(ret, cur);
    } else {
        xmlChar *prop;
        xsltTemplatePtr template;

        /*
         * the document itself might be the template, check xsl:version
         */
        prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
        if (prop == NULL) {
            xsltTransformError(NULL, ret, cur,
                "xsltParseStylesheetProcess : document is not a stylesheet\n");
            return(NULL);
        }

#ifdef WITH_XSLT_DEBUG_PARSING
        xsltGenericDebug(xsltGenericDebugContext,
                "xsltParseStylesheetProcess : document is stylesheet\n");
#endif
        
        if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) {
            xsltTransformError(NULL, ret, cur,
                "xsl:version: only 1.0 features are supported\n");
             /* TODO set up compatibility when not XSLT 1.0 */
            ret->warnings++;
        }
        xmlFree(prop);

        /*
         * Create and link the template
         */
        template = xsltNewTemplate();
        if (template == NULL) {
            return(NULL);
        }
        template->next = ret->templates;
        ret->templates = template;
        template->match = xmlStrdup((const xmlChar *)"/");

        /*
         * parse the content and register the pattern
         */
        xsltParseTemplateContent(ret, (xmlNodePtr) doc);
        template->elem = (xmlNodePtr) doc;
        template->content = doc->children;
        xsltAddTemplate(ret, template, NULL, NULL);
        ret->literal_result = 1;        
    }

    return(ret);
}

#endif /* else of XSLT_REFACTORED */

/**
 * xsltParseStylesheetImportedDoc:
 * @doc:  an xmlDoc parsed XML
 * @parentStyle: pointer to the parent stylesheet (if it exists)
 *
 * parse an XSLT stylesheet building the associated structures
 * except the processing not needed for imported documents.
 *
 * Returns a new XSLT stylesheet structure.
 */

xsltStylesheetPtr
xsltParseStylesheetImportedDoc(xmlDocPtr doc,
                               xsltStylesheetPtr parentStyle) {
    xsltStylesheetPtr retStyle;

    if (doc == NULL)
        return(NULL);

    retStyle = xsltNewStylesheet();
    if (retStyle == NULL)
        return(NULL);
    /*
    * Set the importing stylesheet module; also used to detect recursion.
    */
    retStyle->parent = parentStyle;
    /*
    * Adjust the string dict.
    */
    if (doc->dict != NULL) {
        xmlDictFree(retStyle->dict);
        retStyle->dict = doc->dict;
#ifdef WITH_XSLT_DEBUG
        xsltGenericDebug(xsltGenericDebugContext,
            "reusing dictionary from %s for stylesheet\n",
            doc->URL);
#endif
        xmlDictReference(retStyle->dict);
    }           
    
    /*
    * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
    *  the stylesheet to containt distinct namespace prefixes.
    */
    xsltGatherNamespaces(retStyle);

#ifdef XSLT_REFACTORED
    {
        xsltCompilerCtxtPtr cctxt;
        xsltStylesheetPtr oldCurSheet;
            
        if (parentStyle == NULL) {
            xsltPrincipalStylesheetDataPtr principalData;
            /*
            * Principal stylesheet
            * --------------------
            */
            retStyle->principal = retStyle;
            /*
            * Create extra data for the principal stylesheet.
            */
            principalData = xsltNewPrincipalStylesheetData();
            if (principalData == NULL) {
                xsltFreeStylesheet(retStyle);
                return(NULL);
            }
            retStyle->principalData = principalData;
            /*
            * Create the compilation context
            * ------------------------------
            * (only once; for the principal stylesheet).
            * This is currently the only function where the
            * compilation context is created.
            */
            cctxt = xsltCompilationCtxtCreate(retStyle);
            if (cctxt == NULL) {
                xsltFreeStylesheet(retStyle);
                return(NULL);
            }               
            retStyle->compCtxt = (void *) cctxt;
            cctxt->style = retStyle;
            cctxt->dict = retStyle->dict;
            cctxt->psData = principalData;
            /*
            * Push initial dummy node info.
            */
            cctxt->depth = -1;
            xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
        } else {
            /*
            * Imported stylesheet.
            */
            retStyle->principal = parentStyle->principal;
            cctxt = parentStyle->compCtxt;
            retStyle->compCtxt = cctxt;
        }
        /*
        * Save the old and set the current stylesheet structure in the
        * compilation context.
        */
        oldCurSheet = cctxt->style;
        cctxt->style = retStyle;
        
        retStyle->doc = doc;
        xsltParseStylesheetProcess(retStyle, doc);
        
        cctxt->style = oldCurSheet;
        if (parentStyle == NULL) {
            /*
            * Pop the initial dummy node info.
            */
            xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
        } else {
            /*
            * Clear the compilation context of imported
            * stylesheets.
            * TODO: really?
            */
            /* retStyle->compCtxt = NULL; */
        }
        /*
        * Free the stylesheet if there were errors.
        */
        if (retStyle != NULL) {
            if (retStyle->errors != 0) {
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
                /*
                * Restore all changes made to namespace URIs of ns-decls.
                */
                if (cctxt->psData->nsMap)               
                    xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
#endif
                /*
                * Detach the doc from the stylesheet; otherwise the doc
                * will be freed in xsltFreeStylesheet().
                */
                retStyle->doc = NULL;
                /*
                * Cleanup the doc if its the main stylesheet.
                */
                if (parentStyle == NULL) {
                    xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
                    if (retStyle->compCtxt != NULL) {                   
                        xsltCompilationCtxtFree(retStyle->compCtxt);
                        retStyle->compCtxt = NULL;
                    }
                }

                xsltFreeStylesheet(retStyle);
                retStyle = NULL;
            }
        }
    }
        
#else /* XSLT_REFACTORED */
    /*
    * Old behaviour.
    */
    retStyle->doc = doc;
    if (xsltParseStylesheetProcess(retStyle, doc) == NULL) {
                retStyle->doc = NULL;
                xsltFreeStylesheet(retStyle);
                retStyle = NULL;
    }
    if (retStyle != NULL) {
        if (retStyle->errors != 0) {
            retStyle->doc = NULL;
            if (parentStyle == NULL)
                xsltCleanupStylesheetTree(doc,
                    xmlDocGetRootElement(doc));
            xsltFreeStylesheet(retStyle);
            retStyle = NULL;
        }
    }
#endif /* else of XSLT_REFACTORED */
        
    return(retStyle);
}

/**
 * xsltParseStylesheetDoc:
 * @doc:  and xmlDoc parsed XML
 *
 * parse an XSLT stylesheet, building the associated structures.  doc
 * is kept as a reference within the returned stylesheet, so changes
 * to doc after the parsing will be reflected when the stylesheet
 * is applied, and the doc is automatically freed when the
 * stylesheet is closed.
 *
 * Returns a new XSLT stylesheet structure.
 */

xsltStylesheetPtr
xsltParseStylesheetDoc(xmlDocPtr doc) {
    xsltStylesheetPtr ret;

    xsltInitGlobals();

    ret = xsltParseStylesheetImportedDoc(doc, NULL);
    if (ret == NULL)
        return(NULL);

    xsltResolveStylesheetAttributeSet(ret);
#ifdef XSLT_REFACTORED
    /*
    * Free the compilation context.
    * TODO: Check if it's better to move this cleanup to
    *   xsltParseStylesheetImportedDoc().
    */
    if (ret->compCtxt != NULL) {
        xsltCompilationCtxtFree(XSLT_CCTXT(ret));
        ret->compCtxt = NULL;
    }
#endif
    return(ret);
}

/**
 * xsltParseStylesheetFile:
 * @filename:  the filename/URL to the stylesheet
 *
 * Load and parse an XSLT stylesheet
 *
 * Returns a new XSLT stylesheet structure.
 */

xsltStylesheetPtr
xsltParseStylesheetFile(const xmlChar* filename) {
    xsltSecurityPrefsPtr sec;
    xsltStylesheetPtr ret;
    xmlDocPtr doc;
    
    xsltInitGlobals();

    if (filename == NULL)
        return(NULL);

#ifdef WITH_XSLT_DEBUG_PARSING
    xsltGenericDebug(xsltGenericDebugContext,
            "xsltParseStylesheetFile : parse %s\n", filename);
#endif

    /*
     * Security framework check
     */
    sec = xsltGetDefaultSecurityPrefs();
    if (sec != NULL) {
        int res;

        res = xsltCheckRead(sec, NULL, filename);
        if (res == 0) {
            xsltTransformError(NULL, NULL, NULL,
                 "xsltParseStylesheetFile: read rights for %s denied\n",
                             filename);
            return(NULL);
        }
    }

    doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,
                               NULL, XSLT_LOAD_START);
    if (doc == NULL) {
        xsltTransformError(NULL, NULL, NULL,
                "xsltParseStylesheetFile : cannot parse %s\n", filename);
        return(NULL);
    }
    ret = xsltParseStylesheetDoc(doc);
    if (ret == NULL) {
        xmlFreeDoc(doc);
        return(NULL);
    }

    return(ret);
}

/************************************************************************
 *                                                                      *
 *                      Handling of Stylesheet PI                       *
 *                                                                      *
 ************************************************************************/

#define CUR (*cur)
#define SKIP(val) cur += (val)
#define NXT(val) cur[(val)]
#define SKIP_BLANKS                                             \
    while (IS_BLANK(CUR)) NEXT
#define NEXT ((*cur) ?  cur++ : cur)

/**
 * xsltParseStylesheetPI:
 * @value: the value of the PI
 *
 * This function checks that the type is text/xml and extracts
 * the URI-Reference for the stylesheet
 *
 * Returns the URI-Reference for the stylesheet or NULL (it need to
 *         be freed by the caller)
 */
static xmlChar *
xsltParseStylesheetPI(const xmlChar *value) {
    const xmlChar *cur;
    const xmlChar *start;
    xmlChar *val;
    xmlChar tmp;
    xmlChar *href = NULL;
    int isXml = 0;

    if (value == NULL)
        return(NULL);

    cur = value;
    while (CUR != 0) {
        SKIP_BLANKS;
        if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
            (NXT(3) == 'e')) {
            SKIP(4);
            SKIP_BLANKS;
            if (CUR != '=')
                continue;
            NEXT;
            if ((CUR != '\'') && (CUR != '"'))
                continue;
            tmp = CUR;
            NEXT;
            start = cur;
            while ((CUR != 0) && (CUR != tmp))
                NEXT;
            if (CUR != tmp)
                continue;
            val = xmlStrndup(start, cur - start);
            NEXT;
            if (val == NULL) 
                return(NULL);
            if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
                (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
                xmlFree(val);
                break;
            }
            isXml = 1;
            xmlFree(val);
        } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
            (NXT(3) == 'f')) {
            SKIP(4);
            SKIP_BLANKS;
            if (CUR != '=')
                continue;
            NEXT;
            if ((CUR != '\'') && (CUR != '"'))
                continue;
            tmp = CUR;
            NEXT;
            start = cur;
            while ((CUR != 0) && (CUR != tmp))
                NEXT;
            if (CUR != tmp)
                continue;
            if (href == NULL)
                href = xmlStrndup(start, cur - start);
            NEXT;
        } else {
            while ((CUR != 0) && (!IS_BLANK(CUR)))
                NEXT;
        }
            
    }

    if (!isXml) {
        if (href != NULL)
            xmlFree(href);
        href = NULL;
    }
    return(href);
}

/**
 * xsltLoadStylesheetPI:
 * @doc:  a document to process
 *
 * This function tries to locate the stylesheet PI in the given document
 * If found, and if contained within the document, it will extract 
 * that subtree to build the stylesheet to process @doc (doc itself will
 * be modified). If found but referencing an external document it will
 * attempt to load it and generate a stylesheet from it. In both cases,
 * the resulting stylesheet and the document need to be freed once the
 * transformation is done.
 *
 * Returns a new XSLT stylesheet structure or NULL if not found.
 */
xsltStylesheetPtr
xsltLoadStylesheetPI(xmlDocPtr doc) {
    xmlNodePtr child;
    xsltStylesheetPtr ret = NULL;
    xmlChar *href = NULL;
    xmlURIPtr URI;

    xsltInitGlobals();

    if (doc == NULL)
        return(NULL);

    /*
     * Find the text/xml stylesheet PI id any before the root
     */
    child = doc->children;
    while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
        if ((child->type == XML_PI_NODE) &&
            (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
            href = xsltParseStylesheetPI(child->content);
            if (href != NULL)
                break;
        }
        child = child->next;
    }

    /*
     * If found check the href to select processing
     */
    if (href != NULL) {
#ifdef WITH_XSLT_DEBUG_PARSING
        xsltGenericDebug(xsltGenericDebugContext,
                "xsltLoadStylesheetPI : found PI href=%s\n", href);
#endif
        URI = xmlParseURI((const char *) href);
        if (URI == NULL) {
            xsltTransformError(NULL, NULL, child,
                    "xml-stylesheet : href %s is not valid\n", href);
            xmlFree(href);
            return(NULL);
        }
        if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
            (URI->opaque == NULL) && (URI->authority == NULL) &&
            (URI->server == NULL) && (URI->user == NULL) &&
            (URI->path == NULL) && (URI->query == NULL)) {
            xmlAttrPtr ID;

#ifdef WITH_XSLT_DEBUG_PARSING
            xsltGenericDebug(xsltGenericDebugContext,
                    "xsltLoadStylesheetPI : Reference to ID %s\n", href);
#endif
            if (URI->fragment[0] == '#')
                ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
            else
                ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
            if (ID == NULL) {
                xsltTransformError(NULL, NULL, child,
                    "xml-stylesheet : no ID %s found\n", URI->fragment);
            } else {
                xmlDocPtr fake;
                xmlNodePtr subtree, newtree;
                xmlNsPtr ns;

#ifdef WITH_XSLT_DEBUG
                xsltGenericDebug(xsltGenericDebugContext,
                    "creating new document from %s for embedded stylesheet\n",
                    doc->URL);
#endif
                /*
                 * move the subtree in a new document passed to
                 * the stylesheet analyzer
                 */
                subtree = ID->parent;
                fake = xmlNewDoc(NULL);
                if (fake != NULL) {
                    /*
                    * Should the dictionary still be shared even though
                    * the nodes are being copied rather than moved?
                    */
                    fake->dict = doc->dict;
                    xmlDictReference(doc->dict);
#ifdef WITH_XSLT_DEBUG
                    xsltGenericDebug(xsltGenericDebugContext,
                        "reusing dictionary from %s for embedded stylesheet\n",
                        doc->URL);
#endif

                    newtree = xmlDocCopyNode(subtree, fake, 1);

                    fake->URL = xmlNodeGetBase(doc, subtree->parent);
#ifdef WITH_XSLT_DEBUG
                    xsltGenericDebug(xsltGenericDebugContext,
                        "set base URI for embedded stylesheet as %s\n",
                        fake->URL);
#endif

                    /*
                    * Add all namespaces in scope of embedded stylesheet to
                    * root element of newly created stylesheet document
                    */
                    while ((subtree = subtree->parent) != (xmlNodePtr)doc) {
                        for (ns = subtree->ns; ns; ns = ns->next) {
                            xmlNewNs(newtree,  ns->href, ns->prefix);
                        }
                    }

                    xmlAddChild((xmlNodePtr)fake, newtree);
                    ret = xsltParseStylesheetDoc(fake);
                    if (ret == NULL)
                        xmlFreeDoc(fake);
                }
            }
        } else {
            xmlChar *URL, *base;

            /*
             * Reference to an external stylesheet
             */

            base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
            URL = xmlBuildURI(href, base);
            if (URL != NULL) {
#ifdef WITH_XSLT_DEBUG_PARSING
                xsltGenericDebug(xsltGenericDebugContext,
                        "xsltLoadStylesheetPI : fetching %s\n", URL);
#endif
                ret = xsltParseStylesheetFile(URL);
                xmlFree(URL);
            } else {
#ifdef WITH_XSLT_DEBUG_PARSING
                xsltGenericDebug(xsltGenericDebugContext,
                        "xsltLoadStylesheetPI : fetching %s\n", href);
#endif
                ret = xsltParseStylesheetFile(href);
            }
            if (base != NULL)
                xmlFree(base);
        }
        xmlFreeURI(URI);
        xmlFree(href);
    }
    return(ret);
}

/* [<][>][^][v][top][bottom][index][help] */