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