Add barebone libxslt files to Android to support Android webkit.

This from libxslt version 2.7.7.
No change is made, just directly from open source.
Other currenlty omitted files can be added later if necessary.

Change-Id: I4a2ee1c4dfa330065380f7ad446164c5deb69105
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..094ebbc
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,20 @@
+Daniel Veillard:
+   daniel@veillard.com
+   DV on #gnome IRC channel
+   http://veillard.com/
+   Used to work at W3C, now Red Hat
+   co-chair of W3C XML Linking WG
+   invited expert on the W3C XML Core WG
+   Author of libxml upon which this library is based.
+
+Bjorn Reese:
+   breese@users.sourceforge.net
+   http://home1.stofanet.dk/breese/
+   Software developer at http://www.systematic.dk/
+   Member of the XML-MTF Mapping WG.
+
+William Brack <wbrack@mmm.com.hk>
+
+Thomas Broyer <tbroyer@ltgt.net>
+
+Igor Zlatkovic <igor@zlatkovic.com> for the Windows port
diff --git a/Copyright b/Copyright
new file mode 100644
index 0000000..627eeff
--- /dev/null
+++ b/Copyright
@@ -0,0 +1,53 @@
+Licence for libxslt except libexslt
+----------------------------------------------------------------------
+ Copyright (C) 2001-2002 Daniel Veillard.  All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is fur-
+nished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
+NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
+NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Daniel Veillard shall not
+be used in advertising or otherwise to promote the sale, use or other deal-
+ings in this Software without prior written authorization from him.
+
+----------------------------------------------------------------------
+
+Licence for libexslt
+----------------------------------------------------------------------
+ Copyright (C) 2001-2002 Thomas Broyer, Charlie Bozeman and Daniel Veillard.
+ All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is fur-
+nished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
+NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
+NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the authors shall not
+be used in advertising or otherwise to promote the sale, use or other deal-
+ings in this Software without prior written authorization from him.
+----------------------------------------------------------------------
diff --git a/README b/README
new file mode 100644
index 0000000..85bf80e
--- /dev/null
+++ b/README
@@ -0,0 +1,24 @@
+
+     XSLT support for libxml2 (XML toolkit from the GNOME project)
+
+Full documentation is available on-line at
+    http://xmlsoft.org/XSLT/
+
+This code is released under the MIT Licence see the Copyright file.
+ 
+To report bugs, follow the instructions at:
+  http://xmlsoft.org/XSLT/bugs.html
+
+A mailing-list xslt@gnome.org is available, to subscribe:
+    http://mail.gnome.org/mailman/listinfo/xslt
+
+The list archive is at:
+    http://mail.gnome.org/archives/xslt/
+
+All technical answers asked privately will be automatically answered on
+the list and archived for public access unless pricacy is explicitely
+required and justified.
+
+Daniel Veillard
+
+$Id$
diff --git a/libxslt/attributes.c b/libxslt/attributes.c
new file mode 100644
index 0000000..ce47df7
--- /dev/null
+++ b/libxslt/attributes.c
@@ -0,0 +1,1139 @@
+/*
+ * attributes.c: Implementation of the XSLT attributes handling
+ *
+ * Reference:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+#ifdef HAVE_NAN_H
+#include <nan.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/hash.h>
+#include <libxml/xmlerror.h>
+#include <libxml/uri.h>
+#include <libxml/parserInternals.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "attributes.h"
+#include "namespaces.h"
+#include "templates.h"
+#include "imports.h"
+#include "transform.h"
+#include "preproc.h"
+
+#define WITH_XSLT_DEBUG_ATTRIBUTES
+#ifdef WITH_XSLT_DEBUG
+#define WITH_XSLT_DEBUG_ATTRIBUTES
+#endif
+
+/*
+ * TODO: merge attribute sets from different import precedence.
+ *       all this should be precomputed just before the transformation
+ *       starts or at first hit with a cache in the context.
+ *       The simple way for now would be to not allow redefinition of
+ *       attributes once generated in the output tree, possibly costlier.
+ */
+
+/*
+ * Useful macros
+ */
+#ifdef IS_BLANK
+#undef IS_BLANK
+#endif
+
+#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||	\
+                     ((c) == 0x0D))
+
+#define IS_BLANK_NODE(n)						\
+    (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
+
+
+/*
+ * The in-memory structure corresponding to an XSLT Attribute in
+ * an attribute set
+ */
+
+
+typedef struct _xsltAttrElem xsltAttrElem;
+typedef xsltAttrElem *xsltAttrElemPtr;
+struct _xsltAttrElem {
+    struct _xsltAttrElem *next;/* chained list */
+    xmlNodePtr attr;	/* the xsl:attribute definition */
+    const xmlChar *set; /* or the attribute set */
+    const xmlChar *ns;  /* and its namespace */
+};
+
+/************************************************************************
+ *									*
+ *			XSLT Attribute handling				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltNewAttrElem:
+ * @attr:  the new xsl:attribute node
+ *
+ * Create a new XSLT AttrElem
+ *
+ * Returns the newly allocated xsltAttrElemPtr or NULL in case of error
+ */
+static xsltAttrElemPtr
+xsltNewAttrElem(xmlNodePtr attr) {
+    xsltAttrElemPtr cur;
+
+    cur = (xsltAttrElemPtr) xmlMalloc(sizeof(xsltAttrElem));
+    if (cur == NULL) {
+        xsltGenericError(xsltGenericErrorContext,
+		"xsltNewAttrElem : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltAttrElem));
+    cur->attr = attr;
+    return(cur);
+}
+
+/**
+ * xsltFreeAttrElem:
+ * @attr:  an XSLT AttrElem
+ *
+ * Free up the memory allocated by @attr
+ */
+static void
+xsltFreeAttrElem(xsltAttrElemPtr attr) {
+    xmlFree(attr);
+}
+
+/**
+ * xsltFreeAttrElemList:
+ * @list:  an XSLT AttrElem list
+ *
+ * Free up the memory allocated by @list
+ */
+static void
+xsltFreeAttrElemList(xsltAttrElemPtr list) {
+    xsltAttrElemPtr next;
+    
+    while (list != NULL) {
+	next = list->next;
+	xsltFreeAttrElem(list);
+	list = next;
+    }
+}
+
+#ifdef XSLT_REFACTORED
+    /*
+    * This was moved to xsltParseStylesheetAttributeSet().
+    */
+#else
+/**
+ * xsltAddAttrElemList:
+ * @list:  an XSLT AttrElem list
+ * @attr:  the new xsl:attribute node
+ *
+ * Add the new attribute to the list.
+ *
+ * Returns the new list pointer
+ */
+static xsltAttrElemPtr
+xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) {
+    xsltAttrElemPtr next, cur;
+
+    if (attr == NULL)
+	return(list);
+    if (list == NULL)
+	return(xsltNewAttrElem(attr));
+    cur = list;
+    while (cur != NULL) {	
+	next = cur->next;
+	if (cur->attr == attr)
+	    return(cur);
+	if (cur->next == NULL) {
+	    cur->next = xsltNewAttrElem(attr);
+	    return(list);
+	}
+	cur = next;
+    }
+    return(list);
+}
+#endif /* XSLT_REFACTORED */
+
+/**
+ * xsltMergeAttrElemList:
+ * @list:  an XSLT AttrElem list
+ * @old:  another XSLT AttrElem list
+ *
+ * Add all the attributes from list @old to list @list,
+ * but drop redefinition of existing values.
+ *
+ * Returns the new list pointer
+ */
+static xsltAttrElemPtr
+xsltMergeAttrElemList(xsltStylesheetPtr style,
+		      xsltAttrElemPtr list, xsltAttrElemPtr old) {
+    xsltAttrElemPtr cur;
+    int add;
+
+    while (old != NULL) {
+	if ((old->attr == NULL) && (old->set == NULL)) {
+	    old = old->next;
+	    continue;
+	}
+	/*
+	 * Check that the attribute is not yet in the list
+	 */
+	cur = list;
+	add = 1;
+	while (cur != NULL) {
+	    if ((cur->attr == NULL) && (cur->set == NULL)) {
+		if (cur->next == NULL)
+		    break;
+		cur = cur->next;
+		continue;
+	    }
+	    if ((cur->set != NULL) && (cur->set == old->set)) {
+		add = 0;
+		break;
+	    }
+	    if (cur->set != NULL) {
+		if (cur->next == NULL)
+		    break;
+		cur = cur->next;
+		continue;
+	    }
+	    if (old->set != NULL) {
+		if (cur->next == NULL)
+		    break;
+		cur = cur->next;
+		continue;
+	    }
+	    if (cur->attr == old->attr) {
+		xsltGenericError(xsltGenericErrorContext,
+	     "xsl:attribute-set : use-attribute-sets recursion detected\n");
+		return(list);
+	    }
+	    if (cur->next == NULL)
+		break;
+            cur = cur->next;
+	}
+
+	if (add == 1) {
+	    /*
+	    * Changed to use the string-dict, rather than duplicating
+	    * @set and @ns; this fixes bug #340400.
+	    */
+	    if (cur == NULL) {
+		list = xsltNewAttrElem(old->attr);
+		if (old->set != NULL) {
+		    list->set = xmlDictLookup(style->dict, old->set, -1);
+		    if (old->ns != NULL)
+			list->ns = xmlDictLookup(style->dict, old->ns, -1);
+		}
+	    } else if (add) {
+		cur->next = xsltNewAttrElem(old->attr);
+		if (old->set != NULL) {
+		    cur->next->set = xmlDictLookup(style->dict, old->set, -1);
+		    if (old->ns != NULL)
+			cur->next->ns = xmlDictLookup(style->dict, old->ns, -1);
+		}
+	    }
+	}
+
+	old = old->next;
+    }
+    return(list);
+}
+
+/************************************************************************
+ *									*
+ *			Module interfaces				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltParseStylesheetAttributeSet:
+ * @style:  the XSLT stylesheet
+ * @cur:  the "attribute-set" element
+ *
+ * parse an XSLT stylesheet attribute-set element
+ */
+
+void
+xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
+    const xmlChar *ncname;
+    const xmlChar *prefix;
+    xmlChar *value;
+    xmlNodePtr child;
+    xsltAttrElemPtr attrItems;
+
+    if ((cur == NULL) || (style == NULL))
+	return;
+
+    value = xmlGetNsProp(cur, (const xmlChar *)"name", NULL);
+    if (value == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	     "xsl:attribute-set : name is missing\n");
+	return;
+    }
+
+    ncname = xsltSplitQName(style->dict, value, &prefix);
+    xmlFree(value);
+    value = NULL;
+
+    if (style->attributeSets == NULL) {
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
+	xsltGenericDebug(xsltGenericDebugContext,
+	    "creating attribute set table\n");
+#endif
+	style->attributeSets = xmlHashCreate(10);
+    }
+    if (style->attributeSets == NULL)
+	return;
+
+    attrItems = xmlHashLookup2(style->attributeSets, ncname, prefix);
+
+    /*
+    * Parse the content. Only xsl:attribute elements are allowed.
+    */
+    child = cur->children;
+    while (child != NULL) {
+	/*
+	* Report invalid nodes.
+	*/
+	if ((child->type != XML_ELEMENT_NODE) ||
+	    (child->ns == NULL) ||
+	    (! IS_XSLT_ELEM(child)))
+	{
+	    if (child->type == XML_ELEMENT_NODE)
+		xsltTransformError(NULL, style, child,
+			"xsl:attribute-set : unexpected child %s\n",
+		                 child->name);
+	    else
+		xsltTransformError(NULL, style, child,
+			"xsl:attribute-set : child of unexpected type\n");
+	} else if (!IS_XSLT_NAME(child, "attribute")) {
+	    xsltTransformError(NULL, style, child,
+		"xsl:attribute-set : unexpected child xsl:%s\n",
+		child->name);
+	} else {
+#ifdef XSLT_REFACTORED
+	    xsltAttrElemPtr nextAttr, curAttr;
+
+	    /*
+	    * Process xsl:attribute
+	    * ---------------------
+	    */
+
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
+	    xsltGenericDebug(xsltGenericDebugContext,
+		"add attribute to list %s\n", ncname);
+#endif
+	    /*
+	    * The following was taken over from
+	    * xsltAddAttrElemList().
+	    */
+	    if (attrItems == NULL) {
+		attrItems = xsltNewAttrElem(child);
+	    } else {
+		curAttr = attrItems;
+		while (curAttr != NULL) {
+		    nextAttr = curAttr->next;
+		    if (curAttr->attr == child) {
+			/*
+			* URGENT TODO: Can somebody explain
+			*  why attrItems is set to curAttr
+			*  here? Is this somehow related to
+			*  avoidance of recursions?
+			*/
+			attrItems = curAttr;
+			goto next_child;
+		    }
+		    if (curAttr->next == NULL)			
+			curAttr->next = xsltNewAttrElem(child);
+		    curAttr = nextAttr;
+		}
+	    }
+	    /*
+	    * Parse the xsl:attribute and its content.
+	    */
+	    xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
+#else
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
+	    xsltGenericDebug(xsltGenericDebugContext,
+		"add attribute to list %s\n", ncname);
+#endif
+	    /*
+	    * OLD behaviour:
+	    */
+	    attrItems = xsltAddAttrElemList(attrItems, child);
+#endif
+	}
+
+#ifdef XSLT_REFACTORED
+next_child:
+#endif
+	child = child->next;
+    }
+
+    /*
+    * Process attribue "use-attribute-sets".
+    */
+    /* TODO check recursion */    
+    value = xmlGetNsProp(cur, (const xmlChar *)"use-attribute-sets",
+	NULL);
+    if (value != NULL) {
+	const xmlChar *curval, *endval;
+	curval = value;
+	while (*curval != 0) {
+	    while (IS_BLANK(*curval)) curval++;
+	    if (*curval == 0)
+		break;
+	    endval = curval;
+	    while ((*endval != 0) && (!IS_BLANK(*endval))) endval++;
+	    curval = xmlDictLookup(style->dict, curval, endval - curval);
+	    if (curval) {
+		const xmlChar *ncname2 = NULL;
+		const xmlChar *prefix2 = NULL;
+		xsltAttrElemPtr refAttrItems;
+		
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
+		xsltGenericDebug(xsltGenericDebugContext,
+		    "xsl:attribute-set : %s adds use %s\n", ncname, curval);
+#endif
+		ncname2 = xsltSplitQName(style->dict, curval, &prefix2);
+		refAttrItems = xsltNewAttrElem(NULL);
+		if (refAttrItems != NULL) {
+		    refAttrItems->set = ncname2;
+		    refAttrItems->ns = prefix2;
+		    attrItems = xsltMergeAttrElemList(style,
+			attrItems, refAttrItems);
+		    xsltFreeAttrElem(refAttrItems);
+		}
+	    }
+	    curval = endval;
+	}
+	xmlFree(value);
+	value = NULL;
+    }
+
+    /*
+     * Update the value
+     */
+    /*
+    * TODO: Why is this dummy entry needed.?
+    */
+    if (attrItems == NULL)
+	attrItems = xsltNewAttrElem(NULL);
+    xmlHashUpdateEntry2(style->attributeSets, ncname, prefix, attrItems, NULL);
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
+    xsltGenericDebug(xsltGenericDebugContext,
+	"updated attribute list %s\n", ncname);
+#endif
+}
+
+/**
+ * xsltGetSAS:
+ * @style:  the XSLT stylesheet
+ * @name:  the attribute list name
+ * @ns:  the attribute list namespace
+ *
+ * lookup an attribute set based on the style cascade
+ *
+ * Returns the attribute set or NULL
+ */
+static xsltAttrElemPtr
+xsltGetSAS(xsltStylesheetPtr style, const xmlChar *name, const xmlChar *ns) {
+    xsltAttrElemPtr values;
+
+    while (style != NULL) {
+	values = xmlHashLookup2(style->attributeSets, name, ns);
+	if (values != NULL)
+	    return(values);
+	style = xsltNextImport(style);
+    }
+    return(NULL);
+}
+
+/**
+ * xsltResolveSASCallback,:
+ * @style:  the XSLT stylesheet
+ *
+ * resolve the references in an attribute set.
+ */
+static void
+xsltResolveSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style,
+	               const xmlChar *name, const xmlChar *ns,
+		       ATTRIBUTE_UNUSED const xmlChar *ignored) {
+    xsltAttrElemPtr tmp;
+    xsltAttrElemPtr refs;
+
+    tmp = values;
+    while (tmp != NULL) {
+	if (tmp->set != NULL) {
+	    /*
+	     * Check against cycles !
+	     */
+	    if ((xmlStrEqual(name, tmp->set)) && (xmlStrEqual(ns, tmp->ns))) {
+		xsltGenericError(xsltGenericErrorContext,
+     "xsl:attribute-set : use-attribute-sets recursion detected on %s\n",
+                                 name);
+	    } else {
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
+		xsltGenericDebug(xsltGenericDebugContext,
+			"Importing attribute list %s\n", tmp->set);
+#endif
+
+		refs = xsltGetSAS(style, tmp->set, tmp->ns);
+		if (refs == NULL) {
+		    xsltGenericError(xsltGenericErrorContext,
+     "xsl:attribute-set : use-attribute-sets %s reference missing %s\n",
+				     name, tmp->set);
+		} else {
+		    /*
+		     * recurse first for cleanup
+		     */
+		    xsltResolveSASCallback(refs, style, name, ns, NULL);
+		    /*
+		     * Then merge
+		     */
+		    xsltMergeAttrElemList(style, values, refs);
+		    /*
+		     * Then suppress the reference
+		     */
+		    tmp->set = NULL;
+		    tmp->ns = NULL;
+		}
+	    }
+	}
+	tmp = tmp->next;
+    }
+}
+
+/**
+ * xsltMergeSASCallback,:
+ * @style:  the XSLT stylesheet
+ *
+ * Merge an attribute set from an imported stylesheet.
+ */
+static void
+xsltMergeSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style,
+	               const xmlChar *name, const xmlChar *ns,
+		       ATTRIBUTE_UNUSED const xmlChar *ignored) {
+    int ret;
+    xsltAttrElemPtr topSet;
+
+    ret = xmlHashAddEntry2(style->attributeSets, name, ns, values);
+    if (ret < 0) {
+	/*
+	 * Add failed, this attribute set can be removed.
+	 */
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
+	xsltGenericDebug(xsltGenericDebugContext,
+		"attribute set %s present already in top stylesheet"
+		" - merging\n", name);
+#endif
+	topSet = xmlHashLookup2(style->attributeSets, name, ns);
+	if (topSet==NULL) {
+	    xsltGenericError(xsltGenericErrorContext,
+	        "xsl:attribute-set : logic error merging from imports for"
+		" attribute-set %s\n", name);
+	} else {
+	    topSet = xsltMergeAttrElemList(style, topSet, values);
+	    xmlHashUpdateEntry2(style->attributeSets, name, ns, topSet, NULL);
+	}
+	xsltFreeAttrElemList(values);
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
+    } else {
+	xsltGenericDebug(xsltGenericDebugContext,
+		"attribute set %s moved to top stylesheet\n",
+		         name);
+#endif
+    }
+}
+
+/**
+ * xsltResolveStylesheetAttributeSet:
+ * @style:  the XSLT stylesheet
+ *
+ * resolve the references between attribute sets.
+ */
+void
+xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) {
+    xsltStylesheetPtr cur;
+
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
+    xsltGenericDebug(xsltGenericDebugContext,
+	    "Resolving attribute sets references\n");
+#endif
+    /*
+     * First aggregate all the attribute sets definitions from the imports
+     */
+    cur = xsltNextImport(style);
+    while (cur != NULL) {
+	if (cur->attributeSets != NULL) {
+	    if (style->attributeSets == NULL) {
+#ifdef WITH_XSLT_DEBUG_ATTRIBUTES
+		xsltGenericDebug(xsltGenericDebugContext,
+		    "creating attribute set table\n");
+#endif
+		style->attributeSets = xmlHashCreate(10);
+	    }
+	    xmlHashScanFull(cur->attributeSets, 
+		(xmlHashScannerFull) xsltMergeSASCallback, style);
+	    /*
+	     * the attribute lists have either been migrated to style
+	     * or freed directly in xsltMergeSASCallback()
+	     */
+	    xmlHashFree(cur->attributeSets, NULL);
+	    cur->attributeSets = NULL;
+	}
+	cur = xsltNextImport(cur);
+    }
+
+    /*
+     * Then resolve all the references and computes the resulting sets
+     */
+    if (style->attributeSets != NULL) {
+	xmlHashScanFull(style->attributeSets, 
+		(xmlHashScannerFull) xsltResolveSASCallback, style);
+    }
+}
+
+/**
+ * xsltAttributeInternal:
+ * @ctxt:  a XSLT process context
+ * @node:  the current node in the source tree
+ * @inst:  the xsl:attribute element
+ * @comp:  precomputed information
+ * @fromAttributeSet:  the attribute comes from an attribute-set
+ *
+ * Process the xslt attribute node on the source node
+ */
+static void
+xsltAttributeInternal(xsltTransformContextPtr ctxt,
+		      xmlNodePtr contextNode,
+                      xmlNodePtr inst,
+		      xsltStylePreCompPtr castedComp,
+                      int fromAttributeSet)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleItemAttributePtr comp =
+	(xsltStyleItemAttributePtr) castedComp;   
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif
+    xmlNodePtr targetElem;
+    xmlChar *prop = NULL;    
+    const xmlChar *name = NULL, *prefix = NULL, *nsName = NULL;
+    xmlChar *value = NULL;
+    xmlNsPtr ns = NULL;
+    xmlAttrPtr attr;    
+
+    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
+        return;
+
+    /* 
+    * A comp->has_name == 0 indicates that we need to skip this instruction,
+    * since it was evaluated to be invalid already during compilation.
+    */
+    if (!comp->has_name)
+        return;
+    /*
+    * BIG NOTE: This previously used xsltGetSpecialNamespace() and
+    *  xsltGetNamespace(), but since both are not appropriate, we
+    *  will process namespace lookup here to avoid adding yet another
+    *  ns-lookup function to namespaces.c.
+    */
+    /*
+    * SPEC XSLT 1.0: Error cases:
+    * - Creating nodes other than text nodes during the instantiation of
+    *   the content of the xsl:attribute element; implementations may
+    *   either signal the error or ignore the offending nodes."
+    */
+
+    if (comp == NULL) {
+        xsltTransformError(ctxt, NULL, inst,
+	    "Internal error in xsltAttributeInternal(): "
+	    "The XSLT 'attribute' instruction was not compiled.\n");
+        return;
+    }
+    /*
+    * TODO: Shouldn't ctxt->insert == NULL be treated as an internal error?
+    *   So report an internal error?
+    */
+    if (ctxt->insert == NULL)
+        return;    
+    /*
+    * SPEC XSLT 1.0:
+    *  "Adding an attribute to a node that is not an element;
+    *  implementations may either signal the error or ignore the attribute."
+    *
+    * TODO: I think we should signal such errors in the future, and maybe
+    *  provide an option to ignore such errors.
+    */
+    targetElem = ctxt->insert;
+    if (targetElem->type != XML_ELEMENT_NODE)
+	return;
+    
+    /*
+    * SPEC XSLT 1.0:
+    * "Adding an attribute to an element after children have been added
+    *  to it; implementations may either signal the error or ignore the
+    *  attribute."
+    *
+    * TODO: We should decide whether not to report such errors or
+    *  to ignore them; note that we *ignore* if the parent is not an
+    *  element, but here we report an error.
+    */
+    if (targetElem->children != NULL) {
+	/*
+	* NOTE: Ah! This seems to be intended to support streamed
+	*  result generation!.
+	*/
+        xsltTransformError(ctxt, NULL, inst,
+	    "xsl:attribute: Cannot add attributes to an "
+	    "element if children have been already added "
+	    "to the element.\n");
+        return;
+    }
+
+    /*
+    * Process the name
+    * ----------------
+    */    
+
+#ifdef WITH_DEBUGGER
+    if (ctxt->debugStatus != XSLT_DEBUG_NONE)
+        xslHandleDebugger(inst, contextNode, NULL, ctxt);
+#endif
+
+    if (comp->name == NULL) {
+	/* TODO: fix attr acquisition wrt to the XSLT namespace */
+        prop = xsltEvalAttrValueTemplate(ctxt, inst,
+	    (const xmlChar *) "name", XSLT_NAMESPACE);
+        if (prop == NULL) {
+            xsltTransformError(ctxt, NULL, inst,
+		"xsl:attribute: The attribute 'name' is missing.\n");
+            goto error;
+        }
+	if (xmlValidateQName(prop, 0)) {
+	    xsltTransformError(ctxt, NULL, inst,
+		"xsl:attribute: The effective name '%s' is not a "
+		"valid QName.\n", prop);
+	    /* we fall through to catch any further errors, if possible */
+	}
+	name = xsltSplitQName(ctxt->dict, prop, &prefix);
+	xmlFree(prop);
+
+	/*
+	* Reject a prefix of "xmlns".
+	*/
+	if ((prefix != NULL) &&
+	    (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)))
+	{
+#ifdef WITH_XSLT_DEBUG_PARSING
+	    xsltGenericDebug(xsltGenericDebugContext,
+		"xsltAttribute: xmlns prefix forbidden\n");
+#endif
+	    /*
+	    * SPEC XSLT 1.0:
+	    *  "It is an error if the string that results from instantiating
+	    *  the attribute value template is not a QName or is the string
+	    *  xmlns. An XSLT processor may signal the error; if it does not
+	    *  signal the error, it must recover by not adding the attribute
+	    *  to the result tree."
+	    * TODO: Decide which way to go here.
+	    */
+	    goto error;
+	}
+
+    } else {
+	/*
+	* The "name" value was static.
+	*/
+#ifdef XSLT_REFACTORED
+	prefix = comp->nsPrefix;
+	name = comp->name;
+#else
+	name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
+#endif
+    }
+    
+    /*
+    * Process namespace semantics
+    * ---------------------------
+    *
+    * Evaluate the namespace name.
+    */
+    if (comp->has_ns) {
+	/*
+	* The "namespace" attribute was existent.
+	*/
+	if (comp->ns != NULL) {
+	    /*
+	    * No AVT; just plain text for the namespace name.
+	    */
+	    if (comp->ns[0] != 0)
+		nsName = comp->ns;
+	} else {
+	    xmlChar *tmpNsName;
+	    /*
+	    * Eval the AVT.
+	    */
+	    /* TODO: check attr acquisition wrt to the XSLT namespace */
+	    tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
+		(const xmlChar *) "namespace", XSLT_NAMESPACE);	
+	    /*
+	    * This fixes bug #302020: The AVT might also evaluate to the 
+	    * empty string; this means that the empty string also indicates
+	    * "no namespace".
+	    * SPEC XSLT 1.0:
+	    *  "If the string is empty, then the expanded-name of the
+	    *  attribute has a null namespace URI."
+	    */
+	    if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
+		nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
+	    xmlFree(tmpNsName);		
+	};	    
+    } else if (prefix != NULL) {
+	/*
+	* SPEC XSLT 1.0:
+	*  "If the namespace attribute is not present, then the QName is
+	*  expanded into an expanded-name using the namespace declarations
+	*  in effect for the xsl:attribute element, *not* including any
+	*  default namespace declaration."
+	*/	
+	ns = xmlSearchNs(inst->doc, inst, prefix);
+	if (ns == NULL) {
+	    /*
+	    * Note that this is treated as an error now (checked with
+	    *  Saxon, Xalan-J and MSXML).
+	    */
+	    xsltTransformError(ctxt, NULL, inst,
+		"xsl:attribute: The QName '%s:%s' has no "
+		"namespace binding in scope in the stylesheet; "
+		"this is an error, since the namespace was not "
+		"specified by the instruction itself.\n", prefix, name);
+	} else
+	    nsName = ns->href;	
+    }
+
+    if (fromAttributeSet) {
+	/*
+	* This tries to ensure that xsl:attribute(s) coming
+	* from an xsl:attribute-set won't override attribute of
+	* literal result elements or of explicit xsl:attribute(s).
+	* URGENT TODO: This might be buggy, since it will miss to
+	*  overwrite two equal attributes both from attribute sets.
+	*/
+	attr = xmlHasNsProp(targetElem, name, nsName);
+	if (attr != NULL)
+	    return;
+    }
+
+    /*
+    * Find/create a matching ns-decl in the result tree.
+    */
+    ns = NULL;
+    
+#if 0
+    if (0) {	
+	/*
+	* OPTIMIZE TODO: How do we know if we are adding to a
+	*  fragment or to the result tree?
+	*
+	* If we are adding to a result tree fragment (i.e., not to the
+	* actual result tree), we'll don't bother searching for the
+	* ns-decl, but just store it in the dummy-doc of the result
+	* tree fragment.
+	*/
+	if (nsName != NULL) {
+	    /*
+	    * TODO: Get the doc of @targetElem.
+	    */
+	    ns = xsltTreeAcquireStoredNs(some doc, nsName, prefix);
+	}
+    }
+#endif
+
+    if (nsName != NULL) {	
+	/*
+	* Something about ns-prefixes:
+	* SPEC XSLT 1.0:
+	*  "XSLT processors may make use of the prefix of the QName specified
+	*  in the name attribute when selecting the prefix used for outputting
+	*  the created attribute as XML; however, they are not required to do
+	*  so and, if the prefix is xmlns, they must not do so"
+	*/
+	/*
+	* xsl:attribute can produce a scenario where the prefix is NULL,
+	* so generate a prefix.
+	*/
+	if (prefix == NULL) {
+	    xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");
+
+	    ns = xsltGetSpecialNamespace(ctxt, inst, nsName, BAD_CAST pref,
+		targetElem);
+
+	    xmlFree(pref);
+	} else {
+	    ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix,
+		targetElem);
+	}
+	if (ns == NULL) {
+	    xsltTransformError(ctxt, NULL, inst,
+		"Namespace fixup error: Failed to acquire an in-scope "
+		"namespace binding for the generated attribute '{%s}%s'.\n",
+		nsName, name);
+	    goto error;
+	}
+    }
+    /*
+    * Construction of the value
+    * -------------------------
+    */
+    if (inst->children == NULL) {
+	/*
+	* No content.
+	* TODO: Do we need to put the empty string in ?
+	*/
+	attr = xmlSetNsProp(ctxt->insert, ns, name, (const xmlChar *) "");
+    } else if ((inst->children->next == NULL) && 
+	    ((inst->children->type == XML_TEXT_NODE) ||
+	     (inst->children->type == XML_CDATA_SECTION_NODE)))
+    {
+	xmlNodePtr copyTxt;
+	
+	/*
+	* xmlSetNsProp() will take care of duplicates.
+	*/
+	attr = xmlSetNsProp(ctxt->insert, ns, name, NULL);
+	if (attr == NULL) /* TODO: report error ? */
+	    goto error;
+	/*
+	* This was taken over from xsltCopyText() (transform.c).
+	*/
+	if (ctxt->internalized &&
+	    (ctxt->insert->doc != NULL) &&
+	    (ctxt->insert->doc->dict == ctxt->dict))
+	{
+	    copyTxt = xmlNewText(NULL);
+	    if (copyTxt == NULL) /* TODO: report error */
+		goto error;
+	    /*
+	    * This is a safe scenario where we don't need to lookup
+	    * the dict.
+	    */
+	    copyTxt->content = inst->children->content;
+	    /*
+	    * Copy "disable-output-escaping" information.
+	    * TODO: Does this have any effect for attribute values
+	    *  anyway?
+	    */
+	    if (inst->children->name == xmlStringTextNoenc)
+		copyTxt->name = xmlStringTextNoenc;
+	} else {
+	    /*
+	    * Copy the value.
+	    */
+	    copyTxt = xmlNewText(inst->children->content);
+	    if (copyTxt == NULL) /* TODO: report error */
+		goto error;	    	    
+	}
+	attr->children = attr->last = copyTxt;
+	copyTxt->parent = (xmlNodePtr) attr;
+	copyTxt->doc = attr->doc;
+	/*
+	* Copy "disable-output-escaping" information.
+	* TODO: Does this have any effect for attribute values
+	*  anyway?
+	*/
+	if (inst->children->name == xmlStringTextNoenc)
+	    copyTxt->name = xmlStringTextNoenc;	
+
+        /*
+         * since we create the attribute without content IDness must be
+         * asserted as a second step
+         */
+        if ((copyTxt->content != NULL) &&
+            (xmlIsID(attr->doc, attr->parent, attr)))
+            xmlAddID(NULL, attr->doc, copyTxt->content, attr);
+    } else {
+	/*
+	* The sequence constructor might be complex, so instantiate it.
+	*/
+	value = xsltEvalTemplateString(ctxt, contextNode, inst);
+	if (value != NULL) {
+	    attr = xmlSetNsProp(ctxt->insert, ns, name, value);
+	    xmlFree(value);
+	} else {
+	    /*
+	    * TODO: Do we have to add the empty string to the attr?
+	    * TODO: Does a  value of NULL indicate an
+	    *  error in xsltEvalTemplateString() ?
+	    */
+	    attr = xmlSetNsProp(ctxt->insert, ns, name,
+		(const xmlChar *) "");
+	}
+    }
+
+error:
+    return;    
+}
+
+/**
+ * xsltAttribute:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt attribute node
+ * @comp:  precomputed information
+ *
+ * Process the xslt attribute node on the source node
+ */
+void
+xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	      xmlNodePtr inst, xsltStylePreCompPtr comp) {
+    xsltAttributeInternal(ctxt, node, inst, comp, 0);
+}
+
+/**
+ * xsltApplyAttributeSet:
+ * @ctxt:  the XSLT stylesheet
+ * @node:  the node in the source tree.
+ * @inst:  the attribute node "xsl:use-attribute-sets"
+ * @attrSets:  the list of QNames of the attribute-sets to be applied
+ *
+ * Apply the xsl:use-attribute-sets.
+ * If @attrSets is NULL, then @inst will be used to exctract this
+ * value.
+ * If both, @attrSets and @inst, are NULL, then this will do nothing.
+ */
+void
+xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                      xmlNodePtr inst,
+                      const xmlChar *attrSets)
+{
+    const xmlChar *ncname = NULL;
+    const xmlChar *prefix = NULL;    
+    const xmlChar *curstr, *endstr;
+    xsltAttrElemPtr attrs;
+    xsltStylesheetPtr style;    
+
+    if (attrSets == NULL) {
+	if (inst == NULL)
+	    return;
+	else {
+	    /*
+	    * Extract the value from @inst.
+	    */
+	    if (inst->type == XML_ATTRIBUTE_NODE) {
+		if ( ((xmlAttrPtr) inst)->children != NULL)
+		    attrSets = ((xmlAttrPtr) inst)->children->content;
+		
+	    }
+	    if (attrSets == NULL) {
+		/*
+		* TODO: Return an error?
+		*/
+		return;
+	    }
+	}
+    }
+    /*
+    * Parse/apply the list of QNames.
+    */
+    curstr = attrSets;
+    while (*curstr != 0) {
+        while (IS_BLANK(*curstr))
+            curstr++;
+        if (*curstr == 0)
+            break;
+        endstr = curstr;
+        while ((*endstr != 0) && (!IS_BLANK(*endstr)))
+            endstr++;
+        curstr = xmlDictLookup(ctxt->dict, curstr, endstr - curstr);
+        if (curstr) {
+	    /*
+	    * TODO: Validate the QName.
+	    */
+
+#ifdef WITH_XSLT_DEBUG_curstrUTES
+            xsltGenericDebug(xsltGenericDebugContext,
+                             "apply curstrute set %s\n", curstr);
+#endif
+            ncname = xsltSplitQName(ctxt->dict, curstr, &prefix);
+
+            style = ctxt->style;
+
+#ifdef WITH_DEBUGGER
+            if ((style != NULL) &&
+		(style->attributeSets != NULL) &&
+		(ctxt->debugStatus != XSLT_DEBUG_NONE))
+	    {
+                attrs =
+                    xmlHashLookup2(style->attributeSets, ncname, prefix);
+                if ((attrs != NULL) && (attrs->attr != NULL))
+                    xslHandleDebugger(attrs->attr->parent, node, NULL,
+			ctxt);
+            }
+#endif
+	    /*
+	    * Lookup the referenced curstrute-set.
+	    */
+            while (style != NULL) {
+                attrs =
+                    xmlHashLookup2(style->attributeSets, ncname, prefix);
+                while (attrs != NULL) {
+                    if (attrs->attr != NULL) {
+                        xsltAttributeInternal(ctxt, node, attrs->attr,
+			    attrs->attr->psvi, 1);
+                    }
+                    attrs = attrs->next;
+                }
+                style = xsltNextImport(style);
+            }
+        }
+        curstr = endstr;
+    }
+}
+
+/**
+ * xsltFreeAttributeSetsHashes:
+ * @style: an XSLT stylesheet
+ *
+ * Free up the memory used by attribute sets
+ */
+void
+xsltFreeAttributeSetsHashes(xsltStylesheetPtr style) {
+    if (style->attributeSets != NULL)
+	xmlHashFree((xmlHashTablePtr) style->attributeSets,
+		    (xmlHashDeallocator) xsltFreeAttrElemList);
+    style->attributeSets = NULL;
+}
diff --git a/libxslt/attributes.h b/libxslt/attributes.h
new file mode 100644
index 0000000..d61ebb0
--- /dev/null
+++ b/libxslt/attributes.h
@@ -0,0 +1,38 @@
+/*
+ * Summary: interface for the XSLT attribute handling
+ * Description: this module handles the specificities of attribute
+ *              and attribute groups processing.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_ATTRIBUTES_H__
+#define __XML_XSLT_ATTRIBUTES_H__
+
+#include <libxml/tree.h>
+#include "xsltexports.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+XSLTPUBFUN void XSLTCALL
+	xsltParseStylesheetAttributeSet	(xsltStylesheetPtr style,
+					 xmlNodePtr cur);
+XSLTPUBFUN void XSLTCALL    
+	xsltFreeAttributeSetsHashes	(xsltStylesheetPtr style);
+XSLTPUBFUN void XSLTCALL	
+	xsltApplyAttributeSet		(xsltTransformContextPtr ctxt,
+					 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 const xmlChar *attributes);
+XSLTPUBFUN void XSLTCALL	
+	xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_ATTRIBUTES_H__ */
+
diff --git a/libxslt/attrvt.c b/libxslt/attrvt.c
new file mode 100644
index 0000000..bda0910
--- /dev/null
+++ b/libxslt/attrvt.c
@@ -0,0 +1,387 @@
+/*
+ * attrvt.c: Implementation of the XSL Transformation 1.0 engine
+ *           attribute value template handling part.
+ *
+ * References:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ *   Michael Kay "XSLT Programmer's Reference" pp 637-643
+ *   Writing Multiple Output Files
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include "xslt.h"
+#include "xsltutils.h"
+#include "xsltInternals.h"
+#include "templates.h"
+
+#ifdef WITH_XSLT_DEBUG
+#define WITH_XSLT_DEBUG_AVT
+#endif
+
+#define MAX_AVT_SEG 10
+
+typedef struct _xsltAttrVT xsltAttrVT;
+typedef xsltAttrVT *xsltAttrVTPtr;
+struct _xsltAttrVT {
+    struct _xsltAttrVT *next; /* next xsltAttrVT */
+    int nb_seg;		/* Number of segments */
+    int max_seg;	/* max capacity before re-alloc needed */
+    int strstart;	/* is the start a string */
+    /*
+     * the namespaces in scope
+     */
+    xmlNsPtr *nsList;
+    int nsNr;
+    /*
+     * the content is an alternate of string and xmlXPathCompExprPtr
+     */
+    void *segments[MAX_AVT_SEG];
+};
+
+/**
+ * xsltNewAttrVT:
+ * @style:  a XSLT process context
+ *
+ * Build a new xsltAttrVT structure
+ *
+ * Returns the structure or NULL in case of error
+ */
+static xsltAttrVTPtr
+xsltNewAttrVT(xsltStylesheetPtr style) {
+    xsltAttrVTPtr cur;
+
+    cur = (xsltAttrVTPtr) xmlMalloc(sizeof(xsltAttrVT));
+    if (cur == NULL) {
+	xsltTransformError(NULL, style, NULL,
+		"xsltNewAttrVTPtr : malloc failed\n");
+	if (style != NULL) style->errors++;
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltAttrVT));
+
+    cur->nb_seg = 0;
+    cur->max_seg = MAX_AVT_SEG;
+    cur->strstart = 0;
+    cur->next = style->attVTs;
+    /*
+     * Note: this pointer may be changed by a re-alloc within xsltCompileAttr,
+     * so that code may change the stylesheet pointer also!
+     */
+    style->attVTs = (xsltAttrVTPtr) cur;
+
+    return(cur);
+}
+
+/**
+ * xsltFreeAttrVT:
+ * @avt: pointer to an xsltAttrVT structure
+ *
+ * Free up the memory associated to the attribute value template
+ */
+static void
+xsltFreeAttrVT(xsltAttrVTPtr avt) {
+    int i;
+
+    if (avt == NULL) return;
+
+    if (avt->strstart == 1) {
+	for (i = 0;i < avt->nb_seg; i += 2)
+	    if (avt->segments[i] != NULL)
+		xmlFree((xmlChar *) avt->segments[i]);
+	for (i = 1;i < avt->nb_seg; i += 2)
+	    xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]);
+    } else {
+	for (i = 0;i < avt->nb_seg; i += 2)
+	    xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]);
+	for (i = 1;i < avt->nb_seg; i += 2)
+	    if (avt->segments[i] != NULL)
+		xmlFree((xmlChar *) avt->segments[i]);
+    }
+    if (avt->nsList != NULL)
+        xmlFree(avt->nsList);
+    xmlFree(avt);
+}
+
+/**
+ * xsltFreeAVTList:
+ * @avt: pointer to an list of AVT structures
+ *
+ * Free up the memory associated to the attribute value templates
+ */
+void
+xsltFreeAVTList(void *avt) {
+    xsltAttrVTPtr cur = (xsltAttrVTPtr) avt, next;
+
+    while (cur != NULL) {
+        next = cur->next;
+	xsltFreeAttrVT(cur);
+	cur = next;
+    }
+}
+/**
+ * xsltSetAttrVTsegment:
+ * @ avt: pointer to an xsltAttrVT structure
+ * @ val: the value to be set to the next available segment
+ *
+ * Within xsltCompileAttr there are several places where a value
+ * needs to be added to the 'segments' array within the xsltAttrVT
+ * structure, and at each place the allocated size may have to be
+ * re-allocated.  This routine takes care of that situation.
+ *
+ * Returns the avt pointer, which may have been changed by a re-alloc
+ */
+static xsltAttrVTPtr
+xsltSetAttrVTsegment(xsltAttrVTPtr avt, void *val) {
+    if (avt->nb_seg >= avt->max_seg) {
+	avt = (xsltAttrVTPtr) xmlRealloc(avt, sizeof(xsltAttrVT) +
+	    		avt->max_seg * sizeof(void *));
+	if (avt == NULL) {
+	    return NULL;
+	}
+	memset(&avt->segments[avt->nb_seg], 0, MAX_AVT_SEG*sizeof(void *));
+	avt->max_seg += MAX_AVT_SEG;
+    }
+    avt->segments[avt->nb_seg++] = val;
+    return avt;
+}
+
+/**
+ * xsltCompileAttr:
+ * @style:  a XSLT process context
+ * @attr: the attribute coming from the stylesheet.
+ *
+ * Precompile an attribute in a stylesheet, basically it checks if it is
+ * an attrubute value template, and if yes establish some structures needed
+ * to process it at transformation time.
+ */
+void
+xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) {
+    const xmlChar *str;
+    const xmlChar *cur;
+    xmlChar *ret = NULL;
+    xmlChar *expr = NULL;
+    xsltAttrVTPtr avt;
+    int i = 0, lastavt = 0;
+
+    if ((style == NULL) || (attr == NULL) || (attr->children == NULL))
+        return;
+    if ((attr->children->type != XML_TEXT_NODE) || 
+        (attr->children->next != NULL)) {
+        xsltTransformError(NULL, style, attr->parent,
+	    "Attribute '%s': The content is expected to be a single text "
+	    "node when compiling an AVT.\n", attr->name);
+	style->errors++;
+	return;
+    }
+    str = attr->children->content;
+    if ((xmlStrchr(str, '{') == NULL) &&
+        (xmlStrchr(str, '}') == NULL)) return;
+
+#ifdef WITH_XSLT_DEBUG_AVT
+    xsltGenericDebug(xsltGenericDebugContext,
+		    "Found AVT %s: %s\n", attr->name, str);
+#endif
+    if (attr->psvi != NULL) {
+#ifdef WITH_XSLT_DEBUG_AVT
+	xsltGenericDebug(xsltGenericDebugContext,
+			"AVT %s: already compiled\n", attr->name);
+#endif
+        return;
+    }
+    /*
+    * Create a new AVT object.
+    */
+    avt = xsltNewAttrVT(style);
+    if (avt == NULL)
+	return;
+    attr->psvi = avt;
+
+    avt->nsList = xmlGetNsList(attr->doc, attr->parent);
+    if (avt->nsList != NULL) {
+	while (avt->nsList[i] != NULL)
+	    i++;
+    }
+    avt->nsNr = i;
+
+    cur = str;
+    while (*cur != 0) {
+	if (*cur == '{') {
+	    if (*(cur+1) == '{') {	/* escaped '{' */
+	        cur++;
+		ret = xmlStrncat(ret, str, cur - str);
+		cur++;
+		str = cur;
+		continue;
+	    }
+	    if (*(cur+1) == '}') {	/* skip empty AVT */
+		ret = xmlStrncat(ret, str, cur - str);
+	        cur += 2;
+		str = cur;
+		continue;
+	    }
+	    if ((ret != NULL) || (cur - str > 0)) {
+		ret = xmlStrncat(ret, str, cur - str);
+		str = cur;
+		if (avt->nb_seg == 0)
+		    avt->strstart = 1;
+		if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
+		    goto error;
+		ret = NULL;
+		lastavt = 0;
+	    }
+
+	    cur++;
+	    while ((*cur != 0) && (*cur != '}')) {
+		/* Need to check for literal (bug539741) */
+		if ((*cur == '\'') || (*cur == '"')) {
+		    char delim = *(cur++);
+		    while ((*cur != 0) && (*cur != delim)) 
+			cur++;
+		    if (*cur != 0)
+			cur++;	/* skip the ending delimiter */
+		} else
+		    cur++;
+	    }
+	    if (*cur == 0) {
+	        xsltTransformError(NULL, style, attr->parent,
+		     "Attribute '%s': The AVT has an unmatched '{'.\n",
+		     attr->name);
+		style->errors++;
+		goto error;
+	    }
+	    str++;
+	    expr = xmlStrndup(str, cur - str);
+	    if (expr == NULL) {
+		/*
+		* TODO: What needs to be done here?
+		*/
+	        XSLT_TODO
+		goto error;
+	    } else {
+		xmlXPathCompExprPtr comp;
+
+		comp = xsltXPathCompile(style, expr);
+		if (comp == NULL) {
+		    xsltTransformError(NULL, style, attr->parent,
+			 "Attribute '%s': Failed to compile the expression "
+			 "'%s' in the AVT.\n", attr->name, expr);
+		    style->errors++;
+		    goto error;
+		}
+		if (avt->nb_seg == 0)
+		    avt->strstart = 0;
+		if (lastavt == 1) {
+		    if ((avt = xsltSetAttrVTsegment(avt, NULL)) == NULL)
+		        goto error;
+		}
+		if ((avt = xsltSetAttrVTsegment(avt, (void *) comp)) == NULL)
+		    goto error;
+		lastavt = 1;
+		xmlFree(expr);
+		expr = NULL;
+	    }
+	    cur++;
+	    str = cur;
+	} else if (*cur == '}') {
+	    cur++;
+	    if (*cur == '}') {	/* escaped '}' */
+		ret = xmlStrncat(ret, str, cur - str);
+		cur++;
+		str = cur;
+		continue;
+	    } else {
+	        xsltTransformError(NULL, style, attr->parent,
+		     "Attribute '%s': The AVT has an unmatched '}'.\n",
+		     attr->name);
+		goto error;
+	    }
+	} else
+	    cur++;
+    }
+    if ((ret != NULL) || (cur - str > 0)) {
+	ret = xmlStrncat(ret, str, cur - str);
+	str = cur;
+	if (avt->nb_seg == 0)
+	    avt->strstart = 1;
+	if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
+	    goto error;
+	ret = NULL;
+    }
+
+error:
+    if (avt == NULL) {
+        xsltTransformError(NULL, style, attr->parent,
+		"xsltCompileAttr: malloc problem\n");
+    } else {
+        if (attr->psvi != avt) {  /* may have changed from realloc */
+            attr->psvi = avt;
+	    /*
+	     * This is a "hack", but I can't see any clean method of
+	     * doing it.  If a re-alloc has taken place, then the pointer
+	     * for this AVT may have changed.  style->attVTs was set by
+	     * xsltNewAttrVT, so it needs to be re-set to the new value!
+	     */
+	    style->attVTs = avt;
+	}
+    }
+    if (ret != NULL)
+	xmlFree(ret);
+    if (expr != NULL)
+	xmlFree(expr);
+}
+
+
+/**
+ * xsltEvalAVT:
+ * @ctxt: the XSLT transformation context
+ * @avt: the prevompiled attribute value template info
+ * @node: the node hosting the attribute
+ *
+ * Process the given AVT, and return the new string value.
+ *
+ * Returns the computed string value or NULL, must be deallocated by the
+ *         caller.
+ */
+xmlChar *
+xsltEvalAVT(xsltTransformContextPtr ctxt, void *avt, xmlNodePtr node) {
+    xmlChar *ret = NULL, *tmp;
+    xmlXPathCompExprPtr comp;
+    xsltAttrVTPtr cur = (xsltAttrVTPtr) avt;
+    int i;
+    int str;
+
+    if ((ctxt == NULL) || (avt == NULL) || (node == NULL))
+        return(NULL);
+    str = cur->strstart;
+    for (i = 0;i < cur->nb_seg;i++) {
+        if (str) {
+	    ret = xmlStrcat(ret, (const xmlChar *) cur->segments[i]);
+	} else {
+	    comp = (xmlXPathCompExprPtr) cur->segments[i];
+	    tmp = xsltEvalXPathStringNs(ctxt, comp, cur->nsNr, cur->nsList);
+	    if (tmp != NULL) {
+	        if (ret != NULL) {
+		    ret = xmlStrcat(ret, tmp);
+		    xmlFree(tmp);
+		} else {
+		    ret = tmp;
+		}
+	    }
+	}
+	str = !str;
+    }
+    return(ret);
+}
diff --git a/libxslt/documents.c b/libxslt/documents.c
new file mode 100644
index 0000000..128cefe
--- /dev/null
+++ b/libxslt/documents.c
@@ -0,0 +1,434 @@
+/*
+ * documents.c: Implementation of the documents handling
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/hash.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "documents.h"
+#include "transform.h"
+#include "imports.h"
+#include "keys.h"
+#include "security.h"
+
+#ifdef LIBXML_XINCLUDE_ENABLED
+#include <libxml/xinclude.h>
+#endif
+
+#define WITH_XSLT_DEBUG_DOCUMENTS
+
+#ifdef WITH_XSLT_DEBUG
+#define WITH_XSLT_DEBUG_DOCUMENTS
+#endif
+
+/************************************************************************
+ * 									*
+ * 		Hooks for the document loader				*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltDocDefaultLoaderFunc:
+ * @URI: the URI of the document to load
+ * @dict: the dictionary to use when parsing that document
+ * @options: parsing options, a set of xmlParserOption
+ * @ctxt: the context, either a stylesheet or a transformation context
+ * @type: the xsltLoadType indicating the kind of loading required
+ *
+ * Default function to load document not provided by the compilation or
+ * transformation API themselve, for example when an xsl:import,
+ * xsl:include is found at compilation time or when a document()
+ * call is made at runtime.
+ *
+ * Returns the pointer to the document (which will be modified and
+ * freed by the engine later), or NULL in case of error.
+ */
+static xmlDocPtr
+xsltDocDefaultLoaderFunc(const xmlChar * URI, xmlDictPtr dict, int options,
+                         void *ctxt ATTRIBUTE_UNUSED,
+			 xsltLoadType type ATTRIBUTE_UNUSED)
+{
+    xmlParserCtxtPtr pctxt;
+    xmlParserInputPtr inputStream;
+    xmlDocPtr doc;
+
+    pctxt = xmlNewParserCtxt();
+    if (pctxt == NULL)
+        return(NULL);
+    if ((dict != NULL) && (pctxt->dict != NULL)) {
+        xmlDictFree(pctxt->dict);
+	pctxt->dict = NULL;
+    }
+    if (dict != NULL) {
+	pctxt->dict = dict;
+	xmlDictReference(pctxt->dict);
+#ifdef WITH_XSLT_DEBUG
+	xsltGenericDebug(xsltGenericDebugContext,
+                     "Reusing dictionary for document\n");
+#endif
+    }
+    xmlCtxtUseOptions(pctxt, options);
+    inputStream = xmlLoadExternalEntity((const char *) URI, NULL, pctxt);
+    if (inputStream == NULL) {
+        xmlFreeParserCtxt(pctxt);
+	return(NULL);
+    }
+    inputPush(pctxt, inputStream);
+    if (pctxt->directory == NULL)
+        pctxt->directory = xmlParserGetDirectory((const char *) URI);
+
+    xmlParseDocument(pctxt);
+
+    if (pctxt->wellFormed) {
+        doc = pctxt->myDoc;
+    }
+    else {
+        doc = NULL;
+        xmlFreeDoc(pctxt->myDoc);
+        pctxt->myDoc = NULL;
+    }
+    xmlFreeParserCtxt(pctxt);
+
+    return(doc);
+}
+
+
+xsltDocLoaderFunc xsltDocDefaultLoader = xsltDocDefaultLoaderFunc;
+
+/**
+ * xsltSetLoaderFunc:
+ * @f: the new function to handle document loading.
+ *
+ * Set the new function to load document, if NULL it resets it to the
+ * default function.
+ */
+ 
+void
+xsltSetLoaderFunc(xsltDocLoaderFunc f) {
+    if (f == NULL)
+        xsltDocDefaultLoader = xsltDocDefaultLoaderFunc;
+    else
+        xsltDocDefaultLoader = f;
+}
+
+/************************************************************************
+ *									*
+ *			Module interfaces				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltNewDocument:
+ * @ctxt: an XSLT transformation context (or NULL)
+ * @doc:  a parsed XML document
+ *
+ * Register a new document, apply key computations
+ *
+ * Returns a handler to the document
+ */
+xsltDocumentPtr	
+xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) {
+    xsltDocumentPtr cur;
+
+    cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
+    if (cur == NULL) {
+	xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
+		"xsltNewDocument : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltDocument));
+    cur->doc = doc;
+    if (ctxt != NULL) {
+        if (! XSLT_IS_RES_TREE_FRAG(doc)) {
+	    cur->next = ctxt->docList;
+	    ctxt->docList = cur;
+	}
+	/*
+	* A key with a specific name for a specific document
+	* will only be computed if there's a call to the key()
+	* function using that specific name for that specific
+	* document. I.e. computation of keys will be done in
+	* xsltGetKey() (keys.c) on an on-demand basis.
+	*
+	* xsltInitCtxtKeys(ctxt, cur); not called here anymore
+	*/
+    }
+    return(cur);
+}
+
+/**
+ * xsltNewStyleDocument:
+ * @style: an XSLT style sheet
+ * @doc:  a parsed XML document
+ *
+ * Register a new document, apply key computations
+ *
+ * Returns a handler to the document
+ */
+xsltDocumentPtr	
+xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) {
+    xsltDocumentPtr cur;
+
+    cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
+    if (cur == NULL) {
+	xsltTransformError(NULL, style, (xmlNodePtr) doc,
+		"xsltNewStyleDocument : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltDocument));
+    cur->doc = doc;
+    if (style != NULL) {
+	cur->next = style->docList;
+	style->docList = cur;
+    }
+    return(cur);
+}
+
+/**
+ * xsltFreeStyleDocuments:
+ * @style: an XSLT stylesheet (representing a stylesheet-level)
+ *
+ * Frees the node-trees (and xsltDocument structures) of all
+ * stylesheet-modules of the stylesheet-level represented by
+ * the given @style. 
+ */
+void	
+xsltFreeStyleDocuments(xsltStylesheetPtr style) {
+    xsltDocumentPtr doc, cur;
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+    xsltNsMapPtr nsMap;
+#endif
+    
+    if (style == NULL)
+	return;
+
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+    if (XSLT_HAS_INTERNAL_NSMAP(style))
+	nsMap = XSLT_GET_INTERNAL_NSMAP(style);
+    else
+	nsMap = NULL;    
+#endif   
+
+    cur = style->docList;
+    while (cur != NULL) {
+	doc = cur;
+	cur = cur->next;
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+	/*
+	* Restore all changed namespace URIs of ns-decls.
+	*/
+	if (nsMap)
+	    xsltRestoreDocumentNamespaces(nsMap, doc->doc);
+#endif
+	xsltFreeDocumentKeys(doc);
+	if (!doc->main)
+	    xmlFreeDoc(doc->doc);
+        xmlFree(doc);
+    }
+}
+
+/**
+ * xsltFreeDocuments:
+ * @ctxt: an XSLT transformation context
+ *
+ * Free up all the space used by the loaded documents
+ */
+void	
+xsltFreeDocuments(xsltTransformContextPtr ctxt) {
+    xsltDocumentPtr doc, cur;
+
+    cur = ctxt->docList;
+    while (cur != NULL) {
+	doc = cur;
+	cur = cur->next;
+	xsltFreeDocumentKeys(doc);
+	if (!doc->main)
+	    xmlFreeDoc(doc->doc);
+        xmlFree(doc);
+    }
+    cur = ctxt->styleList;
+    while (cur != NULL) {
+	doc = cur;
+	cur = cur->next;
+	xsltFreeDocumentKeys(doc);
+	if (!doc->main)
+	    xmlFreeDoc(doc->doc);
+        xmlFree(doc);
+    }
+}
+
+/**
+ * xsltLoadDocument:
+ * @ctxt: an XSLT transformation context
+ * @URI:  the computed URI of the document
+ *
+ * Try to load a document (not a stylesheet)
+ * within the XSLT transformation context
+ *
+ * Returns the new xsltDocumentPtr or NULL in case of error
+ */
+xsltDocumentPtr	
+xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {
+    xsltDocumentPtr ret;
+    xmlDocPtr doc;
+
+    if ((ctxt == NULL) || (URI == NULL))
+	return(NULL);
+
+    /*
+     * Security framework check
+     */
+    if (ctxt->sec != NULL) {
+	int res;
+	
+	res = xsltCheckRead(ctxt->sec, ctxt, URI);
+	if (res == 0) {
+	    xsltTransformError(ctxt, NULL, NULL,
+		 "xsltLoadDocument: read rights for %s denied\n",
+			     URI);
+	    return(NULL);
+	}
+    }
+
+    /*
+     * Walk the context list to find the document if preparsed
+     */
+    ret = ctxt->docList;
+    while (ret != NULL) {
+	if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
+	    (xmlStrEqual(ret->doc->URL, URI)))
+	    return(ret);
+	ret = ret->next;
+    }
+
+    doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions,
+                               (void *) ctxt, XSLT_LOAD_DOCUMENT);
+
+    if (doc == NULL)
+	return(NULL);
+
+    if (ctxt->xinclude != 0) {
+#ifdef LIBXML_XINCLUDE_ENABLED
+#if LIBXML_VERSION >= 20603
+	xmlXIncludeProcessFlags(doc, ctxt->parserOptions);
+#else
+	xmlXIncludeProcess(doc);
+#endif
+#else
+	xsltTransformError(ctxt, NULL, NULL,
+	    "xsltLoadDocument(%s) : XInclude processing not compiled in\n",
+	                 URI);
+#endif
+    }
+    /*
+     * Apply white-space stripping if asked for
+     */
+    if (xsltNeedElemSpaceHandling(ctxt))
+	xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
+    if (ctxt->debugStatus == XSLT_DEBUG_NONE)
+	xmlXPathOrderDocElems(doc);
+
+    ret = xsltNewDocument(ctxt, doc);
+    return(ret);
+}
+
+/**
+ * xsltLoadStyleDocument:
+ * @style: an XSLT style sheet
+ * @URI:  the computed URI of the document
+ *
+ * Try to load a stylesheet document within the XSLT transformation context
+ *
+ * Returns the new xsltDocumentPtr or NULL in case of error
+ */
+xsltDocumentPtr	
+xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) {
+    xsltDocumentPtr ret;
+    xmlDocPtr doc;
+    xsltSecurityPrefsPtr sec;
+
+    if ((style == NULL) || (URI == NULL))
+	return(NULL);
+
+    /*
+     * Security framework check
+     */
+    sec = xsltGetDefaultSecurityPrefs();
+    if (sec != NULL) {
+	int res;
+
+	res = xsltCheckRead(sec, NULL, URI);
+	if (res == 0) {
+	    xsltTransformError(NULL, NULL, NULL,
+		 "xsltLoadStyleDocument: read rights for %s denied\n",
+			     URI);
+	    return(NULL);
+	}
+    }
+
+    /*
+     * Walk the context list to find the document if preparsed
+     */
+    ret = style->docList;
+    while (ret != NULL) {
+	if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
+	    (xmlStrEqual(ret->doc->URL, URI)))
+	    return(ret);
+	ret = ret->next;
+    }
+
+    doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,
+                               (void *) style, XSLT_LOAD_STYLESHEET);
+    if (doc == NULL)
+	return(NULL);
+
+    ret = xsltNewStyleDocument(style, doc);
+    return(ret);
+}
+
+/**
+ * xsltFindDocument:
+ * @ctxt: an XSLT transformation context
+ * @doc: a parsed XML document
+ *
+ * Try to find a document within the XSLT transformation context.
+ * This will not find document infos for temporary
+ * Result Tree Fragments.
+ *
+ * Returns the desired xsltDocumentPtr or NULL in case of error
+ */
+xsltDocumentPtr
+xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) {
+    xsltDocumentPtr ret;
+
+    if ((ctxt == NULL) || (doc == NULL))
+	return(NULL);
+
+    /*
+     * Walk the context list to find the document
+     */
+    ret = ctxt->docList;
+    while (ret != NULL) {
+	if (ret->doc == doc)
+	    return(ret);
+	ret = ret->next;
+    }
+    if (doc == ctxt->style->doc)
+	return(ctxt->document);
+    return(NULL);
+}
+
diff --git a/libxslt/documents.h b/libxslt/documents.h
new file mode 100644
index 0000000..2eb1f2a
--- /dev/null
+++ b/libxslt/documents.h
@@ -0,0 +1,93 @@
+/*
+ * Summary: interface for the document handling
+ * Description: implements document loading and cache (multiple
+ *              document() reference for the same resources must
+ *              be equal.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_DOCUMENTS_H__
+#define __XML_XSLT_DOCUMENTS_H__
+
+#include <libxml/tree.h>
+#include "xsltexports.h"
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+XSLTPUBFUN xsltDocumentPtr XSLTCALL	
+		xsltNewDocument		(xsltTransformContextPtr ctxt,
+					 xmlDocPtr doc);
+XSLTPUBFUN xsltDocumentPtr XSLTCALL	
+    		xsltLoadDocument	(xsltTransformContextPtr ctxt,
+					 const xmlChar *URI);
+XSLTPUBFUN xsltDocumentPtr XSLTCALL	
+    		xsltFindDocument	(xsltTransformContextPtr ctxt,
+					 xmlDocPtr doc);
+XSLTPUBFUN void XSLTCALL		
+    		xsltFreeDocuments	(xsltTransformContextPtr ctxt);
+
+XSLTPUBFUN xsltDocumentPtr XSLTCALL	
+    		xsltLoadStyleDocument	(xsltStylesheetPtr style,
+					 const xmlChar *URI);
+XSLTPUBFUN xsltDocumentPtr XSLTCALL	
+    		xsltNewStyleDocument	(xsltStylesheetPtr style,
+					 xmlDocPtr doc);
+XSLTPUBFUN void XSLTCALL		
+    		xsltFreeStyleDocuments	(xsltStylesheetPtr style);
+
+/*
+ * Hooks for document loading
+ */
+
+/**
+ * xsltLoadType:
+ *
+ * Enum defining the kind of loader requirement.
+ */
+typedef enum {
+    XSLT_LOAD_START = 0,	/* loading for a top stylesheet */
+    XSLT_LOAD_STYLESHEET = 1,	/* loading for a stylesheet include/import */
+    XSLT_LOAD_DOCUMENT = 2	/* loading document at transformation time */
+} xsltLoadType;
+
+/**
+ * xsltDocLoaderFunc:
+ * @URI: the URI of the document to load
+ * @dict: the dictionary to use when parsing that document
+ * @options: parsing options, a set of xmlParserOption
+ * @ctxt: the context, either a stylesheet or a transformation context
+ * @type: the xsltLoadType indicating the kind of loading required
+ *
+ * An xsltDocLoaderFunc is a signature for a function which can be
+ * registered to load document not provided by the compilation or
+ * transformation API themselve, for example when an xsl:import,
+ * xsl:include is found at compilation time or when a document()
+ * call is made at runtime.
+ *
+ * Returns the pointer to the document (which will be modified and
+ * freed by the engine later), or NULL in case of error.
+ */
+typedef xmlDocPtr (*xsltDocLoaderFunc)		(const xmlChar *URI,
+						 xmlDictPtr dict,
+						 int options,
+						 void *ctxt,
+						 xsltLoadType type);
+
+XSLTPUBFUN void XSLTCALL
+		xsltSetLoaderFunc		(xsltDocLoaderFunc f);
+
+/* the loader may be needed by extension libraries so it is exported */
+XSLTPUBVAR xsltDocLoaderFunc xsltDocDefaultLoader;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_DOCUMENTS_H__ */
+
diff --git a/libxslt/extensions.c b/libxslt/extensions.c
new file mode 100644
index 0000000..6187b7a
--- /dev/null
+++ b/libxslt/extensions.c
@@ -0,0 +1,2361 @@
+/*
+ * extensions.c: Implemetation of the extensions support
+ *
+ * Reference:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+#include <limits.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/hash.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parserInternals.h>
+#include <libxml/xpathInternals.h>
+#ifdef WITH_MODULES
+#include <libxml/xmlmodule.h>
+#endif
+#include <libxml/list.h>
+#include <libxml/xmlIO.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "imports.h"
+#include "extensions.h"
+
+#ifdef _WIN32
+#include <stdlib.h>             /* for _MAX_PATH */
+#ifndef PATH_MAX
+#define PATH_MAX _MAX_PATH
+#endif
+#endif
+
+#ifdef WITH_XSLT_DEBUG
+#define WITH_XSLT_DEBUG_EXTENSIONS
+#endif
+
+/************************************************************************
+ * 									*
+ * 			Private Types and Globals			*
+ * 									*
+ ************************************************************************/
+
+typedef struct _xsltExtDef xsltExtDef;
+typedef xsltExtDef *xsltExtDefPtr;
+struct _xsltExtDef {
+    struct _xsltExtDef *next;
+    xmlChar *prefix;
+    xmlChar *URI;
+    void *data;
+};
+
+typedef struct _xsltExtModule xsltExtModule;
+typedef xsltExtModule *xsltExtModulePtr;
+struct _xsltExtModule {
+    xsltExtInitFunction initFunc;
+    xsltExtShutdownFunction shutdownFunc;
+    xsltStyleExtInitFunction styleInitFunc;
+    xsltStyleExtShutdownFunction styleShutdownFunc;
+};
+
+typedef struct _xsltExtData xsltExtData;
+typedef xsltExtData *xsltExtDataPtr;
+struct _xsltExtData {
+    xsltExtModulePtr extModule;
+    void *extData;
+};
+
+typedef struct _xsltExtElement xsltExtElement;
+typedef xsltExtElement *xsltExtElementPtr;
+struct _xsltExtElement {
+    xsltPreComputeFunction precomp;
+    xsltTransformFunction transform;
+};
+
+static xmlHashTablePtr xsltExtensionsHash = NULL;
+static xmlHashTablePtr xsltFunctionsHash = NULL;
+static xmlHashTablePtr xsltElementsHash = NULL;
+static xmlHashTablePtr xsltTopLevelsHash = NULL;
+static xmlHashTablePtr xsltModuleHash = NULL;
+static xmlMutexPtr xsltExtMutex = NULL;
+
+/************************************************************************
+ * 									*
+ * 			Type functions 					*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltNewExtDef:
+ * @prefix:  the extension prefix
+ * @URI:  the namespace URI
+ *
+ * Create a new XSLT ExtDef
+ *
+ * Returns the newly allocated xsltExtDefPtr or NULL in case of error
+ */
+static xsltExtDefPtr
+xsltNewExtDef(const xmlChar * prefix, const xmlChar * URI)
+{
+    xsltExtDefPtr cur;
+
+    cur = (xsltExtDefPtr) xmlMalloc(sizeof(xsltExtDef));
+    if (cur == NULL) {
+        xsltTransformError(NULL, NULL, NULL,
+                           "xsltNewExtDef : malloc failed\n");
+        return (NULL);
+    }
+    memset(cur, 0, sizeof(xsltExtDef));
+    if (prefix != NULL)
+        cur->prefix = xmlStrdup(prefix);
+    if (URI != NULL)
+        cur->URI = xmlStrdup(URI);
+    return (cur);
+}
+
+/**
+ * xsltFreeExtDef:
+ * @extensiond:  an XSLT extension definition
+ *
+ * Free up the memory allocated by @extensiond
+ */
+static void
+xsltFreeExtDef(xsltExtDefPtr extensiond)
+{
+    if (extensiond == NULL)
+        return;
+    if (extensiond->prefix != NULL)
+        xmlFree(extensiond->prefix);
+    if (extensiond->URI != NULL)
+        xmlFree(extensiond->URI);
+    xmlFree(extensiond);
+}
+
+/**
+ * xsltFreeExtDefList:
+ * @extensiond:  an XSLT extension definition list
+ *
+ * Free up the memory allocated by all the elements of @extensiond
+ */
+static void
+xsltFreeExtDefList(xsltExtDefPtr extensiond)
+{
+    xsltExtDefPtr cur;
+
+    while (extensiond != NULL) {
+        cur = extensiond;
+        extensiond = extensiond->next;
+        xsltFreeExtDef(cur);
+    }
+}
+
+/**
+ * xsltNewExtModule:
+ * @initFunc:  the module initialization function
+ * @shutdownFunc:  the module shutdown function
+ * @styleInitFunc:  the stylesheet module data allocator function
+ * @styleShutdownFunc:  the stylesheet module data free function
+ *
+ * Create a new XSLT extension module
+ *
+ * Returns the newly allocated xsltExtModulePtr or NULL in case of error
+ */
+static xsltExtModulePtr
+xsltNewExtModule(xsltExtInitFunction initFunc,
+                 xsltExtShutdownFunction shutdownFunc,
+                 xsltStyleExtInitFunction styleInitFunc,
+                 xsltStyleExtShutdownFunction styleShutdownFunc)
+{
+    xsltExtModulePtr cur;
+
+    cur = (xsltExtModulePtr) xmlMalloc(sizeof(xsltExtModule));
+    if (cur == NULL) {
+        xsltTransformError(NULL, NULL, NULL,
+                           "xsltNewExtModule : malloc failed\n");
+        return (NULL);
+    }
+    cur->initFunc = initFunc;
+    cur->shutdownFunc = shutdownFunc;
+    cur->styleInitFunc = styleInitFunc;
+    cur->styleShutdownFunc = styleShutdownFunc;
+    return (cur);
+}
+
+/**
+ * xsltFreeExtModule:
+ * @ext:  an XSLT extension module
+ *
+ * Free up the memory allocated by @ext
+ */
+static void
+xsltFreeExtModule(xsltExtModulePtr ext)
+{
+    if (ext == NULL)
+        return;
+    xmlFree(ext);
+}
+
+/**
+ * xsltNewExtData:
+ * @extModule:  the module
+ * @extData:  the associated data
+ *
+ * Create a new XSLT extension module data wrapper
+ *
+ * Returns the newly allocated xsltExtDataPtr or NULL in case of error
+ */
+static xsltExtDataPtr
+xsltNewExtData(xsltExtModulePtr extModule, void *extData)
+{
+    xsltExtDataPtr cur;
+
+    if (extModule == NULL)
+        return (NULL);
+    cur = (xsltExtDataPtr) xmlMalloc(sizeof(xsltExtData));
+    if (cur == NULL) {
+        xsltTransformError(NULL, NULL, NULL,
+                           "xsltNewExtData : malloc failed\n");
+        return (NULL);
+    }
+    cur->extModule = extModule;
+    cur->extData = extData;
+    return (cur);
+}
+
+/**
+ * xsltFreeExtData:
+ * @ext:  an XSLT extension module data wrapper
+ *
+ * Free up the memory allocated by @ext
+ */
+static void
+xsltFreeExtData(xsltExtDataPtr ext)
+{
+    if (ext == NULL)
+        return;
+    xmlFree(ext);
+}
+
+/**
+ * xsltNewExtElement:
+ * @precomp:  the pre-computation function
+ * @transform:  the transformation function
+ *
+ * Create a new XSLT extension element
+ *
+ * Returns the newly allocated xsltExtElementPtr or NULL in case of
+ * error
+ */
+static xsltExtElementPtr
+xsltNewExtElement(xsltPreComputeFunction precomp,
+                  xsltTransformFunction transform)
+{
+    xsltExtElementPtr cur;
+
+    if (transform == NULL)
+        return (NULL);
+
+    cur = (xsltExtElementPtr) xmlMalloc(sizeof(xsltExtElement));
+    if (cur == NULL) {
+        xsltTransformError(NULL, NULL, NULL,
+                           "xsltNewExtElement : malloc failed\n");
+        return (NULL);
+    }
+    cur->precomp = precomp;
+    cur->transform = transform;
+    return (cur);
+}
+
+/**
+ * xsltFreeExtElement:
+ * @ext: an XSLT extension element
+ *
+ * Frees up the memory allocated by @ext
+ */
+static void
+xsltFreeExtElement(xsltExtElementPtr ext)
+{
+    if (ext == NULL)
+        return;
+    xmlFree(ext);
+}
+
+
+#ifdef WITH_MODULES
+typedef void (*exsltRegisterFunction) (void);
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+/**
+ * xsltExtModuleRegisterDynamic:
+ * @URI:  the function or element namespace URI
+ *
+ * Dynamically loads an extension plugin when available.
+ * 
+ * The plugin name is derived from the URI by removing the 
+ * initial protocol designation, e.g. "http://", then converting
+ * the characters ".", "-", "/", and "\" into "_", the removing
+ * any trailing "/", then concatenating LIBXML_MODULE_EXTENSION.
+ * 
+ * Plugins are loaded from the directory specified by the 
+ * environment variable LIBXSLT_PLUGINS_PATH, or if NULL, 
+ * by LIBXSLT_DEFAULT_PLUGINS_PATH() which is determined at
+ * compile time.
+ *
+ * Returns 0 if successful, -1 in case of error. 
+ */
+
+static int
+xsltExtModuleRegisterDynamic(const xmlChar * URI)
+{
+
+    xmlModulePtr m;
+    exsltRegisterFunction regfunc;
+    xmlChar *ext_name;
+    char module_filename[PATH_MAX];
+    const xmlChar *ext_directory = NULL;
+    const xmlChar *protocol = NULL;
+    xmlChar *i, *regfunc_name;
+    void *vregfunc;
+    int rc;
+
+    /* check for bad inputs */
+    if (URI == NULL)
+        return (-1);
+
+    if (NULL == xsltModuleHash) {
+        xsltModuleHash = xmlHashCreate(5);
+        if (xsltModuleHash == NULL)
+            return (-1);
+    }
+
+    xmlMutexLock(xsltExtMutex);
+
+    /* have we attempted to register this module already? */
+    if (xmlHashLookup(xsltModuleHash, URI) != NULL) {
+        xmlMutexUnlock(xsltExtMutex);
+        return (-1);
+    }
+    xmlMutexUnlock(xsltExtMutex);
+
+    /* transform extension namespace into a module name */
+    protocol = xmlStrstr(URI, BAD_CAST "://");
+    if (protocol == NULL) {
+        ext_name = xmlStrdup(URI);
+    } else {
+        ext_name = xmlStrdup(protocol + 3);
+    }
+    if (ext_name == NULL) {
+        return (-1);
+    }
+
+    i = ext_name;
+    while ('\0' != *i) {
+        if (('/' == *i) || ('\\' == *i) || ('.' == *i) || ('-' == *i))
+            *i = '_';
+        i++;
+    }
+
+    if (*(i - 1) == '_')
+        *i = '\0';
+
+    /* determine module directory */
+    ext_directory = (xmlChar *) getenv("LIBXSLT_PLUGINS_PATH");
+
+    if (NULL == ext_directory) {
+        ext_directory = BAD_CAST LIBXSLT_DEFAULT_PLUGINS_PATH();
+	if (NULL == ext_directory)
+	  return (-1);
+    }
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+    else
+      xsltGenericDebug(xsltGenericDebugContext,
+		       "LIBXSLT_PLUGINS_PATH is %s\n", ext_directory);
+#endif
+
+    /* build the module filename, and confirm the module exists */
+    xmlStrPrintf((xmlChar *) module_filename, sizeof(module_filename),
+                 BAD_CAST "%s/%s%s",
+                 ext_directory, ext_name, LIBXML_MODULE_EXTENSION);
+
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "Attempting to load plugin: %s for URI: %s\n", 
+                     module_filename, URI);
+#endif
+
+    if (1 != xmlCheckFilename(module_filename)) {
+
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+	xsltGenericDebug(xsltGenericDebugContext,
+                     "xmlCheckFilename failed for plugin: %s\n", module_filename);
+#endif
+
+        xmlFree(ext_name);
+        return (-1);
+    }
+
+    /* attempt to open the module */
+    m = xmlModuleOpen(module_filename, 0);
+    if (NULL == m) {
+
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+	xsltGenericDebug(xsltGenericDebugContext,
+                     "xmlModuleOpen failed for plugin: %s\n", module_filename);
+#endif
+
+        xmlFree(ext_name);
+        return (-1);
+    }
+
+    /* construct initialization func name */
+    regfunc_name = xmlStrdup(ext_name);
+    regfunc_name = xmlStrcat(regfunc_name, BAD_CAST "_init");
+
+    vregfunc = NULL;
+    rc = xmlModuleSymbol(m, (const char *) regfunc_name, &vregfunc);
+    regfunc = vregfunc;
+    if (0 == rc) {
+        /*
+	 * Call the module's init function.  Note that this function
+	 * calls xsltRegisterExtModuleFull which will add the module
+	 * to xsltExtensionsHash (together with it's entry points).
+	 */
+        (*regfunc) ();
+
+        /* register this module in our hash */
+        xmlMutexLock(xsltExtMutex);
+        xmlHashAddEntry(xsltModuleHash, URI, (void *) m);
+        xmlMutexUnlock(xsltExtMutex);
+    } else {
+
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+	xsltGenericDebug(xsltGenericDebugContext,
+                     "xmlModuleSymbol failed for plugin: %s, regfunc: %s\n", 
+                     module_filename, regfunc_name);
+#endif
+
+        /* if regfunc not found unload the module immediately */
+        xmlModuleClose(m);
+    }
+
+    xmlFree(ext_name);
+    xmlFree(regfunc_name);
+    return (NULL == regfunc) ? -1 : 0;
+}
+#else
+static int
+xsltExtModuleRegisterDynamic(const xmlChar * URI ATTRIBUTE_UNUSED)
+{
+  return -1;
+}
+#endif
+
+/************************************************************************
+ * 									*
+ * 		The stylesheet extension prefixes handling		*
+ * 									*
+ ************************************************************************/
+
+
+/**
+ * xsltFreeExts:
+ * @style: an XSLT stylesheet
+ *
+ * Free up the memory used by XSLT extensions in a stylesheet
+ */
+void
+xsltFreeExts(xsltStylesheetPtr style)
+{
+    if (style->nsDefs != NULL)
+        xsltFreeExtDefList((xsltExtDefPtr) style->nsDefs);
+}
+
+/**
+ * xsltRegisterExtPrefix:
+ * @style: an XSLT stylesheet
+ * @prefix: the prefix used (optional)
+ * @URI: the URI associated to the extension
+ * 
+ * Registers an extension namespace
+ * This is called from xslt.c during compile-time.
+ * The given prefix is not needed.
+ * Called by:
+ *   xsltParseExtElemPrefixes() (new function)
+ *   xsltRegisterExtPrefix() (old function)
+ *
+ * Returns 0 in case of success, 1 if the @URI was already
+ *         registered as an extension namespace and
+ *         -1 in case of failure
+ */
+int
+xsltRegisterExtPrefix(xsltStylesheetPtr style,
+                      const xmlChar * prefix, const xmlChar * URI)
+{
+    xsltExtDefPtr def, ret;
+
+    if ((style == NULL) || (URI == NULL))
+        return (-1);
+
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+    xsltGenericDebug(xsltGenericDebugContext,
+	"Registering extension namespace '%s'.\n", URI);
+#endif
+    def = (xsltExtDefPtr) style->nsDefs;
+#ifdef XSLT_REFACTORED
+    /*
+    * The extension is associated with a namespace name.
+    */
+    while (def != NULL) {
+        if (xmlStrEqual(URI, def->URI))
+            return (1);
+        def = def->next;
+    }
+#else
+    while (def != NULL) {
+        if (xmlStrEqual(prefix, def->prefix))
+            return (-1);
+        def = def->next;
+    }
+#endif
+    ret = xsltNewExtDef(prefix, URI);
+    if (ret == NULL)
+        return (-1);
+    ret->next = (xsltExtDefPtr) style->nsDefs;
+    style->nsDefs = ret;
+
+    /*
+     * check whether there is an extension module with a stylesheet
+     * initialization function.
+     */
+#ifdef XSLT_REFACTORED
+    /*
+    * Don't initialize modules based on specified namespaces via
+    * the attribute "[xsl:]extension-element-prefixes".
+    */
+#else
+    if (xsltExtensionsHash != NULL) {
+        xsltExtModulePtr module;
+
+        xmlMutexLock(xsltExtMutex);
+        module = xmlHashLookup(xsltExtensionsHash, URI);
+        xmlMutexUnlock(xsltExtMutex);
+        if (NULL == module) {
+            if (!xsltExtModuleRegisterDynamic(URI)) {
+                xmlMutexLock(xsltExtMutex);
+                module = xmlHashLookup(xsltExtensionsHash, URI);
+                xmlMutexUnlock(xsltExtMutex);
+            }
+        }
+        if (module != NULL) {
+            xsltStyleGetExtData(style, URI);
+        }
+    }
+#endif
+    return (0);
+}
+
+/************************************************************************
+ * 									*
+ * 		The extensions modules interfaces			*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltRegisterExtFunction:
+ * @ctxt: an XSLT transformation context
+ * @name: the name of the element
+ * @URI: the URI associated to the element
+ * @function: the actual implementation which should be called 
+ *
+ * Registers an extension function
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+int
+xsltRegisterExtFunction(xsltTransformContextPtr ctxt, const xmlChar * name,
+                        const xmlChar * URI, xmlXPathFunction function)
+{
+    int ret;
+
+    if ((ctxt == NULL) || (name == NULL) ||
+        (URI == NULL) || (function == NULL))
+        return (-1);
+    if (ctxt->xpathCtxt != NULL) {
+        xmlXPathRegisterFuncNS(ctxt->xpathCtxt, name, URI, function);
+    }
+    if (ctxt->extFunctions == NULL)
+        ctxt->extFunctions = xmlHashCreate(10);
+    if (ctxt->extFunctions == NULL)
+        return (-1);
+
+    ret = xmlHashAddEntry2(ctxt->extFunctions, name, URI,
+                           XML_CAST_FPTR(function));
+
+    return(ret);
+}
+
+/**
+ * xsltRegisterExtElement:
+ * @ctxt: an XSLT transformation context
+ * @name: the name of the element
+ * @URI: the URI associated to the element
+ * @function: the actual implementation which should be called 
+ *
+ * Registers an extension element
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+int
+xsltRegisterExtElement(xsltTransformContextPtr ctxt, const xmlChar * name,
+                       const xmlChar * URI, xsltTransformFunction function)
+{
+    if ((ctxt == NULL) || (name == NULL) ||
+        (URI == NULL) || (function == NULL))
+        return (-1);
+    if (ctxt->extElements == NULL)
+        ctxt->extElements = xmlHashCreate(10);
+    if (ctxt->extElements == NULL)
+        return (-1);
+    return (xmlHashAddEntry2
+            (ctxt->extElements, name, URI, XML_CAST_FPTR(function)));
+}
+
+/**
+ * xsltFreeCtxtExts:
+ * @ctxt: an XSLT transformation context
+ *
+ * Free the XSLT extension data
+ */
+void
+xsltFreeCtxtExts(xsltTransformContextPtr ctxt)
+{
+    if (ctxt->extElements != NULL)
+        xmlHashFree(ctxt->extElements, NULL);
+    if (ctxt->extFunctions != NULL)
+        xmlHashFree(ctxt->extFunctions, NULL);
+}
+
+/**
+ * xsltStyleGetStylesheetExtData:
+ * @style: an XSLT stylesheet
+ * @URI:  the URI associated to the exension module
+ *
+ * Fires the compile-time initialization callback
+ * of an extension module and returns a container
+ * holding the user-data (retrieved via the callback).
+ *
+ * Returns the create module-data container
+ *         or NULL if such a module was not registered.
+ */
+static xsltExtDataPtr
+xsltStyleInitializeStylesheetModule(xsltStylesheetPtr style,
+				     const xmlChar * URI)
+{
+    xsltExtDataPtr dataContainer;
+    void *userData = NULL;
+    xsltExtModulePtr module;
+    
+    if ((style == NULL) || (URI == NULL))	
+	return(NULL);
+
+    if (xsltExtensionsHash == NULL) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+	xsltGenericDebug(xsltGenericDebugContext,
+	    "Not registered extension module: %s\n", URI);
+#endif
+	return(NULL);
+    }
+
+    xmlMutexLock(xsltExtMutex);
+
+    module = xmlHashLookup(xsltExtensionsHash, URI);
+
+    xmlMutexUnlock(xsltExtMutex);
+
+    if (module == NULL) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+	xsltGenericDebug(xsltGenericDebugContext,
+	    "Not registered extension module: %s\n", URI);
+#endif
+	return (NULL);
+    }
+    /*
+    * The specified module was registered so initialize it.
+    */
+    if (style->extInfos == NULL) {
+	style->extInfos = xmlHashCreate(10);
+	if (style->extInfos == NULL)
+	    return (NULL);
+    }
+    /*
+    * Fire the initialization callback if available.
+    */
+    if (module->styleInitFunc == NULL) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+	xsltGenericDebug(xsltGenericDebugContext,
+	    "Initializing module with *no* callback: %s\n", URI);
+#endif
+    } else {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+	xsltGenericDebug(xsltGenericDebugContext,
+	    "Initializing module with callback: %s\n", URI);
+#endif
+	/*
+	* Fire the initialization callback.
+	*/
+	userData = module->styleInitFunc(style, URI);
+    }    
+    /*
+    * Store the user-data in the context of the given stylesheet.
+    */
+    dataContainer = xsltNewExtData(module, userData);
+    if (dataContainer == NULL)
+	return (NULL);
+
+    if (xmlHashAddEntry(style->extInfos, URI,
+	(void *) dataContainer) < 0)
+    {
+	xsltTransformError(NULL, style, NULL,	    
+	    "Failed to register module '%s'.\n", URI);
+	style->errors++;
+	if (module->styleShutdownFunc)
+	    module->styleShutdownFunc(style, URI, userData);
+	xsltFreeExtData(dataContainer);
+	return (NULL);
+    }
+
+    return(dataContainer);
+}
+
+/**
+ * xsltStyleGetExtData:
+ * @style: an XSLT stylesheet
+ * @URI:  the URI associated to the exension module
+ *
+ * Retrieve the data associated to the extension module
+ * in this given stylesheet.
+ * Called by:
+ *   xsltRegisterExtPrefix(),
+ *   ( xsltExtElementPreCompTest(), xsltExtInitTest )
+ *
+ * Returns the pointer or NULL if not present
+ */
+void *
+xsltStyleGetExtData(xsltStylesheetPtr style, const xmlChar * URI)
+{
+    xsltExtDataPtr dataContainer = NULL;
+    xsltStylesheetPtr tmpStyle;
+
+    if ((style == NULL) || (URI == NULL) ||
+	(xsltExtensionsHash == NULL))
+	return (NULL);
+
+    
+#ifdef XSLT_REFACTORED
+    /*
+    * This is intended for global storage, so only the main
+    * stylesheet will hold the data.
+    */
+    tmpStyle = style;
+    while (tmpStyle->parent != NULL)
+	tmpStyle = tmpStyle->parent;
+    if (tmpStyle->extInfos != NULL) {
+	dataContainer =
+	    (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI);
+	if (dataContainer != NULL) {
+	    /*
+	    * The module was already initialized in the context
+	    * of this stylesheet; just return the user-data that
+	    * comes with it.
+	    */
+	    return(dataContainer->extData);
+	}
+    }
+#else
+    /*
+    * Old behaviour.
+    */
+    tmpStyle = style;
+    while (tmpStyle != NULL) {
+	if (tmpStyle->extInfos != NULL) {
+	    dataContainer =
+		(xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI);
+	    if (dataContainer != NULL) {
+		return(dataContainer->extData);
+	    }
+	}
+	tmpStyle = xsltNextImport(tmpStyle);
+    }
+    tmpStyle = style;
+#endif
+
+    dataContainer =
+        xsltStyleInitializeStylesheetModule(tmpStyle, URI);
+    if (dataContainer != NULL)
+	return (dataContainer->extData);
+    return(NULL);
+}
+
+#ifdef XSLT_REFACTORED
+/**
+ * xsltStyleStylesheetLevelGetExtData:
+ * @style: an XSLT stylesheet
+ * @URI:  the URI associated to the exension module
+ *
+ * Retrieve the data associated to the extension module in this given
+ * stylesheet.
+ *
+ * Returns the pointer or NULL if not present
+ */
+void *
+xsltStyleStylesheetLevelGetExtData(xsltStylesheetPtr style,
+				   const xmlChar * URI)
+{
+    xsltExtDataPtr dataContainer = NULL;
+
+    if ((style == NULL) || (URI == NULL) ||
+	(xsltExtensionsHash == NULL))
+	return (NULL);
+
+    if (style->extInfos != NULL) {
+	dataContainer = (xsltExtDataPtr) xmlHashLookup(style->extInfos, URI);
+	/*
+	* The module was already initialized in the context
+	* of this stylesheet; just return the user-data that
+	* comes with it.
+	*/
+	if (dataContainer)
+	    return(dataContainer->extData);
+    }  
+
+    dataContainer =
+        xsltStyleInitializeStylesheetModule(style, URI);
+    if (dataContainer != NULL)
+	return (dataContainer->extData);
+    return(NULL);
+}
+#endif
+
+/**
+ * xsltGetExtData:
+ * @ctxt: an XSLT transformation context
+ * @URI:  the URI associated to the exension module
+ *
+ * Retrieve the data associated to the extension module in this given
+ * transformation.
+ *
+ * Returns the pointer or NULL if not present
+ */
+void *
+xsltGetExtData(xsltTransformContextPtr ctxt, const xmlChar * URI)
+{
+    xsltExtDataPtr data;
+
+    if ((ctxt == NULL) || (URI == NULL))
+        return (NULL);
+    if (ctxt->extInfos == NULL) {
+        ctxt->extInfos = xmlHashCreate(10);
+        if (ctxt->extInfos == NULL)
+            return (NULL);
+        data = NULL;
+    } else {
+        data = (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos, URI);
+    }
+    if (data == NULL) {
+        void *extData;
+        xsltExtModulePtr module;
+
+        xmlMutexLock(xsltExtMutex);
+
+        module = xmlHashLookup(xsltExtensionsHash, URI);
+
+        xmlMutexUnlock(xsltExtMutex);
+
+        if (module == NULL) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+            xsltGenericDebug(xsltGenericDebugContext,
+                             "Not registered extension module: %s\n", URI);
+#endif
+            return (NULL);
+        } else {
+            if (module->initFunc == NULL)
+                return (NULL);
+
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+            xsltGenericDebug(xsltGenericDebugContext,
+                             "Initializing module: %s\n", URI);
+#endif
+
+            extData = module->initFunc(ctxt, URI);
+            if (extData == NULL)
+                return (NULL);
+
+            data = xsltNewExtData(module, extData);
+            if (data == NULL)
+                return (NULL);
+            if (xmlHashAddEntry(ctxt->extInfos, URI, (void *) data) < 0) {
+                xsltTransformError(ctxt, NULL, NULL,
+                                   "Failed to register module data: %s\n",
+                                   URI);
+                if (module->shutdownFunc)
+                    module->shutdownFunc(ctxt, URI, extData);
+                xsltFreeExtData(data);
+                return (NULL);
+            }
+        }
+    }
+    return (data->extData);
+}
+
+typedef struct _xsltInitExtCtxt xsltInitExtCtxt;
+struct _xsltInitExtCtxt {
+    xsltTransformContextPtr ctxt;
+    int ret;
+};
+
+/**
+ * xsltInitCtxtExt:
+ * @styleData:  the registered stylesheet data for the module
+ * @ctxt:  the XSLT transformation context + the return value
+ * @URI:  the extension URI
+ *
+ * Initializes an extension module
+ */
+static void
+xsltInitCtxtExt(xsltExtDataPtr styleData, xsltInitExtCtxt * ctxt,
+                const xmlChar * URI)
+{
+    xsltExtModulePtr module;
+    xsltExtDataPtr ctxtData;
+    void *extData;
+
+    if ((styleData == NULL) || (ctxt == NULL) || (URI == NULL) ||
+        (ctxt->ret == -1)) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+        xsltGenericDebug(xsltGenericDebugContext,
+                         "xsltInitCtxtExt: NULL param or error\n");
+#endif
+        return;
+    }
+    module = styleData->extModule;
+    if ((module == NULL) || (module->initFunc == NULL)) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+        xsltGenericDebug(xsltGenericDebugContext,
+                         "xsltInitCtxtExt: no module or no initFunc\n");
+#endif
+        return;
+    }
+
+    ctxtData = (xsltExtDataPtr) xmlHashLookup(ctxt->ctxt->extInfos, URI);
+    if (ctxtData != NULL) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+        xsltGenericDebug(xsltGenericDebugContext,
+                         "xsltInitCtxtExt: already initialized\n");
+#endif
+        return;
+    }
+
+    extData = module->initFunc(ctxt->ctxt, URI);
+    if (extData == NULL) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+        xsltGenericDebug(xsltGenericDebugContext,
+                         "xsltInitCtxtExt: no extData\n");
+#endif
+    }
+    ctxtData = xsltNewExtData(module, extData);
+    if (ctxtData == NULL) {
+        ctxt->ret = -1;
+        return;
+    }
+
+    if (ctxt->ctxt->extInfos == NULL)
+        ctxt->ctxt->extInfos = xmlHashCreate(10);
+    if (ctxt->ctxt->extInfos == NULL) {
+        ctxt->ret = -1;
+        return;
+    }
+
+    if (xmlHashAddEntry(ctxt->ctxt->extInfos, URI, ctxtData) < 0) {
+        xsltGenericError(xsltGenericErrorContext,
+                         "Failed to register module data: %s\n", URI);
+        if (module->shutdownFunc)
+            module->shutdownFunc(ctxt->ctxt, URI, extData);
+        xsltFreeExtData(ctxtData);
+        ctxt->ret = -1;
+        return;
+    }
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+    xsltGenericDebug(xsltGenericDebugContext, "Registered module %s\n",
+                     URI);
+#endif
+    ctxt->ret++;
+}
+
+/**
+ * xsltInitCtxtExts:
+ * @ctxt: an XSLT transformation context
+ *
+ * Initialize the set of modules with registered stylesheet data
+ *
+ * Returns the number of modules initialized or -1 in case of error
+ */
+int
+xsltInitCtxtExts(xsltTransformContextPtr ctxt)
+{
+    xsltStylesheetPtr style;
+    xsltInitExtCtxt ctx;
+
+    if (ctxt == NULL)
+        return (-1);
+
+    style = ctxt->style;
+    if (style == NULL)
+        return (-1);
+
+    ctx.ctxt = ctxt;
+    ctx.ret = 0;
+
+    while (style != NULL) {
+        if (style->extInfos != NULL) {
+            xmlHashScan(style->extInfos,
+                        (xmlHashScanner) xsltInitCtxtExt, &ctx);
+            if (ctx.ret == -1)
+                return (-1);
+        }
+        style = xsltNextImport(style);
+    }
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+    xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n",
+                     ctx.ret);
+#endif
+    return (ctx.ret);
+}
+
+/**
+ * xsltShutdownCtxtExt:
+ * @data:  the registered data for the module
+ * @ctxt:  the XSLT transformation context
+ * @URI:  the extension URI
+ *
+ * Shutdown an extension module loaded
+ */
+static void
+xsltShutdownCtxtExt(xsltExtDataPtr data, xsltTransformContextPtr ctxt,
+                    const xmlChar * URI)
+{
+    xsltExtModulePtr module;
+
+    if ((data == NULL) || (ctxt == NULL) || (URI == NULL))
+        return;
+    module = data->extModule;
+    if ((module == NULL) || (module->shutdownFunc == NULL))
+        return;
+
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "Shutting down module : %s\n", URI);
+#endif
+    module->shutdownFunc(ctxt, URI, data->extData);
+}
+
+/**
+ * xsltShutdownCtxtExts:
+ * @ctxt: an XSLT transformation context
+ *
+ * Shutdown the set of modules loaded
+ */
+void
+xsltShutdownCtxtExts(xsltTransformContextPtr ctxt)
+{
+    if (ctxt == NULL)
+        return;
+    if (ctxt->extInfos == NULL)
+        return;
+    xmlHashScan(ctxt->extInfos, (xmlHashScanner) xsltShutdownCtxtExt,
+                ctxt);
+    xmlHashFree(ctxt->extInfos, (xmlHashDeallocator) xsltFreeExtData);
+    ctxt->extInfos = NULL;
+}
+
+/**
+ * xsltShutdownExt:
+ * @data:  the registered data for the module
+ * @ctxt:  the XSLT stylesheet
+ * @URI:  the extension URI
+ *
+ * Shutdown an extension module loaded
+ */
+static void
+xsltShutdownExt(xsltExtDataPtr data, xsltStylesheetPtr style,
+                const xmlChar * URI)
+{
+    xsltExtModulePtr module;
+
+    if ((data == NULL) || (style == NULL) || (URI == NULL))
+        return;
+    module = data->extModule;
+    if ((module == NULL) || (module->styleShutdownFunc == NULL))
+        return;
+
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "Shutting down module : %s\n", URI);
+#endif
+    module->styleShutdownFunc(style, URI, data->extData);
+    /*
+    * Don't remove the entry from the hash table here, since
+    * this will produce segfaults - this fixes bug #340624.
+    *
+    * xmlHashRemoveEntry(style->extInfos, URI,
+    *   (xmlHashDeallocator) xsltFreeExtData);
+    */    
+}
+
+/**
+ * xsltShutdownExts:
+ * @style: an XSLT stylesheet
+ *
+ * Shutdown the set of modules loaded
+ */
+void
+xsltShutdownExts(xsltStylesheetPtr style)
+{
+    if (style == NULL)
+        return;
+    if (style->extInfos == NULL)
+        return;
+    xmlHashScan(style->extInfos, (xmlHashScanner) xsltShutdownExt, style);
+    xmlHashFree(style->extInfos, (xmlHashDeallocator) xsltFreeExtData);
+    style->extInfos = NULL;
+}
+
+/**
+ * xsltCheckExtPrefix:
+ * @style: the stylesheet
+ * @URI: the namespace prefix (possibly NULL)
+ *
+ * Check if the given prefix is one of the declared extensions.
+ * This is intended to be called only at compile-time.
+ * Called by:
+ *  xsltGetInheritedNsList() (xslt.c)
+ *  xsltParseTemplateContent (xslt.c)
+ *
+ * Returns 1 if this is an extension, 0 otherwise
+ */
+int
+xsltCheckExtPrefix(xsltStylesheetPtr style, const xmlChar * URI)
+{    
+#ifdef XSLT_REFACTORED
+    if ((style == NULL) || (style->compCtxt == NULL) ||
+	(XSLT_CCTXT(style)->inode == NULL) ||
+	(XSLT_CCTXT(style)->inode->extElemNs == NULL))
+        return (0);    
+    /*
+    * Lookup the extension namespaces registered
+    * at the current node in the stylesheet's tree.
+    */
+    if (XSLT_CCTXT(style)->inode->extElemNs != NULL) {
+	int i;
+	xsltPointerListPtr list = XSLT_CCTXT(style)->inode->extElemNs;
+
+	for (i = 0; i < list->number; i++) {
+	    if (xmlStrEqual((const xmlChar *) list->items[i],
+		URI))
+	    {
+		return(1);
+	    }	    
+	}
+    }
+#else
+    xsltExtDefPtr cur;
+
+    if ((style == NULL) || (style->nsDefs == NULL))
+        return (0);
+    if (URI == NULL)
+        URI = BAD_CAST "#default";
+    cur = (xsltExtDefPtr) style->nsDefs;
+    while (cur != NULL) {
+	/*
+	* NOTE: This was change to work on namespace names rather
+	* than namespace prefixes. This fixes bug #339583.
+	* TODO: Consider renaming the field "prefix" of xsltExtDef
+	*  to "href".
+	*/
+        if (xmlStrEqual(URI, cur->prefix))
+            return (1);
+        cur = cur->next;
+    }
+#endif
+    return (0);
+}
+
+/**
+ * xsltCheckExtURI:
+ * @style: the stylesheet
+ * @URI: the namespace URI (possibly NULL)
+ *
+ * Check if the given prefix is one of the declared extensions.
+ * This is intended to be called only at compile-time.
+ * Called by:
+ *  xsltPrecomputeStylesheet() (xslt.c)
+ *  xsltParseTemplateContent (xslt.c)
+ *
+ * Returns 1 if this is an extension, 0 otherwise
+ */
+int
+xsltCheckExtURI(xsltStylesheetPtr style, const xmlChar * URI)
+{
+    xsltExtDefPtr cur;
+
+    if ((style == NULL) || (style->nsDefs == NULL))
+        return (0);
+    if (URI == NULL)
+        return (0);
+    cur = (xsltExtDefPtr) style->nsDefs;
+    while (cur != NULL) {
+        if (xmlStrEqual(URI, cur->URI))
+            return (1);
+        cur = cur->next;
+    }
+    return (0);
+}
+
+/**
+ * xsltRegisterExtModuleFull:
+ * @URI:  URI associated to this module
+ * @initFunc:  the module initialization function
+ * @shutdownFunc:  the module shutdown function
+ * @styleInitFunc:  the module initialization function
+ * @styleShutdownFunc:  the module shutdown function
+ *
+ * Register an XSLT extension module to the library.
+ *
+ * Returns 0 if sucessful, -1 in case of error
+ */
+int
+xsltRegisterExtModuleFull(const xmlChar * URI,
+                          xsltExtInitFunction initFunc,
+                          xsltExtShutdownFunction shutdownFunc,
+                          xsltStyleExtInitFunction styleInitFunc,
+                          xsltStyleExtShutdownFunction styleShutdownFunc)
+{
+    int ret;
+    xsltExtModulePtr module;
+
+    if ((URI == NULL) || (initFunc == NULL))
+        return (-1);
+    if (xsltExtensionsHash == NULL)
+        xsltExtensionsHash = xmlHashCreate(10);
+
+    if (xsltExtensionsHash == NULL)
+        return (-1);
+
+    xmlMutexLock(xsltExtMutex);
+
+    module = xmlHashLookup(xsltExtensionsHash, URI);
+    if (module != NULL) {
+        if ((module->initFunc == initFunc) &&
+            (module->shutdownFunc == shutdownFunc))
+            ret = 0;
+        else
+            ret = -1;
+        goto done;
+    }
+    module = xsltNewExtModule(initFunc, shutdownFunc,
+                              styleInitFunc, styleShutdownFunc);
+    if (module == NULL) {
+        ret = -1;
+        goto done;
+    }
+    ret = xmlHashAddEntry(xsltExtensionsHash, URI, (void *) module);
+
+done:
+    xmlMutexUnlock(xsltExtMutex);
+    return (ret);
+}
+
+/**
+ * xsltRegisterExtModule:
+ * @URI:  URI associated to this module
+ * @initFunc:  the module initialization function
+ * @shutdownFunc:  the module shutdown function
+ *
+ * Register an XSLT extension module to the library.
+ *
+ * Returns 0 if sucessful, -1 in case of error
+ */
+int
+xsltRegisterExtModule(const xmlChar * URI,
+                      xsltExtInitFunction initFunc,
+                      xsltExtShutdownFunction shutdownFunc)
+{
+    return xsltRegisterExtModuleFull(URI, initFunc, shutdownFunc,
+                                     NULL, NULL);
+}
+
+/**
+ * xsltUnregisterExtModule:
+ * @URI:  URI associated to this module
+ *
+ * Unregister an XSLT extension module from the library.
+ *
+ * Returns 0 if sucessful, -1 in case of error
+ */
+int
+xsltUnregisterExtModule(const xmlChar * URI)
+{
+    int ret;
+
+    if (URI == NULL)
+        return (-1);
+    if (xsltExtensionsHash == NULL)
+        return (-1);
+
+    xmlMutexLock(xsltExtMutex);
+
+    ret = xmlHashRemoveEntry(xsltExtensionsHash, URI,
+                             (xmlHashDeallocator) xsltFreeExtModule);
+
+    xmlMutexUnlock(xsltExtMutex);
+
+    return (ret);
+}
+
+/**
+ * xsltUnregisterAllExtModules:
+ *
+ * Unregister all the XSLT extension module from the library.
+ */
+static void
+xsltUnregisterAllExtModules(void)
+{
+    if (xsltExtensionsHash == NULL)
+        return;
+
+    xmlMutexLock(xsltExtMutex);
+
+    xmlHashFree(xsltExtensionsHash,
+                (xmlHashDeallocator) xsltFreeExtModule);
+    xsltExtensionsHash = NULL;
+
+    xmlMutexUnlock(xsltExtMutex);
+}
+
+/**
+ * xsltXPathGetTransformContext:
+ * @ctxt:  an XPath transformation context
+ *
+ * Provides the XSLT transformation context from the XPath transformation
+ * context. This is useful when an XPath function in the extension module
+ * is called by the XPath interpreter and that the XSLT context is needed
+ * for example to retrieve the associated data pertaining to this XSLT
+ * transformation.
+ *
+ * Returns the XSLT transformation context or NULL in case of error.
+ */
+xsltTransformContextPtr
+xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt)
+{
+    if ((ctxt == NULL) || (ctxt->context == NULL))
+        return (NULL);
+    return (ctxt->context->extra);
+}
+
+/**
+ * xsltRegisterExtModuleFunction:
+ * @name:  the function name
+ * @URI:  the function namespace URI
+ * @function:  the function callback
+ *
+ * Registers an extension module function.
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+xsltRegisterExtModuleFunction(const xmlChar * name, const xmlChar * URI,
+                              xmlXPathFunction function)
+{
+    if ((name == NULL) || (URI == NULL) || (function == NULL))
+        return (-1);
+
+    if (xsltFunctionsHash == NULL)
+        xsltFunctionsHash = xmlHashCreate(10);
+    if (xsltFunctionsHash == NULL)
+        return (-1);
+
+    xmlMutexLock(xsltExtMutex);
+
+    xmlHashUpdateEntry2(xsltFunctionsHash, name, URI,
+                        XML_CAST_FPTR(function), NULL);
+
+    xmlMutexUnlock(xsltExtMutex);
+
+    return (0);
+}
+
+/**
+ * xsltExtModuleFunctionLookup:
+ * @name:  the function name
+ * @URI:  the function namespace URI
+ *
+ * Looks up an extension module function
+ *
+ * Returns the function if found, NULL otherwise.
+ */
+xmlXPathFunction
+xsltExtModuleFunctionLookup(const xmlChar * name, const xmlChar * URI)
+{
+    xmlXPathFunction ret;
+
+    if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
+        return (NULL);
+
+    xmlMutexLock(xsltExtMutex);
+
+    XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI);
+
+    xmlMutexUnlock(xsltExtMutex);
+
+    /* if lookup fails, attempt a dynamic load on supported platforms */
+    if (NULL == ret) {
+        if (!xsltExtModuleRegisterDynamic(URI)) {
+            xmlMutexLock(xsltExtMutex);
+
+            XML_CAST_FPTR(ret) =
+                xmlHashLookup2(xsltFunctionsHash, name, URI);
+
+            xmlMutexUnlock(xsltExtMutex);
+        }
+    }
+
+    return ret;
+}
+
+/**
+ * xsltUnregisterExtModuleFunction:
+ * @name:  the function name
+ * @URI:  the function namespace URI
+ *
+ * Unregisters an extension module function
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+xsltUnregisterExtModuleFunction(const xmlChar * name, const xmlChar * URI)
+{
+    int ret;
+
+    if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
+        return (-1);
+
+    xmlMutexLock(xsltExtMutex);
+
+    ret = xmlHashRemoveEntry2(xsltFunctionsHash, name, URI, NULL);
+
+    xmlMutexUnlock(xsltExtMutex);
+
+    return(ret);
+}
+
+/**
+ * xsltUnregisterAllExtModuleFunction:
+ *
+ * Unregisters all extension module function
+ */
+static void
+xsltUnregisterAllExtModuleFunction(void)
+{
+    xmlMutexLock(xsltExtMutex);
+
+    xmlHashFree(xsltFunctionsHash, NULL);
+    xsltFunctionsHash = NULL;
+
+    xmlMutexUnlock(xsltExtMutex);
+}
+
+
+/**
+ * xsltNewElemPreComp:
+ * @style:  the XSLT stylesheet
+ * @inst:  the element node
+ * @function: the transform function
+ *
+ * Creates and initializes an #xsltElemPreComp
+ *
+ * Returns the new and initialized #xsltElemPreComp
+ */
+xsltElemPreCompPtr
+xsltNewElemPreComp(xsltStylesheetPtr style, xmlNodePtr inst,
+                   xsltTransformFunction function)
+{
+    xsltElemPreCompPtr cur;
+
+    cur = (xsltElemPreCompPtr) xmlMalloc(sizeof(xsltElemPreComp));
+    if (cur == NULL) {
+        xsltTransformError(NULL, style, NULL,
+                           "xsltNewExtElement : malloc failed\n");
+        return (NULL);
+    }
+    memset(cur, 0, sizeof(xsltElemPreComp));
+
+    xsltInitElemPreComp(cur, style, inst, function,
+                        (xsltElemPreCompDeallocator) xmlFree);
+
+    return (cur);
+}
+
+/**
+ * xsltInitElemPreComp:
+ * @comp:  an #xsltElemPreComp (or generally a derived structure)
+ * @style:  the XSLT stylesheet
+ * @inst:  the element node
+ * @function:  the transform function
+ * @freeFunc:  the @comp deallocator
+ *
+ * Initializes an existing #xsltElemPreComp structure. This is usefull
+ * when extending an #xsltElemPreComp to store precomputed data.
+ * This function MUST be called on any extension element precomputed
+ * data struct.
+ */
+void
+xsltInitElemPreComp(xsltElemPreCompPtr comp, xsltStylesheetPtr style,
+                    xmlNodePtr inst, xsltTransformFunction function,
+                    xsltElemPreCompDeallocator freeFunc)
+{
+    comp->type = XSLT_FUNC_EXTENSION;
+    comp->func = function;
+    comp->inst = inst;
+    comp->free = freeFunc;
+
+    comp->next = style->preComps;
+    style->preComps = comp;
+}
+
+/**
+ * xsltPreComputeExtModuleElement:
+ * @style:  the stylesheet
+ * @inst:  the element node
+ *
+ * Precomputes an extension module element
+ *
+ * Returns the precomputed data
+ */
+xsltElemPreCompPtr
+xsltPreComputeExtModuleElement(xsltStylesheetPtr style, xmlNodePtr inst)
+{
+    xsltExtElementPtr ext;
+    xsltElemPreCompPtr comp = NULL;
+
+    if ((style == NULL) || (inst == NULL) ||
+        (inst->type != XML_ELEMENT_NODE) || (inst->ns == NULL))
+        return (NULL);
+
+    xmlMutexLock(xsltExtMutex);
+
+    ext = (xsltExtElementPtr)
+        xmlHashLookup2(xsltElementsHash, inst->name, inst->ns->href);
+
+    xmlMutexUnlock(xsltExtMutex);
+
+    /*
+    * EXT TODO: Now what?
+    */
+    if (ext == NULL)
+        return (NULL);
+
+    if (ext->precomp != NULL) {
+	/*
+	* REVISIT TODO: Check if the text below is correct.
+	* This will return a xsltElemPreComp structure or NULL.
+	* 1) If the the author of the extension needs a
+	*  custom structure to hold the specific values of
+	*  this extension, he will derive a structure based on
+	*  xsltElemPreComp; thus we obviously *cannot* refactor
+	*  the xsltElemPreComp structure, since all already derived
+	*  user-defined strucures will break.
+	*  Example: For the extension xsl:document,
+	*   in xsltDocumentComp() (preproc.c), the structure
+	*   xsltStyleItemDocument is allocated, filled with
+	*   specific values and returned.
+	* 2) If the author needs no values to be stored in
+	*  this structure, then he'll return NULL;
+	*/
+        comp = ext->precomp(style, inst, ext->transform);
+    }
+    if (comp == NULL) {
+	/*
+	* Default creation of a xsltElemPreComp structure, if
+	* the author of this extension did not create a custom
+	* structure.
+	*/
+        comp = xsltNewElemPreComp(style, inst, ext->transform);
+    }
+
+    return (comp);
+}
+
+/**
+ * xsltRegisterExtModuleElement:
+ * @name:  the element name
+ * @URI:  the element namespace URI
+ * @precomp:  the pre-computation callback
+ * @transform:  the transformation callback
+ *
+ * Registers an extension module element.
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+xsltRegisterExtModuleElement(const xmlChar * name, const xmlChar * URI,
+                             xsltPreComputeFunction precomp,
+                             xsltTransformFunction transform)
+{
+    int ret;
+
+    xsltExtElementPtr ext;
+
+    if ((name == NULL) || (URI == NULL) || (transform == NULL))
+        return (-1);
+
+    if (xsltElementsHash == NULL)
+        xsltElementsHash = xmlHashCreate(10);
+    if (xsltElementsHash == NULL)
+        return (-1);
+
+    xmlMutexLock(xsltExtMutex);
+
+    ext = xsltNewExtElement(precomp, transform);
+    if (ext == NULL) {
+        ret = -1;
+        goto done;
+    }
+
+    xmlHashUpdateEntry2(xsltElementsHash, name, URI, (void *) ext,
+                        (xmlHashDeallocator) xsltFreeExtElement);
+
+done:
+    xmlMutexUnlock(xsltExtMutex);
+
+    return (0);
+}
+
+/**
+ * xsltExtElementLookup:
+ * @ctxt:  an XSLT process context
+ * @name:  the element name
+ * @URI:  the element namespace URI
+ *
+ * Looks up an extension element. @ctxt can be NULL to search only in
+ * module elements.
+ *
+ * Returns the element callback or NULL if not found
+ */
+xsltTransformFunction
+xsltExtElementLookup(xsltTransformContextPtr ctxt,
+                     const xmlChar * name, const xmlChar * URI)
+{
+    xsltTransformFunction ret;
+
+    if ((name == NULL) || (URI == NULL))
+        return (NULL);
+
+    if ((ctxt != NULL) && (ctxt->extElements != NULL)) {
+        XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->extElements, name, URI);
+        if (ret != NULL) {
+            return(ret);
+        }
+    }
+
+    ret = xsltExtModuleElementLookup(name, URI);
+
+    return (ret);
+}
+
+/**
+ * xsltExtModuleElementLookup:
+ * @name:  the element name
+ * @URI:  the element namespace URI
+ *
+ * Looks up an extension module element
+ *
+ * Returns the callback function if found, NULL otherwise.
+ */
+xsltTransformFunction
+xsltExtModuleElementLookup(const xmlChar * name, const xmlChar * URI)
+{
+    xsltExtElementPtr ext;
+
+    if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
+        return (NULL);
+
+    xmlMutexLock(xsltExtMutex);
+
+    ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
+
+    xmlMutexUnlock(xsltExtMutex);
+
+    /*
+     * if function lookup fails, attempt a dynamic load on
+     * supported platforms
+     */
+    if (NULL == ext) {
+        if (!xsltExtModuleRegisterDynamic(URI)) {
+            xmlMutexLock(xsltExtMutex);
+
+            ext = (xsltExtElementPtr)
+	          xmlHashLookup2(xsltElementsHash, name, URI);
+
+            xmlMutexUnlock(xsltExtMutex);
+        }
+    }
+
+    if (ext == NULL)
+        return (NULL);
+    return (ext->transform);
+}
+
+/**
+ * xsltExtModuleElementPreComputeLookup:
+ * @name:  the element name
+ * @URI:  the element namespace URI
+ *
+ * Looks up an extension module element pre-computation function
+ *
+ * Returns the callback function if found, NULL otherwise.
+ */
+xsltPreComputeFunction
+xsltExtModuleElementPreComputeLookup(const xmlChar * name,
+                                     const xmlChar * URI)
+{
+    xsltExtElementPtr ext;
+
+    if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
+        return (NULL);
+
+    xmlMutexLock(xsltExtMutex);
+
+    ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
+
+    xmlMutexUnlock(xsltExtMutex);
+
+    if (ext == NULL) {
+        if (!xsltExtModuleRegisterDynamic(URI)) {
+            xmlMutexLock(xsltExtMutex);
+
+            ext = (xsltExtElementPtr)
+	          xmlHashLookup2(xsltElementsHash, name, URI);
+
+            xmlMutexUnlock(xsltExtMutex);
+        }
+    }
+
+    if (ext == NULL)
+        return (NULL);
+    return (ext->precomp);
+}
+
+/**
+ * xsltUnregisterExtModuleElement:
+ * @name:  the element name
+ * @URI:  the element namespace URI
+ *
+ * Unregisters an extension module element
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+xsltUnregisterExtModuleElement(const xmlChar * name, const xmlChar * URI)
+{
+    int ret;
+
+    if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
+        return (-1);
+
+    xmlMutexLock(xsltExtMutex);
+
+    ret = xmlHashRemoveEntry2(xsltElementsHash, name, URI,
+                              (xmlHashDeallocator) xsltFreeExtElement);
+
+    xmlMutexUnlock(xsltExtMutex);
+
+    return(ret);
+}
+
+/**
+ * xsltUnregisterAllExtModuleElement:
+ *
+ * Unregisters all extension module element
+ */
+static void
+xsltUnregisterAllExtModuleElement(void)
+{
+    xmlMutexLock(xsltExtMutex);
+
+    xmlHashFree(xsltElementsHash, (xmlHashDeallocator) xsltFreeExtElement);
+    xsltElementsHash = NULL;
+
+    xmlMutexUnlock(xsltExtMutex);
+}
+
+/**
+ * xsltRegisterExtModuleTopLevel:
+ * @name:  the top-level element name
+ * @URI:  the top-level element namespace URI
+ * @function:  the top-level element callback
+ *
+ * Registers an extension module top-level element.
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+xsltRegisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI,
+                              xsltTopLevelFunction function)
+{
+    if ((name == NULL) || (URI == NULL) || (function == NULL))
+        return (-1);
+
+    if (xsltTopLevelsHash == NULL)
+        xsltTopLevelsHash = xmlHashCreate(10);
+    if (xsltTopLevelsHash == NULL)
+        return (-1);
+
+    xmlMutexLock(xsltExtMutex);
+
+    xmlHashUpdateEntry2(xsltTopLevelsHash, name, URI,
+                        XML_CAST_FPTR(function), NULL);
+
+    xmlMutexUnlock(xsltExtMutex);
+
+    return (0);
+}
+
+/**
+ * xsltExtModuleTopLevelLookup:
+ * @name:  the top-level element name
+ * @URI:  the top-level element namespace URI
+ *
+ * Looks up an extension module top-level element
+ *
+ * Returns the callback function if found, NULL otherwise.
+ */
+xsltTopLevelFunction
+xsltExtModuleTopLevelLookup(const xmlChar * name, const xmlChar * URI)
+{
+    xsltTopLevelFunction ret;
+
+    if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
+        return (NULL);
+
+    xmlMutexLock(xsltExtMutex);
+
+    XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
+
+    xmlMutexUnlock(xsltExtMutex);
+
+    /* if lookup fails, attempt a dynamic load on supported platforms */
+    if (NULL == ret) {
+        if (!xsltExtModuleRegisterDynamic(URI)) {
+            xmlMutexLock(xsltExtMutex);
+
+            XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
+
+            xmlMutexUnlock(xsltExtMutex);
+        }
+    }
+
+    return (ret);
+}
+
+/**
+ * xsltUnregisterExtModuleTopLevel:
+ * @name:  the top-level element name
+ * @URI:  the top-level element namespace URI
+ *
+ * Unregisters an extension module top-level element
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+xsltUnregisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI)
+{
+    int ret;
+
+    if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
+        return (-1);
+
+    xmlMutexLock(xsltExtMutex);
+
+    ret = xmlHashRemoveEntry2(xsltTopLevelsHash, name, URI, NULL);
+
+    xmlMutexUnlock(xsltExtMutex);
+
+    return(ret);
+}
+
+/**
+ * xsltUnregisterAllExtModuleTopLevel:
+ *
+ * Unregisters all extension module function
+ */
+static void
+xsltUnregisterAllExtModuleTopLevel(void)
+{
+    xmlMutexLock(xsltExtMutex);
+
+    xmlHashFree(xsltTopLevelsHash, NULL);
+    xsltTopLevelsHash = NULL;
+
+    xmlMutexUnlock(xsltExtMutex);
+}
+
+/**
+ * xsltGetExtInfo:
+ * @style:  pointer to a stylesheet
+ * @URI:    the namespace URI desired
+ *
+ * looks up URI in extInfos of the stylesheet
+ *
+ * returns a pointer to the hash table if found, else NULL
+ */
+xmlHashTablePtr
+xsltGetExtInfo(xsltStylesheetPtr style, const xmlChar * URI)
+{
+    xsltExtDataPtr data;
+
+    /*
+    * TODO: Why do we have a return type of xmlHashTablePtr?
+    *   Is the user-allocated data for extension modules expected
+    *   to be a xmlHashTablePtr only? Or is this intended for
+    *   the EXSLT module only?
+    */
+
+    if (style != NULL && style->extInfos != NULL) {
+        data = xmlHashLookup(style->extInfos, URI);
+        if (data != NULL && data->extData != NULL)
+            return data->extData;
+    }
+    return NULL;
+}
+
+/************************************************************************
+ * 									*
+ * 		Test module http://xmlsoft.org/XSLT/			*
+ * 									*
+ ************************************************************************/
+
+/************************************************************************
+ * 									*
+ * 		Test of the extension module API			*
+ * 									*
+ ************************************************************************/
+
+static xmlChar *testData = NULL;
+static xmlChar *testStyleData = NULL;
+
+/**
+ * xsltExtFunctionTest:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * function libxslt:test() for testing the extensions support.
+ */
+static void
+xsltExtFunctionTest(xmlXPathParserContextPtr ctxt,
+                    int nargs ATTRIBUTE_UNUSED)
+{
+    xsltTransformContextPtr tctxt;
+    void *data = NULL;
+
+    tctxt = xsltXPathGetTransformContext(ctxt);
+
+    if (testData == NULL) {
+        xsltGenericDebug(xsltGenericDebugContext,
+                         "xsltExtFunctionTest: not initialized,"
+                         " calling xsltGetExtData\n");
+        data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
+        if (data == NULL) {
+            xsltTransformError(tctxt, NULL, NULL,
+                               "xsltExtElementTest: not initialized\n");
+            return;
+        }
+    }
+    if (tctxt == NULL) {
+        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+                           "xsltExtFunctionTest: failed to get the transformation context\n");
+        return;
+    }
+    if (data == NULL)
+        data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
+    if (data == NULL) {
+        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+                           "xsltExtFunctionTest: failed to get module data\n");
+        return;
+    }
+    if (data != testData) {
+        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+                           "xsltExtFunctionTest: got wrong module data\n");
+        return;
+    }
+#ifdef WITH_XSLT_DEBUG_FUNCTION
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "libxslt:test() called with %d args\n", nargs);
+#endif
+}
+
+/**
+ * xsltExtElementPreCompTest:
+ * @style:  the stylesheet
+ * @inst:  the instruction in the stylesheet
+ *
+ * Process a libxslt:test node
+ */
+static xsltElemPreCompPtr
+xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst,
+                          xsltTransformFunction function)
+{
+    xsltElemPreCompPtr ret;
+
+    if (style == NULL) {
+        xsltTransformError(NULL, NULL, inst,
+                           "xsltExtElementTest: no transformation context\n");
+        return (NULL);
+    }
+    if (testStyleData == NULL) {
+        xsltGenericDebug(xsltGenericDebugContext,
+                         "xsltExtElementPreCompTest: not initialized,"
+                         " calling xsltStyleGetExtData\n");
+        xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL);
+        if (testStyleData == NULL) {
+            xsltTransformError(NULL, style, inst,
+                               "xsltExtElementPreCompTest: not initialized\n");
+            if (style != NULL)
+                style->errors++;
+            return (NULL);
+        }
+    }
+    if (inst == NULL) {
+        xsltTransformError(NULL, style, inst,
+                           "xsltExtElementPreCompTest: no instruction\n");
+        if (style != NULL)
+            style->errors++;
+        return (NULL);
+    }
+    ret = xsltNewElemPreComp(style, inst, function);
+    return (ret);
+}
+
+/**
+ * xsltExtElementTest:
+ * @ctxt:  an XSLT processing context
+ * @node:  The current node
+ * @inst:  the instruction in the stylesheet
+ * @comp:  precomputed informations
+ *
+ * Process a libxslt:test node
+ */
+static void
+xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                   xmlNodePtr inst,
+                   xsltElemPreCompPtr comp ATTRIBUTE_UNUSED)
+{
+    xmlNodePtr commentNode;
+
+    if (testData == NULL) {
+        xsltGenericDebug(xsltGenericDebugContext,
+                         "xsltExtElementTest: not initialized,"
+                         " calling xsltGetExtData\n");
+        xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL);
+        if (testData == NULL) {
+            xsltTransformError(ctxt, NULL, inst,
+                               "xsltExtElementTest: not initialized\n");
+            return;
+        }
+    }
+    if (ctxt == NULL) {
+        xsltTransformError(ctxt, NULL, inst,
+                           "xsltExtElementTest: no transformation context\n");
+        return;
+    }
+    if (node == NULL) {
+        xsltTransformError(ctxt, NULL, inst,
+                           "xsltExtElementTest: no current node\n");
+        return;
+    }
+    if (inst == NULL) {
+        xsltTransformError(ctxt, NULL, inst,
+                           "xsltExtElementTest: no instruction\n");
+        return;
+    }
+    if (ctxt->insert == NULL) {
+        xsltTransformError(ctxt, NULL, inst,
+                           "xsltExtElementTest: no insertion point\n");
+        return;
+    }
+    commentNode = xmlNewComment((const xmlChar *)
+                                "libxslt:test element test worked");
+    xmlAddChild(ctxt->insert, commentNode);
+}
+
+/**
+ * xsltExtInitTest:
+ * @ctxt:  an XSLT transformation context
+ * @URI:  the namespace URI for the extension
+ *
+ * A function called at initialization time of an XSLT extension module
+ *
+ * Returns a pointer to the module specific data for this transformation
+ */
+static void *
+xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI)
+{
+    if (testStyleData == NULL) {
+        xsltGenericDebug(xsltGenericErrorContext,
+                         "xsltExtInitTest: not initialized,"
+                         " calling xsltStyleGetExtData\n");
+        testStyleData = xsltStyleGetExtData(ctxt->style, URI);
+        if (testStyleData == NULL) {
+            xsltTransformError(ctxt, NULL, NULL,
+                               "xsltExtInitTest: not initialized\n");
+            return (NULL);
+        }
+    }
+    if (testData != NULL) {
+        xsltTransformError(ctxt, NULL, NULL,
+                           "xsltExtInitTest: already initialized\n");
+        return (NULL);
+    }
+    testData = (void *) "test data";
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "Registered test module : %s\n", URI);
+    return (testData);
+}
+
+
+/**
+ * xsltExtShutdownTest:
+ * @ctxt:  an XSLT transformation context
+ * @URI:  the namespace URI for the extension
+ * @data:  the data associated to this module
+ *
+ * A function called at shutdown time of an XSLT extension module
+ */
+static void
+xsltExtShutdownTest(xsltTransformContextPtr ctxt,
+                    const xmlChar * URI, void *data)
+{
+    if (testData == NULL) {
+        xsltTransformError(ctxt, NULL, NULL,
+                           "xsltExtShutdownTest: not initialized\n");
+        return;
+    }
+    if (data != testData) {
+        xsltTransformError(ctxt, NULL, NULL,
+                           "xsltExtShutdownTest: wrong data\n");
+    }
+    testData = NULL;
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "Unregistered test module : %s\n", URI);
+}
+
+/**
+ * xsltExtStyleInitTest:
+ * @style:  an XSLT stylesheet
+ * @URI:  the namespace URI for the extension
+ *
+ * A function called at initialization time of an XSLT extension module
+ *
+ * Returns a pointer to the module specific data for this transformation
+ */
+static void *
+xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
+                     const xmlChar * URI)
+{
+    if (testStyleData != NULL) {
+        xsltTransformError(NULL, NULL, NULL,
+                           "xsltExtInitTest: already initialized\n");
+        return (NULL);
+    }
+    testStyleData = (void *) "test data";
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "Registered test module : %s\n", URI);
+    return (testStyleData);
+}
+
+
+/**
+ * xsltExtStyleShutdownTest:
+ * @style:  an XSLT stylesheet
+ * @URI:  the namespace URI for the extension
+ * @data:  the data associated to this module
+ *
+ * A function called at shutdown time of an XSLT extension module
+ */
+static void
+xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED,
+                         const xmlChar * URI, void *data)
+{
+    if (testStyleData == NULL) {
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtShutdownTest: not initialized\n");
+        return;
+    }
+    if (data != testStyleData) {
+        xsltTransformError(NULL, NULL, NULL,
+                           "xsltExtShutdownTest: wrong data\n");
+    }
+    testStyleData = NULL;
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "Unregistered test module : %s\n", URI);
+}
+
+/**
+ * xsltRegisterTestModule:
+ *
+ * Registers the test module
+ */
+void
+xsltRegisterTestModule(void)
+{
+    xsltInitGlobals();
+    xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL,
+                              xsltExtInitTest, xsltExtShutdownTest,
+                              xsltExtStyleInitTest,
+                              xsltExtStyleShutdownTest);
+    xsltRegisterExtModuleFunction((const xmlChar *) "test",
+                                  (const xmlChar *) XSLT_DEFAULT_URL,
+                                  xsltExtFunctionTest);
+    xsltRegisterExtModuleElement((const xmlChar *) "test",
+                                 (const xmlChar *) XSLT_DEFAULT_URL,
+                                 xsltExtElementPreCompTest,
+                                 xsltExtElementTest);
+}
+
+static void
+xsltHashScannerModuleFree(void *payload ATTRIBUTE_UNUSED,
+                          void *data ATTRIBUTE_UNUSED,
+                          xmlChar * name ATTRIBUTE_UNUSED)
+{
+#ifdef WITH_MODULES
+    xmlModuleClose(payload);
+#endif
+}
+
+/**
+ * xsltInitGlobals:
+ *
+ * Initialize the global variables for extensions
+ */
+void
+xsltInitGlobals(void)
+{
+    if (xsltExtMutex == NULL) {
+        xsltExtMutex = xmlNewMutex();
+    }
+}
+
+/**
+ * xsltCleanupGlobals:
+ *
+ * Unregister all global variables set up by the XSLT library
+ */
+void
+xsltCleanupGlobals(void)
+{
+    xsltUnregisterAllExtModules();
+    xsltUnregisterAllExtModuleFunction();
+    xsltUnregisterAllExtModuleElement();
+    xsltUnregisterAllExtModuleTopLevel();
+
+    xmlMutexLock(xsltExtMutex);
+    /* cleanup dynamic module hash */
+    if (NULL != xsltModuleHash) {
+        xmlHashScan(xsltModuleHash, xsltHashScannerModuleFree, 0);
+        xmlHashFree(xsltModuleHash, NULL);
+        xsltModuleHash = NULL;
+    }
+    xmlMutexUnlock(xsltExtMutex);
+
+    xmlFreeMutex(xsltExtMutex);
+    xsltExtMutex = NULL;
+    xsltUninit();
+}
+
+static void
+xsltDebugDumpExtensionsCallback(void *function ATTRIBUTE_UNUSED,
+                                FILE * output, const xmlChar * name,
+                                const xmlChar * URI,
+                                const xmlChar * not_used ATTRIBUTE_UNUSED)
+{
+    if (!name || !URI)
+        return;
+    fprintf(output, "{%s}%s\n", URI, name);
+}
+
+static void
+xsltDebugDumpExtModulesCallback(void *function ATTRIBUTE_UNUSED,
+                                FILE * output, const xmlChar * URI,
+                                const xmlChar * not_used ATTRIBUTE_UNUSED,
+                                const xmlChar * not_used2 ATTRIBUTE_UNUSED)
+{
+    if (!URI)
+        return;
+    fprintf(output, "%s\n", URI);
+}
+
+/**
+ * xsltDebugDumpExtensions:
+ * @output:  the FILE * for the output, if NULL stdout is used
+ *
+ * Dumps a list of the registered XSLT extension functions and elements
+ */
+void
+xsltDebugDumpExtensions(FILE * output)
+{
+    if (output == NULL)
+        output = stdout;
+    fprintf(output,
+            "Registered XSLT Extensions\n--------------------------\n");
+    if (!xsltFunctionsHash)
+        fprintf(output, "No registered extension functions\n");
+    else {
+        fprintf(output, "Registered Extension Functions:\n");
+        xmlMutexLock(xsltExtMutex);
+        xmlHashScanFull(xsltFunctionsHash,
+                        (xmlHashScannerFull)
+                        xsltDebugDumpExtensionsCallback, output);
+        xmlMutexUnlock(xsltExtMutex);
+    }
+    if (!xsltElementsHash)
+        fprintf(output, "\nNo registered extension elements\n");
+    else {
+        fprintf(output, "\nRegistered Extension Elements:\n");
+        xmlMutexLock(xsltExtMutex);
+        xmlHashScanFull(xsltElementsHash,
+                        (xmlHashScannerFull)
+                        xsltDebugDumpExtensionsCallback, output);
+        xmlMutexUnlock(xsltExtMutex);
+    }
+    if (!xsltExtensionsHash)
+        fprintf(output, "\nNo registered extension modules\n");
+    else {
+        fprintf(output, "\nRegistered Extension Modules:\n");
+        xmlMutexLock(xsltExtMutex);
+        xmlHashScanFull(xsltExtensionsHash,
+                        (xmlHashScannerFull)
+                        xsltDebugDumpExtModulesCallback, output);
+        xmlMutexUnlock(xsltExtMutex);
+    }
+
+}
diff --git a/libxslt/extensions.h b/libxslt/extensions.h
new file mode 100644
index 0000000..900779c
--- /dev/null
+++ b/libxslt/extensions.h
@@ -0,0 +1,262 @@
+/*
+ * Summary: interface for the extension support
+ * Description: This provide the API needed for simple and module
+ *              extension support.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_EXTENSION_H__
+#define __XML_XSLT_EXTENSION_H__
+
+#include <libxml/xpath.h>
+#include "xsltexports.h"
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Extension Modules API.
+ */
+
+/**
+ * xsltInitGlobals:
+ *
+ * Initialize the global variables for extensions
+ *
+ */
+
+XSLTPUBFUN void XSLTCALL
+		xsltInitGlobals                 (void);
+
+/**
+ * xsltStyleExtInitFunction:
+ * @ctxt:  an XSLT stylesheet
+ * @URI:  the namespace URI for the extension
+ *
+ * A function called at initialization time of an XSLT extension module.
+ *
+ * Returns a pointer to the module specific data for this transformation.
+ */
+typedef void * (*xsltStyleExtInitFunction)	(xsltStylesheetPtr style,
+						 const xmlChar *URI);
+
+/**
+ * xsltStyleExtShutdownFunction:
+ * @ctxt:  an XSLT stylesheet
+ * @URI:  the namespace URI for the extension
+ * @data:  the data associated to this module
+ *
+ * A function called at shutdown time of an XSLT extension module.
+ */
+typedef void (*xsltStyleExtShutdownFunction)	(xsltStylesheetPtr style,
+						 const xmlChar *URI,
+						 void *data);
+
+/**
+ * xsltExtInitFunction:
+ * @ctxt:  an XSLT transformation context
+ * @URI:  the namespace URI for the extension
+ *
+ * A function called at initialization time of an XSLT extension module.
+ *
+ * Returns a pointer to the module specific data for this transformation.
+ */
+typedef void * (*xsltExtInitFunction)	(xsltTransformContextPtr ctxt,
+					 const xmlChar *URI);
+
+/**
+ * xsltExtShutdownFunction:
+ * @ctxt:  an XSLT transformation context
+ * @URI:  the namespace URI for the extension
+ * @data:  the data associated to this module
+ *
+ * A function called at shutdown time of an XSLT extension module.
+ */
+typedef void (*xsltExtShutdownFunction) (xsltTransformContextPtr ctxt,
+					 const xmlChar *URI,
+					 void *data);
+
+XSLTPUBFUN int XSLTCALL
+		xsltRegisterExtModule	(const xmlChar *URI,
+					 xsltExtInitFunction initFunc,
+					 xsltExtShutdownFunction shutdownFunc);
+XSLTPUBFUN int XSLTCALL
+		xsltRegisterExtModuleFull
+					(const xmlChar * URI,
+					 xsltExtInitFunction initFunc,
+					 xsltExtShutdownFunction shutdownFunc,
+					 xsltStyleExtInitFunction styleInitFunc,
+					 xsltStyleExtShutdownFunction styleShutdownFunc);
+
+XSLTPUBFUN int XSLTCALL
+		xsltUnregisterExtModule	(const xmlChar * URI);
+
+XSLTPUBFUN void * XSLTCALL
+		xsltGetExtData		(xsltTransformContextPtr ctxt,
+					 const xmlChar *URI);
+
+XSLTPUBFUN void * XSLTCALL
+		xsltStyleGetExtData	(xsltStylesheetPtr style,
+					 const xmlChar *URI);
+#ifdef XSLT_REFACTORED
+XSLTPUBFUN void * XSLTCALL
+		xsltStyleStylesheetLevelGetExtData(
+					 xsltStylesheetPtr style,
+					 const xmlChar * URI);
+#endif
+XSLTPUBFUN void XSLTCALL
+		xsltShutdownCtxtExts	(xsltTransformContextPtr ctxt);
+
+XSLTPUBFUN void XSLTCALL
+		xsltShutdownExts	(xsltStylesheetPtr style);
+
+XSLTPUBFUN xsltTransformContextPtr XSLTCALL
+		xsltXPathGetTransformContext
+					(xmlXPathParserContextPtr ctxt);
+
+/*
+ * extension functions
+*/
+XSLTPUBFUN int XSLTCALL
+		xsltRegisterExtModuleFunction
+					(const xmlChar *name,
+					 const xmlChar *URI,
+					 xmlXPathFunction function);
+XSLTPUBFUN xmlXPathFunction XSLTCALL
+	xsltExtModuleFunctionLookup	(const xmlChar *name,
+					 const xmlChar *URI);
+XSLTPUBFUN int XSLTCALL
+		xsltUnregisterExtModuleFunction
+					(const xmlChar *name,
+					 const xmlChar *URI);
+
+/*
+ * extension elements
+ */
+typedef xsltElemPreCompPtr (*xsltPreComputeFunction)
+					(xsltStylesheetPtr style,
+					 xmlNodePtr inst,
+					 xsltTransformFunction function);
+
+XSLTPUBFUN xsltElemPreCompPtr XSLTCALL
+		xsltNewElemPreComp	(xsltStylesheetPtr style,
+					 xmlNodePtr inst,
+					 xsltTransformFunction function);
+XSLTPUBFUN void XSLTCALL
+		xsltInitElemPreComp	(xsltElemPreCompPtr comp,
+					 xsltStylesheetPtr style,
+					 xmlNodePtr inst,
+					 xsltTransformFunction function,
+					 xsltElemPreCompDeallocator freeFunc);
+
+XSLTPUBFUN int XSLTCALL
+		xsltRegisterExtModuleElement
+					(const xmlChar *name,
+					 const xmlChar *URI,
+					 xsltPreComputeFunction precomp,
+					 xsltTransformFunction transform);
+XSLTPUBFUN xsltTransformFunction XSLTCALL
+		xsltExtElementLookup	(xsltTransformContextPtr ctxt,
+					 const xmlChar *name,
+					 const xmlChar *URI);
+XSLTPUBFUN xsltTransformFunction XSLTCALL
+		xsltExtModuleElementLookup
+					(const xmlChar *name,
+					 const xmlChar *URI);
+XSLTPUBFUN xsltPreComputeFunction XSLTCALL
+		xsltExtModuleElementPreComputeLookup
+					(const xmlChar *name,
+					 const xmlChar *URI);
+XSLTPUBFUN int XSLTCALL
+		xsltUnregisterExtModuleElement
+					(const xmlChar *name,
+					 const xmlChar *URI);
+
+/*
+ * top-level elements
+ */
+typedef void (*xsltTopLevelFunction)	(xsltStylesheetPtr style,
+					 xmlNodePtr inst);
+
+XSLTPUBFUN int XSLTCALL
+		xsltRegisterExtModuleTopLevel
+					(const xmlChar *name,
+					 const xmlChar *URI,
+					 xsltTopLevelFunction function);
+XSLTPUBFUN xsltTopLevelFunction XSLTCALL
+		xsltExtModuleTopLevelLookup
+					(const xmlChar *name,
+					 const xmlChar *URI);
+XSLTPUBFUN int XSLTCALL
+		xsltUnregisterExtModuleTopLevel
+					(const xmlChar *name,
+					 const xmlChar *URI);
+
+
+/* These 2 functions are deprecated for use within modules. */
+XSLTPUBFUN int XSLTCALL
+		xsltRegisterExtFunction	(xsltTransformContextPtr ctxt,
+					 const xmlChar *name,
+					 const xmlChar *URI,
+					 xmlXPathFunction function);
+XSLTPUBFUN int XSLTCALL
+		xsltRegisterExtElement	(xsltTransformContextPtr ctxt,
+					 const xmlChar *name,
+					 const xmlChar *URI,
+					 xsltTransformFunction function);
+
+/*
+ * Extension Prefix handling API.
+ * Those are used by the XSLT (pre)processor.
+ */
+
+XSLTPUBFUN int XSLTCALL
+		xsltRegisterExtPrefix	(xsltStylesheetPtr style,
+					 const xmlChar *prefix,
+					 const xmlChar *URI);
+XSLTPUBFUN int XSLTCALL
+		xsltCheckExtPrefix	(xsltStylesheetPtr style,
+					 const xmlChar *URI);
+XSLTPUBFUN int XSLTCALL
+		xsltCheckExtURI		(xsltStylesheetPtr style,
+					 const xmlChar *URI);
+XSLTPUBFUN int XSLTCALL
+		xsltInitCtxtExts	(xsltTransformContextPtr ctxt);
+XSLTPUBFUN void XSLTCALL
+		xsltFreeCtxtExts	(xsltTransformContextPtr ctxt);
+XSLTPUBFUN void XSLTCALL
+		xsltFreeExts		(xsltStylesheetPtr style);
+
+XSLTPUBFUN xsltElemPreCompPtr XSLTCALL
+		xsltPreComputeExtModuleElement
+					(xsltStylesheetPtr style,
+					 xmlNodePtr inst);
+/*
+ * Extension Infos access.
+ * Used by exslt initialisation
+ */
+
+XSLTPUBFUN xmlHashTablePtr XSLTCALL
+		xsltGetExtInfo		(xsltStylesheetPtr style,
+					 const xmlChar *URI);
+
+/**
+ * Test module http://xmlsoft.org/XSLT/
+ */
+XSLTPUBFUN void XSLTCALL
+		xsltRegisterTestModule	(void);
+XSLTPUBFUN void XSLTCALL
+		xsltDebugDumpExtensions	(FILE * output);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_EXTENSION_H__ */
+
diff --git a/libxslt/extra.c b/libxslt/extra.c
new file mode 100644
index 0000000..3a0f547
--- /dev/null
+++ b/libxslt/extra.c
@@ -0,0 +1,329 @@
+/*
+ * extra.c: Implementation of non-standard features
+ *
+ * Reference:
+ *   Michael Kay "XSLT Programmer's Reference" pp 637-643
+ *   The node-set() extension function
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/hash.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parserInternals.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "extensions.h"
+#include "variables.h"
+#include "transform.h"
+#include "extra.h"
+#include "preproc.h"
+
+#ifdef WITH_XSLT_DEBUG
+#define WITH_XSLT_DEBUG_EXTRA
+#endif
+
+/************************************************************************
+ * 									*
+ * 		Handling of XSLT debugging				*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltDebug:
+ * @ctxt:  an XSLT processing context
+ * @node:  The current node
+ * @inst:  the instruction in the stylesheet
+ * @comp:  precomputed informations
+ *
+ * Process an debug node
+ */
+void
+xsltDebug(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
+          xmlNodePtr inst ATTRIBUTE_UNUSED,
+          xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
+{
+    int i, j;
+
+    xsltGenericError(xsltGenericErrorContext, "Templates:\n");
+    for (i = 0, j = ctxt->templNr - 1; ((i < 15) && (j >= 0)); i++, j--) {
+        xsltGenericError(xsltGenericErrorContext, "#%d ", i);
+        if (ctxt->templTab[j]->name != NULL)
+            xsltGenericError(xsltGenericErrorContext, "name %s ",
+                             ctxt->templTab[j]->name);
+        if (ctxt->templTab[j]->match != NULL)
+            xsltGenericError(xsltGenericErrorContext, "name %s ",
+                             ctxt->templTab[j]->match);
+        if (ctxt->templTab[j]->mode != NULL)
+            xsltGenericError(xsltGenericErrorContext, "name %s ",
+                             ctxt->templTab[j]->mode);
+        xsltGenericError(xsltGenericErrorContext, "\n");
+    }
+    xsltGenericError(xsltGenericErrorContext, "Variables:\n");
+    for (i = 0, j = ctxt->varsNr - 1; ((i < 15) && (j >= 0)); i++, j--) {
+        xsltStackElemPtr cur;
+
+        if (ctxt->varsTab[j] == NULL)
+            continue;
+        xsltGenericError(xsltGenericErrorContext, "#%d\n", i);
+        cur = ctxt->varsTab[j];
+        while (cur != NULL) {
+            if (cur->comp == NULL) {
+                xsltGenericError(xsltGenericErrorContext,
+                                 "corrupted !!!\n");
+            } else if (cur->comp->type == XSLT_FUNC_PARAM) {
+                xsltGenericError(xsltGenericErrorContext, "param ");
+            } else if (cur->comp->type == XSLT_FUNC_VARIABLE) {
+                xsltGenericError(xsltGenericErrorContext, "var ");
+            }
+            if (cur->name != NULL)
+                xsltGenericError(xsltGenericErrorContext, "%s ",
+                                 cur->name);
+            else
+                xsltGenericError(xsltGenericErrorContext, "noname !!!!");
+#ifdef LIBXML_DEBUG_ENABLED
+            if (cur->value != NULL) {
+                xmlXPathDebugDumpObject(stdout, cur->value, 1);
+            } else {
+                xsltGenericError(xsltGenericErrorContext, "NULL !!!!");
+            }
+#endif
+            xsltGenericError(xsltGenericErrorContext, "\n");
+            cur = cur->next;
+        }
+
+    }
+}
+
+/************************************************************************
+ * 									*
+ * 		Classic extensions as described by M. Kay		*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltFunctionNodeSet:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the node-set() XSLT function
+ *   node-set node-set(result-tree)
+ *
+ * This function is available in libxslt, saxon or xt namespace.
+ */
+void
+xsltFunctionNodeSet(xmlXPathParserContextPtr ctxt, int nargs){
+    if (nargs != 1) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+		"node-set() : expects one result-tree arg\n");
+	ctxt->error = XPATH_INVALID_ARITY;
+	return;
+    }
+    if ((ctxt->value == NULL) ||
+	((ctxt->value->type != XPATH_XSLT_TREE) &&
+	 (ctxt->value->type != XPATH_NODESET))) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+	    "node-set() invalid arg expecting a result tree\n");
+	ctxt->error = XPATH_INVALID_TYPE;
+	return;
+    }
+    if (ctxt->value->type == XPATH_XSLT_TREE) {
+	ctxt->value->type = XPATH_NODESET;
+    }
+}
+
+
+/*
+ * Okay the following really seems unportable and since it's not
+ * part of any standard I'm not too ashamed to do this
+ */
+#if defined(linux) || defined(__sun)
+#if defined(HAVE_MKTIME) && defined(HAVE_LOCALTIME) && defined(HAVE_ASCTIME)
+#define WITH_LOCALTIME
+
+/**
+ * xsltFunctionLocalTime:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the localTime XSLT function used by NORM
+ *   string localTime(???)
+ *
+ * This function is available in Norm's extension namespace
+ * Code (and comments) contributed by Norm
+ */
+static void
+xsltFunctionLocalTime(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr obj;
+    char *str;
+    char digits[5];
+    char result[29];
+    long int field;
+    time_t gmt, lmt;
+    struct tm gmt_tm;
+    struct tm *local_tm;
+ 
+    if (nargs != 1) {
+       xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+                      "localTime() : invalid number of args %d\n", nargs);
+       ctxt->error = XPATH_INVALID_ARITY;
+       return;
+    }
+ 
+    obj = valuePop(ctxt);
+
+    if (obj->type != XPATH_STRING) {
+	obj = xmlXPathConvertString(obj);
+    }
+    if (obj == NULL) {
+	valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
+	return;
+    }
+    
+    str = (char *) obj->stringval;
+
+    /* str = "$Date$" */
+    memset(digits, 0, sizeof(digits));
+    strncpy(digits, str+7, 4);
+    field = strtol(digits, NULL, 10);
+    gmt_tm.tm_year = field - 1900;
+
+    memset(digits, 0, sizeof(digits));
+    strncpy(digits, str+12, 2);
+    field = strtol(digits, NULL, 10);
+    gmt_tm.tm_mon = field - 1;
+
+    memset(digits, 0, sizeof(digits));
+    strncpy(digits, str+15, 2);
+    field = strtol(digits, NULL, 10);
+    gmt_tm.tm_mday = field;
+
+    memset(digits, 0, sizeof(digits));
+    strncpy(digits, str+18, 2);
+    field = strtol(digits, NULL, 10);
+    gmt_tm.tm_hour = field;
+
+    memset(digits, 0, sizeof(digits));
+    strncpy(digits, str+21, 2);
+    field = strtol(digits, NULL, 10);
+    gmt_tm.tm_min = field;
+
+    memset(digits, 0, sizeof(digits));
+    strncpy(digits, str+24, 2);
+    field = strtol(digits, NULL, 10);
+    gmt_tm.tm_sec = field;
+
+    /* Now turn gmt_tm into a time. */
+    gmt = mktime(&gmt_tm);
+
+
+    /*
+     * FIXME: it's been too long since I did manual memory management.
+     * (I swore never to do it again.) Does this introduce a memory leak?
+     */
+    local_tm = localtime(&gmt);
+
+    /*
+     * Calling localtime() has the side-effect of setting timezone.
+     * After we know the timezone, we can adjust for it
+     */
+    lmt = gmt - timezone;
+
+    /*
+     * FIXME: it's been too long since I did manual memory management.
+     * (I swore never to do it again.) Does this introduce a memory leak?
+     */
+    local_tm = localtime(&lmt);
+
+    /*
+     * Now convert local_tm back into a string. This doesn't introduce
+     * a memory leak, so says asctime(3).
+     */
+
+    str = asctime(local_tm);           /* "Tue Jun 26 05:02:16 2001" */
+                                       /*  0123456789 123456789 123 */
+
+    memset(result, 0, sizeof(result)); /* "Thu, 26 Jun 2001" */
+                                       /*  0123456789 12345 */
+
+    strncpy(result, str, 20);
+    strcpy(result+20, "???");          /* tzname doesn't work, fake it */
+    strncpy(result+23, str+19, 5);
+
+    /* Ok, now result contains the string I want to send back. */
+    valuePush(ctxt, xmlXPathNewString((xmlChar *)result));
+}
+#endif
+#endif /* linux or sun */
+
+
+/**
+ * xsltRegisterExtras:
+ * @ctxt:  a XSLT process context
+ *
+ * Registers the built-in extensions. This function is deprecated, use
+ * xsltRegisterAllExtras instead.
+ */
+void
+xsltRegisterExtras(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED) {
+    xsltRegisterAllExtras();
+}
+
+/**
+ * xsltRegisterAllExtras:
+ *
+ * Registers the built-in extensions
+ */
+void
+xsltRegisterAllExtras (void) {
+    xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
+				  XSLT_LIBXSLT_NAMESPACE,
+				  xsltFunctionNodeSet);
+    xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
+				  XSLT_SAXON_NAMESPACE,
+				  xsltFunctionNodeSet);
+    xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
+				  XSLT_XT_NAMESPACE,
+				  xsltFunctionNodeSet);
+#ifdef WITH_LOCALTIME
+    xsltRegisterExtModuleFunction((const xmlChar *) "localTime",
+				  XSLT_NORM_SAXON_NAMESPACE,
+				  xsltFunctionLocalTime);
+#endif
+    xsltRegisterExtModuleElement((const xmlChar *) "debug",
+				 XSLT_LIBXSLT_NAMESPACE,
+				 NULL,
+				 (xsltTransformFunction) xsltDebug);
+    xsltRegisterExtModuleElement((const xmlChar *) "output",
+				 XSLT_SAXON_NAMESPACE,
+				 xsltDocumentComp,
+				 (xsltTransformFunction) xsltDocumentElem);
+    xsltRegisterExtModuleElement((const xmlChar *) "write",
+				 XSLT_XALAN_NAMESPACE,
+				 xsltDocumentComp,
+				 (xsltTransformFunction) xsltDocumentElem);
+    xsltRegisterExtModuleElement((const xmlChar *) "document",
+				 XSLT_XT_NAMESPACE,
+				 xsltDocumentComp,
+				 (xsltTransformFunction) xsltDocumentElem);
+    xsltRegisterExtModuleElement((const xmlChar *) "document",
+				 XSLT_NAMESPACE,
+				 xsltDocumentComp,
+				 (xsltTransformFunction) xsltDocumentElem);
+}
diff --git a/libxslt/extra.h b/libxslt/extra.h
new file mode 100644
index 0000000..59e932b
--- /dev/null
+++ b/libxslt/extra.h
@@ -0,0 +1,80 @@
+/*
+ * Summary: interface for the non-standard features
+ * Description: implement some extension outside the XSLT namespace
+ *              but not EXSLT with is in a different library.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_EXTRA_H__
+#define __XML_XSLT_EXTRA_H__
+
+#include <libxml/xpath.h>
+#include "xsltexports.h"
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * XSLT_LIBXSLT_NAMESPACE:
+ *
+ * This is the libxslt namespace for specific extensions.
+ */
+#define XSLT_LIBXSLT_NAMESPACE ((xmlChar *) "http://xmlsoft.org/XSLT/namespace")
+
+/**
+ * XSLT_SAXON_NAMESPACE:
+ *
+ * This is Michael Kay's Saxon processor namespace for extensions.
+ */
+#define XSLT_SAXON_NAMESPACE ((xmlChar *) "http://icl.com/saxon")
+
+/**
+ * XSLT_XT_NAMESPACE:
+ *
+ * This is James Clark's XT processor namespace for extensions.
+ */
+#define XSLT_XT_NAMESPACE ((xmlChar *) "http://www.jclark.com/xt")
+
+/**
+ * XSLT_XALAN_NAMESPACE:
+ *
+ * This is the Apache project XALAN processor namespace for extensions.
+ */
+#define XSLT_XALAN_NAMESPACE ((xmlChar *)	\
+	                        "org.apache.xalan.xslt.extensions.Redirect")
+
+/**
+ * XSLT_NORM_SAXON_NAMESPACE:
+ *
+ * This is Norm's namespace for SAXON extensions.
+ */
+#define XSLT_NORM_SAXON_NAMESPACE ((xmlChar *)	\
+	"http://nwalsh.com/xslt/ext/com.nwalsh.saxon.CVS")
+
+
+XSLTPUBFUN void XSLTCALL
+		xsltFunctionNodeSet	(xmlXPathParserContextPtr ctxt,
+					 int nargs);
+XSLTPUBFUN void XSLTCALL		
+		xsltDebug		(xsltTransformContextPtr ctxt,
+					 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+
+
+XSLTPUBFUN void XSLTCALL		
+		xsltRegisterExtras	(xsltTransformContextPtr ctxt);
+XSLTPUBFUN void XSLTCALL		
+		xsltRegisterAllExtras	(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_EXTRA_H__ */
+
diff --git a/libxslt/functions.c b/libxslt/functions.c
new file mode 100644
index 0000000..4720c7a
--- /dev/null
+++ b/libxslt/functions.c
@@ -0,0 +1,975 @@
+/*
+ * functions.c: Implementation of the XSLT extra functions
+ *
+ * Reference:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ * Bjorn Reese <breese@users.sourceforge.net> for number formatting
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+#include <libxml/hash.h>
+#include <libxml/xmlerror.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/parserInternals.h>
+#include <libxml/uri.h>
+#include <libxml/xpointer.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "functions.h"
+#include "extensions.h"
+#include "numbersInternals.h"
+#include "keys.h"
+#include "documents.h"
+
+#ifdef WITH_XSLT_DEBUG
+#define WITH_XSLT_DEBUG_FUNCTION
+#endif
+
+/*
+ * Some versions of DocBook XSL use the vendor string to detect
+ * supporting chunking, this is a workaround to be considered
+ * in the list of decent XSLT processors <grin/>
+ */
+#define DOCBOOK_XSL_HACK
+
+/**
+ * xsltXPathFunctionLookup:
+ * @ctxt:  a void * but the XSLT transformation context actually
+ * @name:  the function name
+ * @ns_uri:  the function namespace URI
+ *
+ * This is the entry point when a function is needed by the XPath
+ * interpretor.
+ *
+ * Returns the callback function or NULL if not found
+ */
+xmlXPathFunction
+xsltXPathFunctionLookup (xmlXPathContextPtr ctxt,
+			 const xmlChar *name, const xmlChar *ns_uri) {
+    xmlXPathFunction ret;
+
+    if ((ctxt == NULL) || (name == NULL) || (ns_uri == NULL))
+	return (NULL);
+
+#ifdef WITH_XSLT_DEBUG_FUNCTION
+    xsltGenericDebug(xsltGenericDebugContext,
+            "Lookup function {%s}%s\n", ns_uri, name);
+#endif
+
+    /* give priority to context-level functions */
+    /*
+    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
+    */
+    XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
+
+    if (ret == NULL)
+	ret = xsltExtModuleFunctionLookup(name, ns_uri);
+
+#ifdef WITH_XSLT_DEBUG_FUNCTION
+    if (ret != NULL)
+        xsltGenericDebug(xsltGenericDebugContext,
+            "found function %s\n", name);
+#endif
+    return(ret);
+}
+
+
+/************************************************************************
+ *									*
+ *			Module interfaces				*
+ *									*
+ ************************************************************************/
+
+static void
+xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
+{
+    xsltTransformContextPtr tctxt;
+    xmlURIPtr uri;
+    xmlChar *fragment;
+    xsltDocumentPtr idoc; /* document info */
+    xmlDocPtr doc;
+    xmlXPathContextPtr xptrctxt = NULL;
+    xmlXPathObjectPtr resObj = NULL;
+
+    tctxt = xsltXPathGetTransformContext(ctxt);
+    if (tctxt == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+	    "document() : internal error tctxt == NULL\n");
+	valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+	return;
+    } 
+	
+    uri = xmlParseURI((const char *) URI);
+    if (uri == NULL) {
+	xsltTransformError(tctxt, NULL, NULL,
+	    "document() : failed to parse URI\n");
+	valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+	return;
+    } 
+    
+    /*
+     * check for and remove fragment identifier
+     */
+    fragment = (xmlChar *)uri->fragment;
+    if (fragment != NULL) {
+        xmlChar *newURI;
+	uri->fragment = NULL;
+	newURI = xmlSaveUri(uri);
+	idoc = xsltLoadDocument(tctxt, newURI);
+	xmlFree(newURI);
+    } else
+	idoc = xsltLoadDocument(tctxt, URI);
+    xmlFreeURI(uri);
+    
+    if (idoc == NULL) {
+	if ((URI == NULL) ||
+	    (URI[0] == '#') ||
+	    ((tctxt->style->doc != NULL) &&
+	    (xmlStrEqual(tctxt->style->doc->URL, URI)))) 
+	{
+	    /*
+	    * This selects the stylesheet's doc itself.
+	    */
+	    doc = tctxt->style->doc;
+	} else {
+	    valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+
+	    if (fragment != NULL)
+		xmlFree(fragment);
+
+	    return;
+	}
+    } else
+	doc = idoc->doc;
+
+    if (fragment == NULL) {
+	valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc));
+	return;
+    }
+	
+    /* use XPointer of HTML location for fragment ID */
+#ifdef LIBXML_XPTR_ENABLED
+    xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
+    if (xptrctxt == NULL) {
+	xsltTransformError(tctxt, NULL, NULL,
+	    "document() : internal error xptrctxt == NULL\n");
+	goto out_fragment;
+    }
+
+    resObj = xmlXPtrEval(fragment, xptrctxt);
+    xmlXPathFreeContext(xptrctxt);
+#endif
+    xmlFree(fragment);	
+
+    if (resObj == NULL)
+	goto out_fragment;
+	
+    switch (resObj->type) {
+	case XPATH_NODESET:
+	    break;
+	case XPATH_UNDEFINED:
+	case XPATH_BOOLEAN:
+	case XPATH_NUMBER:
+	case XPATH_STRING:
+	case XPATH_POINT:
+	case XPATH_USERS:
+	case XPATH_XSLT_TREE:
+	case XPATH_RANGE:
+	case XPATH_LOCATIONSET:
+	    xsltTransformError(tctxt, NULL, NULL,
+		"document() : XPointer does not select a node set: #%s\n", 
+		fragment);
+	goto out_object;
+    }
+    
+    valuePush(ctxt, resObj);
+    return;
+
+out_object:
+    xmlXPathFreeObject(resObj);
+
+out_fragment:
+    valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+}
+
+/**
+ * xsltDocumentFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the document() XSLT function
+ *   node-set document(object, node-set?)
+ */
+void
+xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
+{
+    xmlXPathObjectPtr obj, obj2 = NULL;
+    xmlChar *base = NULL, *URI;
+
+
+    if ((nargs < 1) || (nargs > 2)) {
+        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+                         "document() : invalid number of args %d\n",
+                         nargs);
+        ctxt->error = XPATH_INVALID_ARITY;
+        return;
+    }
+    if (ctxt->value == NULL) {
+        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+                         "document() : invalid arg value\n");
+        ctxt->error = XPATH_INVALID_TYPE;
+        return;
+    }
+
+    if (nargs == 2) {
+        if (ctxt->value->type != XPATH_NODESET) {
+            xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+                             "document() : invalid arg expecting a nodeset\n");
+            ctxt->error = XPATH_INVALID_TYPE;
+            return;
+        }
+
+        obj2 = valuePop(ctxt);
+    }
+
+    if (ctxt->value->type == XPATH_NODESET) {
+        int i;
+        xmlXPathObjectPtr newobj, ret;
+
+        obj = valuePop(ctxt);
+        ret = xmlXPathNewNodeSet(NULL);
+
+        if (obj->nodesetval) {
+            for (i = 0; i < obj->nodesetval->nodeNr; i++) {
+                valuePush(ctxt,
+                          xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
+                xmlXPathStringFunction(ctxt, 1);
+                if (nargs == 2) {
+                    valuePush(ctxt, xmlXPathObjectCopy(obj2));
+                } else {
+                    valuePush(ctxt,
+                              xmlXPathNewNodeSet(obj->nodesetval->
+                                                 nodeTab[i]));
+                }
+                xsltDocumentFunction(ctxt, 2);
+                newobj = valuePop(ctxt);
+                ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
+                                                       newobj->nodesetval);
+                xmlXPathFreeObject(newobj);
+            }
+        }
+
+        xmlXPathFreeObject(obj);
+        if (obj2 != NULL)
+            xmlXPathFreeObject(obj2);
+        valuePush(ctxt, ret);
+        return;
+    }
+    /*
+     * Make sure it's converted to a string
+     */
+    xmlXPathStringFunction(ctxt, 1);
+    if (ctxt->value->type != XPATH_STRING) {
+        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+                         "document() : invalid arg expecting a string\n");
+        ctxt->error = XPATH_INVALID_TYPE;
+        if (obj2 != NULL)
+            xmlXPathFreeObject(obj2);
+        return;
+    }
+    obj = valuePop(ctxt);
+    if (obj->stringval == NULL) {
+        valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+    } else {
+        if ((obj2 != NULL) && (obj2->nodesetval != NULL) &&
+            (obj2->nodesetval->nodeNr > 0) &&
+            IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) {
+            xmlNodePtr target;
+
+            target = obj2->nodesetval->nodeTab[0];
+            if ((target->type == XML_ATTRIBUTE_NODE) ||
+	        (target->type == XML_PI_NODE)) {
+                target = ((xmlAttrPtr) target)->parent;
+            }
+            base = xmlNodeGetBase(target->doc, target);
+        } else {
+            xsltTransformContextPtr tctxt;
+
+            tctxt = xsltXPathGetTransformContext(ctxt);
+            if ((tctxt != NULL) && (tctxt->inst != NULL)) {
+                base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst);
+            } else if ((tctxt != NULL) && (tctxt->style != NULL) &&
+                       (tctxt->style->doc != NULL)) {
+                base = xmlNodeGetBase(tctxt->style->doc,
+                                      (xmlNodePtr) tctxt->style->doc);
+            }
+        }
+        URI = xmlBuildURI(obj->stringval, base);
+        if (base != NULL)
+            xmlFree(base);
+        if (URI == NULL) {
+            valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+        } else {
+	    xsltDocumentFunctionLoadDocument( ctxt, URI );
+	    xmlFree(URI);
+	}
+    }
+    xmlXPathFreeObject(obj);
+    if (obj2 != NULL)
+        xmlXPathFreeObject(obj2);
+}
+
+/**
+ * xsltKeyFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the key() XSLT function
+ *   node-set key(string, object)
+ */
+void
+xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){    
+    xmlXPathObjectPtr obj1, obj2;    
+    
+    if (nargs != 2) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+		"key() : expects two arguments\n");
+	ctxt->error = XPATH_INVALID_ARITY;
+	return;
+    }    
+
+    /*
+    * Get the key's value.
+    */
+    obj2 = valuePop(ctxt);
+    xmlXPathStringFunction(ctxt, 1);
+    if ((obj2 == NULL) ||
+	(ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+	    "key() : invalid arg expecting a string\n");
+	ctxt->error = XPATH_INVALID_TYPE;
+	xmlXPathFreeObject(obj2);
+
+	return;
+    }
+    /*
+    * Get the key's name.
+    */
+    obj1 = valuePop(ctxt);    
+
+    if ((obj2->type == XPATH_NODESET) || (obj2->type == XPATH_XSLT_TREE)) {
+	int i;
+	xmlXPathObjectPtr newobj, ret;
+
+	ret = xmlXPathNewNodeSet(NULL);
+
+	if (obj2->nodesetval != NULL) {
+	    for (i = 0; i < obj2->nodesetval->nodeNr; i++) {
+		valuePush(ctxt, xmlXPathObjectCopy(obj1));
+		valuePush(ctxt,
+			  xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i]));
+		xmlXPathStringFunction(ctxt, 1);
+		xsltKeyFunction(ctxt, 2);
+		newobj = valuePop(ctxt);
+		ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
+						       newobj->nodesetval);
+		xmlXPathFreeObject(newobj);
+	    }
+	}
+	valuePush(ctxt, ret);
+    } else {
+	xmlNodeSetPtr nodelist = NULL;
+	xmlChar *key = NULL, *value;
+	const xmlChar *keyURI;
+	xsltTransformContextPtr tctxt;   
+	xmlChar *qname, *prefix;
+	xmlXPathContextPtr xpctxt = ctxt->context;
+	xmlNodePtr tmpNode = NULL;
+	xsltDocumentPtr oldDocInfo;
+
+	tctxt = xsltXPathGetTransformContext(ctxt);
+
+	oldDocInfo = tctxt->document;
+
+	if (xpctxt->node == NULL) {
+	    xsltTransformError(tctxt, NULL, tctxt->inst,
+		"Internal error in xsltKeyFunction(): "
+		"The context node is not set on the XPath context.\n");
+	    tctxt->state = XSLT_STATE_STOPPED;
+	    goto error;
+	}	
+	/*
+	 * Get the associated namespace URI if qualified name
+	 */
+	qname = obj1->stringval;
+	key = xmlSplitQName2(qname, &prefix);
+	if (key == NULL) {
+	    key = xmlStrdup(obj1->stringval);
+	    keyURI = NULL;
+	    if (prefix != NULL)
+		xmlFree(prefix);
+	} else {
+	    if (prefix != NULL) {
+		keyURI = xmlXPathNsLookup(xpctxt, prefix);
+		if (keyURI == NULL) {
+		    xsltTransformError(tctxt, NULL, tctxt->inst,
+			"key() : prefix %s is not bound\n", prefix);
+		    /*
+		    * TODO: Shouldn't we stop here?
+		    */
+		}
+		xmlFree(prefix);
+	    } else {
+		keyURI = NULL;
+	    }
+	}
+
+	/*
+	 * Force conversion of first arg to string
+	 */
+	valuePush(ctxt, obj2);
+	xmlXPathStringFunction(ctxt, 1);
+	if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
+	    xsltTransformError(tctxt, NULL, tctxt->inst,
+		"key() : invalid arg expecting a string\n");
+	    ctxt->error = XPATH_INVALID_TYPE;
+	    goto error;
+	}
+	obj2 = valuePop(ctxt);
+	value = obj2->stringval;
+	
+	/*
+	* We need to ensure that ctxt->document is available for
+	* xsltGetKey().
+	* First find the relevant doc, which is the context node's
+	* owner doc; using context->doc is not safe, since
+	* the doc could have been acquired via the document() function,
+	* or the doc might be a Result Tree Fragment.
+	* FUTURE INFO: In XSLT 2.0 the key() function takes an additional
+	* argument indicating the doc to use.
+	*/	
+	if (xpctxt->node->type == XML_NAMESPACE_DECL) {
+	    /*
+	    * REVISIT: This is a libxml hack! Check xpath.c for details.
+	    * The XPath module sets the owner element of a ns-node on
+	    * the ns->next field.
+	    */
+	    if ((((xmlNsPtr) xpctxt->node)->next != NULL) &&
+		(((xmlNsPtr) xpctxt->node)->next->type == XML_ELEMENT_NODE))
+	    {
+		tmpNode = (xmlNodePtr) ((xmlNsPtr) xpctxt->node)->next;
+	    }
+	} else
+	    tmpNode = xpctxt->node;
+
+	if ((tmpNode == NULL) || (tmpNode->doc == NULL)) {
+	    xsltTransformError(tctxt, NULL, tctxt->inst,
+		"Internal error in xsltKeyFunction(): "
+		"Couldn't get the doc of the XPath context node.\n");
+	    goto error;
+	}
+
+	if ((tctxt->document == NULL) ||
+	    (tctxt->document->doc != tmpNode->doc))
+	{	   
+	    if (tmpNode->doc->name && (tmpNode->doc->name[0] == ' ')) {
+		/*
+		* This is a Result Tree Fragment.
+		*/
+		if (tmpNode->doc->_private == NULL) {
+		    tmpNode->doc->_private = xsltNewDocument(tctxt, tmpNode->doc);
+		    if (tmpNode->doc->_private == NULL)
+			goto error;
+		}
+		tctxt->document = (xsltDocumentPtr) tmpNode->doc->_private;		
+	    } else {
+		/*
+		* May be the initial source doc or a doc acquired via the
+		* document() function.
+		*/
+		tctxt->document = xsltFindDocument(tctxt, tmpNode->doc);
+	    }
+	    if (tctxt->document == NULL) {
+		xsltTransformError(tctxt, NULL, tctxt->inst,
+		    "Internal error in xsltKeyFunction(): "
+		    "Could not get the document info of a context doc.\n");
+		tctxt->state = XSLT_STATE_STOPPED;
+		goto error;
+	    }
+	}
+	/*
+	* Get/compute the key value.
+	*/
+	nodelist = xsltGetKey(tctxt, key, keyURI, value);
+
+error:	
+	tctxt->document = oldDocInfo;
+	valuePush(ctxt, xmlXPathWrapNodeSet(
+	    xmlXPathNodeSetMerge(NULL, nodelist)));
+	if (key != NULL)
+	    xmlFree(key);
+    }    
+
+    if (obj1 != NULL)
+	xmlXPathFreeObject(obj1);
+    if (obj2 != NULL)
+	xmlXPathFreeObject(obj2);    
+}
+
+/**
+ * xsltUnparsedEntityURIFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the unparsed-entity-uri() XSLT function
+ *   string unparsed-entity-uri(string)
+ */
+void
+xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){
+    xmlXPathObjectPtr obj;
+    xmlChar *str;
+
+    if ((nargs != 1) || (ctxt->value == NULL)) {
+        xsltGenericError(xsltGenericErrorContext,
+		"unparsed-entity-uri() : expects one string arg\n");
+	ctxt->error = XPATH_INVALID_ARITY;
+	return;
+    }
+    obj = valuePop(ctxt);
+    if (obj->type != XPATH_STRING) {
+	obj = xmlXPathConvertString(obj);
+    }
+
+    str = obj->stringval;
+    if (str == NULL) {
+	valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
+    } else {
+	xmlEntityPtr entity;
+
+	entity = xmlGetDocEntity(ctxt->context->doc, str);
+	if (entity == NULL) {
+	    valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
+	} else {
+	    if (entity->URI != NULL)
+		valuePush(ctxt, xmlXPathNewString(entity->URI));
+	    else
+		valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
+	}
+    }
+    xmlXPathFreeObject(obj);
+}
+
+/**
+ * xsltFormatNumberFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the format-number() XSLT function
+ *   string format-number(number, string, string?)
+ */
+void
+xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
+{
+    xmlXPathObjectPtr numberObj = NULL;
+    xmlXPathObjectPtr formatObj = NULL;
+    xmlXPathObjectPtr decimalObj = NULL;
+    xsltStylesheetPtr sheet;
+    xsltDecimalFormatPtr formatValues;
+    xmlChar *result;
+    xsltTransformContextPtr tctxt;
+
+    tctxt = xsltXPathGetTransformContext(ctxt);
+    if (tctxt == NULL)
+	return;
+    sheet = tctxt->style;
+    if (sheet == NULL)
+	return;
+    formatValues = sheet->decimalFormat;
+    
+    switch (nargs) {
+    case 3:
+	CAST_TO_STRING;
+	decimalObj = valuePop(ctxt);
+	formatValues = xsltDecimalFormatGetByName(sheet, decimalObj->stringval);
+	if (formatValues == NULL) {
+	    xsltTransformError(tctxt, NULL, NULL,
+		    "format-number() : undeclared decimal format '%s'\n", 
+		    decimalObj->stringval);
+	}
+	/* Intentional fall-through */
+    case 2:
+	CAST_TO_STRING;
+	formatObj = valuePop(ctxt);
+	CAST_TO_NUMBER;
+	numberObj = valuePop(ctxt);
+	break;
+    default:
+	XP_ERROR(XPATH_INVALID_ARITY);
+    }
+
+    if (formatValues != NULL) {
+	if (xsltFormatNumberConversion(formatValues,
+				       formatObj->stringval,
+				       numberObj->floatval,
+				       &result) == XPATH_EXPRESSION_OK) {
+	    valuePush(ctxt, xmlXPathNewString(result));
+	    xmlFree(result);
+	}
+    }
+
+    xmlXPathFreeObject(numberObj);
+    xmlXPathFreeObject(formatObj);
+    xmlXPathFreeObject(decimalObj);
+}
+
+/**
+ * xsltGenerateIdFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the generate-id() XSLT function
+ *   string generate-id(node-set?)
+ */
+void
+xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){
+    xmlNodePtr cur = NULL;
+    unsigned long val;
+    xmlChar str[20];
+
+    if (nargs == 0) {
+	cur = ctxt->context->node;
+    } else if (nargs == 1) {
+	xmlXPathObjectPtr obj;
+	xmlNodeSetPtr nodelist;
+	int i, ret;
+
+	if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
+	    ctxt->error = XPATH_INVALID_TYPE;
+	    xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+		"generate-id() : invalid arg expecting a node-set\n");
+	    return;
+	}
+	obj = valuePop(ctxt);
+	nodelist = obj->nodesetval;
+	if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) {
+	    xmlXPathFreeObject(obj);
+	    valuePush(ctxt, xmlXPathNewCString(""));
+	    return;
+	}
+	cur = nodelist->nodeTab[0];
+	for (i = 1;i < nodelist->nodeNr;i++) {
+	    ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]);
+	    if (ret == -1)
+	        cur = nodelist->nodeTab[i];
+	}
+	xmlXPathFreeObject(obj);
+    } else {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+		"generate-id() : invalid number of args %d\n", nargs);
+	ctxt->error = XPATH_INVALID_ARITY;
+	return;
+    }
+    /*
+     * Okay this is ugly but should work, use the NodePtr address
+     * to forge the ID
+     */
+    val = (unsigned long)((char *)cur - (char *)0);
+    val /= sizeof(xmlNode);
+    sprintf((char *)str, "id%ld", val);
+    valuePush(ctxt, xmlXPathNewString(str));
+}
+
+/**
+ * xsltSystemPropertyFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the system-property() XSLT function
+ *   object system-property(string)
+ */
+void
+xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){
+    xmlXPathObjectPtr obj;
+    xmlChar *prefix, *name;
+    const xmlChar *nsURI = NULL;
+
+    if (nargs != 1) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+		"system-property() : expects one string arg\n");
+	ctxt->error = XPATH_INVALID_ARITY;
+	return;
+    }
+    if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+	    "system-property() : invalid arg expecting a string\n");
+	ctxt->error = XPATH_INVALID_TYPE;
+	return;
+    }
+    obj = valuePop(ctxt);
+    if (obj->stringval == NULL) {
+	valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
+    } else {
+	name = xmlSplitQName2(obj->stringval, &prefix);
+	if (name == NULL) {
+	    name = xmlStrdup(obj->stringval);
+	} else {
+	    nsURI = xmlXPathNsLookup(ctxt->context, prefix);
+	    if (nsURI == NULL) {
+		xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+		    "system-property() : prefix %s is not bound\n", prefix);
+	    }
+	}
+
+	if (xmlStrEqual(nsURI, XSLT_NAMESPACE)) {
+#ifdef DOCBOOK_XSL_HACK
+	    if (xmlStrEqual(name, (const xmlChar *)"vendor")) {
+		xsltStylesheetPtr sheet;
+		xsltTransformContextPtr tctxt;
+
+		tctxt = xsltXPathGetTransformContext(ctxt);
+		if ((tctxt != NULL) && (tctxt->inst != NULL) &&
+		    (xmlStrEqual(tctxt->inst->name, BAD_CAST "variable")) &&
+		    (tctxt->inst->parent != NULL) &&
+		    (xmlStrEqual(tctxt->inst->parent->name,
+				 BAD_CAST "template")))
+		    sheet = tctxt->style;
+		else
+		    sheet = NULL;
+		if ((sheet != NULL) && (sheet->doc != NULL) &&
+		    (sheet->doc->URL != NULL) &&
+		    (xmlStrstr(sheet->doc->URL,
+			       (const xmlChar *)"chunk") != NULL)) {
+		    valuePush(ctxt, xmlXPathNewString(
+			(const xmlChar *)"libxslt (SAXON 6.2 compatible)"));
+
+		} else {
+		    valuePush(ctxt, xmlXPathNewString(
+			(const xmlChar *)XSLT_DEFAULT_VENDOR));
+		}
+	    } else
+#else
+	    if (xmlStrEqual(name, (const xmlChar *)"vendor")) {
+		valuePush(ctxt, xmlXPathNewString(
+			  (const xmlChar *)XSLT_DEFAULT_VENDOR));
+	    } else
+#endif
+	    if (xmlStrEqual(name, (const xmlChar *)"version")) {
+		valuePush(ctxt, xmlXPathNewString(
+		    (const xmlChar *)XSLT_DEFAULT_VERSION));
+	    } else if (xmlStrEqual(name, (const xmlChar *)"vendor-url")) {
+		valuePush(ctxt, xmlXPathNewString(
+		    (const xmlChar *)XSLT_DEFAULT_URL));
+	    } else {
+		valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
+	    }
+	}
+	if (name != NULL)
+	    xmlFree(name);
+	if (prefix != NULL)
+	    xmlFree(prefix);
+    }
+    xmlXPathFreeObject(obj);
+}
+
+/**
+ * xsltElementAvailableFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the element-available() XSLT function
+ *   boolean element-available(string)
+ */
+void
+xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
+    xmlXPathObjectPtr obj;
+    xmlChar *prefix, *name;
+    const xmlChar *nsURI = NULL;
+    xsltTransformContextPtr tctxt;
+
+    if (nargs != 1) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+		"element-available() : expects one string arg\n");
+	ctxt->error = XPATH_INVALID_ARITY;
+	return;
+    }
+    xmlXPathStringFunction(ctxt, 1);
+    if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+	    "element-available() : invalid arg expecting a string\n");
+	ctxt->error = XPATH_INVALID_TYPE;
+	return;
+    }
+    obj = valuePop(ctxt);
+    tctxt = xsltXPathGetTransformContext(ctxt);
+    if (tctxt == NULL) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+		"element-available() : internal error tctxt == NULL\n");
+	xmlXPathFreeObject(obj);
+	valuePush(ctxt, xmlXPathNewBoolean(0));
+	return;
+    }
+
+
+    name = xmlSplitQName2(obj->stringval, &prefix);
+    if (name == NULL) {
+	xmlNsPtr ns;
+
+	name = xmlStrdup(obj->stringval);
+	ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL);
+	if (ns != NULL) nsURI = xmlStrdup(ns->href);
+    } else {
+	nsURI = xmlXPathNsLookup(ctxt->context, prefix);
+	if (nsURI == NULL) {
+	    xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+		"element-available() : prefix %s is not bound\n", prefix);
+	}
+    }
+
+    if (xsltExtElementLookup(tctxt, name, nsURI) != NULL) {
+	valuePush(ctxt, xmlXPathNewBoolean(1));
+    } else {
+	valuePush(ctxt, xmlXPathNewBoolean(0));
+    }
+
+    xmlXPathFreeObject(obj);
+    if (name != NULL)
+	xmlFree(name);
+    if (prefix != NULL)
+	xmlFree(prefix);
+}
+
+/**
+ * xsltFunctionAvailableFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the function-available() XSLT function
+ *   boolean function-available(string)
+ */
+void
+xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
+    xmlXPathObjectPtr obj;
+    xmlChar *prefix, *name;
+    const xmlChar *nsURI = NULL;
+
+    if (nargs != 1) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+		"function-available() : expects one string arg\n");
+	ctxt->error = XPATH_INVALID_ARITY;
+	return;
+    }
+    xmlXPathStringFunction(ctxt, 1);
+    if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+	    "function-available() : invalid arg expecting a string\n");
+	ctxt->error = XPATH_INVALID_TYPE;
+	return;
+    }
+    obj = valuePop(ctxt);
+
+    name = xmlSplitQName2(obj->stringval, &prefix);
+    if (name == NULL) {
+	name = xmlStrdup(obj->stringval);
+    } else {
+	nsURI = xmlXPathNsLookup(ctxt->context, prefix);
+	if (nsURI == NULL) {
+	    xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+		"function-available() : prefix %s is not bound\n", prefix);
+	}
+    }
+
+    if (xmlXPathFunctionLookupNS(ctxt->context, name, nsURI) != NULL) {
+	valuePush(ctxt, xmlXPathNewBoolean(1));
+    } else {
+	valuePush(ctxt, xmlXPathNewBoolean(0));
+    }
+
+    xmlXPathFreeObject(obj);
+    if (name != NULL)
+	xmlFree(name);
+    if (prefix != NULL)
+	xmlFree(prefix);
+}
+
+/**
+ * xsltCurrentFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the current() XSLT function
+ *   node-set current()
+ */
+static void
+xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){
+    xsltTransformContextPtr tctxt;
+
+    if (nargs != 0) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+		"current() : function uses no argument\n");
+	ctxt->error = XPATH_INVALID_ARITY;
+	return;
+    }
+    tctxt = xsltXPathGetTransformContext(ctxt);
+    if (tctxt == NULL) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+		"current() : internal error tctxt == NULL\n");
+	valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+    } else {
+	valuePush(ctxt, xmlXPathNewNodeSet(tctxt->node)); /* current */
+    }
+}
+
+/************************************************************************
+ * 									*
+ * 		Registration of XSLT and libxslt functions		*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltRegisterAllFunctions:
+ * @ctxt:  the XPath context
+ *
+ * Registers all default XSLT functions in this context
+ */
+void
+xsltRegisterAllFunctions(xmlXPathContextPtr ctxt)
+{
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "current",
+                         xsltCurrentFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "document",
+                         xsltDocumentFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "key", xsltKeyFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "unparsed-entity-uri",
+                         xsltUnparsedEntityURIFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "format-number",
+                         xsltFormatNumberFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "generate-id",
+                         xsltGenerateIdFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "system-property",
+                         xsltSystemPropertyFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "element-available",
+                         xsltElementAvailableFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *) "function-available",
+                         xsltFunctionAvailableFunction);
+}
diff --git a/libxslt/functions.h b/libxslt/functions.h
new file mode 100644
index 0000000..caa4941
--- /dev/null
+++ b/libxslt/functions.h
@@ -0,0 +1,78 @@
+/*
+ * Summary: interface for the XSLT functions not from XPath
+ * Description: a set of extra functions coming from XSLT but not in XPath
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard and Bjorn Reese <breese@users.sourceforge.net>
+ */
+
+#ifndef __XML_XSLT_FUNCTIONS_H__
+#define __XML_XSLT_FUNCTIONS_H__
+
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include "xsltexports.h"
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * XSLT_REGISTER_FUNCTION_LOOKUP:
+ *
+ * Registering macro, not general purpose at all but used in different modules.
+ */
+#define XSLT_REGISTER_FUNCTION_LOOKUP(ctxt)			\
+    xmlXPathRegisterFuncLookup((ctxt)->xpathCtxt,		\
+	(xmlXPathFuncLookupFunc) xsltXPathFunctionLookup,	\
+	(void *)(ctxt->xpathCtxt));
+
+XSLTPUBFUN xmlXPathFunction XSLTCALL
+	xsltXPathFunctionLookup		(xmlXPathContextPtr ctxt,
+					 const xmlChar *name,
+					 const xmlChar *ns_uri);
+
+/*
+ * Interfaces for the functions implementations.
+ */
+
+XSLTPUBFUN void XSLTCALL	
+	xsltDocumentFunction		(xmlXPathParserContextPtr ctxt,
+					 int nargs);
+XSLTPUBFUN void XSLTCALL	
+	xsltKeyFunction			(xmlXPathParserContextPtr ctxt,
+					 int nargs);
+XSLTPUBFUN void XSLTCALL	
+	xsltUnparsedEntityURIFunction	(xmlXPathParserContextPtr ctxt,
+					 int nargs);
+XSLTPUBFUN void XSLTCALL	
+	xsltFormatNumberFunction	(xmlXPathParserContextPtr ctxt,
+					 int nargs);
+XSLTPUBFUN void XSLTCALL	
+	xsltGenerateIdFunction		(xmlXPathParserContextPtr ctxt,
+					 int nargs);
+XSLTPUBFUN void XSLTCALL	
+	xsltSystemPropertyFunction	(xmlXPathParserContextPtr ctxt,
+					 int nargs);
+XSLTPUBFUN void XSLTCALL	
+	xsltElementAvailableFunction	(xmlXPathParserContextPtr ctxt,
+					 int nargs);
+XSLTPUBFUN void XSLTCALL	
+	xsltFunctionAvailableFunction	(xmlXPathParserContextPtr ctxt,
+					 int nargs);
+
+/*
+ * And the registration
+ */
+
+XSLTPUBFUN void XSLTCALL	
+	xsltRegisterAllFunctions	(xmlXPathContextPtr ctxt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_FUNCTIONS_H__ */
+
diff --git a/libxslt/imports.c b/libxslt/imports.c
new file mode 100644
index 0000000..23538ab
--- /dev/null
+++ b/libxslt/imports.c
@@ -0,0 +1,419 @@
+/*
+ * imports.c: Implementation of the XSLT imports
+ *
+ * Reference:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+#ifdef HAVE_NAN_H
+#include <nan.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/hash.h>
+#include <libxml/xmlerror.h>
+#include <libxml/uri.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "preproc.h"
+#include "imports.h"
+#include "documents.h"
+#include "security.h"
+#include "pattern.h"
+
+
+/************************************************************************
+ *									*
+ *			Module interfaces				*
+ *									*
+ ************************************************************************/
+/**
+ * xsltFixImportedCompSteps:
+ * @master: the "master" stylesheet
+ * @style: the stylesheet being imported by the master
+ *
+ * normalize the comp steps for the stylesheet being imported
+ * by the master, together with any imports within that. 
+ *
+ */
+static void xsltFixImportedCompSteps(xsltStylesheetPtr master, 
+			xsltStylesheetPtr style) {
+    xsltStylesheetPtr res;
+    xmlHashScan(style->templatesHash,
+	            (xmlHashScanner) xsltNormalizeCompSteps, master);
+    master->extrasNr += style->extrasNr;
+    for (res = style->imports; res != NULL; res = res->next) {
+        xsltFixImportedCompSteps(master, res);
+    }
+}
+
+/**
+ * xsltParseStylesheetImport:
+ * @style:  the XSLT stylesheet
+ * @cur:  the import element
+ *
+ * parse an XSLT stylesheet import element
+ *
+ * Returns 0 in case of success -1 in case of failure.
+ */
+
+int
+xsltParseStylesheetImport(xsltStylesheetPtr style, xmlNodePtr cur) {
+    int ret = -1;
+    xmlDocPtr import = NULL;
+    xmlChar *base = NULL;
+    xmlChar *uriRef = NULL;
+    xmlChar *URI = NULL;
+    xsltStylesheetPtr res;
+    xsltSecurityPrefsPtr sec;
+
+    if ((cur == NULL) || (style == NULL))
+	return (ret);
+
+    uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL);
+    if (uriRef == NULL) {
+	xsltTransformError(NULL, style, cur,
+	    "xsl:import : missing href attribute\n");
+	goto error;
+    }
+
+    base = xmlNodeGetBase(style->doc, cur);
+    URI = xmlBuildURI(uriRef, base);
+    if (URI == NULL) {
+	xsltTransformError(NULL, style, cur,
+	    "xsl:import : invalid URI reference %s\n", uriRef);
+	goto error;
+    }
+
+    res = style;
+    while (res != NULL) {
+        if (res->doc == NULL)
+	    break;
+	if (xmlStrEqual(res->doc->URL, URI)) {
+	    xsltTransformError(NULL, style, cur,
+	       "xsl:import : recursion detected on imported URL %s\n", URI);
+	    goto error;
+	}
+	res = res->parent;
+    }
+
+    /*
+     * Security framework check
+     */
+    sec = xsltGetDefaultSecurityPrefs();
+    if (sec != NULL) {
+	int secres;
+
+	secres = xsltCheckRead(sec, NULL, URI);
+	if (secres == 0) {
+	    xsltTransformError(NULL, NULL, NULL,
+		 "xsl:import: read rights for %s denied\n",
+			     URI);
+	    goto error;
+	}
+    }
+
+    import = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,
+                                  (void *) style, XSLT_LOAD_STYLESHEET);
+    if (import == NULL) {
+	xsltTransformError(NULL, style, cur,
+	    "xsl:import : unable to load %s\n", URI);
+	goto error;
+    }
+
+    res = xsltParseStylesheetImportedDoc(import, style);
+    if (res != NULL) {
+	res->next = style->imports;
+	style->imports = res;
+	if (style->parent == NULL) {
+	    xsltFixImportedCompSteps(style, res);
+	}
+	ret = 0;
+    } else {
+	xmlFreeDoc(import);
+	}
+
+error:
+    if (uriRef != NULL)
+	xmlFree(uriRef);
+    if (base != NULL)
+	xmlFree(base);
+    if (URI != NULL)
+	xmlFree(URI);
+
+    return (ret);
+}
+
+/**
+ * xsltParseStylesheetInclude:
+ * @style:  the XSLT stylesheet
+ * @cur:  the include node
+ *
+ * parse an XSLT stylesheet include element
+ *
+ * Returns 0 in case of success -1 in case of failure
+ */
+
+int
+xsltParseStylesheetInclude(xsltStylesheetPtr style, xmlNodePtr cur) {
+    int ret = -1;
+    xmlDocPtr oldDoc;
+    xmlChar *base = NULL;
+    xmlChar *uriRef = NULL;
+    xmlChar *URI = NULL;
+    xsltStylesheetPtr result;
+    xsltDocumentPtr include;
+    xsltDocumentPtr docptr;
+    int oldNopreproc;
+
+    if ((cur == NULL) || (style == NULL))
+	return (ret);
+
+    uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL);
+    if (uriRef == NULL) {
+	xsltTransformError(NULL, style, cur,
+	    "xsl:include : missing href attribute\n");
+	goto error;
+    }
+
+    base = xmlNodeGetBase(style->doc, cur);
+    URI = xmlBuildURI(uriRef, base);
+    if (URI == NULL) {
+	xsltTransformError(NULL, style, cur,
+	    "xsl:include : invalid URI reference %s\n", uriRef);
+	goto error;
+    }
+
+    /*
+     * in order to detect recursion, we check all previously included
+     * stylesheets.
+     */
+    docptr = style->includes;
+    while (docptr != NULL) {
+        if (xmlStrEqual(docptr->doc->URL, URI)) {
+	    xsltTransformError(NULL, style, cur,
+	        "xsl:include : recursion detected on included URL %s\n", URI);
+	    goto error;
+	}
+	docptr = docptr->includes;
+    }
+
+    include = xsltLoadStyleDocument(style, URI);
+    if (include == NULL) {
+	xsltTransformError(NULL, style, cur,
+	    "xsl:include : unable to load %s\n", URI);
+	goto error;
+    }
+#ifdef XSLT_REFACTORED    
+    if (IS_XSLT_ELEM_FAST(cur) && (cur->psvi != NULL)) {
+	((xsltStyleItemIncludePtr) cur->psvi)->include = include;
+    } else {
+	xsltTransformError(NULL, style, cur,
+	    "Internal error: (xsltParseStylesheetInclude) "
+	    "The xsl:include element was not compiled.\n", URI);
+	style->errors++;
+    }
+#endif
+    oldDoc = style->doc;
+    style->doc = include->doc;
+    /* chain to stylesheet for recursion checking */
+    include->includes = style->includes;
+    style->includes = include;
+    oldNopreproc = style->nopreproc;
+    style->nopreproc = include->preproc;
+    /*
+    * TODO: This will change some values of the
+    *  including stylesheet with every included module
+    *  (e.g. excluded-result-prefixes)
+    *  We need to strictly seperate such stylesheet-owned values.
+    */
+    result = xsltParseStylesheetProcess(style, include->doc);
+    style->nopreproc = oldNopreproc;
+    include->preproc = 1;
+    style->includes = include->includes;
+    style->doc = oldDoc;
+    if (result == NULL) {
+	ret = -1;
+	goto error;
+    }
+    ret = 0;
+
+error:
+    if (uriRef != NULL)
+	xmlFree(uriRef);
+    if (base != NULL)
+	xmlFree(base);
+    if (URI != NULL)
+	xmlFree(URI);
+
+    return (ret);
+}
+
+/**
+ * xsltNextImport:
+ * @cur:  the current XSLT stylesheet
+ *
+ * Find the next stylesheet in import precedence.
+ *
+ * Returns the next stylesheet or NULL if it was the last one
+ */
+
+xsltStylesheetPtr
+xsltNextImport(xsltStylesheetPtr cur) {
+    if (cur == NULL)
+	return(NULL);
+    if (cur->imports != NULL)
+	return(cur->imports);
+    if (cur->next != NULL)
+	return(cur->next) ;
+    do {
+	cur = cur->parent;
+	if (cur == NULL) break;
+	if (cur->next != NULL) return(cur->next);
+    } while (cur != NULL);
+    return(cur);
+}
+
+/**
+ * xsltNeedElemSpaceHandling:
+ * @ctxt:  an XSLT transformation context
+ *
+ * Checks whether that stylesheet requires white-space stripping
+ *
+ * Returns 1 if space should be stripped, 0 if not
+ */
+
+int
+xsltNeedElemSpaceHandling(xsltTransformContextPtr ctxt) {
+    xsltStylesheetPtr style;
+
+    if (ctxt == NULL)
+	return(0);
+    style = ctxt->style;
+    while (style != NULL) {
+	if (style->stripSpaces != NULL)
+	    return(1);
+	style = xsltNextImport(style);
+    }
+    return(0);
+}
+
+/**
+ * xsltFindElemSpaceHandling:
+ * @ctxt:  an XSLT transformation context
+ * @node:  an XML node
+ *
+ * Find strip-space or preserve-space informations for an element
+ * respect the import precedence or the wildcards
+ *
+ * Returns 1 if space should be stripped, 0 if not, and 2 if everything
+ *         should be CDTATA wrapped.
+ */
+
+int
+xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt, xmlNodePtr node) {
+    xsltStylesheetPtr style;
+    const xmlChar *val;
+
+    if ((ctxt == NULL) || (node == NULL))
+	return(0);
+    style = ctxt->style;
+    while (style != NULL) {
+	if (node->ns != NULL) {
+	    val = (const xmlChar *)
+	      xmlHashLookup2(style->stripSpaces, node->name, node->ns->href);
+            if (val == NULL) {
+                val = (const xmlChar *)
+                    xmlHashLookup2(style->stripSpaces, BAD_CAST "*",
+                                   node->ns->href);
+            }
+	} else {
+	    val = (const xmlChar *)
+		  xmlHashLookup2(style->stripSpaces, node->name, NULL);
+	}
+	if (val != NULL) {
+	    if (xmlStrEqual(val, (xmlChar *) "strip"))
+		return(1);
+	    if (xmlStrEqual(val, (xmlChar *) "preserve"))
+		return(0);
+	}
+	if (style->stripAll == 1)
+	    return(1);
+	if (style->stripAll == -1)
+	    return(0);
+
+	style = xsltNextImport(style);
+    }
+    return(0);
+}
+
+/**
+ * xsltFindTemplate:
+ * @ctxt:  an XSLT transformation context
+ * @name: the template name
+ * @nameURI: the template name URI
+ *
+ * Finds the named template, apply import precedence rule.
+ * REVISIT TODO: We'll change the nameURI fields of
+ *  templates to be in the string dict, so if the
+ *  specified @nameURI is in the same dict, then use pointer
+ *  comparison. Check if this can be done in a sane way.
+ *  Maybe this function is not needed internally at
+ *  transformation-time if we hard-wire the called templates
+ *  to the caller.
+ *
+ * Returns the xsltTemplatePtr or NULL if not found
+ */
+xsltTemplatePtr
+xsltFindTemplate(xsltTransformContextPtr ctxt, const xmlChar *name,
+	         const xmlChar *nameURI) {
+    xsltTemplatePtr cur;
+    xsltStylesheetPtr style;
+
+    if ((ctxt == NULL) || (name == NULL))
+	return(NULL);
+    style = ctxt->style;
+    while (style != NULL) {
+	cur = style->templates;
+	while (cur != NULL) {
+	    if (xmlStrEqual(name, cur->name)) {
+		if (((nameURI == NULL) && (cur->nameURI == NULL)) ||
+		    ((nameURI != NULL) && (cur->nameURI != NULL) &&
+		     (xmlStrEqual(nameURI, cur->nameURI)))) {
+		    return(cur);
+		}
+	    }
+	    cur = cur->next;
+	}
+
+	style = xsltNextImport(style);
+    }
+    return(NULL);
+}
+
diff --git a/libxslt/imports.h b/libxslt/imports.h
new file mode 100644
index 0000000..38656f1
--- /dev/null
+++ b/libxslt/imports.h
@@ -0,0 +1,75 @@
+/*
+ * Summary: interface for the XSLT import support
+ * Description: macros and fuctions needed to implement and
+ *              access the import tree
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_IMPORTS_H__
+#define __XML_XSLT_IMPORTS_H__
+
+#include <libxml/tree.h>
+#include "xsltexports.h"
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * XSLT_GET_IMPORT_PTR:
+ *
+ * A macro to import pointers from the stylesheet cascading order.
+ */
+#define XSLT_GET_IMPORT_PTR(res, style, name) {			\
+    xsltStylesheetPtr st = style;				\
+    res = NULL;							\
+    while (st != NULL) {					\
+	if (st->name != NULL) { res = st->name; break; }	\
+	st = xsltNextImport(st);				\
+    }}
+
+/**
+ * XSLT_GET_IMPORT_INT:
+ *
+ * A macro to import intergers from the stylesheet cascading order.
+ */
+#define XSLT_GET_IMPORT_INT(res, style, name) {			\
+    xsltStylesheetPtr st = style;				\
+    res = -1;							\
+    while (st != NULL) {					\
+	if (st->name != -1) { res = st->name; break; }	\
+	st = xsltNextImport(st);				\
+    }}
+
+/*
+ * Module interfaces
+ */
+XSLTPUBFUN int XSLTCALL			
+			xsltParseStylesheetImport(xsltStylesheetPtr style,
+						  xmlNodePtr cur);
+XSLTPUBFUN int XSLTCALL			
+			xsltParseStylesheetInclude
+						 (xsltStylesheetPtr style,
+						  xmlNodePtr cur);
+XSLTPUBFUN xsltStylesheetPtr XSLTCALL	
+			xsltNextImport		 (xsltStylesheetPtr style);
+XSLTPUBFUN int XSLTCALL			
+			xsltNeedElemSpaceHandling(xsltTransformContextPtr ctxt);
+XSLTPUBFUN int XSLTCALL			
+			xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt,
+						  xmlNodePtr node);
+XSLTPUBFUN xsltTemplatePtr XSLTCALL		
+			xsltFindTemplate	 (xsltTransformContextPtr ctxt,
+						  const xmlChar *name,
+						  const xmlChar *nameURI);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_IMPORTS_H__ */
+
diff --git a/libxslt/keys.c b/libxslt/keys.c
new file mode 100644
index 0000000..d28aea6
--- /dev/null
+++ b/libxslt/keys.c
@@ -0,0 +1,919 @@
+/*
+ * keys.c: Implemetation of the keys support
+ *
+ * Reference:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+#include <libxml/hash.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parserInternals.h>
+#include <libxml/xpathInternals.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "imports.h"
+#include "templates.h"
+#include "keys.h"
+
+#ifdef WITH_XSLT_DEBUG
+#define WITH_XSLT_DEBUG_KEYS
+#endif
+
+static int
+xsltInitDocKeyTable(xsltTransformContextPtr ctxt, const xmlChar *name,
+                    const xmlChar *nameURI);
+
+/************************************************************************
+ * 									*
+ * 			Type functions 					*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltNewKeyDef:
+ * @name:  the key name or NULL
+ * @nameURI:  the name URI or NULL
+ *
+ * Create a new XSLT KeyDef
+ *
+ * Returns the newly allocated xsltKeyDefPtr or NULL in case of error
+ */
+static xsltKeyDefPtr
+xsltNewKeyDef(const xmlChar *name, const xmlChar *nameURI) {
+    xsltKeyDefPtr cur;
+
+    cur = (xsltKeyDefPtr) xmlMalloc(sizeof(xsltKeyDef));
+    if (cur == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+		"xsltNewKeyDef : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltKeyDef));
+    if (name != NULL)
+	cur->name = xmlStrdup(name);
+    if (nameURI != NULL)
+	cur->nameURI = xmlStrdup(nameURI);
+    cur->nsList = NULL;
+    return(cur);
+}
+
+/**
+ * xsltFreeKeyDef:
+ * @keyd:  an XSLT key definition
+ *
+ * Free up the memory allocated by @keyd
+ */
+static void
+xsltFreeKeyDef(xsltKeyDefPtr keyd) {
+    if (keyd == NULL)
+	return;
+    if (keyd->comp != NULL)
+	xmlXPathFreeCompExpr(keyd->comp);
+    if (keyd->usecomp != NULL)
+	xmlXPathFreeCompExpr(keyd->usecomp);
+    if (keyd->name != NULL)
+	xmlFree(keyd->name);
+    if (keyd->nameURI != NULL)
+	xmlFree(keyd->nameURI);
+    if (keyd->match != NULL)
+	xmlFree(keyd->match);
+    if (keyd->use != NULL)
+	xmlFree(keyd->use);
+    if (keyd->nsList != NULL)
+        xmlFree(keyd->nsList);
+    memset(keyd, -1, sizeof(xsltKeyDef));
+    xmlFree(keyd);
+}
+
+/**
+ * xsltFreeKeyDefList:
+ * @keyd:  an XSLT key definition list
+ *
+ * Free up the memory allocated by all the elements of @keyd
+ */
+static void
+xsltFreeKeyDefList(xsltKeyDefPtr keyd) {
+    xsltKeyDefPtr cur;
+
+    while (keyd != NULL) {
+	cur = keyd;
+	keyd = keyd->next;
+	xsltFreeKeyDef(cur);
+    }
+}
+
+/**
+ * xsltNewKeyTable:
+ * @name:  the key name or NULL
+ * @nameURI:  the name URI or NULL
+ *
+ * Create a new XSLT KeyTable
+ *
+ * Returns the newly allocated xsltKeyTablePtr or NULL in case of error
+ */
+static xsltKeyTablePtr
+xsltNewKeyTable(const xmlChar *name, const xmlChar *nameURI) {
+    xsltKeyTablePtr cur;
+
+    cur = (xsltKeyTablePtr) xmlMalloc(sizeof(xsltKeyTable));
+    if (cur == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+		"xsltNewKeyTable : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltKeyTable));
+    if (name != NULL)
+	cur->name = xmlStrdup(name);
+    if (nameURI != NULL)
+	cur->nameURI = xmlStrdup(nameURI);
+    cur->keys = xmlHashCreate(0);
+    return(cur);
+}
+
+/**
+ * xsltFreeKeyTable:
+ * @keyt:  an XSLT key table
+ *
+ * Free up the memory allocated by @keyt
+ */
+static void
+xsltFreeKeyTable(xsltKeyTablePtr keyt) {
+    if (keyt == NULL)
+	return;
+    if (keyt->name != NULL)
+	xmlFree(keyt->name);
+    if (keyt->nameURI != NULL)
+	xmlFree(keyt->nameURI);
+    if (keyt->keys != NULL)
+	xmlHashFree(keyt->keys, 
+		    (xmlHashDeallocator) xmlXPathFreeNodeSet);
+    memset(keyt, -1, sizeof(xsltKeyTable));
+    xmlFree(keyt);
+}
+
+/**
+ * xsltFreeKeyTableList:
+ * @keyt:  an XSLT key table list
+ *
+ * Free up the memory allocated by all the elements of @keyt
+ */
+static void
+xsltFreeKeyTableList(xsltKeyTablePtr keyt) {
+    xsltKeyTablePtr cur;
+
+    while (keyt != NULL) {
+	cur = keyt;
+	keyt = keyt->next;
+	xsltFreeKeyTable(cur);
+    }
+}
+
+/************************************************************************
+ * 									*
+ * 		The interpreter for the precompiled patterns		*
+ * 									*
+ ************************************************************************/
+
+
+/**
+ * xsltFreeKeys:
+ * @style: an XSLT stylesheet
+ *
+ * Free up the memory used by XSLT keys in a stylesheet
+ */
+void
+xsltFreeKeys(xsltStylesheetPtr style) {
+    if (style->keys)
+	xsltFreeKeyDefList((xsltKeyDefPtr) style->keys);
+}
+
+/**
+ * skipString:
+ * @cur: the current pointer
+ * @end: the current offset
+ *
+ * skip a string delimited by " or '
+ *
+ * Returns the byte after the string or -1 in case of error
+ */
+static int
+skipString(const xmlChar *cur, int end) {
+    xmlChar limit;
+
+    if ((cur == NULL) || (end < 0)) return(-1);
+    if ((cur[end] == '\'') || (cur[end] == '"')) limit = cur[end];
+    else return(end);
+    end++;
+    while (cur[end] != 0) {
+        if (cur[end] == limit)
+	    return(end + 1);
+	end++;
+    }
+    return(-1);
+}
+
+/**
+ * skipPredicate:
+ * @cur: the current pointer
+ * @end: the current offset
+ *
+ * skip a predicate
+ *
+ * Returns the byte after the predicate or -1 in case of error
+ */
+static int
+skipPredicate(const xmlChar *cur, int end) {
+    if ((cur == NULL) || (end < 0)) return(-1);
+    if (cur[end] != '[') return(end);
+    end++;
+    while (cur[end] != 0) {
+        if ((cur[end] == '\'') || (cur[end] == '"')) {
+	    end = skipString(cur, end);
+	    if (end <= 0)
+	        return(-1);
+	    continue;
+	} else if (cur[end] == '[') {
+	    end = skipPredicate(cur, end);
+	    if (end <= 0)
+	        return(-1);
+	    continue;
+	} else if (cur[end] == ']')
+	    return(end + 1);
+	end++;
+    }
+    return(-1);
+}
+
+/**
+ * xsltAddKey:
+ * @style: an XSLT stylesheet
+ * @name:  the key name or NULL
+ * @nameURI:  the name URI or NULL
+ * @match:  the match value
+ * @use:  the use value
+ * @inst: the key instruction
+ *
+ * add a key definition to a stylesheet
+ *
+ * Returns 0 in case of success, and -1 in case of failure.
+ */
+int
+xsltAddKey(xsltStylesheetPtr style, const xmlChar *name,
+	   const xmlChar *nameURI, const xmlChar *match,
+	   const xmlChar *use, xmlNodePtr inst) {
+    xsltKeyDefPtr key;
+    xmlChar *pattern = NULL;
+    int current, end, start, i = 0;
+
+    if ((style == NULL) || (name == NULL) || (match == NULL) || (use == NULL))
+	return(-1);
+
+#ifdef WITH_XSLT_DEBUG_KEYS
+    xsltGenericDebug(xsltGenericDebugContext,
+	"Add key %s, match %s, use %s\n", name, match, use);
+#endif
+
+    key = xsltNewKeyDef(name, nameURI);
+    key->match = xmlStrdup(match);
+    key->use = xmlStrdup(use);
+    key->inst = inst;
+    key->nsList = xmlGetNsList(inst->doc, inst);
+    if (key->nsList != NULL) {
+        while (key->nsList[i] != NULL)
+	    i++;
+    }
+    key->nsNr = i;
+
+    /*
+     * Split the | and register it as as many keys
+     */
+    current = end = 0;
+    while (match[current] != 0) {
+	start = current;
+	while (IS_BLANK_CH(match[current]))
+	    current++;
+	end = current;
+	while ((match[end] != 0) && (match[end] != '|')) {
+	    if (match[end] == '[') {
+	        end = skipPredicate(match, end);
+		if (end <= 0) {
+		    xsltTransformError(NULL, style, inst,
+		                       "key pattern is malformed: %s",
+				       key->match);
+		    if (style != NULL) style->errors++;
+		    goto error;
+		}
+	    } else
+		end++;
+	}
+	if (current == end) {
+	    xsltTransformError(NULL, style, inst,
+			       "key pattern is empty\n");
+	    if (style != NULL) style->errors++;
+	    goto error;
+	}
+	if (match[start] != '/') {
+	    pattern = xmlStrcat(pattern, (xmlChar *)"//");
+	    if (pattern == NULL) {
+		if (style != NULL) style->errors++;
+		goto error;
+	    }
+	}
+	pattern = xmlStrncat(pattern, &match[start], end - start);
+	if (pattern == NULL) {
+	    if (style != NULL) style->errors++;
+	    goto error;
+	}
+
+	if (match[end] == '|') {
+	    pattern = xmlStrcat(pattern, (xmlChar *)"|");
+	    end++;
+	}
+	current = end;
+    }
+#ifdef WITH_XSLT_DEBUG_KEYS
+    xsltGenericDebug(xsltGenericDebugContext,
+	"   resulting pattern %s\n", pattern);
+#endif
+    /*
+    * XSLT-1: "It is an error for the value of either the use
+    *  attribute or the match attribute to contain a
+    *  VariableReference."
+    * TODO: We should report a variable-reference at compile-time.
+    *   Maybe a search for "$", if it occurs outside of quotation
+    *   marks, could be sufficient.
+    */
+    key->comp = xsltXPathCompile(style, pattern);
+    if (key->comp == NULL) {
+	xsltTransformError(NULL, style, inst,
+		"xsl:key : XPath pattern compilation failed '%s'\n",
+		         pattern);
+	if (style != NULL) style->errors++;
+    }
+    key->usecomp = xsltXPathCompile(style, use);
+    if (key->usecomp == NULL) {
+	xsltTransformError(NULL, style, inst,
+		"xsl:key : XPath pattern compilation failed '%s'\n",
+		         use);
+	if (style != NULL) style->errors++;
+    }
+
+    /*
+     * Sometimes the stylesheet writer use the order to ease the
+     * resolution of keys when they are dependant, keep the provided
+     * order so add the new one at the end.
+     */
+    if (style->keys == NULL) {
+	style->keys = key;
+    } else {
+        xsltKeyDefPtr prev = style->keys;
+
+	while (prev->next != NULL)
+	    prev = prev->next;
+
+	prev->next = key;
+    }
+    key->next = NULL;
+
+error:
+    if (pattern != NULL)
+	xmlFree(pattern);
+    return(0);
+}
+
+/**
+ * xsltGetKey:
+ * @ctxt: an XSLT transformation context
+ * @name:  the key name or NULL
+ * @nameURI:  the name URI or NULL
+ * @value:  the key value to look for
+ *
+ * Looks up a key of the in current source doc (the document info
+ * on @ctxt->document). Computes the key if not already done
+ * for the current source doc.
+ *
+ * Returns the nodeset resulting from the query or NULL
+ */
+xmlNodeSetPtr
+xsltGetKey(xsltTransformContextPtr ctxt, const xmlChar *name,
+	   const xmlChar *nameURI, const xmlChar *value) {
+    xmlNodeSetPtr ret;
+    xsltKeyTablePtr table;
+    int init_table = 0;
+
+    if ((ctxt == NULL) || (name == NULL) || (value == NULL) ||
+	(ctxt->document == NULL))
+	return(NULL);
+
+#ifdef WITH_XSLT_DEBUG_KEYS
+    xsltGenericDebug(xsltGenericDebugContext,
+	"Get key %s, value %s\n", name, value);
+#endif
+
+    /*
+     * keys are computed only on-demand on first key access for a document
+     */
+    if ((ctxt->document->nbKeysComputed < ctxt->nbKeys) &&
+        (ctxt->keyInitLevel == 0)) {
+        /*
+	 * If non-recursive behaviour, just try to initialize all keys
+	 */
+	if (xsltInitAllDocKeys(ctxt))
+	    return(NULL);
+    }
+
+retry:
+    table = (xsltKeyTablePtr) ctxt->document->keys;
+    while (table != NULL) {
+	if (((nameURI != NULL) == (table->nameURI != NULL)) &&
+	    xmlStrEqual(table->name, name) &&
+	    xmlStrEqual(table->nameURI, nameURI))
+	{
+	    ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value);
+	    return(ret);
+	}
+	table = table->next;
+    }
+
+    if ((ctxt->keyInitLevel != 0) && (init_table == 0)) {
+        /*
+	 * Apparently one key is recursive and this one is needed,
+	 * initialize just it, that time and retry
+	 */
+        xsltInitDocKeyTable(ctxt, name, nameURI);
+	init_table = 1;
+	goto retry;
+    }
+
+    return(NULL);
+}
+
+
+/**
+ * xsltInitDocKeyTable:
+ *
+ * INTERNAL ROUTINE ONLY
+ *
+ * Check if any keys on the current document need to be computed
+ */
+static int
+xsltInitDocKeyTable(xsltTransformContextPtr ctxt, const xmlChar *name,
+                    const xmlChar *nameURI)
+{
+    xsltStylesheetPtr style;
+    xsltKeyDefPtr keyd = NULL;
+    int found = 0;
+
+#ifdef KEY_INIT_DEBUG
+fprintf(stderr, "xsltInitDocKeyTable %s\n", name);
+#endif
+
+    style = ctxt->style;
+    while (style != NULL) {
+	keyd = (xsltKeyDefPtr) style->keys;
+	while (keyd != NULL) {
+	    if (((keyd->nameURI != NULL) ==
+		 (nameURI != NULL)) &&
+		xmlStrEqual(keyd->name, name) &&
+		xmlStrEqual(keyd->nameURI, nameURI))
+	    {
+		xsltInitCtxtKey(ctxt, ctxt->document, keyd);
+		if (ctxt->document->nbKeysComputed == ctxt->nbKeys)
+		    return(0);
+		found = 1;
+	    }
+	    keyd = keyd->next;
+	}
+	style = xsltNextImport(style);
+    }
+    if (found == 0) {
+#ifdef WITH_XSLT_DEBUG_KEYS
+	XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltInitDocKeyTable: did not found %s\n", name));
+#endif
+	xsltTransformError(ctxt, NULL, keyd? keyd->inst : NULL,
+	    "Failed to find key definition for %s\n", name);
+	ctxt->state = XSLT_STATE_STOPPED;
+        return(-1);
+    }
+#ifdef KEY_INIT_DEBUG
+fprintf(stderr, "xsltInitDocKeyTable %s done\n", name);
+#endif
+    return(0);
+}
+
+/**
+ * xsltInitAllDocKeys:
+ * @ctxt: transformation context
+ *
+ * INTERNAL ROUTINE ONLY
+ *
+ * Check if any keys on the current document need to be computed
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+int
+xsltInitAllDocKeys(xsltTransformContextPtr ctxt)
+{
+    xsltStylesheetPtr style;
+    xsltKeyDefPtr keyd;
+    xsltKeyTablePtr table;
+
+    if (ctxt == NULL)
+	return(-1);
+
+#ifdef KEY_INIT_DEBUG
+fprintf(stderr, "xsltInitAllDocKeys %d %d\n",
+        ctxt->document->nbKeysComputed, ctxt->nbKeys);
+#endif
+
+    if (ctxt->document->nbKeysComputed == ctxt->nbKeys)
+	return(0);
+
+
+    /*
+    * TODO: This could be further optimized
+    */
+    style = ctxt->style;
+    while (style) {
+	keyd = (xsltKeyDefPtr) style->keys;
+	while (keyd != NULL) {
+#ifdef KEY_INIT_DEBUG
+fprintf(stderr, "Init key %s\n", keyd->name);
+#endif
+	    /*
+	    * Check if keys with this QName have been already
+	    * computed.
+	    */
+	    table = (xsltKeyTablePtr) ctxt->document->keys;
+	    while (table) {
+		if (((keyd->nameURI != NULL) == (table->nameURI != NULL)) &&
+		    xmlStrEqual(keyd->name, table->name) &&
+		    xmlStrEqual(keyd->nameURI, table->nameURI))
+		{
+		    break;
+		}
+		table = table->next;
+	    }
+	    if (table == NULL) {
+		/*
+		* Keys with this QName have not been yet computed.
+		*/
+		xsltInitDocKeyTable(ctxt, keyd->name, keyd->nameURI);
+	    }
+	    keyd = keyd->next;
+	}
+	style = xsltNextImport(style);
+    }
+#ifdef KEY_INIT_DEBUG
+fprintf(stderr, "xsltInitAllDocKeys: done\n");
+#endif
+    return(0);
+}
+
+/**
+ * xsltInitCtxtKey:
+ * @ctxt: an XSLT transformation context
+ * @idoc:  the document information (holds key values)
+ * @keyDef: the key definition
+ *
+ * Computes the key tables this key and for the current input document.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int
+xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc,
+	        xsltKeyDefPtr keyDef)
+{
+    int i, len, k;
+    xmlNodeSetPtr matchList = NULL, keylist;
+    xmlXPathObjectPtr matchRes = NULL, useRes = NULL;
+    xmlChar *str = NULL;
+    xsltKeyTablePtr table;
+    xmlNodePtr oldInst, cur;
+    xmlNodePtr oldContextNode;
+    xsltDocumentPtr oldDocInfo;
+    int	oldXPPos, oldXPSize;
+    xmlDocPtr oldXPDoc;
+    int oldXPNsNr;
+    xmlNsPtr *oldXPNamespaces;
+    xmlXPathContextPtr xpctxt;
+
+#ifdef KEY_INIT_DEBUG
+fprintf(stderr, "xsltInitCtxtKey %s : %d\n", keyDef->name, ctxt->keyInitLevel);
+#endif
+
+    if ((keyDef->comp == NULL) || (keyDef->usecomp == NULL))
+	return(-1);
+
+    /*
+     * Detect recursive keys
+     */
+    if (ctxt->keyInitLevel > ctxt->nbKeys) {
+#ifdef WITH_XSLT_DEBUG_KEYS
+	XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,
+	           xsltGenericDebug(xsltGenericDebugContext,
+		       "xsltInitCtxtKey: key definition of %s is recursive\n",
+		       keyDef->name));
+#endif
+	xsltTransformError(ctxt, NULL, keyDef->inst,
+	    "Key definition for %s is recursive\n", keyDef->name);
+	ctxt->state = XSLT_STATE_STOPPED;
+        return(-1);
+    }
+    ctxt->keyInitLevel++;
+
+    xpctxt = ctxt->xpathCtxt;
+    idoc->nbKeysComputed++;
+    /*
+    * Save context state.
+    */
+    oldInst = ctxt->inst;
+    oldDocInfo = ctxt->document;
+    oldContextNode = ctxt->node;
+
+    oldXPDoc = xpctxt->doc;
+    oldXPPos = xpctxt->proximityPosition;
+    oldXPSize = xpctxt->contextSize;
+    oldXPNsNr = xpctxt->nsNr;
+    oldXPNamespaces = xpctxt->namespaces;
+
+    /*
+    * Set up contexts.
+    */
+    ctxt->document = idoc;
+    ctxt->node = (xmlNodePtr) idoc->doc;
+    ctxt->inst = keyDef->inst;
+
+    xpctxt->doc = idoc->doc;
+    xpctxt->node = (xmlNodePtr) idoc->doc;
+    /* TODO : clarify the use of namespaces in keys evaluation */
+    xpctxt->namespaces = keyDef->nsList;
+    xpctxt->nsNr = keyDef->nsNr;
+
+    /*
+    * Evaluate the 'match' expression of the xsl:key.
+    * TODO: The 'match' is a *pattern*.
+    */
+    matchRes = xmlXPathCompiledEval(keyDef->comp, xpctxt);
+    if (matchRes == NULL) {
+
+#ifdef WITH_XSLT_DEBUG_KEYS
+	XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltInitCtxtKey: %s evaluation failed\n", keyDef->match));
+#endif
+	xsltTransformError(ctxt, NULL, keyDef->inst,
+	    "Failed to evaluate the 'match' expression.\n");
+	ctxt->state = XSLT_STATE_STOPPED;
+	goto error;
+    } else {
+	if (matchRes->type == XPATH_NODESET) {
+	    matchList = matchRes->nodesetval;
+
+#ifdef WITH_XSLT_DEBUG_KEYS
+	    if (matchList != NULL)
+		XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltInitCtxtKey: %s evaluates to %d nodes\n",
+				 keyDef->match, matchList->nodeNr));
+#endif
+	} else {
+	    /*
+	    * Is not a node set, but must be.
+	    */
+#ifdef WITH_XSLT_DEBUG_KEYS
+	    XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
+		 "xsltInitCtxtKey: %s is not a node set\n", keyDef->match));
+#endif
+	    xsltTransformError(ctxt, NULL, keyDef->inst,
+		"The 'match' expression did not evaluate to a node set.\n");
+	    ctxt->state = XSLT_STATE_STOPPED;
+	    goto error;
+	}
+    }
+    if ((matchList == NULL) || (matchList->nodeNr <= 0))
+	goto exit;
+
+    /**
+     * Multiple key definitions for the same name are allowed, so
+     * we must check if the key is already present for this doc
+     */
+    table = (xsltKeyTablePtr) idoc->keys;
+    while (table != NULL) {
+        if (xmlStrEqual(table->name, keyDef->name) &&
+	    (((keyDef->nameURI == NULL) && (table->nameURI == NULL)) ||
+	     ((keyDef->nameURI != NULL) && (table->nameURI != NULL) &&
+	      (xmlStrEqual(table->nameURI, keyDef->nameURI)))))
+	    break;
+	table = table->next;
+    }
+    /**
+     * If the key was not previously defined, create it now and
+     * chain it to the list of keys for the doc
+     */
+    if (table == NULL) {
+        table = xsltNewKeyTable(keyDef->name, keyDef->nameURI);
+        if (table == NULL)
+	    goto error;
+        table->next = idoc->keys;
+        idoc->keys = table;
+    }
+
+    /*
+    * SPEC XSLT 1.0 (XSLT 2.0 does not clarify the context size!)
+    * "...the use attribute of the xsl:key element is evaluated with x as
+    "  the current node and with a node list containing just x as the
+    *  current node list"
+    */
+    xpctxt->contextSize = 1;
+    xpctxt->proximityPosition = 1;
+
+    for (i = 0; i < matchList->nodeNr; i++) {
+	cur = matchList->nodeTab[i];
+	if (! IS_XSLT_REAL_NODE(cur))
+	    continue;
+	xpctxt->node = cur;
+	/*
+	* Process the 'use' of the xsl:key.
+	* SPEC XSLT 1.0:
+	* "The use attribute is an expression specifying the values of
+	*  the key; the expression is evaluated once for each node that
+	*  matches the pattern."
+	*/
+	if (useRes != NULL)
+	    xmlXPathFreeObject(useRes);
+	useRes = xmlXPathCompiledEval(keyDef->usecomp, xpctxt);
+	if (useRes == NULL) {
+	    xsltTransformError(ctxt, NULL, keyDef->inst,
+		"Failed to evaluate the 'use' expression.\n");
+	    ctxt->state = XSLT_STATE_STOPPED;
+	    break;
+	}
+	if (useRes->type == XPATH_NODESET) {
+	    if ((useRes->nodesetval != NULL) &&
+		(useRes->nodesetval->nodeNr != 0))
+	    {
+		len = useRes->nodesetval->nodeNr;
+		str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[0]);
+	    } else {
+		continue;
+	    }
+	} else {
+	    len = 1;
+	    if (useRes->type == XPATH_STRING) {
+		/*
+		* Consume the string value.
+		*/
+		str = useRes->stringval;
+		useRes->stringval = NULL;
+	    } else {
+		str = xmlXPathCastToString(useRes);
+	    }
+	}
+	/*
+	* Process all strings.
+	*/
+	k = 0;
+	while (1) {
+	    if (str == NULL)
+		goto next_string;
+
+#ifdef WITH_XSLT_DEBUG_KEYS
+	    XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
+		"xsl:key : node associated to ('%s', '%s')\n", keyDef->name, str));
+#endif
+
+	    keylist = xmlHashLookup(table->keys, str);
+	    if (keylist == NULL) {
+		keylist = xmlXPathNodeSetCreate(cur);
+		if (keylist == NULL)
+		    goto error;
+		xmlHashAddEntry(table->keys, str, keylist);
+	    } else {
+		/*
+		* TODO: How do we know if this function failed?
+		*/
+		xmlXPathNodeSetAdd(keylist, cur);
+	    }
+	    switch (cur->type) {
+		case XML_ELEMENT_NODE:
+		case XML_TEXT_NODE:
+		case XML_CDATA_SECTION_NODE:
+		case XML_PI_NODE:
+		case XML_COMMENT_NODE:
+		    cur->psvi = keyDef;
+		    break;
+		case XML_ATTRIBUTE_NODE:
+		    ((xmlAttrPtr) cur)->psvi = keyDef;
+		    break;
+		case XML_DOCUMENT_NODE:
+		case XML_HTML_DOCUMENT_NODE:
+		    ((xmlDocPtr) cur)->psvi = keyDef;
+		    break;
+		default:
+		    break;
+	    }
+	    xmlFree(str);
+	    str = NULL;
+
+next_string:
+	    k++;
+	    if (k >= len)
+		break;
+	    str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[k]);
+	}
+    }
+
+exit:
+error:
+    ctxt->keyInitLevel--;
+    /*
+    * Restore context state.
+    */
+    xpctxt->doc = oldXPDoc;
+    xpctxt->nsNr = oldXPNsNr;
+    xpctxt->namespaces = oldXPNamespaces;
+    xpctxt->proximityPosition = oldXPPos;
+    xpctxt->contextSize = oldXPSize;
+
+    ctxt->node = oldContextNode;
+    ctxt->document = oldDocInfo;
+    ctxt->inst = oldInst;
+
+    if (str)
+	xmlFree(str);
+    if (useRes != NULL)
+	xmlXPathFreeObject(useRes);
+    if (matchRes != NULL)
+	xmlXPathFreeObject(matchRes);
+    return(0);
+}
+
+/**
+ * xsltInitCtxtKeys:
+ * @ctxt:  an XSLT transformation context
+ * @idoc:  a document info
+ *
+ * Computes all the keys tables for the current input document.
+ * Should be done before global varibales are initialized.
+ * NOTE: Not used anymore in the refactored code.
+ */
+void
+xsltInitCtxtKeys(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc) {
+    xsltStylesheetPtr style;
+    xsltKeyDefPtr keyDef;
+
+    if ((ctxt == NULL) || (idoc == NULL))
+	return;
+
+#ifdef KEY_INIT_DEBUG
+fprintf(stderr, "xsltInitCtxtKeys on document\n");
+#endif
+
+#ifdef WITH_XSLT_DEBUG_KEYS
+    if ((idoc->doc != NULL) && (idoc->doc->URL != NULL))
+	XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "Initializing keys on %s\n",
+		     idoc->doc->URL));
+#endif
+    style = ctxt->style;
+    while (style != NULL) {
+	keyDef = (xsltKeyDefPtr) style->keys;
+	while (keyDef != NULL) {
+	    xsltInitCtxtKey(ctxt, idoc, keyDef);
+
+	    keyDef = keyDef->next;
+	}
+
+	style = xsltNextImport(style);
+    }
+
+#ifdef KEY_INIT_DEBUG
+fprintf(stderr, "xsltInitCtxtKeys on document: done\n");
+#endif
+
+}
+
+/**
+ * xsltFreeDocumentKeys:
+ * @idoc: a XSLT document
+ *
+ * Free the keys associated to a document
+ */
+void
+xsltFreeDocumentKeys(xsltDocumentPtr idoc) {
+    if (idoc != NULL)
+        xsltFreeKeyTableList(idoc->keys);
+}
+
diff --git a/libxslt/keys.h b/libxslt/keys.h
new file mode 100644
index 0000000..9182baa
--- /dev/null
+++ b/libxslt/keys.h
@@ -0,0 +1,53 @@
+/*
+ * Summary:  interface for the key matching used in key() and template matches.
+ * Description: implementation of the key mechanims.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_KEY_H__
+#define __XML_XSLT_KEY_H__
+
+#include <libxml/xpath.h>
+#include "xsltexports.h"
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * NODE_IS_KEYED:
+ *
+ * check for bit 15 set
+ */
+#define NODE_IS_KEYED (1 >> 15)
+
+XSLTPUBFUN int XSLTCALL
+		xsltAddKey		(xsltStylesheetPtr style,
+					 const xmlChar *name,
+					 const xmlChar *nameURI,
+					 const xmlChar *match,
+					 const xmlChar *use,
+					 xmlNodePtr inst);
+XSLTPUBFUN xmlNodeSetPtr XSLTCALL	
+		xsltGetKey		(xsltTransformContextPtr ctxt,
+					 const xmlChar *name,
+					 const xmlChar *nameURI,
+					 const xmlChar *value);
+XSLTPUBFUN void XSLTCALL		
+		xsltInitCtxtKeys	(xsltTransformContextPtr ctxt,
+					 xsltDocumentPtr doc);
+XSLTPUBFUN void XSLTCALL		
+		xsltFreeKeys		(xsltStylesheetPtr style);
+XSLTPUBFUN void XSLTCALL		
+		xsltFreeDocumentKeys	(xsltDocumentPtr doc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_H__ */
+
diff --git a/libxslt/libxslt.h b/libxslt/libxslt.h
new file mode 100644
index 0000000..2b9f52a
--- /dev/null
+++ b/libxslt/libxslt.h
@@ -0,0 +1,30 @@
+/*
+ * Summary: internal header only used during the compilation of libxslt
+ * Description: internal header only used during the compilation of libxslt
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XSLT_LIBXSLT_H__
+#define __XSLT_LIBXSLT_H__
+
+#if defined(WIN32) && !defined (__CYGWIN__) && !defined (__MINGW32__)
+#include <win32config.h>
+#else
+#include "config.h"
+#endif
+
+#include <libxslt/xsltconfig.h>
+#include <libxml/xmlversion.h>
+
+#if !defined LIBXSLT_PUBLIC
+#if (defined (__CYGWIN__) || defined _MSC_VER) && !defined IN_LIBXSLT && !defined LIBXSLT_STATIC
+#define LIBXSLT_PUBLIC __declspec(dllimport)
+#else
+#define LIBXSLT_PUBLIC 
+#endif
+#endif
+
+#endif /* ! __XSLT_LIBXSLT_H__ */
diff --git a/libxslt/namespaces.c b/libxslt/namespaces.c
new file mode 100644
index 0000000..3e3891f
--- /dev/null
+++ b/libxslt/namespaces.c
@@ -0,0 +1,851 @@
+/*
+ * namespaces.c: Implementation of the XSLT namespaces handling
+ *
+ * Reference:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+#ifdef HAVE_NAN_H
+#include <nan.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#ifndef	XSLT_NEED_TRIO
+#include <stdio.h>
+#else
+#include <trio.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/hash.h>
+#include <libxml/xmlerror.h>
+#include <libxml/uri.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "namespaces.h"
+#include "imports.h"
+
+/************************************************************************
+ *									*
+ *			Module interfaces				*
+ *									*
+ ************************************************************************/
+
+#ifdef XSLT_REFACTORED  
+static xsltNsAliasPtr
+xsltNewNsAlias(xsltCompilerCtxtPtr cctxt)
+{
+    xsltNsAliasPtr ret;
+
+    if (cctxt == NULL)
+	return(NULL);
+
+    ret = (xsltNsAliasPtr) xmlMalloc(sizeof(xsltNsAlias));
+    if (ret == NULL) {
+	xsltTransformError(NULL, cctxt->style, NULL,
+	    "Internal error in xsltNewNsAlias(): Memory allocation failed.\n");
+	cctxt->style->errors++;
+	return(NULL);
+    }
+    memset(ret, 0, sizeof(xsltNsAlias));    
+    /*
+    * TODO: Store the item at current stylesheet-level.
+    */
+    ret->next = cctxt->nsAliases;
+    cctxt->nsAliases = ret;       
+
+    return(ret);
+}
+#endif /* XSLT_REFACTORED */
+/**
+ * xsltNamespaceAlias:
+ * @style:  the XSLT stylesheet
+ * @node:  the xsl:namespace-alias node
+ *
+ * Read the stylesheet-prefix and result-prefix attributes, register
+ * them as well as the corresponding namespace.
+ */
+void
+xsltNamespaceAlias(xsltStylesheetPtr style, xmlNodePtr node)
+{
+    xmlChar *resultPrefix = NULL;
+    xmlChar *stylePrefix = NULL;
+    xmlNsPtr literalNs = NULL;
+    xmlNsPtr targetNs = NULL;
+ 
+#ifdef XSLT_REFACTORED 
+    xsltNsAliasPtr alias;
+
+    if ((style == NULL) || (node == NULL))
+	return;
+
+    /*
+    * SPEC XSLT 1.0:
+    *  "If a namespace URI is declared to be an alias for multiple
+    *  different namespace URIs, then the declaration with the highest
+    *  import precedence is used. It is an error if there is more than
+    *  one such declaration. An XSLT processor may signal the error;
+    *  if it does not signal the error, it must recover by choosing,
+    *  from amongst the declarations with the highest import precedence,
+    *  the one that occurs last in the stylesheet."
+    *
+    * SPEC TODO: Check for the errors mentioned above.
+    */
+    /*
+    * NOTE that the XSLT 2.0 also *does* use the NULL namespace if
+    *  "#default" is used and there's no default namespace is scope.
+    *  I.e., this is *not* an error. 
+    *  Most XSLT 1.0 implementations work this way.
+    *  The XSLT 1.0 spec has nothing to say on the subject. 
+    */
+    /*
+    * Attribute "stylesheet-prefix".
+    */
+    stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL);
+    if (stylePrefix == NULL) {
+	xsltTransformError(NULL, style, node,
+	    "The attribute 'stylesheet-prefix' is missing.\n");
+	return;
+    }
+    if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default"))
+	literalNs = xmlSearchNs(node->doc, node, NULL);	
+    else {
+	literalNs = xmlSearchNs(node->doc, node, stylePrefix);
+	if (literalNs == NULL) {
+	    xsltTransformError(NULL, style, node,
+	        "Attribute 'stylesheet-prefix': There's no namespace "
+		"declaration in scope for the prefix '%s'.\n",
+		    stylePrefix);
+	    goto error;
+	}
+    }
+    /*
+    * Attribute "result-prefix".
+    */
+    resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL);
+    if (resultPrefix == NULL) {
+	xsltTransformError(NULL, style, node,
+	    "The attribute 'result-prefix' is missing.\n");
+	goto error;
+    }        
+    if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default"))
+	targetNs = xmlSearchNs(node->doc, node, NULL);
+    else {
+	targetNs = xmlSearchNs(node->doc, node, resultPrefix);
+
+        if (targetNs == NULL) {
+	   xsltTransformError(NULL, style, node,
+	        "Attribute 'result-prefix': There's no namespace "
+		"declaration in scope for the prefix '%s'.\n",
+		    stylePrefix);
+	    goto error;
+	}
+    }
+    /*
+     *
+     * Same alias for multiple different target namespace URIs:
+     *  TODO: The one with the highest import precedence is used.
+     *  Example:
+     *  <xsl:namespace-alias stylesheet-prefix="foo"
+     *                       result-prefix="bar"/>
+     *
+     *  <xsl:namespace-alias stylesheet-prefix="foo"
+     *                       result-prefix="zar"/>
+     *
+     * Same target namespace URI for multiple different aliases:
+     *  All alias-definitions will be used.
+     *  Example:
+     *  <xsl:namespace-alias stylesheet-prefix="bar"
+     *                       result-prefix="foo"/>
+     *
+     *  <xsl:namespace-alias stylesheet-prefix="zar"
+     *                       result-prefix="foo"/>
+     * Cases using #default:
+     *  <xsl:namespace-alias stylesheet-prefix="#default"
+     *                       result-prefix="#default"/>
+     *  TODO: Has this an effect at all?
+     *
+     *  <xsl:namespace-alias stylesheet-prefix="foo"
+     *                       result-prefix="#default"/>
+     *  From namespace to no namespace.
+     *
+     *  <xsl:namespace-alias stylesheet-prefix="#default"
+     *                       result-prefix="foo"/>
+     *  From no namespace to namespace.
+     */
+    
+	
+     /*
+     * Store the ns-node in the alias-object.
+    */
+    alias = xsltNewNsAlias(XSLT_CCTXT(style));
+    if (alias == NULL)
+	return;
+    alias->literalNs = literalNs;
+    alias->targetNs = targetNs;
+    XSLT_CCTXT(style)->hasNsAliases = 1;
+
+
+#else /* XSLT_REFACTORED */
+    const xmlChar *literalNsName;
+    const xmlChar *targetNsName;
+    
+
+    if ((style == NULL) || (node == NULL))
+	return;
+
+    stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL);
+    if (stylePrefix == NULL) {
+	xsltTransformError(NULL, style, node,
+	    "namespace-alias: stylesheet-prefix attribute missing\n");
+	return;
+    }
+    resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL);
+    if (resultPrefix == NULL) {
+	xsltTransformError(NULL, style, node,
+	    "namespace-alias: result-prefix attribute missing\n");
+	goto error;
+    }
+    
+    if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default")) {
+	literalNs = xmlSearchNs(node->doc, node, NULL);
+	if (literalNs == NULL) {
+	    literalNsName = NULL;
+	} else
+	    literalNsName = literalNs->href; /* Yes - set for nsAlias table */
+    } else {
+	literalNs = xmlSearchNs(node->doc, node, stylePrefix);
+ 
+	if ((literalNs == NULL) || (literalNs->href == NULL)) {
+	    xsltTransformError(NULL, style, node,
+	        "namespace-alias: prefix %s not bound to any namespace\n",
+					stylePrefix);
+	    goto error;
+	} else
+	    literalNsName = literalNs->href;
+    }
+
+    /*
+     * When "#default" is used for result, if a default namespace has not
+     * been explicitly declared the special value UNDEFINED_DEFAULT_NS is
+     * put into the nsAliases table
+     */
+    if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default")) {
+	targetNs = xmlSearchNs(node->doc, node, NULL);
+	if (targetNs == NULL) {
+	    targetNsName = UNDEFINED_DEFAULT_NS;
+	} else
+	    targetNsName = targetNs->href;
+    } else {
+	targetNs = xmlSearchNs(node->doc, node, resultPrefix);
+
+        if ((targetNs == NULL) || (targetNs->href == NULL)) {
+	    xsltTransformError(NULL, style, node,
+	        "namespace-alias: prefix %s not bound to any namespace\n",
+					resultPrefix);
+	    goto error;
+	} else
+	    targetNsName = targetNs->href;
+    }
+    /*
+     * Special case: if #default is used for
+     *  the stylesheet-prefix (literal namespace) and there's no default
+     *  namespace in scope, we'll use style->defaultAlias for this.
+     */   
+    if (literalNsName == NULL) {
+        if (targetNs != NULL) {
+	    /*
+	    * BUG TODO: Is it not sufficient to have only 1 field for
+	    *  this, since subsequently alias declarations will
+	    *  overwrite this.	    
+	    *  Example:
+	    *   <xsl:namespace-alias result-prefix="foo"
+	    *                        stylesheet-prefix="#default"/>
+	    *   <xsl:namespace-alias result-prefix="bar"
+	    *                        stylesheet-prefix="#default"/>
+	    *  The mapping for "foo" won't be visible anymore.
+	    */
+            style->defaultAlias = targetNs->href;
+	}
+    } else {
+        if (style->nsAliases == NULL)
+	    style->nsAliases = xmlHashCreate(10);
+        if (style->nsAliases == NULL) {
+	    xsltTransformError(NULL, style, node,
+	        "namespace-alias: cannot create hash table\n");
+	    goto error;
+        }
+	xmlHashAddEntry((xmlHashTablePtr) style->nsAliases,
+	    literalNsName, (void *) targetNsName);
+    }
+#endif /* else of XSLT_REFACTORED */
+
+error:
+    if (stylePrefix != NULL)
+	xmlFree(stylePrefix);
+    if (resultPrefix != NULL)
+	xmlFree(resultPrefix);
+}
+
+/**
+ * xsltGetSpecialNamespace:
+ * @ctxt:  the transformation context
+ * @invocNode: the invoking node; e.g. a literal result element/attr;
+ *             only used for error reports
+ * @nsName:  the namespace name (or NULL)
+ * @nsPrefix:  the suggested namespace prefix (or NULL)
+ * @target:  the result element on which to anchor a namespace
+ *
+ * Find a matching (prefix and ns-name) ns-declaration
+ * for the requested @nsName and @nsPrefix in the result tree.
+ * If none is found then a new ns-declaration will be
+ * added to @resultElem. If, in this case, the given prefix is
+ * already in use, then a ns-declaration with a modified ns-prefix
+ * be we created. Note that this function's priority is to
+ * preserve ns-prefixes; it will only change a prefix if there's
+ * a namespace clash.
+ * If both @nsName and @nsPrefix are NULL, then this will try to
+ * "undeclare" a default namespace by declaring an xmlns="".
+ *
+ * Returns a namespace declaration or NULL.
+ */
+xmlNsPtr
+xsltGetSpecialNamespace(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
+		const xmlChar *nsName, const xmlChar *nsPrefix,
+		xmlNodePtr target)
+{
+    xmlNsPtr ns;
+    int prefixOccupied = 0;
+
+    if ((ctxt == NULL) || (target == NULL) ||
+	(target->type != XML_ELEMENT_NODE))
+	return(NULL);
+
+    /*
+    * NOTE: Namespace exclusion and ns-aliasing is performed at
+    *  compilation-time in the refactored code; so this need not be done
+    *  here (it was in the old code).
+    * NOTE: @invocNode was named @cur in the old code and was documented to
+    *  be an input node; since it was only used to anchor an error report
+    *  somewhere, we can safely change this to @invocNode, which now
+    *  will be the XSLT instruction (also a literal result element/attribute),
+    *  which was responsible for this call.
+    */
+    /*
+    * OPTIMIZE TODO: This all could be optimized by keeping track of
+    *  the ns-decls currently in-scope via a specialized context.
+    */    
+    if ((nsPrefix == NULL) && ((nsName == NULL) || (nsName[0] == 0))) {
+	/*
+	* NOTE: the "undeclaration" of the default namespace was
+	* part of the logic of the old xsltGetSpecialNamespace() code,
+	* so we'll keep that mechanism.
+	* Related to the old code: bug #302020:
+	*/
+	/*
+	* OPTIMIZE TODO: This all could be optimized by keeping track of
+	*  the ns-decls currently in-scope via a specialized context.
+	*/
+	/*
+	* Search on the result element itself.
+	*/
+	if (target->nsDef != NULL) {
+	    ns = target->nsDef;
+	    do {
+		if (ns->prefix == NULL) {
+		    if ((ns->href != NULL) && (ns->href[0] != 0)) {
+			/*
+			* Raise a namespace normalization error.
+			*/
+			xsltTransformError(ctxt, NULL, invocNode,
+			    "Namespace normalization error: Cannot undeclare "
+			    "the default namespace, since the default namespace "
+			    "'%s' is already declared on the result element "
+			    "'%s'.\n", ns->href, target->name);
+			return(NULL);
+		    } else {
+			/*
+			* The default namespace was undeclared on the
+			* result element.
+			*/
+			return(NULL);
+		    }
+		    break;
+		}
+		ns = ns->next;
+	    } while (ns != NULL);
+	}	
+	if ((target->parent != NULL) &&
+	    (target->parent->type == XML_ELEMENT_NODE))
+	{
+	    /*
+	    * The parent element is in no namespace, so assume
+	    * that there is no default namespace in scope.
+	    */
+	    if (target->parent->ns == NULL)
+		return(NULL);
+	    
+	    ns = xmlSearchNs(target->doc, target->parent,
+		NULL);
+	    /*
+	    * Fine if there's no default ns is scope, or if the
+	    * default ns was undeclared.
+	    */
+	    if ((ns == NULL) || (ns->href == NULL) || (ns->href[0] == 0))
+		return(NULL);
+	    
+	    /*
+	    * Undeclare the default namespace.
+	    */
+	    xmlNewNs(target, BAD_CAST "", NULL);
+	    /* TODO: Check result */	
+	    return(NULL);
+	}
+	return(NULL);
+    }
+    /*
+    * Handle the XML namespace.
+    * QUESTION: Is this faster than using xmlStrEqual() anyway?
+    */
+    if ((nsPrefix != NULL) &&
+	(nsPrefix[0] == 'x') && (nsPrefix[1] == 'm') &&
+	(nsPrefix[2] == 'l') && (nsPrefix[3] == 0))
+    {
+	return(xmlSearchNs(target->doc, target, nsPrefix));
+    }
+    /*
+    * First: search on the result element itself.
+    */
+    if (target->nsDef != NULL) {
+	ns = target->nsDef;
+	do {
+	    if ((ns->prefix == NULL) == (nsPrefix == NULL)) {
+		if (ns->prefix == nsPrefix) {
+		    if (xmlStrEqual(ns->href, nsName))
+			return(ns);
+		    prefixOccupied = 1;
+		    break;
+		} else if (xmlStrEqual(ns->prefix, nsPrefix)) {
+		    if (xmlStrEqual(ns->href, nsName))
+			return(ns);
+		    prefixOccupied = 1;
+		    break;
+		}
+	    }
+	    ns = ns->next;
+	} while (ns != NULL);
+    }
+    if (prefixOccupied) {
+	/*
+	* If the ns-prefix is occupied by an other ns-decl on the
+	* result element, then this means:
+	* 1) The desired prefix is shadowed
+	* 2) There's no way around changing the prefix	
+	*
+	* Try a desperate search for an in-scope ns-decl
+	* with a matching ns-name before we use the last option,
+	* which is to recreate the ns-decl with a modified prefix.
+	*/
+	ns = xmlSearchNsByHref(target->doc, target, nsName);
+	if (ns != NULL)
+	    return(ns);
+
+	/*
+	* Fallback to changing the prefix.
+	*/    
+    } else if ((target->parent != NULL) &&
+	(target->parent->type == XML_ELEMENT_NODE))
+    {
+	/*
+	* Try to find a matching ns-decl in the ancestor-axis.
+	*
+	* Check the common case: The parent element of the current
+	* result element is in the same namespace (with an equal ns-prefix).
+	*/     
+	if ((target->parent->ns != NULL) &&
+	    ((target->parent->ns->prefix != NULL) == (nsPrefix != NULL)))
+	{
+	    ns = target->parent->ns;
+	    
+	    if (nsPrefix == NULL) {
+		if (xmlStrEqual(ns->href, nsName))
+		    return(ns);
+	    } else if (xmlStrEqual(ns->prefix, nsPrefix) &&
+		xmlStrEqual(ns->href, nsName))
+	    {
+		return(ns);
+	    }
+	}
+	/*
+	* Lookup the remaining in-scope namespaces.
+	*/    
+	ns = xmlSearchNs(target->doc, target->parent, nsPrefix);
+	if (ns != NULL) {
+	    if (xmlStrEqual(ns->href, nsName))
+		return(ns);	    
+	    /*
+	    * Now check for a nasty case: We need to ensure that the new
+	    * ns-decl won't shadow a prefix in-use by an existing attribute.
+	    * <foo xmlns:a="urn:test:a">
+	    *   <bar a:a="val-a">
+	    *     <xsl:attribute xmlns:a="urn:test:b" name="a:b">
+	    *        val-b</xsl:attribute>
+	    *   </bar>
+	    * </foo>
+	    */
+	    if (target->properties) {
+		xmlAttrPtr attr = target->properties;
+		do {
+		    if ((attr->ns) &&
+			xmlStrEqual(attr->ns->prefix, nsPrefix))
+		    {
+			/*
+			* Bad, this prefix is already in use.
+			* Since we'll change the prefix anyway, try
+			* a search for a matching ns-decl based on the
+			* namespace name.
+			*/
+			ns = xmlSearchNsByHref(target->doc, target, nsName);
+			if (ns != NULL)
+			    return(ns);
+			goto declare_new_prefix;
+		    }
+		    attr = attr->next;
+		} while (attr != NULL);
+	    }
+	} else {
+	    /*
+	    * Either no matching ns-prefix was found or the namespace is
+	    * shadowed.
+	    * Create a new ns-decl on the current result element.
+	    *
+	    * Hmm, we could also try to reuse an in-scope
+	    * namespace with a matching ns-name but a different
+	    * ns-prefix.
+	    * What has higher priority?
+	    *  1) If keeping the prefix: create a new ns-decl.
+	    *  2) If reusal: first lookup ns-names; then fallback
+	    *     to creation of a new ns-decl.
+	    * REVISIT: this currently uses case 1) although
+	    *  the old way was use xmlSearchNsByHref() and to let change
+	    *  the prefix.
+	    */
+#if 0
+	    ns = xmlSearchNsByHref(target->doc, target, nsName);
+	    if (ns != NULL)
+		return(ns);
+#endif
+	}
+	/*
+	* Create the ns-decl on the current result element.
+	*/
+	ns = xmlNewNs(target, nsName, nsPrefix);
+	/* TODO: check errors */
+	return(ns);
+    } else {
+	/*
+	* This is either the root of the tree or something weird is going on.
+	*/
+	ns = xmlNewNs(target, nsName, nsPrefix);
+	/* TODO: Check result */
+	return(ns);
+    }
+
+declare_new_prefix:
+    /*
+    * Fallback: we need to generate a new prefix and declare the namespace
+    * on the result element.
+    */
+    {
+	xmlChar pref[30];
+	int counter = 1;
+
+	if (nsPrefix == NULL) {
+	    nsPrefix = "ns";
+	}
+
+	do {
+	    snprintf((char *) pref, 30, "%s_%d", nsPrefix, counter++);
+	    ns = xmlSearchNs(target->doc, target, BAD_CAST pref);
+	    if (counter > 1000) {
+		xsltTransformError(ctxt, NULL, invocNode,
+		    "Internal error in xsltAcquireResultInScopeNs(): "
+		    "Failed to compute a unique ns-prefix for the "
+		    "generated element");
+		return(NULL);
+	    }
+	} while (ns != NULL);
+	ns = xmlNewNs(target, nsName, BAD_CAST pref);
+	/* TODO: Check result */
+	return(ns);
+    }
+    return(NULL);
+}
+
+/**
+ * xsltGetNamespace:
+ * @ctxt:  a transformation context
+ * @cur:  the input node
+ * @ns:  the namespace
+ * @out:  the output node (or its parent)
+ *
+ * Find a matching (prefix and ns-name) ns-declaration
+ * for the requested @ns->prefix and @ns->href in the result tree.
+ * If none is found then a new ns-declaration will be
+ * added to @resultElem. If, in this case, the given prefix is
+ * already in use, then a ns-declaration with a modified ns-prefix
+ * be we created.
+ *
+ * Called by:
+ *  - xsltCopyPropList() (*not*  anymore)
+ *  - xsltShallowCopyElement()
+ *  - xsltCopyTreeInternal() (*not*  anymore)
+ *  - xsltApplySequenceConstructor() (*not* in the refactored code),
+ *  - xsltElement() (*not* anymore)
+ *
+ * Returns a namespace declaration or NULL in case of
+ *         namespace fixup failures or API or internal errors.
+ */
+xmlNsPtr
+xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns,
+	         xmlNodePtr out)
+{    
+    
+    if (ns == NULL)
+	return(NULL);
+
+#ifdef XSLT_REFACTORED
+    /*
+    * Namespace exclusion and ns-aliasing is performed at
+    * compilation-time in the refactored code.
+    * Additionally, aliasing is not intended for non Literal
+    * Result Elements.
+    */
+    return(xsltGetSpecialNamespace(ctxt, cur, ns->href, ns->prefix, out));
+#else
+    {
+	xsltStylesheetPtr style;
+	const xmlChar *URI = NULL; /* the replacement URI */
+
+	if ((ctxt == NULL) || (cur == NULL) || (out == NULL))
+	    return(NULL);
+
+	style = ctxt->style;
+	while (style != NULL) {
+	    if (style->nsAliases != NULL)
+		URI = (const xmlChar *) 
+		xmlHashLookup(style->nsAliases, ns->href);
+	    if (URI != NULL)
+		break;
+	    
+	    style = xsltNextImport(style);
+	}
+	
+	
+	if (URI == UNDEFINED_DEFAULT_NS) {
+	    return(xsltGetSpecialNamespace(ctxt, cur, NULL, NULL, out));
+#if 0
+	    /*
+	    * TODO: Removed, since wrong. If there was no default
+	    * namespace in the stylesheet then this must resolve to
+	    * the NULL namespace.
+	    */
+	    xmlNsPtr dflt;	    
+	    dflt = xmlSearchNs(cur->doc, cur, NULL);
+	    if (dflt != NULL)
+		URI = dflt->href;
+	    else
+		return NULL;
+#endif
+	} else if (URI == NULL)
+	    URI = ns->href;
+
+	return(xsltGetSpecialNamespace(ctxt, cur, URI, ns->prefix, out));
+    }
+#endif
+}
+
+/**
+ * xsltGetPlainNamespace:
+ * @ctxt:  a transformation context
+ * @cur:  the input node
+ * @ns:  the namespace
+ * @out:  the result element
+ *
+ * Obsolete. 
+ * *Not* called by any Libxslt/Libexslt function.
+ * Exaclty the same as xsltGetNamespace(). 
+ *
+ * Returns a namespace declaration or NULL in case of
+ *         namespace fixup failures or API or internal errors.
+ */
+xmlNsPtr
+xsltGetPlainNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur,
+                      xmlNsPtr ns, xmlNodePtr out)
+{    
+    return(xsltGetNamespace(ctxt, cur, ns, out));
+}
+
+/**
+ * xsltCopyNamespaceList:
+ * @ctxt:  a transformation context
+ * @node:  the target node
+ * @cur:  the first namespace
+ *
+ * Do a copy of an namespace list. If @node is non-NULL the
+ * new namespaces are added automatically. This handles namespaces
+ * aliases.
+ * This function is intended only for *internal* use at
+ * transformation-time for copying ns-declarations of Literal
+ * Result Elements.
+ * 
+ * Called by:
+ *   xsltCopyTreeInternal() (transform.c)
+ *   xsltShallowCopyElem() (transform.c)
+ *
+ * REVISIT: This function won't be used in the refactored code.
+ *
+ * Returns: a new xmlNsPtr, or NULL in case of error.
+ */
+xmlNsPtr
+xsltCopyNamespaceList(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	              xmlNsPtr cur) {
+    xmlNsPtr ret = NULL, tmp;
+    xmlNsPtr p = NULL,q;    
+
+    if (cur == NULL)
+	return(NULL);
+    if (cur->type != XML_NAMESPACE_DECL)
+	return(NULL);
+
+    /*
+     * One can add namespaces only on element nodes
+     */
+    if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
+	node = NULL;
+
+    while (cur != NULL) {
+	if (cur->type != XML_NAMESPACE_DECL)
+	    break;
+
+	/*
+	 * Avoid duplicating namespace declarations in the tree if
+	 * a matching declaration is in scope.
+	 */
+	if (node != NULL) {
+	    if ((node->ns != NULL) &&
+		(xmlStrEqual(node->ns->prefix, cur->prefix)) &&
+        	(xmlStrEqual(node->ns->href, cur->href))) {
+		cur = cur->next;
+		continue;
+	    }
+	    tmp = xmlSearchNs(node->doc, node, cur->prefix);
+	    if ((tmp != NULL) && (xmlStrEqual(tmp->href, cur->href))) {
+		cur = cur->next;
+		continue;
+	    }
+	}
+#ifdef XSLT_REFACTORED
+	/*
+	* Namespace exclusion and ns-aliasing is performed at
+	* compilation-time in the refactored code.
+	*/
+	q = xmlNewNs(node, cur->href, cur->prefix);
+	if (p == NULL) {
+	    ret = p = q;
+	} else {
+	    p->next = q;
+	    p = q;
+	}
+#else
+	/*
+	* TODO: Remove this if the refactored code gets enabled.
+	*/
+	if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) {
+	    const xmlChar *URI;
+	    /* TODO apply cascading */
+	    URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases,
+		                                  cur->href);
+	    if (URI == UNDEFINED_DEFAULT_NS)
+	        continue;
+	    if (URI != NULL) {
+		q = xmlNewNs(node, URI, cur->prefix);
+	    } else {
+		q = xmlNewNs(node, cur->href, cur->prefix);
+	    }
+	    if (p == NULL) {
+		ret = p = q;
+	    } else {
+		p->next = q;
+		p = q;
+	    }
+	}
+#endif
+	cur = cur->next;
+    }
+    return(ret);
+}
+
+/**
+ * xsltCopyNamespace:
+ * @ctxt:  a transformation context
+ * @elem:  the target element node
+ * @ns:  the namespace node
+ *
+ * Copies a namespace node (declaration). If @elem is not NULL,
+ * then the new namespace will be declared on @elem.
+ *
+ * Returns: a new xmlNsPtr, or NULL in case of an error.
+ */
+xmlNsPtr
+xsltCopyNamespace(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
+		  xmlNodePtr elem, xmlNsPtr ns)
+{    
+    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
+	return(NULL);
+    /*
+     * One can add namespaces only on element nodes
+     */
+    if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
+	return(xmlNewNs(NULL, ns->href, ns->prefix));
+    else
+	return(xmlNewNs(elem, ns->href, ns->prefix));
+}
+
+
+/**
+ * xsltFreeNamespaceAliasHashes:
+ * @style: an XSLT stylesheet
+ *
+ * Free up the memory used by namespaces aliases
+ */
+void
+xsltFreeNamespaceAliasHashes(xsltStylesheetPtr style) {
+    if (style->nsAliases != NULL)
+	xmlHashFree((xmlHashTablePtr) style->nsAliases, NULL);
+    style->nsAliases = NULL;
+}
diff --git a/libxslt/namespaces.h b/libxslt/namespaces.h
new file mode 100644
index 0000000..0bda596
--- /dev/null
+++ b/libxslt/namespaces.h
@@ -0,0 +1,68 @@
+/*
+ * Summary: interface for the XSLT namespace handling
+ * Description: set of function easing the processing and generation
+ *              of namespace nodes in XSLT.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_NAMESPACES_H__
+#define __XML_XSLT_NAMESPACES_H__
+
+#include <libxml/tree.h>
+#include "xsltexports.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Used within nsAliases hashtable when the default namespace is required
+ * but it's not been explicitly defined
+ */
+/**
+ * UNDEFINED_DEFAULT_NS:
+ *
+ * Special value for undefined namespace, internal
+ */
+#define	UNDEFINED_DEFAULT_NS	(const xmlChar *) -1L
+
+XSLTPUBFUN void XSLTCALL
+		xsltNamespaceAlias	(xsltStylesheetPtr style,
+					 xmlNodePtr node);
+XSLTPUBFUN xmlNsPtr XSLTCALL	
+		xsltGetNamespace	(xsltTransformContextPtr ctxt,
+					 xmlNodePtr cur,
+					 xmlNsPtr ns,
+					 xmlNodePtr out);
+XSLTPUBFUN xmlNsPtr XSLTCALL	
+		xsltGetPlainNamespace	(xsltTransformContextPtr ctxt,
+					 xmlNodePtr cur,
+					 xmlNsPtr ns,
+					 xmlNodePtr out);
+XSLTPUBFUN xmlNsPtr XSLTCALL	
+		xsltGetSpecialNamespace	(xsltTransformContextPtr ctxt,
+					 xmlNodePtr cur,
+					 const xmlChar *URI,
+					 const xmlChar *prefix,
+					 xmlNodePtr out);
+XSLTPUBFUN xmlNsPtr XSLTCALL	
+		xsltCopyNamespace	(xsltTransformContextPtr ctxt,
+					 xmlNodePtr elem,
+					 xmlNsPtr ns);
+XSLTPUBFUN xmlNsPtr XSLTCALL	
+		xsltCopyNamespaceList	(xsltTransformContextPtr ctxt,
+					 xmlNodePtr node,
+					 xmlNsPtr cur);
+XSLTPUBFUN void XSLTCALL		
+		xsltFreeNamespaceAliasHashes
+					(xsltStylesheetPtr style);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_NAMESPACES_H__ */
+
diff --git a/libxslt/numbers.c b/libxslt/numbers.c
new file mode 100644
index 0000000..8683ca8
--- /dev/null
+++ b/libxslt/numbers.c
@@ -0,0 +1,1351 @@
+/*
+ * numbers.c: Implementation of the XSLT number functions
+ *
+ * Reference:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ * Bjorn Reese <breese@users.sourceforge.net>
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <math.h>
+#include <limits.h>
+#include <float.h>
+#include <string.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/parserInternals.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/encoding.h>
+#include "xsltutils.h"
+#include "pattern.h"
+#include "templates.h"
+#include "transform.h"
+#include "numbersInternals.h"
+
+#ifndef FALSE
+# define FALSE (0 == 1)
+# define TRUE (1 == 1)
+#endif
+
+#define SYMBOL_QUOTE		((xmlChar)'\'')
+
+#define DEFAULT_TOKEN		(xmlChar)'0'
+#define DEFAULT_SEPARATOR	"."
+
+#define MAX_TOKENS		1024
+
+typedef struct _xsltFormatToken xsltFormatToken;
+typedef xsltFormatToken *xsltFormatTokenPtr;
+struct _xsltFormatToken {
+    xmlChar	*separator;
+    xmlChar	 token;
+    int		 width;
+};
+
+typedef struct _xsltFormat xsltFormat;
+typedef xsltFormat *xsltFormatPtr;
+struct _xsltFormat {
+    xmlChar		*start;
+    xsltFormatToken	 tokens[MAX_TOKENS];
+    int			 nTokens;
+    xmlChar		*end;
+};
+
+static char alpha_upper_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static char alpha_lower_list[] = "abcdefghijklmnopqrstuvwxyz";
+static xsltFormatToken default_token;
+
+/*
+ * **** Start temp insert ****
+ *
+ * The following two routines (xsltUTF8Size and xsltUTF8Charcmp)
+ * will be replaced with calls to the corresponding libxml routines
+ * at a later date (when other inter-library dependencies require it)
+ */
+
+/**
+ * xsltUTF8Size:
+ * @utf: pointer to the UTF8 character
+ *
+ * returns the numbers of bytes in the character, -1 on format error
+ */
+static int
+xsltUTF8Size(xmlChar *utf) {
+    xmlChar mask;
+    int len;
+
+    if (utf == NULL)
+        return -1;
+    if (*utf < 0x80)
+        return 1;
+    /* check valid UTF8 character */
+    if (!(*utf & 0x40))
+        return -1;
+    /* determine number of bytes in char */
+    len = 2;
+    for (mask=0x20; mask != 0; mask>>=1) {
+        if (!(*utf & mask))
+            return len;
+        len++;
+    }
+    return -1;
+}
+
+/**
+ * xsltUTF8Charcmp
+ * @utf1: pointer to first UTF8 char
+ * @utf2: pointer to second UTF8 char
+ *
+ * returns result of comparing the two UCS4 values
+ * as with xmlStrncmp
+ */
+static int
+xsltUTF8Charcmp(xmlChar *utf1, xmlChar *utf2) {
+
+    if (utf1 == NULL ) {
+        if (utf2 == NULL)
+            return 0;
+        return -1;
+    }
+    return xmlStrncmp(utf1, utf2, xsltUTF8Size(utf1));
+}
+
+/***** Stop temp insert *****/
+/************************************************************************
+ *									*
+ *			Utility functions				*
+ *									*
+ ************************************************************************/
+
+#define IS_SPECIAL(self,letter)			\
+    ((xsltUTF8Charcmp((letter), (self)->zeroDigit) == 0)	    ||	\
+     (xsltUTF8Charcmp((letter), (self)->digit) == 0)	    ||	\
+     (xsltUTF8Charcmp((letter), (self)->decimalPoint) == 0)  ||	\
+     (xsltUTF8Charcmp((letter), (self)->grouping) == 0)	    ||	\
+     (xsltUTF8Charcmp((letter), (self)->patternSeparator) == 0))
+
+#define IS_DIGIT_ZERO(x) xsltIsDigitZero(x)
+#define IS_DIGIT_ONE(x) xsltIsDigitZero((xmlChar)(x)-1)
+
+static int
+xsltIsDigitZero(unsigned int ch)
+{
+    /*
+     * Reference: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
+     */
+    switch (ch) {
+    case 0x0030: case 0x0660: case 0x06F0: case 0x0966:
+    case 0x09E6: case 0x0A66: case 0x0AE6: case 0x0B66:
+    case 0x0C66: case 0x0CE6: case 0x0D66: case 0x0E50:
+    case 0x0E60: case 0x0F20: case 0x1040: case 0x17E0:
+    case 0x1810: case 0xFF10:
+	return TRUE;
+    default:
+	return FALSE;
+    }
+}
+
+static void
+xsltNumberFormatDecimal(xmlBufferPtr buffer,
+			double number,
+			int digit_zero,
+			int width,
+			int digitsPerGroup,
+			int groupingCharacter,
+			int groupingCharacterLen)
+{
+    /*
+     * This used to be
+     *  xmlChar temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 4];
+     * which would be length 68 on x86 arch.  It was changed to be a longer,
+     * fixed length in order to try to cater for (reasonable) UTF8
+     * separators and numeric characters.  The max UTF8 char size will be
+     * 6 or less, so the value used [500] should be *much* larger than needed
+     */
+    xmlChar temp_string[500];
+    xmlChar *pointer;
+    xmlChar temp_char[6];
+    int i;
+    int val;
+    int len;
+
+    /* Build buffer from back */
+    pointer = &temp_string[sizeof(temp_string)] - 1;	/* last char */
+    *pointer = 0;
+    i = 0;
+    while (pointer > temp_string) {
+	if ((i >= width) && (fabs(number) < 1.0))
+	    break; /* for */
+	if ((i > 0) && (groupingCharacter != 0) &&
+	    (digitsPerGroup > 0) &&
+	    ((i % digitsPerGroup) == 0)) {
+	    if (pointer - groupingCharacterLen < temp_string) {
+	        i = -1;		/* flag error */
+		break;
+	    }
+	    pointer -= groupingCharacterLen;
+	    xmlCopyCharMultiByte(pointer, groupingCharacter);
+	}
+	
+	val = digit_zero + (int)fmod(number, 10.0);
+	if (val < 0x80) {			/* shortcut if ASCII */
+	    if (pointer <= temp_string) {	/* Check enough room */
+	        i = -1;
+		break;
+	    }
+	    *(--pointer) = val;
+	}
+	else {
+	/* 
+	 * Here we have a multibyte character.  It's a little messy,
+	 * because until we generate the char we don't know how long
+	 * it is.  So, we generate it into the buffer temp_char, then
+	 * copy from there into temp_string.
+	 */
+	    len = xmlCopyCharMultiByte(temp_char, val);
+	    if ( (pointer - len) < temp_string ) {
+	        i = -1;
+		break;
+	    }
+	    pointer -= len;
+	    memcpy(pointer, temp_char, len);
+	}
+	number /= 10.0;
+	++i;
+    }
+    if (i < 0)
+        xsltGenericError(xsltGenericErrorContext,
+		"xsltNumberFormatDecimal: Internal buffer size exceeded");
+    xmlBufferCat(buffer, pointer);
+}
+
+static void
+xsltNumberFormatAlpha(xmlBufferPtr buffer,
+		      double number,
+		      int is_upper)
+{
+    char temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 1];
+    char *pointer;
+    int i;
+    char *alpha_list;
+    double alpha_size = (double)(sizeof(alpha_upper_list) - 1);
+
+    /* Build buffer from back */
+    pointer = &temp_string[sizeof(temp_string)];
+    *(--pointer) = 0;
+    alpha_list = (is_upper) ? alpha_upper_list : alpha_lower_list;
+    
+    for (i = 1; i < (int)sizeof(temp_string); i++) {
+	number--;
+	*(--pointer) = alpha_list[((int)fmod(number, alpha_size))];
+	number /= alpha_size;
+	if (fabs(number) < 1.0)
+	    break; /* for */
+    }
+    xmlBufferCCat(buffer, pointer);
+}
+
+static void
+xsltNumberFormatRoman(xmlBufferPtr buffer,
+		      double number,
+		      int is_upper)
+{
+    /*
+     * Based on an example by Jim Walsh
+     */
+    while (number >= 1000.0) {
+	xmlBufferCCat(buffer, (is_upper) ? "M" : "m");
+	number -= 1000.0;
+    }
+    if (number >= 900.0) {
+	xmlBufferCCat(buffer, (is_upper) ? "CM" : "cm");
+	number -= 900.0;
+    }
+    while (number >= 500.0) {
+	xmlBufferCCat(buffer, (is_upper) ? "D" : "d");
+	number -= 500.0;
+    }
+    if (number >= 400.0) {
+	xmlBufferCCat(buffer, (is_upper) ? "CD" : "cd");
+	number -= 400.0;
+    }
+    while (number >= 100.0) {
+	xmlBufferCCat(buffer, (is_upper) ? "C" : "c");
+	number -= 100.0;
+    }
+    if (number >= 90.0) {
+	xmlBufferCCat(buffer, (is_upper) ? "XC" : "xc");
+	number -= 90.0;
+    }
+    while (number >= 50.0) {
+	xmlBufferCCat(buffer, (is_upper) ? "L" : "l");
+	number -= 50.0;
+    }
+    if (number >= 40.0) {
+	xmlBufferCCat(buffer, (is_upper) ? "XL" : "xl");
+	number -= 40.0;
+    }
+    while (number >= 10.0) {
+	xmlBufferCCat(buffer, (is_upper) ? "X" : "x");
+	number -= 10.0;
+    }
+    if (number >= 9.0) {
+	xmlBufferCCat(buffer, (is_upper) ? "IX" : "ix");
+	number -= 9.0;
+    }
+    while (number >= 5.0) {
+	xmlBufferCCat(buffer, (is_upper) ? "V" : "v");
+	number -= 5.0;
+    }
+    if (number >= 4.0) {
+	xmlBufferCCat(buffer, (is_upper) ? "IV" : "iv");
+	number -= 4.0;
+    }
+    while (number >= 1.0) {
+	xmlBufferCCat(buffer, (is_upper) ? "I" : "i");
+	number--;
+    }
+}
+
+static void
+xsltNumberFormatTokenize(const xmlChar *format,
+			 xsltFormatPtr tokens)
+{
+    int ix = 0;
+    int j;
+    int val;
+    int len;
+
+    default_token.token = DEFAULT_TOKEN;
+    default_token.width = 1;
+    default_token.separator = BAD_CAST(DEFAULT_SEPARATOR);
+
+
+    tokens->start = NULL;
+    tokens->tokens[0].separator = NULL;
+    tokens->end = NULL;
+
+    /*
+     * Insert initial non-alphanumeric token.
+     * There is always such a token in the list, even if NULL
+     */
+    while (! (IS_LETTER(val=xmlStringCurrentChar(NULL, format+ix, &len)) ||
+    	      IS_DIGIT(val)) ) {
+	if (format[ix] == 0)		/* if end of format string */
+	    break; /* while */
+	ix += len;
+    }
+    if (ix > 0)
+	tokens->start = xmlStrndup(format, ix);
+
+
+    for (tokens->nTokens = 0; tokens->nTokens < MAX_TOKENS;
+	 tokens->nTokens++) {
+	if (format[ix] == 0)
+	    break; /* for */
+
+	/*
+	 * separator has already been parsed (except for the first
+	 * number) in tokens->end, recover it.
+	 */
+	if (tokens->nTokens > 0) {
+	    tokens->tokens[tokens->nTokens].separator = tokens->end;
+	    tokens->end = NULL;
+	}
+
+	val = xmlStringCurrentChar(NULL, format+ix, &len);
+	if (IS_DIGIT_ONE(val) ||
+		 IS_DIGIT_ZERO(val)) {
+	    tokens->tokens[tokens->nTokens].width = 1;
+	    while (IS_DIGIT_ZERO(val)) {
+		tokens->tokens[tokens->nTokens].width++;
+		ix += len;
+		val = xmlStringCurrentChar(NULL, format+ix, &len);
+	    }
+	    if (IS_DIGIT_ONE(val)) {
+		tokens->tokens[tokens->nTokens].token = val - 1;
+		ix += len;
+		val = xmlStringCurrentChar(NULL, format+ix, &len);
+	    }
+	} else if ( (val == (xmlChar)'A') ||
+		    (val == (xmlChar)'a') ||
+		    (val == (xmlChar)'I') ||
+		    (val == (xmlChar)'i') ) {
+	    tokens->tokens[tokens->nTokens].token = val;
+	    ix += len;
+	    val = xmlStringCurrentChar(NULL, format+ix, &len);
+	} else {
+	    /* XSLT section 7.7
+	     * "Any other format token indicates a numbering sequence
+	     *  that starts with that token. If an implementation does
+	     *  not support a numbering sequence that starts with that
+	     *  token, it must use a format token of 1."
+	     */
+	    tokens->tokens[tokens->nTokens].token = (xmlChar)'0';
+	    tokens->tokens[tokens->nTokens].width = 1;
+	}
+	/*
+	 * Skip over remaining alphanumeric characters from the Nd
+	 * (Number, decimal digit), Nl (Number, letter), No (Number,
+	 * other), Lu (Letter, uppercase), Ll (Letter, lowercase), Lt
+	 * (Letters, titlecase), Lm (Letters, modifiers), and Lo
+	 * (Letters, other (uncased)) Unicode categories. This happens
+	 * to correspond to the Letter and Digit classes from XML (and
+	 * one wonders why XSLT doesn't refer to these instead).
+	 */
+	while (IS_LETTER(val) || IS_DIGIT(val)) {
+	    ix += len;
+	    val = xmlStringCurrentChar(NULL, format+ix, &len);
+	}
+
+	/*
+	 * Insert temporary non-alphanumeric final tooken.
+	 */
+	j = ix;
+	while (! (IS_LETTER(val) || IS_DIGIT(val))) {
+	    if (val == 0)
+		break; /* while */
+	    ix += len;
+	    val = xmlStringCurrentChar(NULL, format+ix, &len);
+	}
+	if (ix > j)
+	    tokens->end = xmlStrndup(&format[j], ix - j);
+    }
+}
+
+static void
+xsltNumberFormatInsertNumbers(xsltNumberDataPtr data,
+			      double *numbers,
+			      int numbers_max,
+			      xsltFormatPtr tokens,
+			      xmlBufferPtr buffer)
+{
+    int i = 0;
+    double number;
+    xsltFormatTokenPtr token;
+
+    /*
+     * Handle initial non-alphanumeric token
+     */
+    if (tokens->start != NULL)
+	 xmlBufferCat(buffer, tokens->start);
+
+    for (i = 0; i < numbers_max; i++) {
+	/* Insert number */
+	number = numbers[(numbers_max - 1) - i];
+	if (i < tokens->nTokens) {
+	  /*
+	   * The "n"th format token will be used to format the "n"th
+	   * number in the list
+	   */
+	  token = &(tokens->tokens[i]);
+	} else if (tokens->nTokens > 0) {
+	  /*
+	   * If there are more numbers than format tokens, then the
+	   * last format token will be used to format the remaining
+	   * numbers.
+	   */
+	  token = &(tokens->tokens[tokens->nTokens - 1]);
+	} else {
+	  /*
+	   * If there are no format tokens, then a format token of
+	   * 1 is used to format all numbers.
+	   */
+	  token = &default_token;
+	}
+
+	/* Print separator, except for the first number */
+	if (i > 0) {
+	    if (token->separator != NULL)
+		xmlBufferCat(buffer, token->separator);
+	    else
+		xmlBufferCCat(buffer, DEFAULT_SEPARATOR);
+	}
+
+	switch (xmlXPathIsInf(number)) {
+	case -1:
+	    xmlBufferCCat(buffer, "-Infinity");
+	    break;
+	case 1:
+	    xmlBufferCCat(buffer, "Infinity");
+	    break;
+	default:
+	    if (xmlXPathIsNaN(number)) {
+		xmlBufferCCat(buffer, "NaN");
+	    } else {
+
+		switch (token->token) {
+		case 'A':
+		    xsltNumberFormatAlpha(buffer,
+					  number,
+					  TRUE);
+
+		    break;
+		case 'a':
+		    xsltNumberFormatAlpha(buffer,
+					  number,
+					  FALSE);
+
+		    break;
+		case 'I':
+		    xsltNumberFormatRoman(buffer,
+					  number,
+					  TRUE);
+
+		    break;
+		case 'i':
+		    xsltNumberFormatRoman(buffer,
+					  number,
+					  FALSE);
+
+		    break;
+		default:
+		    if (IS_DIGIT_ZERO(token->token)) {
+			xsltNumberFormatDecimal(buffer,
+						number,
+						token->token,
+						token->width,
+						data->digitsPerGroup,
+						data->groupingCharacter,
+						data->groupingCharacterLen);
+		    }
+		    break;
+		}
+	    }
+
+	}
+    }
+
+    /*
+     * Handle final non-alphanumeric token
+     */
+    if (tokens->end != NULL)
+	 xmlBufferCat(buffer, tokens->end);
+
+}
+
+static int
+xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context,
+			    xmlNodePtr node,
+			    const xmlChar *count,
+			    const xmlChar *from,
+			    double *array,
+			    xmlDocPtr doc,
+			    xmlNodePtr elem)
+{
+    int amount = 0;
+    int cnt = 0;
+    xmlNodePtr cur;
+    xsltCompMatchPtr countPat = NULL;
+    xsltCompMatchPtr fromPat = NULL;
+
+    if (count != NULL)
+	countPat = xsltCompilePattern(count, doc, elem, NULL, context);
+    if (from != NULL)
+	fromPat = xsltCompilePattern(from, doc, elem, NULL, context);
+	
+    /* select the starting node */
+    switch (node->type) {
+	case XML_ELEMENT_NODE:
+	    cur = node;
+	    break;
+	case XML_ATTRIBUTE_NODE:
+	    cur = ((xmlAttrPtr) node)->parent;
+	    break;
+	case XML_TEXT_NODE:
+	case XML_PI_NODE:
+	case XML_COMMENT_NODE:
+	    cur = node->parent;
+	    break;
+	default:
+	    cur = NULL;
+	    break;
+    }
+
+    while (cur != NULL) {
+	/* process current node */
+	if (count == NULL) {
+	    if ((node->type == cur->type) &&
+		/* FIXME: must use expanded-name instead of local name */
+		xmlStrEqual(node->name, cur->name)) {
+		    if ((node->ns == cur->ns) ||
+		        ((node->ns != NULL) &&
+			 (cur->ns != NULL) &&
+		         (xmlStrEqual(node->ns->href,
+		             cur->ns->href) )))
+		        cnt++;
+	    }
+	} else {
+	    if (xsltTestCompMatchList(context, cur, countPat))
+		cnt++;
+	}
+	if ((from != NULL) &&
+	    xsltTestCompMatchList(context, cur, fromPat)) {
+	    break; /* while */
+	}
+
+	/* Skip to next preceding or ancestor */
+	if ((cur->type == XML_DOCUMENT_NODE) ||
+#ifdef LIBXML_DOCB_ENABLED
+            (cur->type == XML_DOCB_DOCUMENT_NODE) ||
+#endif
+            (cur->type == XML_HTML_DOCUMENT_NODE))
+	    break; /* while */
+
+	while ((cur->prev != NULL) && ((cur->prev->type == XML_DTD_NODE) ||
+	       (cur->prev->type == XML_XINCLUDE_START) ||
+	       (cur->prev->type == XML_XINCLUDE_END)))
+	    cur = cur->prev;
+	if (cur->prev != NULL) {
+	    for (cur = cur->prev; cur->last != NULL; cur = cur->last);
+	} else {
+	    cur = cur->parent;
+	}
+
+    }
+
+    array[amount++] = (double) cnt;
+
+    if (countPat != NULL)
+	xsltFreeCompMatchList(countPat);
+    if (fromPat != NULL)
+	xsltFreeCompMatchList(fromPat);
+    return(amount);
+}
+
+static int
+xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context,
+				 xmlNodePtr node,
+				 const xmlChar *count,
+				 const xmlChar *from,
+				 double *array,
+				 int max,
+				 xmlDocPtr doc,
+				 xmlNodePtr elem)
+{
+    int amount = 0;
+    int cnt;
+    xmlNodePtr ancestor;
+    xmlNodePtr preceding;
+    xmlXPathParserContextPtr parser;
+    xsltCompMatchPtr countPat;
+    xsltCompMatchPtr fromPat;
+
+    if (count != NULL)
+	countPat = xsltCompilePattern(count, doc, elem, NULL, context);
+    else
+	countPat = NULL;
+    if (from != NULL)
+	fromPat = xsltCompilePattern(from, doc, elem, NULL, context);
+    else
+	fromPat = NULL;
+    context->xpathCtxt->node = node;
+    parser = xmlXPathNewParserContext(NULL, context->xpathCtxt);
+    if (parser) {
+	/* ancestor-or-self::*[count] */
+	for (ancestor = node;
+	     (ancestor != NULL) && (ancestor->type != XML_DOCUMENT_NODE);
+	     ancestor = xmlXPathNextAncestor(parser, ancestor)) {
+	    
+	    if ((from != NULL) &&
+		xsltTestCompMatchList(context, ancestor, fromPat))
+		break; /* for */
+	    
+	    if ((count == NULL && node->type == ancestor->type && 
+		xmlStrEqual(node->name, ancestor->name)) ||
+		xsltTestCompMatchList(context, ancestor, countPat)) {
+		/* count(preceding-sibling::*) */
+		cnt = 0;
+		for (preceding = ancestor;
+		     preceding != NULL;
+		     preceding = 
+		        xmlXPathNextPrecedingSibling(parser, preceding)) {
+		    if (count == NULL) {
+			if ((preceding->type == ancestor->type) &&
+			    xmlStrEqual(preceding->name, ancestor->name)){
+			    if ((preceding->ns == ancestor->ns) ||
+			        ((preceding->ns != NULL) &&
+				 (ancestor->ns != NULL) &&
+			         (xmlStrEqual(preceding->ns->href,
+			             ancestor->ns->href) )))
+			        cnt++;
+			}
+		    } else {
+			if (xsltTestCompMatchList(context, preceding,
+				                  countPat))
+			    cnt++;
+		    }
+		}
+		array[amount++] = (double)cnt;
+		if (amount >= max)
+		    break; /* for */
+	    }
+	}
+	xmlXPathFreeParserContext(parser);
+    }
+    xsltFreeCompMatchList(countPat);
+    xsltFreeCompMatchList(fromPat);
+    return amount;
+}
+
+static int
+xsltNumberFormatGetValue(xmlXPathContextPtr context,
+			 xmlNodePtr node,
+			 const xmlChar *value,
+			 double *number)
+{
+    int amount = 0;
+    xmlBufferPtr pattern;
+    xmlXPathObjectPtr obj;
+    
+    pattern = xmlBufferCreate();
+    if (pattern != NULL) {
+	xmlBufferCCat(pattern, "number(");
+	xmlBufferCat(pattern, value);
+	xmlBufferCCat(pattern, ")");
+	context->node = node;
+	obj = xmlXPathEvalExpression(xmlBufferContent(pattern),
+				     context);
+	if (obj != NULL) {
+	    *number = obj->floatval;
+	    amount++;
+	    xmlXPathFreeObject(obj);
+	}
+	xmlBufferFree(pattern);
+    }
+    return amount;
+}
+
+/**
+ * xsltNumberFormat:
+ * @ctxt: the XSLT transformation context
+ * @data: the formatting informations
+ * @node: the data to format
+ *
+ * Convert one number.
+ */
+void
+xsltNumberFormat(xsltTransformContextPtr ctxt,
+		 xsltNumberDataPtr data,
+		 xmlNodePtr node)
+{
+    xmlBufferPtr output = NULL;
+    int amount, i;
+    double number;
+    xsltFormat tokens;
+    int tempformat = 0;
+
+    if ((data->format == NULL) && (data->has_format != 0)) {
+	data->format = xsltEvalAttrValueTemplate(ctxt, data->node,
+					     (const xmlChar *) "format",
+					     XSLT_NAMESPACE);
+	tempformat = 1;
+    }
+    if (data->format == NULL) {
+	return;
+    }
+
+    output = xmlBufferCreate();
+    if (output == NULL)
+	goto XSLT_NUMBER_FORMAT_END;
+
+    xsltNumberFormatTokenize(data->format, &tokens);
+
+    /*
+     * Evaluate the XPath expression to find the value(s)
+     */
+    if (data->value) {
+	amount = xsltNumberFormatGetValue(ctxt->xpathCtxt,
+					  node,
+					  data->value,
+					  &number);
+	if (amount == 1) {
+	    xsltNumberFormatInsertNumbers(data,
+					  &number,
+					  1,
+					  &tokens,
+					  output);
+	}
+	
+    } else if (data->level) {
+	
+	if (xmlStrEqual(data->level, (const xmlChar *) "single")) {
+	    amount = xsltNumberFormatGetMultipleLevel(ctxt,
+						      node,
+						      data->count,
+						      data->from,
+						      &number,
+						      1,
+						      data->doc,
+						      data->node);
+	    if (amount == 1) {
+		xsltNumberFormatInsertNumbers(data,
+					      &number,
+					      1,
+					      &tokens,
+					      output);
+	    }
+	} else if (xmlStrEqual(data->level, (const xmlChar *) "multiple")) {
+	    double numarray[1024];
+	    int max = sizeof(numarray)/sizeof(numarray[0]);
+	    amount = xsltNumberFormatGetMultipleLevel(ctxt,
+						      node,
+						      data->count,
+						      data->from,
+						      numarray,
+						      max,
+						      data->doc,
+						      data->node);
+	    if (amount > 0) {
+		xsltNumberFormatInsertNumbers(data,
+					      numarray,
+					      amount,
+					      &tokens,
+					      output);
+	    }
+	} else if (xmlStrEqual(data->level, (const xmlChar *) "any")) {
+	    amount = xsltNumberFormatGetAnyLevel(ctxt,
+						 node,
+						 data->count,
+						 data->from,
+						 &number, 
+						 data->doc,
+						 data->node);
+	    if (amount > 0) {
+		xsltNumberFormatInsertNumbers(data,
+					      &number,
+					      1,
+					      &tokens,
+					      output);
+	    }
+	}
+    }
+    /* Insert number as text node */
+    xsltCopyTextString(ctxt, ctxt->insert, xmlBufferContent(output), 0);
+
+    if (tokens.start != NULL)
+	xmlFree(tokens.start);
+    if (tokens.end != NULL)
+	xmlFree(tokens.end);
+    for (i = 0;i < tokens.nTokens;i++) {
+	if (tokens.tokens[i].separator != NULL)
+	    xmlFree(tokens.tokens[i].separator);
+    }
+    
+XSLT_NUMBER_FORMAT_END:
+    if (tempformat == 1) {
+	/* The format need to be recomputed each time */
+	data->format = NULL;
+    }
+    if (output != NULL)
+	xmlBufferFree(output);
+}
+
+static int
+xsltFormatNumberPreSuffix(xsltDecimalFormatPtr self, xmlChar **format, xsltFormatNumberInfoPtr info)
+{
+    int	count=0;	/* will hold total length of prefix/suffix */
+    int len;
+
+    while (1) {
+	/* 
+	 * prefix / suffix ends at end of string or at 
+	 * first 'special' character 
+	 */
+	if (**format == 0)
+	    return count;
+	/* if next character 'escaped' just count it */
+	if (**format == SYMBOL_QUOTE) {
+	    if (*++(*format) == 0)
+		return -1;
+	}
+	else if (IS_SPECIAL(self, *format))
+	    return count;
+	/*
+	 * else treat percent/per-mille as special cases,
+	 * depending on whether +ve or -ve 
+	 */
+	else {
+	    /*
+	     * for +ve prefix/suffix, allow only a 
+	     * single occurence of either 
+	     */
+	    if (xsltUTF8Charcmp(*format, self->percent) == 0) {
+		if (info->is_multiplier_set)
+		    return -1;
+		info->multiplier = 100;
+		info->is_multiplier_set = TRUE;
+	    } else if (xsltUTF8Charcmp(*format, self->permille) == 0) {
+		if (info->is_multiplier_set)
+		    return -1;
+		info->multiplier = 1000;
+		info->is_multiplier_set = TRUE;
+	    }
+	}
+	
+	if ((len=xsltUTF8Size(*format)) < 1)
+	    return -1;
+	count += len;
+	*format += len;
+    }
+}
+	    
+/**
+ * xsltFormatNumberConversion:
+ * @self: the decimal format
+ * @format: the format requested
+ * @number: the value to format
+ * @result: the place to ouput the result
+ *
+ * format-number() uses the JDK 1.1 DecimalFormat class:
+ *
+ * http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html
+ *
+ * Structure:
+ *
+ *   pattern    := subpattern{;subpattern}
+ *   subpattern := {prefix}integer{.fraction}{suffix}
+ *   prefix     := '\\u0000'..'\\uFFFD' - specialCharacters
+ *   suffix     := '\\u0000'..'\\uFFFD' - specialCharacters
+ *   integer    := '#'* '0'* '0'
+ *   fraction   := '0'* '#'*
+ *
+ *   Notation:
+ *    X*       0 or more instances of X
+ *    (X | Y)  either X or Y.
+ *    X..Y     any character from X up to Y, inclusive.
+ *    S - T    characters in S, except those in T
+ *
+ * Special Characters:
+ *
+ *   Symbol Meaning
+ *   0      a digit
+ *   #      a digit, zero shows as absent
+ *   .      placeholder for decimal separator
+ *   ,      placeholder for grouping separator.
+ *   ;      separates formats.
+ *   -      default negative prefix.
+ *   %      multiply by 100 and show as percentage
+ *   ?      multiply by 1000 and show as per mille
+ *   X      any other characters can be used in the prefix or suffix
+ *   '      used to quote special characters in a prefix or suffix.
+ *
+ * Returns a possible XPath error
+ */
+xmlXPathError
+xsltFormatNumberConversion(xsltDecimalFormatPtr self,
+			   xmlChar *format,
+			   double number,
+			   xmlChar **result)
+{
+    xmlXPathError status = XPATH_EXPRESSION_OK;
+    xmlBufferPtr buffer;
+    xmlChar *the_format, *prefix = NULL, *suffix = NULL;
+    xmlChar *nprefix, *nsuffix = NULL;
+    xmlChar pchar;
+    int	    prefix_length, suffix_length = 0, nprefix_length, nsuffix_length;
+    double  scale;
+    int	    j, len;
+    int     self_grouping_len;
+    xsltFormatNumberInfo format_info;
+    /* 
+     * delayed_multiplier allows a 'trailing' percent or
+     * permille to be treated as suffix 
+     */
+    int		delayed_multiplier = 0;
+    /* flag to show no -ve format present for -ve number */
+    char	default_sign = 0;
+    /* flag to show error found, should use default format */
+    char	found_error = 0;
+
+    if (xmlStrlen(format) <= 0) {
+	xsltTransformError(NULL, NULL, NULL,
+                "xsltFormatNumberConversion : "
+		"Invalid format (0-length)\n");
+    }
+    *result = NULL;
+    switch (xmlXPathIsInf(number)) {
+	case -1:
+	    if (self->minusSign == NULL)
+		*result = xmlStrdup(BAD_CAST "-");
+	    else
+		*result = xmlStrdup(self->minusSign);
+	    /* no-break on purpose */
+	case 1:
+	    if ((self == NULL) || (self->infinity == NULL))
+		*result = xmlStrcat(*result, BAD_CAST "Infinity");
+	    else
+		*result = xmlStrcat(*result, self->infinity);
+	    return(status);
+	default:
+	    if (xmlXPathIsNaN(number)) {
+		if ((self == NULL) || (self->noNumber == NULL))
+		    *result = xmlStrdup(BAD_CAST "NaN");
+		else
+		    *result = xmlStrdup(self->noNumber);
+		return(status);
+	    }
+    }
+
+    buffer = xmlBufferCreate();
+    if (buffer == NULL) {
+	return XPATH_MEMORY_ERROR;
+    }
+
+    format_info.integer_hash = 0;
+    format_info.integer_digits = 0;
+    format_info.frac_digits = 0;
+    format_info.frac_hash = 0;
+    format_info.group = -1;
+    format_info.multiplier = 1;
+    format_info.add_decimal = FALSE;
+    format_info.is_multiplier_set = FALSE;
+    format_info.is_negative_pattern = FALSE;
+
+    the_format = format;
+
+    /*
+     * First we process the +ve pattern to get percent / permille,
+     * as well as main format 
+     */
+    prefix = the_format;
+    prefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
+    if (prefix_length < 0) {
+	found_error = 1;
+	goto OUTPUT_NUMBER;
+    }
+
+    /* 
+     * Here we process the "number" part of the format.  It gets 
+     * a little messy because of the percent/per-mille - if that
+     * appears at the end, it may be part of the suffix instead 
+     * of part of the number, so the variable delayed_multiplier 
+     * is used to handle it 
+     */
+    self_grouping_len = xmlStrlen(self->grouping);
+    while ((*the_format != 0) &&
+	   (xsltUTF8Charcmp(the_format, self->decimalPoint) != 0) &&
+	   (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) {
+	
+	if (delayed_multiplier != 0) {
+	    format_info.multiplier = delayed_multiplier;
+	    format_info.is_multiplier_set = TRUE;
+	    delayed_multiplier = 0;
+	}
+	if (xsltUTF8Charcmp(the_format, self->digit) == 0) {
+	    if (format_info.integer_digits > 0) {
+		found_error = 1;
+		goto OUTPUT_NUMBER;
+	    }
+	    format_info.integer_hash++;
+	    if (format_info.group >= 0)
+		format_info.group++;
+	} else if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) {
+	    format_info.integer_digits++;
+	    if (format_info.group >= 0)
+		format_info.group++;
+	} else if ((self_grouping_len > 0) &&
+	    (!xmlStrncmp(the_format, self->grouping, self_grouping_len))) {
+	    /* Reset group count */
+	    format_info.group = 0;
+	    the_format += self_grouping_len;
+	    continue;
+	} else if (xsltUTF8Charcmp(the_format, self->percent) == 0) {
+	    if (format_info.is_multiplier_set) {
+		found_error = 1;
+		goto OUTPUT_NUMBER;
+	    }
+	    delayed_multiplier = 100;
+	} else  if (xsltUTF8Charcmp(the_format, self->permille) == 0) {
+	    if (format_info.is_multiplier_set) {
+		found_error = 1;
+		goto OUTPUT_NUMBER;
+	    }
+	    delayed_multiplier = 1000;
+	} else
+	    break; /* while */
+	
+	if ((len=xsltUTF8Size(the_format)) < 1) {
+	    found_error = 1;
+	    goto OUTPUT_NUMBER;
+	}
+	the_format += len;
+
+    }
+
+    /* We have finished the integer part, now work on fraction */
+    if (xsltUTF8Charcmp(the_format, self->decimalPoint) == 0) {
+        format_info.add_decimal = TRUE;
+	the_format += xsltUTF8Size(the_format);	/* Skip over the decimal */
+    }
+    
+    while (*the_format != 0) {
+	
+	if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) {
+	    if (format_info.frac_hash != 0) {
+		found_error = 1;
+		goto OUTPUT_NUMBER;
+	    }
+	    format_info.frac_digits++;
+	} else if (xsltUTF8Charcmp(the_format, self->digit) == 0) {
+	    format_info.frac_hash++;
+	} else if (xsltUTF8Charcmp(the_format, self->percent) == 0) {
+	    if (format_info.is_multiplier_set) {
+		found_error = 1;
+		goto OUTPUT_NUMBER;
+	    }
+	    delayed_multiplier = 100;
+	    if ((len = xsltUTF8Size(the_format)) < 1) {
+	        found_error = 1;
+		goto OUTPUT_NUMBER;
+	    }
+	    the_format += len;
+	    continue; /* while */
+	} else if (xsltUTF8Charcmp(the_format, self->permille) == 0) {
+	    if (format_info.is_multiplier_set) {
+		found_error = 1;
+		goto OUTPUT_NUMBER;
+	    }
+	    delayed_multiplier = 1000;
+	    if  ((len = xsltUTF8Size(the_format)) < 1) {
+	        found_error = 1;
+		goto OUTPUT_NUMBER;
+	    }
+	    the_format += len;
+	    continue; /* while */
+	} else if (xsltUTF8Charcmp(the_format, self->grouping) != 0) {
+	    break; /* while */
+	}
+	if ((len = xsltUTF8Size(the_format)) < 1) {
+	    found_error = 1;
+	    goto OUTPUT_NUMBER;
+	}
+	the_format += len;
+	if (delayed_multiplier != 0) {
+	    format_info.multiplier = delayed_multiplier;
+	    delayed_multiplier = 0;
+	    format_info.is_multiplier_set = TRUE;
+	}
+    }
+
+    /* 
+     * If delayed_multiplier is set after processing the 
+     * "number" part, should be in suffix 
+     */
+    if (delayed_multiplier != 0) {
+	the_format -= len;
+	delayed_multiplier = 0;
+    }
+
+    suffix = the_format;
+    suffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
+    if ( (suffix_length < 0) ||
+	 ((*the_format != 0) && 
+	  (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) ) {
+	found_error = 1;
+	goto OUTPUT_NUMBER;
+    }
+
+    /*
+     * We have processed the +ve prefix, number part and +ve suffix.
+     * If the number is -ve, we must substitute the -ve prefix / suffix
+     */
+    if (number < 0) {
+        /*
+	 * Note that j is the number of UTF8 chars before the separator,
+	 * not the number of bytes! (bug 151975)
+	 */
+        j =  xmlUTF8Strloc(format, self->patternSeparator);
+	if (j < 0) {
+	/* No -ve pattern present, so use default signing */
+	    default_sign = 1;
+	}
+	else {
+	    /* Skip over pattern separator (accounting for UTF8) */
+	    the_format = (xmlChar *)xmlUTF8Strpos(format, j + 1);
+	    /* 
+	     * Flag changes interpretation of percent/permille 
+	     * in -ve pattern 
+	     */
+	    format_info.is_negative_pattern = TRUE;
+	    format_info.is_multiplier_set = FALSE;
+
+	    /* First do the -ve prefix */
+	    nprefix = the_format;
+	    nprefix_length = xsltFormatNumberPreSuffix(self, 
+	    				&the_format, &format_info);
+	    if (nprefix_length<0) {
+		found_error = 1;
+		goto OUTPUT_NUMBER;
+	    }
+
+	    while (*the_format != 0) {
+		if ( (xsltUTF8Charcmp(the_format, (self)->percent) == 0) ||
+		     (xsltUTF8Charcmp(the_format, (self)->permille)== 0) ) {
+		    if (format_info.is_multiplier_set) {
+			found_error = 1;
+			goto OUTPUT_NUMBER;
+		    }
+		    format_info.is_multiplier_set = TRUE;
+		    delayed_multiplier = 1;
+		}
+		else if (IS_SPECIAL(self, the_format))
+		    delayed_multiplier = 0;
+		else
+		    break; /* while */
+		if ((len = xsltUTF8Size(the_format)) < 1) {
+		    found_error = 1;
+		    goto OUTPUT_NUMBER;
+		}
+		the_format += len;
+	    }
+	    if (delayed_multiplier != 0) {
+		format_info.is_multiplier_set = FALSE;
+		the_format -= len;
+	    }
+
+	    /* Finally do the -ve suffix */
+	    if (*the_format != 0) {
+		nsuffix = the_format;
+		nsuffix_length = xsltFormatNumberPreSuffix(self, 
+					&the_format, &format_info);
+		if (nsuffix_length < 0) {
+		    found_error = 1;
+		    goto OUTPUT_NUMBER;
+		}
+	    }
+	    else
+		nsuffix_length = 0;
+	    if (*the_format != 0) {
+		found_error = 1;
+		goto OUTPUT_NUMBER;
+	    }
+	    /*
+	     * Here's another Java peculiarity:
+	     * if -ve prefix/suffix == +ve ones, discard & use default
+	     */
+	    if ((nprefix_length != prefix_length) ||
+	    	(nsuffix_length != suffix_length) ||
+		((nprefix_length > 0) && 
+		 (xmlStrncmp(nprefix, prefix, prefix_length) !=0 )) ||
+		((nsuffix_length > 0) && 
+		 (xmlStrncmp(nsuffix, suffix, suffix_length) !=0 ))) {
+	 	prefix = nprefix;
+		prefix_length = nprefix_length;
+		suffix = nsuffix;
+		suffix_length = nsuffix_length;
+	    } /* else {
+		default_sign = 1;
+	    }
+	    */
+	}
+    }
+
+OUTPUT_NUMBER:
+    if (found_error != 0) {
+	xsltTransformError(NULL, NULL, NULL,
+                "xsltFormatNumberConversion : "
+		"error in format string '%s', using default\n", format);
+	default_sign = (number < 0.0) ? 1 : 0;
+	prefix_length = suffix_length = 0;
+	format_info.integer_hash = 0;
+	format_info.integer_digits = 1;
+	format_info.frac_digits = 1;
+	format_info.frac_hash = 4;
+	format_info.group = -1;
+	format_info.multiplier = 1;
+	format_info.add_decimal = TRUE;
+    }
+
+    /* Ready to output our number.  First see if "default sign" is required */
+    if (default_sign != 0)
+	xmlBufferAdd(buffer, self->minusSign, xsltUTF8Size(self->minusSign));
+
+    /* Put the prefix into the buffer */
+    for (j = 0; j < prefix_length; j++) {
+	if ((pchar = *prefix++) == SYMBOL_QUOTE) {
+	    len = xsltUTF8Size(prefix);
+	    xmlBufferAdd(buffer, prefix, len);
+	    prefix += len;
+	    j += len - 1;	/* length of symbol less length of quote */
+	} else
+	    xmlBufferAdd(buffer, &pchar, 1);
+    }
+
+    /* Next do the integer part of the number */
+    number = fabs(number) * (double)format_info.multiplier;
+    scale = pow(10.0, (double)(format_info.frac_digits + format_info.frac_hash));
+    number = floor((scale * number + 0.5)) / scale;
+    if ((self->grouping != NULL) && 
+        (self->grouping[0] != 0)) {
+	
+	len = xmlStrlen(self->grouping);
+	pchar = xsltGetUTF8Char(self->grouping, &len);
+	xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
+				format_info.integer_digits,
+				format_info.group,
+				pchar, len);
+    } else
+	xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
+				format_info.integer_digits,
+				format_info.group,
+				',', 1);
+
+    /* Special case: java treats '.#' like '.0', '.##' like '.0#', etc. */
+    if ((format_info.integer_digits + format_info.integer_hash +
+	 format_info.frac_digits == 0) && (format_info.frac_hash > 0)) {
+        ++format_info.frac_digits;
+	--format_info.frac_hash;
+    }
+
+    /* Add leading zero, if required */
+    if ((floor(number) == 0) &&
+	(format_info.integer_digits + format_info.frac_digits == 0)) {
+        xmlBufferAdd(buffer, self->zeroDigit, xsltUTF8Size(self->zeroDigit));
+    }
+
+    /* Next the fractional part, if required */
+    if (format_info.frac_digits + format_info.frac_hash == 0) {
+        if (format_info.add_decimal)
+	    xmlBufferAdd(buffer, self->decimalPoint, 
+	    		 xsltUTF8Size(self->decimalPoint));
+    }
+    else {
+      number -= floor(number);
+	if ((number != 0) || (format_info.frac_digits != 0)) {
+	    xmlBufferAdd(buffer, self->decimalPoint,
+	    		 xsltUTF8Size(self->decimalPoint));
+	    number = floor(scale * number + 0.5);
+	    for (j = format_info.frac_hash; j > 0; j--) {
+		if (fmod(number, 10.0) >= 1.0)
+		    break; /* for */
+		number /= 10.0;
+	    }
+	    xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
+				format_info.frac_digits + j,
+				0, 0, 0);
+	}
+    }
+    /* Put the suffix into the buffer */
+    for (j = 0; j < suffix_length; j++) {
+	if ((pchar = *suffix++) == SYMBOL_QUOTE) {
+            len = xsltUTF8Size(suffix);
+	    xmlBufferAdd(buffer, suffix, len);
+	    suffix += len;
+	    j += len - 1;	/* length of symbol less length of escape */
+	} else
+	    xmlBufferAdd(buffer, &pchar, 1);
+    }
+
+    *result = xmlStrdup(xmlBufferContent(buffer));
+    xmlBufferFree(buffer);
+    return status;
+}
+
diff --git a/libxslt/numbersInternals.h b/libxslt/numbersInternals.h
new file mode 100644
index 0000000..7b3cb17
--- /dev/null
+++ b/libxslt/numbersInternals.h
@@ -0,0 +1,69 @@
+/*
+ * Summary: Implementation of the XSLT number functions
+ * Description: Implementation of the XSLT number functions
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Bjorn Reese <breese@users.sourceforge.net> and Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_NUMBERSINTERNALS_H__
+#define __XML_XSLT_NUMBERSINTERNALS_H__
+
+#include <libxml/tree.h>
+#include "xsltexports.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * xsltNumberData:
+ *
+ * This data structure is just a wrapper to pass xsl:number data in.
+ */
+typedef struct _xsltNumberData xsltNumberData;
+typedef xsltNumberData *xsltNumberDataPtr;
+    
+struct _xsltNumberData {
+    const xmlChar *level;
+    const xmlChar *count;
+    const xmlChar *from;
+    const xmlChar *value;
+    const xmlChar *format;
+    int has_format;
+    int digitsPerGroup;
+    int groupingCharacter;
+    int groupingCharacterLen;
+    xmlDocPtr doc;
+    xmlNodePtr node;
+
+    /*
+     * accelerators
+     */
+};
+
+/**
+ * xsltFormatNumberInfo,:
+ *
+ * This data structure lists the various parameters needed to format numbers.
+ */
+typedef struct _xsltFormatNumberInfo xsltFormatNumberInfo;
+typedef xsltFormatNumberInfo *xsltFormatNumberInfoPtr;
+
+struct _xsltFormatNumberInfo {
+    int	    integer_hash;	/* Number of '#' in integer part */
+    int	    integer_digits;	/* Number of '0' in integer part */
+    int	    frac_digits;	/* Number of '0' in fractional part */
+    int	    frac_hash;		/* Number of '#' in fractional part */
+    int	    group;		/* Number of chars per display 'group' */
+    int     multiplier;		/* Scaling for percent or permille */
+    char    add_decimal;	/* Flag for whether decimal point appears in pattern */
+    char    is_multiplier_set;	/* Flag to catch multiple occurences of percent/permille */
+    char    is_negative_pattern;/* Flag for processing -ve prefix/suffix */
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_XSLT_NUMBERSINTERNALS_H__ */
diff --git a/libxslt/pattern.c b/libxslt/pattern.c
new file mode 100644
index 0000000..8ce74e3
--- /dev/null
+++ b/libxslt/pattern.c
@@ -0,0 +1,2509 @@
+/*
+ * pattern.c: Implemetation of the template match compilation and lookup
+ *
+ * Reference:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+/*
+ * TODO: handle pathological cases like *[*[@a="b"]]
+ * TODO: detect [number] at compilation, optimize accordingly
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+#include <libxml/hash.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parserInternals.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "imports.h"
+#include "templates.h"
+#include "keys.h"
+#include "pattern.h"
+#include "documents.h"
+
+#ifdef WITH_XSLT_DEBUG
+#define WITH_XSLT_DEBUG_PATTERN
+#endif
+
+/*
+ * Types are private:
+ */
+
+typedef enum {
+    XSLT_OP_END=0,
+    XSLT_OP_ROOT,
+    XSLT_OP_ELEM,
+    XSLT_OP_ATTR,
+    XSLT_OP_PARENT,
+    XSLT_OP_ANCESTOR,
+    XSLT_OP_ID,
+    XSLT_OP_KEY,
+    XSLT_OP_NS,
+    XSLT_OP_ALL,
+    XSLT_OP_PI,
+    XSLT_OP_COMMENT,
+    XSLT_OP_TEXT,
+    XSLT_OP_NODE,
+    XSLT_OP_PREDICATE
+} xsltOp;
+
+typedef enum {
+    AXIS_CHILD=1,
+    AXIS_ATTRIBUTE
+} xsltAxis;
+
+typedef struct _xsltStepState xsltStepState;
+typedef xsltStepState *xsltStepStatePtr;
+struct _xsltStepState {
+    int step;
+    xmlNodePtr node;
+};
+
+typedef struct _xsltStepStates xsltStepStates;
+typedef xsltStepStates *xsltStepStatesPtr;
+struct _xsltStepStates {
+    int nbstates;
+    int maxstates;
+    xsltStepStatePtr states;
+};
+
+typedef struct _xsltStepOp xsltStepOp;
+typedef xsltStepOp *xsltStepOpPtr;
+struct _xsltStepOp {
+    xsltOp op;
+    xmlChar *value;
+    xmlChar *value2;
+    xmlChar *value3;
+    xmlXPathCompExprPtr comp;
+    /*
+     * Optimisations for count
+     */
+    int        previousExtra;
+    int        indexExtra;
+    int        lenExtra;
+};
+
+struct _xsltCompMatch {
+    struct _xsltCompMatch *next; /* siblings in the name hash */
+    float priority;              /* the priority */
+    const xmlChar *pattern;       /* the pattern */
+    const xmlChar *mode;         /* the mode */
+    const xmlChar *modeURI;      /* the mode URI */
+    xsltTemplatePtr template;    /* the associated template */
+
+    int direct;
+    /* TODO fix the statically allocated size steps[] */
+    int nbStep;
+    int maxStep;
+    xmlNsPtr *nsList;		/* the namespaces in scope */
+    int nsNr;			/* the number of namespaces in scope */
+    xsltStepOpPtr steps;        /* ops for computation */
+};
+
+typedef struct _xsltParserContext xsltParserContext;
+typedef xsltParserContext *xsltParserContextPtr;
+struct _xsltParserContext {
+    xsltStylesheetPtr style;		/* the stylesheet */
+    xsltTransformContextPtr ctxt;	/* the transformation or NULL */
+    const xmlChar *cur;			/* the current char being parsed */
+    const xmlChar *base;		/* the full expression */
+    xmlDocPtr      doc;			/* the source document */
+    xmlNodePtr    elem;			/* the source element */
+    int error;				/* error code */
+    xsltCompMatchPtr comp;		/* the result */
+};
+
+/************************************************************************
+ * 									*
+ * 			Type functions 					*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltNewCompMatch:
+ *
+ * Create a new XSLT CompMatch
+ *
+ * Returns the newly allocated xsltCompMatchPtr or NULL in case of error
+ */
+static xsltCompMatchPtr
+xsltNewCompMatch(void) {
+    xsltCompMatchPtr cur;
+
+    cur = (xsltCompMatchPtr) xmlMalloc(sizeof(xsltCompMatch));
+    if (cur == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+		"xsltNewCompMatch : out of memory error\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltCompMatch));
+    cur->maxStep = 10;
+    cur->nbStep = 0;
+    cur-> steps = (xsltStepOpPtr) xmlMalloc(sizeof(xsltStepOp) *
+                                            cur->maxStep);
+    if (cur->steps == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+		"xsltNewCompMatch : out of memory error\n");
+	xmlFree(cur);
+	return(NULL);
+    }
+    cur->nsNr = 0;
+    cur->nsList = NULL;
+    cur->direct = 0;
+    return(cur);
+}
+
+/**
+ * xsltFreeCompMatch:
+ * @comp:  an XSLT comp
+ *
+ * Free up the memory allocated by @comp
+ */
+static void
+xsltFreeCompMatch(xsltCompMatchPtr comp) {
+    xsltStepOpPtr op;
+    int i;
+
+    if (comp == NULL)
+	return;
+    if (comp->pattern != NULL)
+	xmlFree((xmlChar *)comp->pattern);
+    if (comp->nsList != NULL)
+	xmlFree(comp->nsList);
+    for (i = 0;i < comp->nbStep;i++) {
+	op = &comp->steps[i];
+	if (op->value != NULL)
+	    xmlFree(op->value);
+	if (op->value2 != NULL)
+	    xmlFree(op->value2);
+	if (op->value3 != NULL)
+	    xmlFree(op->value3);
+	if (op->comp != NULL)
+	    xmlXPathFreeCompExpr(op->comp);
+    }
+    xmlFree(comp->steps);
+    memset(comp, -1, sizeof(xsltCompMatch));
+    xmlFree(comp);
+}
+
+/**
+ * xsltFreeCompMatchList:
+ * @comp:  an XSLT comp list
+ *
+ * Free up the memory allocated by all the elements of @comp
+ */
+void
+xsltFreeCompMatchList(xsltCompMatchPtr comp) {
+    xsltCompMatchPtr cur;
+
+    while (comp != NULL) {
+	cur = comp;
+	comp = comp->next;
+	xsltFreeCompMatch(cur);
+    }
+}
+
+/**
+ * xsltNormalizeCompSteps:
+ * @payload: pointer to template hash table entry
+ * @data: pointer to the stylesheet
+ * @name: template match name
+ *
+ * This is a hashtable scanner function to normalize the compiled
+ * steps of an imported stylesheet.
+ */
+void xsltNormalizeCompSteps(void *payload,
+        void *data, const xmlChar *name ATTRIBUTE_UNUSED) {
+    xsltCompMatchPtr comp = payload;
+    xsltStylesheetPtr style = data;
+    int ix;
+
+    for (ix = 0; ix < comp->nbStep; ix++) {
+        comp->steps[ix].previousExtra += style->extrasNr;
+        comp->steps[ix].indexExtra += style->extrasNr;
+        comp->steps[ix].lenExtra += style->extrasNr;
+    }
+}
+
+/**
+ * xsltNewParserContext:
+ * @style:  the stylesheet
+ * @ctxt:  the transformation context, if done at run-time
+ *
+ * Create a new XSLT ParserContext
+ *
+ * Returns the newly allocated xsltParserContextPtr or NULL in case of error
+ */
+static xsltParserContextPtr
+xsltNewParserContext(xsltStylesheetPtr style, xsltTransformContextPtr ctxt) {
+    xsltParserContextPtr cur;
+
+    cur = (xsltParserContextPtr) xmlMalloc(sizeof(xsltParserContext));
+    if (cur == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+		"xsltNewParserContext : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltParserContext));
+    cur->style = style;
+    cur->ctxt = ctxt;
+    return(cur);
+}
+
+/**
+ * xsltFreeParserContext:
+ * @ctxt:  an XSLT parser context
+ *
+ * Free up the memory allocated by @ctxt
+ */
+static void
+xsltFreeParserContext(xsltParserContextPtr ctxt) {
+    if (ctxt == NULL)
+	return;
+    memset(ctxt, -1, sizeof(xsltParserContext));
+    xmlFree(ctxt);
+}
+
+/**
+ * xsltCompMatchAdd:
+ * @comp:  the compiled match expression
+ * @op:  an op
+ * @value:  the first value
+ * @value2:  the second value
+ * @novar:  flag to set XML_XPATH_NOVAR
+ *
+ * Add an step to an XSLT Compiled Match
+ *
+ * Returns -1 in case of failure, 0 otherwise.
+ */
+static int
+xsltCompMatchAdd(xsltParserContextPtr ctxt, xsltCompMatchPtr comp,
+                 xsltOp op, xmlChar * value, xmlChar * value2, int novar)
+{
+    if (comp->nbStep >= comp->maxStep) {
+        xsltStepOpPtr tmp;
+
+	tmp = (xsltStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
+	                                 sizeof(xsltStepOp));
+	if (tmp == NULL) {
+	    xsltGenericError(xsltGenericErrorContext,
+	     "xsltCompMatchAdd: memory re-allocation failure.\n");
+	    if (ctxt->style != NULL)
+		ctxt->style->errors++;
+	    return (-1);
+	}
+        comp->maxStep *= 2;
+	comp->steps = tmp;
+    }
+    comp->steps[comp->nbStep].op = op;
+    comp->steps[comp->nbStep].value = value;
+    comp->steps[comp->nbStep].value2 = value2;
+    comp->steps[comp->nbStep].value3 = NULL;
+    comp->steps[comp->nbStep].comp = NULL;
+    if (ctxt->ctxt != NULL) {
+	comp->steps[comp->nbStep].previousExtra =
+	    xsltAllocateExtraCtxt(ctxt->ctxt);
+	comp->steps[comp->nbStep].indexExtra =
+	    xsltAllocateExtraCtxt(ctxt->ctxt);
+	comp->steps[comp->nbStep].lenExtra =
+	    xsltAllocateExtraCtxt(ctxt->ctxt);
+    } else {
+	comp->steps[comp->nbStep].previousExtra =
+	    xsltAllocateExtra(ctxt->style);
+	comp->steps[comp->nbStep].indexExtra =
+	    xsltAllocateExtra(ctxt->style);
+	comp->steps[comp->nbStep].lenExtra =
+	    xsltAllocateExtra(ctxt->style);
+    }
+    if (op == XSLT_OP_PREDICATE) {
+	xmlXPathContextPtr xctxt;
+
+	if (ctxt->style != NULL)
+	    xctxt = xmlXPathNewContext(ctxt->style->doc);
+	else
+	    xctxt = xmlXPathNewContext(NULL);
+#ifdef XML_XPATH_NOVAR
+	if (novar != 0)
+	    xctxt->flags = XML_XPATH_NOVAR;
+#endif
+	if (ctxt->style != NULL)
+	    xctxt->dict = ctxt->style->dict;
+	comp->steps[comp->nbStep].comp = xmlXPathCtxtCompile(xctxt, value);
+	xmlXPathFreeContext(xctxt);
+	if (comp->steps[comp->nbStep].comp == NULL) {
+	    xsltTransformError(NULL, ctxt->style, ctxt->elem,
+		    "Failed to compile predicate\n");
+	    if (ctxt->style != NULL)
+		ctxt->style->errors++;
+	}
+    }
+    comp->nbStep++;
+    return (0);
+}
+
+/**
+ * xsltSwapTopCompMatch:
+ * @comp:  the compiled match expression
+ *
+ * reverse the two top steps.
+ */
+static void
+xsltSwapTopCompMatch(xsltCompMatchPtr comp) {
+    int i;
+    int j = comp->nbStep - 1;
+
+    if (j > 0) {
+	register xmlChar *tmp;
+	register xsltOp op;
+	register xmlXPathCompExprPtr expr; 
+	register int t;
+	i = j - 1;
+	tmp = comp->steps[i].value;
+	comp->steps[i].value = comp->steps[j].value;
+	comp->steps[j].value = tmp;
+	tmp = comp->steps[i].value2;
+	comp->steps[i].value2 = comp->steps[j].value2;
+	comp->steps[j].value2 = tmp;
+	tmp = comp->steps[i].value3;
+	comp->steps[i].value3 = comp->steps[j].value3;
+	comp->steps[j].value3 = tmp;
+	op = comp->steps[i].op;
+	comp->steps[i].op = comp->steps[j].op;
+	comp->steps[j].op = op;
+	expr = comp->steps[i].comp;
+	comp->steps[i].comp = comp->steps[j].comp;
+	comp->steps[j].comp = expr;
+	t = comp->steps[i].previousExtra;
+	comp->steps[i].previousExtra = comp->steps[j].previousExtra;
+	comp->steps[j].previousExtra = t;
+	t = comp->steps[i].indexExtra;
+	comp->steps[i].indexExtra = comp->steps[j].indexExtra;
+	comp->steps[j].indexExtra = t;
+	t = comp->steps[i].lenExtra;
+	comp->steps[i].lenExtra = comp->steps[j].lenExtra;
+	comp->steps[j].lenExtra = t;
+    }
+}
+
+/**
+ * xsltReverseCompMatch:
+ * @ctxt: the parser context
+ * @comp:  the compiled match expression
+ *
+ * reverse all the stack of expressions
+ */
+static void
+xsltReverseCompMatch(xsltParserContextPtr ctxt, xsltCompMatchPtr comp) {
+    int i = 0;
+    int j = comp->nbStep - 1;
+
+    while (j > i) {
+	register xmlChar *tmp;
+	register xsltOp op;
+	register xmlXPathCompExprPtr expr;
+	register int t;
+
+	tmp = comp->steps[i].value;
+	comp->steps[i].value = comp->steps[j].value;
+	comp->steps[j].value = tmp;
+	tmp = comp->steps[i].value2;
+	comp->steps[i].value2 = comp->steps[j].value2;
+	comp->steps[j].value2 = tmp;
+	tmp = comp->steps[i].value3;
+	comp->steps[i].value3 = comp->steps[j].value3;
+	comp->steps[j].value3 = tmp;
+	op = comp->steps[i].op;
+	comp->steps[i].op = comp->steps[j].op;
+	comp->steps[j].op = op;
+	expr = comp->steps[i].comp;
+	comp->steps[i].comp = comp->steps[j].comp;
+	comp->steps[j].comp = expr;
+	t = comp->steps[i].previousExtra;
+	comp->steps[i].previousExtra = comp->steps[j].previousExtra;
+	comp->steps[j].previousExtra = t;
+	t = comp->steps[i].indexExtra;
+	comp->steps[i].indexExtra = comp->steps[j].indexExtra;
+	comp->steps[j].indexExtra = t;
+	t = comp->steps[i].lenExtra;
+	comp->steps[i].lenExtra = comp->steps[j].lenExtra;
+	comp->steps[j].lenExtra = t;
+	j--;
+	i++;
+    }
+    xsltCompMatchAdd(ctxt, comp, XSLT_OP_END, NULL, NULL, 0);
+
+    /*
+     * detect consecutive XSLT_OP_PREDICATE indicating a direct
+     * matching should be done.
+     */
+    for (i = 0;i < comp->nbStep - 1;i++) {
+        if ((comp->steps[i].op == XSLT_OP_PREDICATE) &&
+	    (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) {
+
+	    comp->direct = 1;
+	    if (comp->pattern[0] != '/') {
+		xmlChar *query;
+
+		query = xmlStrdup((const xmlChar *)"//");
+		query = xmlStrcat(query, comp->pattern);
+
+		xmlFree((xmlChar *) comp->pattern);
+		comp->pattern = query;
+	    }
+	    break;
+	}
+    }
+}
+
+/************************************************************************
+ * 									*
+ * 		The interpreter for the precompiled patterns		*
+ * 									*
+ ************************************************************************/
+
+static int
+xsltPatPushState(xsltTransformContextPtr ctxt, xsltStepStates *states,
+                 int step, xmlNodePtr node) {
+    if ((states->states == NULL) || (states->maxstates <= 0)) {
+        states->maxstates = 4;
+	states->nbstates = 0;
+	states->states = xmlMalloc(4 * sizeof(xsltStepState));
+    }
+    else if (states->maxstates <= states->nbstates) {
+        xsltStepState *tmp;
+
+	tmp = (xsltStepStatePtr) xmlRealloc(states->states,
+			       2 * states->maxstates * sizeof(xsltStepState));
+	if (tmp == NULL) {
+	    xsltGenericError(xsltGenericErrorContext,
+	     "xsltPatPushState: memory re-allocation failure.\n");
+	    ctxt->state = XSLT_STATE_STOPPED;
+	    return(-1);
+	}
+	states->states = tmp;
+	states->maxstates *= 2;
+    }
+    states->states[states->nbstates].step = step;
+    states->states[states->nbstates++].node = node;
+#if 0
+    fprintf(stderr, "Push: %d, %s\n", step, node->name);
+#endif
+    return(0);
+}
+
+/**
+ * xsltTestCompMatchDirect:
+ * @ctxt:  a XSLT process context
+ * @comp: the precompiled pattern
+ * @node: a node
+ * @nsList: the namespaces in scope
+ * @nsNr: the number of namespaces in scope
+ *
+ * Test whether the node matches the pattern, do a direct evalutation
+ * and not a step by step evaluation.
+ *
+ * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
+ */
+static int
+xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
+	                xmlNodePtr node, xmlNsPtr *nsList, int nsNr) {
+    xsltStepOpPtr sel = NULL;
+    xmlDocPtr prevdoc;
+    xmlDocPtr doc;
+    xmlXPathObjectPtr list;
+    int ix, j;
+    int nocache = 0;
+    int isRVT;
+
+    doc = node->doc;
+    if (XSLT_IS_RES_TREE_FRAG(doc))
+	isRVT = 1;
+    else
+	isRVT = 0;
+    sel = &comp->steps[0]; /* store extra in first step arbitrarily */
+
+    prevdoc = (xmlDocPtr)
+	XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
+    ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
+    list = (xmlXPathObjectPtr)
+	XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra);
+    
+    if ((list == NULL) || (prevdoc != doc)) {
+	xmlXPathObjectPtr newlist;
+	xmlNodePtr parent = node->parent;
+	xmlDocPtr olddoc;
+	xmlNodePtr oldnode;
+	int oldNsNr;
+	xmlNsPtr *oldNamespaces;
+
+	oldnode = ctxt->xpathCtxt->node;
+	olddoc = ctxt->xpathCtxt->doc;
+	oldNsNr = ctxt->xpathCtxt->nsNr;
+	oldNamespaces = ctxt->xpathCtxt->namespaces;
+	ctxt->xpathCtxt->node = node;
+	ctxt->xpathCtxt->doc = doc;
+	ctxt->xpathCtxt->namespaces = nsList;
+	ctxt->xpathCtxt->nsNr = nsNr;
+	newlist = xmlXPathEval(comp->pattern, ctxt->xpathCtxt);
+	ctxt->xpathCtxt->node = oldnode;
+	ctxt->xpathCtxt->doc = olddoc;
+	ctxt->xpathCtxt->namespaces = oldNamespaces;
+	ctxt->xpathCtxt->nsNr = oldNsNr;
+	if (newlist == NULL)
+	    return(-1);
+	if (newlist->type != XPATH_NODESET) {
+	    xmlXPathFreeObject(newlist);
+	    return(-1);
+	}
+	ix = 0;
+
+	if ((parent == NULL) || (node->doc == NULL) || isRVT)
+	    nocache = 1;
+	
+	if (nocache == 0) {
+	    if (list != NULL)
+		xmlXPathFreeObject(list);
+	    list = newlist;
+
+	    XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra) =
+		(void *) list;
+	    XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
+		(void *) doc;
+	    XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
+		0;
+	    XSLT_RUNTIME_EXTRA_FREE(ctxt, sel->lenExtra) =
+		(xmlFreeFunc) xmlXPathFreeObject;
+	} else
+	    list = newlist;
+    }
+    if ((list->nodesetval == NULL) ||
+	(list->nodesetval->nodeNr <= 0)) {
+	if (nocache == 1)
+	    xmlXPathFreeObject(list);
+	return(0);
+    }
+    /* TODO: store the index and use it for the scan */
+    if (ix == 0) {
+	for (j = 0;j < list->nodesetval->nodeNr;j++) {
+	    if (list->nodesetval->nodeTab[j] == node) {
+		if (nocache == 1)
+		    xmlXPathFreeObject(list);
+		return(1);
+	    }
+	}
+    } else {
+    }
+    if (nocache == 1)
+	xmlXPathFreeObject(list);
+    return(0);
+}
+
+/**
+ * xsltTestCompMatch:
+ * @ctxt:  a XSLT process context
+ * @comp: the precompiled pattern
+ * @node: a node
+ * @mode:  the mode name or NULL
+ * @modeURI:  the mode URI or NULL
+ *
+ * Test whether the node matches the pattern
+ *
+ * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
+ */
+static int
+xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
+	          xmlNodePtr node, const xmlChar *mode,
+		  const xmlChar *modeURI) {
+    int i;
+    xsltStepOpPtr step, sel = NULL;
+    xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */
+
+    if ((comp == NULL) || (node == NULL) || (ctxt == NULL)) {
+	xsltTransformError(ctxt, NULL, node,
+		"xsltTestCompMatch: null arg\n");
+        return(-1);
+    }
+    if (mode != NULL) {
+	if (comp->mode == NULL)
+	    return(0);
+	/*
+	 * both mode strings must be interned on the stylesheet dictionary
+	 */
+	if (comp->mode != mode)
+	    return(0);
+    } else {
+	if (comp->mode != NULL)
+	    return(0);
+    }
+    if (modeURI != NULL) {
+	if (comp->modeURI == NULL)
+	    return(0);
+	/*
+	 * both modeURI strings must be interned on the stylesheet dictionary
+	 */
+	if (comp->modeURI != modeURI)
+	    return(0);
+    } else {
+	if (comp->modeURI != NULL)
+	    return(0);
+    }
+
+    i = 0;
+restart:
+    for (;i < comp->nbStep;i++) {
+	step = &comp->steps[i];
+	if (step->op != XSLT_OP_PREDICATE)
+	    sel = step;
+	switch (step->op) {
+            case XSLT_OP_END:
+		goto found;
+            case XSLT_OP_ROOT:
+		if ((node->type == XML_DOCUMENT_NODE) ||
+#ifdef LIBXML_DOCB_ENABLED
+		    (node->type == XML_DOCB_DOCUMENT_NODE) ||
+#endif
+		    (node->type == XML_HTML_DOCUMENT_NODE))
+		    continue;
+		if ((node->type == XML_ELEMENT_NODE) && (node->name[0] == ' '))
+		    continue;
+		goto rollback;
+            case XSLT_OP_ELEM:
+		if (node->type != XML_ELEMENT_NODE)
+		    goto rollback;
+		if (step->value == NULL)
+		    continue;
+		if (step->value[0] != node->name[0])
+		    goto rollback;
+		if (!xmlStrEqual(step->value, node->name))
+		    goto rollback;
+
+		/* Namespace test */
+		if (node->ns == NULL) {
+		    if (step->value2 != NULL)
+			goto rollback;
+		} else if (node->ns->href != NULL) {
+		    if (step->value2 == NULL)
+			goto rollback;
+		    if (!xmlStrEqual(step->value2, node->ns->href))
+			goto rollback;
+		}
+		continue;
+            case XSLT_OP_ATTR:
+		if (node->type != XML_ATTRIBUTE_NODE)
+		    goto rollback;
+		if (step->value != NULL) {
+		    if (step->value[0] != node->name[0])
+			goto rollback;
+		    if (!xmlStrEqual(step->value, node->name))
+			goto rollback;
+		}
+		/* Namespace test */
+		if (node->ns == NULL) {
+		    if (step->value2 != NULL)
+			goto rollback;
+		} else if (step->value2 != NULL) {
+		    if (!xmlStrEqual(step->value2, node->ns->href))
+			goto rollback;
+		}
+		continue;
+            case XSLT_OP_PARENT:
+		if ((node->type == XML_DOCUMENT_NODE) ||
+		    (node->type == XML_HTML_DOCUMENT_NODE) ||
+#ifdef LIBXML_DOCB_ENABLED
+		    (node->type == XML_DOCB_DOCUMENT_NODE) ||
+#endif
+		    (node->type == XML_NAMESPACE_DECL))
+		    goto rollback;
+		node = node->parent;
+		if (node == NULL)
+		    goto rollback;
+		if (step->value == NULL)
+		    continue;
+		if (step->value[0] != node->name[0])
+		    goto rollback;
+		if (!xmlStrEqual(step->value, node->name))
+		    goto rollback;
+		/* Namespace test */
+		if (node->ns == NULL) {
+		    if (step->value2 != NULL)
+			goto rollback;
+		} else if (node->ns->href != NULL) {
+		    if (step->value2 == NULL)
+			goto rollback;
+		    if (!xmlStrEqual(step->value2, node->ns->href))
+			goto rollback;
+		}
+		continue;
+            case XSLT_OP_ANCESTOR:
+		/* TODO: implement coalescing of ANCESTOR/NODE ops */
+		if (step->value == NULL) {
+		    step = &comp->steps[i+1];
+		    if (step->op == XSLT_OP_ROOT)
+			goto found;
+		    /* added NS, ID and KEY as a result of bug 168208 */
+		    if ((step->op != XSLT_OP_ELEM) && 
+			(step->op != XSLT_OP_ALL) && 
+			(step->op != XSLT_OP_NS) &&
+			(step->op != XSLT_OP_ID) &&
+			(step->op != XSLT_OP_KEY))
+			goto rollback;
+		}
+		if (node == NULL)
+		    goto rollback;
+		if ((node->type == XML_DOCUMENT_NODE) ||
+		    (node->type == XML_HTML_DOCUMENT_NODE) ||
+#ifdef LIBXML_DOCB_ENABLED
+		    (node->type == XML_DOCB_DOCUMENT_NODE) ||
+#endif
+		    (node->type == XML_NAMESPACE_DECL))
+		    goto rollback;
+		node = node->parent;
+		if ((step->op != XSLT_OP_ELEM) && step->op != XSLT_OP_ALL) {
+		    xsltPatPushState(ctxt, &states, i, node);
+		    continue;
+		}
+		i++;
+		if (step->value == NULL) {
+		    xsltPatPushState(ctxt, &states, i - 1, node);
+		    continue;
+		}
+		while (node != NULL) {
+		    if ((node->type == XML_ELEMENT_NODE) &&
+			(step->value[0] == node->name[0]) &&
+			(xmlStrEqual(step->value, node->name))) {
+			/* Namespace test */
+			if (node->ns == NULL) {
+			    if (step->value2 == NULL)
+				break;
+			} else if (node->ns->href != NULL) {
+			    if ((step->value2 != NULL) &&
+			        (xmlStrEqual(step->value2, node->ns->href)))
+				break;
+			}
+		    }
+		    node = node->parent;
+		}
+		if (node == NULL)
+		    goto rollback;
+		xsltPatPushState(ctxt, &states, i - 1, node);
+		continue;
+            case XSLT_OP_ID: {
+		/* TODO Handle IDs decently, must be done differently */
+		xmlAttrPtr id;
+
+		if (node->type != XML_ELEMENT_NODE)
+		    goto rollback;
+
+		id = xmlGetID(node->doc, step->value);
+		if ((id == NULL) || (id->parent != node))
+		    goto rollback;
+		break;
+	    }
+            case XSLT_OP_KEY: {
+		xmlNodeSetPtr list;
+		int indx;
+
+		list = xsltGetKey(ctxt, step->value,
+			          step->value3, step->value2);
+		if (list == NULL)
+		    goto rollback;
+		for (indx = 0;indx < list->nodeNr;indx++)
+		    if (list->nodeTab[indx] == node)
+			break;
+		if (indx >= list->nodeNr)
+		    goto rollback;
+		break;
+	    }
+            case XSLT_OP_NS:
+		if (node->type != XML_ELEMENT_NODE)
+		    goto rollback;
+		if (node->ns == NULL) {
+		    if (step->value != NULL)
+			goto rollback;
+		} else if (node->ns->href != NULL) {
+		    if (step->value == NULL)
+			goto rollback;
+		    if (!xmlStrEqual(step->value, node->ns->href))
+			goto rollback;
+		}
+		break;
+            case XSLT_OP_ALL:
+		if (node->type != XML_ELEMENT_NODE)
+		    goto rollback;
+		break;
+	    case XSLT_OP_PREDICATE: {
+		xmlNodePtr oldNode;
+		xmlDocPtr doc;
+		int oldCS, oldCP;
+		int pos = 0, len = 0;
+		int isRVT;
+
+		/*
+		 * when there is cascading XSLT_OP_PREDICATE, then use a
+		 * direct computation approach. It's not done directly
+		 * at the beginning of the routine to filter out as much
+		 * as possible this costly computation.
+		 */
+		if (comp->direct) {
+		    if (states.states != NULL) {
+			/* Free the rollback states */
+			xmlFree(states.states);
+		    }
+		    return(xsltTestCompMatchDirect(ctxt, comp, node,
+		    				   comp->nsList, comp->nsNr));
+		}
+
+		doc = node->doc;
+		if (XSLT_IS_RES_TREE_FRAG(doc))
+		    isRVT = 1;
+		else
+		    isRVT = 0;
+
+		/*
+		 * Depending on the last selection, one may need to
+		 * recompute contextSize and proximityPosition.
+		 */
+		oldCS = ctxt->xpathCtxt->contextSize;
+		oldCP = ctxt->xpathCtxt->proximityPosition;
+		if ((sel != NULL) &&
+		    (sel->op == XSLT_OP_ELEM) &&
+		    (sel->value != NULL) &&
+		    (node->type == XML_ELEMENT_NODE) &&
+		    (node->parent != NULL)) {
+		    xmlNodePtr previous;
+		    int ix, nocache = 0;
+
+		    previous = (xmlNodePtr)
+			XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
+		    ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
+		    if ((previous != NULL) &&
+			(previous->parent == node->parent)) {
+			/*
+			 * just walk back to adjust the index
+			 */
+			int indx = 0;
+			xmlNodePtr sibling = node;
+
+			while (sibling != NULL) {
+			    if (sibling == previous)
+				break;
+			    if ((previous->type == XML_ELEMENT_NODE) &&
+				(previous->name != NULL) &&
+				(sibling->name != NULL) &&
+				(previous->name[0] == sibling->name[0]) &&
+				(xmlStrEqual(previous->name, sibling->name)))
+			    {
+				if ((sel->value2 == NULL) ||
+				    ((sibling->ns != NULL) &&
+				     (xmlStrEqual(sel->value2,
+						  sibling->ns->href))))
+				    indx++;
+			    }
+			    sibling = sibling->prev;
+			}
+			if (sibling == NULL) {
+			    /* hum going backward in document order ... */
+			    indx = 0;
+			    sibling = node;
+			    while (sibling != NULL) {
+				if (sibling == previous)
+				    break;
+				if ((previous->type == XML_ELEMENT_NODE) &&
+				    (previous->name != NULL) &&
+				    (sibling->name != NULL) &&
+				    (previous->name[0] == sibling->name[0]) &&
+				    (xmlStrEqual(previous->name, sibling->name)))
+				{
+				    if ((sel->value2 == NULL) ||
+					((sibling->ns != NULL) &&
+					(xmlStrEqual(sel->value2,
+					sibling->ns->href))))
+				    {
+					indx--;
+				    }
+				}
+				sibling = sibling->next;
+			    }
+			}
+			if (sibling != NULL) {
+			    pos = ix + indx;
+			    /*
+			     * If the node is in a Value Tree we need to
+			     * save len, but cannot cache the node!
+			     * (bugs 153137 and 158840)
+			     */
+			    if (node->doc != NULL) {
+				len = XSLT_RUNTIME_EXTRA(ctxt,
+				        sel->lenExtra, ival);
+				if (!isRVT) {
+				    XSLT_RUNTIME_EXTRA(ctxt,
+					sel->previousExtra, ptr) = node;
+				    XSLT_RUNTIME_EXTRA(ctxt,
+				        sel->indexExtra, ival) = pos;
+				}
+			    }
+			    ix = pos;
+			} else
+			    pos = 0;
+		    } else {
+			/*
+			 * recompute the index
+			 */
+			xmlNodePtr parent = node->parent;
+			xmlNodePtr siblings = NULL;
+
+                        if (parent) siblings = parent->children;
+
+			while (siblings != NULL) {
+			    if (siblings->type == XML_ELEMENT_NODE) {
+				if (siblings == node) {
+				    len++;
+				    pos = len;
+				} else if ((node->name != NULL) &&
+					   (siblings->name != NULL) &&
+				    (node->name[0] == siblings->name[0]) &&
+				    (xmlStrEqual(node->name, siblings->name))) {
+				    if ((sel->value2 == NULL) ||
+					((siblings->ns != NULL) &&
+					 (xmlStrEqual(sel->value2,
+						      siblings->ns->href))))
+					len++;
+				}
+			    }
+			    siblings = siblings->next;
+			}
+			if ((parent == NULL) || (node->doc == NULL))
+			    nocache = 1;
+			else {
+			    while (parent->parent != NULL)
+				parent = parent->parent;
+			    if (((parent->type != XML_DOCUMENT_NODE) &&
+				 (parent->type != XML_HTML_DOCUMENT_NODE)) ||
+				 (parent != (xmlNodePtr) node->doc))
+				nocache = 1;
+			}
+		    }
+		    if (pos != 0) {
+			ctxt->xpathCtxt->contextSize = len;
+			ctxt->xpathCtxt->proximityPosition = pos;
+			/*
+			 * If the node is in a Value Tree we cannot
+			 * cache it !
+			 */
+			if ((!isRVT) && (node->doc != NULL) &&
+			    (nocache == 0)) {
+			    XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
+				node;
+			    XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
+				pos;
+			    XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =
+				len;
+			}
+		    }
+		} else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) &&
+			   (node->type == XML_ELEMENT_NODE)) {
+		    xmlNodePtr previous;
+		    int ix, nocache = 0;
+
+		    previous = (xmlNodePtr)
+			XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
+		    ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
+		    if ((previous != NULL) &&
+			(previous->parent == node->parent)) {
+			/*
+			 * just walk back to adjust the index
+			 */
+			int indx = 0;
+			xmlNodePtr sibling = node;
+
+			while (sibling != NULL) {
+			    if (sibling == previous)
+				break;
+			    if (sibling->type == XML_ELEMENT_NODE)
+				indx++;
+			    sibling = sibling->prev;
+			}
+			if (sibling == NULL) {
+			    /* hum going backward in document order ... */
+			    indx = 0;
+			    sibling = node;
+			    while (sibling != NULL) {
+				if (sibling == previous)
+				    break;
+				if (sibling->type == XML_ELEMENT_NODE)
+				    indx--;
+				sibling = sibling->next;
+			    }
+			}
+			if (sibling != NULL) {
+			    pos = ix + indx;
+			    /*
+			     * If the node is in a Value Tree we cannot
+			     * cache it !
+			     */
+			    if ((node->doc != NULL) && !isRVT) {
+				len = XSLT_RUNTIME_EXTRA(ctxt,
+				        sel->lenExtra, ival);
+				XSLT_RUNTIME_EXTRA(ctxt,
+					sel->previousExtra, ptr) = node;
+				XSLT_RUNTIME_EXTRA(ctxt,
+					sel->indexExtra, ival) = pos;
+			    }
+			} else
+			    pos = 0;
+		    } else {
+			/*
+			 * recompute the index
+			 */
+			xmlNodePtr parent = node->parent;
+			xmlNodePtr siblings = NULL;
+
+                        if (parent) siblings = parent->children;
+
+			while (siblings != NULL) {
+			    if (siblings->type == XML_ELEMENT_NODE) {
+				len++;
+				if (siblings == node) {
+				    pos = len;
+				}
+			    }
+			    siblings = siblings->next;
+			}
+			if ((parent == NULL) || (node->doc == NULL))
+			    nocache = 1;
+			else {
+			    while (parent->parent != NULL)
+				parent = parent->parent;
+			    if (((parent->type != XML_DOCUMENT_NODE) &&
+				 (parent->type != XML_HTML_DOCUMENT_NODE)) ||
+				 (parent != (xmlNodePtr) node->doc))
+				nocache = 1;
+			}
+		    }
+		    if (pos != 0) {
+			ctxt->xpathCtxt->contextSize = len;
+			ctxt->xpathCtxt->proximityPosition = pos;
+			/*
+			 * If the node is in a Value Tree we cannot
+			 * cache it !
+			 */
+			if ((node->doc != NULL) && (nocache == 0) && !isRVT) {
+			    XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
+				node;
+			    XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
+				pos;
+			    XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =
+				len;
+			}
+		    }
+		}
+		oldNode = ctxt->node;
+		ctxt->node = node;
+
+		if (step->value == NULL)
+		    goto wrong_index;
+		if (step->comp == NULL)
+		    goto wrong_index;
+
+		if (!xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList,
+			                    comp->nsNr))
+		    goto wrong_index;
+
+		if (pos != 0) {
+		    ctxt->xpathCtxt->contextSize = oldCS;
+		    ctxt->xpathCtxt->proximityPosition = oldCP;
+		}
+		ctxt->node = oldNode;
+		break;
+wrong_index:
+		if (pos != 0) {
+		    ctxt->xpathCtxt->contextSize = oldCS;
+		    ctxt->xpathCtxt->proximityPosition = oldCP;
+		}
+		ctxt->node = oldNode;
+		goto rollback;
+	    }
+            case XSLT_OP_PI:
+		if (node->type != XML_PI_NODE)
+		    goto rollback;
+		if (step->value != NULL) {
+		    if (!xmlStrEqual(step->value, node->name))
+			goto rollback;
+		}
+		break;
+            case XSLT_OP_COMMENT:
+		if (node->type != XML_COMMENT_NODE)
+		    goto rollback;
+		break;
+            case XSLT_OP_TEXT:
+		if ((node->type != XML_TEXT_NODE) &&
+		    (node->type != XML_CDATA_SECTION_NODE))
+		    goto rollback;
+		break;
+            case XSLT_OP_NODE:
+		switch (node->type) {
+		    case XML_ELEMENT_NODE:
+		    case XML_CDATA_SECTION_NODE:
+		    case XML_PI_NODE:
+		    case XML_COMMENT_NODE:
+		    case XML_TEXT_NODE:
+			break;
+		    default:
+			goto rollback;
+		}
+		break;
+	}
+    }
+found:
+    if (states.states != NULL) {
+        /* Free the rollback states */
+	xmlFree(states.states);
+    }
+    return(1);
+rollback:
+    /* got an error try to rollback */
+    if (states.states == NULL)
+	return(0);
+    if (states.nbstates <= 0) {
+	xmlFree(states.states);
+	return(0);
+    }
+    states.nbstates--;
+    i = states.states[states.nbstates].step;
+    node = states.states[states.nbstates].node;
+#if 0
+    fprintf(stderr, "Pop: %d, %s\n", i, node->name);
+#endif
+    goto restart;
+}
+
+/**
+ * xsltTestCompMatchList:
+ * @ctxt:  a XSLT process context
+ * @node: a node
+ * @comp: the precompiled pattern list
+ *
+ * Test whether the node matches one of the patterns in the list
+ *
+ * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
+ */
+int
+xsltTestCompMatchList(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	              xsltCompMatchPtr comp) {
+    int ret;
+
+    if ((ctxt == NULL) || (node == NULL))
+	return(-1);
+    while (comp != NULL) {
+	ret = xsltTestCompMatch(ctxt, comp, node, NULL, NULL);
+	if (ret == 1)
+	    return(1);
+	comp = comp->next;
+    }
+    return(0);
+}
+
+/************************************************************************
+ *									*
+ *			Dedicated parser for templates			*
+ *									*
+ ************************************************************************/
+
+#define CUR (*ctxt->cur)
+#define SKIP(val) ctxt->cur += (val)
+#define NXT(val) ctxt->cur[(val)]
+#define CUR_PTR ctxt->cur
+
+#define SKIP_BLANKS 							\
+    while (IS_BLANK_CH(CUR)) NEXT
+
+#define CURRENT (*ctxt->cur)
+#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
+
+
+#define PUSH(op, val, val2, novar) 						\
+    if (xsltCompMatchAdd(ctxt, ctxt->comp, (op), (val), (val2), (novar))) goto error;
+
+#define SWAP() 						\
+    xsltSwapTopCompMatch(ctxt->comp);
+
+#define XSLT_ERROR(X)							\
+    { xsltError(ctxt, __FILE__, __LINE__, X);			\
+      ctxt->error = (X); return; }
+
+#define XSLT_ERROR0(X)							\
+    { xsltError(ctxt, __FILE__, __LINE__, X);			\
+      ctxt->error = (X); return(0); }
+
+/**
+ * xsltScanLiteral:
+ * @ctxt:  the XPath Parser context
+ *
+ * Parse an XPath Litteral:
+ *
+ * [29] Literal ::= '"' [^"]* '"'
+ *                | "'" [^']* "'"
+ *
+ * Returns the Literal parsed or NULL
+ */
+
+static xmlChar *
+xsltScanLiteral(xsltParserContextPtr ctxt) {
+    const xmlChar *q, *cur;
+    xmlChar *ret = NULL;
+    int val, len;
+
+    SKIP_BLANKS;
+    if (CUR == '"') {
+        NEXT;
+	cur = q = CUR_PTR;
+	val = xmlStringCurrentChar(NULL, cur, &len);
+	while ((IS_CHAR(val)) && (val != '"')) {
+	    cur += len;
+	    val = xmlStringCurrentChar(NULL, cur, &len);
+	}
+	if (!IS_CHAR(val)) {
+	    ctxt->error = 1;
+	    return(NULL);
+	} else {
+	    ret = xmlStrndup(q, cur - q);
+        }
+	cur += len;
+	CUR_PTR = cur;
+    } else if (CUR == '\'') {
+        NEXT;
+	cur = q = CUR_PTR;
+	val = xmlStringCurrentChar(NULL, cur, &len);
+	while ((IS_CHAR(val)) && (val != '\'')) {
+	    cur += len;
+	    val = xmlStringCurrentChar(NULL, cur, &len);
+	}
+	if (!IS_CHAR(val)) {
+	    ctxt->error = 1;
+	    return(NULL);
+	} else {
+	    ret = xmlStrndup(q, cur - q);
+        }
+	cur += len;
+	CUR_PTR = cur;
+    } else {
+	/* XP_ERROR(XPATH_START_LITERAL_ERROR); */
+	ctxt->error = 1;
+	return(NULL);
+    }
+    return(ret);
+}
+
+/**
+ * xsltScanNCName:
+ * @ctxt:  the XPath Parser context
+ *
+ * Parses a non qualified name
+ *
+ * Returns the Name parsed or NULL
+ */
+
+static xmlChar *
+xsltScanNCName(xsltParserContextPtr ctxt) {
+    const xmlChar *q, *cur;
+    xmlChar *ret = NULL;
+    int val, len;
+
+    SKIP_BLANKS;
+
+    cur = q = CUR_PTR;
+    val = xmlStringCurrentChar(NULL, cur, &len);
+    if (!IS_LETTER(val) && (val != '_'))
+	return(NULL);
+
+    while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
+           (val == '.') || (val == '-') ||
+	   (val == '_') ||
+	   (IS_COMBINING(val)) ||
+	   (IS_EXTENDER(val))) {
+	cur += len;
+	val = xmlStringCurrentChar(NULL, cur, &len);
+    }
+    ret = xmlStrndup(q, cur - q);
+    CUR_PTR = cur;
+    return(ret);
+}
+
+/*
+ * xsltCompileIdKeyPattern:
+ * @ctxt:  the compilation context
+ * @name:  a preparsed name
+ * @aid:  whether id/key are allowed there
+ * @novar:  flag to prohibit xslt var
+ *
+ * Compile the XSLT LocationIdKeyPattern
+ * [3] IdKeyPattern ::= 'id' '(' Literal ')'
+ *                    | 'key' '(' Literal ',' Literal ')'
+ *
+ * also handle NodeType and PI from:
+ *
+ * [7]  NodeTest ::= NameTest
+ *                 | NodeType '(' ')'
+ *                 | 'processing-instruction' '(' Literal ')'
+ */
+static void
+xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name,
+		int aid, int novar, xsltAxis axis) {
+    xmlChar *lit = NULL;
+    xmlChar *lit2 = NULL;
+
+    if (CUR != '(') {
+	xsltTransformError(NULL, NULL, NULL,
+		"xsltCompileIdKeyPattern : ( expected\n");
+	ctxt->error = 1;
+	return;
+    }
+    if ((aid) && (xmlStrEqual(name, (const xmlChar *)"id"))) {
+	if (axis != 0) {
+	    xsltTransformError(NULL, NULL, NULL,
+		    "xsltCompileIdKeyPattern : NodeTest expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	SKIP_BLANKS;
+        lit = xsltScanLiteral(ctxt);
+	if (ctxt->error)
+	    return;
+	SKIP_BLANKS;
+	if (CUR != ')') {
+	    xsltTransformError(NULL, NULL, NULL,
+		    "xsltCompileIdKeyPattern : ) expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	PUSH(XSLT_OP_ID, lit, NULL, novar);
+    } else if ((aid) && (xmlStrEqual(name, (const xmlChar *)"key"))) {
+	if (axis != 0) {
+	    xsltTransformError(NULL, NULL, NULL,
+		    "xsltCompileIdKeyPattern : NodeTest expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	SKIP_BLANKS;
+        lit = xsltScanLiteral(ctxt);
+	if (ctxt->error)
+	    return;
+	SKIP_BLANKS;
+	if (CUR != ',') {
+	    xsltTransformError(NULL, NULL, NULL,
+		    "xsltCompileIdKeyPattern : , expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	SKIP_BLANKS;
+        lit2 = xsltScanLiteral(ctxt);
+	if (ctxt->error)
+	    return;
+	SKIP_BLANKS;
+	if (CUR != ')') {
+	    xsltTransformError(NULL, NULL, NULL,
+		    "xsltCompileIdKeyPattern : ) expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	/* URGENT TODO: support namespace in keys */
+	PUSH(XSLT_OP_KEY, lit, lit2, novar);
+    } else if (xmlStrEqual(name, (const xmlChar *)"processing-instruction")) {
+	NEXT;
+	SKIP_BLANKS;
+	if (CUR != ')') {
+	    lit = xsltScanLiteral(ctxt);
+	    if (ctxt->error)
+		return;
+	    SKIP_BLANKS;
+	    if (CUR != ')') {
+		xsltTransformError(NULL, NULL, NULL,
+			"xsltCompileIdKeyPattern : ) expected\n");
+		ctxt->error = 1;
+		return;
+	    }
+	}
+	NEXT;
+	PUSH(XSLT_OP_PI, lit, NULL, novar);
+    } else if (xmlStrEqual(name, (const xmlChar *)"text")) {
+	NEXT;
+	SKIP_BLANKS;
+	if (CUR != ')') {
+	    xsltTransformError(NULL, NULL, NULL,
+		    "xsltCompileIdKeyPattern : ) expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	PUSH(XSLT_OP_TEXT, NULL, NULL, novar);
+    } else if (xmlStrEqual(name, (const xmlChar *)"comment")) {
+	NEXT;
+	SKIP_BLANKS;
+	if (CUR != ')') {
+	    xsltTransformError(NULL, NULL, NULL,
+		    "xsltCompileIdKeyPattern : ) expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	PUSH(XSLT_OP_COMMENT, NULL, NULL, novar);
+    } else if (xmlStrEqual(name, (const xmlChar *)"node")) {
+	NEXT;
+	SKIP_BLANKS;
+	if (CUR != ')') {
+	    xsltTransformError(NULL, NULL, NULL,
+		    "xsltCompileIdKeyPattern : ) expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	if (axis == AXIS_ATTRIBUTE) {
+	    PUSH(XSLT_OP_ATTR, NULL, NULL, novar);
+	}
+	else {
+	    PUSH(XSLT_OP_NODE, NULL, NULL, novar);
+	}
+    } else if (aid) {
+	xsltTransformError(NULL, NULL, NULL,
+	    "xsltCompileIdKeyPattern : expecting 'key' or 'id' or node type\n");
+	ctxt->error = 1;
+	return;
+    } else {
+	xsltTransformError(NULL, NULL, NULL,
+	    "xsltCompileIdKeyPattern : node type\n");
+	ctxt->error = 1;
+	return;
+    }
+error:
+    if (name != NULL)
+	xmlFree(name);
+}
+
+/**
+ * xsltCompileStepPattern:
+ * @ctxt:  the compilation context
+ * @token:  a posible precompiled name
+ * @novar: flag to prohibit xslt variables from pattern
+ *
+ * Compile the XSLT StepPattern and generates a precompiled
+ * form suitable for fast matching.
+ *
+ * [5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate* 
+ * [6] ChildOrAttributeAxisSpecifier ::= AbbreviatedAxisSpecifier
+ *                                     | ('child' | 'attribute') '::'
+ * from XPath
+ * [7]  NodeTest ::= NameTest
+ *                 | NodeType '(' ')'
+ *                 | 'processing-instruction' '(' Literal ')'
+ * [8] Predicate ::= '[' PredicateExpr ']'
+ * [9] PredicateExpr ::= Expr
+ * [13] AbbreviatedAxisSpecifier ::= '@'?
+ * [37] NameTest ::= '*' | NCName ':' '*' | QName
+ */
+
+static void
+xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) {
+    xmlChar *name = NULL;
+    const xmlChar *URI = NULL;
+    xmlChar *URL = NULL;
+    int level;
+    xsltAxis axis = 0;
+
+    SKIP_BLANKS;
+    if ((token == NULL) && (CUR == '@')) {
+	NEXT;
+        axis = AXIS_ATTRIBUTE;
+    }
+parse_node_test:
+    if (token == NULL)
+	token = xsltScanNCName(ctxt);
+    if (token == NULL) {
+	if (CUR == '*') {
+	    NEXT;
+	    if (axis == AXIS_ATTRIBUTE) {
+                PUSH(XSLT_OP_ATTR, NULL, NULL, novar);
+            }
+            else {
+                PUSH(XSLT_OP_ALL, NULL, NULL, novar);
+            }
+	    goto parse_predicate;
+	} else {
+	    xsltTransformError(NULL, NULL, NULL,
+		    "xsltCompileStepPattern : Name expected\n");
+	    ctxt->error = 1;
+	    goto error;
+	}
+    }
+
+
+    SKIP_BLANKS;
+    if (CUR == '(') {
+	xsltCompileIdKeyPattern(ctxt, token, 0, novar, axis);
+	if (ctxt->error)
+	    goto error;
+    } else if (CUR == ':') {
+	NEXT;
+	if (CUR != ':') {
+	    xmlChar *prefix = token;
+	    xmlNsPtr ns;
+
+	    /*
+	     * This is a namespace match
+	     */
+	    token = xsltScanNCName(ctxt);
+	    ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix);
+	    if (ns == NULL) {
+		xsltTransformError(NULL, NULL, NULL,
+	    "xsltCompileStepPattern : no namespace bound to prefix %s\n",
+				 prefix);
+		xmlFree(prefix);
+		ctxt->error = 1;
+		goto error;
+	    } else {
+		URL = xmlStrdup(ns->href);
+	    }
+	    xmlFree(prefix);
+	    if (token == NULL) {
+		if (CUR == '*') {
+		    NEXT;
+                    if (axis == AXIS_ATTRIBUTE) {
+                        PUSH(XSLT_OP_ATTR, NULL, URL, novar);
+                    }
+                    else {
+                        PUSH(XSLT_OP_NS, URL, NULL, novar);
+                    }
+		} else {
+		    xsltTransformError(NULL, NULL, NULL,
+			    "xsltCompileStepPattern : Name expected\n");
+		    ctxt->error = 1;
+		    goto error;
+		}
+	    } else {
+                if (axis == AXIS_ATTRIBUTE) {
+                    PUSH(XSLT_OP_ATTR, token, URL, novar);
+                }
+                else {
+                    PUSH(XSLT_OP_ELEM, token, URL, novar);
+                }
+	    }
+	} else {
+	    if (axis != 0) {
+		xsltTransformError(NULL, NULL, NULL,
+		    "xsltCompileStepPattern : NodeTest expected\n");
+		ctxt->error = 1;
+		goto error;
+	    }
+	    NEXT;
+	    if (xmlStrEqual(token, (const xmlChar *) "child")) {
+	        axis = AXIS_CHILD;
+	    } else if (xmlStrEqual(token, (const xmlChar *) "attribute")) {
+	        axis = AXIS_ATTRIBUTE;
+	    } else {
+		xsltTransformError(NULL, NULL, NULL,
+		    "xsltCompileStepPattern : 'child' or 'attribute' expected\n");
+		ctxt->error = 1;
+		goto error;
+	    }
+	    xmlFree(token);
+            SKIP_BLANKS;
+            token = xsltScanNCName(ctxt);
+	    goto parse_node_test;
+	}
+    } else {
+	URI = xsltGetQNameURI(ctxt->elem, &token);
+	if (token == NULL) {
+	    ctxt->error = 1;
+	    goto error;
+	}
+	if (URI != NULL)
+	    URL = xmlStrdup(URI);
+        if (axis == AXIS_ATTRIBUTE) {
+            PUSH(XSLT_OP_ATTR, token, URL, novar);
+        }
+        else {
+            PUSH(XSLT_OP_ELEM, token, URL, novar);
+        }
+    }
+parse_predicate:
+    SKIP_BLANKS;
+    level = 0;
+    while (CUR == '[') {
+	const xmlChar *q;
+	xmlChar *ret = NULL;
+
+	level++;
+	NEXT;
+	q = CUR_PTR;
+	while (CUR != 0) {
+	    /* Skip over nested predicates */
+	    if (CUR == '[')
+		level++;
+	    else if (CUR == ']') {
+		level--;
+		if (level == 0)
+		    break;
+	    } else if (CUR == '"') {
+		NEXT;
+		while ((CUR != 0) && (CUR != '"'))
+		    NEXT;
+	    } else if (CUR == '\'') {
+		NEXT;
+		while ((CUR != 0) && (CUR != '\''))
+		    NEXT;
+	    }
+	    NEXT;
+	}
+	if (CUR == 0) {
+	    xsltTransformError(NULL, NULL, NULL,
+		    "xsltCompileStepPattern : ']' expected\n");
+	    ctxt->error = 1;
+	    return;
+        }
+	ret = xmlStrndup(q, CUR_PTR - q);
+	PUSH(XSLT_OP_PREDICATE, ret, NULL, novar);
+	/* push the predicate lower than local test */
+	SWAP();
+	NEXT;
+	SKIP_BLANKS;
+    }
+    return;
+error:
+    if (token != NULL)
+	xmlFree(token);
+    if (name != NULL)
+	xmlFree(name);
+}
+
+/**
+ * xsltCompileRelativePathPattern:
+ * @comp:  the compilation context
+ * @token:  a posible precompiled name
+ * @novar:  flag to prohibit xslt variables
+ *
+ * Compile the XSLT RelativePathPattern and generates a precompiled
+ * form suitable for fast matching.
+ *
+ * [4] RelativePathPattern ::= StepPattern
+ *                           | RelativePathPattern '/' StepPattern
+ *                           | RelativePathPattern '//' StepPattern
+ */
+static void
+xsltCompileRelativePathPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) {
+    xsltCompileStepPattern(ctxt, token, novar);
+    if (ctxt->error)
+	goto error;
+    SKIP_BLANKS;
+    while ((CUR != 0) && (CUR != '|')) {
+	if ((CUR == '/') && (NXT(1) == '/')) {
+	    PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar);
+	    NEXT;
+	    NEXT;
+	    SKIP_BLANKS;
+	    xsltCompileStepPattern(ctxt, NULL, novar);
+	} else if (CUR == '/') {
+	    PUSH(XSLT_OP_PARENT, NULL, NULL, novar);
+	    NEXT;
+	    SKIP_BLANKS;
+	    if ((CUR != 0) && (CUR != '|')) {
+		xsltCompileRelativePathPattern(ctxt, NULL, novar);
+	    }
+	} else {
+	    ctxt->error = 1;
+	}
+	if (ctxt->error)
+	    goto error;
+	SKIP_BLANKS;
+    }
+error:
+    return;
+}
+
+/**
+ * xsltCompileLocationPathPattern:
+ * @ctxt:  the compilation context
+ * @novar:  flag to prohibit xslt variables
+ *
+ * Compile the XSLT LocationPathPattern and generates a precompiled
+ * form suitable for fast matching.
+ *
+ * [2] LocationPathPattern ::= '/' RelativePathPattern?
+ *                           | IdKeyPattern (('/' | '//') RelativePathPattern)?
+ *                           | '//'? RelativePathPattern
+ */
+static void
+xsltCompileLocationPathPattern(xsltParserContextPtr ctxt, int novar) {
+    SKIP_BLANKS;
+    if ((CUR == '/') && (NXT(1) == '/')) {
+	/*
+	 * since we reverse the query
+	 * a leading // can be safely ignored
+	 */
+	NEXT;
+	NEXT;
+	ctxt->comp->priority = 0.5;	/* '//' means not 0 priority */
+	xsltCompileRelativePathPattern(ctxt, NULL, novar);
+    } else if (CUR == '/') {
+	/*
+	 * We need to find root as the parent
+	 */
+	NEXT;
+	SKIP_BLANKS;
+	PUSH(XSLT_OP_ROOT, NULL, NULL, novar);
+	if ((CUR != 0) && (CUR != '|')) {
+	    PUSH(XSLT_OP_PARENT, NULL, NULL, novar);
+	    xsltCompileRelativePathPattern(ctxt, NULL, novar);
+	}
+    } else if (CUR == '*') {
+	xsltCompileRelativePathPattern(ctxt, NULL, novar);
+    } else if (CUR == '@') {
+	xsltCompileRelativePathPattern(ctxt, NULL, novar);
+    } else {
+	xmlChar *name;
+	name = xsltScanNCName(ctxt);
+	if (name == NULL) {
+	    xsltTransformError(NULL, NULL, NULL,
+		    "xsltCompileLocationPathPattern : Name expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	SKIP_BLANKS;
+	if ((CUR == '(') && !xmlXPathIsNodeType(name)) {
+	    xsltCompileIdKeyPattern(ctxt, name, 1, novar, 0);
+	    if ((CUR == '/') && (NXT(1) == '/')) {
+		PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar);
+		NEXT;
+		NEXT;
+		SKIP_BLANKS;
+		xsltCompileRelativePathPattern(ctxt, NULL, novar);
+	    } else if (CUR == '/') {
+		PUSH(XSLT_OP_PARENT, NULL, NULL, novar);
+		NEXT;
+		SKIP_BLANKS;
+		xsltCompileRelativePathPattern(ctxt, NULL, novar);
+	    }
+	    return;
+	}
+	xsltCompileRelativePathPattern(ctxt, name, novar);
+    }
+error:
+    return;
+}
+
+/**
+ * xsltCompilePatternInternal:
+ * @pattern: an XSLT pattern
+ * @doc:  the containing document
+ * @node:  the containing element
+ * @style:  the stylesheet
+ * @runtime:  the transformation context, if done at run-time
+ * @novar:  flag to prohibit xslt variables
+ *
+ * Compile the XSLT pattern and generates a list of precompiled form suitable
+ * for fast matching.
+ *
+ * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern
+ *
+ * Returns the generated pattern list or NULL in case of failure
+ */
+
+static xsltCompMatchPtr
+xsltCompilePatternInternal(const xmlChar *pattern, xmlDocPtr doc,
+	           xmlNodePtr node, xsltStylesheetPtr style,
+		   xsltTransformContextPtr runtime, int novar) {
+    xsltParserContextPtr ctxt = NULL;
+    xsltCompMatchPtr element, first = NULL, previous = NULL;
+    int current, start, end, level, j;
+
+    if (pattern == NULL) {
+	xsltTransformError(NULL, NULL, node,
+			 "xsltCompilePattern : NULL pattern\n");
+	return(NULL);
+    }
+
+    ctxt = xsltNewParserContext(style, runtime);
+    if (ctxt == NULL)
+	return(NULL);
+    ctxt->doc = doc;
+    ctxt->elem = node;
+    current = end = 0;
+    while (pattern[current] != 0) {
+	start = current;
+	while (IS_BLANK_CH(pattern[current]))
+	    current++;
+	end = current;
+	level = 0;
+	while ((pattern[end] != 0) && ((pattern[end] != '|') || (level != 0))) {
+	    if (pattern[end] == '[')
+		level++;
+	    else if (pattern[end] == ']')
+		level--;
+	    else if (pattern[end] == '\'') {
+		end++;
+		while ((pattern[end] != 0) && (pattern[end] != '\''))
+		    end++;
+	    } else if (pattern[end] == '"') {
+		end++;
+		while ((pattern[end] != 0) && (pattern[end] != '"'))
+		    end++;
+	    }
+	    end++;
+	}
+	if (current == end) {
+	    xsltTransformError(NULL, NULL, node,
+			     "xsltCompilePattern : NULL pattern\n");
+	    goto error;
+	}
+	element = xsltNewCompMatch();
+	if (element == NULL) {
+	    goto error;
+	}
+	if (first == NULL)
+	    first = element;
+	else if (previous != NULL)
+	    previous->next = element;
+	previous = element;
+
+	ctxt->comp = element;
+	ctxt->base = xmlStrndup(&pattern[start], end - start);
+	if (ctxt->base == NULL)
+	    goto error;
+	ctxt->cur = &(ctxt->base)[current - start];
+	element->pattern = ctxt->base;
+	element->nsList = xmlGetNsList(doc, node);
+	j = 0;
+	if (element->nsList != NULL) {
+	    while (element->nsList[j] != NULL)
+		j++;
+	}
+	element->nsNr = j;
+
+
+#ifdef WITH_XSLT_DEBUG_PATTERN
+	xsltGenericDebug(xsltGenericDebugContext,
+			 "xsltCompilePattern : parsing '%s'\n",
+			 element->pattern);
+#endif
+	/*
+	 Preset default priority to be zero.
+	 This may be changed by xsltCompileLocationPathPattern.
+	 */
+	element->priority = 0;
+	xsltCompileLocationPathPattern(ctxt, novar);
+	if (ctxt->error) {
+	    xsltTransformError(NULL, style, node,
+			     "xsltCompilePattern : failed to compile '%s'\n",
+			     element->pattern);
+	    if (style != NULL) style->errors++;
+	    goto error;
+	}
+
+	/*
+	 * Reverse for faster interpretation.
+	 */
+	xsltReverseCompMatch(ctxt, element);
+
+	/*
+	 * Set-up the priority
+	 */
+	if (element->priority == 0) {	/* if not yet determined */
+	    if (((element->steps[0].op == XSLT_OP_ELEM) ||
+		 (element->steps[0].op == XSLT_OP_ATTR) ||
+		 (element->steps[0].op == XSLT_OP_PI)) &&
+		(element->steps[0].value != NULL) &&
+		(element->steps[1].op == XSLT_OP_END)) {
+		;	/* previously preset */
+	    } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
+		       (element->steps[0].value2 != NULL) &&
+		       (element->steps[1].op == XSLT_OP_END)) {
+			element->priority = -0.25;
+	    } else if ((element->steps[0].op == XSLT_OP_NS) &&
+		       (element->steps[0].value != NULL) &&
+		       (element->steps[1].op == XSLT_OP_END)) {
+			element->priority = -0.25;
+	    } else if ((element->steps[0].op == XSLT_OP_ATTR) &&
+		       (element->steps[0].value == NULL) &&
+		       (element->steps[0].value2 == NULL) &&
+		       (element->steps[1].op == XSLT_OP_END)) {
+			element->priority = -0.5;
+	    } else if (((element->steps[0].op == XSLT_OP_PI) ||
+		       (element->steps[0].op == XSLT_OP_TEXT) ||
+		       (element->steps[0].op == XSLT_OP_ALL) ||
+		       (element->steps[0].op == XSLT_OP_NODE) ||
+		       (element->steps[0].op == XSLT_OP_COMMENT)) &&
+		       (element->steps[1].op == XSLT_OP_END)) {
+			element->priority = -0.5;
+	    } else {
+		element->priority = 0.5;
+	    }
+	}
+#ifdef WITH_XSLT_DEBUG_PATTERN
+	xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltCompilePattern : parsed %s, default priority %f\n",
+			 element->pattern, element->priority);
+#endif
+	if (pattern[end] == '|')
+	    end++;
+	current = end;
+    }
+    if (end == 0) {
+	xsltTransformError(NULL, style, node,
+			 "xsltCompilePattern : NULL pattern\n");
+	if (style != NULL) style->errors++;
+	goto error;
+    }
+
+    xsltFreeParserContext(ctxt);
+    return(first);
+
+error:
+    if (ctxt != NULL)
+	xsltFreeParserContext(ctxt);
+    if (first != NULL)
+	xsltFreeCompMatchList(first);
+    return(NULL);
+}
+
+/**
+ * xsltCompilePattern:
+ * @pattern: an XSLT pattern
+ * @doc:  the containing document
+ * @node:  the containing element
+ * @style:  the stylesheet
+ * @runtime:  the transformation context, if done at run-time
+ *
+ * Compile the XSLT pattern and generates a list of precompiled form suitable
+ * for fast matching.
+ *
+ * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern
+ *
+ * Returns the generated pattern list or NULL in case of failure
+ */
+
+xsltCompMatchPtr
+xsltCompilePattern(const xmlChar *pattern, xmlDocPtr doc,
+	           xmlNodePtr node, xsltStylesheetPtr style,
+		   xsltTransformContextPtr runtime) {
+    return (xsltCompilePatternInternal(pattern, doc, node, style, runtime, 0));
+}
+
+/************************************************************************
+ *									*
+ *			Module interfaces				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltAddTemplate:
+ * @style: an XSLT stylesheet
+ * @cur: an XSLT template
+ * @mode:  the mode name or NULL
+ * @modeURI:  the mode URI or NULL
+ *
+ * Register the XSLT pattern associated to @cur
+ *
+ * Returns -1 in case of error, 0 otherwise
+ */
+int
+xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,
+	        const xmlChar *mode, const xmlChar *modeURI) {
+    xsltCompMatchPtr pat, list, next;
+    /*
+     * 'top' will point to style->xxxMatch ptr - declaring as 'void'
+     *  avoids gcc 'type-punned pointer' warning.
+     */
+    void **top = NULL;
+    const xmlChar *name = NULL;
+    float priority;              /* the priority */
+
+    if ((style == NULL) || (cur == NULL) || (cur->match == NULL))
+	return(-1);
+
+    priority = cur->priority;
+    pat = xsltCompilePatternInternal(cur->match, style->doc, cur->elem,
+		    style, NULL, 1);
+    if (pat == NULL)
+    	return(-1);
+    while (pat) {
+	next = pat->next;
+	pat->next = NULL;
+	name = NULL;
+	
+	pat->template = cur;
+	if (mode != NULL)
+	    pat->mode = xmlDictLookup(style->dict, mode, -1);
+	if (modeURI != NULL)
+	    pat->modeURI = xmlDictLookup(style->dict, modeURI, -1);
+	if (priority != XSLT_PAT_NO_PRIORITY)
+	    pat->priority = priority;
+
+	/*
+	 * insert it in the hash table list corresponding to its lookup name
+	 */
+	switch (pat->steps[0].op) {
+        case XSLT_OP_ATTR:
+	    if (pat->steps[0].value != NULL)
+		name = pat->steps[0].value;
+	    else
+		top = &(style->attrMatch);
+	    break;
+        case XSLT_OP_PARENT:
+        case XSLT_OP_ANCESTOR:
+	    top = &(style->elemMatch);
+	    break;
+        case XSLT_OP_ROOT:
+	    top = &(style->rootMatch);
+	    break;
+        case XSLT_OP_KEY:
+	    top = &(style->keyMatch);
+	    break;
+        case XSLT_OP_ID:
+	    /* TODO optimize ID !!! */
+        case XSLT_OP_NS:
+        case XSLT_OP_ALL:
+	    top = &(style->elemMatch);
+	    break;
+        case XSLT_OP_END:
+	case XSLT_OP_PREDICATE:
+	    xsltTransformError(NULL, style, NULL,
+			     "xsltAddTemplate: invalid compiled pattern\n");
+	    xsltFreeCompMatch(pat);
+	    return(-1);
+	    /*
+	     * TODO: some flags at the top level about type based patterns
+	     *       would be faster than inclusion in the hash table.
+	     */
+	case XSLT_OP_PI:
+	    if (pat->steps[0].value != NULL)
+		name = pat->steps[0].value;
+	    else
+		top = &(style->piMatch);
+	    break;
+	case XSLT_OP_COMMENT:
+	    top = &(style->commentMatch);
+	    break;
+	case XSLT_OP_TEXT:
+	    top = &(style->textMatch);
+	    break;
+        case XSLT_OP_ELEM:
+	case XSLT_OP_NODE:
+	    if (pat->steps[0].value != NULL)
+		name = pat->steps[0].value;
+	    else
+		top = &(style->elemMatch);
+	    break;
+	}
+	if (name != NULL) {
+	    if (style->templatesHash == NULL) {
+		style->templatesHash = xmlHashCreate(1024);
+		if (style->templatesHash == NULL) {
+		    xsltFreeCompMatch(pat);
+		    return(-1);
+		}
+		xmlHashAddEntry3(style->templatesHash, name, mode, modeURI, pat);
+	    } else {
+		list = (xsltCompMatchPtr) xmlHashLookup3(style->templatesHash,
+							 name, mode, modeURI);
+		if (list == NULL) {
+		    xmlHashAddEntry3(style->templatesHash, name,
+				     mode, modeURI, pat);
+		} else {
+		    /*
+		     * Note '<=' since one must choose among the matching
+		     * template rules that are left, the one that occurs
+		     * last in the stylesheet
+		     */
+		    if (list->priority <= pat->priority) {
+			pat->next = list;
+			xmlHashUpdateEntry3(style->templatesHash, name,
+					    mode, modeURI, pat, NULL);
+		    } else {
+			while (list->next != NULL) {
+			    if (list->next->priority <= pat->priority)
+				break;
+			    list = list->next;
+			}
+			pat->next = list->next;
+			list->next = pat;
+		    }
+		}
+	    }
+	} else if (top != NULL) {
+	    list = *top;
+	    if (list == NULL) {
+		*top = pat;
+		pat->next = NULL;
+	    } else if (list->priority <= pat->priority) {
+		pat->next = list;
+		*top = pat;
+	    } else {
+		while (list->next != NULL) {
+		    if (list->next->priority <= pat->priority)
+			break;
+		    list = list->next;
+		}
+		pat->next = list->next;
+		list->next = pat;
+	    }
+	} else {
+	    xsltTransformError(NULL, style, NULL,
+			     "xsltAddTemplate: invalid compiled pattern\n");
+	    xsltFreeCompMatch(pat);
+	    return(-1);
+	}
+#ifdef WITH_XSLT_DEBUG_PATTERN
+	if (mode)
+	    xsltGenericDebug(xsltGenericDebugContext,
+			 "added pattern : '%s' mode '%s' priority %f\n",
+			     pat->pattern, pat->mode, pat->priority);
+	else
+	    xsltGenericDebug(xsltGenericDebugContext,
+			 "added pattern : '%s' priority %f\n",
+			     pat->pattern, pat->priority);
+#endif
+
+	pat = next;
+    }
+    return(0);
+}
+
+static int
+xsltComputeAllKeys(xsltTransformContextPtr ctxt, xmlNodePtr contextNode)
+{
+    if ((ctxt == NULL) || (contextNode == NULL)) {
+	xsltTransformError(ctxt, NULL, ctxt->inst,
+	    "Internal error in xsltComputeAllKeys(): "
+	    "Bad arguments.\n");
+	return(-1);
+    }
+
+    if (ctxt->document == NULL) {
+	/*
+	* The document info will only be NULL if we have a RTF.
+	*/
+	if (contextNode->doc->_private != NULL)
+	    goto doc_info_mismatch;
+	/*
+	* On-demand creation of the document info (needed for keys).
+	*/
+	ctxt->document = xsltNewDocument(ctxt, contextNode->doc);
+	if (ctxt->document == NULL)
+	    return(-1);
+    }
+    return xsltInitAllDocKeys(ctxt);
+
+doc_info_mismatch:
+    xsltTransformError(ctxt, NULL, ctxt->inst,
+	"Internal error in xsltComputeAllKeys(): "
+	"The context's document info doesn't match the "
+	"document info of the current result tree.\n");
+    ctxt->state = XSLT_STATE_STOPPED;
+    return(-1);
+}
+
+/**
+ * xsltGetTemplate:
+ * @ctxt:  a XSLT process context
+ * @node:  the node being processed
+ * @style:  the current style
+ *
+ * Finds the template applying to this node, if @style is non-NULL
+ * it means one needs to look for the next imported template in scope.
+ *
+ * Returns the xsltTemplatePtr or NULL if not found
+ */
+xsltTemplatePtr
+xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	        xsltStylesheetPtr style)
+{
+    xsltStylesheetPtr curstyle;
+    xsltTemplatePtr ret = NULL;
+    const xmlChar *name = NULL;
+    xsltCompMatchPtr list = NULL;
+    float priority;
+    int keyed = 0;
+
+    if ((ctxt == NULL) || (node == NULL))
+	return(NULL);
+
+    if (style == NULL) {
+	curstyle = ctxt->style;
+    } else {
+	curstyle = xsltNextImport(style);
+    }
+
+    while ((curstyle != NULL) && (curstyle != style)) {
+	priority = XSLT_PAT_NO_PRIORITY;
+	/* TODO : handle IDs/keys here ! */
+	if (curstyle->templatesHash != NULL) {
+	    /*
+	     * Use the top name as selector
+	     */
+	    switch (node->type) {
+		case XML_ELEMENT_NODE:
+		    if (node->name[0] == ' ')
+			break;
+		case XML_ATTRIBUTE_NODE:
+		case XML_PI_NODE:
+		    name = node->name;
+		    break;
+		case XML_DOCUMENT_NODE:
+		case XML_HTML_DOCUMENT_NODE:
+		case XML_TEXT_NODE:
+		case XML_CDATA_SECTION_NODE:
+		case XML_COMMENT_NODE:
+		case XML_ENTITY_REF_NODE:
+		case XML_ENTITY_NODE:
+		case XML_DOCUMENT_TYPE_NODE:
+		case XML_DOCUMENT_FRAG_NODE:
+		case XML_NOTATION_NODE:
+		case XML_DTD_NODE:
+		case XML_ELEMENT_DECL:
+		case XML_ATTRIBUTE_DECL:
+		case XML_ENTITY_DECL:
+		case XML_NAMESPACE_DECL:
+		case XML_XINCLUDE_START:
+		case XML_XINCLUDE_END:
+		    break;
+		default:
+		    return(NULL);
+
+	    }
+	}
+	if (name != NULL) {
+	    /*
+	     * find the list of applicable expressions based on the name
+	     */
+	    list = (xsltCompMatchPtr) xmlHashLookup3(curstyle->templatesHash,
+					     name, ctxt->mode, ctxt->modeURI);
+	} else
+	    list = NULL;
+	while (list != NULL) {
+	    if (xsltTestCompMatch(ctxt, list, node,
+			          ctxt->mode, ctxt->modeURI)) {
+		ret = list->template;
+		priority = list->priority;
+		break;
+	    }
+	    list = list->next;
+	}
+	list = NULL;
+
+	/*
+	 * find alternate generic matches
+	 */
+	switch (node->type) {
+	    case XML_ELEMENT_NODE:
+		if (node->name[0] == ' ')
+		    list = curstyle->rootMatch;
+		else
+		    list = curstyle->elemMatch;
+		if (node->psvi != NULL) keyed = 1;
+		break;
+	    case XML_ATTRIBUTE_NODE: {
+	        xmlAttrPtr attr;
+
+		list = curstyle->attrMatch;
+		attr = (xmlAttrPtr) node;
+		if (attr->psvi != NULL) keyed = 1;
+		break;
+	    }
+	    case XML_PI_NODE:
+		list = curstyle->piMatch;
+		if (node->psvi != NULL) keyed = 1;
+		break;
+	    case XML_DOCUMENT_NODE:
+	    case XML_HTML_DOCUMENT_NODE: {
+	        xmlDocPtr doc;
+
+		list = curstyle->rootMatch;
+		doc = (xmlDocPtr) node;
+		if (doc->psvi != NULL) keyed = 1;
+		break;
+	    }
+	    case XML_TEXT_NODE:
+	    case XML_CDATA_SECTION_NODE:
+		list = curstyle->textMatch;
+		if (node->psvi != NULL) keyed = 1;
+		break;
+	    case XML_COMMENT_NODE:
+		list = curstyle->commentMatch;
+		if (node->psvi != NULL) keyed = 1;
+		break;
+	    case XML_ENTITY_REF_NODE:
+	    case XML_ENTITY_NODE:
+	    case XML_DOCUMENT_TYPE_NODE:
+	    case XML_DOCUMENT_FRAG_NODE:
+	    case XML_NOTATION_NODE:
+	    case XML_DTD_NODE:
+	    case XML_ELEMENT_DECL:
+	    case XML_ATTRIBUTE_DECL:
+	    case XML_ENTITY_DECL:
+	    case XML_NAMESPACE_DECL:
+	    case XML_XINCLUDE_START:
+	    case XML_XINCLUDE_END:
+		break;
+	    default:
+		break;
+	}
+	while ((list != NULL) &&
+	       ((ret == NULL)  || (list->priority > priority))) {
+	    if (xsltTestCompMatch(ctxt, list, node,
+			          ctxt->mode, ctxt->modeURI)) {
+		ret = list->template;
+		priority = list->priority;
+		break;
+	    }
+	    list = list->next;
+	}
+	/*
+	 * Some of the tests for elements can also apply to documents
+	 */
+	if ((node->type == XML_DOCUMENT_NODE) ||
+	    (node->type == XML_HTML_DOCUMENT_NODE) ||
+	    (node->type == XML_TEXT_NODE)) {
+	    list = curstyle->elemMatch;
+	    while ((list != NULL) &&
+		   ((ret == NULL)  || (list->priority > priority))) {
+		if (xsltTestCompMatch(ctxt, list, node,
+				      ctxt->mode, ctxt->modeURI)) {
+		    ret = list->template;
+		    priority = list->priority;
+		    break;
+		}
+		list = list->next;
+	    }
+	} else if ((node->type == XML_PI_NODE) ||
+		   (node->type == XML_COMMENT_NODE)) {
+	    list = curstyle->elemMatch;
+	    while ((list != NULL) &&
+		   ((ret == NULL)  || (list->priority > priority))) {
+		if (xsltTestCompMatch(ctxt, list, node,
+				      ctxt->mode, ctxt->modeURI)) {
+		    ret = list->template;
+		    priority = list->priority;
+		    break;
+		}
+		list = list->next;
+	    }
+	}
+
+keyed_match:
+	if (keyed) {
+	    list = curstyle->keyMatch;
+	    while ((list != NULL) &&
+		   ((ret == NULL)  || (list->priority > priority))) {
+		if (xsltTestCompMatch(ctxt, list, node,
+				      ctxt->mode, ctxt->modeURI)) {
+		    ret = list->template;
+		    priority = list->priority;
+		    break;
+		}
+		list = list->next;
+	    }
+	}
+	else if (ctxt->hasTemplKeyPatterns &&
+	    ((ctxt->document == NULL) ||
+	     (ctxt->document->nbKeysComputed < ctxt->nbKeys)))
+	{
+	    /*
+	    * Compute all remaining keys for this document.
+	    *
+	    * REVISIT TODO: I think this could be further optimized.
+	    */
+	    if (xsltComputeAllKeys(ctxt, node) == -1)
+		goto error;
+
+	    switch (node->type) {
+		case XML_ELEMENT_NODE:		    
+		    if (node->psvi != NULL) keyed = 1;
+		    break;
+		case XML_ATTRIBUTE_NODE:
+		    if (((xmlAttrPtr) node)->psvi != NULL) keyed = 1;
+		    break;
+		case XML_TEXT_NODE:
+		case XML_CDATA_SECTION_NODE:
+		case XML_COMMENT_NODE:
+		case XML_PI_NODE:		
+		    if (node->psvi != NULL) keyed = 1;
+		    break;
+		case XML_DOCUMENT_NODE:
+		case XML_HTML_DOCUMENT_NODE:
+		    if (((xmlDocPtr) node)->psvi != NULL) keyed = 1;
+		    break;		
+		default:
+		    break;
+	    }
+	    if (keyed)
+		goto keyed_match;
+	}
+	if (ret != NULL)
+	    return(ret);
+
+	/*
+	 * Cycle on next curstylesheet import.
+	 */
+	curstyle = xsltNextImport(curstyle);
+    }
+
+error:
+    return(NULL);
+}
+
+/**
+ * xsltCleanupTemplates:
+ * @style: an XSLT stylesheet
+ *
+ * Cleanup the state of the templates used by the stylesheet and
+ * the ones it imports.
+ */
+void
+xsltCleanupTemplates(xsltStylesheetPtr style ATTRIBUTE_UNUSED) {
+}
+
+/**
+ * xsltFreeTemplateHashes:
+ * @style: an XSLT stylesheet
+ *
+ * Free up the memory used by xsltAddTemplate/xsltGetTemplate mechanism
+ */
+void
+xsltFreeTemplateHashes(xsltStylesheetPtr style) {
+    if (style->templatesHash != NULL)
+	xmlHashFree((xmlHashTablePtr) style->templatesHash,
+		    (xmlHashDeallocator) xsltFreeCompMatchList);
+    if (style->rootMatch != NULL)
+        xsltFreeCompMatchList(style->rootMatch);
+    if (style->keyMatch != NULL)
+        xsltFreeCompMatchList(style->keyMatch);
+    if (style->elemMatch != NULL)
+        xsltFreeCompMatchList(style->elemMatch);
+    if (style->attrMatch != NULL)
+        xsltFreeCompMatchList(style->attrMatch);
+    if (style->parentMatch != NULL)
+        xsltFreeCompMatchList(style->parentMatch);
+    if (style->textMatch != NULL)
+        xsltFreeCompMatchList(style->textMatch);
+    if (style->piMatch != NULL)
+        xsltFreeCompMatchList(style->piMatch);
+    if (style->commentMatch != NULL)
+        xsltFreeCompMatchList(style->commentMatch);
+}
+
diff --git a/libxslt/pattern.h b/libxslt/pattern.h
new file mode 100644
index 0000000..eb21be3
--- /dev/null
+++ b/libxslt/pattern.h
@@ -0,0 +1,81 @@
+/*
+ * Summary: interface for the pattern matching used in template matches.
+ * Description: the implementation of the lookup of the right template
+ *              for a given node must be really fast in order to keep
+ *              decent performances.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_PATTERN_H__
+#define __XML_XSLT_PATTERN_H__
+
+#include "xsltInternals.h"
+#include "xsltexports.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * xsltCompMatch:
+ *
+ * Data structure used for the implementation of patterns.
+ * It is kept private (in pattern.c).
+ */
+typedef struct _xsltCompMatch xsltCompMatch;
+typedef xsltCompMatch *xsltCompMatchPtr;
+
+/*
+ * Pattern related interfaces.
+ */
+
+XSLTPUBFUN xsltCompMatchPtr XSLTCALL
+		xsltCompilePattern	(const xmlChar *pattern,
+					 xmlDocPtr doc,
+					 xmlNodePtr node,
+					 xsltStylesheetPtr style,
+					 xsltTransformContextPtr runtime);
+XSLTPUBFUN void XSLTCALL
+		xsltFreeCompMatchList	(xsltCompMatchPtr comp);
+XSLTPUBFUN int XSLTCALL
+		xsltTestCompMatchList	(xsltTransformContextPtr ctxt,
+					 xmlNodePtr node,
+					 xsltCompMatchPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltNormalizeCompSteps	(void *payload,
+					 void *data,
+					 const xmlChar *name);
+
+/*
+ * Template related interfaces.
+ */
+XSLTPUBFUN int XSLTCALL
+		xsltAddTemplate		(xsltStylesheetPtr style,
+					 xsltTemplatePtr cur,
+					 const xmlChar *mode,
+					 const xmlChar *modeURI);
+XSLTPUBFUN xsltTemplatePtr XSLTCALL
+		xsltGetTemplate		(xsltTransformContextPtr ctxt,
+					 xmlNodePtr node,
+					 xsltStylesheetPtr style);
+XSLTPUBFUN void XSLTCALL
+		xsltFreeTemplateHashes	(xsltStylesheetPtr style);
+XSLTPUBFUN void XSLTCALL
+		xsltCleanupTemplates	(xsltStylesheetPtr style);
+
+#if 0
+int		xsltMatchPattern	(xsltTransformContextPtr ctxt,
+					 xmlNodePtr node,
+					 const xmlChar *pattern,
+					 xmlDocPtr ctxtdoc,
+					 xmlNodePtr ctxtnode);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_PATTERN_H__ */
+
diff --git a/libxslt/preproc.c b/libxslt/preproc.c
new file mode 100644
index 0000000..b47d809
--- /dev/null
+++ b/libxslt/preproc.c
@@ -0,0 +1,2350 @@
+/*
+ * preproc.c: Preprocessing of style operations
+ *
+ * References:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ *   Michael Kay "XSLT Programmer's Reference" pp 637-643
+ *   Writing Multiple Output Files
+ *
+ *   XSLT-1.1 Working Draft
+ *   http://www.w3.org/TR/xslt11#multiple-output
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+#include <libxml/hash.h>
+#include <libxml/uri.h>
+#include <libxml/encoding.h>
+#include <libxml/xmlerror.h>
+#include "xslt.h"
+#include "xsltutils.h"
+#include "xsltInternals.h"
+#include "transform.h"
+#include "templates.h"
+#include "variables.h"
+#include "numbersInternals.h"
+#include "preproc.h"
+#include "extra.h"
+#include "imports.h"
+#include "extensions.h"
+
+#ifdef WITH_XSLT_DEBUG
+#define WITH_XSLT_DEBUG_PREPROC
+#endif
+
+const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element";
+
+/************************************************************************
+ *									*
+ *			Grammar checks					*
+ *									*
+ ************************************************************************/
+
+#ifdef XSLT_REFACTORED
+    /*
+    * Grammar checks are now performed in xslt.c.
+    */
+#else
+/**
+ * xsltCheckTopLevelElement:
+ * @style: the XSLT stylesheet
+ * @inst: the XSLT instruction
+ * @err: raise an error or not
+ *
+ * Check that the instruction is instanciated as a top level element.
+ *
+ * Returns -1 in case of error, 0 if failed and 1 in case of success
+ */
+static int
+xsltCheckTopLevelElement(xsltStylesheetPtr style, xmlNodePtr inst, int err) {
+    xmlNodePtr parent;
+    if ((style == NULL) || (inst == NULL) || (inst->ns == NULL))
+        return(-1);
+    
+    parent = inst->parent;
+    if (parent == NULL) {
+        if (err) {
+	    xsltTransformError(NULL, style, inst,
+		    "internal problem: element has no parent\n");
+	    style->errors++;
+	}
+	return(0);
+    }
+    if ((parent->ns == NULL) || (parent->type != XML_ELEMENT_NODE) ||
+        ((parent->ns != inst->ns) &&
+	 (!xmlStrEqual(parent->ns->href, inst->ns->href))) ||
+	((!xmlStrEqual(parent->name, BAD_CAST "stylesheet")) &&
+	 (!xmlStrEqual(parent->name, BAD_CAST "transform")))) {
+	if (err) {
+	    xsltTransformError(NULL, style, inst,
+		    "element %s only allowed as child of stylesheet\n",
+			       inst->name);
+	    style->errors++;
+	}
+	return(0);
+    }
+    return(1);
+}
+
+/**
+ * xsltCheckInstructionElement:
+ * @style: the XSLT stylesheet
+ * @inst: the XSLT instruction
+ *
+ * Check that the instruction is instanciated as an instruction element.
+ */
+static void
+xsltCheckInstructionElement(xsltStylesheetPtr style, xmlNodePtr inst) {
+    xmlNodePtr parent;
+    int has_ext;
+
+    if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||
+        (style->literal_result))
+        return;
+
+    has_ext = (style->extInfos != NULL);
+    
+    parent = inst->parent;
+    if (parent == NULL) {
+	xsltTransformError(NULL, style, inst,
+		"internal problem: element has no parent\n");
+	style->errors++;
+	return;
+    }
+    while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) {
+        if (((parent->ns == inst->ns) ||
+	     ((parent->ns != NULL) &&
+	      (xmlStrEqual(parent->ns->href, inst->ns->href)))) &&
+	    ((xmlStrEqual(parent->name, BAD_CAST "template")) ||
+	     (xmlStrEqual(parent->name, BAD_CAST "param")) ||
+	     (xmlStrEqual(parent->name, BAD_CAST "attribute")) ||
+	     (xmlStrEqual(parent->name, BAD_CAST "variable")))) {
+	    return;
+	}
+
+	/*
+	 * if we are within an extension element all bets are off
+	 * about the semantic there e.g. xsl:param within func:function
+	 */
+	if ((has_ext) && (parent->ns != NULL) &&
+	    (xmlHashLookup(style->extInfos, parent->ns->href) != NULL))
+	    return;
+	
+        parent = parent->parent;
+    }
+    xsltTransformError(NULL, style, inst,
+	    "element %s only allowed within a template, variable or param\n",
+		           inst->name);
+    style->errors++;
+}
+
+/**
+ * xsltCheckParentElement:
+ * @style: the XSLT stylesheet
+ * @inst: the XSLT instruction
+ * @allow1: allowed parent1
+ * @allow2: allowed parent2
+ *
+ * Check that the instruction is instanciated as the childre of one of the
+ * possible parents.
+ */
+static void
+xsltCheckParentElement(xsltStylesheetPtr style, xmlNodePtr inst,
+                       const xmlChar *allow1, const xmlChar *allow2) {
+    xmlNodePtr parent;
+
+    if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) ||
+        (style->literal_result))
+        return;
+
+    parent = inst->parent;
+    if (parent == NULL) {
+	xsltTransformError(NULL, style, inst,
+		"internal problem: element has no parent\n");
+	style->errors++;
+	return;
+    }
+    if (((parent->ns == inst->ns) ||
+	 ((parent->ns != NULL) &&
+	  (xmlStrEqual(parent->ns->href, inst->ns->href)))) &&
+	((xmlStrEqual(parent->name, allow1)) ||
+	 (xmlStrEqual(parent->name, allow2)))) {
+	return;
+    }
+
+    if (style->extInfos != NULL) {
+	while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) {
+	    /*
+	     * if we are within an extension element all bets are off
+	     * about the semantic there e.g. xsl:param within func:function
+	     */
+	    if ((parent->ns != NULL) &&
+		(xmlHashLookup(style->extInfos, parent->ns->href) != NULL))
+		return;
+	    
+	    parent = parent->parent;
+	}
+    }
+    xsltTransformError(NULL, style, inst,
+		       "element %s is not allowed within that context\n",
+		       inst->name);
+    style->errors++;
+}
+#endif
+
+/************************************************************************
+ *									*
+ *			handling of precomputed data			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltNewStylePreComp:
+ * @style:  the XSLT stylesheet
+ * @type:  the construct type
+ *
+ * Create a new XSLT Style precomputed block
+ *
+ * Returns the newly allocated specialized structure
+ *         or NULL in case of error
+ */
+static xsltStylePreCompPtr
+xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) {
+    xsltStylePreCompPtr cur;
+#ifdef XSLT_REFACTORED
+    size_t size;
+#endif
+
+    if (style == NULL)
+        return(NULL);
+   
+#ifdef XSLT_REFACTORED
+    /*
+    * URGENT TODO: Use specialized factory functions in order
+    *   to avoid this ugliness.
+    */
+    switch (type) {
+        case XSLT_FUNC_COPY:
+            size = sizeof(xsltStyleItemCopy); break;
+        case XSLT_FUNC_SORT:
+            size = sizeof(xsltStyleItemSort); break;
+        case XSLT_FUNC_TEXT:
+            size = sizeof(xsltStyleItemText); break;
+        case XSLT_FUNC_ELEMENT:
+            size = sizeof(xsltStyleItemElement); break;
+        case XSLT_FUNC_ATTRIBUTE:
+            size = sizeof(xsltStyleItemAttribute); break;
+        case XSLT_FUNC_COMMENT:
+            size = sizeof(xsltStyleItemComment); break;
+        case XSLT_FUNC_PI:
+            size = sizeof(xsltStyleItemPI); break;
+        case XSLT_FUNC_COPYOF:
+            size = sizeof(xsltStyleItemCopyOf); break;
+        case XSLT_FUNC_VALUEOF:
+            size = sizeof(xsltStyleItemValueOf); break;;
+        case XSLT_FUNC_NUMBER:
+            size = sizeof(xsltStyleItemNumber); break;
+        case XSLT_FUNC_APPLYIMPORTS:
+            size = sizeof(xsltStyleItemApplyImports); break;
+        case XSLT_FUNC_CALLTEMPLATE:
+            size = sizeof(xsltStyleItemCallTemplate); break;
+        case XSLT_FUNC_APPLYTEMPLATES:
+            size = sizeof(xsltStyleItemApplyTemplates); break;
+        case XSLT_FUNC_CHOOSE:
+            size = sizeof(xsltStyleItemChoose); break;
+        case XSLT_FUNC_IF:
+            size = sizeof(xsltStyleItemIf); break;
+        case XSLT_FUNC_FOREACH:
+            size = sizeof(xsltStyleItemForEach); break;
+        case XSLT_FUNC_DOCUMENT:
+            size = sizeof(xsltStyleItemDocument); break;
+	case XSLT_FUNC_WITHPARAM:
+	    size = sizeof(xsltStyleItemWithParam); break;
+	case XSLT_FUNC_PARAM:
+	    size = sizeof(xsltStyleItemParam); break;
+	case XSLT_FUNC_VARIABLE:
+	    size = sizeof(xsltStyleItemVariable); break;
+	case XSLT_FUNC_WHEN:
+	    size = sizeof(xsltStyleItemWhen); break;
+	case XSLT_FUNC_OTHERWISE:
+	    size = sizeof(xsltStyleItemOtherwise); break;
+	default:	
+	    xsltTransformError(NULL, style, NULL,
+		    "xsltNewStylePreComp : invalid type %d\n", type);
+	    style->errors++;
+	    return(NULL);
+    }
+    /*
+    * Create the structure.
+    */
+    cur = (xsltStylePreCompPtr) xmlMalloc(size);
+    if (cur == NULL) {
+	xsltTransformError(NULL, style, NULL,
+		"xsltNewStylePreComp : malloc failed\n");
+	style->errors++;
+	return(NULL);
+    }
+    memset(cur, 0, size);
+
+#else /* XSLT_REFACTORED */
+    /*
+    * Old behaviour.
+    */
+    cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp));
+    if (cur == NULL) {
+	xsltTransformError(NULL, style, NULL,
+		"xsltNewStylePreComp : malloc failed\n");
+	style->errors++;
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltStylePreComp));
+#endif /* XSLT_REFACTORED */
+
+    /*
+    * URGENT TODO: Better to move this to spezialized factory functions.
+    */
+    cur->type = type;
+    switch (cur->type) {
+        case XSLT_FUNC_COPY:
+            cur->func = (xsltTransformFunction) xsltCopy;break;
+        case XSLT_FUNC_SORT:
+            cur->func = (xsltTransformFunction) xsltSort;break;
+        case XSLT_FUNC_TEXT:
+            cur->func = (xsltTransformFunction) xsltText;break;
+        case XSLT_FUNC_ELEMENT:
+            cur->func = (xsltTransformFunction) xsltElement;break;
+        case XSLT_FUNC_ATTRIBUTE:
+            cur->func = (xsltTransformFunction) xsltAttribute;break;
+        case XSLT_FUNC_COMMENT:
+            cur->func = (xsltTransformFunction) xsltComment;break;
+        case XSLT_FUNC_PI:
+            cur->func = (xsltTransformFunction) xsltProcessingInstruction;
+	    break;
+        case XSLT_FUNC_COPYOF:
+            cur->func = (xsltTransformFunction) xsltCopyOf;break;
+        case XSLT_FUNC_VALUEOF:
+            cur->func = (xsltTransformFunction) xsltValueOf;break;
+        case XSLT_FUNC_NUMBER:
+            cur->func = (xsltTransformFunction) xsltNumber;break;
+        case XSLT_FUNC_APPLYIMPORTS:
+            cur->func = (xsltTransformFunction) xsltApplyImports;break;
+        case XSLT_FUNC_CALLTEMPLATE:
+            cur->func = (xsltTransformFunction) xsltCallTemplate;break;
+        case XSLT_FUNC_APPLYTEMPLATES:
+            cur->func = (xsltTransformFunction) xsltApplyTemplates;break;
+        case XSLT_FUNC_CHOOSE:
+            cur->func = (xsltTransformFunction) xsltChoose;break;
+        case XSLT_FUNC_IF:
+            cur->func = (xsltTransformFunction) xsltIf;break;
+        case XSLT_FUNC_FOREACH:
+            cur->func = (xsltTransformFunction) xsltForEach;break;
+        case XSLT_FUNC_DOCUMENT:
+            cur->func = (xsltTransformFunction) xsltDocumentElem;break;
+	case XSLT_FUNC_WITHPARAM:
+	case XSLT_FUNC_PARAM:	    
+	case XSLT_FUNC_VARIABLE:	    
+	case XSLT_FUNC_WHEN:
+	    break;
+	default:
+	if (cur->func == NULL) {
+	    xsltTransformError(NULL, style, NULL,
+		    "xsltNewStylePreComp : no function for type %d\n", type);
+	    style->errors++;
+	}
+    }
+    cur->next = style->preComps;
+    style->preComps = (xsltElemPreCompPtr) cur;
+
+    return(cur);
+}
+
+/**
+ * xsltFreeStylePreComp:
+ * @comp:  an XSLT Style precomputed block
+ *
+ * Free up the memory allocated by @comp
+ */
+static void
+xsltFreeStylePreComp(xsltStylePreCompPtr comp) {
+    if (comp == NULL)
+	return;
+#ifdef XSLT_REFACTORED
+    /*
+    * URGENT TODO: Implement destructors.
+    */
+    switch (comp->type) {
+	case XSLT_FUNC_LITERAL_RESULT_ELEMENT:
+	    break;
+	case XSLT_FUNC_COPY:
+            break;
+        case XSLT_FUNC_SORT: {
+		xsltStyleItemSortPtr item = (xsltStyleItemSortPtr) comp;
+		if (item->locale != (xsltLocale)0)
+		    xsltFreeLocale(item->locale);
+		if (item->comp != NULL)
+		    xmlXPathFreeCompExpr(item->comp);
+	    }
+            break;
+        case XSLT_FUNC_TEXT:
+            break;
+        case XSLT_FUNC_ELEMENT:
+            break;
+        case XSLT_FUNC_ATTRIBUTE:
+            break;
+        case XSLT_FUNC_COMMENT:
+            break;
+        case XSLT_FUNC_PI:
+	    break;
+        case XSLT_FUNC_COPYOF: {
+		xsltStyleItemCopyOfPtr item = (xsltStyleItemCopyOfPtr) comp;
+		if (item->comp != NULL)
+		    xmlXPathFreeCompExpr(item->comp);
+	    }
+            break;
+        case XSLT_FUNC_VALUEOF: {
+		xsltStyleItemValueOfPtr item = (xsltStyleItemValueOfPtr) comp;
+		if (item->comp != NULL)
+		    xmlXPathFreeCompExpr(item->comp);
+	    }
+            break;
+        case XSLT_FUNC_NUMBER:
+            break;
+        case XSLT_FUNC_APPLYIMPORTS:
+            break;
+        case XSLT_FUNC_CALLTEMPLATE:
+            break;
+        case XSLT_FUNC_APPLYTEMPLATES: {
+		xsltStyleItemApplyTemplatesPtr item =
+		    (xsltStyleItemApplyTemplatesPtr) comp;
+		if (item->comp != NULL)
+		    xmlXPathFreeCompExpr(item->comp);
+	    }
+            break;
+        case XSLT_FUNC_CHOOSE:
+            break;
+        case XSLT_FUNC_IF: {
+		xsltStyleItemIfPtr item = (xsltStyleItemIfPtr) comp;
+		if (item->comp != NULL)
+		    xmlXPathFreeCompExpr(item->comp);
+	    }
+            break;
+        case XSLT_FUNC_FOREACH: {
+		xsltStyleItemForEachPtr item =
+		    (xsltStyleItemForEachPtr) comp;
+		if (item->comp != NULL)
+		    xmlXPathFreeCompExpr(item->comp);
+	    }
+            break;
+        case XSLT_FUNC_DOCUMENT:
+            break;
+	case XSLT_FUNC_WITHPARAM: {
+		xsltStyleItemWithParamPtr item =
+		    (xsltStyleItemWithParamPtr) comp;
+		if (item->comp != NULL)
+		    xmlXPathFreeCompExpr(item->comp);
+	    }
+	    break;
+	case XSLT_FUNC_PARAM: {
+		xsltStyleItemParamPtr item =
+		    (xsltStyleItemParamPtr) comp;
+		if (item->comp != NULL)
+		    xmlXPathFreeCompExpr(item->comp);
+	    }
+	    break;
+	case XSLT_FUNC_VARIABLE: {
+		xsltStyleItemVariablePtr item =
+		    (xsltStyleItemVariablePtr) comp;
+		if (item->comp != NULL)
+		    xmlXPathFreeCompExpr(item->comp);
+	    }
+	    break;
+	case XSLT_FUNC_WHEN: {
+		xsltStyleItemWhenPtr item =
+		    (xsltStyleItemWhenPtr) comp;
+		if (item->comp != NULL)
+		    xmlXPathFreeCompExpr(item->comp);
+	    }
+	    break;
+	case XSLT_FUNC_OTHERWISE:	    
+	case XSLT_FUNC_FALLBACK:
+	case XSLT_FUNC_MESSAGE:
+	case XSLT_FUNC_INCLUDE:
+	case XSLT_FUNC_ATTRSET:
+	
+	    break;
+	default:
+	    /* TODO: Raise error. */
+	    break;
+    }
+#else    
+    if (comp->locale != (xsltLocale)0)
+	xsltFreeLocale(comp->locale);
+    if (comp->comp != NULL)
+	xmlXPathFreeCompExpr(comp->comp);
+    if (comp->nsList != NULL)
+	xmlFree(comp->nsList);
+#endif
+
+    xmlFree(comp);
+}
+
+
+/************************************************************************
+ *									*
+ *		    XSLT-1.1 extensions					*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltDocumentComp:
+ * @style:  the XSLT stylesheet
+ * @inst:  the instruction in the stylesheet
+ * @function:  unused
+ *
+ * Pre process an XSLT-1.1 document element
+ *
+ * Returns a precompiled data structure for the element
+ */
+xsltElemPreCompPtr
+xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst,
+		 xsltTransformFunction function ATTRIBUTE_UNUSED) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemDocumentPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+    const xmlChar *filename = NULL;
+
+    /*
+    * As of 2006-03-30, this function is currently defined in Libxslt
+    * to be used for:
+    * (in libxslt/extra.c)
+    * "output" in XSLT_SAXON_NAMESPACE
+    * "write" XSLT_XALAN_NAMESPACE
+    * "document" XSLT_XT_NAMESPACE
+    * "document" XSLT_NAMESPACE (from the abandoned old working
+    *                            draft of XSLT 1.1)
+    * (in libexslt/common.c)
+    * "document" in EXSLT_COMMON_NAMESPACE
+    */
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemDocumentPtr)
+	xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT);
+#endif
+    
+    if (comp == NULL)
+	return (NULL);
+    comp->inst = inst;
+    comp->ver11 = 0;
+
+    if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
+#ifdef WITH_XSLT_DEBUG_EXTRA
+	xsltGenericDebug(xsltGenericDebugContext,
+	    "Found saxon:output extension\n");
+#endif
+	/*
+	* The element "output" is in the namespace XSLT_SAXON_NAMESPACE
+	*   (http://icl.com/saxon)
+	* The @file is in no namespace; it is an AVT.
+	*   (http://www.computerwizards.com/saxon/doc/extensions.html#saxon:output)
+	*
+	* TODO: Do we need not to check the namespace here?
+	*/
+	filename = xsltEvalStaticAttrValueTemplate(style, inst,
+			 (const xmlChar *)"file",
+			 NULL, &comp->has_filename);
+    } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
+#ifdef WITH_XSLT_DEBUG_EXTRA
+	xsltGenericDebug(xsltGenericDebugContext,
+	    "Found xalan:write extension\n");
+#endif
+	/* the filename need to be interpreted */
+	/*
+	* TODO: Is "filename need to be interpreted" meant to be a todo?
+	*   Where will be the filename of xalan:write be processed?
+	*
+	* TODO: Do we need not to check the namespace here?
+	*   The extension ns is "http://xml.apache.org/xalan/redirect".
+	*   See http://xml.apache.org/xalan-j/extensionslib.html.
+	*/
+    } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
+	if (inst->ns != NULL) {
+	    if (xmlStrEqual(inst->ns->href, XSLT_NAMESPACE)) {
+		/*
+		* Mark the instruction as being of
+		* XSLT version 1.1 (abandoned).
+		*/
+		comp->ver11 = 1;
+#ifdef WITH_XSLT_DEBUG_EXTRA
+		xsltGenericDebug(xsltGenericDebugContext,
+		    "Found xslt11:document construct\n");
+#endif	    		
+	    } else {		
+		if (xmlStrEqual(inst->ns->href,
+		    (const xmlChar *)"http://exslt.org/common")) {
+		    /* EXSLT. */
+#ifdef WITH_XSLT_DEBUG_EXTRA
+		    xsltGenericDebug(xsltGenericDebugContext,
+			"Found exslt:document extension\n");
+#endif
+		} else if (xmlStrEqual(inst->ns->href, XSLT_XT_NAMESPACE)) {
+		    /* James Clark's XT. */
+#ifdef WITH_XSLT_DEBUG_EXTRA
+		    xsltGenericDebug(xsltGenericDebugContext,
+			"Found xt:document extension\n");
+#endif
+		}
+	    }
+	}
+	/*
+	* The element "document" is used in conjunction with the
+	* following namespaces:
+	*
+	* 1) XSLT_NAMESPACE (http://www.w3.org/1999/XSL/Transform version 1.1)
+	*    <!ELEMENT xsl:document %template;>
+	*    <!ATTLIST xsl:document
+	*       href %avt; #REQUIRED
+	*    @href is an AVT
+	*    IMPORTANT: xsl:document was in the abandoned XSLT 1.1 draft,
+	*    it was removed and isn't available in XSLT 1.1 anymore.
+	*    In XSLT 2.0 it was renamed to xsl:result-document.
+	*
+	*   All other attributes are identical to the attributes
+	*   on xsl:output
+	*
+	* 2) EXSLT_COMMON_NAMESPACE (http://exslt.org/common)
+	*    <exsl:document
+	*       href = { uri-reference }
+	*    TODO: is @href is an AVT?
+	*
+	* 3) XSLT_XT_NAMESPACE (http://www.jclark.com/xt)
+	*     Example: <xt:document method="xml" href="myFile.xml">
+	*    TODO: is @href is an AVT?
+	*		
+	* In all cases @href is in no namespace.
+	*/
+	filename = xsltEvalStaticAttrValueTemplate(style, inst,
+	    (const xmlChar *)"href", NULL, &comp->has_filename);
+    }		
+    if (!comp->has_filename) {
+	goto error;
+    }
+    comp->filename = filename;
+
+error:
+    return ((xsltElemPreCompPtr) comp);
+}
+
+/************************************************************************
+ *									*
+ *		Most of the XSLT-1.0 transformations			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltSortComp:
+ * @style:  the XSLT stylesheet
+ * @inst:  the xslt sort node
+ *
+ * Process the xslt sort node on the source node
+ */
+static void
+xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemSortPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemSortPtr) xsltNewStylePreComp(style, XSLT_FUNC_SORT);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_SORT);
+#endif
+    
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+    comp->stype = xsltEvalStaticAttrValueTemplate(style, inst,
+			 (const xmlChar *)"data-type",
+			 NULL, &comp->has_stype);
+    if (comp->stype != NULL) {
+	if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
+	    comp->number = 0;
+	else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
+	    comp->number = 1;
+	else {
+	    xsltTransformError(NULL, style, inst,
+		 "xsltSortComp: no support for data-type = %s\n", comp->stype);
+	    comp->number = 0; /* use default */
+	    if (style != NULL) style->warnings++;
+	}
+    }
+    comp->order = xsltEvalStaticAttrValueTemplate(style, inst,
+			      (const xmlChar *)"order",
+			      NULL, &comp->has_order);
+    if (comp->order != NULL) {
+	if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
+	    comp->descending = 0;
+	else if (xmlStrEqual(comp->order, (const xmlChar *) "descending"))
+	    comp->descending = 1;
+	else {
+	    xsltTransformError(NULL, style, inst,
+		 "xsltSortComp: invalid value %s for order\n", comp->order);
+	    comp->descending = 0; /* use default */
+	    if (style != NULL) style->warnings++;
+	}
+    }
+    comp->case_order = xsltEvalStaticAttrValueTemplate(style, inst,
+			      (const xmlChar *)"case-order",
+			      NULL, &comp->has_use);
+    if (comp->case_order != NULL) {
+	if (xmlStrEqual(comp->case_order, (const xmlChar *) "upper-first"))
+	    comp->lower_first = 0;
+	else if (xmlStrEqual(comp->case_order, (const xmlChar *) "lower-first"))
+	    comp->lower_first = 1;
+	else {
+	    xsltTransformError(NULL, style, inst,
+		 "xsltSortComp: invalid value %s for order\n", comp->order);
+	    comp->lower_first = 0; /* use default */
+	    if (style != NULL) style->warnings++;
+	}
+    }
+
+    comp->lang = xsltEvalStaticAttrValueTemplate(style, inst,
+				 (const xmlChar *)"lang",
+				 NULL, &comp->has_lang);
+    if (comp->lang != NULL) {
+	comp->locale = xsltNewLocale(comp->lang);
+    }
+    else {
+        comp->locale = (xsltLocale)0;
+    }
+
+    comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE);
+    if (comp->select == NULL) {
+	/*
+	 * The default value of the select attribute is ., which will
+	 * cause the string-value of the current node to be used as
+	 * the sort key.
+	 */
+	comp->select = xmlDictLookup(style->dict, BAD_CAST ".", 1);
+    }
+    comp->comp = xsltXPathCompile(style, comp->select);
+    if (comp->comp == NULL) {
+	xsltTransformError(NULL, style, inst,
+	     "xsltSortComp: could not compile select expression '%s'\n",
+	                 comp->select);
+	if (style != NULL) style->errors++;
+    }
+    if (inst->children != NULL) {
+	xsltTransformError(NULL, style, inst,
+	"xsl:sort : is not empty\n");
+	if (style != NULL) style->errors++;
+    }
+}
+
+/**
+ * xsltCopyComp:
+ * @style:  the XSLT stylesheet
+ * @inst:  the xslt copy node
+ *
+ * Process the xslt copy node on the source node
+ */
+static void
+xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemCopyPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemCopyPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPY);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_COPY);
+#endif
+    
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+
+    comp->use = xsltGetCNsProp(style, inst, (const xmlChar *)"use-attribute-sets",
+				    XSLT_NAMESPACE);
+    if (comp->use == NULL)
+	comp->has_use = 0;
+    else
+	comp->has_use = 1;
+}
+
+#ifdef XSLT_REFACTORED
+    /* Enable if ever needed for xsl:text. */
+#else
+/**
+ * xsltTextComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt text node
+ *
+ * TODO: This function is obsolete, since xsl:text won't
+ *  be compiled, but removed from the tree.
+ *
+ * Process the xslt text node on the source node
+ */
+static void
+xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemTextPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+    const xmlChar *prop;
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemTextPtr) xsltNewStylePreComp(style, XSLT_FUNC_TEXT);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_TEXT);
+#endif    
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+    comp->noescape = 0;
+
+    prop = xsltGetCNsProp(style, inst,
+	    (const xmlChar *)"disable-output-escaping",
+			XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
+	    comp->noescape = 1;
+	} else if (!xmlStrEqual(prop,
+	    (const xmlChar *)"no")){
+	    xsltTransformError(NULL, style, inst,
+		"xsl:text: disable-output-escaping allows only yes or no\n");
+	    if (style != NULL) style->warnings++;
+	}
+    }
+}
+#endif /* else of XSLT_REFACTORED */
+
+/**
+ * xsltElementComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt element node
+ *
+ * Process the xslt element node on the source node
+ */
+static void
+xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemElementPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    /*
+    * <xsl:element
+    *   name = { qname }
+    *   namespace = { uri-reference }
+    *   use-attribute-sets = qnames>
+    *   <!-- Content: template -->
+    * </xsl:element>
+    */
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemElementPtr) xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+    /*
+    * Attribute "name".
+    */
+    /*
+    * TODO: Precompile the AVT. See bug #344894.
+    */
+    comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
+	(const xmlChar *)"name", NULL, &comp->has_name);
+    if (! comp->has_name) {
+	xsltTransformError(NULL, style, inst,
+	    "xsl:element: The attribute 'name' is missing.\n");
+	style->errors++;
+	goto error;
+    }
+    /*
+    * Attribute "namespace".
+    */
+    /*
+    * TODO: Precompile the AVT. See bug #344894.
+    */
+    comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
+	(const xmlChar *)"namespace", NULL, &comp->has_ns);
+    
+    if (comp->name != NULL) {	
+	if (xmlValidateQName(comp->name, 0)) {
+	    xsltTransformError(NULL, style, inst,
+		"xsl:element: The value '%s' of the attribute 'name' is "
+		"not a valid QName.\n", comp->name);
+	    style->errors++;
+	} else {
+	    const xmlChar *prefix = NULL, *name;
+
+	    name = xsltSplitQName(style->dict, comp->name, &prefix);
+	    if (comp->has_ns == 0) {	    
+		xmlNsPtr ns;
+
+		/*
+		* SPEC XSLT 1.0:
+		*  "If the namespace attribute is not present, then the QName is
+		*  expanded into an expanded-name using the namespace declarations
+		*  in effect for the xsl:element element, including any default
+		*  namespace declaration.
+		*/		
+		ns = xmlSearchNs(inst->doc, inst, prefix);
+		if (ns != NULL) {
+		    comp->ns = xmlDictLookup(style->dict, ns->href, -1);
+		    comp->has_ns = 1;
+#ifdef XSLT_REFACTORED
+		    comp->nsPrefix = prefix;
+		    comp->name = name;
+#endif
+		} else if (prefix != NULL) {
+		    xsltTransformError(NULL, style, inst,
+			"xsl:element: The prefixed QName '%s' "
+			"has no namespace binding in scope in the "
+			"stylesheet; this is an error, since the namespace was "
+			"not specified by the instruction itself.\n", comp->name);
+		    style->errors++;
+		}
+	    }	    
+	    if ((prefix != NULL) &&
+		(!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))
+	    {
+		/*
+		* Mark is to be skipped.
+		*/
+		comp->has_name = 0;		
+	    }
+	}
+    }    
+    /*
+    * Attribute "use-attribute-sets",
+    */
+    comp->use = xsltEvalStaticAttrValueTemplate(style, inst,
+		       (const xmlChar *)"use-attribute-sets",
+		       NULL, &comp->has_use);
+
+error:    
+    return;
+}
+
+/**
+ * xsltAttributeComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt attribute node
+ *
+ * Process the xslt attribute node on the source node
+ */
+static void
+xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemAttributePtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    /*
+    * <xsl:attribute
+    *   name = { qname }
+    *   namespace = { uri-reference }>
+    *   <!-- Content: template -->
+    * </xsl:attribute>
+    */
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style,
+	XSLT_FUNC_ATTRIBUTE);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE);
+#endif
+    
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+    /*
+    * Attribute "name".
+    */
+    /*
+    * TODO: Precompile the AVT. See bug #344894.
+    */
+    comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
+				 (const xmlChar *)"name",
+				 NULL, &comp->has_name);
+    if (! comp->has_name) {
+	xsltTransformError(NULL, style, inst,
+	    "XSLT-attribute: The attribute 'name' is missing.\n");
+	style->errors++;
+	return;
+    }    
+    /*
+    * Attribute "namespace".
+    */
+    /*
+    * TODO: Precompile the AVT. See bug #344894.
+    */
+    comp->ns = xsltEvalStaticAttrValueTemplate(style, inst,
+	(const xmlChar *)"namespace",
+	NULL, &comp->has_ns);
+
+    if (comp->name != NULL) {
+	if (xmlValidateQName(comp->name, 0)) {
+	    xsltTransformError(NULL, style, inst,
+		"xsl:attribute: The value '%s' of the attribute 'name' is "
+		"not a valid QName.\n", comp->name);
+	    style->errors++;
+	} else {
+	    const xmlChar *prefix = NULL, *name;
+
+	    name = xsltSplitQName(style->dict, comp->name, &prefix);
+	    if (prefix != NULL) {
+		if (comp->has_ns == 0) {
+		    xmlNsPtr ns;
+
+		    /*
+		    * SPEC XSLT 1.0:
+		    *  "If the namespace attribute is not present, then the
+		    *  QName is expanded into an expanded-name using the
+		    *  namespace declarations in effect for the xsl:element
+		    *  element, including any default namespace declaration.
+		    */	    	    
+		    ns = xmlSearchNs(inst->doc, inst, prefix);
+		    if (ns != NULL) {
+			comp->ns = xmlDictLookup(style->dict, ns->href, -1);
+			comp->has_ns = 1;
+#ifdef XSLT_REFACTORED
+			comp->nsPrefix = prefix;
+			comp->name = name;
+#endif
+		    } else {
+			xsltTransformError(NULL, style, inst,
+			    "xsl:attribute: The prefixed QName '%s' "
+			    "has no namespace binding in scope in the "
+			    "stylesheet; this is an error, since the "
+			    "namespace was not specified by the instruction "
+			    "itself.\n", comp->name);
+			style->errors++;
+		    }
+		}
+		if (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5)) {
+		    /*
+		    * SPEC XSLT 1.0:
+		    *  "It is an error if the string that results from
+		    *  instantiating the attribute value template is not a
+		    *  QName or is the string xmlns. An XSLT processor may
+		    *  signal the error; if it does not signal the error,
+		    *  it must recover by not adding the attribute to the
+		    *  result tree."
+		    *
+		    * Reject a prefix of "xmlns". Mark to be skipped.
+		    */
+		    comp->has_name = 0;
+		    
+#ifdef WITH_XSLT_DEBUG_PARSING
+		    xsltGenericDebug(xsltGenericDebugContext,
+			"xsltAttribute: xmlns prefix forbidden\n");
+#endif		    
+		    return;
+		}
+		
+	    }
+	}	
+    }
+}
+
+/**
+ * xsltCommentComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt comment node
+ *
+ * Process the xslt comment node on the source node
+ */
+static void
+xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemCommentPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemCommentPtr) xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_COMMENT);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+}
+
+/**
+ * xsltProcessingInstructionComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt processing-instruction node
+ *
+ * Process the xslt processing-instruction node on the source node
+ */
+static void
+xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemPIPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemPIPtr) xsltNewStylePreComp(style, XSLT_FUNC_PI);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_PI);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+    comp->name = xsltEvalStaticAttrValueTemplate(style, inst,
+				 (const xmlChar *)"name",
+				 XSLT_NAMESPACE, &comp->has_name);
+}
+
+/**
+ * xsltCopyOfComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt copy-of node
+ *
+ * Process the xslt copy-of node on the source node
+ */
+static void
+xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemCopyOfPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemCopyOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_COPYOF);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+    comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
+	                        XSLT_NAMESPACE);
+    if (comp->select == NULL) {
+	xsltTransformError(NULL, style, inst,
+	     "xsl:copy-of : select is missing\n");
+	if (style != NULL) style->errors++;
+	return;
+    }
+    comp->comp = xsltXPathCompile(style, comp->select);
+    if (comp->comp == NULL) {
+	xsltTransformError(NULL, style, inst,
+	     "xsl:copy-of : could not compile select expression '%s'\n",
+	                 comp->select);
+	if (style != NULL) style->errors++;
+    }
+}
+
+/**
+ * xsltValueOfComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt value-of node
+ *
+ * Process the xslt value-of node on the source node
+ */
+static void
+xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemValueOfPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+    const xmlChar *prop;
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemValueOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+    prop = xsltGetCNsProp(style, inst,
+	    (const xmlChar *)"disable-output-escaping",
+			XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
+	    comp->noescape = 1;
+	} else if (!xmlStrEqual(prop,
+				(const xmlChar *)"no")){
+	    xsltTransformError(NULL, style, inst,
+"xsl:value-of : disable-output-escaping allows only yes or no\n");
+	    if (style != NULL) style->warnings++;
+	}
+    }
+    comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
+	                        XSLT_NAMESPACE);
+    if (comp->select == NULL) {
+	xsltTransformError(NULL, style, inst,
+	     "xsl:value-of : select is missing\n");
+	if (style != NULL) style->errors++;
+	return;
+    }
+    comp->comp = xsltXPathCompile(style, comp->select);
+    if (comp->comp == NULL) {
+	xsltTransformError(NULL, style, inst,
+	     "xsl:value-of : could not compile select expression '%s'\n",
+	                 comp->select);
+	if (style != NULL) style->errors++;
+    }
+}
+
+static void
+xsltGetQNameProperty(xsltStylesheetPtr style, xmlNodePtr inst,
+		     const xmlChar *propName,
+		     int mandatory,
+		     int *hasProp, const xmlChar **nsName,
+		     const xmlChar** localName)
+{
+    const xmlChar *prop;
+
+    if (nsName)
+	*nsName = NULL;
+    if (localName)
+	*localName = NULL;
+    if (hasProp)
+	*hasProp = 0;
+
+    prop = xsltGetCNsProp(style, inst, propName, XSLT_NAMESPACE);
+    if (prop == NULL) {
+	if (mandatory) {
+	    xsltTransformError(NULL, style, inst,
+		"The attribute '%s' is missing.\n", propName);
+	    style->errors++;
+	    return;
+	}
+    } else {
+        const xmlChar *URI;
+
+	if (xmlValidateQName(prop, 0)) {
+	    xsltTransformError(NULL, style, inst,
+		"The value '%s' of the attribute "
+		"'%s' is not a valid QName.\n", prop, propName);
+	    style->errors++;
+	    return;
+	} else {
+	    /*
+	    * @prop will be in the string dict afterwards, @URI not.
+	    */
+	    URI = xsltGetQNameURI2(style, inst, &prop);
+	    if (prop == NULL) {
+		style->errors++;
+	    } else {
+		*localName = prop;
+		if (hasProp)
+		    *hasProp = 1;
+		if (URI != NULL) {
+		    /*
+		    * Fixes bug #308441: Put the ns-name in the dict
+		    * in order to pointer compare names during XPath's
+		    * variable lookup.
+		    */
+		    if (nsName)
+			*nsName = xmlDictLookup(style->dict, URI, -1);
+		    /* comp->has_ns = 1; */
+		}
+	    }
+	}
+    }
+    return;
+}
+
+/**
+ * xsltWithParamComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt with-param node
+ *
+ * Process the xslt with-param node on the source node
+ * Allowed parents: xsl:call-template, xsl:apply-templates.
+ * <xsl:with-param
+ *  name = qname
+ *  select = expression>
+ *  <!-- Content: template -->
+ * </xsl:with-param>
+ */
+static void
+xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemWithParamPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemWithParamPtr) xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+    /*
+    * Attribute "name".
+    */
+    xsltGetQNameProperty(style, inst, BAD_CAST "name",
+	1, &(comp->has_name), &(comp->ns), &(comp->name));
+    if (comp->ns)
+	comp->has_ns = 1;
+    /*
+    * Attribute "select".
+    */
+    comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
+	                        XSLT_NAMESPACE);
+    if (comp->select != NULL) {
+	comp->comp = xsltXPathCompile(style, comp->select);
+	if (comp->comp == NULL) {
+	    xsltTransformError(NULL, style, inst,
+		 "XSLT-with-param: Failed to compile select "
+		 "expression '%s'\n", comp->select);
+	    style->errors++;
+	}
+	if (inst->children != NULL) {
+	    xsltTransformError(NULL, style, inst,
+		"XSLT-with-param: The content should be empty since "
+		"the attribute select is present.\n");
+	    style->warnings++;
+	}
+    }
+}
+
+/**
+ * xsltNumberComp:
+ * @style: an XSLT compiled stylesheet
+ * @cur:   the xslt number node
+ *
+ * Process the xslt number node on the source node
+ */
+static void
+xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemNumberPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+    const xmlChar *prop;
+
+    if ((style == NULL) || (cur == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemNumberPtr) xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_NUMBER);
+#endif
+
+    if (comp == NULL)
+	return;
+    cur->psvi = comp;
+
+    if ((style == NULL) || (cur == NULL))
+	return;
+
+    comp->numdata.doc = cur->doc;
+    comp->numdata.node = cur;
+    comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value",
+	                                XSLT_NAMESPACE);
+    
+    prop = xsltEvalStaticAttrValueTemplate(style, cur,
+			 (const xmlChar *)"format",
+			 XSLT_NAMESPACE, &comp->numdata.has_format);
+    if (comp->numdata.has_format == 0) {
+	comp->numdata.format = xmlDictLookup(style->dict, BAD_CAST "" , 0);
+    } else {
+	comp->numdata.format = prop;
+    }
+
+    comp->numdata.count = xsltGetCNsProp(style, cur, (const xmlChar *)"count",
+					XSLT_NAMESPACE);
+    comp->numdata.from = xsltGetCNsProp(style, cur, (const xmlChar *)"from",
+					XSLT_NAMESPACE);
+    
+    prop = xsltGetCNsProp(style, cur, (const xmlChar *)"level", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (xmlStrEqual(prop, BAD_CAST("single")) ||
+	    xmlStrEqual(prop, BAD_CAST("multiple")) ||
+	    xmlStrEqual(prop, BAD_CAST("any"))) {
+	    comp->numdata.level = prop;
+	} else {
+	    xsltTransformError(NULL, style, cur,
+			 "xsl:number : invalid value %s for level\n", prop);
+	    if (style != NULL) style->warnings++;
+	}
+    }
+    
+    prop = xsltGetCNsProp(style, cur, (const xmlChar *)"lang", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	    xsltTransformError(NULL, style, cur,
+		 "xsl:number : lang attribute not implemented\n");
+	XSLT_TODO; /* xsl:number lang attribute */
+    }
+    
+    prop = xsltGetCNsProp(style, cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) {
+	    xsltTransformError(NULL, style, cur,
+		 "xsl:number : letter-value 'alphabetic' not implemented\n");
+	    if (style != NULL) style->warnings++;
+	    XSLT_TODO; /* xsl:number letter-value attribute alphabetic */
+	} else if (xmlStrEqual(prop, BAD_CAST("traditional"))) {
+	    xsltTransformError(NULL, style, cur,
+		 "xsl:number : letter-value 'traditional' not implemented\n");
+	    if (style != NULL) style->warnings++;
+	    XSLT_TODO; /* xsl:number letter-value attribute traditional */
+	} else {
+	    xsltTransformError(NULL, style, cur,
+		     "xsl:number : invalid value %s for letter-value\n", prop);
+	    if (style != NULL) style->warnings++;
+	}
+    }
+    
+    prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-separator",
+	                XSLT_NAMESPACE);
+    if (prop != NULL) {
+        comp->numdata.groupingCharacterLen = xmlStrlen(prop);
+	comp->numdata.groupingCharacter =
+	    xsltGetUTF8Char(prop, &(comp->numdata.groupingCharacterLen));
+    }
+    
+    prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup);
+    } else {
+	comp->numdata.groupingCharacter = 0;
+    }
+
+    /* Set default values */
+    if (comp->numdata.value == NULL) {
+	if (comp->numdata.level == NULL) {
+	    comp->numdata.level = xmlDictLookup(style->dict,
+	                                        BAD_CAST"single", 6);
+	}
+    }
+    
+}
+
+/**
+ * xsltApplyImportsComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt apply-imports node
+ *
+ * Process the xslt apply-imports node on the source node
+ */
+static void
+xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemApplyImportsPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemApplyImportsPtr) xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+}
+
+/**
+ * xsltCallTemplateComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt call-template node
+ *
+ * Process the xslt call-template node on the source node
+ */
+static void
+xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemCallTemplatePtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemCallTemplatePtr)
+	xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+    /*
+     * Attribute "name".
+     */
+    xsltGetQNameProperty(style, inst, BAD_CAST "name",
+	1, &(comp->has_name), &(comp->ns), &(comp->name));
+    if (comp->ns)
+	comp->has_ns = 1;
+}
+
+/**
+ * xsltApplyTemplatesComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the apply-templates node
+ *
+ * Process the apply-templates node on the source node
+ */
+static void
+xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemApplyTemplatesPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemApplyTemplatesPtr)
+	xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+    /*
+     * Attribute "mode".
+     */
+    xsltGetQNameProperty(style, inst, BAD_CAST "mode",
+	0, NULL, &(comp->modeURI), &(comp->mode));
+    /*
+    * Attribute "select".
+    */
+    comp->select = xsltGetCNsProp(style, inst, BAD_CAST "select",
+	XSLT_NAMESPACE);
+    if (comp->select != NULL) {
+	comp->comp = xsltXPathCompile(style, comp->select);
+	if (comp->comp == NULL) {
+	    xsltTransformError(NULL, style, inst,
+		"XSLT-apply-templates: could not compile select "
+		"expression '%s'\n", comp->select);
+	     style->errors++;
+	}
+    }
+    /* TODO: handle (or skip) the xsl:sort and xsl:with-param */
+}
+
+/**
+ * xsltChooseComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt choose node
+ *
+ * Process the xslt choose node on the source node
+ */
+static void
+xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemChoosePtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemChoosePtr)
+	xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+}
+
+/**
+ * xsltIfComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt if node
+ *
+ * Process the xslt if node on the source node
+ */
+static void
+xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemIfPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemIfPtr)
+	xsltNewStylePreComp(style, XSLT_FUNC_IF);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_IF);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+    comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE);
+    if (comp->test == NULL) {
+	xsltTransformError(NULL, style, inst,
+	     "xsl:if : test is not defined\n");
+	if (style != NULL) style->errors++;
+	return;
+    }
+    comp->comp = xsltXPathCompile(style, comp->test);
+    if (comp->comp == NULL) {
+	xsltTransformError(NULL, style, inst,
+	     "xsl:if : could not compile test expression '%s'\n",
+	                 comp->test);
+	if (style != NULL) style->errors++;
+    }
+}
+
+/**
+ * xsltWhenComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt if node
+ *
+ * Process the xslt if node on the source node
+ */
+static void
+xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemWhenPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemWhenPtr)
+	xsltNewStylePreComp(style, XSLT_FUNC_WHEN);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_WHEN);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+    comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE);
+    if (comp->test == NULL) {
+	xsltTransformError(NULL, style, inst,
+	     "xsl:when : test is not defined\n");
+	if (style != NULL) style->errors++;
+	return;
+    }
+    comp->comp = xsltXPathCompile(style, comp->test);
+    if (comp->comp == NULL) {
+	xsltTransformError(NULL, style, inst,
+	     "xsl:when : could not compile test expression '%s'\n",
+	                 comp->test);
+	if (style != NULL) style->errors++;
+    }
+}
+
+/**
+ * xsltForEachComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt for-each node
+ *
+ * Process the xslt for-each node on the source node
+ */
+static void
+xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemForEachPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemForEachPtr)
+	xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_FOREACH);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+    comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
+	                        XSLT_NAMESPACE);
+    if (comp->select == NULL) {
+	xsltTransformError(NULL, style, inst,
+		"xsl:for-each : select is missing\n");
+	if (style != NULL) style->errors++;
+    } else {
+	comp->comp = xsltXPathCompile(style, comp->select);
+	if (comp->comp == NULL) {
+	    xsltTransformError(NULL, style, inst,
+     "xsl:for-each : could not compile select expression '%s'\n",
+			     comp->select);
+	    if (style != NULL) style->errors++;
+	}
+    }
+    /* TODO: handle and skip the xsl:sort */
+}
+
+/**
+ * xsltVariableComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt variable node
+ *
+ * Process the xslt variable node on the source node
+ */
+static void
+xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemVariablePtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemVariablePtr)
+	xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE);
+#endif
+
+    if (comp == NULL)
+	return;
+
+    inst->psvi = comp;
+    comp->inst = inst;
+    /*
+     * The full template resolution can be done statically
+     */
+
+    /*
+    * Attribute "name".
+    */
+    xsltGetQNameProperty(style, inst, BAD_CAST "name",
+	1, &(comp->has_name), &(comp->ns), &(comp->name));
+    if (comp->ns)
+	comp->has_ns = 1;    
+    /*
+    * Attribute "select".
+    */
+    comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
+	                        XSLT_NAMESPACE);
+    if (comp->select != NULL) {
+	comp->comp = xsltXPathCompile(style, comp->select);
+	if (comp->comp == NULL) {
+	    xsltTransformError(NULL, style, inst,
+		"XSLT-variable: Failed to compile the XPath expression '%s'.\n",
+		comp->select);
+	    style->errors++;
+	}
+	if (inst->children != NULL) {
+	    xsltTransformError(NULL, style, inst,
+		"XSLT-variable: The must be no child nodes, since the "
+		"attribute 'select' was specified.\n");
+	    style->errors++;
+	}
+    }
+}
+
+/**
+ * xsltParamComp:
+ * @style: an XSLT compiled stylesheet
+ * @inst:  the xslt param node
+ *
+ * Process the xslt param node on the source node
+ */
+static void
+xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemParamPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((style == NULL) || (inst == NULL))
+	return;
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleItemParamPtr)
+	xsltNewStylePreComp(style, XSLT_FUNC_PARAM);
+#else
+    comp = xsltNewStylePreComp(style, XSLT_FUNC_PARAM);
+#endif
+
+    if (comp == NULL)
+	return;
+    inst->psvi = comp;
+    comp->inst = inst;
+
+    /*
+     * Attribute "name".
+     */
+    xsltGetQNameProperty(style, inst, BAD_CAST "name",
+	1, &(comp->has_name), &(comp->ns), &(comp->name));
+    if (comp->ns)
+	comp->has_ns = 1;
+    /*
+    * Attribute "select".
+    */
+    comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
+	                        XSLT_NAMESPACE);
+    if (comp->select != NULL) {
+	comp->comp = xsltXPathCompile(style, comp->select);
+	if (comp->comp == NULL) {
+	    xsltTransformError(NULL, style, inst,
+		"XSLT-param: could not compile select expression '%s'.\n",
+		comp->select);
+	    style->errors++;
+	}
+	if (inst->children != NULL) {
+	    xsltTransformError(NULL, style, inst,
+		"XSLT-param: The content should be empty since the "
+		"attribute 'select' is present.\n");
+	    style->warnings++;
+	}
+    }
+}
+
+/************************************************************************
+ *									*
+ *		    Generic interface					*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltFreeStylePreComps:
+ * @style:  an XSLT transformation context
+ *
+ * Free up the memory allocated by all precomputed blocks
+ */
+void
+xsltFreeStylePreComps(xsltStylesheetPtr style) {
+    xsltElemPreCompPtr cur, next;
+
+    if (style == NULL)
+	return;        
+    
+    cur = style->preComps;
+    while (cur != NULL) {
+	next = cur->next;		
+	if (cur->type == XSLT_FUNC_EXTENSION)
+	    cur->free(cur);
+	else
+	    xsltFreeStylePreComp((xsltStylePreCompPtr) cur);
+	cur = next;
+    }
+}
+
+#ifdef XSLT_REFACTORED
+
+/**
+ * xsltStylePreCompute:
+ * @style:  the XSLT stylesheet
+ * @node:  the element in the XSLT namespace
+ *
+ * Precompute an XSLT element.
+ * This expects the type of the element to be already
+ * set in style->compCtxt->inode->type;
+ */
+void
+xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr node) {
+    /*    
+    * The xsltXSLTElemMarker marker was set beforehand by
+    *  the parsing mechanism for all elements in the XSLT namespace.
+    */
+    if (style == NULL) {
+	if (node != NULL)
+	    node->psvi = NULL;
+	return;
+    }
+    if (node == NULL)
+	return;
+    if (! IS_XSLT_ELEM_FAST(node))
+	return;
+
+    node->psvi = NULL;
+    if (XSLT_CCTXT(style)->inode->type != 0) {
+	switch (XSLT_CCTXT(style)->inode->type) {
+	    case XSLT_FUNC_APPLYTEMPLATES:
+		xsltApplyTemplatesComp(style, node);
+		break;
+	    case XSLT_FUNC_WITHPARAM:			   
+		xsltWithParamComp(style, node);
+		break;
+	    case XSLT_FUNC_VALUEOF:	    
+		xsltValueOfComp(style, node);
+		break;
+	    case XSLT_FUNC_COPY:	    
+		xsltCopyComp(style, node);
+		break;
+	    case XSLT_FUNC_COPYOF:
+		xsltCopyOfComp(style, node);
+		break;
+	    case XSLT_FUNC_IF:	    
+		xsltIfComp(style, node);
+		break;
+	    case XSLT_FUNC_CHOOSE:	    
+		xsltChooseComp(style, node);
+		break;
+	    case XSLT_FUNC_WHEN:	    
+		xsltWhenComp(style, node);
+		break;
+	    case XSLT_FUNC_OTHERWISE:	    
+		/* NOP yet */
+		return;
+	    case XSLT_FUNC_FOREACH:	    
+		xsltForEachComp(style, node);
+		break;
+	    case XSLT_FUNC_APPLYIMPORTS:	    
+		xsltApplyImportsComp(style, node);
+		break;
+	    case XSLT_FUNC_ATTRIBUTE:	    
+		xsltAttributeComp(style, node);
+		break;
+	    case XSLT_FUNC_ELEMENT:	    
+		xsltElementComp(style, node);
+		break;
+	    case XSLT_FUNC_SORT:	    
+		xsltSortComp(style, node);
+		break;
+	    case XSLT_FUNC_COMMENT:	    
+		xsltCommentComp(style, node);
+		break;
+	    case XSLT_FUNC_NUMBER:	    
+		xsltNumberComp(style, node);
+		break;
+	    case XSLT_FUNC_PI:	    
+		xsltProcessingInstructionComp(style, node);
+		break;
+	    case XSLT_FUNC_CALLTEMPLATE:	    
+		xsltCallTemplateComp(style, node);
+		break;
+	    case XSLT_FUNC_PARAM:	    
+		xsltParamComp(style, node);
+		break;
+	    case XSLT_FUNC_VARIABLE:	    
+		xsltVariableComp(style, node);
+		break;
+	    case XSLT_FUNC_FALLBACK:	    
+		/* NOP yet */
+		return;
+	    case XSLT_FUNC_DOCUMENT:	    
+		/* The extra one */
+		node->psvi = (void *) xsltDocumentComp(style, node,
+		    (xsltTransformFunction) xsltDocumentElem);
+		break;
+	    case XSLT_FUNC_MESSAGE:
+		/* NOP yet */
+		return;
+	    default:
+		/*
+		* NOTE that xsl:text, xsl:template, xsl:stylesheet,
+		*  xsl:transform, xsl:import, xsl:include are not expected
+		*  to be handed over to this function.
+		*/
+		xsltTransformError(NULL, style, node,
+		    "Internal error: (xsltStylePreCompute) cannot handle "
+		    "the XSLT element '%s'.\n", node->name);
+		style->errors++;
+		return;
+	}
+    } else {
+	/*
+	* Fallback to string comparison.
+	*/	
+	if (IS_XSLT_NAME(node, "apply-templates")) {
+	    xsltApplyTemplatesComp(style, node);
+	} else if (IS_XSLT_NAME(node, "with-param")) {
+	    xsltWithParamComp(style, node);
+	} else if (IS_XSLT_NAME(node, "value-of")) {
+	    xsltValueOfComp(style, node);
+	} else if (IS_XSLT_NAME(node, "copy")) {
+	    xsltCopyComp(style, node);
+	} else if (IS_XSLT_NAME(node, "copy-of")) {
+	    xsltCopyOfComp(style, node);
+	} else if (IS_XSLT_NAME(node, "if")) {
+	    xsltIfComp(style, node);
+	} else if (IS_XSLT_NAME(node, "choose")) {
+	    xsltChooseComp(style, node);
+	} else if (IS_XSLT_NAME(node, "when")) {
+	    xsltWhenComp(style, node);	
+	} else if (IS_XSLT_NAME(node, "otherwise")) {
+	    /* NOP yet */
+	    return;
+	} else if (IS_XSLT_NAME(node, "for-each")) {
+	    xsltForEachComp(style, node);
+	} else if (IS_XSLT_NAME(node, "apply-imports")) {
+	    xsltApplyImportsComp(style, node);
+	} else if (IS_XSLT_NAME(node, "attribute")) {
+	    xsltAttributeComp(style, node);
+	} else if (IS_XSLT_NAME(node, "element")) {
+	    xsltElementComp(style, node);
+	} else if (IS_XSLT_NAME(node, "sort")) {
+	    xsltSortComp(style, node);
+	} else if (IS_XSLT_NAME(node, "comment")) {
+	    xsltCommentComp(style, node);
+	} else if (IS_XSLT_NAME(node, "number")) {
+	    xsltNumberComp(style, node);
+	} else if (IS_XSLT_NAME(node, "processing-instruction")) {
+	    xsltProcessingInstructionComp(style, node);
+	} else if (IS_XSLT_NAME(node, "call-template")) {
+	    xsltCallTemplateComp(style, node);
+	} else if (IS_XSLT_NAME(node, "param")) {
+	    xsltParamComp(style, node);
+	} else if (IS_XSLT_NAME(node, "variable")) {
+	    xsltVariableComp(style, node);
+	} else if (IS_XSLT_NAME(node, "fallback")) {
+	    /* NOP yet */
+	    return;
+	} else if (IS_XSLT_NAME(node, "document")) {
+	    /* The extra one */
+	    node->psvi = (void *) xsltDocumentComp(style, node,
+		(xsltTransformFunction) xsltDocumentElem);	
+	} else if (IS_XSLT_NAME(node, "output")) {
+	    /* Top-level */
+	    return;
+	} else if (IS_XSLT_NAME(node, "preserve-space")) {
+	    /* Top-level */
+	    return;
+	} else if (IS_XSLT_NAME(node, "strip-space")) {
+	    /* Top-level */
+	    return;	
+	} else if (IS_XSLT_NAME(node, "key")) {
+	    /* Top-level */
+	    return;
+	} else if (IS_XSLT_NAME(node, "message")) {
+	    return;
+	} else if (IS_XSLT_NAME(node, "attribute-set")) {
+	    /* Top-level */
+	    return;
+	} else if (IS_XSLT_NAME(node, "namespace-alias")) {
+	    /* Top-level */
+	    return;
+	} else if (IS_XSLT_NAME(node, "decimal-format")) {
+	    /* Top-level */
+	    return;
+	} else if (IS_XSLT_NAME(node, "include")) {
+	    /* Top-level */	    	    
+	} else {
+	    /*
+	    * NOTE that xsl:text, xsl:template, xsl:stylesheet,
+	    *  xsl:transform, xsl:import, xsl:include are not expected
+	    *  to be handed over to this function.
+	    */
+	    xsltTransformError(NULL, style, node,
+		"Internal error: (xsltStylePreCompute) cannot handle "
+		"the XSLT element '%s'.\n", node->name);
+		style->errors++;
+	    return;
+	}	
+    }
+    /*
+    * Assign the current list of in-scope namespaces to the
+    * item. This is needed for XPath expressions.
+    */
+    if (node->psvi != NULL) {
+	((xsltStylePreCompPtr) node->psvi)->inScopeNs =
+	    XSLT_CCTXT(style)->inode->inScopeNs;
+    }
+}
+
+#else
+
+/**
+ * xsltStylePreCompute:
+ * @style:  the XSLT stylesheet
+ * @inst:  the instruction in the stylesheet
+ *
+ * Precompute an XSLT stylesheet element
+ */
+void
+xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) {
+    /*
+    * URGENT TODO: Normally inst->psvi Should never be reserved here,
+    *   BUT: since if we include the same stylesheet from
+    *   multiple imports, then the stylesheet will be parsed
+    *   again. We simply must not try to compute the stylesheet again.
+    * TODO: Get to the point where we don't need to query the
+    *   namespace- and local-name of the node, but can evaluate this
+    *   using cctxt->style->inode->category;
+    */
+    if (inst->psvi != NULL)
+	return;
+
+    if (IS_XSLT_ELEM(inst)) {
+	xsltStylePreCompPtr cur;
+
+	if (IS_XSLT_NAME(inst, "apply-templates")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltApplyTemplatesComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "with-param")) {
+	    xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",
+	                           BAD_CAST "call-template");
+	    xsltWithParamComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "value-of")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltValueOfComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "copy")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltCopyComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "copy-of")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltCopyOfComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "if")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltIfComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "when")) {
+	    xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);
+	    xsltWhenComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "choose")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltChooseComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "for-each")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltForEachComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "apply-imports")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltApplyImportsComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "attribute")) {
+	    xmlNodePtr parent = inst->parent;
+
+	    if ((parent == NULL) || (parent->ns == NULL) ||
+		((parent->ns != inst->ns) &&
+		 (!xmlStrEqual(parent->ns->href, inst->ns->href))) ||
+		(!xmlStrEqual(parent->name, BAD_CAST "attribute-set"))) {
+		xsltCheckInstructionElement(style, inst);
+	    }
+	    xsltAttributeComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "element")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltElementComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "text")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltTextComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "sort")) {
+	    xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",
+	                           BAD_CAST "for-each");
+	    xsltSortComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "comment")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltCommentComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "number")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltNumberComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "processing-instruction")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltProcessingInstructionComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "call-template")) {
+	    xsltCheckInstructionElement(style, inst);
+	    xsltCallTemplateComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "param")) {	   
+	    if (xsltCheckTopLevelElement(style, inst, 0) == 0)
+	        xsltCheckInstructionElement(style, inst);
+	    xsltParamComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "variable")) {
+	    if (xsltCheckTopLevelElement(style, inst, 0) == 0)
+	        xsltCheckInstructionElement(style, inst);
+	    xsltVariableComp(style, inst);
+	} else if (IS_XSLT_NAME(inst, "otherwise")) {
+	    xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);
+	    xsltCheckInstructionElement(style, inst);
+	    return;
+	} else if (IS_XSLT_NAME(inst, "template")) {
+	    xsltCheckTopLevelElement(style, inst, 1);
+	    return;
+	} else if (IS_XSLT_NAME(inst, "output")) {
+	    xsltCheckTopLevelElement(style, inst, 1);
+	    return;
+	} else if (IS_XSLT_NAME(inst, "preserve-space")) {
+	    xsltCheckTopLevelElement(style, inst, 1);
+	    return;
+	} else if (IS_XSLT_NAME(inst, "strip-space")) {
+	    xsltCheckTopLevelElement(style, inst, 1);
+	    return;
+	} else if ((IS_XSLT_NAME(inst, "stylesheet")) ||
+	           (IS_XSLT_NAME(inst, "transform"))) {
+	    xmlNodePtr parent = inst->parent;
+
+	    if ((parent == NULL) || (parent->type != XML_DOCUMENT_NODE)) {
+		xsltTransformError(NULL, style, inst,
+		    "element %s only allowed only as root element\n",
+				   inst->name);
+		style->errors++;
+	    }
+	    return;
+	} else if (IS_XSLT_NAME(inst, "key")) {
+	    xsltCheckTopLevelElement(style, inst, 1);
+	    return;
+	} else if (IS_XSLT_NAME(inst, "message")) {
+	    xsltCheckInstructionElement(style, inst);
+	    return;
+	} else if (IS_XSLT_NAME(inst, "attribute-set")) {
+	    xsltCheckTopLevelElement(style, inst, 1);
+	    return;
+	} else if (IS_XSLT_NAME(inst, "namespace-alias")) {
+	    xsltCheckTopLevelElement(style, inst, 1);
+	    return;
+	} else if (IS_XSLT_NAME(inst, "include")) {
+	    xsltCheckTopLevelElement(style, inst, 1);
+	    return;
+	} else if (IS_XSLT_NAME(inst, "import")) {
+	    xsltCheckTopLevelElement(style, inst, 1);
+	    return;
+	} else if (IS_XSLT_NAME(inst, "decimal-format")) {
+	    xsltCheckTopLevelElement(style, inst, 1);
+	    return;
+	} else if (IS_XSLT_NAME(inst, "fallback")) {
+	    xsltCheckInstructionElement(style, inst);
+	    return;
+	} else if (IS_XSLT_NAME(inst, "document")) {
+	    xsltCheckInstructionElement(style, inst);
+	    inst->psvi = (void *) xsltDocumentComp(style, inst,
+				(xsltTransformFunction) xsltDocumentElem);
+	} else {
+	    xsltTransformError(NULL, style, inst,
+		 "xsltStylePreCompute: unknown xsl:%s\n", inst->name);
+	    if (style != NULL) style->warnings++;
+	}
+	
+	cur = (xsltStylePreCompPtr) inst->psvi;
+	/*
+	* A ns-list is build for every XSLT item in the
+	* node-tree. This is needed for XPath expressions.
+	*/
+	if (cur != NULL) {
+	    int i = 0;
+
+	    cur->nsList = xmlGetNsList(inst->doc, inst);
+            if (cur->nsList != NULL) {
+		while (cur->nsList[i] != NULL)
+		    i++;
+	    }
+	    cur->nsNr = i;
+	}
+    } else {
+	inst->psvi =
+	    (void *) xsltPreComputeExtModuleElement(style, inst);
+
+	/*
+	 * Unknown element, maybe registered at the context
+	 * level. Mark it for later recognition.
+	 */
+	if (inst->psvi == NULL)
+	    inst->psvi = (void *) xsltExtMarker;
+    }
+}
+#endif /* XSLT_REFACTORED */
diff --git a/libxslt/preproc.h b/libxslt/preproc.h
new file mode 100644
index 0000000..f67b389
--- /dev/null
+++ b/libxslt/preproc.h
@@ -0,0 +1,43 @@
+/*
+ * Summary: precomputing stylesheets
+ * Description: this is the compilation phase, where most of the
+ *              stylesheet is "compiled" into faster to use data.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_PRECOMP_H__
+#define __XML_XSLT_PRECOMP_H__
+
+#include <libxml/tree.h>
+#include "xsltexports.h"
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Interfaces
+ */
+extern const xmlChar *xsltExtMarker;
+
+XSLTPUBFUN xsltElemPreCompPtr XSLTCALL 
+		xsltDocumentComp	(xsltStylesheetPtr style,
+					 xmlNodePtr inst,
+					 xsltTransformFunction function);
+
+XSLTPUBFUN void XSLTCALL		
+		xsltStylePreCompute	(xsltStylesheetPtr style,
+					 xmlNodePtr inst);
+XSLTPUBFUN void XSLTCALL		
+		xsltFreeStylePreComps	(xsltStylesheetPtr style);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_PRECOMP_H__ */
+
diff --git a/libxslt/security.c b/libxslt/security.c
new file mode 100644
index 0000000..b766cf7
--- /dev/null
+++ b/libxslt/security.c
@@ -0,0 +1,480 @@
+/*
+ * security.c: Implementation of the XSLT security framework
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+#ifdef HAVE_NAN_H
+#include <nan.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#if defined(WIN32) && !defined(__CYGWIN__)
+#include <windows.h>
+#ifndef INVALID_FILE_ATTRIBUTES
+#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+#endif
+#endif
+
+#ifndef HAVE_STAT
+#  ifdef HAVE__STAT
+     /* MS C library seems to define stat and _stat. The definition
+      *         is identical. Still, mapping them to each other causes a warning. */
+#    ifndef _MSC_VER
+#      define stat(x,y) _stat(x,y)
+#    endif
+#    define HAVE_STAT
+#  endif
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/uri.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "extensions.h"
+#include "security.h"
+
+
+struct _xsltSecurityPrefs {
+    xsltSecurityCheck readFile;
+    xsltSecurityCheck createFile;
+    xsltSecurityCheck createDir;
+    xsltSecurityCheck readNet;
+    xsltSecurityCheck writeNet;
+};
+
+static xsltSecurityPrefsPtr xsltDefaultSecurityPrefs = NULL;
+
+/************************************************************************
+ *									*
+ *			Module interfaces				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltNewSecurityPrefs:
+ *
+ * Create a new security preference block
+ *
+ * Returns a pointer to the new block or NULL in case of error
+ */
+xsltSecurityPrefsPtr
+xsltNewSecurityPrefs(void) {
+    xsltSecurityPrefsPtr ret;
+
+    xsltInitGlobals();
+
+    ret = (xsltSecurityPrefsPtr) xmlMalloc(sizeof(xsltSecurityPrefs));
+    if (ret == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+		"xsltNewSecurityPrefs : malloc failed\n");
+	return(NULL);
+    }
+    memset(ret, 0, sizeof(xsltSecurityPrefs));
+    return(ret);
+}
+
+/**
+ * xsltFreeSecurityPrefs:
+ * @sec:  the security block to free
+ *
+ * Free up a security preference block
+ */
+void
+xsltFreeSecurityPrefs(xsltSecurityPrefsPtr sec) {
+    if (sec == NULL)
+	return;
+    xmlFree(sec);
+}
+
+/**
+ * xsltSetSecurityPrefs:
+ * @sec:  the security block to update
+ * @option:  the option to update
+ * @func:  the user callback to use for this option
+ *
+ * Update the security option to use the new callback checking function
+ *
+ * Returns -1 in case of error, 0 otherwise
+ */
+int
+xsltSetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option,
+                     xsltSecurityCheck func) {
+    xsltInitGlobals();
+    if (sec == NULL)
+	return(-1);
+    switch (option) {
+        case XSLT_SECPREF_READ_FILE:
+            sec->readFile = func; return(0);
+        case XSLT_SECPREF_WRITE_FILE:
+            sec->createFile = func; return(0);
+        case XSLT_SECPREF_CREATE_DIRECTORY:
+            sec->createDir = func; return(0);
+        case XSLT_SECPREF_READ_NETWORK:
+            sec->readNet = func; return(0);
+        case XSLT_SECPREF_WRITE_NETWORK:
+            sec->writeNet = func; return(0);
+    }
+    return(-1);
+}
+
+/**
+ * xsltGetSecurityPrefs:
+ * @sec:  the security block to update
+ * @option:  the option to lookup
+ *
+ * Lookup the security option to get the callback checking function
+ *
+ * Returns NULL if not found, the function otherwise
+ */
+xsltSecurityCheck
+xsltGetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option) {
+    if (sec == NULL)
+	return(NULL);
+    switch (option) {
+        case XSLT_SECPREF_READ_FILE:
+            return(sec->readFile);
+        case XSLT_SECPREF_WRITE_FILE:
+            return(sec->createFile);
+        case XSLT_SECPREF_CREATE_DIRECTORY:
+            return(sec->createDir);
+        case XSLT_SECPREF_READ_NETWORK:
+            return(sec->readNet);
+        case XSLT_SECPREF_WRITE_NETWORK:
+            return(sec->writeNet);
+    }
+    return(NULL);
+}
+
+/**
+ * xsltSetDefaultSecurityPrefs:
+ * @sec:  the security block to use
+ *
+ * Set the default security preference application-wide
+ */
+void
+xsltSetDefaultSecurityPrefs(xsltSecurityPrefsPtr sec) {
+    
+    xsltDefaultSecurityPrefs = sec;
+}
+
+/**
+ * xsltGetDefaultSecurityPrefs:
+ *
+ * Get the default security preference application-wide
+ *
+ * Returns the current xsltSecurityPrefsPtr in use or NULL if none
+ */
+xsltSecurityPrefsPtr
+xsltGetDefaultSecurityPrefs(void) {
+    return(xsltDefaultSecurityPrefs);
+}
+
+/**
+ * xsltSetCtxtSecurityPrefs:
+ * @sec:  the security block to use
+ * @ctxt:  an XSLT transformation context
+ *
+ * Set the security preference for a specific transformation
+ *
+ * Returns -1 in case of error, 0 otherwise
+ */
+int                    
+xsltSetCtxtSecurityPrefs(xsltSecurityPrefsPtr sec,
+	                 xsltTransformContextPtr ctxt) {
+    if (ctxt == NULL)
+	return(-1);
+    ctxt->sec = (void *) sec;
+    return(0);
+}
+
+
+/**
+ * xsltSecurityAllow:
+ * @sec:  the security block to use
+ * @ctxt:  an XSLT transformation context
+ * @value:  unused
+ *
+ * Function used to always allow an operation
+ *
+ * Returns 1 always
+ */
+int
+xsltSecurityAllow(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED,
+	          xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
+		  const char *value ATTRIBUTE_UNUSED) {
+    return(1);
+}
+
+/**
+ * xsltSecurityForbid:
+ * @sec:  the security block to use
+ * @ctxt:  an XSLT transformation context
+ * @value:  unused
+ *
+ * Function used to always forbid an operation
+ *
+ * Returns 0 always
+ */
+int
+xsltSecurityForbid(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED,
+	          xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
+		  const char *value ATTRIBUTE_UNUSED) {
+    return(0);
+}
+
+/************************************************************************
+ *									*
+ *			Internal interfaces				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltCheckFilename
+ * @path:  the path to check
+ *
+ * function checks to see if @path is a valid source
+ * (file, socket...) for XML.
+ *
+ * TODO: remove at some point !!!
+ * Local copy of xmlCheckFilename to avoid a hard dependency on
+ * a new version of libxml2 
+ *
+ * if stat is not available on the target machine,
+ * returns 1.  if stat fails, returns 0 (if calling
+ * stat on the filename fails, it can't be right).
+ * if stat succeeds and the file is a directory,
+ * returns 2.  otherwise returns 1.
+ */
+
+static int
+xsltCheckFilename (const char *path)
+{
+#ifdef HAVE_STAT
+    struct stat stat_buffer;
+#if defined(WIN32) && !defined(__CYGWIN__)
+    DWORD dwAttrs;
+
+    dwAttrs = GetFileAttributes(path); 
+    if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
+        if (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) {
+            return 2;
+		}
+    }
+#endif
+
+    if (stat(path, &stat_buffer) == -1)
+        return 0;
+
+#ifdef S_ISDIR
+    if (S_ISDIR(stat_buffer.st_mode)) {
+        return 2;
+    }
+#endif
+#endif
+    return 1;
+}
+
+static int
+xsltCheckWritePath(xsltSecurityPrefsPtr sec,
+		   xsltTransformContextPtr ctxt,
+		   const char *path)
+{
+    int ret;
+    xsltSecurityCheck check;
+    char *directory;
+
+    check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_FILE);
+    if (check != NULL) {
+	ret = check(sec, ctxt, path);
+	if (ret == 0) {
+	    xsltTransformError(ctxt, NULL, NULL,
+			       "File write for %s refused\n", path);
+	    return(0);
+	}
+    }
+
+    directory = xmlParserGetDirectory (path);
+
+    if (directory != NULL) {
+	ret = xsltCheckFilename(directory);
+	if (ret == 0) {
+	    /*
+	     * The directory doesn't exist check for creation
+	     */
+	    check = xsltGetSecurityPrefs(sec,
+					 XSLT_SECPREF_CREATE_DIRECTORY);
+	    if (check != NULL) {
+		ret = check(sec, ctxt, directory);
+		if (ret == 0) {
+		    xsltTransformError(ctxt, NULL, NULL,
+				       "Directory creation for %s refused\n",
+				       path);
+		    xmlFree(directory);
+		    return(0);
+		}
+	    }
+	    ret = xsltCheckWritePath(sec, ctxt, directory);
+	    if (ret == 1)
+		ret = mkdir(directory, 0755);
+	}
+	xmlFree(directory);
+	if (ret < 0)
+	    return(ret);
+    }
+
+    return(1);
+}
+
+/**
+ * xsltCheckWrite:
+ * @sec:  the security options
+ * @ctxt:  an XSLT transformation context
+ * @URL:  the resource to be written
+ *
+ * Check if the resource is allowed to be written, if necessary makes
+ * some preliminary work like creating directories
+ *
+ * Return 1 if write is allowed, 0 if not and -1 in case or error.
+ */
+int
+xsltCheckWrite(xsltSecurityPrefsPtr sec,
+	       xsltTransformContextPtr ctxt, const xmlChar *URL) {
+    int ret;
+    xmlURIPtr uri;
+    xsltSecurityCheck check;
+
+    uri = xmlParseURI((const char *)URL);
+    if (uri == NULL) {
+        uri = xmlCreateURI();
+	if (uri == NULL) {
+	    xsltTransformError(ctxt, NULL, NULL,
+	     "xsltCheckWrite: out of memory for %s\n", URL);
+	    return(-1);
+	}
+	uri->path = (char *)xmlStrdup(URL);
+    }
+    if ((uri->scheme == NULL) ||
+	(xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
+
+#if defined(WIN32) && !defined(__CYGWIN__)
+    if ((uri->path)&&(uri->path[0]=='/')&&
+        (uri->path[1]!='\0')&&(uri->path[2]==':'))
+    ret = xsltCheckWritePath(sec, ctxt, uri->path+1);
+    else
+#endif
+
+	/*
+	 * Check if we are allowed to write this file
+	 */
+	ret = xsltCheckWritePath(sec, ctxt, uri->path);
+	if (ret <= 0) {
+	    xmlFreeURI(uri);
+	    return(ret);
+	}
+    } else {
+	/*
+	 * Check if we are allowed to write this network resource
+	 */
+	check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_NETWORK);
+	if (check != NULL) {
+	    ret = check(sec, ctxt, (const char *)URL);
+	    if (ret == 0) {
+		xsltTransformError(ctxt, NULL, NULL,
+			     "File write for %s refused\n", URL);
+		xmlFreeURI(uri);
+		return(0);
+	    }
+	}
+    }
+    xmlFreeURI(uri);
+    return(1);
+}
+
+
+/**
+ * xsltCheckRead:
+ * @sec:  the security options
+ * @ctxt: an XSLT transformation context
+ * @URL:  the resource to be read
+ *
+ * Check if the resource is allowed to be read
+ *
+ * Return 1 if read is allowed, 0 if not and -1 in case or error.
+ */
+int
+xsltCheckRead(xsltSecurityPrefsPtr sec,
+	      xsltTransformContextPtr ctxt, const xmlChar *URL) {
+    int ret;
+    xmlURIPtr uri;
+    xsltSecurityCheck check;
+
+    uri = xmlParseURI((const char *)URL);
+    if (uri == NULL) {
+	xsltTransformError(ctxt, NULL, NULL,
+	 "xsltCheckRead: URL parsing failed for %s\n",
+			 URL);
+	return(-1);
+    }
+    if ((uri->scheme == NULL) ||
+	(xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
+
+	/*
+	 * Check if we are allowed to read this file
+	 */
+	check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_FILE);
+	if (check != NULL) {
+	    ret = check(sec, ctxt, uri->path);
+	    if (ret == 0) {
+		xsltTransformError(ctxt, NULL, NULL,
+			     "Local file read for %s refused\n", URL);
+		xmlFreeURI(uri);
+		return(0);
+	    }
+	}
+    } else {
+	/*
+	 * Check if we are allowed to write this network resource
+	 */
+	check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_NETWORK);
+	if (check != NULL) {
+	    ret = check(sec, ctxt, (const char *)URL);
+	    if (ret == 0) {
+		xsltTransformError(ctxt, NULL, NULL,
+			     "Network file read for %s refused\n", URL);
+		xmlFreeURI(uri);
+		return(0);
+	    }
+	}
+    }
+    xmlFreeURI(uri);
+    return(1);
+}
+
diff --git a/libxslt/security.h b/libxslt/security.h
new file mode 100644
index 0000000..d52c0ae
--- /dev/null
+++ b/libxslt/security.h
@@ -0,0 +1,104 @@
+/*
+ * Summary: interface for the libxslt security framework
+ * Description: the libxslt security framework allow to restrict
+ *              the access to new resources (file or URL) from
+ *              the stylesheet at runtime.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_SECURITY_H__
+#define __XML_XSLT_SECURITY_H__
+
+#include <libxml/tree.h>
+#include "xsltexports.h"
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * xsltSecurityPref:
+ *
+ * structure to indicate the preferences for security in the XSLT
+ * transformation.
+ */
+typedef struct _xsltSecurityPrefs xsltSecurityPrefs;
+typedef xsltSecurityPrefs *xsltSecurityPrefsPtr;
+
+/**
+ * xsltSecurityOption:
+ *
+ * the set of option that can be configured
+ */
+typedef enum {
+    XSLT_SECPREF_READ_FILE = 1,
+    XSLT_SECPREF_WRITE_FILE,
+    XSLT_SECPREF_CREATE_DIRECTORY,
+    XSLT_SECPREF_READ_NETWORK,
+    XSLT_SECPREF_WRITE_NETWORK
+} xsltSecurityOption;
+
+/**
+ * xsltSecurityCheck:
+ *
+ * User provided function to check the value of a string like a file
+ * path or an URL ...
+ */
+typedef int (*xsltSecurityCheck)	(xsltSecurityPrefsPtr sec,
+					 xsltTransformContextPtr ctxt,
+					 const char *value);
+
+/*
+ * Module interfaces
+ */
+XSLTPUBFUN xsltSecurityPrefsPtr XSLTCALL	
+		    xsltNewSecurityPrefs	(void);
+XSLTPUBFUN void XSLTCALL			
+		    xsltFreeSecurityPrefs	(xsltSecurityPrefsPtr sec);
+XSLTPUBFUN int XSLTCALL			
+		    xsltSetSecurityPrefs	(xsltSecurityPrefsPtr sec,
+						 xsltSecurityOption option,
+						 xsltSecurityCheck func);
+XSLTPUBFUN xsltSecurityCheck XSLTCALL	
+		    xsltGetSecurityPrefs	(xsltSecurityPrefsPtr sec,
+						 xsltSecurityOption option);
+
+XSLTPUBFUN void XSLTCALL			
+		    xsltSetDefaultSecurityPrefs	(xsltSecurityPrefsPtr sec);
+XSLTPUBFUN xsltSecurityPrefsPtr XSLTCALL	
+		    xsltGetDefaultSecurityPrefs	(void);
+
+XSLTPUBFUN int XSLTCALL			
+		    xsltSetCtxtSecurityPrefs	(xsltSecurityPrefsPtr sec,
+						 xsltTransformContextPtr ctxt);
+
+XSLTPUBFUN int XSLTCALL			
+		    xsltSecurityAllow		(xsltSecurityPrefsPtr sec,
+						 xsltTransformContextPtr ctxt,
+						 const char *value);
+XSLTPUBFUN int XSLTCALL	
+		    xsltSecurityForbid		(xsltSecurityPrefsPtr sec,
+						 xsltTransformContextPtr ctxt,
+						 const char *value);
+/*
+ * internal interfaces
+ */
+XSLTPUBFUN int XSLTCALL			
+		    xsltCheckWrite		(xsltSecurityPrefsPtr sec,
+						 xsltTransformContextPtr ctxt,
+						 const xmlChar *URL);
+XSLTPUBFUN int XSLTCALL			
+		    xsltCheckRead		(xsltSecurityPrefsPtr sec,
+						 xsltTransformContextPtr ctxt,
+						 const xmlChar *URL);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_SECURITY_H__ */
+
diff --git a/libxslt/templates.c b/libxslt/templates.c
new file mode 100644
index 0000000..c6250dc
--- /dev/null
+++ b/libxslt/templates.c
@@ -0,0 +1,825 @@
+/*
+ * templates.c: Implementation of the template processing
+ *
+ * Reference:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/globals.h>
+#include <libxml/xmlerror.h>
+#include <libxml/tree.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/parserInternals.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "variables.h"
+#include "functions.h"
+#include "templates.h"
+#include "transform.h"
+#include "namespaces.h"
+#include "attributes.h"
+
+#ifdef WITH_XSLT_DEBUG
+#define WITH_XSLT_DEBUG_TEMPLATES
+#endif
+
+/************************************************************************
+ *									*
+ *			Module interfaces				*
+ *									*
+ ************************************************************************/
+ 
+/**
+ * xsltEvalXPathPredicate:
+ * @ctxt:  the XSLT transformation context
+ * @comp:  the XPath compiled expression
+ * @nsList:  the namespaces in scope
+ * @nsNr:  the number of namespaces in scope
+ *
+ * Process the expression using XPath and evaluate the result as
+ * an XPath predicate
+ *
+ * Returns 1 is the predicate was true, 0 otherwise
+ */
+int
+xsltEvalXPathPredicate(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
+		       xmlNsPtr *nsList, int nsNr) {
+    int ret;
+    xmlXPathObjectPtr res;
+    int oldNsNr;
+    xmlNsPtr *oldNamespaces;
+    xmlNodePtr oldInst;
+    int oldProximityPosition, oldContextSize;
+
+    oldContextSize = ctxt->xpathCtxt->contextSize;
+    oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
+    oldNsNr = ctxt->xpathCtxt->nsNr;
+    oldNamespaces = ctxt->xpathCtxt->namespaces;
+    oldInst = ctxt->inst;
+
+    ctxt->xpathCtxt->node = ctxt->node;
+    ctxt->xpathCtxt->namespaces = nsList;
+    ctxt->xpathCtxt->nsNr = nsNr;
+
+    res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
+
+    if (res != NULL) {
+	ret = xmlXPathEvalPredicate(ctxt->xpathCtxt, res);
+	xmlXPathFreeObject(res);
+#ifdef WITH_XSLT_DEBUG_TEMPLATES
+	XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltEvalXPathPredicate: returns %d\n", ret));
+#endif
+    } else {
+#ifdef WITH_XSLT_DEBUG_TEMPLATES
+	XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltEvalXPathPredicate: failed\n"));
+#endif
+	ctxt->state = XSLT_STATE_STOPPED;
+	ret = 0;
+    }
+    ctxt->xpathCtxt->nsNr = oldNsNr;
+
+    ctxt->xpathCtxt->namespaces = oldNamespaces;
+    ctxt->inst = oldInst;
+    ctxt->xpathCtxt->contextSize = oldContextSize;
+    ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
+
+    return(ret);
+}
+
+/**
+ * xsltEvalXPathStringNs:
+ * @ctxt:  the XSLT transformation context
+ * @comp:  the compiled XPath expression
+ * @nsNr:  the number of namespaces in the list
+ * @nsList:  the list of in-scope namespaces to use
+ *
+ * Process the expression using XPath, allowing to pass a namespace mapping
+ * context and get a string
+ *
+ * Returns the computed string value or NULL, must be deallocated by the
+ *    caller.
+ */
+xmlChar *
+xsltEvalXPathStringNs(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
+	              int nsNr, xmlNsPtr *nsList) {
+    xmlChar *ret = NULL;
+    xmlXPathObjectPtr res;
+    xmlNodePtr oldInst;
+    xmlNodePtr oldNode;
+    int	oldPos, oldSize;
+    int oldNsNr;
+    xmlNsPtr *oldNamespaces;
+
+    oldInst = ctxt->inst;
+    oldNode = ctxt->node;
+    oldPos = ctxt->xpathCtxt->proximityPosition;
+    oldSize = ctxt->xpathCtxt->contextSize;
+    oldNsNr = ctxt->xpathCtxt->nsNr;
+    oldNamespaces = ctxt->xpathCtxt->namespaces;
+
+    ctxt->xpathCtxt->node = ctxt->node;
+    /* TODO: do we need to propagate the namespaces here ? */
+    ctxt->xpathCtxt->namespaces = nsList;
+    ctxt->xpathCtxt->nsNr = nsNr;
+    res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt);
+    if (res != NULL) {
+	if (res->type != XPATH_STRING)
+	    res = xmlXPathConvertString(res);
+	if (res->type == XPATH_STRING) {
+            ret = res->stringval;
+	    res->stringval = NULL;
+	} else {
+	    xsltTransformError(ctxt, NULL, NULL,
+		 "xpath : string() function didn't return a String\n");
+	}
+	xmlXPathFreeObject(res);
+    } else {
+	ctxt->state = XSLT_STATE_STOPPED;
+    }
+#ifdef WITH_XSLT_DEBUG_TEMPLATES
+    XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
+	 "xsltEvalXPathString: returns %s\n", ret));
+#endif
+    ctxt->inst = oldInst;
+    ctxt->node = oldNode;
+    ctxt->xpathCtxt->contextSize = oldSize;
+    ctxt->xpathCtxt->proximityPosition = oldPos;
+    ctxt->xpathCtxt->nsNr = oldNsNr;
+    ctxt->xpathCtxt->namespaces = oldNamespaces;
+    return(ret);
+}
+
+/**
+ * xsltEvalXPathString:
+ * @ctxt:  the XSLT transformation context
+ * @comp:  the compiled XPath expression
+ *
+ * Process the expression using XPath and get a string
+ *
+ * Returns the computed string value or NULL, must be deallocated by the
+ *    caller.
+ */
+xmlChar *
+xsltEvalXPathString(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp) {
+    return(xsltEvalXPathStringNs(ctxt, comp, 0, NULL));
+}
+
+/**
+ * xsltEvalTemplateString:
+ * @ctxt:  the XSLT transformation context
+ * @contextNode:  the current node in the source tree
+ * @inst:  the XSLT instruction (xsl:comment, xsl:processing-instruction)
+ *
+ * Processes the sequence constructor of the given instruction on
+ * @contextNode and converts the resulting tree to a string.
+ * This is needed by e.g. xsl:comment and xsl:processing-instruction.
+ *
+ * Returns the computed string value or NULL; it's up to the caller to
+ *         free the result.
+ */
+xmlChar *
+xsltEvalTemplateString(xsltTransformContextPtr ctxt,
+		       xmlNodePtr contextNode,
+	               xmlNodePtr inst)
+{
+    xmlNodePtr oldInsert, insert = NULL;
+    xmlChar *ret;
+
+    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
+	return(NULL);
+
+    if (inst->children == NULL)
+	return(NULL);
+
+    /*
+    * This creates a temporary element-node to add the resulting
+    * text content to.
+    * OPTIMIZE TODO: Keep such an element-node in the transformation
+    *  context to avoid creating it every time.
+    */
+    insert = xmlNewDocNode(ctxt->output, NULL,
+	                   (const xmlChar *)"fake", NULL);
+    if (insert == NULL) {
+	xsltTransformError(ctxt, NULL, contextNode,
+		"Failed to create temporary node\n");
+	return(NULL);
+    }
+    oldInsert = ctxt->insert;
+    ctxt->insert = insert;
+    /*
+    * OPTIMIZE TODO: if inst->children consists only of text-nodes.
+    */
+    xsltApplyOneTemplate(ctxt, contextNode, inst->children, NULL, NULL);
+
+    ctxt->insert = oldInsert;
+
+    ret = xmlNodeGetContent(insert);
+    if (insert != NULL)
+	xmlFreeNode(insert);
+    return(ret);
+}
+
+/**
+ * xsltAttrTemplateValueProcessNode:
+ * @ctxt:  the XSLT transformation context
+ * @str:  the attribute template node value
+ * @inst:  the instruction (or LRE) in the stylesheet holding the
+ *         attribute with an AVT
+ *
+ * Process the given string, allowing to pass a namespace mapping
+ * context and return the new string value.
+ *
+ * Called by:
+ *  - xsltAttrTemplateValueProcess() (templates.c)
+ *  - xsltEvalAttrValueTemplate() (templates.c)
+ *
+ * QUESTION: Why is this function public? It is not used outside
+ *  of templates.c.
+ *
+ * Returns the computed string value or NULL, must be deallocated by the
+ *    caller.
+ */
+xmlChar *
+xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,
+	  const xmlChar *str, xmlNodePtr inst)
+{
+    xmlChar *ret = NULL;
+    const xmlChar *cur;
+    xmlChar *expr, *val;
+    xmlNsPtr *nsList = NULL;
+    int nsNr = 0;
+
+    if (str == NULL) return(NULL);
+    if (*str == 0)
+	return(xmlStrndup((xmlChar *)"", 0));
+
+    cur = str;
+    while (*cur != 0) {
+	if (*cur == '{') {
+	    if (*(cur+1) == '{') {	/* escaped '{' */
+	        cur++;
+		ret = xmlStrncat(ret, str, cur - str);
+		cur++;
+		str = cur;
+		continue;
+	    }
+	    ret = xmlStrncat(ret, str, cur - str);
+	    str = cur;
+	    cur++;
+	    while ((*cur != 0) && (*cur != '}')) cur++;
+	    if (*cur == 0) {
+	        xsltTransformError(ctxt, NULL, inst,
+			"xsltAttrTemplateValueProcessNode: unmatched '{'\n");
+		ret = xmlStrncat(ret, str, cur - str);
+		return(ret);
+	    }
+	    str++;
+	    expr = xmlStrndup(str, cur - str);
+	    if (expr == NULL)
+		return(ret);
+	    else if (*expr == '{') {
+		ret = xmlStrcat(ret, expr);
+		xmlFree(expr);
+	    } else {
+		xmlXPathCompExprPtr comp;
+		/*
+		 * TODO: keep precompiled form around
+		 */
+		if ((nsList == NULL) && (inst != NULL)) {
+		    int i = 0;
+
+		    nsList = xmlGetNsList(inst->doc, inst);
+		    if (nsList != NULL) {
+			while (nsList[i] != NULL)
+			    i++;
+			nsNr = i;
+		    }
+		}
+		comp = xmlXPathCompile(expr);
+                val = xsltEvalXPathStringNs(ctxt, comp, nsNr, nsList);
+		xmlXPathFreeCompExpr(comp);
+		xmlFree(expr);
+		if (val != NULL) {
+		    ret = xmlStrcat(ret, val);
+		    xmlFree(val);
+		}
+	    }
+	    cur++;
+	    str = cur;
+	} else if (*cur == '}') {
+	    cur++;
+	    if (*cur == '}') {	/* escaped '}' */
+		ret = xmlStrncat(ret, str, cur - str);
+		cur++;
+		str = cur;
+		continue;
+	    } else {
+	        xsltTransformError(ctxt, NULL, inst,
+		     "xsltAttrTemplateValueProcessNode: unmatched '}'\n");
+	    }
+	} else
+	    cur++;
+    }
+    if (cur != str) {
+	ret = xmlStrncat(ret, str, cur - str);
+    }
+
+    if (nsList != NULL)
+	xmlFree(nsList);
+
+    return(ret);
+}
+
+/**
+ * xsltAttrTemplateValueProcess:
+ * @ctxt:  the XSLT transformation context
+ * @str:  the attribute template node value
+ *
+ * Process the given node and return the new string value.
+ *
+ * Returns the computed string value or NULL, must be deallocated by the
+ *    caller.
+ */
+xmlChar *
+xsltAttrTemplateValueProcess(xsltTransformContextPtr ctxt, const xmlChar *str) {
+    return(xsltAttrTemplateValueProcessNode(ctxt, str, NULL));
+}
+
+/**
+ * xsltEvalAttrValueTemplate:
+ * @ctxt:  the XSLT transformation context
+ * @inst:  the instruction (or LRE) in the stylesheet holding the
+ *         attribute with an AVT
+ * @name:  the attribute QName
+ * @ns:  the attribute namespace URI
+ *
+ * Evaluate a attribute value template, i.e. the attribute value can
+ * contain expressions contained in curly braces ({}) and those are
+ * substituted by they computed value.
+ *
+ * Returns the computed string value or NULL, must be deallocated by the
+ *    caller.
+ */
+xmlChar *
+xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr inst,
+	                  const xmlChar *name, const xmlChar *ns)
+{
+    xmlChar *ret;
+    xmlChar *expr;
+
+    if ((ctxt == NULL) || (inst == NULL) || (name == NULL))
+	return(NULL);
+
+    expr = xsltGetNsProp(inst, name, ns);
+    if (expr == NULL)
+	return(NULL);
+
+    /*
+     * TODO: though now {} is detected ahead, it would still be good to
+     *       optimize both functions to keep the splitted value if the
+     *       attribute content and the XPath precompiled expressions around
+     */
+
+    ret = xsltAttrTemplateValueProcessNode(ctxt, expr, inst);
+#ifdef WITH_XSLT_DEBUG_TEMPLATES
+    XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
+	 "xsltEvalAttrValueTemplate: %s returns %s\n", expr, ret));
+#endif
+    if (expr != NULL)
+	xmlFree(expr);
+    return(ret);
+}
+
+/**
+ * xsltEvalStaticAttrValueTemplate:
+ * @style:  the XSLT stylesheet
+ * @inst:  the instruction (or LRE) in the stylesheet holding the
+ *         attribute with an AVT
+ * @name:  the attribute Name
+ * @ns:  the attribute namespace URI
+ * @found:  indicator whether the attribute is present
+ *
+ * Check if an attribute value template has a static value, i.e. the
+ * attribute value does not contain expressions contained in curly braces ({})
+ *
+ * Returns the static string value or NULL, must be deallocated by the
+ *    caller.
+ */
+const xmlChar *
+xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr inst,
+			const xmlChar *name, const xmlChar *ns, int *found) {
+    const xmlChar *ret;
+    xmlChar *expr;
+
+    if ((style == NULL) || (inst == NULL) || (name == NULL))
+	return(NULL);
+
+    expr = xsltGetNsProp(inst, name, ns);
+    if (expr == NULL) {
+	*found = 0;
+	return(NULL);
+    }
+    *found = 1;
+
+    ret = xmlStrchr(expr, '{');
+    if (ret != NULL) {
+	xmlFree(expr);
+	return(NULL);
+    }
+    ret = xmlDictLookup(style->dict, expr, -1);
+    xmlFree(expr);
+    return(ret);
+}
+
+/**
+ * xsltAttrTemplateProcess:
+ * @ctxt:  the XSLT transformation context
+ * @target:  the element where the attribute will be grafted
+ * @attr:  the attribute node of a literal result element
+ *
+ * Process one attribute of a Literal Result Element (in the stylesheet).
+ * Evaluates Attribute Value Templates and copies the attribute over to
+ * the result element.
+ * This does *not* process attribute sets (xsl:use-attribute-set).
+ * 
+ *
+ * Returns the generated attribute node.
+ */
+xmlAttrPtr
+xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
+	                xmlAttrPtr attr)
+{
+    const xmlChar *value;
+    xmlAttrPtr ret;
+
+    if ((ctxt == NULL) || (attr == NULL) || (target == NULL))
+	return(NULL);
+    
+    if (attr->type != XML_ATTRIBUTE_NODE)
+	return(NULL);
+
+    /*
+    * Skip all XSLT attributes.
+    */
+#ifdef XSLT_REFACTORED    
+    if (attr->psvi == xsltXSLTAttrMarker)
+	return(NULL);
+#else
+    if ((attr->ns != NULL) && xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
+	return(NULL);
+#endif
+    /*
+    * Get the value.
+    */
+    if (attr->children != NULL) {
+	if ((attr->children->type != XML_TEXT_NODE) ||
+	    (attr->children->next != NULL))
+	{
+	    xsltTransformError(ctxt, NULL, attr->parent,
+		"Internal error: The children of an attribute node of a "
+		"literal result element are not in the expected form.\n");
+	    return(NULL);
+	}
+	value = attr->children->content;
+	if (value == NULL)
+	    value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
+    } else
+	value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
+    /*
+    * Overwrite duplicates.
+    */
+    ret = target->properties;
+    while (ret != NULL) {
+        if (((attr->ns != NULL) == (ret->ns != NULL)) &&
+	    xmlStrEqual(ret->name, attr->name) &&
+	    ((attr->ns == NULL) || xmlStrEqual(ret->ns->href, attr->ns->href)))
+	{
+	    break;
+	}
+        ret = ret->next;
+    }
+    if (ret != NULL) {	
+        /* free the existing value */
+	xmlFreeNodeList(ret->children);
+	ret->children = ret->last = NULL;
+	/*
+	* Adjust ns-prefix if needed.
+	*/
+	if ((ret->ns != NULL) &&
+	    (! xmlStrEqual(ret->ns->prefix, attr->ns->prefix)))
+	{
+	    ret->ns = xsltGetNamespace(ctxt, attr->parent, attr->ns, target);
+	}
+    } else {
+        /* create a new attribute */
+	if (attr->ns != NULL)
+	    ret = xmlNewNsProp(target,
+		xsltGetNamespace(ctxt, attr->parent, attr->ns, target),
+		    attr->name, NULL);
+	else
+	    ret = xmlNewNsProp(target, NULL, attr->name, NULL);	
+    }
+    /*
+    * Set the value.
+    */
+    if (ret != NULL) {
+        xmlNodePtr text;
+
+        text = xmlNewText(NULL);
+	if (text != NULL) {
+	    ret->last = ret->children = text;
+	    text->parent = (xmlNodePtr) ret;
+	    text->doc = ret->doc;
+
+	    if (attr->psvi != NULL) {
+		/*
+		* Evaluate the Attribute Value Template.
+		*/
+		xmlChar *val;
+		val = xsltEvalAVT(ctxt, attr->psvi, attr->parent);
+		if (val == NULL) {
+		    /*
+		    * TODO: Damn, we need an easy mechanism to report
+		    * qualified names!
+		    */
+		    if (attr->ns) {
+			xsltTransformError(ctxt, NULL, attr->parent,
+			    "Internal error: Failed to evaluate the AVT "
+			    "of attribute '{%s}%s'.\n",
+			    attr->ns->href, attr->name);
+		    } else {
+			xsltTransformError(ctxt, NULL, attr->parent,
+			    "Internal error: Failed to evaluate the AVT "
+			    "of attribute '%s'.\n",
+			    attr->name);
+		    }
+		    text->content = xmlStrdup(BAD_CAST "");
+		} else {
+		    text->content = val;
+		}
+	    } else if ((ctxt->internalized) && (target != NULL) &&
+	               (target->doc != NULL) &&
+		       (target->doc->dict == ctxt->dict)) {
+		text->content = (xmlChar *) value;
+	    } else {
+		text->content = xmlStrdup(value);
+	    }
+	}
+    } else {
+	if (attr->ns) {
+	    xsltTransformError(ctxt, NULL, attr->parent,
+	    	"Internal error: Failed to create attribute '{%s}%s'.\n",
+		attr->ns->href, attr->name);
+	} else {
+	    xsltTransformError(ctxt, NULL, attr->parent,
+	    	"Internal error: Failed to create attribute '%s'.\n",
+		attr->name);
+	}
+    }
+    return(ret);
+}
+
+
+/**
+ * xsltAttrListTemplateProcess:
+ * @ctxt:  the XSLT transformation context
+ * @target:  the element where the attributes will be grafted
+ * @attrs:  the first attribute
+ *
+ * Processes all attributes of a Literal Result Element.
+ * Attribute references are applied via xsl:use-attribute-set
+ * attributes.
+ * Copies all non XSLT-attributes over to the @target element
+ * and evaluates Attribute Value Templates.
+ *
+ * Called by xsltApplySequenceConstructor() (transform.c).
+ *
+ * Returns a new list of attribute nodes, or NULL in case of error.
+ *         (Don't assign the result to @target->properties; if
+ *         the result is NULL, you'll get memory leaks, since the
+ *         attributes will be disattached.)
+ */
+xmlAttrPtr
+xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt, 
+	                    xmlNodePtr target, xmlAttrPtr attrs)
+{
+    xmlAttrPtr attr, copy, last;
+    xmlNodePtr oldInsert, text;
+    xmlNsPtr origNs = NULL, copyNs = NULL;
+    const xmlChar *value;
+    xmlChar *valueAVT;
+
+    if ((ctxt == NULL) || (target == NULL) || (attrs == NULL))
+	return(NULL);
+
+    oldInsert = ctxt->insert;
+    ctxt->insert = target;        
+
+    /*
+    * Instantiate LRE-attributes.
+    */
+    if (target->properties) {
+	last = target->properties;
+	while (last->next != NULL)
+	    last = last->next;
+    } else {
+	last = NULL;
+    }
+    attr = attrs;
+    do {
+	/*
+	* Skip XSLT attributes.
+	*/
+#ifdef XSLT_REFACTORED
+	if (attr->psvi == xsltXSLTAttrMarker) {
+	    goto next_attribute;
+	}
+#else
+	if ((attr->ns != NULL) &&
+	    xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
+	{
+	    goto next_attribute;
+	}
+#endif
+	/*
+	* Get the value.
+	*/
+	if (attr->children != NULL) {
+	    if ((attr->children->type != XML_TEXT_NODE) ||
+		(attr->children->next != NULL))
+	    {
+		xsltTransformError(ctxt, NULL, attr->parent,
+		    "Internal error: The children of an attribute node of a "
+		    "literal result element are not in the expected form.\n");
+		goto error;
+	    }
+	    value = attr->children->content;
+	    if (value == NULL)
+		value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
+	} else
+	    value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0);
+
+	/*
+	* Create a new attribute.
+	*/
+	copy = xmlNewDocProp(target->doc, attr->name, NULL);
+	if (copy == NULL) {
+	    if (attr->ns) {
+		xsltTransformError(ctxt, NULL, attr->parent,
+		    "Internal error: Failed to create attribute '{%s}%s'.\n",
+		    attr->ns->href, attr->name);
+	    } else {
+		xsltTransformError(ctxt, NULL, attr->parent,
+		    "Internal error: Failed to create attribute '%s'.\n",
+		    attr->name);
+	    }
+	    goto error;
+	}
+	/*
+	* Attach it to the target element.
+	*/
+	copy->parent = target;
+	if (last == NULL) {
+	    target->properties = copy;
+	    last = copy;
+	} else {
+	    last->next = copy;
+	    copy->prev = last;
+	    last = copy;
+	}
+	/*
+	* Set the namespace. Avoid lookups of same namespaces.
+	*/
+	if (attr->ns != origNs) {
+	    origNs = attr->ns;
+	    if (attr->ns != NULL) {
+#ifdef XSLT_REFACTORED
+		copyNs = xsltGetSpecialNamespace(ctxt, attr->parent,
+		    attr->ns->href, attr->ns->prefix, target);
+#else
+		copyNs = xsltGetNamespace(ctxt, attr->parent,
+		    attr->ns, target);
+#endif
+		if (copyNs == NULL)
+		    goto error;
+	    } else
+		copyNs = NULL;
+	}
+	copy->ns = copyNs;
+
+	/*
+	* Set the value.
+	*/
+	text = xmlNewText(NULL);
+	if (text != NULL) {
+	    copy->last = copy->children = text;
+	    text->parent = (xmlNodePtr) copy;
+	    text->doc = copy->doc;
+
+	    if (attr->psvi != NULL) {
+		/*
+		* Evaluate the Attribute Value Template.
+		*/
+		valueAVT = xsltEvalAVT(ctxt, attr->psvi, attr->parent);
+		if (valueAVT == NULL) {
+		    /*
+		    * TODO: Damn, we need an easy mechanism to report
+		    * qualified names!
+		    */
+		    if (attr->ns) {
+			xsltTransformError(ctxt, NULL, attr->parent,
+			    "Internal error: Failed to evaluate the AVT "
+			    "of attribute '{%s}%s'.\n",
+			    attr->ns->href, attr->name);
+		    } else {
+			xsltTransformError(ctxt, NULL, attr->parent,
+			    "Internal error: Failed to evaluate the AVT "
+			    "of attribute '%s'.\n",
+			    attr->name);
+		    }
+		    text->content = xmlStrdup(BAD_CAST "");
+		    goto error;
+		} else {
+		    text->content = valueAVT;
+		}
+	    } else if ((ctxt->internalized) &&
+		(target->doc != NULL) &&
+		(target->doc->dict == ctxt->dict))
+	    {
+		text->content = (xmlChar *) value;
+	    } else {
+		text->content = xmlStrdup(value);
+	    }
+            if ((copy != NULL) && (text != NULL) &&
+                (xmlIsID(copy->doc, copy->parent, copy)))
+                xmlAddID(NULL, copy->doc, text->content, copy);
+	}
+
+next_attribute:
+	attr = attr->next;
+    } while (attr != NULL);
+
+    /*
+    * Apply attribute-sets.
+    * The creation of such attributes will not overwrite any existing
+    * attribute.
+    */
+    attr = attrs;
+    do {
+#ifdef XSLT_REFACTORED
+	if ((attr->psvi == xsltXSLTAttrMarker) &&
+	    xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets"))
+	{
+	    xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL);
+	}
+#else
+	if ((attr->ns != NULL) &&
+	    xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets") &&
+	    xmlStrEqual(attr->ns->href, XSLT_NAMESPACE))
+	{
+	    xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL);
+	}
+#endif
+	attr = attr->next;
+    } while (attr != NULL);
+
+    ctxt->insert = oldInsert;
+    return(target->properties);
+
+error:
+    ctxt->insert = oldInsert;
+    return(NULL);
+}
+
+
+/**
+ * xsltTemplateProcess:
+ * @ctxt:  the XSLT transformation context
+ * @node:  the attribute template node
+ *
+ * Obsolete. Don't use it.
+ *
+ * Returns NULL.
+ */
+xmlNodePtr *
+xsltTemplateProcess(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr node) {
+    if (node == NULL)
+	return(NULL);
+    
+    return(0);
+}
+
+
diff --git a/libxslt/templates.h b/libxslt/templates.h
new file mode 100644
index 0000000..18adfdb
--- /dev/null
+++ b/libxslt/templates.h
@@ -0,0 +1,77 @@
+/*
+ * Summary: interface for the template processing
+ * Description: This set of routine encapsulates XPath calls
+ *              and Attribute Value Templates evaluation.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_TEMPLATES_H__
+#define __XML_XSLT_TEMPLATES_H__
+
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include "xsltexports.h"
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+XSLTPUBFUN int XSLTCALL		
+		xsltEvalXPathPredicate		(xsltTransformContextPtr ctxt,
+						 xmlXPathCompExprPtr comp,
+		                                 xmlNsPtr *nsList,
+						 int nsNr);
+XSLTPUBFUN xmlChar * XSLTCALL	
+		xsltEvalTemplateString		(xsltTransformContextPtr ctxt,
+						 xmlNodePtr contextNode,
+						 xmlNodePtr inst);
+XSLTPUBFUN xmlChar * XSLTCALL	
+		xsltEvalAttrValueTemplate	(xsltTransformContextPtr ctxt,
+						 xmlNodePtr node,
+						 const xmlChar *name,
+						 const xmlChar *ns);
+XSLTPUBFUN const xmlChar * XSLTCALL	
+		xsltEvalStaticAttrValueTemplate	(xsltStylesheetPtr style,
+						 xmlNodePtr node,
+						 const xmlChar *name,
+						 const xmlChar *ns,
+						 int *found);
+
+/* TODO: this is obviously broken ... the namespaces should be passed too ! */
+XSLTPUBFUN xmlChar * XSLTCALL	
+		xsltEvalXPathString		(xsltTransformContextPtr ctxt,
+						 xmlXPathCompExprPtr comp);
+XSLTPUBFUN xmlChar * XSLTCALL	
+		xsltEvalXPathStringNs		(xsltTransformContextPtr ctxt,
+						 xmlXPathCompExprPtr comp,
+						 int nsNr,
+						 xmlNsPtr *nsList);
+
+XSLTPUBFUN xmlNodePtr * XSLTCALL	
+		xsltTemplateProcess		(xsltTransformContextPtr ctxt,
+						 xmlNodePtr node);
+XSLTPUBFUN xmlAttrPtr XSLTCALL	
+		xsltAttrListTemplateProcess	(xsltTransformContextPtr ctxt,
+						 xmlNodePtr target,
+						 xmlAttrPtr cur);
+XSLTPUBFUN xmlAttrPtr XSLTCALL	
+		xsltAttrTemplateProcess		(xsltTransformContextPtr ctxt,
+						 xmlNodePtr target,
+						 xmlAttrPtr attr);
+XSLTPUBFUN xmlChar * XSLTCALL	
+		xsltAttrTemplateValueProcess	(xsltTransformContextPtr ctxt,
+						 const xmlChar* attr);
+XSLTPUBFUN xmlChar * XSLTCALL	
+		xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt,
+						 const xmlChar* str,
+						 xmlNodePtr node);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_TEMPLATES_H__ */
+
diff --git a/libxslt/transform.c b/libxslt/transform.c
new file mode 100644
index 0000000..a4ca41d
--- /dev/null
+++ b/libxslt/transform.c
@@ -0,0 +1,6475 @@
+/*
+ * transform.c: Implementation of the XSL Transformation 1.0 engine
+ *              transform part, i.e. applying a Stylesheet to a document
+ *
+ * References:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ *   Michael Kay "XSLT Programmer's Reference" pp 637-643
+ *   Writing Multiple Output Files
+ *
+ *   XSLT-1.1 Working Draft
+ *   http://www.w3.org/TR/xslt11#multiple-output
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+#include <libxml/hash.h>
+#include <libxml/encoding.h>
+#include <libxml/xmlerror.h>
+#include <libxml/xpath.h>
+#include <libxml/parserInternals.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/HTMLtree.h>
+#include <libxml/debugXML.h>
+#include <libxml/uri.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "pattern.h"
+#include "transform.h"
+#include "variables.h"
+#include "numbersInternals.h"
+#include "namespaces.h"
+#include "attributes.h"
+#include "templates.h"
+#include "imports.h"
+#include "keys.h"
+#include "documents.h"
+#include "extensions.h"
+#include "extra.h"
+#include "preproc.h"
+#include "security.h"
+
+#ifdef WITH_XSLT_DEBUG
+#define WITH_XSLT_DEBUG_EXTRA
+#define WITH_XSLT_DEBUG_PROCESS
+#endif
+
+#define XSLT_GENERATE_HTML_DOCTYPE
+#ifdef XSLT_GENERATE_HTML_DOCTYPE
+static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
+			  const xmlChar **systemID);
+#endif
+
+int xsltMaxDepth = 3000;
+
+/*
+ * Useful macros
+ */
+
+#ifndef FALSE
+# define FALSE (0 == 1)
+# define TRUE (!FALSE)
+#endif
+
+#define IS_BLANK_NODE(n)						\
+    (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
+
+
+/*
+* Forward declarations
+*/
+
+static xmlNsPtr
+xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur);
+
+static xmlNodePtr
+xsltCopyTreeInternal(xsltTransformContextPtr ctxt,
+		     xmlNodePtr invocNode,
+		     xmlNodePtr node,
+		     xmlNodePtr insert, int isLRE, int topElemVisited);
+
+static void
+xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
+			     xmlNodePtr contextNode, xmlNodePtr list,
+			     xsltTemplatePtr templ);
+
+static void
+xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
+		      xmlNodePtr contextNode,
+		      xmlNodePtr list,
+		      xsltTemplatePtr templ,
+		      xsltStackElemPtr withParams);
+
+/**
+ * templPush:
+ * @ctxt: the transformation context
+ * @value:  the template to push on the stack
+ *
+ * Push a template on the stack
+ *
+ * Returns the new index in the stack or 0 in case of error
+ */
+static int
+templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value)
+{
+    if (ctxt->templMax == 0) {
+        ctxt->templMax = 4;
+        ctxt->templTab =
+            (xsltTemplatePtr *) xmlMalloc(ctxt->templMax *
+                                          sizeof(ctxt->templTab[0]));
+        if (ctxt->templTab == NULL) {
+            xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
+            return (0);
+        }
+    }
+    if (ctxt->templNr >= ctxt->templMax) {
+        ctxt->templMax *= 2;
+        ctxt->templTab =
+            (xsltTemplatePtr *) xmlRealloc(ctxt->templTab,
+                                           ctxt->templMax *
+                                           sizeof(ctxt->templTab[0]));
+        if (ctxt->templTab == NULL) {
+            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
+            return (0);
+        }
+    }
+    ctxt->templTab[ctxt->templNr] = value;
+    ctxt->templ = value;
+    return (ctxt->templNr++);
+}
+/**
+ * templPop:
+ * @ctxt: the transformation context
+ *
+ * Pop a template value from the stack
+ *
+ * Returns the stored template value
+ */
+static xsltTemplatePtr
+templPop(xsltTransformContextPtr ctxt)
+{
+    xsltTemplatePtr ret;
+
+    if (ctxt->templNr <= 0)
+        return (0);
+    ctxt->templNr--;
+    if (ctxt->templNr > 0)
+        ctxt->templ = ctxt->templTab[ctxt->templNr - 1];
+    else
+        ctxt->templ = (xsltTemplatePtr) 0;
+    ret = ctxt->templTab[ctxt->templNr];
+    ctxt->templTab[ctxt->templNr] = 0;
+    return (ret);
+}
+
+/**
+ * xsltLocalVariablePop:
+ * @ctxt: the transformation context
+ * @limitNr: number of variables which should remain
+ * @level: the depth in the xsl:template's tree
+ *
+ * Pops all variable values at the given @depth from the stack.
+ *
+ * Returns the stored variable value
+ * **NOTE:**
+ * This is an internal routine and should not be called by users!
+ */
+void
+xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level)
+{
+    xsltStackElemPtr variable;
+
+    if (ctxt->varsNr <= 0)
+        return;
+
+    do {
+	if (ctxt->varsNr <= limitNr)
+	    break;
+	variable = ctxt->varsTab[ctxt->varsNr - 1];
+	if (variable->level <= level)
+	    break;
+	if (variable->level >= 0)
+	    xsltFreeStackElemList(variable);
+	ctxt->varsNr--;
+    } while (ctxt->varsNr != 0);
+    if (ctxt->varsNr > 0)
+        ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
+    else
+        ctxt->vars = NULL;
+}
+
+/**
+ * xsltTemplateParamsCleanup:
+ *
+ * Removes xsl:param and xsl:with-param items from the
+ * variable-stack. Only xsl:with-param items are not freed.
+ */
+static void
+xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt)
+{
+    xsltStackElemPtr param;
+
+    for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) {
+	param = ctxt->varsTab[ctxt->varsNr -1];
+	/*
+	* Free xsl:param items.
+	* xsl:with-param items will have a level of -1 or -2.
+	*/
+	if (param->level >= 0) {
+	    xsltFreeStackElemList(param);
+	}
+    }
+    if (ctxt->varsNr > 0)
+        ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1];
+    else
+        ctxt->vars = NULL;
+}
+
+/**
+ * profPush:
+ * @ctxt: the transformation context
+ * @value:  the profiling value to push on the stack
+ *
+ * Push a profiling value on the stack
+ *
+ * Returns the new index in the stack or 0 in case of error
+ */
+static int
+profPush(xsltTransformContextPtr ctxt, long value)
+{
+    if (ctxt->profMax == 0) {
+        ctxt->profMax = 4;
+        ctxt->profTab =
+            (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0]));
+        if (ctxt->profTab == NULL) {
+            xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
+            return (0);
+        }
+    }
+    if (ctxt->profNr >= ctxt->profMax) {
+        ctxt->profMax *= 2;
+        ctxt->profTab =
+            (long *) xmlRealloc(ctxt->profTab,
+                                ctxt->profMax * sizeof(ctxt->profTab[0]));
+        if (ctxt->profTab == NULL) {
+            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
+            return (0);
+        }
+    }
+    ctxt->profTab[ctxt->profNr] = value;
+    ctxt->prof = value;
+    return (ctxt->profNr++);
+}
+/**
+ * profPop:
+ * @ctxt: the transformation context
+ *
+ * Pop a profiling value from the stack
+ *
+ * Returns the stored profiling value
+ */
+static long
+profPop(xsltTransformContextPtr ctxt)
+{
+    long ret;
+
+    if (ctxt->profNr <= 0)
+        return (0);
+    ctxt->profNr--;
+    if (ctxt->profNr > 0)
+        ctxt->prof = ctxt->profTab[ctxt->profNr - 1];
+    else
+        ctxt->prof = (long) 0;
+    ret = ctxt->profTab[ctxt->profNr];
+    ctxt->profTab[ctxt->profNr] = 0;
+    return (ret);
+}
+
+/************************************************************************
+ *									*
+ *			XInclude default settings			*
+ *									*
+ ************************************************************************/
+
+static int xsltDoXIncludeDefault = 0;
+
+/**
+ * xsltSetXIncludeDefault:
+ * @xinclude: whether to do XInclude processing
+ *
+ * Set whether XInclude should be processed on document being loaded by default
+ */
+void
+xsltSetXIncludeDefault(int xinclude) {
+    xsltDoXIncludeDefault = (xinclude != 0);
+}
+
+/**
+ * xsltGetXIncludeDefault:
+ *
+ * Provides the default state for XInclude processing
+ *
+ * Returns 0 if there is no processing 1 otherwise
+ */
+int
+xsltGetXIncludeDefault(void) {
+    return(xsltDoXIncludeDefault);
+}
+
+unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL;
+
+/**
+ * xsltDebugSetDefaultTrace:
+ * @val: tracing level mask
+ *
+ * Set the default debug tracing level mask
+ */
+void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) {
+	xsltDefaultTrace = val;
+}
+
+/**
+ * xsltDebugGetDefaultTrace:
+ *
+ * Get the current default debug tracing level mask
+ *
+ * Returns the current default debug tracing level mask
+ */
+xsltDebugTraceCodes xsltDebugGetDefaultTrace() {
+	return xsltDefaultTrace;
+}
+
+/************************************************************************
+ *									*
+ *			Handling of Transformation Contexts		*
+ *									*
+ ************************************************************************/
+
+static xsltTransformCachePtr
+xsltTransformCacheCreate(void)
+{
+    xsltTransformCachePtr ret;
+
+    ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache));
+    if (ret == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+	    "xsltTransformCacheCreate : malloc failed\n");
+	return(NULL);
+    }
+    memset(ret, 0, sizeof(xsltTransformCache));
+    return(ret);
+}
+
+static void
+xsltTransformCacheFree(xsltTransformCachePtr cache)
+{
+    if (cache == NULL)
+	return;
+    /*
+    * Free tree fragments.
+    */
+    if (cache->RVT) {
+	xmlDocPtr tmp, cur = cache->RVT;
+	while (cur) {
+	    tmp = cur;
+	    cur = (xmlDocPtr) cur->next;
+	    if (tmp->_private != NULL) {
+		/*
+		* Tree the document info.
+		*/
+		xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private);
+		xmlFree(tmp->_private);
+	    }
+	    xmlFreeDoc(tmp);
+	}
+    }
+    /*
+    * Free vars/params.
+    */
+    if (cache->stackItems) {
+	xsltStackElemPtr tmp, cur = cache->stackItems;
+	while (cur) {
+	    tmp = cur;
+	    cur = cur->next;
+	    /*
+	    * REVISIT TODO: Should be call a destruction-function
+	    * instead?
+	    */
+	    xmlFree(tmp);
+	}
+    }
+    xmlFree(cache);
+}
+
+/**
+ * xsltNewTransformContext:
+ * @style:  a parsed XSLT stylesheet
+ * @doc:  the input document
+ *
+ * Create a new XSLT TransformContext
+ *
+ * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
+ */
+xsltTransformContextPtr
+xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) {
+    xsltTransformContextPtr cur;
+    xsltDocumentPtr docu;
+    int i;
+
+    xsltInitGlobals();
+
+    cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext));
+    if (cur == NULL) {
+	xsltTransformError(NULL, NULL, (xmlNodePtr)doc,
+		"xsltNewTransformContext : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltTransformContext));
+
+    cur->cache = xsltTransformCacheCreate();
+    if (cur->cache == NULL)
+	goto internal_err;
+    /*
+     * setup of the dictionary must be done early as some of the
+     * processing later like key handling may need it.
+     */
+    cur->dict = xmlDictCreateSub(style->dict);
+    cur->internalized = ((style->internalized) && (cur->dict != NULL));
+#ifdef WITH_XSLT_DEBUG
+    xsltGenericDebug(xsltGenericDebugContext,
+	     "Creating sub-dictionary from stylesheet for transformation\n");
+#endif
+
+    /*
+     * initialize the template stack
+     */
+    cur->templTab = (xsltTemplatePtr *)
+	        xmlMalloc(10 * sizeof(xsltTemplatePtr));
+    if (cur->templTab == NULL) {
+	xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
+		"xsltNewTransformContext: out of memory\n");
+	goto internal_err;
+    }
+    cur->templNr = 0;
+    cur->templMax = 5;
+    cur->templ = NULL;
+
+    /*
+     * initialize the variables stack
+     */
+    cur->varsTab = (xsltStackElemPtr *)
+	        xmlMalloc(10 * sizeof(xsltStackElemPtr));
+    if (cur->varsTab == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xsltNewTransformContext: out of memory\n");
+	goto internal_err;
+    }
+    cur->varsNr = 0;
+    cur->varsMax = 10;
+    cur->vars = NULL;
+    cur->varsBase = 0;
+
+    /*
+     * the profiling stack is not initialized by default
+     */
+    cur->profTab = NULL;
+    cur->profNr = 0;
+    cur->profMax = 0;
+    cur->prof = 0;
+
+    cur->style = style;
+    xmlXPathInit();
+    cur->xpathCtxt = xmlXPathNewContext(doc);
+    if (cur->xpathCtxt == NULL) {
+	xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
+		"xsltNewTransformContext : xmlXPathNewContext failed\n");
+	goto internal_err;
+    }
+    /*
+    * Create an XPath cache.
+    */
+    if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1)
+	goto internal_err;
+    /*
+     * Initialize the extras array
+     */
+    if (style->extrasNr != 0) {
+	cur->extrasMax = style->extrasNr + 20;
+	cur->extras = (xsltRuntimeExtraPtr)
+	    xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra));
+	if (cur->extras == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xsltNewTransformContext: out of memory\n");
+	    goto internal_err;
+	}
+	cur->extrasNr = style->extrasNr;
+	for (i = 0;i < cur->extrasMax;i++) {
+	    cur->extras[i].info = NULL;
+	    cur->extras[i].deallocate = NULL;
+	    cur->extras[i].val.ptr = NULL;
+	}
+    } else {
+	cur->extras = NULL;
+	cur->extrasNr = 0;
+	cur->extrasMax = 0;
+    }
+
+    XSLT_REGISTER_VARIABLE_LOOKUP(cur);
+    XSLT_REGISTER_FUNCTION_LOOKUP(cur);
+    cur->xpathCtxt->nsHash = style->nsHash;
+    /*
+     * Initialize the registered external modules
+     */
+    xsltInitCtxtExts(cur);
+    /*
+     * Setup document element ordering for later efficiencies
+     * (bug 133289)
+     */
+    if (xslDebugStatus == XSLT_DEBUG_NONE)
+        xmlXPathOrderDocElems(doc);
+    /*
+     * Must set parserOptions before calling xsltNewDocument
+     * (bug 164530)
+     */
+    cur->parserOptions = XSLT_PARSE_OPTIONS;
+    docu = xsltNewDocument(cur, doc);
+    if (docu == NULL) {
+	xsltTransformError(cur, NULL, (xmlNodePtr)doc,
+		"xsltNewTransformContext : xsltNewDocument failed\n");
+	goto internal_err;
+    }
+    docu->main = 1;
+    cur->document = docu;
+    cur->inst = NULL;
+    cur->outputFile = NULL;
+    cur->sec = xsltGetDefaultSecurityPrefs();
+    cur->debugStatus = xslDebugStatus;
+    cur->traceCode = (unsigned long*) &xsltDefaultTrace;
+    cur->xinclude = xsltGetXIncludeDefault();
+    cur->keyInitLevel = 0;
+
+    return(cur);
+
+internal_err:
+    if (cur != NULL)
+	xsltFreeTransformContext(cur);
+    return(NULL);
+}
+
+/**
+ * xsltFreeTransformContext:
+ * @ctxt:  an XSLT parser context
+ *
+ * Free up the memory allocated by @ctxt
+ */
+void
+xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
+    if (ctxt == NULL)
+	return;
+
+    /*
+     * Shutdown the extension modules associated to the stylesheet
+     * used if needed.
+     */
+    xsltShutdownCtxtExts(ctxt);
+
+    if (ctxt->xpathCtxt != NULL) {
+	ctxt->xpathCtxt->nsHash = NULL;
+	xmlXPathFreeContext(ctxt->xpathCtxt);
+    }
+    if (ctxt->templTab != NULL)
+	xmlFree(ctxt->templTab);
+    if (ctxt->varsTab != NULL)
+	xmlFree(ctxt->varsTab);
+    if (ctxt->profTab != NULL)
+	xmlFree(ctxt->profTab);
+    if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) {
+	int i;
+
+	for (i = 0;i < ctxt->extrasNr;i++) {
+	    if ((ctxt->extras[i].deallocate != NULL) &&
+		(ctxt->extras[i].info != NULL))
+		ctxt->extras[i].deallocate(ctxt->extras[i].info);
+	}
+	xmlFree(ctxt->extras);
+    }
+    xsltFreeGlobalVariables(ctxt);
+    xsltFreeDocuments(ctxt);
+    xsltFreeCtxtExts(ctxt);
+    xsltFreeRVTs(ctxt);
+    xsltTransformCacheFree(ctxt->cache);
+    xmlDictFree(ctxt->dict);
+#ifdef WITH_XSLT_DEBUG
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "freeing transformation dictionary\n");
+#endif
+    memset(ctxt, -1, sizeof(xsltTransformContext));
+    xmlFree(ctxt);
+}
+
+/************************************************************************
+ *									*
+ *			Copy of Nodes in an XSLT fashion		*
+ *									*
+ ************************************************************************/
+
+xmlNodePtr xsltCopyTree(xsltTransformContextPtr ctxt,
+                        xmlNodePtr node, xmlNodePtr insert, int literal);
+
+/**
+ * xsltAddChild:
+ * @parent:  the parent node
+ * @cur:  the child node
+ *
+ * Wrapper version of xmlAddChild with a more consistent behaviour on
+ * error. One expect the use to be child = xsltAddChild(parent, child);
+ * and the routine will take care of not leaking on errors or node merge
+ *
+ * Returns the child is successfully attached or NULL if merged or freed
+ */
+static xmlNodePtr
+xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) {
+   xmlNodePtr ret;
+
+   if ((cur == NULL) || (parent == NULL))
+       return(NULL);
+   if (parent == NULL) {
+       xmlFreeNode(cur);
+       return(NULL);
+   }
+   ret = xmlAddChild(parent, cur);
+
+   return(ret);
+}
+
+/**
+ * xsltAddTextString:
+ * @ctxt:  a XSLT process context
+ * @target:  the text node where the text will be attached
+ * @string:  the text string
+ * @len:  the string length in byte
+ *
+ * Extend the current text node with the new string, it handles coalescing
+ *
+ * Returns: the text node
+ */
+static xmlNodePtr
+xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
+		  const xmlChar *string, int len) {
+    /*
+     * optimization
+     */
+    if ((len <= 0) || (string == NULL) || (target == NULL))
+        return(target);
+
+    if (ctxt->lasttext == target->content) {
+
+	if (ctxt->lasttuse + len >= ctxt->lasttsize) {
+	    xmlChar *newbuf;
+	    int size;
+
+	    size = ctxt->lasttsize + len + 100;
+	    size *= 2;
+	    newbuf = (xmlChar *) xmlRealloc(target->content,size);
+	    if (newbuf == NULL) {
+		xsltTransformError(ctxt, NULL, target,
+		 "xsltCopyText: text allocation failed\n");
+		return(NULL);
+	    }
+	    ctxt->lasttsize = size;
+	    ctxt->lasttext = newbuf;
+	    target->content = newbuf;
+	}
+	memcpy(&(target->content[ctxt->lasttuse]), string, len);
+	ctxt->lasttuse += len;
+	target->content[ctxt->lasttuse] = 0;
+    } else {
+	xmlNodeAddContent(target, string);
+	ctxt->lasttext = target->content;
+	len = xmlStrlen(target->content);
+	ctxt->lasttsize = len;
+	ctxt->lasttuse = len;
+    }
+    return(target);
+}
+
+/**
+ * xsltCopyTextString:
+ * @ctxt:  a XSLT process context
+ * @target:  the element where the text will be attached
+ * @string:  the text string
+ * @noescape:  should disable-escaping be activated for this text node.
+ *
+ * Adds @string to a newly created or an existent text node child of
+ * @target.
+ *
+ * Returns: the text node, where the text content of @cur is copied to.
+ *          NULL in case of API or internal errors.
+ */
+xmlNodePtr
+xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target,
+	           const xmlChar *string, int noescape)
+{
+    xmlNodePtr copy;
+    int len;
+
+    if (string == NULL)
+	return(NULL);
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltCopyTextString: copy text %s\n",
+		     string));
+#endif
+
+    /*
+    * Play save and reset the merging mechanism for every new
+    * target node.
+    */
+    if ((target == NULL) || (target->children == NULL)) {
+	ctxt->lasttext = NULL;
+    }
+
+    /* handle coalescing of text nodes here */
+    len = xmlStrlen(string);
+    if ((ctxt->type == XSLT_OUTPUT_XML) &&
+	(ctxt->style->cdataSection != NULL) &&
+	(target != NULL) &&
+	(target->type == XML_ELEMENT_NODE) &&
+	(((target->ns == NULL) &&
+	  (xmlHashLookup2(ctxt->style->cdataSection,
+		          target->name, NULL) != NULL)) ||
+	 ((target->ns != NULL) &&
+	  (xmlHashLookup2(ctxt->style->cdataSection,
+	                  target->name, target->ns->href) != NULL))))
+    {
+	/*
+	* Process "cdata-section-elements".
+	*/
+	if ((target->last != NULL) &&
+	    (target->last->type == XML_CDATA_SECTION_NODE))
+	{
+	    return(xsltAddTextString(ctxt, target->last, string, len));
+	}
+	copy = xmlNewCDataBlock(ctxt->output, string, len);
+    } else if (noescape) {
+	/*
+	* Process "disable-output-escaping".
+	*/
+	if ((target != NULL) && (target->last != NULL) &&
+	    (target->last->type == XML_TEXT_NODE) &&
+	    (target->last->name == xmlStringTextNoenc))
+	{
+	    return(xsltAddTextString(ctxt, target->last, string, len));
+	}
+	copy = xmlNewTextLen(string, len);
+	if (copy != NULL)
+	    copy->name = xmlStringTextNoenc;
+    } else {
+	/*
+	* Default processing.
+	*/
+	if ((target != NULL) && (target->last != NULL) &&
+	    (target->last->type == XML_TEXT_NODE) &&
+	    (target->last->name == xmlStringText)) {
+	    return(xsltAddTextString(ctxt, target->last, string, len));
+	}
+	copy = xmlNewTextLen(string, len);
+    }
+    if (copy != NULL) {
+	if (target != NULL)
+	    copy = xsltAddChild(target, copy);
+	ctxt->lasttext = copy->content;
+	ctxt->lasttsize = len;
+	ctxt->lasttuse = len;
+    } else {
+	xsltTransformError(ctxt, NULL, target,
+			 "xsltCopyTextString: text copy failed\n");
+	ctxt->lasttext = NULL;
+    }
+    return(copy);
+}
+
+/**
+ * xsltCopyText:
+ * @ctxt:  a XSLT process context
+ * @target:  the element where the text will be attached
+ * @cur:  the text or CDATA node
+ * @interned:  the string is in the target doc dictionary
+ *
+ * Copy the text content of @cur and append it to @target's children.
+ *
+ * Returns: the text node, where the text content of @cur is copied to.
+ *          NULL in case of API or internal errors.
+ */
+static xmlNodePtr
+xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target,
+	     xmlNodePtr cur, int interned)
+{
+    xmlNodePtr copy;
+
+    if ((cur->type != XML_TEXT_NODE) &&
+	(cur->type != XML_CDATA_SECTION_NODE))
+	return(NULL);
+    if (cur->content == NULL)
+	return(NULL);
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    if (cur->type == XML_CDATA_SECTION_NODE) {
+	XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
+			 "xsltCopyText: copy CDATA text %s\n",
+			 cur->content));
+    } else if (cur->name == xmlStringTextNoenc) {
+	XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltCopyText: copy unescaped text %s\n",
+			 cur->content));
+    } else {
+	XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext,
+			 "xsltCopyText: copy text %s\n",
+			 cur->content));
+    }
+#endif
+
+    /*
+    * Play save and reset the merging mechanism for every new
+    * target node.
+    */
+    if ((target == NULL) || (target->children == NULL)) {
+	ctxt->lasttext = NULL;
+    }
+
+    if ((ctxt->style->cdataSection != NULL) &&
+	(ctxt->type == XSLT_OUTPUT_XML) &&
+	(target != NULL) &&
+	(target->type == XML_ELEMENT_NODE) &&
+	(((target->ns == NULL) &&
+	  (xmlHashLookup2(ctxt->style->cdataSection,
+		          target->name, NULL) != NULL)) ||
+	 ((target->ns != NULL) &&
+	  (xmlHashLookup2(ctxt->style->cdataSection,
+	                  target->name, target->ns->href) != NULL))))
+    {
+	/*
+	* Process "cdata-section-elements".
+	*/
+	/*
+	* OPTIMIZE TODO: xsltCopyText() is also used for attribute content.
+	*/
+	/*
+	* TODO: Since this doesn't merge adjacent CDATA-section nodes,
+	* we'll get: <![CDATA[x]]><!CDATA[y]]>.
+	* TODO: Reported in #321505.
+	*/
+	if ((target->last != NULL) &&
+	     (target->last->type == XML_CDATA_SECTION_NODE))
+	{
+	    /*
+	    * Append to existing CDATA-section node.
+	    */
+	    copy = xsltAddTextString(ctxt, target->last, cur->content,
+		xmlStrlen(cur->content));
+	    goto exit;
+	} else {
+	    unsigned int len;
+
+	    len = xmlStrlen(cur->content);
+	    copy = xmlNewCDataBlock(ctxt->output, cur->content, len);
+	    if (copy == NULL)
+		goto exit;
+	    ctxt->lasttext = copy->content;
+	    ctxt->lasttsize = len;
+	    ctxt->lasttuse = len;
+	}
+    } else if ((target != NULL) &&
+	(target->last != NULL) &&
+	/* both escaped or both non-escaped text-nodes */
+	(((target->last->type == XML_TEXT_NODE) &&
+	(target->last->name == cur->name)) ||
+        /* non-escaped text nodes and CDATA-section nodes */
+	(((target->last->type == XML_CDATA_SECTION_NODE) &&
+	(cur->name == xmlStringTextNoenc)))))
+    {
+	/*
+	 * we are appending to an existing text node
+	 */
+	copy = xsltAddTextString(ctxt, target->last, cur->content,
+	    xmlStrlen(cur->content));
+	goto exit;
+    } else if ((interned) && (target != NULL) &&
+	(target->doc != NULL) &&
+	(target->doc->dict == ctxt->dict))
+    {
+	/*
+	* TODO: DO we want to use this also for "text" output?
+	*/
+        copy = xmlNewTextLen(NULL, 0);
+	if (copy == NULL)
+	    goto exit;
+	if (cur->name == xmlStringTextNoenc)
+	    copy->name = xmlStringTextNoenc;
+
+	/*
+	 * Must confirm that content is in dict (bug 302821)
+	 * TODO: This check should be not needed for text coming
+	 * from the stylesheets
+	 */
+	if (xmlDictOwns(ctxt->dict, cur->content))
+	    copy->content = cur->content;
+	else {
+	    if ((copy->content = xmlStrdup(cur->content)) == NULL)
+		return NULL;
+	}
+    } else {
+        /*
+	 * normal processing. keep counters to extend the text node
+	 * in xsltAddTextString if needed.
+	 */
+        unsigned int len;
+
+	len = xmlStrlen(cur->content);
+	copy = xmlNewTextLen(cur->content, len);
+	if (copy == NULL)
+	    goto exit;
+	if (cur->name == xmlStringTextNoenc)
+	    copy->name = xmlStringTextNoenc;
+	ctxt->lasttext = copy->content;
+	ctxt->lasttsize = len;
+	ctxt->lasttuse = len;
+    }
+    if (copy != NULL) {
+	if (target != NULL) {
+	    copy->doc = target->doc;
+	    /*
+	    * MAYBE TODO: Maybe we should reset the ctxt->lasttext here
+	    *  to ensure that the optimized text-merging mechanism
+	    *  won't interfere with normal node-merging in any case.
+	    */
+	    copy = xsltAddChild(target, copy);
+	}
+    } else {
+	xsltTransformError(ctxt, NULL, target,
+			 "xsltCopyText: text copy failed\n");
+    }
+
+exit:
+    if ((copy == NULL) || (copy->content == NULL)) {
+	xsltTransformError(ctxt, NULL, target,
+	    "Internal error in xsltCopyText(): "
+	    "Failed to copy the string.\n");
+	ctxt->state = XSLT_STATE_STOPPED;
+    }
+    return(copy);
+}
+
+/**
+ * xsltShallowCopyAttr:
+ * @ctxt:  a XSLT process context
+ * @invocNode: responsible node in the stylesheet; used for error reports
+ * @target:  the element where the attribute will be grafted
+ * @attr: the attribute to be copied
+ *
+ * Do a copy of an attribute.
+ * Called by:
+ *  - xsltCopyTreeInternal()
+ *  - xsltCopyOf()
+ *  - xsltCopy()
+ *
+ * Returns: a new xmlAttrPtr, or NULL in case of error.
+ */
+static xmlAttrPtr
+xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
+	     xmlNodePtr target, xmlAttrPtr attr)
+{
+    xmlAttrPtr copy;
+    xmlChar *value;
+
+    if (attr == NULL)
+	return(NULL);
+
+    if (target->type != XML_ELEMENT_NODE) {
+	xsltTransformError(ctxt, NULL, invocNode,
+	    "Cannot add an attribute node to a non-element node.\n");
+	return(NULL);
+    }
+
+    if (target->children != NULL) {
+	xsltTransformError(ctxt, NULL, invocNode,
+	    "Attribute nodes must be added before "
+	    "any child nodes to an element.\n");
+	return(NULL);
+    }
+
+    value = xmlNodeListGetString(attr->doc, attr->children, 1);
+    if (attr->ns != NULL) {
+	xmlNsPtr ns;
+
+	ns = xsltGetSpecialNamespace(ctxt, invocNode,
+	    attr->ns->href, attr->ns->prefix, target);
+	if (ns == NULL) {
+	    xsltTransformError(ctxt, NULL, invocNode,
+		"Namespace fixup error: Failed to acquire an in-scope "
+		"namespace binding of the copied attribute '{%s}%s'.\n",
+		attr->ns->href, attr->name);
+	    /*
+	    * TODO: Should we just stop here?
+	    */
+	}
+	/*
+	* Note that xmlSetNsProp() will take care of duplicates
+	* and assigns the new namespace even to a duplicate.
+	*/
+	copy = xmlSetNsProp(target, ns, attr->name, value);
+    } else {
+	copy = xmlSetNsProp(target, NULL, attr->name, value);
+    }
+    if (value != NULL)
+	xmlFree(value);
+
+    if (copy == NULL)
+	return(NULL);
+
+#if 0
+    /*
+    * NOTE: This was optimized according to bug #342695.
+    * TODO: Can this further be optimized, if source and target
+    *  share the same dict and attr->children is just 1 text node
+    *  which is in the dict? How probable is such a case?
+    */
+    /*
+    * TODO: Do we need to create an empty text node if the value
+    *  is the empty string?
+    */
+    value = xmlNodeListGetString(attr->doc, attr->children, 1);
+    if (value != NULL) {
+	txtNode = xmlNewDocText(target->doc, NULL);
+	if (txtNode == NULL)
+	    return(NULL);
+	if ((target->doc != NULL) &&
+	    (target->doc->dict != NULL))
+	{
+	    txtNode->content =
+		(xmlChar *) xmlDictLookup(target->doc->dict,
+		    BAD_CAST value, -1);
+	    xmlFree(value);
+	} else
+	    txtNode->content = value;
+	copy->children = txtNode;
+    }
+#endif
+
+    return(copy);
+}
+
+/**
+ * xsltCopyAttrListNoOverwrite:
+ * @ctxt:  a XSLT process context
+ * @invocNode: responsible node in the stylesheet; used for error reports
+ * @target:  the element where the new attributes will be grafted
+ * @attr:  the first attribute in the list to be copied
+ *
+ * Copies a list of attribute nodes, starting with @attr, over to the
+ * @target element node.
+ *
+ * Called by:
+ *  - xsltCopyTreeInternal()
+ *
+ * Returns 0 on success and -1 on errors and internal errors.
+ */
+static int
+xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt,
+			    xmlNodePtr invocNode,
+			    xmlNodePtr target, xmlAttrPtr attr)
+{
+    xmlAttrPtr copy;
+    xmlNsPtr origNs = NULL, copyNs = NULL;
+    xmlChar *value;
+
+    /*
+    * Don't use xmlCopyProp() here, since it will try to
+    * reconciliate namespaces.
+    */
+    while (attr != NULL) {
+	/*
+	* Find a namespace node in the tree of @target.
+	* Avoid searching for the same ns.
+	*/
+	if (attr->ns != origNs) {
+	    origNs = attr->ns;
+	    if (attr->ns != NULL) {
+		copyNs = xsltGetSpecialNamespace(ctxt, invocNode,
+		    attr->ns->href, attr->ns->prefix, target);
+		if (copyNs == NULL)
+		    return(-1);
+	    } else
+		copyNs = NULL;
+	}
+	/*
+	 * If attribute has a value, we need to copy it (watching out
+	 * for possible entities)
+	 */
+	if ((attr->children) && (attr->children->type == XML_TEXT_NODE) &&
+            (attr->children->next == NULL)) {
+            copy = xmlNewNsProp(target, copyNs, attr->name,
+                                attr->children->content);
+        } else if (attr->children != NULL) {
+	    value = xmlNodeListGetString(attr->doc, attr->children, 1);
+            copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value);
+	    xmlFree(value);
+        } else {
+            copy = xmlNewNsProp(target, copyNs, attr->name, NULL);
+        }
+
+	if (copy == NULL)
+	    return(-1);
+
+	attr = attr->next;
+    }
+    return(0);
+}
+
+/**
+ * xsltShallowCopyElem:
+ * @ctxt:  the XSLT process context
+ * @node:  the element node in the source tree
+ *         or the Literal Result Element
+ * @insert:  the parent in the result tree
+ * @isLRE: if @node is a Literal Result Element
+ *
+ * Make a copy of the element node @node
+ * and insert it as last child of @insert.
+ *
+ * URGENT TODO: The problem with this one (for the non-refactored code)
+ * is that it is used for both, Literal Result Elements *and*
+ * copying input nodes.
+ *
+ * BIG NOTE: This is only called for XML_ELEMENT_NODEs.
+ *
+ * Called from:
+ *   xsltApplySequenceConstructor()
+ *    (for Literal Result Elements - which is a problem)
+ *   xsltCopy() (for shallow-copying elements via xsl:copy)
+ *
+ * Returns a pointer to the new node, or NULL in case of error
+ */
+static xmlNodePtr
+xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
+		    xmlNodePtr insert, int isLRE)
+{
+    xmlNodePtr copy;
+
+    if ((node->type == XML_DTD_NODE) || (insert == NULL))
+	return(NULL);
+    if ((node->type == XML_TEXT_NODE) ||
+	(node->type == XML_CDATA_SECTION_NODE))
+	return(xsltCopyText(ctxt, insert, node, 0));
+
+    copy = xmlDocCopyNode(node, insert->doc, 0);
+    if (copy != NULL) {
+	copy->doc = ctxt->output;
+	copy = xsltAddChild(insert, copy);
+
+	if (node->type == XML_ELEMENT_NODE) {
+	    /*
+	     * Add namespaces as they are needed
+	     */
+	    if (node->nsDef != NULL) {
+		/*
+		* TODO: Remove the LRE case in the refactored code
+		* gets enabled.
+		*/
+		if (isLRE)
+		    xsltCopyNamespaceList(ctxt, copy, node->nsDef);
+		else
+		    xsltCopyNamespaceListInternal(copy, node->nsDef);
+	    }
+
+	    /*
+	    * URGENT TODO: The problem with this is that it does not
+	    *  copy over all namespace nodes in scope.
+	    *  The damn thing about this is, that we would need to
+	    *  use the xmlGetNsList(), for every single node; this is
+	    *  also done in xsltCopyTreeInternal(), but only for the top node.
+	    */
+	    if (node->ns != NULL) {
+		if (isLRE) {
+		    /*
+		    * REVISIT TODO: Since the non-refactored code still does
+		    *  ns-aliasing, we need to call xsltGetNamespace() here.
+		    *  Remove this when ready.
+		    */
+		    copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy);
+		} else {
+		    copy->ns = xsltGetSpecialNamespace(ctxt,
+			node, node->ns->href, node->ns->prefix, copy);
+
+		}
+	    } else if ((insert->type == XML_ELEMENT_NODE) &&
+		       (insert->ns != NULL))
+	    {
+		/*
+		* "Undeclare" the default namespace.
+		*/
+		xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy);
+	    }
+	}
+    } else {
+	xsltTransformError(ctxt, NULL, node,
+		"xsltShallowCopyElem: copy %s failed\n", node->name);
+    }
+    return(copy);
+}
+
+/**
+ * xsltCopyTreeList:
+ * @ctxt:  a XSLT process context
+ * @invocNode: responsible node in the stylesheet; used for error reports
+ * @list:  the list of element nodes in the source tree.
+ * @insert:  the parent in the result tree.
+ * @isLRE:  is this a literal result element list
+ * @topElemVisited: indicates if a top-most element was already processed
+ *
+ * Make a copy of the full list of tree @list
+ * and insert it as last children of @insert
+ *
+ * NOTE: Not to be used for Literal Result Elements.
+ *
+ * Used by:
+ *  - xsltCopyOf()
+ *
+ * Returns a pointer to the new list, or NULL in case of error
+ */
+static xmlNodePtr
+xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode,
+		 xmlNodePtr list,
+		 xmlNodePtr insert, int isLRE, int topElemVisited)
+{
+    xmlNodePtr copy, ret = NULL;
+
+    while (list != NULL) {
+	copy = xsltCopyTreeInternal(ctxt, invocNode,
+	    list, insert, isLRE, topElemVisited);
+	if (copy != NULL) {
+	    if (ret == NULL) {
+		ret = copy;
+	    }
+	}
+	list = list->next;
+    }
+    return(ret);
+}
+
+/**
+ * xsltCopyNamespaceListInternal:
+ * @node:  the target node
+ * @cur:  the first namespace
+ *
+ * Do a copy of a namespace list. If @node is non-NULL the
+ * new namespaces are added automatically.
+ * Called by:
+ *   xsltCopyTreeInternal()
+ *
+ * QUESTION: What is the exact difference between this function
+ *  and xsltCopyNamespaceList() in "namespaces.c"?
+ * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases.
+ *
+ * Returns: a new xmlNsPtr, or NULL in case of error.
+ */
+static xmlNsPtr
+xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) {
+    xmlNsPtr ret = NULL;
+    xmlNsPtr p = NULL, q, luNs;
+
+    if (ns == NULL)
+	return(NULL);
+    /*
+     * One can add namespaces only on element nodes
+     */
+    if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE))
+	elem = NULL;
+
+    do {
+	if (ns->type != XML_NAMESPACE_DECL)
+	    break;
+	/*
+	 * Avoid duplicating namespace declarations on the tree.
+	 */
+	if (elem != NULL) {
+	    if ((elem->ns != NULL) &&
+		xmlStrEqual(elem->ns->prefix, ns->prefix) &&
+		xmlStrEqual(elem->ns->href, ns->href))
+	    {
+		ns = ns->next;
+		continue;
+	    }
+	    luNs = xmlSearchNs(elem->doc, elem, ns->prefix);
+	    if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href)))
+	    {
+		ns = ns->next;
+		continue;
+	    }
+	}
+	q = xmlNewNs(elem, ns->href, ns->prefix);
+	if (p == NULL) {
+	    ret = p = q;
+	} else if (q != NULL) {
+	    p->next = q;
+	    p = q;
+	}
+	ns = ns->next;
+    } while (ns != NULL);
+    return(ret);
+}
+
+/**
+ * xsltShallowCopyNsNode:
+ * @ctxt:  the XSLT transformation context
+ * @invocNode: responsible node in the stylesheet; used for error reports
+ * @insert:  the target element node in the result tree
+ * @ns: the namespace node
+ *
+ * This is used for copying ns-nodes with xsl:copy-of and xsl:copy.
+ *
+ * Returns a new/existing ns-node, or NULL.
+ */
+static xmlNsPtr
+xsltShallowCopyNsNode(xsltTransformContextPtr ctxt,
+		      xmlNodePtr invocNode,
+		      xmlNodePtr insert,
+		      xmlNsPtr ns)
+{
+    /*
+     * TODO: Contrary to header comments, this is declared as int.
+     * be modified to return a node pointer, or NULL if any error
+     */
+    xmlNsPtr tmpns;
+
+    if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE))
+	return(NULL);
+
+    if (insert->children != NULL) {
+	xsltTransformError(ctxt, NULL, invocNode,
+	    "Namespace nodes must be added before "
+	    "any child nodes are added to an element.\n");
+	return(NULL);
+    }
+    /*
+     * BIG NOTE: Xalan-J simply overwrites any ns-decls with
+     * an equal prefix. We definitively won't do that.
+     *
+     * MSXML 4.0 and the .NET ignores ns-decls for which an
+     * equal prefix is already in use.
+     *
+     * Saxon raises an error like:
+     * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace
+     * nodes with the same name".
+     *
+     * NOTE: We'll currently follow MSXML here.
+     * REVISIT TODO: Check if it's better to follow Saxon here.
+     */
+    if (ns->prefix == NULL) {
+	/*
+	* If we are adding ns-nodes to an element using e.g.
+	* <xsl:copy-of select="/foo/namespace::*">, then we need
+	* to ensure that we don't incorrectly declare a default
+	* namespace on an element in no namespace, which otherwise
+	* would move the element incorrectly into a namespace, if
+	* the node tree is serialized.
+	*/
+	if (insert->ns == NULL)
+	    goto occupied;
+    } else if ((ns->prefix[0] == 'x') &&
+	xmlStrEqual(ns->prefix, BAD_CAST "xml"))
+    {
+	/*
+	* The XML namespace is built in.
+	*/
+	return(NULL);
+    }
+
+    if (insert->nsDef != NULL) {
+	tmpns = insert->nsDef;
+	do {
+	    if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) {
+		if ((tmpns->prefix == ns->prefix) ||
+		    xmlStrEqual(tmpns->prefix, ns->prefix))
+		{
+		    /*
+		    * Same prefix.
+		    */
+		    if (xmlStrEqual(tmpns->href, ns->href))
+			return(NULL);
+		    goto occupied;
+		}
+	    }
+	    tmpns = tmpns->next;
+	} while (tmpns != NULL);
+    }
+    tmpns = xmlSearchNs(insert->doc, insert, ns->prefix);
+    if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href))
+	return(NULL);
+    /*
+    * Declare a new namespace.
+    * TODO: The problem (wrt efficiency) with this xmlNewNs() is
+    * that it will again search the already declared namespaces
+    * for a duplicate :-/
+    */
+    return(xmlNewNs(insert, ns->href, ns->prefix));
+
+occupied:
+    /*
+    * TODO: We could as well raise an error here (like Saxon does),
+    * or at least generate a warning.
+    */
+    return(NULL);
+}
+
+/**
+ * xsltCopyTreeInternal:
+ * @ctxt:  the XSLT transformation context
+ * @invocNode: responsible node in the stylesheet; used for error reports
+ * @node:  the element node in the source tree
+ * @insert:  the parent in the result tree
+ * @isLRE:  indicates if @node is a Literal Result Element
+ * @topElemVisited: indicates if a top-most element was already processed
+ *
+ * Make a copy of the full tree under the element node @node
+ * and insert it as last child of @insert
+ *
+ * NOTE: Not to be used for Literal Result Elements.
+ *
+ * Used by:
+ *  - xsltCopyOf()
+ *
+ * Returns a pointer to the new tree, or NULL in case of error
+ */
+static xmlNodePtr
+xsltCopyTreeInternal(xsltTransformContextPtr ctxt,
+		     xmlNodePtr invocNode,
+		     xmlNodePtr node,
+		     xmlNodePtr insert, int isLRE, int topElemVisited)
+{
+    xmlNodePtr copy;
+
+    if (node == NULL)
+	return(NULL);
+    switch (node->type) {
+        case XML_ELEMENT_NODE:
+        case XML_ENTITY_REF_NODE:
+        case XML_ENTITY_NODE:
+        case XML_PI_NODE:
+        case XML_COMMENT_NODE:
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+#ifdef LIBXML_DOCB_ENABLED
+        case XML_DOCB_DOCUMENT_NODE:
+#endif
+	    break;
+        case XML_TEXT_NODE: {
+	    int noenc = (node->name == xmlStringTextNoenc);
+	    return(xsltCopyTextString(ctxt, insert, node->content, noenc));
+	    }
+        case XML_CDATA_SECTION_NODE:
+	    return(xsltCopyTextString(ctxt, insert, node->content, 0));
+        case XML_ATTRIBUTE_NODE:
+	    return((xmlNodePtr)
+		xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node));
+        case XML_NAMESPACE_DECL:
+	    return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode,
+		insert, (xmlNsPtr) node));
+
+        case XML_DOCUMENT_TYPE_NODE:
+        case XML_DOCUMENT_FRAG_NODE:
+        case XML_NOTATION_NODE:
+        case XML_DTD_NODE:
+        case XML_ELEMENT_DECL:
+        case XML_ATTRIBUTE_DECL:
+        case XML_ENTITY_DECL:
+        case XML_XINCLUDE_START:
+        case XML_XINCLUDE_END:
+            return(NULL);
+    }
+    if (XSLT_IS_RES_TREE_FRAG(node)) {
+	if (node->children != NULL)
+	    copy = xsltCopyTreeList(ctxt, invocNode,
+		node->children, insert, 0, 0);
+	else
+	    copy = NULL;
+	return(copy);
+    }
+    copy = xmlDocCopyNode(node, insert->doc, 0);
+    if (copy != NULL) {
+	copy->doc = ctxt->output;
+	copy = xsltAddChild(insert, copy);
+	/*
+	 * The node may have been coalesced into another text node.
+	 */
+	if (insert->last != copy)
+	    return(insert->last);
+	copy->next = NULL;
+
+	if (node->type == XML_ELEMENT_NODE) {
+	    /*
+	    * Copy in-scope namespace nodes.
+	    *
+	    * REVISIT: Since we try to reuse existing in-scope ns-decls by
+	    *  using xmlSearchNsByHref(), this will eventually change
+	    *  the prefix of an original ns-binding; thus it might
+	    *  break QNames in element/attribute content.
+	    * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation
+	    *  context, plus a ns-lookup function, which writes directly
+	    *  to a given list, then we wouldn't need to create/free the
+	    *  nsList every time.
+	    */
+	    if ((topElemVisited == 0) &&
+		(node->parent != NULL) &&
+		(node->parent->type != XML_DOCUMENT_NODE) &&
+		(node->parent->type != XML_HTML_DOCUMENT_NODE))
+	    {
+		xmlNsPtr *nsList, *curns, ns;
+
+		/*
+		* If this is a top-most element in a tree to be
+		* copied, then we need to ensure that all in-scope
+		* namespaces are copied over. For nodes deeper in the
+		* tree, it is sufficient to reconcile only the ns-decls
+		* (node->nsDef entries).
+		*/
+
+		nsList = xmlGetNsList(node->doc, node);
+		if (nsList != NULL) {
+		    curns = nsList;
+		    do {
+			/*
+			* Search by prefix first in order to break as less
+			* QNames in element/attribute content as possible.
+			*/
+			ns = xmlSearchNs(insert->doc, insert,
+			    (*curns)->prefix);
+
+			if ((ns == NULL) ||
+			    (! xmlStrEqual(ns->href, (*curns)->href)))
+			{
+			    ns = NULL;
+			    /*
+			    * Search by namespace name.
+			    * REVISIT TODO: Currently disabled.
+			    */
+#if 0
+			    ns = xmlSearchNsByHref(insert->doc,
+				insert, (*curns)->href);
+#endif
+			}
+			if (ns == NULL) {
+			    /*
+			    * Declare a new namespace on the copied element.
+			    */
+			    ns = xmlNewNs(copy, (*curns)->href,
+				(*curns)->prefix);
+			    /* TODO: Handle errors */
+			}
+			if (node->ns == *curns) {
+			    /*
+			    * If this was the original's namespace then set
+			    * the generated counterpart on the copy.
+			    */
+			    copy->ns = ns;
+			}
+			curns++;
+		    } while (*curns != NULL);
+		    xmlFree(nsList);
+		}
+	    } else if (node->nsDef != NULL) {
+		/*
+		* Copy over all namespace declaration attributes.
+		*/
+		if (node->nsDef != NULL) {
+		    if (isLRE)
+			xsltCopyNamespaceList(ctxt, copy, node->nsDef);
+		    else
+			xsltCopyNamespaceListInternal(copy, node->nsDef);
+		}
+	    }
+	    /*
+	    * Set the namespace.
+	    */
+	    if (node->ns != NULL) {
+		if (copy->ns == NULL) {
+		    /*
+		    * This will map copy->ns to one of the newly created
+		    * in-scope ns-decls, OR create a new ns-decl on @copy.
+		    */
+		    copy->ns = xsltGetSpecialNamespace(ctxt, invocNode,
+			node->ns->href, node->ns->prefix, copy);
+		}
+	    } else if ((insert->type == XML_ELEMENT_NODE) &&
+		(insert->ns != NULL))
+	    {
+		/*
+		* "Undeclare" the default namespace on @copy with xmlns="".
+		*/
+		xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy);
+	    }
+	    /*
+	    * Copy attribute nodes.
+	    */
+	    if (node->properties != NULL) {
+		xsltCopyAttrListNoOverwrite(ctxt, invocNode,
+		    copy, node->properties);
+	    }
+	    if (topElemVisited == 0)
+		topElemVisited = 1;
+	}
+	/*
+	* Copy the subtree.
+	*/
+	if (node->children != NULL) {
+	    xsltCopyTreeList(ctxt, invocNode,
+		node->children, copy, isLRE, topElemVisited);
+	}
+    } else {
+	xsltTransformError(ctxt, NULL, invocNode,
+	    "xsltCopyTreeInternal: Copying of '%s' failed.\n", node->name);
+    }
+    return(copy);
+}
+
+/**
+ * xsltCopyTree:
+ * @ctxt:  the XSLT transformation context
+ * @node:  the element node in the source tree
+ * @insert:  the parent in the result tree
+ * @literal:  indicates if @node is a Literal Result Element
+ *
+ * Make a copy of the full tree under the element node @node
+ * and insert it as last child of @insert
+ * For literal result element, some of the namespaces may not be copied
+ * over according to section 7.1.
+ * TODO: Why is this a public function?
+ *
+ * Returns a pointer to the new tree, or NULL in case of error
+ */
+xmlNodePtr
+xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	     xmlNodePtr insert, int literal)
+{
+    return(xsltCopyTreeInternal(ctxt, node, node, insert, literal, 0));
+
+}
+
+/************************************************************************
+ *									*
+ *		Error/fallback processing				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltApplyFallbacks:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the node generating the error
+ *
+ * Process possible xsl:fallback nodes present under @inst
+ *
+ * Returns the number of xsl:fallback element found and processed
+ */
+static int
+xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	           xmlNodePtr inst) {
+
+    xmlNodePtr child;
+    int ret = 0;
+
+    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) ||
+	(inst->children == NULL))
+	return(0);
+
+    child = inst->children;
+    while (child != NULL) {
+        if ((IS_XSLT_ELEM(child)) &&
+            (xmlStrEqual(child->name, BAD_CAST "fallback"))) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+	    xsltGenericDebug(xsltGenericDebugContext,
+			     "applying xsl:fallback\n");
+#endif
+	    ret++;
+	    xsltApplySequenceConstructor(ctxt, node, child->children,
+		NULL);
+	}
+	child = child->next;
+    }
+    return(ret);
+}
+
+/************************************************************************
+ *									*
+ *			Default processing				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltDefaultProcessOneNode:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @params: extra parameters passed to the template if any
+ *
+ * Process the source node with the default built-in template rule:
+ * <xsl:template match="*|/">
+ *   <xsl:apply-templates/>
+ * </xsl:template>
+ *
+ * and
+ *
+ * <xsl:template match="text()|@*">
+ *   <xsl:value-of select="."/>
+ * </xsl:template>
+ *
+ * Note also that namespace declarations are copied directly:
+ *
+ * the built-in template rule is the only template rule that is applied
+ * for namespace nodes.
+ */
+static void
+xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
+			  xsltStackElemPtr params) {
+    xmlNodePtr copy;
+    xmlNodePtr delete = NULL, cur;
+    int nbchild = 0, oldSize;
+    int childno = 0, oldPos;
+    xsltTemplatePtr template;
+
+    CHECK_STOPPED;
+    /*
+     * Handling of leaves
+     */
+    switch (node->type) {
+	case XML_DOCUMENT_NODE:
+	case XML_HTML_DOCUMENT_NODE:
+	case XML_ELEMENT_NODE:
+	    break;
+	case XML_CDATA_SECTION_NODE:
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltDefaultProcessOneNode: copy CDATA %s\n",
+		node->content));
+#endif
+	    copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
+	    if (copy == NULL) {
+		xsltTransformError(ctxt, NULL, node,
+		 "xsltDefaultProcessOneNode: cdata copy failed\n");
+	    }
+	    return;
+	case XML_TEXT_NODE:
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	    if (node->content == NULL) {
+		XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+		 "xsltDefaultProcessOneNode: copy empty text\n"));
+		return;
+	    } else {
+		XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+		 "xsltDefaultProcessOneNode: copy text %s\n",
+			node->content));
+            }
+#endif
+	    copy = xsltCopyText(ctxt, ctxt->insert, node, 0);
+	    if (copy == NULL) {
+		xsltTransformError(ctxt, NULL, node,
+		 "xsltDefaultProcessOneNode: text copy failed\n");
+	    }
+	    return;
+	case XML_ATTRIBUTE_NODE:
+	    cur = node->children;
+	    while ((cur != NULL) && (cur->type != XML_TEXT_NODE))
+		cur = cur->next;
+	    if (cur == NULL) {
+		xsltTransformError(ctxt, NULL, node,
+		 "xsltDefaultProcessOneNode: no text for attribute\n");
+	    } else {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		if (cur->content == NULL) {
+		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltDefaultProcessOneNode: copy empty text\n"));
+		} else {
+		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltDefaultProcessOneNode: copy text %s\n",
+			cur->content));
+                }
+#endif
+		copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
+		if (copy == NULL) {
+		    xsltTransformError(ctxt, NULL, node,
+		     "xsltDefaultProcessOneNode: text copy failed\n");
+		}
+	    }
+	    return;
+	default:
+	    return;
+    }
+    /*
+     * Handling of Elements: first pass, cleanup and counting
+     */
+    cur = node->children;
+    while (cur != NULL) {
+	switch (cur->type) {
+	    case XML_TEXT_NODE:
+	    case XML_CDATA_SECTION_NODE:
+	    case XML_DOCUMENT_NODE:
+	    case XML_HTML_DOCUMENT_NODE:
+	    case XML_ELEMENT_NODE:
+	    case XML_PI_NODE:
+	    case XML_COMMENT_NODE:
+		nbchild++;
+		break;
+            case XML_DTD_NODE:
+		/* Unlink the DTD, it's still reachable using doc->intSubset */
+		if (cur->next != NULL)
+		    cur->next->prev = cur->prev;
+		if (cur->prev != NULL)
+		    cur->prev->next = cur->next;
+		break;
+	    default:
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+		 "xsltDefaultProcessOneNode: skipping node type %d\n",
+		                 cur->type));
+#endif
+		delete = cur;
+	}
+	cur = cur->next;
+	if (delete != NULL) {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+		 "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
+#endif
+	    xmlUnlinkNode(delete);
+	    xmlFreeNode(delete);
+	    delete = NULL;
+	}
+    }
+    if (delete != NULL) {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltDefaultProcessOneNode: removing ignorable blank node\n"));
+#endif
+	xmlUnlinkNode(delete);
+	xmlFreeNode(delete);
+	delete = NULL;
+    }
+
+    /*
+     * Handling of Elements: second pass, actual processing
+     */
+    oldSize = ctxt->xpathCtxt->contextSize;
+    oldPos = ctxt->xpathCtxt->proximityPosition;
+    cur = node->children;
+    while (cur != NULL) {
+	childno++;
+	switch (cur->type) {
+	    case XML_DOCUMENT_NODE:
+	    case XML_HTML_DOCUMENT_NODE:
+	    case XML_ELEMENT_NODE:
+		ctxt->xpathCtxt->contextSize = nbchild;
+		ctxt->xpathCtxt->proximityPosition = childno;
+		xsltProcessOneNode(ctxt, cur, params);
+		break;
+	    case XML_CDATA_SECTION_NODE:
+		template = xsltGetTemplate(ctxt, cur, NULL);
+		if (template) {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+		 "xsltDefaultProcessOneNode: applying template for CDATA %s\n",
+				     cur->content));
+#endif
+		    /*
+		    * Instantiate the xsl:template.
+		    */
+		    xsltApplyXSLTTemplate(ctxt, cur, template->content,
+			template, params);
+		} else /* if (ctxt->mode == NULL) */ {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltDefaultProcessOneNode: copy CDATA %s\n",
+				     cur->content));
+#endif
+		    copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
+		    if (copy == NULL) {
+			xsltTransformError(ctxt, NULL, cur,
+			    "xsltDefaultProcessOneNode: cdata copy failed\n");
+		    }
+		}
+		break;
+	    case XML_TEXT_NODE:
+		template = xsltGetTemplate(ctxt, cur, NULL);
+		if (template) {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltDefaultProcessOneNode: applying template for text %s\n",
+				     cur->content));
+#endif
+		    ctxt->xpathCtxt->contextSize = nbchild;
+		    ctxt->xpathCtxt->proximityPosition = childno;
+		    /*
+		    * Instantiate the xsl:template.
+		    */
+		    xsltApplyXSLTTemplate(ctxt, cur, template->content,
+			template, params);
+		} else /* if (ctxt->mode == NULL) */ {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		    if (cur->content == NULL) {
+			XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+			 "xsltDefaultProcessOneNode: copy empty text\n"));
+		    } else {
+			XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltDefaultProcessOneNode: copy text %s\n",
+					 cur->content));
+                    }
+#endif
+		    copy = xsltCopyText(ctxt, ctxt->insert, cur, 0);
+		    if (copy == NULL) {
+			xsltTransformError(ctxt, NULL, cur,
+			    "xsltDefaultProcessOneNode: text copy failed\n");
+		    }
+		}
+		break;
+	    case XML_PI_NODE:
+	    case XML_COMMENT_NODE:
+		template = xsltGetTemplate(ctxt, cur, NULL);
+		if (template) {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		    if (cur->type == XML_PI_NODE) {
+			XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltDefaultProcessOneNode: template found for PI %s\n",
+			                 cur->name));
+		    } else if (cur->type == XML_COMMENT_NODE) {
+			XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltDefaultProcessOneNode: template found for comment\n"));
+                    }
+#endif
+		    ctxt->xpathCtxt->contextSize = nbchild;
+		    ctxt->xpathCtxt->proximityPosition = childno;
+		    /*
+		    * Instantiate the xsl:template.
+		    */
+		    xsltApplyXSLTTemplate(ctxt, cur, template->content,
+			template, params);
+		}
+		break;
+	    default:
+		break;
+	}
+	cur = cur->next;
+    }
+    ctxt->xpathCtxt->contextSize = oldSize;
+    ctxt->xpathCtxt->proximityPosition = oldPos;
+}
+
+/**
+ * xsltProcessOneNode:
+ * @ctxt:  a XSLT process context
+ * @contextNode:  the "current node" in the source tree
+ * @withParams:  extra parameters (e.g. xsl:with-param) passed to the
+ *               template if any
+ *
+ * Process the source node.
+ */
+void
+xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
+	           xsltStackElemPtr withParams)
+{
+    xsltTemplatePtr templ;
+    xmlNodePtr oldNode;
+
+    templ = xsltGetTemplate(ctxt, contextNode, NULL);
+    /*
+     * If no template is found, apply the default rule.
+     */
+    if (templ == NULL) {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	if (contextNode->type == XML_DOCUMENT_NODE) {
+	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltProcessOneNode: no template found for /\n"));
+	} else if (contextNode->type == XML_CDATA_SECTION_NODE) {
+	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltProcessOneNode: no template found for CDATA\n"));
+	} else if (contextNode->type == XML_ATTRIBUTE_NODE) {
+	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltProcessOneNode: no template found for attribute %s\n",
+	                     ((xmlAttrPtr) contextNode)->name));
+	} else  {
+	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltProcessOneNode: no template found for %s\n", contextNode->name));
+        }
+#endif
+	oldNode = ctxt->node;
+	ctxt->node = contextNode;
+	xsltDefaultProcessOneNode(ctxt, contextNode, withParams);
+	ctxt->node = oldNode;
+	return;
+    }
+
+    if (contextNode->type == XML_ATTRIBUTE_NODE) {
+	xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
+	/*
+	* Set the "current template rule".
+	*/
+	ctxt->currentTemplateRule = templ;
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltProcessOneNode: applying template '%s' for attribute %s\n",
+	                 templ->match, contextNode->name));
+#endif
+	xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
+
+	ctxt->currentTemplateRule = oldCurTempRule;
+    } else {
+	xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule;
+	/*
+	* Set the "current template rule".
+	*/
+	ctxt->currentTemplateRule = templ;
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	if (contextNode->type == XML_DOCUMENT_NODE) {
+	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltProcessOneNode: applying template '%s' for /\n",
+	                     templ->match));
+	} else {
+	    XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltProcessOneNode: applying template '%s' for %s\n",
+	                     templ->match, contextNode->name));
+        }
+#endif
+	xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams);
+
+	ctxt->currentTemplateRule = oldCurTempRule;
+    }
+}
+
+static xmlNodePtr
+xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt,
+				     xmlNodePtr contextNode,
+				     xmlNodePtr list,
+				     xsltTemplatePtr templ,
+				     int *addCallResult)
+{
+    xmlNodePtr debugedNode = NULL;
+
+    if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
+        if (templ) {
+            *addCallResult = xslAddCall(templ, templ->elem);
+        } else {
+            *addCallResult = xslAddCall(NULL, list);
+        }
+        switch (ctxt->debugStatus) {
+            case XSLT_DEBUG_RUN_RESTART:
+            case XSLT_DEBUG_QUIT:
+                if (*addCallResult)
+                    xslDropCall();
+                return(NULL);
+        }
+        if (templ) {
+            xslHandleDebugger(templ->elem, contextNode, templ, ctxt);
+            debugedNode = templ->elem;
+        } else if (list) {
+            xslHandleDebugger(list, contextNode, templ, ctxt);
+            debugedNode = list;
+        } else if (ctxt->inst) {
+            xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt);
+            debugedNode = ctxt->inst;
+        }
+    }
+    return(debugedNode);
+}
+
+/**
+ * xsltLocalVariablePush:
+ * @ctxt: the transformation context
+ * @variable: variable to be pushed to the variable stack
+ * @level: new value for variable's level
+ *
+ * Places the variable onto the local variable stack
+ *
+ * Returns: 0 for success, -1 for any error
+ * **NOTE:**
+ * This is an internal routine and should not be called by users!
+ */
+int
+xsltLocalVariablePush(xsltTransformContextPtr ctxt,
+		      xsltStackElemPtr variable,
+		      int level)
+{
+    if (ctxt->varsMax == 0) {
+	ctxt->varsMax = 10;
+	ctxt->varsTab =
+	    (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
+	    sizeof(ctxt->varsTab[0]));
+	if (ctxt->varsTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
+	    return (-1);
+	}
+    }
+    if (ctxt->varsNr >= ctxt->varsMax) {
+	ctxt->varsMax *= 2;
+	ctxt->varsTab =
+	    (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
+	    ctxt->varsMax *
+	    sizeof(ctxt->varsTab[0]));
+	if (ctxt->varsTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
+	    return (-1);
+	}
+    }
+    ctxt->varsTab[ctxt->varsNr++] = variable;
+    ctxt->vars = variable;
+    variable->level = level;
+    return(0);
+}
+
+/**
+ * xsltReleaseLocalRVTs:
+ *
+ * Fragments which are results of extension instructions
+ * are preserved; all other fragments are freed/cached.
+ */
+static void
+xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base)
+{
+    xmlDocPtr cur = ctxt->localRVT, tmp;
+
+    while ((cur != NULL) && (cur != base)) {
+	if (cur->psvi == (void *) ((long) 1)) {
+	    cur = (xmlDocPtr) cur->next;
+	} else {
+	    tmp = cur;
+	    cur = (xmlDocPtr) cur->next;
+
+	    if (tmp == ctxt->localRVT)
+		ctxt->localRVT = cur;
+
+	    /*
+	    * We need ctxt->localRVTBase for extension instructions
+	    * which return values (like EXSLT's function).
+	    */
+	    if (tmp == ctxt->localRVTBase)
+		ctxt->localRVTBase = cur;
+
+	    if (tmp->prev)
+		tmp->prev->next = (xmlNodePtr) cur;
+	    if (cur)
+		cur->prev = tmp->prev;
+	    xsltReleaseRVT(ctxt, tmp);
+	}
+    }
+}
+
+/**
+ * xsltApplySequenceConstructor:
+ * @ctxt:  a XSLT process context
+ * @contextNode:  the "current node" in the source tree
+ * @list:  the nodes of a sequence constructor;
+ *         (plus leading xsl:param elements)
+ * @templ: the compiled xsl:template (optional)
+ *
+ * Processes a sequence constructor.
+ *
+ * NOTE: ctxt->currentTemplateRule was introduced to reflect the
+ * semantics of "current template rule". I.e. the field ctxt->templ
+ * is not intended to reflect this, thus always pushed onto the
+ * template stack.
+ */
+static void
+xsltApplySequenceConstructor(xsltTransformContextPtr ctxt,
+			     xmlNodePtr contextNode, xmlNodePtr list,
+			     xsltTemplatePtr templ)
+{
+    xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode;
+    xmlNodePtr cur, insert, copy = NULL;
+    int level = 0, oldVarsNr;
+    xmlDocPtr oldLocalFragmentTop, oldLocalFragmentBase;
+
+#ifdef XSLT_REFACTORED
+    xsltStylePreCompPtr info;
+#endif
+
+#ifdef WITH_DEBUGGER
+    int addCallResult = 0;
+    xmlNodePtr debuggedNode = NULL;
+#endif
+
+    if (ctxt == NULL)
+	return;
+
+#ifdef WITH_DEBUGGER
+    if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
+	debuggedNode =
+	    xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
+		list, templ, &addCallResult);
+	if (debuggedNode == NULL)
+	    return;
+    }
+#endif
+
+    if (list == NULL)
+        return;
+    CHECK_STOPPED;
+
+    oldLocalFragmentTop = ctxt->localRVT;
+    oldInsert = insert = ctxt->insert;
+    oldInst = oldCurInst = ctxt->inst;
+    oldContextNode = ctxt->node;
+    /*
+    * Save current number of variables on the stack; new vars are popped when
+    * exiting.
+    */
+    oldVarsNr = ctxt->varsNr;
+    /*
+    * Process the sequence constructor.
+    */
+    cur = list;
+    while (cur != NULL) {
+        ctxt->inst = cur;
+
+#ifdef WITH_DEBUGGER
+        switch (ctxt->debugStatus) {
+            case XSLT_DEBUG_RUN_RESTART:
+            case XSLT_DEBUG_QUIT:
+                break;
+
+        }
+#endif
+        /*
+         * Test; we must have a valid insertion point.
+         */
+        if (insert == NULL) {
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+            XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
+		"xsltApplySequenceConstructor: insert == NULL !\n"));
+#endif
+            goto error;
+        }
+
+#ifdef WITH_DEBUGGER
+        if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur))
+            xslHandleDebugger(cur, contextNode, templ, ctxt);
+#endif
+
+#ifdef XSLT_REFACTORED
+	if (cur->type == XML_ELEMENT_NODE) {
+	    info = (xsltStylePreCompPtr) cur->psvi;
+	    /*
+	    * We expect a compiled representation on:
+	    * 1) XSLT instructions of this XSLT version (1.0)
+	    *    (with a few exceptions)
+	    * 2) Literal result elements
+	    * 3) Extension instructions
+	    * 4) XSLT instructions of future XSLT versions
+	    *    (forwards-compatible mode).
+	    */
+	    if (info == NULL) {
+		/*
+		* Handle the rare cases where we don't expect a compiled
+		* representation on an XSLT element.
+		*/
+		if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) {
+		    xsltMessage(ctxt, contextNode, cur);
+		    goto skip_children;
+		}
+		/*
+		* Something really went wrong:
+		*/
+		xsltTransformError(ctxt, NULL, cur,
+		    "Internal error in xsltApplySequenceConstructor(): "
+		    "The element '%s' in the stylesheet has no compiled "
+		    "representation.\n",
+		    cur->name);
+                goto skip_children;
+            }
+
+	    if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) {
+		xsltStyleItemLRElementInfoPtr lrInfo =
+		    (xsltStyleItemLRElementInfoPtr) info;
+		/*
+		* Literal result elements
+		* --------------------------------------------------------
+		*/
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
+		    xsltGenericDebug(xsltGenericDebugContext,
+		    "xsltApplySequenceConstructor: copy literal result "
+		    "element '%s'\n", cur->name));
+#endif
+		/*
+		* Copy the raw element-node.
+		* OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert))
+		*     == NULL)
+		*   goto error;
+		*/
+		copy = xmlDocCopyNode(cur, insert->doc, 0);
+		if (copy == NULL) {
+		    xsltTransformError(ctxt, NULL, cur,
+			"Internal error in xsltApplySequenceConstructor(): "
+			"Failed to copy literal result element '%s'.\n",
+			cur->name);
+		    goto error;
+		} else {
+		    /*
+		    * Add the element-node to the result tree.
+		    */
+		    copy->doc = ctxt->output;
+		    copy = xsltAddChild(insert, copy);
+		    /*
+		    * Create effective namespaces declarations.
+		    * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef);
+		    */
+		    if (lrInfo->effectiveNs != NULL) {
+			xsltEffectiveNsPtr effNs = lrInfo->effectiveNs;
+			xmlNsPtr ns, lastns = NULL;
+
+			while (effNs != NULL) {
+			    /*
+			    * Avoid generating redundant namespace
+			    * declarations; thus lookup if there is already
+			    * such a ns-decl in the result.
+			    */
+			    ns = xmlSearchNs(copy->doc, copy, effNs->prefix);
+			    if ((ns != NULL) &&
+				(xmlStrEqual(ns->href, effNs->nsName)))
+			    {
+				effNs = effNs->next;
+				continue;
+			    }
+			    ns = xmlNewNs(copy, effNs->nsName, effNs->prefix);
+			    if (ns == NULL) {
+				xsltTransformError(ctxt, NULL, cur,
+				    "Internal error in "
+				    "xsltApplySequenceConstructor(): "
+				    "Failed to copy a namespace "
+				    "declaration.\n");
+				goto error;
+			    }
+
+			    if (lastns == NULL)
+				copy->nsDef = ns;
+			    else
+				lastns->next =ns;
+			    lastns = ns;
+
+			    effNs = effNs->next;
+			}
+
+		    }
+		    /*
+		    * NOTE that we don't need to apply ns-alising: this was
+		    *  already done at compile-time.
+		    */
+		    if (cur->ns != NULL) {
+			/*
+			* If there's no such ns-decl in the result tree,
+			* then xsltGetSpecialNamespace() will
+			* create a ns-decl on the copied node.
+			*/
+			copy->ns = xsltGetSpecialNamespace(ctxt, cur,
+			    cur->ns->href, cur->ns->prefix, copy);
+		    } else {
+			/*
+			* Undeclare the default namespace if needed.
+			* This can be skipped, if the result element has
+			*  no ns-decls, in which case the result element
+			*  obviously does not declare a default namespace;
+			*  AND there's either no parent, or the parent
+			*  element is in no namespace; this means there's no
+			*  default namespace is scope to care about.
+			*
+			* REVISIT: This might result in massive
+			*  generation of ns-decls if nodes in a default
+			*  namespaces are mixed with nodes in no namespace.
+			*
+			*/
+			if (copy->nsDef ||
+			    ((insert != NULL) &&
+			     (insert->type == XML_ELEMENT_NODE) &&
+			     (insert->ns != NULL)))
+			{
+			    xsltGetSpecialNamespace(ctxt, cur,
+				NULL, NULL, copy);
+			}
+		    }
+		}
+		/*
+		* SPEC XSLT 2.0 "Each attribute of the literal result
+		*  element, other than an attribute in the XSLT namespace,
+		*  is processed to produce an attribute for the element in
+		*  the result tree."
+		* NOTE: See bug #341325.
+		*/
+		if (cur->properties != NULL) {
+		    xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
+		}
+	    } else if (IS_XSLT_ELEM_FAST(cur)) {
+		/*
+		* XSLT instructions
+		* --------------------------------------------------------
+		*/
+		if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) {
+		    /*
+		    * We hit an unknown XSLT element.
+		    * Try to apply one of the fallback cases.
+		    */
+		    ctxt->insert = insert;
+		    if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
+			xsltTransformError(ctxt, NULL, cur,
+			    "The is no fallback behaviour defined for "
+			    "the unknown XSLT element '%s'.\n",
+			    cur->name);
+		    }
+		    ctxt->insert = oldInsert;
+		} else if (info->func != NULL) {
+		    /*
+		    * Execute the XSLT instruction.
+		    */
+		    ctxt->insert = insert;
+
+		    info->func(ctxt, contextNode, cur,
+			(xsltElemPreCompPtr) info);
+
+		    /*
+		    * Cleanup temporary tree fragments.
+		    */
+		    if (oldLocalFragmentTop != ctxt->localRVT)
+			xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
+
+		    ctxt->insert = oldInsert;
+		} else if (info->type == XSLT_FUNC_VARIABLE) {
+		    xsltStackElemPtr tmpvar = ctxt->vars;
+
+		    xsltParseStylesheetVariable(ctxt, cur);
+
+		    if (tmpvar != ctxt->vars) {
+			/*
+			* TODO: Using a @tmpvar is an annoying workaround, but
+			*  the current mechanisms do not provide any other way
+			*  of knowing if the var was really pushed onto the
+			*  stack.
+			*/
+			ctxt->vars->level = level;
+		    }
+		} else if (info->type == XSLT_FUNC_MESSAGE) {
+		    /*
+		    * TODO: Won't be hit, since we don't compile xsl:message.
+		    */
+		    xsltMessage(ctxt, contextNode, cur);
+		} else {
+		    xsltTransformError(ctxt, NULL, cur,
+			"Unexpected XSLT element '%s'.\n", cur->name);
+		}
+		goto skip_children;
+
+	    } else {
+		xsltTransformFunction func;
+		/*
+		* Extension intructions (elements)
+		* --------------------------------------------------------
+		*/
+		if (cur->psvi == xsltExtMarker) {
+		    /*
+		    * The xsltExtMarker was set during the compilation
+		    * of extension instructions if there was no registered
+		    * handler for this specific extension function at
+		    * compile-time.
+		    * Libxslt will now lookup if a handler is
+		    * registered in the context of this transformation.
+		    */
+		    func = (xsltTransformFunction)
+			xsltExtElementLookup(ctxt, cur->name, cur->ns->href);
+		} else
+		    func = ((xsltElemPreCompPtr) cur->psvi)->func;
+
+		if (func == NULL) {
+		    /*
+		    * No handler available.
+		    * Try to execute fallback behaviour via xsl:fallback.
+		    */
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		    XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
+			xsltGenericDebug(xsltGenericDebugContext,
+			    "xsltApplySequenceConstructor: unknown extension %s\n",
+			    cur->name));
+#endif
+		    ctxt->insert = insert;
+		    if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
+			xsltTransformError(ctxt, NULL, cur,
+			    "Unknown extension instruction '{%s}%s'.\n",
+			    cur->ns->href, cur->name);
+		    }
+		    ctxt->insert = oldInsert;
+		} else {
+		    /*
+		    * Execute the handler-callback.
+		    */
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		    XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
+			"xsltApplySequenceConstructor: extension construct %s\n",
+			cur->name));
+#endif
+		    ctxt->insert = insert;
+		    /*
+		    * We need the fragment base for extension instructions
+		    * which return values (like EXSLT's function).
+		    */
+		    oldLocalFragmentBase = ctxt->localRVTBase;
+		    ctxt->localRVTBase = NULL;
+
+		    func(ctxt, contextNode, cur, cur->psvi);
+
+		    ctxt->localRVTBase = oldLocalFragmentBase;
+		    /*
+		    * Cleanup temporary tree fragments.
+		    */
+		    if (oldLocalFragmentTop != ctxt->localRVT)
+			xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
+
+		    ctxt->insert = oldInsert;
+		}
+		goto skip_children;
+	    }
+
+	} else if (XSLT_IS_TEXT_NODE(cur)) {
+	    /*
+	    * Text
+	    * ------------------------------------------------------------
+	    */
+#ifdef WITH_XSLT_DEBUG_PROCESS
+            if (cur->name == xmlStringTextNoenc) {
+                XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
+		    xsltGenericDebug(xsltGenericDebugContext,
+		    "xsltApplySequenceConstructor: copy unescaped text '%s'\n",
+		    cur->content));
+            } else {
+                XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE,
+		    xsltGenericDebug(xsltGenericDebugContext,
+		    "xsltApplySequenceConstructor: copy text '%s'\n",
+		    cur->content));
+            }
+#endif
+            if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
+		goto error;
+	}
+
+#else /* XSLT_REFACTORED */
+
+        if (IS_XSLT_ELEM(cur)) {
+            /*
+             * This is an XSLT node
+             */
+            xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi;
+
+            if (info == NULL) {
+                if (IS_XSLT_NAME(cur, "message")) {
+                    xsltMessage(ctxt, contextNode, cur);
+                } else {
+                    /*
+                     * That's an error try to apply one of the fallback cases
+                     */
+                    ctxt->insert = insert;
+                    if (!xsltApplyFallbacks(ctxt, contextNode, cur)) {
+                        xsltGenericError(xsltGenericErrorContext,
+			    "xsltApplySequenceConstructor: %s was not compiled\n",
+			    cur->name);
+                    }
+                    ctxt->insert = oldInsert;
+                }
+                goto skip_children;
+            }
+
+            if (info->func != NULL) {
+		oldCurInst = ctxt->inst;
+		ctxt->inst = cur;
+                ctxt->insert = insert;
+		oldLocalFragmentBase = ctxt->localRVTBase;
+		ctxt->localRVTBase = NULL;
+
+                info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info);
+
+		ctxt->localRVTBase = oldLocalFragmentBase;
+		/*
+		* Cleanup temporary tree fragments.
+		*/
+		if (oldLocalFragmentTop != ctxt->localRVT)
+		    xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
+
+                ctxt->insert = oldInsert;
+		ctxt->inst = oldCurInst;
+                goto skip_children;
+            }
+
+            if (IS_XSLT_NAME(cur, "variable")) {
+		xsltStackElemPtr tmpvar = ctxt->vars;
+
+		oldCurInst = ctxt->inst;
+		ctxt->inst = cur;
+
+		xsltParseStylesheetVariable(ctxt, cur);
+
+		ctxt->inst = oldCurInst;
+
+		if (tmpvar != ctxt->vars) {
+		    /*
+		    * TODO: Using a @tmpvar is an annoying workaround, but
+		    *  the current mechanisms do not provide any other way
+		    *  of knowing if the var was really pushed onto the
+		    *  stack.
+		    */
+		    ctxt->vars->level = level;
+		}
+            } else if (IS_XSLT_NAME(cur, "message")) {
+                xsltMessage(ctxt, contextNode, cur);
+            } else {
+		xsltTransformError(ctxt, NULL, cur,
+		    "Unexpected XSLT element '%s'.\n", cur->name);
+            }
+            goto skip_children;
+        } else if ((cur->type == XML_TEXT_NODE) ||
+                   (cur->type == XML_CDATA_SECTION_NODE)) {
+
+            /*
+             * This text comes from the stylesheet
+             * For stylesheets, the set of whitespace-preserving
+             * element names consists of just xsl:text.
+             */
+#ifdef WITH_XSLT_DEBUG_PROCESS
+            if (cur->type == XML_CDATA_SECTION_NODE) {
+                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
+                                 "xsltApplySequenceConstructor: copy CDATA text %s\n",
+                                 cur->content));
+            } else if (cur->name == xmlStringTextNoenc) {
+                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
+                                 "xsltApplySequenceConstructor: copy unescaped text %s\n",
+                                 cur->content));
+            } else {
+                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
+                                 "xsltApplySequenceConstructor: copy text %s\n",
+                                 cur->content));
+            }
+#endif
+            if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL)
+		goto error;
+        } else if ((cur->type == XML_ELEMENT_NODE) &&
+                   (cur->ns != NULL) && (cur->psvi != NULL)) {
+            xsltTransformFunction function;
+
+	    oldCurInst = ctxt->inst;
+	    ctxt->inst = cur;
+            /*
+             * Flagged as an extension element
+             */
+            if (cur->psvi == xsltExtMarker)
+                function = (xsltTransformFunction)
+                    xsltExtElementLookup(ctxt, cur->name, cur->ns->href);
+            else
+                function = ((xsltElemPreCompPtr) cur->psvi)->func;
+
+            if (function == NULL) {
+                xmlNodePtr child;
+                int found = 0;
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
+		    "xsltApplySequenceConstructor: unknown extension %s\n",
+                    cur->name));
+#endif
+                /*
+                 * Search if there are fallbacks
+                 */
+                child = cur->children;
+                while (child != NULL) {
+                    if ((IS_XSLT_ELEM(child)) &&
+                        (IS_XSLT_NAME(child, "fallback")))
+		    {
+                        found = 1;
+                        xsltApplySequenceConstructor(ctxt, contextNode,
+			    child->children, NULL);
+                    }
+                    child = child->next;
+                }
+
+                if (!found) {
+                    xsltTransformError(ctxt, NULL, cur,
+			"xsltApplySequenceConstructor: failed to find extension %s\n",
+			cur->name);
+                }
+            } else {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+                XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
+		    "xsltApplySequenceConstructor: extension construct %s\n",
+                    cur->name));
+#endif
+
+                ctxt->insert = insert;
+		/*
+		* We need the fragment base for extension instructions
+		* which return values (like EXSLT's function).
+		*/
+		oldLocalFragmentBase = ctxt->localRVTBase;
+		ctxt->localRVTBase = NULL;
+
+                function(ctxt, contextNode, cur, cur->psvi);
+		/*
+		* Cleanup temporary tree fragments.
+		*/
+		if (oldLocalFragmentTop != ctxt->localRVT)
+		    xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
+
+		ctxt->localRVTBase = oldLocalFragmentBase;
+                ctxt->insert = oldInsert;
+
+            }
+	    ctxt->inst = oldCurInst;
+            goto skip_children;
+        } else if (cur->type == XML_ELEMENT_NODE) {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+            XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
+		"xsltApplySequenceConstructor: copy node %s\n",
+                cur->name));
+#endif
+	    oldCurInst = ctxt->inst;
+	    ctxt->inst = cur;
+
+            if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL)
+		goto error;
+            /*
+             * Add extra namespaces inherited from the current template
+             * if we are in the first level children and this is a
+	     * "real" template.
+             */
+            if ((templ != NULL) && (oldInsert == insert) &&
+                (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) {
+                int i;
+                xmlNsPtr ns, ret;
+
+                for (i = 0; i < ctxt->templ->inheritedNsNr; i++) {
+		    const xmlChar *URI = NULL;
+		    xsltStylesheetPtr style;
+                    ns = ctxt->templ->inheritedNs[i];
+
+		    /* Note that the XSLT namespace was already excluded
+		    * in xsltGetInheritedNsList().
+		    */
+#if 0
+		    if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
+			continue;
+#endif
+		    style = ctxt->style;
+		    while (style != NULL) {
+			if (style->nsAliases != NULL)
+			    URI = (const xmlChar *)
+				xmlHashLookup(style->nsAliases, ns->href);
+			if (URI != NULL)
+			    break;
+
+			style = xsltNextImport(style);
+		    }
+		    if (URI == UNDEFINED_DEFAULT_NS)
+			continue;
+		    if (URI == NULL)
+			URI = ns->href;
+		    /*
+		    * TODO: The following will still be buggy for the
+		    * non-refactored code.
+		    */
+		    ret = xmlSearchNs(copy->doc, copy, ns->prefix);
+		    if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)))
+		    {
+			xmlNewNs(copy, URI, ns->prefix);
+		    }
+                }
+		if (copy->ns != NULL) {
+		    /*
+		     * Fix the node namespace if needed
+		     */
+		    copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy);
+		}
+            }
+	    /*
+             * all the attributes are directly inherited
+             */
+            if (cur->properties != NULL) {
+                xsltAttrListTemplateProcess(ctxt, copy, cur->properties);
+            }
+	    ctxt->inst = oldCurInst;
+        }
+#endif /* else of XSLT_REFACTORED */
+
+        /*
+         * Descend into content in document order.
+         */
+        if (cur->children != NULL) {
+            if (cur->children->type != XML_ENTITY_DECL) {
+                cur = cur->children;
+		level++;
+                if (copy != NULL)
+                    insert = copy;
+                continue;
+            }
+        }
+
+skip_children:
+	/*
+	* If xslt:message was just processed, we might have hit a
+	* terminate='yes'; if so, then break the loop and clean up.
+	* TODO: Do we need to check this also before trying to descend
+	*  into the content?
+	*/
+	if (ctxt->state == XSLT_STATE_STOPPED)
+	    break;
+        if (cur->next != NULL) {
+            cur = cur->next;
+            continue;
+        }
+
+        do {
+            cur = cur->parent;
+	    level--;
+	    /*
+	    * Pop variables/params (xsl:variable and xsl:param).
+	    */
+	    if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) {
+		xsltLocalVariablePop(ctxt, oldVarsNr, level);
+	    }
+
+            insert = insert->parent;
+            if (cur == NULL)
+                break;
+            if (cur == list->parent) {
+                cur = NULL;
+                break;
+            }
+            if (cur->next != NULL) {
+                cur = cur->next;
+                break;
+            }
+        } while (cur != NULL);
+    }
+
+error:
+    /*
+    * In case of errors: pop remaining variables.
+    */
+    if (ctxt->varsNr > oldVarsNr)
+	xsltLocalVariablePop(ctxt, oldVarsNr, -1);
+
+    ctxt->node = oldContextNode;
+    ctxt->inst = oldInst;
+    ctxt->insert = oldInsert;
+
+#ifdef WITH_DEBUGGER
+    if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
+        xslDropCall();
+    }
+#endif
+}
+
+/*
+* xsltApplyXSLTTemplate:
+* @ctxt:  a XSLT transformation context
+* @contextNode:  the node in the source tree.
+* @list:  the nodes of a sequence constructor;
+*         (plus leading xsl:param elements)
+* @templ: the compiled xsl:template declaration;
+*         NULL if a sequence constructor
+* @withParams:  a set of caller-parameters (xsl:with-param) or NULL
+*
+* Called by:
+* - xsltApplyImports()
+* - xsltCallTemplate()
+* - xsltDefaultProcessOneNode()
+* - xsltProcessOneNode()
+*/
+static void
+xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt,
+		      xmlNodePtr contextNode,
+		      xmlNodePtr list,
+		      xsltTemplatePtr templ,
+		      xsltStackElemPtr withParams)
+{
+    int oldVarsBase = 0;
+    long start = 0;
+    xmlNodePtr cur;
+    xsltStackElemPtr tmpParam = NULL;
+    xmlDocPtr oldUserFragmentTop, oldLocalFragmentTop;
+
+#ifdef XSLT_REFACTORED
+    xsltStyleItemParamPtr iparam;
+#else
+    xsltStylePreCompPtr iparam;
+#endif
+
+#ifdef WITH_DEBUGGER
+    int addCallResult = 0;
+#endif
+
+    if (ctxt == NULL)
+	return;
+    if (templ == NULL) {
+	xsltTransformError(ctxt, NULL, list,
+	    "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n");
+	return;
+    }
+
+#ifdef WITH_DEBUGGER
+    if (ctxt->debugStatus != XSLT_DEBUG_NONE) {
+	if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode,
+		list, templ, &addCallResult) == NULL)
+	    return;
+    }
+#endif
+
+    if (list == NULL)
+        return;
+    CHECK_STOPPED;
+
+    /*
+    * Check for infinite recursion: stop if the maximum of nested templates
+    * is excceeded. Adjust xsltMaxDepth if you need more.
+    */
+    if (((ctxt->templNr >= xsltMaxDepth) ||
+        (ctxt->varsNr >= 5 * xsltMaxDepth)))
+    {
+        xsltTransformError(ctxt, NULL, list,
+	    "xsltApplyXSLTTemplate: A potential infinite template recursion "
+	    "was detected.\n"
+	    "You can adjust xsltMaxDepth (--maxdepth) in order to "
+	    "raise the maximum number of nested template calls and "
+	    "variables/params (currently set to %d).\n",
+	    xsltMaxDepth);
+        xsltDebug(ctxt, contextNode, list, NULL);
+        return;
+    }
+
+    oldUserFragmentTop = ctxt->tmpRVT;
+    ctxt->tmpRVT = NULL;
+    oldLocalFragmentTop = ctxt->localRVT;
+
+    /*
+    * Initiate a distinct scope of local params/variables.
+    */
+    oldVarsBase = ctxt->varsBase;
+    ctxt->varsBase = ctxt->varsNr;
+
+    ctxt->node = contextNode;
+    if (ctxt->profile) {
+	templ->nbCalls++;
+	start = xsltTimestamp();
+	profPush(ctxt, 0);
+    }
+    /*
+    * Push the xsl:template declaration onto the stack.
+    */
+    templPush(ctxt, templ);
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    if (templ->name != NULL)
+	XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
+	"applying xsl:template '%s'\n", templ->name));
+#endif
+    /*
+    * Process xsl:param instructions and skip those elements for
+    * further processing.
+    */
+    cur = list;
+    do {
+	if (cur->type == XML_TEXT_NODE) {
+	    cur = cur->next;
+	    continue;
+	}
+	if ((cur->type != XML_ELEMENT_NODE) ||
+	    (cur->name[0] != 'p') ||
+	    (cur->psvi == NULL) ||
+	    (! xmlStrEqual(cur->name, BAD_CAST "param")) ||
+	    (! IS_XSLT_ELEM(cur)))
+	{
+	    break;
+	}
+
+	list = cur->next;
+
+#ifdef XSLT_REFACTORED
+	iparam = (xsltStyleItemParamPtr) cur->psvi;
+#else
+	iparam = (xsltStylePreCompPtr) cur->psvi;
+#endif
+
+	/*
+	* Substitute xsl:param for a given xsl:with-param.
+	* Since the XPath expression will reference the params/vars
+	* by index, we need to slot the xsl:with-params in the
+	* order of encountered xsl:params to keep the sequence of
+	* params/variables in the stack exactly as it was at
+	* compile time,
+	*/
+	tmpParam = NULL;
+	if (withParams) {
+	    tmpParam = withParams;
+	    do {
+		if ((tmpParam->name == (iparam->name)) &&
+		    (tmpParam->nameURI == (iparam->ns)))
+		{
+		    /*
+		    * Push the caller-parameter.
+		    */
+		    xsltLocalVariablePush(ctxt, tmpParam, -1);
+		    break;
+		}
+		tmpParam = tmpParam->next;
+	    } while (tmpParam != NULL);
+	}
+	/*
+	* Push the xsl:param.
+	*/
+	if (tmpParam == NULL) {
+	    /*
+	    * Note that we must assume that the added parameter
+	    * has a @depth of 0.
+	    */
+	    xsltParseStylesheetParam(ctxt, cur);
+	}
+	cur = cur->next;
+    } while (cur != NULL);
+    /*
+    * Process the sequence constructor.
+    */
+    xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
+
+    /*
+    * Remove remaining xsl:param and xsl:with-param items from
+    * the stack. Don't free xsl:with-param items.
+    */
+    if (ctxt->varsNr > ctxt->varsBase)
+	xsltTemplateParamsCleanup(ctxt);
+    ctxt->varsBase = oldVarsBase;
+
+    /*
+    * Clean up remaining local tree fragments.
+    * This also frees fragments which are the result of
+    * extension instructions. Should normally not be hit; but
+    * just for the case xsltExtensionInstructionResultFinalize()
+    * was not called by the extension author.
+    */
+    if (oldLocalFragmentTop != ctxt->localRVT) {
+	xmlDocPtr curdoc = ctxt->localRVT, tmp;
+
+	do {
+	    tmp = curdoc;
+	    curdoc = (xmlDocPtr) curdoc->next;
+	    /* Need to housekeep localRVTBase */
+	    if (tmp == ctxt->localRVTBase)
+	        ctxt->localRVTBase = curdoc;
+	    if (tmp->prev)
+		tmp->prev->next = (xmlNodePtr) curdoc;
+	    if (curdoc)
+		curdoc->prev = tmp->prev;
+	    xsltReleaseRVT(ctxt, tmp);
+	} while (curdoc != oldLocalFragmentTop);
+    }
+    ctxt->localRVT = oldLocalFragmentTop;
+
+    /*
+    * Release user-created fragments stored in the scope
+    * of xsl:template. Note that this mechanism is deprecated:
+    * user code should now use xsltRegisterLocalRVT() instead
+    * of the obsolete xsltRegisterTmpRVT().
+    */
+    if (ctxt->tmpRVT) {
+	xmlDocPtr curdoc = ctxt->tmpRVT, tmp;
+
+	while (curdoc != NULL) {
+	    tmp = curdoc;
+	    curdoc = (xmlDocPtr) curdoc->next;
+	    xsltReleaseRVT(ctxt, tmp);
+	}
+    }
+    ctxt->tmpRVT = oldUserFragmentTop;
+
+    /*
+    * Pop the xsl:template declaration from the stack.
+    */
+    templPop(ctxt);
+    if (ctxt->profile) {
+	long spent, child, total, end;
+
+	end = xsltTimestamp();
+	child = profPop(ctxt);
+	total = end - start;
+	spent = total - child;
+	if (spent <= 0) {
+	    /*
+	    * Not possible unless the original calibration failed
+	    * we can try to correct it on the fly.
+	    */
+	    xsltCalibrateAdjust(spent);
+	    spent = 0;
+	}
+
+	templ->time += spent;
+	if (ctxt->profNr > 0)
+	    ctxt->profTab[ctxt->profNr - 1] += total;
+    }
+
+#ifdef WITH_DEBUGGER
+    if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) {
+        xslDropCall();
+    }
+#endif
+}
+
+
+/**
+ * xsltApplyOneTemplate:
+ * @ctxt:  a XSLT process context
+ * @contextNode:  the node in the source tree.
+ * @list:  the nodes of a sequence constructor
+ * @templ: not used
+ * @params:  a set of parameters (xsl:param) or NULL
+ *
+ * Processes a sequence constructor on the current node in the source tree.
+ *
+ * @params are the already computed variable stack items; this function
+ * pushes them on the variable stack, and pops them before exiting; it's
+ * left to the caller to free or reuse @params afterwards. The initial
+ * states of the variable stack will always be restored before this
+ * function exits.
+ * NOTE that this does *not* initiate a new distinct variable scope; i.e.
+ * variables already on the stack are visible to the process. The caller's
+ * side needs to start a new variable scope if needed (e.g. in exsl:function).
+ *
+ * @templ is obsolete and not used anymore (e.g. <exslt:function> does not
+ * provide a @templ); a non-NULL @templ might raise an error in the future.
+ *
+ * BIG NOTE: This function is not intended to process the content of an
+ * xsl:template; it does not expect xsl:param instructions in @list and
+ * will report errors if found.
+ *
+ * Called by:
+ *  - xsltEvalVariable() (variables.c)
+ *  - exsltFuncFunctionFunction() (libexsl/functions.c)
+ */
+void
+xsltApplyOneTemplate(xsltTransformContextPtr ctxt,
+		     xmlNodePtr contextNode,
+                     xmlNodePtr list,
+		     xsltTemplatePtr templ ATTRIBUTE_UNUSED,
+                     xsltStackElemPtr params)
+{
+    if ((ctxt == NULL) || (list == NULL))
+	return;
+    CHECK_STOPPED;
+
+    if (params) {
+	/*
+	 * This code should be obsolete - was previously used
+	 * by libexslt/functions.c, but due to bug 381319 the
+	 * logic there was changed.
+	 */
+	int oldVarsNr = ctxt->varsNr;
+
+	/*
+	* Push the given xsl:param(s) onto the variable stack.
+	*/
+	while (params != NULL) {
+	    xsltLocalVariablePush(ctxt, params, -1);
+	    params = params->next;
+	}
+	xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
+	/*
+	* Pop the given xsl:param(s) from the stack but don't free them.
+	*/
+	xsltLocalVariablePop(ctxt, oldVarsNr, -2);
+    } else
+	xsltApplySequenceConstructor(ctxt, contextNode, list, templ);
+}
+
+/************************************************************************
+ *									*
+ *		    XSLT-1.1 extensions					*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltDocumentElem:
+ * @ctxt:  an XSLT processing context
+ * @node:  The current node
+ * @inst:  the instruction in the stylesheet
+ * @castedComp:  precomputed information
+ *
+ * Process an EXSLT/XSLT-1.1 document element
+ */
+void
+xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif
+    xsltStylesheetPtr style = NULL;
+    int ret;
+    xmlChar *filename = NULL, *prop, *elements;
+    xmlChar *element, *end;
+    xmlDocPtr res = NULL;
+    xmlDocPtr oldOutput;
+    xmlNodePtr oldInsert, root;
+    const char *oldOutputFile;
+    xsltOutputType oldType;
+    xmlChar *URL = NULL;
+    const xmlChar *method;
+    const xmlChar *doctypePublic;
+    const xmlChar *doctypeSystem;
+    const xmlChar *version;
+    const xmlChar *encoding;
+
+    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
+        return;
+
+    if (comp->filename == NULL) {
+
+        if (xmlStrEqual(inst->name, (const xmlChar *) "output")) {
+	    /*
+	    * The element "output" is in the namespace XSLT_SAXON_NAMESPACE
+	    *   (http://icl.com/saxon)
+	    * The @file is in no namespace.
+	    */
+#ifdef WITH_XSLT_DEBUG_EXTRA
+            xsltGenericDebug(xsltGenericDebugContext,
+                             "Found saxon:output extension\n");
+#endif
+            URL = xsltEvalAttrValueTemplate(ctxt, inst,
+                                                 (const xmlChar *) "file",
+                                                 XSLT_SAXON_NAMESPACE);
+
+	    if (URL == NULL)
+		URL = xsltEvalAttrValueTemplate(ctxt, inst,
+                                                 (const xmlChar *) "href",
+                                                 XSLT_SAXON_NAMESPACE);
+        } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) {
+#ifdef WITH_XSLT_DEBUG_EXTRA
+            xsltGenericDebug(xsltGenericDebugContext,
+                             "Found xalan:write extension\n");
+#endif
+            URL = xsltEvalAttrValueTemplate(ctxt, inst,
+                                                 (const xmlChar *)
+                                                 "select",
+                                                 XSLT_XALAN_NAMESPACE);
+	    if (URL != NULL) {
+		xmlXPathCompExprPtr cmp;
+		xmlChar *val;
+
+		/*
+		 * Trying to handle bug #59212
+		 * The value of the "select" attribute is an
+		 * XPath expression.
+		 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect)
+		 */
+		cmp = xmlXPathCompile(URL);
+                val = xsltEvalXPathString(ctxt, cmp);
+		xmlXPathFreeCompExpr(cmp);
+		xmlFree(URL);
+		URL = val;
+	    }
+	    if (URL == NULL)
+		URL = xsltEvalAttrValueTemplate(ctxt, inst,
+						     (const xmlChar *)
+						     "file",
+						     XSLT_XALAN_NAMESPACE);
+	    if (URL == NULL)
+		URL = xsltEvalAttrValueTemplate(ctxt, inst,
+						     (const xmlChar *)
+						     "href",
+						     XSLT_XALAN_NAMESPACE);
+        } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) {
+            URL = xsltEvalAttrValueTemplate(ctxt, inst,
+                                                 (const xmlChar *) "href",
+                                                 NULL);
+        }
+
+    } else {
+        URL = xmlStrdup(comp->filename);
+    }
+
+    if (URL == NULL) {
+	xsltTransformError(ctxt, NULL, inst,
+		         "xsltDocumentElem: href/URI-Reference not found\n");
+	return;
+    }
+
+    /*
+     * If the computation failed, it's likely that the URL wasn't escaped
+     */
+    filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile);
+    if (filename == NULL) {
+	xmlChar *escURL;
+
+	escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,");
+	if (escURL != NULL) {
+	    filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile);
+	    xmlFree(escURL);
+	}
+    }
+
+    if (filename == NULL) {
+	xsltTransformError(ctxt, NULL, inst,
+		         "xsltDocumentElem: URL computation failed for %s\n",
+			 URL);
+	xmlFree(URL);
+	return;
+    }
+
+    /*
+     * Security checking: can we write to this resource
+     */
+    if (ctxt->sec != NULL) {
+	ret = xsltCheckWrite(ctxt->sec, ctxt, filename);
+	if (ret == 0) {
+	    xsltTransformError(ctxt, NULL, inst,
+		 "xsltDocumentElem: write rights for %s denied\n",
+			     filename);
+	    xmlFree(URL);
+	    xmlFree(filename);
+	    return;
+	}
+    }
+
+    oldOutputFile = ctxt->outputFile;
+    oldOutput = ctxt->output;
+    oldInsert = ctxt->insert;
+    oldType = ctxt->type;
+    ctxt->outputFile = (const char *) filename;
+
+    style = xsltNewStylesheet();
+    if (style == NULL) {
+	xsltTransformError(ctxt, NULL, inst,
+                         "xsltDocumentElem: out of memory\n");
+        goto error;
+    }
+
+    /*
+     * Version described in 1.1 draft allows full parameterization
+     * of the output.
+     */
+    prop = xsltEvalAttrValueTemplate(ctxt, inst,
+				     (const xmlChar *) "version",
+				     NULL);
+    if (prop != NULL) {
+	if (style->version != NULL)
+	    xmlFree(style->version);
+	style->version = prop;
+    }
+    prop = xsltEvalAttrValueTemplate(ctxt, inst,
+				     (const xmlChar *) "encoding",
+				     NULL);
+    if (prop != NULL) {
+	if (style->encoding != NULL)
+	    xmlFree(style->encoding);
+	style->encoding = prop;
+    }
+    prop = xsltEvalAttrValueTemplate(ctxt, inst,
+				     (const xmlChar *) "method",
+				     NULL);
+    if (prop != NULL) {
+	const xmlChar *URI;
+
+	if (style->method != NULL)
+	    xmlFree(style->method);
+	style->method = NULL;
+	if (style->methodURI != NULL)
+	    xmlFree(style->methodURI);
+	style->methodURI = NULL;
+
+	URI = xsltGetQNameURI(inst, &prop);
+	if (prop == NULL) {
+	    if (style != NULL) style->errors++;
+	} else if (URI == NULL) {
+	    if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
+		(xmlStrEqual(prop, (const xmlChar *) "html")) ||
+		(xmlStrEqual(prop, (const xmlChar *) "text"))) {
+		style->method = prop;
+	    } else {
+		xsltTransformError(ctxt, NULL, inst,
+				 "invalid value for method: %s\n", prop);
+		if (style != NULL) style->warnings++;
+	    }
+	} else {
+	    style->method = prop;
+	    style->methodURI = xmlStrdup(URI);
+	}
+    }
+    prop = xsltEvalAttrValueTemplate(ctxt, inst,
+				     (const xmlChar *)
+				     "doctype-system", NULL);
+    if (prop != NULL) {
+	if (style->doctypeSystem != NULL)
+	    xmlFree(style->doctypeSystem);
+	style->doctypeSystem = prop;
+    }
+    prop = xsltEvalAttrValueTemplate(ctxt, inst,
+				     (const xmlChar *)
+				     "doctype-public", NULL);
+    if (prop != NULL) {
+	if (style->doctypePublic != NULL)
+	    xmlFree(style->doctypePublic);
+	style->doctypePublic = prop;
+    }
+    prop = xsltEvalAttrValueTemplate(ctxt, inst,
+				     (const xmlChar *) "standalone",
+				     NULL);
+    if (prop != NULL) {
+	if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
+	    style->standalone = 1;
+	} else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
+	    style->standalone = 0;
+	} else {
+	    xsltTransformError(ctxt, NULL, inst,
+			     "invalid value for standalone: %s\n",
+			     prop);
+	    if (style != NULL) style->warnings++;
+	}
+	xmlFree(prop);
+    }
+
+    prop = xsltEvalAttrValueTemplate(ctxt, inst,
+				     (const xmlChar *) "indent",
+				     NULL);
+    if (prop != NULL) {
+	if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
+	    style->indent = 1;
+	} else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
+	    style->indent = 0;
+	} else {
+	    xsltTransformError(ctxt, NULL, inst,
+			     "invalid value for indent: %s\n", prop);
+	    if (style != NULL) style->warnings++;
+	}
+	xmlFree(prop);
+    }
+
+    prop = xsltEvalAttrValueTemplate(ctxt, inst,
+				     (const xmlChar *)
+				     "omit-xml-declaration",
+				     NULL);
+    if (prop != NULL) {
+	if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
+	    style->omitXmlDeclaration = 1;
+	} else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
+	    style->omitXmlDeclaration = 0;
+	} else {
+	    xsltTransformError(ctxt, NULL, inst,
+			     "invalid value for omit-xml-declaration: %s\n",
+			     prop);
+	    if (style != NULL) style->warnings++;
+	}
+	xmlFree(prop);
+    }
+
+    elements = xsltEvalAttrValueTemplate(ctxt, inst,
+					 (const xmlChar *)
+					 "cdata-section-elements",
+					 NULL);
+    if (elements != NULL) {
+	if (style->stripSpaces == NULL)
+	    style->stripSpaces = xmlHashCreate(10);
+	if (style->stripSpaces == NULL)
+	    return;
+
+	element = elements;
+	while (*element != 0) {
+	    while (IS_BLANK_CH(*element))
+		element++;
+	    if (*element == 0)
+		break;
+	    end = element;
+	    while ((*end != 0) && (!IS_BLANK_CH(*end)))
+		end++;
+	    element = xmlStrndup(element, end - element);
+	    if (element) {
+		const xmlChar *URI;
+
+#ifdef WITH_XSLT_DEBUG_PARSING
+		xsltGenericDebug(xsltGenericDebugContext,
+				 "add cdata section output element %s\n",
+				 element);
+#endif
+                URI = xsltGetQNameURI(inst, &element);
+
+		xmlHashAddEntry2(style->stripSpaces, element, URI,
+			        (xmlChar *) "cdata");
+		xmlFree(element);
+	    }
+	    element = end;
+	}
+	xmlFree(elements);
+    }
+
+    /*
+     * Create a new document tree and process the element template
+     */
+    XSLT_GET_IMPORT_PTR(method, style, method)
+    XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
+    XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
+    XSLT_GET_IMPORT_PTR(version, style, version)
+    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
+
+    if ((method != NULL) &&
+	(!xmlStrEqual(method, (const xmlChar *) "xml"))) {
+	if (xmlStrEqual(method, (const xmlChar *) "html")) {
+	    ctxt->type = XSLT_OUTPUT_HTML;
+	    if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
+		res = htmlNewDoc(doctypeSystem, doctypePublic);
+	    else {
+		if (version != NULL) {
+#ifdef XSLT_GENERATE_HTML_DOCTYPE
+		    xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
+#endif
+                }
+		res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
+	    }
+	    if (res == NULL)
+		goto error;
+	    res->dict = ctxt->dict;
+	    xmlDictReference(res->dict);
+	} else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
+	    xsltTransformError(ctxt, NULL, inst,
+	     "xsltDocumentElem: unsupported method xhtml\n",
+		             style->method);
+	    ctxt->type = XSLT_OUTPUT_HTML;
+	    res = htmlNewDocNoDtD(doctypeSystem, doctypePublic);
+	    if (res == NULL)
+		goto error;
+	    res->dict = ctxt->dict;
+	    xmlDictReference(res->dict);
+	} else if (xmlStrEqual(method, (const xmlChar *) "text")) {
+	    ctxt->type = XSLT_OUTPUT_TEXT;
+	    res = xmlNewDoc(style->version);
+	    if (res == NULL)
+		goto error;
+	    res->dict = ctxt->dict;
+	    xmlDictReference(res->dict);
+#ifdef WITH_XSLT_DEBUG
+	    xsltGenericDebug(xsltGenericDebugContext,
+                     "reusing transformation dict for output\n");
+#endif
+	} else {
+	    xsltTransformError(ctxt, NULL, inst,
+			     "xsltDocumentElem: unsupported method %s\n",
+		             style->method);
+	    goto error;
+	}
+    } else {
+	ctxt->type = XSLT_OUTPUT_XML;
+	res = xmlNewDoc(style->version);
+	if (res == NULL)
+	    goto error;
+	res->dict = ctxt->dict;
+	xmlDictReference(res->dict);
+#ifdef WITH_XSLT_DEBUG
+	xsltGenericDebug(xsltGenericDebugContext,
+                     "reusing transformation dict for output\n");
+#endif
+    }
+    res->charset = XML_CHAR_ENCODING_UTF8;
+    if (encoding != NULL)
+	res->encoding = xmlStrdup(encoding);
+    ctxt->output = res;
+    ctxt->insert = (xmlNodePtr) res;
+    xsltApplySequenceConstructor(ctxt, node, inst->children, NULL);
+
+    /*
+     * Do some post processing work depending on the generated output
+     */
+    root = xmlDocGetRootElement(res);
+    if (root != NULL) {
+        const xmlChar *doctype = NULL;
+
+        if ((root->ns != NULL) && (root->ns->prefix != NULL))
+	    doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
+	if (doctype == NULL)
+	    doctype = root->name;
+
+        /*
+         * Apply the default selection of the method
+         */
+        if ((method == NULL) &&
+            (root->ns == NULL) &&
+            (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
+            xmlNodePtr tmp;
+
+            tmp = res->children;
+            while ((tmp != NULL) && (tmp != root)) {
+                if (tmp->type == XML_ELEMENT_NODE)
+                    break;
+                if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
+                    break;
+		tmp = tmp->next;
+            }
+            if (tmp == root) {
+                ctxt->type = XSLT_OUTPUT_HTML;
+                res->type = XML_HTML_DOCUMENT_NODE;
+                if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
+                    res->intSubset = xmlCreateIntSubset(res, doctype,
+                                                        doctypePublic,
+                                                        doctypeSystem);
+#ifdef XSLT_GENERATE_HTML_DOCTYPE
+		} else if (version != NULL) {
+                    xsltGetHTMLIDs(version, &doctypePublic,
+                                   &doctypeSystem);
+                    if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
+                        res->intSubset =
+                            xmlCreateIntSubset(res, doctype,
+                                               doctypePublic,
+                                               doctypeSystem);
+#endif
+                }
+            }
+
+        }
+        if (ctxt->type == XSLT_OUTPUT_XML) {
+            XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
+                XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
+                if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
+                res->intSubset = xmlCreateIntSubset(res, doctype,
+                                                    doctypePublic,
+                                                    doctypeSystem);
+        }
+    }
+
+    /*
+     * Save the result
+     */
+    ret = xsltSaveResultToFilename((const char *) filename,
+                                   res, style, 0);
+    if (ret < 0) {
+	xsltTransformError(ctxt, NULL, inst,
+                         "xsltDocumentElem: unable to save to %s\n",
+                         filename);
+	ctxt->state = XSLT_STATE_ERROR;
+#ifdef WITH_XSLT_DEBUG_EXTRA
+    } else {
+        xsltGenericDebug(xsltGenericDebugContext,
+                         "Wrote %d bytes to %s\n", ret, filename);
+#endif
+    }
+
+  error:
+    ctxt->output = oldOutput;
+    ctxt->insert = oldInsert;
+    ctxt->type = oldType;
+    ctxt->outputFile = oldOutputFile;
+    if (URL != NULL)
+        xmlFree(URL);
+    if (filename != NULL)
+        xmlFree(filename);
+    if (style != NULL)
+        xsltFreeStylesheet(style);
+    if (res != NULL)
+        xmlFreeDoc(res);
+}
+
+/************************************************************************
+ *									*
+ *		Most of the XSLT-1.0 transformations			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltSort:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt sort node
+ * @comp:  precomputed information
+ *
+ * function attached to xsl:sort nodes, but this should not be
+ * called directly
+ */
+void
+xsltSort(xsltTransformContextPtr ctxt,
+	xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst,
+	xsltStylePreCompPtr comp) {
+    if (comp == NULL) {
+	xsltTransformError(ctxt, NULL, inst,
+	     "xsl:sort : compilation failed\n");
+	return;
+    }
+    xsltTransformError(ctxt, NULL, inst,
+	 "xsl:sort : improper use this should not be reached\n");
+}
+
+/**
+ * xsltCopy:
+ * @ctxt:  an XSLT process context
+ * @node:  the node in the source tree
+ * @inst:  the element node of the XSLT-copy instruction
+ * @castedComp:  computed information of the XSLT-copy instruction
+ *
+ * Execute the XSLT-copy instruction on the source node.
+ */
+void
+xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	 xmlNodePtr inst, xsltStylePreCompPtr castedComp)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif
+    xmlNodePtr copy, oldInsert;
+
+    oldInsert = ctxt->insert;
+    if (ctxt->insert != NULL) {
+	switch (node->type) {
+	    case XML_TEXT_NODE:
+	    case XML_CDATA_SECTION_NODE:
+		/*
+		 * This text comes from the stylesheet
+		 * For stylesheets, the set of whitespace-preserving
+		 * element names consists of just xsl:text.
+		 */
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		if (node->type == XML_CDATA_SECTION_NODE) {
+		    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
+			 "xsltCopy: CDATA text %s\n", node->content));
+		} else {
+		    XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
+			 "xsltCopy: text %s\n", node->content));
+                }
+#endif
+		xsltCopyText(ctxt, ctxt->insert, node, 0);
+		break;
+	    case XML_DOCUMENT_NODE:
+	    case XML_HTML_DOCUMENT_NODE:
+		break;
+	    case XML_ELEMENT_NODE:
+		/*
+		* REVISIT NOTE: The "fake" is a doc-node, not an element node.
+		* REMOVED:
+		*   if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt"))
+		*    return;
+		*/
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
+				 "xsltCopy: node %s\n", node->name));
+#endif
+		copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0);
+		ctxt->insert = copy;
+		if (comp->use != NULL) {
+		    xsltApplyAttributeSet(ctxt, node, inst, comp->use);
+		}
+		break;
+	    case XML_ATTRIBUTE_NODE: {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
+				 "xsltCopy: attribute %s\n", node->name));
+#endif
+		/*
+		* REVISIT: We could also raise an error if the parent is not
+		* an element node.
+		* OPTIMIZE TODO: Can we set the value/children of the
+		* attribute without an intermediate copy of the string value?
+		*/
+		xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node);
+		break;
+	    }
+	    case XML_PI_NODE:
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
+				 "xsltCopy: PI %s\n", node->name));
+#endif
+		copy = xmlNewDocPI(ctxt->insert->doc, node->name,
+		                   node->content);
+		copy = xsltAddChild(ctxt->insert, copy);
+		break;
+	    case XML_COMMENT_NODE:
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
+				 "xsltCopy: comment\n"));
+#endif
+		copy = xmlNewComment(node->content);
+		copy = xsltAddChild(ctxt->insert, copy);
+		break;
+	    case XML_NAMESPACE_DECL:
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext,
+				 "xsltCopy: namespace declaration\n"));
+#endif
+		xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node);
+		break;
+	    default:
+		break;
+
+	}
+    }
+
+    switch (node->type) {
+	case XML_DOCUMENT_NODE:
+	case XML_HTML_DOCUMENT_NODE:
+	case XML_ELEMENT_NODE:
+	    xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
+		NULL);
+	    break;
+	default:
+	    break;
+    }
+    ctxt->insert = oldInsert;
+}
+
+/**
+ * xsltText:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt text node
+ * @comp:  precomputed information
+ *
+ * Process the xslt text node on the source node
+ */
+void
+xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED,
+	    xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
+    if ((inst->children != NULL) && (comp != NULL)) {
+	xmlNodePtr text = inst->children;
+	xmlNodePtr copy;
+
+	while (text != NULL) {
+	    if ((text->type != XML_TEXT_NODE) &&
+	         (text->type != XML_CDATA_SECTION_NODE)) {
+		xsltTransformError(ctxt, NULL, inst,
+				 "xsl:text content problem\n");
+		break;
+	    }
+	    copy = xmlNewDocText(ctxt->output, text->content);
+	    if (text->type != XML_CDATA_SECTION_NODE) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+		xsltGenericDebug(xsltGenericDebugContext,
+		     "Disable escaping: %s\n", text->content);
+#endif
+		copy->name = xmlStringTextNoenc;
+	    }
+	    copy = xsltAddChild(ctxt->insert, copy);
+	    text = text->next;
+	}
+    }
+}
+
+/**
+ * xsltElement:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt element node
+ * @castedComp:  precomputed information
+ *
+ * Process the xslt element node on the source node
+ */
+void
+xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	    xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif
+    xmlChar *prop = NULL;
+    const xmlChar *name, *prefix = NULL, *nsName = NULL;
+    xmlNodePtr copy;
+    xmlNodePtr oldInsert;
+
+    if (ctxt->insert == NULL)
+	return;
+
+    /*
+    * A comp->has_name == 0 indicates that we need to skip this instruction,
+    * since it was evaluated to be invalid already during compilation.
+    */
+    if (!comp->has_name)
+        return;
+
+    /*
+     * stack and saves
+     */
+    oldInsert = ctxt->insert;
+
+    if (comp->name == NULL) {
+	/* TODO: fix attr acquisition wrt to the XSLT namespace */
+        prop = xsltEvalAttrValueTemplate(ctxt, inst,
+	    (const xmlChar *) "name", XSLT_NAMESPACE);
+        if (prop == NULL) {
+            xsltTransformError(ctxt, NULL, inst,
+		"xsl:element: The attribute 'name' is missing.\n");
+            goto error;
+        }
+	if (xmlValidateQName(prop, 0)) {
+	    xsltTransformError(ctxt, NULL, inst,
+		"xsl:element: The effective name '%s' is not a "
+		"valid QName.\n", prop);
+	    /* we fall through to catch any further errors, if possible */
+	}
+	name = xsltSplitQName(ctxt->dict, prop, &prefix);
+	xmlFree(prop);
+	if ((prefix != NULL) &&
+	    (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3)))
+	{
+	    /*
+	    * TODO: Should we really disallow an "xml" prefix?
+	    */
+	    goto error;
+	}
+    } else {
+	/*
+	* The "name" value was static.
+	*/
+#ifdef XSLT_REFACTORED
+	prefix = comp->nsPrefix;
+	name = comp->name;
+#else
+	name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
+#endif
+    }
+
+    /*
+     * Create the new element
+     */
+    if (ctxt->output->dict == ctxt->dict) {
+	copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL);
+    } else {
+	copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL);
+    }
+    if (copy == NULL) {
+	xsltTransformError(ctxt, NULL, inst,
+	    "xsl:element : creation of %s failed\n", name);
+	return;
+    }
+    copy = xsltAddChild(ctxt->insert, copy);
+
+    /*
+    * Namespace
+    * ---------
+    */
+    if (comp->has_ns) {
+	if (comp->ns != NULL) {
+	    /*
+	    * No AVT; just plain text for the namespace name.
+	    */
+	    if (comp->ns[0] != 0)
+		nsName = comp->ns;
+	} else {
+	    xmlChar *tmpNsName;
+	    /*
+	    * Eval the AVT.
+	    */
+	    /* TODO: check attr acquisition wrt to the XSLT namespace */
+	    tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
+		(const xmlChar *) "namespace", XSLT_NAMESPACE);
+	    /*
+	    * SPEC XSLT 1.0:
+	    *  "If the string is empty, then the expanded-name of the
+	    *  attribute has a null namespace URI."
+	    */
+	    if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
+		nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
+	    xmlFree(tmpNsName);
+	};
+    } else {
+	xmlNsPtr ns;
+	/*
+	* SPEC XSLT 1.0:
+	*  "If the namespace attribute is not present, then the QName is
+	*  expanded into an expanded-name using the namespace declarations
+	*  in effect for the xsl:element element, including any default
+	*  namespace declaration.
+	*/
+	ns = xmlSearchNs(inst->doc, inst, prefix);
+	if (ns == NULL) {
+	    /*
+	    * TODO: Check this in the compilation layer in case it's a
+	    * static value.
+	    */
+	    if (prefix != NULL) {
+		xsltTransformError(ctxt, NULL, inst,
+		    "xsl:element: The QName '%s:%s' has no "
+		    "namespace binding in scope in the stylesheet; "
+		    "this is an error, since the namespace was not "
+		    "specified by the instruction itself.\n", prefix, name);
+	    }
+	} else
+	    nsName = ns->href;
+    }
+    /*
+    * Find/create a matching ns-decl in the result tree.
+    */
+    if (nsName != NULL) {
+	copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, copy);
+    } else if ((copy->parent != NULL) &&
+	(copy->parent->type == XML_ELEMENT_NODE) &&
+	(copy->parent->ns != NULL))
+    {
+	/*
+	* "Undeclare" the default namespace.
+	*/
+	xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy);
+    }
+
+    ctxt->insert = copy;
+
+    if (comp->has_use) {
+	if (comp->use != NULL) {
+	    xsltApplyAttributeSet(ctxt, node, inst, comp->use);
+	} else {
+	    xmlChar *attrSets = NULL;
+	    /*
+	    * BUG TODO: use-attribute-sets is not a value template.
+	    *  use-attribute-sets = qnames
+	    */
+	    attrSets = xsltEvalAttrValueTemplate(ctxt, inst,
+		(const xmlChar *)"use-attribute-sets", NULL);
+	    if (attrSets != NULL) {
+		xsltApplyAttributeSet(ctxt, node, inst, attrSets);
+		xmlFree(attrSets);
+	    }
+	}
+    }
+    /*
+    * Instantiate the sequence constructor.
+    */
+    if (inst->children != NULL)
+	xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children,
+	    NULL);
+
+error:
+    ctxt->insert = oldInsert;
+    return;
+}
+
+
+/**
+ * xsltComment:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt comment node
+ * @comp:  precomputed information
+ *
+ * Process the xslt comment node on the source node
+ */
+void
+xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	           xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) {
+    xmlChar *value = NULL;
+    xmlNodePtr commentNode;
+    int len;
+
+    value = xsltEvalTemplateString(ctxt, node, inst);
+    /* TODO: use or generate the compiled form */
+    len = xmlStrlen(value);
+    if (len > 0) {
+        if ((value[len-1] == '-') ||
+	    (xmlStrstr(value, BAD_CAST "--"))) {
+	    xsltTransformError(ctxt, NULL, inst,
+		    "xsl:comment : '--' or ending '-' not allowed in comment\n");
+	    /* fall through to try to catch further errors */
+	}
+    }
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    if (value == NULL) {
+	XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltComment: empty\n"));
+    } else {
+	XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltComment: content %s\n", value));
+    }
+#endif
+
+    commentNode = xmlNewComment(value);
+    commentNode = xsltAddChild(ctxt->insert, commentNode);
+
+    if (value != NULL)
+	xmlFree(value);
+}
+
+/**
+ * xsltProcessingInstruction:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt processing-instruction node
+ * @castedComp:  precomputed information
+ *
+ * Process the xslt processing-instruction node on the source node
+ */
+void
+xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	           xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif
+    const xmlChar *name;
+    xmlChar *value = NULL;
+    xmlNodePtr pi;
+
+
+    if (ctxt->insert == NULL)
+	return;
+    if (comp->has_name == 0)
+	return;
+    if (comp->name == NULL) {
+	name = xsltEvalAttrValueTemplate(ctxt, inst,
+			    (const xmlChar *)"name", NULL);
+	if (name == NULL) {
+	    xsltTransformError(ctxt, NULL, inst,
+		 "xsl:processing-instruction : name is missing\n");
+	    goto error;
+	}
+    } else {
+	name = comp->name;
+    }
+    /* TODO: check that it's both an an NCName and a PITarget. */
+
+
+    value = xsltEvalTemplateString(ctxt, node, inst);
+    if (xmlStrstr(value, BAD_CAST "?>") != NULL) {
+	xsltTransformError(ctxt, NULL, inst,
+	     "xsl:processing-instruction: '?>' not allowed within PI content\n");
+	goto error;
+    }
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    if (value == NULL) {
+	XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltProcessingInstruction: %s empty\n", name));
+    } else {
+	XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltProcessingInstruction: %s content %s\n", name, value));
+    }
+#endif
+
+    pi = xmlNewDocPI(ctxt->insert->doc, name, value);
+    pi = xsltAddChild(ctxt->insert, pi);
+
+error:
+    if ((name != NULL) && (name != comp->name))
+        xmlFree((xmlChar *) name);
+    if (value != NULL)
+	xmlFree(value);
+}
+
+/**
+ * xsltCopyOf:
+ * @ctxt:  an XSLT transformation context
+ * @node:  the current node in the source tree
+ * @inst:  the element node of the XSLT copy-of instruction
+ * @castedComp:  precomputed information of the XSLT copy-of instruction
+ *
+ * Process the XSLT copy-of instruction.
+ */
+void
+xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	           xmlNodePtr inst, xsltStylePreCompPtr castedComp) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif
+    xmlXPathObjectPtr res = NULL;
+    xmlNodeSetPtr list = NULL;
+    int i;
+    xmlDocPtr oldXPContextDoc;
+    xmlNsPtr *oldXPNamespaces;
+    xmlNodePtr oldXPContextNode;
+    int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
+    xmlXPathContextPtr xpctxt;
+
+    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
+	return;
+    if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
+	xsltTransformError(ctxt, NULL, inst,
+	     "xsl:copy-of : compilation failed\n");
+	return;
+    }
+
+     /*
+    * SPEC XSLT 1.0:
+    *  "The xsl:copy-of element can be used to insert a result tree
+    *  fragment into the result tree, without first converting it to
+    *  a string as xsl:value-of does (see [7.6.1 Generating Text with
+    *  xsl:value-of]). The required select attribute contains an
+    *  expression. When the result of evaluating the expression is a
+    *  result tree fragment, the complete fragment is copied into the
+    *  result tree. When the result is a node-set, all the nodes in the
+    *  set are copied in document order into the result tree; copying
+    *  an element node copies the attribute nodes, namespace nodes and
+    *  children of the element node as well as the element node itself;
+    *  a root node is copied by copying its children. When the result
+    *  is neither a node-set nor a result tree fragment, the result is
+    *  converted to a string and then inserted into the result tree,
+    *  as with xsl:value-of.
+    */
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
+	 "xsltCopyOf: select %s\n", comp->select));
+#endif
+
+    /*
+    * Evaluate the "select" expression.
+    */
+    xpctxt = ctxt->xpathCtxt;
+    oldXPContextDoc = xpctxt->doc;
+    oldXPContextNode = xpctxt->node;
+    oldXPProximityPosition = xpctxt->proximityPosition;
+    oldXPContextSize = xpctxt->contextSize;
+    oldXPNsNr = xpctxt->nsNr;
+    oldXPNamespaces = xpctxt->namespaces;
+
+    xpctxt->node = node;
+    if (comp != NULL) {
+
+#ifdef XSLT_REFACTORED
+	if (comp->inScopeNs != NULL) {
+	    xpctxt->namespaces = comp->inScopeNs->list;
+	    xpctxt->nsNr = comp->inScopeNs->xpathNumber;
+	} else {
+	    xpctxt->namespaces = NULL;
+	    xpctxt->nsNr = 0;
+	}
+#else
+	xpctxt->namespaces = comp->nsList;
+	xpctxt->nsNr = comp->nsNr;
+#endif
+    } else {
+	xpctxt->namespaces = NULL;
+	xpctxt->nsNr = 0;
+    }
+
+    res = xmlXPathCompiledEval(comp->comp, xpctxt);
+
+    xpctxt->doc = oldXPContextDoc;
+    xpctxt->node = oldXPContextNode;
+    xpctxt->contextSize = oldXPContextSize;
+    xpctxt->proximityPosition = oldXPProximityPosition;
+    xpctxt->nsNr = oldXPNsNr;
+    xpctxt->namespaces = oldXPNamespaces;
+
+    if (res != NULL) {
+	if (res->type == XPATH_NODESET) {
+	    /*
+	    * Node-set
+	    * --------
+	    */
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
+		 "xsltCopyOf: result is a node set\n"));
+#endif
+	    list = res->nodesetval;
+	    if (list != NULL) {
+		xmlNodePtr cur;
+		/*
+		* The list is already sorted in document order by XPath.
+		* Append everything in this order under ctxt->insert.
+		*/
+		for (i = 0;i < list->nodeNr;i++) {
+		    cur = list->nodeTab[i];
+		    if (cur == NULL)
+			continue;
+		    if ((cur->type == XML_DOCUMENT_NODE) ||
+			(cur->type == XML_HTML_DOCUMENT_NODE))
+		    {
+			xsltCopyTreeList(ctxt, inst,
+			    cur->children, ctxt->insert, 0, 0);
+		    } else if (cur->type == XML_ATTRIBUTE_NODE) {
+			xsltShallowCopyAttr(ctxt, inst,
+			    ctxt->insert, (xmlAttrPtr) cur);
+		    } else {
+			xsltCopyTreeInternal(ctxt, inst,
+			    cur, ctxt->insert, 0, 0);
+		    }
+		}
+	    }
+	} else if (res->type == XPATH_XSLT_TREE) {
+	    /*
+	    * Result tree fragment
+	    * --------------------
+	    * E.g. via <xsl:variable ...><foo/></xsl:variable>
+	    * Note that the root node of such trees is an xmlDocPtr in Libxslt.
+	    */
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	    XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
+		 "xsltCopyOf: result is a result tree fragment\n"));
+#endif
+	    list = res->nodesetval;
+	    if ((list != NULL) && (list->nodeTab != NULL) &&
+		(list->nodeTab[0] != NULL) &&
+		(IS_XSLT_REAL_NODE(list->nodeTab[0])))
+	    {
+		xsltCopyTreeList(ctxt, inst,
+		    list->nodeTab[0]->children, ctxt->insert, 0, 0);
+	    }
+	} else {
+	    xmlChar *value = NULL;
+	    /*
+	    * Convert to a string.
+	    */
+	    value = xmlXPathCastToString(res);
+	    if (value == NULL) {
+		xsltTransformError(ctxt, NULL, inst,
+		    "Internal error in xsltCopyOf(): "
+		    "failed to cast an XPath object to string.\n");
+		ctxt->state = XSLT_STATE_STOPPED;
+	    } else {
+		if (value[0] != 0) {
+		    /*
+		    * Append content as text node.
+		    */
+		    xsltCopyTextString(ctxt, ctxt->insert, value, 0);
+		}
+		xmlFree(value);
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext,
+		    "xsltCopyOf: result %s\n", res->stringval));
+#endif
+	    }
+	}
+    } else {
+	ctxt->state = XSLT_STATE_STOPPED;
+    }
+
+    if (res != NULL)
+	xmlXPathFreeObject(res);
+}
+
+/**
+ * xsltValueOf:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt value-of node
+ * @castedComp:  precomputed information
+ *
+ * Process the xslt value-of node on the source node
+ */
+void
+xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	           xmlNodePtr inst, xsltStylePreCompPtr castedComp)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif
+    xmlXPathObjectPtr res = NULL;
+    xmlNodePtr copy = NULL;
+    xmlChar *value = NULL;
+    xmlDocPtr oldXPContextDoc;
+    xmlNsPtr *oldXPNamespaces;
+    xmlNodePtr oldXPContextNode;
+    int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
+    xmlXPathContextPtr xpctxt;
+
+    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
+	return;
+
+    if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) {
+	xsltTransformError(ctxt, NULL, inst,
+	    "Internal error in xsltValueOf(): "
+	    "The XSLT 'value-of' instruction was not compiled.\n");
+	return;
+    }
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
+	 "xsltValueOf: select %s\n", comp->select));
+#endif
+
+    xpctxt = ctxt->xpathCtxt;
+    oldXPContextDoc = xpctxt->doc;
+    oldXPContextNode = xpctxt->node;
+    oldXPProximityPosition = xpctxt->proximityPosition;
+    oldXPContextSize = xpctxt->contextSize;
+    oldXPNsNr = xpctxt->nsNr;
+    oldXPNamespaces = xpctxt->namespaces;
+
+    xpctxt->node = node;
+    if (comp != NULL) {
+
+#ifdef XSLT_REFACTORED
+	if (comp->inScopeNs != NULL) {
+	    xpctxt->namespaces = comp->inScopeNs->list;
+	    xpctxt->nsNr = comp->inScopeNs->xpathNumber;
+	} else {
+	    xpctxt->namespaces = NULL;
+	    xpctxt->nsNr = 0;
+	}
+#else
+	xpctxt->namespaces = comp->nsList;
+	xpctxt->nsNr = comp->nsNr;
+#endif
+    } else {
+	xpctxt->namespaces = NULL;
+	xpctxt->nsNr = 0;
+    }
+
+    res = xmlXPathCompiledEval(comp->comp, xpctxt);
+
+    xpctxt->doc = oldXPContextDoc;
+    xpctxt->node = oldXPContextNode;
+    xpctxt->contextSize = oldXPContextSize;
+    xpctxt->proximityPosition = oldXPProximityPosition;
+    xpctxt->nsNr = oldXPNsNr;
+    xpctxt->namespaces = oldXPNamespaces;
+
+    /*
+    * Cast the XPath object to string.
+    */
+    if (res != NULL) {
+	value = xmlXPathCastToString(res);
+	if (value == NULL) {
+	    xsltTransformError(ctxt, NULL, inst,
+		"Internal error in xsltValueOf(): "
+		"failed to cast an XPath object to string.\n");
+	    ctxt->state = XSLT_STATE_STOPPED;
+	    goto error;
+	}
+	if (value[0] != 0) {
+	    copy = xsltCopyTextString(ctxt,
+		ctxt->insert, value, comp->noescape);
+	}
+    } else {
+	xsltTransformError(ctxt, NULL, inst,
+	    "XPath evaluation returned no result.\n");
+	ctxt->state = XSLT_STATE_STOPPED;
+	goto error;
+    }
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    if (value) {
+	XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltValueOf: result '%s'\n", value));
+    }
+#endif
+
+error:
+    if (value != NULL)
+	xmlFree(value);
+    if (res != NULL)
+	xmlXPathFreeObject(res);
+}
+
+/**
+ * xsltNumber:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt number node
+ * @castedComp:  precomputed information
+ *
+ * Process the xslt number node on the source node
+ */
+void
+xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	   xmlNodePtr inst, xsltStylePreCompPtr castedComp)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif
+    if (comp == NULL) {
+	xsltTransformError(ctxt, NULL, inst,
+	     "xsl:number : compilation failed\n");
+	return;
+    }
+
+    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
+	return;
+
+    comp->numdata.doc = inst->doc;
+    comp->numdata.node = inst;
+
+    xsltNumberFormat(ctxt, &comp->numdata, node);
+}
+
+/**
+ * xsltApplyImports:
+ * @ctxt:  an XSLT transformation context
+ * @contextNode:  the current node in the source tree.
+ * @inst:  the element node of the XSLT 'apply-imports' instruction
+ * @comp:  the compiled instruction
+ *
+ * Process the XSLT apply-imports element.
+ */
+void
+xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
+	         xmlNodePtr inst,
+		 xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
+{
+    xsltTemplatePtr templ;
+
+    if ((ctxt == NULL) || (inst == NULL))
+	return;
+
+    if (comp == NULL) {
+	xsltTransformError(ctxt, NULL, inst,
+	    "Internal error in xsltApplyImports(): "
+	    "The XSLT 'apply-imports' instruction was not compiled.\n");
+	return;
+    }
+    /*
+    * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
+    * same; the former is the "Current Template Rule" as defined by the
+    * XSLT spec, the latter is simply the template struct being
+    * currently processed.
+    */
+    if (ctxt->currentTemplateRule == NULL) {
+	/*
+	* SPEC XSLT 2.0:
+	* "[ERR XTDE0560] It is a non-recoverable dynamic error if
+	*  xsl:apply-imports or xsl:next-match is evaluated when the
+	*  current template rule is null."
+	*/
+	xsltTransformError(ctxt, NULL, inst,
+	     "It is an error to call 'apply-imports' "
+	     "when there's no current template rule.\n");
+	return;
+    }
+    /*
+    * TODO: Check if this is correct.
+    */
+    templ = xsltGetTemplate(ctxt, contextNode,
+	ctxt->currentTemplateRule->style);
+
+    if (templ != NULL) {
+	xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule;
+	/*
+	* Set the current template rule.
+	*/
+	ctxt->currentTemplateRule = templ;
+	/*
+	* URGENT TODO: Need xsl:with-param be handled somehow here?
+	*/
+	xsltApplyXSLTTemplate(ctxt, contextNode, templ->content,
+	    templ, NULL);
+
+	ctxt->currentTemplateRule = oldCurTemplRule;
+    }
+}
+
+/**
+ * xsltCallTemplate:
+ * @ctxt:  a XSLT transformation context
+ * @node:  the "current node" in the source tree
+ * @inst:  the XSLT 'call-template' instruction
+ * @castedComp:  the compiled information of the instruction
+ *
+ * Processes the XSLT call-template instruction on the source node.
+ */
+void
+xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	           xmlNodePtr inst, xsltStylePreCompPtr castedComp)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleItemCallTemplatePtr comp =
+	(xsltStyleItemCallTemplatePtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif
+    xsltStackElemPtr withParams = NULL;
+
+    if (ctxt->insert == NULL)
+	return;
+    if (comp == NULL) {
+	xsltTransformError(ctxt, NULL, inst,
+	     "The XSLT 'call-template' instruction was not compiled.\n");
+	return;
+    }
+
+    /*
+     * The template must have been precomputed
+     */
+    if (comp->templ == NULL) {
+	comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns);
+	if (comp->templ == NULL) {
+	    if (comp->ns != NULL) {
+	        xsltTransformError(ctxt, NULL, inst,
+			"The called template '{%s}%s' was not found.\n",
+			comp->ns, comp->name);
+	    } else {
+	        xsltTransformError(ctxt, NULL, inst,
+			"The called template '%s' was not found.\n",
+			comp->name);
+	    }
+	    return;
+	}
+    }
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    if ((comp != NULL) && (comp->name != NULL))
+	XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
+			 "call-template: name %s\n", comp->name));
+#endif
+
+    if (inst->children) {
+	xmlNodePtr cur;
+	xsltStackElemPtr param;
+
+	cur = inst->children;
+	while (cur != NULL) {
+#ifdef WITH_DEBUGGER
+	    if (ctxt->debugStatus != XSLT_DEBUG_NONE)
+		xslHandleDebugger(cur, node, comp->templ, ctxt);
+#endif
+	    if (ctxt->state == XSLT_STATE_STOPPED) break;
+	    /*
+	    * TODO: The "with-param"s could be part of the "call-template"
+	    *   structure. Avoid to "search" for params dynamically
+	    *   in the XML tree every time.
+	    */
+	    if (IS_XSLT_ELEM(cur)) {
+		if (IS_XSLT_NAME(cur, "with-param")) {
+		    param = xsltParseStylesheetCallerParam(ctxt, cur);
+		    if (param != NULL) {
+			param->next = withParams;
+			withParams = param;
+		    }
+		} else {
+		    xsltGenericError(xsltGenericErrorContext,
+			"xsl:call-template: misplaced xsl:%s\n", cur->name);
+		}
+	    } else {
+		xsltGenericError(xsltGenericErrorContext,
+		    "xsl:call-template: misplaced %s element\n", cur->name);
+	    }
+	    cur = cur->next;
+	}
+    }
+    /*
+     * Create a new frame using the params first
+     */
+    xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ,
+	withParams);
+    if (withParams != NULL)
+	xsltFreeStackElemList(withParams);
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    if ((comp != NULL) && (comp->name != NULL))
+	XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext,
+			 "call-template returned: name %s\n", comp->name));
+#endif
+}
+
+/**
+ * xsltApplyTemplates:
+ * @ctxt:  a XSLT transformation context
+ * @node:  the 'current node' in the source tree
+ * @inst:  the element node of an XSLT 'apply-templates' instruction
+ * @castedComp:  the compiled instruction
+ *
+ * Processes the XSLT 'apply-templates' instruction on the current node.
+ */
+void
+xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	           xmlNodePtr inst, xsltStylePreCompPtr castedComp)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleItemApplyTemplatesPtr comp =
+	(xsltStyleItemApplyTemplatesPtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif
+    int i;
+    xmlNodePtr cur, delNode = NULL, oldContextNode;
+    xmlNodeSetPtr list = NULL, oldList;
+    xsltStackElemPtr withParams = NULL;
+    int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
+    const xmlChar *oldMode, *oldModeURI;
+    xmlDocPtr oldXPDoc;
+    xsltDocumentPtr oldDocInfo;
+    xmlXPathContextPtr xpctxt;
+    xmlNsPtr *oldXPNamespaces;
+
+    if (comp == NULL) {
+	xsltTransformError(ctxt, NULL, inst,
+	     "xsl:apply-templates : compilation failed\n");
+	return;
+    }
+    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
+	return;
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    if ((node != NULL) && (node->name != NULL))
+	XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltApplyTemplates: node: '%s'\n", node->name));
+#endif
+
+    xpctxt = ctxt->xpathCtxt;
+    /*
+    * Save context states.
+    */
+    oldContextNode = ctxt->node;
+    oldMode = ctxt->mode;
+    oldModeURI = ctxt->modeURI;
+    oldDocInfo = ctxt->document;
+    oldList = ctxt->nodeList;
+
+    /*
+     * The xpath context size and proximity position, as
+     * well as the xpath and context documents, may be changed
+     * so we save their initial state and will restore on exit
+     */
+    oldXPContextSize = xpctxt->contextSize;
+    oldXPProximityPosition = xpctxt->proximityPosition;
+    oldXPDoc = xpctxt->doc;
+    oldXPNsNr = xpctxt->nsNr;
+    oldXPNamespaces = xpctxt->namespaces;
+
+    /*
+    * Set up contexts.
+    */
+    ctxt->mode = comp->mode;
+    ctxt->modeURI = comp->modeURI;
+
+    if (comp->select != NULL) {
+	xmlXPathObjectPtr res = NULL;
+
+	if (comp->comp == NULL) {
+	    xsltTransformError(ctxt, NULL, inst,
+		 "xsl:apply-templates : compilation failed\n");
+	    goto error;
+	}
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltApplyTemplates: select %s\n", comp->select));
+#endif
+
+	/*
+	* Set up XPath.
+	*/
+	xpctxt->node = node; /* Set the "context node" */
+#ifdef XSLT_REFACTORED
+	if (comp->inScopeNs != NULL) {
+	    xpctxt->namespaces = comp->inScopeNs->list;
+	    xpctxt->nsNr = comp->inScopeNs->xpathNumber;
+	} else {
+	    xpctxt->namespaces = NULL;
+	    xpctxt->nsNr = 0;
+	}
+#else
+	xpctxt->namespaces = comp->nsList;
+	xpctxt->nsNr = comp->nsNr;
+#endif
+	res = xmlXPathCompiledEval(comp->comp, xpctxt);
+
+	xpctxt->contextSize = oldXPContextSize;
+	xpctxt->proximityPosition = oldXPProximityPosition;
+	if (res != NULL) {
+	    if (res->type == XPATH_NODESET) {
+		list = res->nodesetval; /* consume the node set */
+		res->nodesetval = NULL;
+	    } else {
+		xsltTransformError(ctxt, NULL, inst,
+		    "The 'select' expression did not evaluate to a "
+		    "node set.\n");
+		ctxt->state = XSLT_STATE_STOPPED;
+		xmlXPathFreeObject(res);
+		goto error;
+	    }
+	    xmlXPathFreeObject(res);
+	    /*
+	    * Note: An xsl:apply-templates with a 'select' attribute,
+	    * can change the current source doc.
+	    */
+	} else {
+	    xsltTransformError(ctxt, NULL, inst,
+		"Failed to evaluate the 'select' expression.\n");
+	    ctxt->state = XSLT_STATE_STOPPED;
+	    goto error;
+	}
+	if (list == NULL) {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	    XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
+		"xsltApplyTemplates: select didn't evaluate to a node list\n"));
+#endif
+	    goto exit;
+	}
+	/*
+	*
+	* NOTE: Previously a document info (xsltDocument) was
+	* created and attached to the Result Tree Fragment.
+	* But such a document info is created on demand in
+	* xsltKeyFunction() (functions.c), so we need to create
+	* it here beforehand.
+	* In order to take care of potential keys we need to
+	* do some extra work for the case when a Result Tree Fragment
+	* is converted into a nodeset (e.g. exslt:node-set()) :
+	* We attach a "pseudo-doc" (xsltDocument) to _private.
+	* This xsltDocument, together with the keyset, will be freed
+	* when the Result Tree Fragment is freed.
+	*
+	*/
+#if 0
+	if ((ctxt->nbKeys > 0) &&
+	    (list->nodeNr != 0) &&
+	    (list->nodeTab[0]->doc != NULL) &&
+	    XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc))
+	{
+	    /*
+	    * NOTE that it's also OK if @effectiveDocInfo will be
+	    * set to NULL.
+	    */
+	    isRTF = 1;
+	    effectiveDocInfo = list->nodeTab[0]->doc->_private;
+	}
+#endif
+    } else {
+	/*
+	 * Build an XPath node set with the children
+	 */
+	list = xmlXPathNodeSetCreate(NULL);
+	if (list == NULL)
+	    goto error;
+	cur = node->children;
+	while (cur != NULL) {
+	    switch (cur->type) {
+		case XML_TEXT_NODE:
+		    if ((IS_BLANK_NODE(cur)) &&
+			(cur->parent != NULL) &&
+			(cur->parent->type == XML_ELEMENT_NODE) &&
+			(ctxt->style->stripSpaces != NULL)) {
+			const xmlChar *val;
+
+			if (cur->parent->ns != NULL) {
+			    val = (const xmlChar *)
+				  xmlHashLookup2(ctxt->style->stripSpaces,
+						 cur->parent->name,
+						 cur->parent->ns->href);
+			    if (val == NULL) {
+				val = (const xmlChar *)
+				  xmlHashLookup2(ctxt->style->stripSpaces,
+						 BAD_CAST "*",
+						 cur->parent->ns->href);
+			    }
+			} else {
+			    val = (const xmlChar *)
+				  xmlHashLookup2(ctxt->style->stripSpaces,
+						 cur->parent->name, NULL);
+			}
+			if ((val != NULL) &&
+			    (xmlStrEqual(val, (xmlChar *) "strip"))) {
+			    delNode = cur;
+			    break;
+			}
+		    }
+		    /* no break on purpose */
+		case XML_ELEMENT_NODE:
+		case XML_DOCUMENT_NODE:
+		case XML_HTML_DOCUMENT_NODE:
+		case XML_CDATA_SECTION_NODE:
+		case XML_PI_NODE:
+		case XML_COMMENT_NODE:
+		    xmlXPathNodeSetAddUnique(list, cur);
+		    break;
+		case XML_DTD_NODE:
+		    /* Unlink the DTD, it's still reachable
+		     * using doc->intSubset */
+		    if (cur->next != NULL)
+			cur->next->prev = cur->prev;
+		    if (cur->prev != NULL)
+			cur->prev->next = cur->next;
+		    break;
+		default:
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		    XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltApplyTemplates: skipping cur type %d\n",
+				     cur->type));
+#endif
+		    delNode = cur;
+	    }
+	    cur = cur->next;
+	    if (delNode != NULL) {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltApplyTemplates: removing ignorable blank cur\n"));
+#endif
+		xmlUnlinkNode(delNode);
+		xmlFreeNode(delNode);
+		delNode = NULL;
+	    }
+	}
+    }
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    if (list != NULL)
+    XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext,
+	"xsltApplyTemplates: list of %d nodes\n", list->nodeNr));
+#endif
+
+    if ((list == NULL) || (list->nodeNr == 0))
+	goto exit;
+
+    /*
+    * Set the context's node set and size; this is also needed for
+    * for xsltDoSortFunction().
+    */
+    ctxt->nodeList = list;
+    /*
+    * Process xsl:with-param and xsl:sort instructions.
+    * (The code became so verbose just to avoid the
+    *  xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort)
+    * BUG TODO: We are not using namespaced potentially defined on the
+    * xsl:sort or xsl:with-param elements; XPath expression might fail.
+    */
+    if (inst->children) {
+	xsltStackElemPtr param;
+
+	cur = inst->children;
+	while (cur) {
+
+#ifdef WITH_DEBUGGER
+	    if (ctxt->debugStatus != XSLT_DEBUG_NONE)
+		xslHandleDebugger(cur, node, NULL, ctxt);
+#endif
+	    if (ctxt->state == XSLT_STATE_STOPPED)
+		break;
+	    if (cur->type == XML_TEXT_NODE) {
+		cur = cur->next;
+		continue;
+	    }
+	    if (! IS_XSLT_ELEM(cur))
+		break;
+	    if (IS_XSLT_NAME(cur, "with-param")) {
+		param = xsltParseStylesheetCallerParam(ctxt, cur);
+		if (param != NULL) {
+		    param->next = withParams;
+		    withParams = param;
+		}
+	    }
+	    if (IS_XSLT_NAME(cur, "sort")) {
+		xsltTemplatePtr oldCurTempRule =
+		    ctxt->currentTemplateRule;
+		int nbsorts = 0;
+		xmlNodePtr sorts[XSLT_MAX_SORT];
+
+		sorts[nbsorts++] = cur;
+
+		while (cur) {
+
+#ifdef WITH_DEBUGGER
+		    if (ctxt->debugStatus != XSLT_DEBUG_NONE)
+			xslHandleDebugger(cur, node, NULL, ctxt);
+#endif
+		    if (ctxt->state == XSLT_STATE_STOPPED)
+			break;
+
+		    if (cur->type == XML_TEXT_NODE) {
+			cur = cur->next;
+			continue;
+		    }
+
+		    if (! IS_XSLT_ELEM(cur))
+			break;
+		    if (IS_XSLT_NAME(cur, "with-param")) {
+			param = xsltParseStylesheetCallerParam(ctxt, cur);
+			if (param != NULL) {
+			    param->next = withParams;
+			    withParams = param;
+			}
+		    }
+		    if (IS_XSLT_NAME(cur, "sort")) {
+			if (nbsorts >= XSLT_MAX_SORT) {
+			    xsltTransformError(ctxt, NULL, cur,
+				"The number (%d) of xsl:sort instructions exceeds the "
+				"maximum allowed by this processor's settings.\n",
+				nbsorts);
+			    ctxt->state = XSLT_STATE_STOPPED;
+			    break;
+			} else {
+			    sorts[nbsorts++] = cur;
+			}
+		    }
+		    cur = cur->next;
+		}
+		/*
+		* The "current template rule" is cleared for xsl:sort.
+		*/
+		ctxt->currentTemplateRule = NULL;
+		/*
+		* Sort.
+		*/
+		xsltDoSortFunction(ctxt, sorts, nbsorts);
+		ctxt->currentTemplateRule = oldCurTempRule;
+		break;
+	    }
+	    cur = cur->next;
+	}
+    }
+    xpctxt->contextSize = list->nodeNr;
+    /*
+    * Apply templates for all selected source nodes.
+    */
+    for (i = 0; i < list->nodeNr; i++) {
+	cur = list->nodeTab[i];
+	/*
+	* The node becomes the "current node".
+	*/
+	ctxt->node = cur;
+	/*
+	* An xsl:apply-templates can change the current context doc.
+	* OPTIMIZE TODO: Get rid of the need to set the context doc.
+	*/
+	if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
+	    xpctxt->doc = cur->doc;
+
+	xpctxt->proximityPosition = i + 1;
+	/*
+	* Find and apply a template for this node.
+	*/
+	xsltProcessOneNode(ctxt, cur, withParams);
+    }
+
+exit:
+error:
+    /*
+    * Free the parameter list.
+    */
+    if (withParams != NULL)
+	xsltFreeStackElemList(withParams);
+    if (list != NULL)
+	xmlXPathFreeNodeSet(list);
+    /*
+    * Restore context states.
+    */
+    xpctxt->nsNr = oldXPNsNr;
+    xpctxt->namespaces = oldXPNamespaces;
+    xpctxt->doc = oldXPDoc;
+    xpctxt->contextSize = oldXPContextSize;
+    xpctxt->proximityPosition = oldXPProximityPosition;
+
+    ctxt->document = oldDocInfo;
+    ctxt->nodeList = oldList;
+    ctxt->node = oldContextNode;
+    ctxt->mode = oldMode;
+    ctxt->modeURI = oldModeURI;
+}
+
+
+/**
+ * xsltChoose:
+ * @ctxt:  a XSLT process context
+ * @contextNode:  the current node in the source tree
+ * @inst:  the xsl:choose instruction
+ * @comp:  compiled information of the instruction
+ *
+ * Processes the xsl:choose instruction on the source node.
+ */
+void
+xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
+	   xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
+{
+    xmlNodePtr cur;
+
+    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
+	return;
+
+    /*
+    * TODO: Content model checks should be done only at compilation
+    * time.
+    */
+    cur = inst->children;
+    if (cur == NULL) {
+	xsltTransformError(ctxt, NULL, inst,
+	    "xsl:choose: The instruction has no content.\n");
+	return;
+    }
+
+#ifdef XSLT_REFACTORED
+    /*
+    * We don't check the content model during transformation.
+    */
+#else
+    if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) {
+	xsltTransformError(ctxt, NULL, inst,
+	     "xsl:choose: xsl:when expected first\n");
+	return;
+    }
+#endif
+
+    {
+	int testRes = 0, res = 0;
+	xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
+	xmlDocPtr oldXPContextDoc = xpctxt->doc;
+	int oldXPProximityPosition = xpctxt->proximityPosition;
+	int oldXPContextSize = xpctxt->contextSize;
+	xmlNsPtr *oldXPNamespaces = xpctxt->namespaces;
+	int oldXPNsNr = xpctxt->nsNr;
+
+#ifdef XSLT_REFACTORED
+	xsltStyleItemWhenPtr wcomp = NULL;
+#else
+	xsltStylePreCompPtr wcomp = NULL;
+#endif
+
+	/*
+	* Process xsl:when ---------------------------------------------------
+	*/
+	while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) {
+	    wcomp = cur->psvi;
+
+	    if ((wcomp == NULL) || (wcomp->test == NULL) ||
+		(wcomp->comp == NULL))
+	    {
+		xsltTransformError(ctxt, NULL, cur,
+		    "Internal error in xsltChoose(): "
+		    "The XSLT 'when' instruction was not compiled.\n");
+		goto error;
+	    }
+
+
+#ifdef WITH_DEBUGGER
+	    if (xslDebugStatus != XSLT_DEBUG_NONE) {
+		/*
+		* TODO: Isn't comp->templ always NULL for xsl:choose?
+		*/
+		xslHandleDebugger(cur, contextNode, NULL, ctxt);
+	    }
+#endif
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	    XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
+		"xsltChoose: test %s\n", wcomp->test));
+#endif
+
+	    xpctxt->node = contextNode;
+	    xpctxt->doc = oldXPContextDoc;
+	    xpctxt->proximityPosition = oldXPProximityPosition;
+	    xpctxt->contextSize = oldXPContextSize;
+
+#ifdef XSLT_REFACTORED
+	    if (wcomp->inScopeNs != NULL) {
+		xpctxt->namespaces = wcomp->inScopeNs->list;
+		xpctxt->nsNr = wcomp->inScopeNs->xpathNumber;
+	    } else {
+		xpctxt->namespaces = NULL;
+		xpctxt->nsNr = 0;
+	    }
+#else
+	    xpctxt->namespaces = wcomp->nsList;
+	    xpctxt->nsNr = wcomp->nsNr;
+#endif
+
+
+#ifdef XSLT_FAST_IF
+	    res = xmlXPathCompiledEvalToBoolean(wcomp->comp, xpctxt);
+
+	    if (res == -1) {
+		ctxt->state = XSLT_STATE_STOPPED;
+		goto error;
+	    }
+	    testRes = (res == 1) ? 1 : 0;
+
+#else /* XSLT_FAST_IF */
+
+	    res = xmlXPathCompiledEval(wcomp->comp, xpctxt);
+
+	    if (res != NULL) {
+		if (res->type != XPATH_BOOLEAN)
+		    res = xmlXPathConvertBoolean(res);
+		if (res->type == XPATH_BOOLEAN)
+		    testRes = res->boolval;
+		else {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		    XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
+			"xsltChoose: test didn't evaluate to a boolean\n"));
+#endif
+		    goto error;
+		}
+		xmlXPathFreeObject(res);
+		res = NULL;
+	    } else {
+		ctxt->state = XSLT_STATE_STOPPED;
+		goto error;
+	    }
+
+#endif /* else of XSLT_FAST_IF */
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	    XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
+		"xsltChoose: test evaluate to %d\n", testRes));
+#endif
+	    if (testRes)
+		goto test_is_true;
+
+	    cur = cur->next;
+	}
+
+	/*
+	* Process xsl:otherwise ----------------------------------------------
+	*/
+	if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) {
+
+#ifdef WITH_DEBUGGER
+	    if (xslDebugStatus != XSLT_DEBUG_NONE)
+		xslHandleDebugger(cur, contextNode, NULL, ctxt);
+#endif
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	    XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext,
+		"evaluating xsl:otherwise\n"));
+#endif
+	    goto test_is_true;
+	}
+	xpctxt->node = contextNode;
+	xpctxt->doc = oldXPContextDoc;
+	xpctxt->proximityPosition = oldXPProximityPosition;
+	xpctxt->contextSize = oldXPContextSize;
+	xpctxt->namespaces = oldXPNamespaces;
+	xpctxt->nsNr = oldXPNsNr;
+	goto exit;
+
+test_is_true:
+
+	xpctxt->node = contextNode;
+	xpctxt->doc = oldXPContextDoc;
+	xpctxt->proximityPosition = oldXPProximityPosition;
+	xpctxt->contextSize = oldXPContextSize;
+	xpctxt->namespaces = oldXPNamespaces;
+	xpctxt->nsNr = oldXPNsNr;
+	goto process_sequence;
+    }
+
+process_sequence:
+
+    /*
+    * Instantiate the sequence constructor.
+    */
+    xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children,
+	NULL);
+
+exit:
+error:
+    return;
+}
+
+/**
+ * xsltIf:
+ * @ctxt:  a XSLT process context
+ * @contextNode:  the current node in the source tree
+ * @inst:  the xsl:if instruction
+ * @castedComp:  compiled information of the instruction
+ *
+ * Processes the xsl:if instruction on the source node.
+ */
+void
+xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
+	           xmlNodePtr inst, xsltStylePreCompPtr castedComp)
+{
+    int res = 0;
+
+#ifdef XSLT_REFACTORED
+    xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif
+
+    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
+	return;
+    if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) {
+	xsltTransformError(ctxt, NULL, inst,
+	    "Internal error in xsltIf(): "
+	    "The XSLT 'if' instruction was not compiled.\n");
+	return;
+    }
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
+	 "xsltIf: test %s\n", comp->test));
+#endif
+
+#ifdef XSLT_FAST_IF
+    {
+	xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
+	xmlDocPtr oldXPContextDoc = xpctxt->doc;
+	xmlNsPtr *oldXPNamespaces = xpctxt->namespaces;
+	xmlNodePtr oldXPContextNode = xpctxt->node;
+	int oldXPProximityPosition = xpctxt->proximityPosition;
+	int oldXPContextSize = xpctxt->contextSize;
+	int oldXPNsNr = xpctxt->nsNr;
+	xmlDocPtr oldLocalFragmentTop = ctxt->localRVT;
+
+	xpctxt->node = contextNode;
+	if (comp != NULL) {
+
+#ifdef XSLT_REFACTORED
+	    if (comp->inScopeNs != NULL) {
+		xpctxt->namespaces = comp->inScopeNs->list;
+		xpctxt->nsNr = comp->inScopeNs->xpathNumber;
+	    } else {
+		xpctxt->namespaces = NULL;
+		xpctxt->nsNr = 0;
+	    }
+#else
+	    xpctxt->namespaces = comp->nsList;
+	    xpctxt->nsNr = comp->nsNr;
+#endif
+	} else {
+	    xpctxt->namespaces = NULL;
+	    xpctxt->nsNr = 0;
+	}
+	/*
+	* This XPath function is optimized for boolean results.
+	*/
+	res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt);
+
+	/*
+	* Cleanup fragments created during evaluation of the
+	* "select" expression.
+	*/
+	if (oldLocalFragmentTop != ctxt->localRVT)
+	    xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop);
+
+	xpctxt->doc = oldXPContextDoc;
+	xpctxt->node = oldXPContextNode;
+	xpctxt->contextSize = oldXPContextSize;
+	xpctxt->proximityPosition = oldXPProximityPosition;
+	xpctxt->nsNr = oldXPNsNr;
+	xpctxt->namespaces = oldXPNamespaces;
+    }
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
+	"xsltIf: test evaluate to %d\n", res));
+#endif
+
+    if (res == -1) {
+	ctxt->state = XSLT_STATE_STOPPED;
+	goto error;
+    }
+    if (res == 1) {
+	/*
+	* Instantiate the sequence constructor of xsl:if.
+	*/
+	xsltApplySequenceConstructor(ctxt,
+	    contextNode, inst->children, NULL);
+    }
+
+#else /* XSLT_FAST_IF */
+    {
+	xmlXPathObjectPtr xpobj = NULL;
+	/*
+	* OLD CODE:
+	*/
+	{
+	    xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
+	    xmlDocPtr oldXPContextDoc = xpctxt->doc;
+	    xmlNsPtr *oldXPNamespaces = xpctxt->namespaces;
+	    xmlNodePtr oldXPContextNode = xpctxt->node;
+	    int oldXPProximityPosition = xpctxt->proximityPosition;
+	    int oldXPContextSize = xpctxt->contextSize;
+	    int oldXPNsNr = xpctxt->nsNr;
+
+	    xpctxt->node = contextNode;
+	    if (comp != NULL) {
+
+#ifdef XSLT_REFACTORED
+		if (comp->inScopeNs != NULL) {
+		    xpctxt->namespaces = comp->inScopeNs->list;
+		    xpctxt->nsNr = comp->inScopeNs->xpathNumber;
+		} else {
+		    xpctxt->namespaces = NULL;
+		    xpctxt->nsNr = 0;
+		}
+#else
+		xpctxt->namespaces = comp->nsList;
+		xpctxt->nsNr = comp->nsNr;
+#endif
+	    } else {
+		xpctxt->namespaces = NULL;
+		xpctxt->nsNr = 0;
+	    }
+
+	    /*
+	    * This XPath function is optimized for boolean results.
+	    */
+	    xpobj = xmlXPathCompiledEval(comp->comp, xpctxt);
+
+	    xpctxt->doc = oldXPContextDoc;
+	    xpctxt->node = oldXPContextNode;
+	    xpctxt->contextSize = oldXPContextSize;
+	    xpctxt->proximityPosition = oldXPProximityPosition;
+	    xpctxt->nsNr = oldXPNsNr;
+	    xpctxt->namespaces = oldXPNamespaces;
+	}
+	if (xpobj != NULL) {
+	    if (xpobj->type != XPATH_BOOLEAN)
+		xpobj = xmlXPathConvertBoolean(xpobj);
+	    if (xpobj->type == XPATH_BOOLEAN) {
+		res = xpobj->boolval;
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext,
+		    "xsltIf: test evaluate to %d\n", res));
+#endif
+		if (res) {
+		    xsltApplySequenceConstructor(ctxt,
+			contextNode, inst->children, NULL);
+		}
+	    } else {
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		XSLT_TRACE(ctxt, XSLT_TRACE_IF,
+		    xsltGenericDebug(xsltGenericDebugContext,
+		    "xsltIf: test didn't evaluate to a boolean\n"));
+#endif
+		ctxt->state = XSLT_STATE_STOPPED;
+	    }
+	    xmlXPathFreeObject(xpobj);
+	} else {
+	    ctxt->state = XSLT_STATE_STOPPED;
+	}
+    }
+#endif /* else of XSLT_FAST_IF */
+
+error:
+    return;
+}
+
+/**
+ * xsltForEach:
+ * @ctxt:  an XSLT transformation context
+ * @contextNode:  the "current node" in the source tree
+ * @inst:  the element node of the xsl:for-each instruction
+ * @castedComp:  the compiled information of the instruction
+ *
+ * Process the xslt for-each node on the source node
+ */
+void
+xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode,
+	    xmlNodePtr inst, xsltStylePreCompPtr castedComp)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif
+    int i;
+    xmlXPathObjectPtr res = NULL;
+    xmlNodePtr cur, curInst;
+    xmlNodeSetPtr list = NULL;
+    xmlNodeSetPtr oldList;
+    int oldXPProximityPosition, oldXPContextSize;
+    xmlNodePtr oldContextNode;
+    xsltTemplatePtr oldCurTemplRule;
+    xmlDocPtr oldXPDoc;
+    xsltDocumentPtr oldDocInfo;
+    xmlXPathContextPtr xpctxt;
+
+    if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) {
+	xsltGenericError(xsltGenericErrorContext,
+	    "xsltForEach(): Bad arguments.\n");
+	return;
+    }
+
+    if (comp == NULL) {
+        xsltTransformError(ctxt, NULL, inst,
+	    "Internal error in xsltForEach(): "
+	    "The XSLT 'for-each' instruction was not compiled.\n");
+        return;
+    }
+    if ((comp->select == NULL) || (comp->comp == NULL)) {
+	xsltTransformError(ctxt, NULL, inst,
+	    "Internal error in xsltForEach(): "
+	    "The selecting expression of the XSLT 'for-each' "
+	    "instruction was not compiled correctly.\n");
+	return;
+    }
+    xpctxt = ctxt->xpathCtxt;
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
+	 "xsltForEach: select %s\n", comp->select));
+#endif
+
+    /*
+    * Save context states.
+    */
+    oldDocInfo = ctxt->document;
+    oldList = ctxt->nodeList;
+    oldContextNode = ctxt->node;
+    /*
+    * The "current template rule" is cleared for the instantiation of
+    * xsl:for-each.
+    */
+    oldCurTemplRule = ctxt->currentTemplateRule;
+    ctxt->currentTemplateRule = NULL;
+
+    oldXPDoc = xpctxt->doc;
+    oldXPProximityPosition = xpctxt->proximityPosition;
+    oldXPContextSize = xpctxt->contextSize;
+    /*
+    * Set up XPath.
+    */
+    xpctxt->node = contextNode;
+#ifdef XSLT_REFACTORED
+    if (comp->inScopeNs != NULL) {
+	xpctxt->namespaces = comp->inScopeNs->list;
+	xpctxt->nsNr = comp->inScopeNs->xpathNumber;
+    } else {
+	xpctxt->namespaces = NULL;
+	xpctxt->nsNr = 0;
+    }
+#else
+    xpctxt->namespaces = comp->nsList;
+    xpctxt->nsNr = comp->nsNr;
+#endif
+
+    /*
+    * Evaluate the 'select' expression.
+    */
+    res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
+
+    if (res != NULL) {
+	if (res->type == XPATH_NODESET)
+	    list = res->nodesetval;
+	else {
+	    xsltTransformError(ctxt, NULL, inst,
+		"The 'select' expression does not evaluate to a node set.\n");
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+	    XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
+		"xsltForEach: select didn't evaluate to a node list\n"));
+#endif
+	    goto error;
+	}
+    } else {
+	xsltTransformError(ctxt, NULL, inst,
+	    "Failed to evaluate the 'select' expression.\n");
+	ctxt->state = XSLT_STATE_STOPPED;
+	goto error;
+    }
+
+    if ((list == NULL) || (list->nodeNr <= 0))
+	goto exit;
+
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext,
+	"xsltForEach: select evaluates to %d nodes\n", list->nodeNr));
+#endif
+
+    /*
+    * Restore XPath states for the "current node".
+    */
+    xpctxt->contextSize = oldXPContextSize;
+    xpctxt->proximityPosition = oldXPProximityPosition;
+    xpctxt->node = contextNode;
+
+    /*
+    * Set the list; this has to be done already here for xsltDoSortFunction().
+    */
+    ctxt->nodeList = list;
+    /*
+    * Handle xsl:sort instructions and skip them for further processing.
+    * BUG TODO: We are not using namespaced potentially defined on the
+    * xsl:sort element; XPath expression might fail.
+    */
+    curInst = inst->children;
+    if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
+	int nbsorts = 0;
+	xmlNodePtr sorts[XSLT_MAX_SORT];
+
+	sorts[nbsorts++] = curInst;
+
+#ifdef WITH_DEBUGGER
+	if (xslDebugStatus != XSLT_DEBUG_NONE)
+	    xslHandleDebugger(curInst, contextNode, NULL, ctxt);
+#endif
+
+	curInst = curInst->next;
+	while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) {
+	    if (nbsorts >= XSLT_MAX_SORT) {
+		xsltTransformError(ctxt, NULL, curInst,
+		    "The number of xsl:sort instructions exceeds the "
+		    "maximum (%d) allowed by this processor.\n",
+		    XSLT_MAX_SORT);
+		goto error;
+	    } else {
+		sorts[nbsorts++] = curInst;
+	    }
+
+#ifdef WITH_DEBUGGER
+	    if (xslDebugStatus != XSLT_DEBUG_NONE)
+		xslHandleDebugger(curInst, contextNode, NULL, ctxt);
+#endif
+	    curInst = curInst->next;
+	}
+	xsltDoSortFunction(ctxt, sorts, nbsorts);
+    }
+    xpctxt->contextSize = list->nodeNr;
+    /*
+    * Instantiate the sequence constructor for each selected node.
+    */
+    for (i = 0; i < list->nodeNr; i++) {
+	cur = list->nodeTab[i];
+	/*
+	* The selected node becomes the "current node".
+	*/
+	ctxt->node = cur;
+	/*
+	* An xsl:for-each can change the current context doc.
+	* OPTIMIZE TODO: Get rid of the need to set the context doc.
+	*/
+	if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL))
+	    xpctxt->doc = cur->doc;
+
+	xpctxt->proximityPosition = i + 1;
+
+	xsltApplySequenceConstructor(ctxt, cur, curInst, NULL);
+    }
+
+exit:
+error:
+    if (res != NULL)
+	xmlXPathFreeObject(res);
+    /*
+    * Restore old states.
+    */
+    ctxt->document = oldDocInfo;
+    ctxt->nodeList = oldList;
+    ctxt->node = oldContextNode;
+    ctxt->currentTemplateRule = oldCurTemplRule;
+
+    xpctxt->doc = oldXPDoc;
+    xpctxt->contextSize = oldXPContextSize;
+    xpctxt->proximityPosition = oldXPProximityPosition;
+}
+
+/************************************************************************
+ *									*
+ *			Generic interface				*
+ *									*
+ ************************************************************************/
+
+#ifdef XSLT_GENERATE_HTML_DOCTYPE
+typedef struct xsltHTMLVersion {
+    const char *version;
+    const char *public;
+    const char *system;
+} xsltHTMLVersion;
+
+static xsltHTMLVersion xsltHTMLVersions[] = {
+    { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
+      "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"},
+    { "4.01strict", "-//W3C//DTD HTML 4.01//EN",
+      "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"},
+    { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
+      "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
+    { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN",
+      "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"},
+    { "4.0strict", "-//W3C//DTD HTML 4.01//EN",
+      "http://www.w3.org/TR/html4/strict.dtd"},
+    { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN",
+      "http://www.w3.org/TR/html4/loose.dtd"},
+    { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN",
+      "http://www.w3.org/TR/html4/frameset.dtd"},
+    { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN",
+      "http://www.w3.org/TR/html4/loose.dtd"},
+    { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL }
+};
+
+/**
+ * xsltGetHTMLIDs:
+ * @version:  the version string
+ * @publicID:  used to return the public ID
+ * @systemID:  used to return the system ID
+ *
+ * Returns -1 if not found, 0 otherwise and the system and public
+ *         Identifier for this given verion of HTML
+ */
+static int
+xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID,
+	            const xmlChar **systemID) {
+    unsigned int i;
+    if (version == NULL)
+	return(-1);
+    for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1]));
+	 i++) {
+	if (!xmlStrcasecmp(version,
+		           (const xmlChar *) xsltHTMLVersions[i].version)) {
+	    if (publicID != NULL)
+		*publicID = (const xmlChar *) xsltHTMLVersions[i].public;
+	    if (systemID != NULL)
+		*systemID = (const xmlChar *) xsltHTMLVersions[i].system;
+	    return(0);
+	}
+    }
+    return(-1);
+}
+#endif
+
+/**
+ * xsltApplyStripSpaces:
+ * @ctxt:  a XSLT process context
+ * @node:  the root of the XML tree
+ *
+ * Strip the unwanted ignorable spaces from the input tree
+ */
+void
+xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) {
+    xmlNodePtr current;
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    int nb = 0;
+#endif
+
+
+    current = node;
+    while (current != NULL) {
+	/*
+	 * Cleanup children empty nodes if asked for
+	 */
+	if ((IS_XSLT_REAL_NODE(current)) &&
+	    (current->children != NULL) &&
+	    (xsltFindElemSpaceHandling(ctxt, current))) {
+	    xmlNodePtr delete = NULL, cur = current->children;
+
+	    while (cur != NULL) {
+		if (IS_BLANK_NODE(cur))
+		    delete = cur;
+
+		cur = cur->next;
+		if (delete != NULL) {
+		    xmlUnlinkNode(delete);
+		    xmlFreeNode(delete);
+		    delete = NULL;
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		    nb++;
+#endif
+		}
+	    }
+	}
+
+	/*
+	 * Skip to next node in document order.
+	 */
+	if (node->type == XML_ENTITY_REF_NODE) {
+	    /* process deep in entities */
+	    xsltApplyStripSpaces(ctxt, node->children);
+	}
+	if ((current->children != NULL) &&
+            (current->type != XML_ENTITY_REF_NODE)) {
+	    current = current->children;
+	} else if (current->next != NULL) {
+	    current = current->next;
+	} else {
+	    do {
+		current = current->parent;
+		if (current == NULL)
+		    break;
+		if (current == node)
+		    goto done;
+		if (current->next != NULL) {
+		    current = current->next;
+		    break;
+		}
+	    } while (current != NULL);
+	}
+    }
+
+done:
+#ifdef WITH_XSLT_DEBUG_PROCESS
+    XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb));
+#endif
+    return;
+}
+
+static int
+xsltCountKeys(xsltTransformContextPtr ctxt)
+{
+    xsltStylesheetPtr style;
+    xsltKeyDefPtr keyd;
+
+    if (ctxt == NULL)
+	return(-1);
+
+    /*
+    * Do we have those nastly templates with a key() in the match pattern?
+    */
+    ctxt->hasTemplKeyPatterns = 0;
+    style = ctxt->style;
+    while (style != NULL) {
+	if (style->keyMatch != NULL) {
+	    ctxt->hasTemplKeyPatterns = 1;
+	    break;
+	}
+	style = xsltNextImport(style);
+    }
+    /*
+    * Count number of key declarations.
+    */
+    ctxt->nbKeys = 0;
+    style = ctxt->style;
+    while (style != NULL) {
+	keyd = style->keys;
+	while (keyd) {
+	    ctxt->nbKeys++;
+	    keyd = keyd->next;
+	}
+	style = xsltNextImport(style);
+    }
+    return(ctxt->nbKeys);
+}
+
+/**
+ * xsltApplyStylesheetInternal:
+ * @style:  a parsed XSLT stylesheet
+ * @doc:  a parsed XML document
+ * @params:  a NULL terminated array of parameters names/values tuples
+ * @output:  the targetted output
+ * @profile:  profile FILE * output or NULL
+ * @user:  user provided parameter
+ *
+ * Apply the stylesheet to the document
+ * NOTE: This may lead to a non-wellformed output XML wise !
+ *
+ * Returns the result document or NULL in case of error
+ */
+static xmlDocPtr
+xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc,
+                            const char **params, const char *output,
+                            FILE * profile, xsltTransformContextPtr userCtxt)
+{
+    xmlDocPtr res = NULL;
+    xsltTransformContextPtr ctxt = NULL;
+    xmlNodePtr root, node;
+    const xmlChar *method;
+    const xmlChar *doctypePublic;
+    const xmlChar *doctypeSystem;
+    const xmlChar *version;
+    const xmlChar *encoding;
+    xsltStackElemPtr variables;
+    xsltStackElemPtr vptr;
+
+    xsltInitGlobals();
+
+    if ((style == NULL) || (doc == NULL))
+        return (NULL);
+
+    if (style->internalized == 0) {
+#ifdef WITH_XSLT_DEBUG
+	xsltGenericDebug(xsltGenericDebugContext,
+			 "Stylesheet was not fully internalized !\n");
+#endif
+    }
+    if (doc->intSubset != NULL) {
+	/*
+	 * Avoid hitting the DTD when scanning nodes
+	 * but keep it linked as doc->intSubset
+	 */
+	xmlNodePtr cur = (xmlNodePtr) doc->intSubset;
+	if (cur->next != NULL)
+	    cur->next->prev = cur->prev;
+	if (cur->prev != NULL)
+	    cur->prev->next = cur->next;
+	if (doc->children == cur)
+	    doc->children = cur->next;
+	if (doc->last == cur)
+	    doc->last = cur->prev;
+	cur->prev = cur->next = NULL;
+    }
+
+    /*
+     * Check for XPath document order availability
+     */
+    root = xmlDocGetRootElement(doc);
+    if (root != NULL) {
+	if (((long) root->content) >= 0 && (xslDebugStatus == XSLT_DEBUG_NONE))
+	    xmlXPathOrderDocElems(doc);
+    }
+
+    if (userCtxt != NULL)
+	ctxt = userCtxt;
+    else
+	ctxt = xsltNewTransformContext(style, doc);
+
+    if (ctxt == NULL)
+        return (NULL);
+
+    ctxt->initialContextDoc = doc;
+    ctxt->initialContextNode = (xmlNodePtr) doc;
+
+    if (profile != NULL)
+        ctxt->profile = 1;
+
+    if (output != NULL)
+        ctxt->outputFile = output;
+    else
+        ctxt->outputFile = NULL;
+
+    /*
+     * internalize the modes if needed
+     */
+    if (ctxt->dict != NULL) {
+        if (ctxt->mode != NULL)
+	    ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1);
+        if (ctxt->modeURI != NULL)
+	    ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1);
+    }
+
+    XSLT_GET_IMPORT_PTR(method, style, method)
+    XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
+    XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
+    XSLT_GET_IMPORT_PTR(version, style, version)
+    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
+
+    if ((method != NULL) &&
+	(!xmlStrEqual(method, (const xmlChar *) "xml")))
+    {
+        if (xmlStrEqual(method, (const xmlChar *) "html")) {
+            ctxt->type = XSLT_OUTPUT_HTML;
+            if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
+                res = htmlNewDoc(doctypeSystem, doctypePublic);
+	    } else {
+                if (version == NULL) {
+		    xmlDtdPtr dtd;
+
+		    res = htmlNewDoc(NULL, NULL);
+		    /*
+		    * Make sure no DTD node is generated in this case
+		    */
+		    if (res != NULL) {
+			dtd = xmlGetIntSubset(res);
+			if (dtd != NULL) {
+			    xmlUnlinkNode((xmlNodePtr) dtd);
+			    xmlFreeDtd(dtd);
+			}
+			res->intSubset = NULL;
+			res->extSubset = NULL;
+		    }
+		} else {
+
+#ifdef XSLT_GENERATE_HTML_DOCTYPE
+		    xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem);
+#endif
+		    res = htmlNewDoc(doctypeSystem, doctypePublic);
+		}
+            }
+            if (res == NULL)
+                goto error;
+	    res->dict = ctxt->dict;
+	    xmlDictReference(res->dict);
+
+#ifdef WITH_XSLT_DEBUG
+	    xsltGenericDebug(xsltGenericDebugContext,
+		"reusing transformation dict for output\n");
+#endif
+        } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) {
+	    xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
+		"xsltApplyStylesheetInternal: unsupported method xhtml, using html\n",
+		style->method);
+            ctxt->type = XSLT_OUTPUT_HTML;
+            res = htmlNewDoc(doctypeSystem, doctypePublic);
+            if (res == NULL)
+                goto error;
+	    res->dict = ctxt->dict;
+	    xmlDictReference(res->dict);
+
+#ifdef WITH_XSLT_DEBUG
+	    xsltGenericDebug(xsltGenericDebugContext,
+		"reusing transformation dict for output\n");
+#endif
+        } else if (xmlStrEqual(method, (const xmlChar *) "text")) {
+            ctxt->type = XSLT_OUTPUT_TEXT;
+            res = xmlNewDoc(style->version);
+            if (res == NULL)
+                goto error;
+	    res->dict = ctxt->dict;
+	    xmlDictReference(res->dict);
+
+#ifdef WITH_XSLT_DEBUG
+	    xsltGenericDebug(xsltGenericDebugContext,
+		"reusing transformation dict for output\n");
+#endif
+        } else {
+	    xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
+		"xsltApplyStylesheetInternal: unsupported method %s\n",
+		style->method);
+            goto error;
+        }
+    } else {
+        ctxt->type = XSLT_OUTPUT_XML;
+        res = xmlNewDoc(style->version);
+        if (res == NULL)
+            goto error;
+	res->dict = ctxt->dict;
+	xmlDictReference(ctxt->dict);
+#ifdef WITH_XSLT_DEBUG
+	xsltGenericDebug(xsltGenericDebugContext,
+			 "reusing transformation dict for output\n");
+#endif
+    }
+    res->charset = XML_CHAR_ENCODING_UTF8;
+    if (encoding != NULL)
+        res->encoding = xmlStrdup(encoding);
+    variables = style->variables;
+
+    /*
+     * Start the evaluation, evaluate the params, the stylesheets globals
+     * and start by processing the top node.
+     */
+    if (xsltNeedElemSpaceHandling(ctxt))
+	xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
+    /*
+    * Evaluate global params and user-provided params.
+    */
+    ctxt->node = (xmlNodePtr) doc;
+    if (ctxt->globalVars == NULL)
+	ctxt->globalVars = xmlHashCreate(20);
+    if (params != NULL) {
+        xsltEvalUserParams(ctxt, params);
+    }
+
+    /* need to be called before evaluating global variables */
+    xsltCountKeys(ctxt);
+
+    xsltEvalGlobalVariables(ctxt);
+
+    ctxt->node = (xmlNodePtr) doc;
+    ctxt->output = res;
+    ctxt->insert = (xmlNodePtr) res;
+    ctxt->varsBase = ctxt->varsNr - 1;
+
+    ctxt->xpathCtxt->contextSize = 1;
+    ctxt->xpathCtxt->proximityPosition = 1;
+    ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */
+    /*
+    * Start processing the source tree -----------------------------------
+    */
+    xsltProcessOneNode(ctxt, ctxt->node, NULL);
+    /*
+    * Remove all remaining vars from the stack.
+    */
+    xsltLocalVariablePop(ctxt, 0, -2);
+    xsltShutdownCtxtExts(ctxt);
+
+    xsltCleanupTemplates(style); /* TODO: <- style should be read only */
+
+    /*
+     * Now cleanup our variables so stylesheet can be re-used
+     *
+     * TODO: this is not needed anymore global variables are copied
+     *       and not evaluated directly anymore, keep this as a check
+     */
+    if (style->variables != variables) {
+        vptr = style->variables;
+        while (vptr->next != variables)
+            vptr = vptr->next;
+        vptr->next = NULL;
+        xsltFreeStackElemList(style->variables);
+        style->variables = variables;
+    }
+    vptr = style->variables;
+    while (vptr != NULL) {
+        if (vptr->computed) {
+            if (vptr->value != NULL) {
+                xmlXPathFreeObject(vptr->value);
+                vptr->value = NULL;
+                vptr->computed = 0;
+            }
+        }
+        vptr = vptr->next;
+    }
+#if 0
+    /*
+     * code disabled by wmb; awaiting kb's review
+     * problem is that global variable(s) may contain xpath objects
+     * from doc associated with RVT, so can't be freed at this point.
+     * xsltFreeTransformContext includes a call to xsltFreeRVTs, so
+     * I assume this shouldn't be required at this point.
+     */
+    /*
+    * Free all remaining tree fragments.
+    */
+    xsltFreeRVTs(ctxt);
+#endif
+    /*
+     * Do some post processing work depending on the generated output
+     */
+    root = xmlDocGetRootElement(res);
+    if (root != NULL) {
+        const xmlChar *doctype = NULL;
+
+        if ((root->ns != NULL) && (root->ns->prefix != NULL))
+	    doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name);
+	if (doctype == NULL)
+	    doctype = root->name;
+
+        /*
+         * Apply the default selection of the method
+         */
+        if ((method == NULL) &&
+            (root->ns == NULL) &&
+            (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) {
+            xmlNodePtr tmp;
+
+            tmp = res->children;
+            while ((tmp != NULL) && (tmp != root)) {
+                if (tmp->type == XML_ELEMENT_NODE)
+                    break;
+                if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp)))
+                    break;
+		tmp = tmp->next;
+            }
+            if (tmp == root) {
+                ctxt->type = XSLT_OUTPUT_HTML;
+		/*
+		* REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the
+		*  transformation on the doc, but functions like
+		*/
+                res->type = XML_HTML_DOCUMENT_NODE;
+                if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
+                    res->intSubset = xmlCreateIntSubset(res, doctype,
+                                                        doctypePublic,
+                                                        doctypeSystem);
+#ifdef XSLT_GENERATE_HTML_DOCTYPE
+		} else if (version != NULL) {
+                    xsltGetHTMLIDs(version, &doctypePublic,
+                                   &doctypeSystem);
+                    if (((doctypePublic != NULL) || (doctypeSystem != NULL)))
+                        res->intSubset =
+                            xmlCreateIntSubset(res, doctype,
+                                               doctypePublic,
+                                               doctypeSystem);
+#endif
+                }
+            }
+
+        }
+        if (ctxt->type == XSLT_OUTPUT_XML) {
+            XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic)
+            XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem)
+            if (((doctypePublic != NULL) || (doctypeSystem != NULL))) {
+	        xmlNodePtr last;
+		/* Need a small "hack" here to assure DTD comes before
+		   possible comment nodes */
+		node = res->children;
+		last = res->last;
+		res->children = NULL;
+		res->last = NULL;
+                res->intSubset = xmlCreateIntSubset(res, doctype,
+                                                    doctypePublic,
+                                                    doctypeSystem);
+		if (res->children != NULL) {
+		    res->children->next = node;
+		    node->prev = res->children;
+		    res->last = last;
+		} else {
+		    res->children = node;
+		    res->last = last;
+		}
+	    }
+        }
+    }
+    xmlXPathFreeNodeSet(ctxt->nodeList);
+    if (profile != NULL) {
+        xsltSaveProfiling(ctxt, profile);
+    }
+
+    /*
+     * Be pedantic.
+     */
+    if ((ctxt != NULL) && (ctxt->state == XSLT_STATE_ERROR)) {
+	xmlFreeDoc(res);
+	res = NULL;
+    }
+    if ((res != NULL) && (ctxt != NULL) && (output != NULL)) {
+	int ret;
+
+	ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output);
+	if (ret == 0) {
+	    xsltTransformError(ctxt, NULL, NULL,
+		     "xsltApplyStylesheet: forbidden to save to %s\n",
+			       output);
+	} else if (ret < 0) {
+	    xsltTransformError(ctxt, NULL, NULL,
+		     "xsltApplyStylesheet: saving to %s may not be possible\n",
+			       output);
+	}
+    }
+
+#ifdef XSLT_DEBUG_PROFILE_CACHE
+    printf("# Cache:\n");
+    printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
+    printf("# Reused variables     : %d\n", ctxt->cache->dbgReusedVars);
+#endif
+
+    if ((ctxt != NULL) && (userCtxt == NULL))
+	xsltFreeTransformContext(ctxt);
+
+    return (res);
+
+error:
+    if (res != NULL)
+        xmlFreeDoc(res);
+
+#ifdef XSLT_DEBUG_PROFILE_CACHE
+    printf("# Cache:\n");
+    printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs);
+    printf("# Reused variables     : %d\n", ctxt->cache->dbgReusedVars);
+#endif
+
+    if ((ctxt != NULL) && (userCtxt == NULL))
+        xsltFreeTransformContext(ctxt);
+    return (NULL);
+}
+
+/**
+ * xsltApplyStylesheet:
+ * @style:  a parsed XSLT stylesheet
+ * @doc:  a parsed XML document
+ * @params:  a NULL terminated arry of parameters names/values tuples
+ *
+ * Apply the stylesheet to the document
+ * NOTE: This may lead to a non-wellformed output XML wise !
+ *
+ * Returns the result document or NULL in case of error
+ */
+xmlDocPtr
+xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
+                    const char **params)
+{
+    return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL));
+}
+
+/**
+ * xsltProfileStylesheet:
+ * @style:  a parsed XSLT stylesheet
+ * @doc:  a parsed XML document
+ * @params:  a NULL terminated arry of parameters names/values tuples
+ * @output:  a FILE * for the profiling output
+ *
+ * Apply the stylesheet to the document and dump the profiling to
+ * the given output.
+ *
+ * Returns the result document or NULL in case of error
+ */
+xmlDocPtr
+xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
+                      const char **params, FILE * output)
+{
+    xmlDocPtr res;
+
+    res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL);
+    return (res);
+}
+
+/**
+ * xsltApplyStylesheetUser:
+ * @style:  a parsed XSLT stylesheet
+ * @doc:  a parsed XML document
+ * @params:  a NULL terminated array of parameters names/values tuples
+ * @output:  the targetted output
+ * @profile:  profile FILE * output or NULL
+ * @userCtxt:  user provided transform context
+ *
+ * Apply the stylesheet to the document and allow the user to provide
+ * its own transformation context.
+ *
+ * Returns the result document or NULL in case of error
+ */
+xmlDocPtr
+xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
+                            const char **params, const char *output,
+                            FILE * profile, xsltTransformContextPtr userCtxt)
+{
+    xmlDocPtr res;
+
+    res = xsltApplyStylesheetInternal(style, doc, params, output,
+	                              profile, userCtxt);
+    return (res);
+}
+
+/**
+ * xsltRunStylesheetUser:
+ * @style:  a parsed XSLT stylesheet
+ * @doc:  a parsed XML document
+ * @params:  a NULL terminated array of parameters names/values tuples
+ * @output:  the URL/filename ot the generated resource if available
+ * @SAX:  a SAX handler for progressive callback output (not implemented yet)
+ * @IObuf:  an output buffer for progressive output (not implemented yet)
+ * @profile:  profile FILE * output or NULL
+ * @userCtxt:  user provided transform context
+ *
+ * Apply the stylesheet to the document and generate the output according
+ * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
+ *
+ * NOTE: This may lead to a non-wellformed output XML wise !
+ * NOTE: This may also result in multiple files being generated
+ * NOTE: using IObuf, the result encoding used will be the one used for
+ *       creating the output buffer, use the following macro to read it
+ *       from the stylesheet
+ *       XSLT_GET_IMPORT_PTR(encoding, style, encoding)
+ * NOTE: using SAX, any encoding specified in the stylesheet will be lost
+ *       since the interface uses only UTF8
+ *
+ * Returns the number of by written to the main resource or -1 in case of
+ *         error.
+ */
+int
+xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc,
+                  const char **params, const char *output,
+                  xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf,
+		  FILE * profile, xsltTransformContextPtr userCtxt)
+{
+    xmlDocPtr tmp;
+    int ret;
+
+    if ((output == NULL) && (SAX == NULL) && (IObuf == NULL))
+        return (-1);
+    if ((SAX != NULL) && (IObuf != NULL))
+        return (-1);
+
+    /* unsupported yet */
+    if (SAX != NULL) {
+        XSLT_TODO   /* xsltRunStylesheet xmlSAXHandlerPtr SAX */
+	return (-1);
+    }
+
+    tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile,
+	                              userCtxt);
+    if (tmp == NULL) {
+	xsltTransformError(NULL, NULL, (xmlNodePtr) doc,
+                         "xsltRunStylesheet : run failed\n");
+        return (-1);
+    }
+    if (IObuf != NULL) {
+        /* TODO: incomplete, IObuf output not progressive */
+        ret = xsltSaveResultTo(IObuf, tmp, style);
+    } else {
+        ret = xsltSaveResultToFilename(output, tmp, style, 0);
+    }
+    xmlFreeDoc(tmp);
+    return (ret);
+}
+
+/**
+ * xsltRunStylesheet:
+ * @style:  a parsed XSLT stylesheet
+ * @doc:  a parsed XML document
+ * @params:  a NULL terminated array of parameters names/values tuples
+ * @output:  the URL/filename ot the generated resource if available
+ * @SAX:  a SAX handler for progressive callback output (not implemented yet)
+ * @IObuf:  an output buffer for progressive output (not implemented yet)
+ *
+ * Apply the stylesheet to the document and generate the output according
+ * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf.
+ *
+ * NOTE: This may lead to a non-wellformed output XML wise !
+ * NOTE: This may also result in multiple files being generated
+ * NOTE: using IObuf, the result encoding used will be the one used for
+ *       creating the output buffer, use the following macro to read it
+ *       from the stylesheet
+ *       XSLT_GET_IMPORT_PTR(encoding, style, encoding)
+ * NOTE: using SAX, any encoding specified in the stylesheet will be lost
+ *       since the interface uses only UTF8
+ *
+ * Returns the number of bytes written to the main resource or -1 in case of
+ *         error.
+ */
+int
+xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc,
+                  const char **params, const char *output,
+                  xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf)
+{
+    return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf,
+		                 NULL, NULL));
+}
+
+/**
+ * xsltRegisterAllElement:
+ * @ctxt:  the XPath context
+ *
+ * Registers all default XSLT elements in this context
+ */
+void
+xsltRegisterAllElement(xsltTransformContextPtr ctxt)
+{
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltApplyTemplates);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltApplyImports);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltCallTemplate);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "element",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltElement);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltAttribute);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "text",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltText);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltProcessingInstruction);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "comment",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltComment);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "copy",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltCopy);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltValueOf);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "number",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltNumber);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltForEach);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "if",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltIf);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "choose",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltChoose);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "sort",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltSort);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltCopyOf);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "message",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltMessage);
+
+    /*
+     * Those don't have callable entry points but are registered anyway
+     */
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "variable",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltDebug);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "param",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltDebug);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltDebug);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltDebug);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "when",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltDebug);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltDebug);
+    xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback",
+                           XSLT_NAMESPACE,
+			   (xsltTransformFunction) xsltDebug);
+
+}
diff --git a/libxslt/transform.h b/libxslt/transform.h
new file mode 100644
index 0000000..2cfbec2
--- /dev/null
+++ b/libxslt/transform.h
@@ -0,0 +1,207 @@
+/*
+ * Summary: the XSLT engine transformation part.
+ * Description: This module implements the bulk of the actual
+ *              transformation processing. Most of the xsl: element
+ *              constructs are implemented in this module.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_TRANSFORM_H__
+#define __XML_XSLT_TRANSFORM_H__
+
+#include <libxml/parser.h>
+#include <libxml/xmlIO.h>
+#include "xsltexports.h"
+#include <libxslt/xsltInternals.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * XInclude default processing.
+ */
+XSLTPUBFUN void XSLTCALL
+		xsltSetXIncludeDefault	(int xinclude);
+XSLTPUBFUN int XSLTCALL
+		xsltGetXIncludeDefault	(void);
+
+/**
+ * Export context to users.
+ */
+XSLTPUBFUN xsltTransformContextPtr XSLTCALL
+		xsltNewTransformContext	(xsltStylesheetPtr style,
+					 xmlDocPtr doc);
+
+XSLTPUBFUN void XSLTCALL
+		xsltFreeTransformContext(xsltTransformContextPtr ctxt);
+
+XSLTPUBFUN xmlDocPtr XSLTCALL
+		xsltApplyStylesheetUser	(xsltStylesheetPtr style,
+					 xmlDocPtr doc,
+					 const char **params,
+					 const char *output,
+					 FILE * profile,
+					 xsltTransformContextPtr userCtxt);
+XSLTPUBFUN void XSLTCALL
+                xsltProcessOneNode      (xsltTransformContextPtr ctxt,
+                                         xmlNodePtr node,
+                                         xsltStackElemPtr params);
+/**
+ * Private Interfaces.
+ */
+XSLTPUBFUN void XSLTCALL
+		xsltApplyStripSpaces	(xsltTransformContextPtr ctxt,
+					 xmlNodePtr node);
+XSLTPUBFUN xmlDocPtr XSLTCALL
+		xsltApplyStylesheet	(xsltStylesheetPtr style,
+					 xmlDocPtr doc,
+					 const char **params);
+XSLTPUBFUN xmlDocPtr XSLTCALL
+		xsltProfileStylesheet	(xsltStylesheetPtr style,
+					 xmlDocPtr doc,
+					 const char **params,
+					 FILE * output);
+XSLTPUBFUN int XSLTCALL
+		xsltRunStylesheet	(xsltStylesheetPtr style,
+					 xmlDocPtr doc,
+					 const char **params,
+					 const char *output,
+					 xmlSAXHandlerPtr SAX,
+					 xmlOutputBufferPtr IObuf);
+XSLTPUBFUN int XSLTCALL
+		xsltRunStylesheetUser	(xsltStylesheetPtr style,
+					 xmlDocPtr doc,
+					 const char **params,
+					 const char *output,
+					 xmlSAXHandlerPtr SAX,
+					 xmlOutputBufferPtr IObuf,
+					 FILE * profile,
+					 xsltTransformContextPtr userCtxt);
+XSLTPUBFUN void XSLTCALL
+		xsltApplyOneTemplate	(xsltTransformContextPtr ctxt,
+					 xmlNodePtr node,
+					 xmlNodePtr list,
+					 xsltTemplatePtr templ,
+					 xsltStackElemPtr params);
+XSLTPUBFUN void XSLTCALL
+		xsltDocumentElem	(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltSort		(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltCopy		(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltText		(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltElement		(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltComment		(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltAttribute		(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltProcessingInstruction(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltCopyOf		(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltValueOf		(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltNumber		(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltApplyImports	(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltCallTemplate	(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltApplyTemplates	(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltChoose		(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltIf			(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltForEach		(xsltTransformContextPtr ctxt,
+	                                 xmlNodePtr node,
+					 xmlNodePtr inst,
+					 xsltStylePreCompPtr comp);
+XSLTPUBFUN void XSLTCALL
+		xsltRegisterAllElement	(xsltTransformContextPtr ctxt);
+
+XSLTPUBFUN xmlNodePtr XSLTCALL
+		xsltCopyTextString	(xsltTransformContextPtr ctxt,
+					 xmlNodePtr target,
+					 const xmlChar *string,
+					 int noescape);
+
+/* Following 2 functions needed for libexslt/functions.c */
+XSLTPUBFUN void XSLTCALL
+		xsltLocalVariablePop	(xsltTransformContextPtr ctxt,
+					 int limitNr,
+					 int level);
+XSLTPUBFUN int XSLTCALL
+		xsltLocalVariablePush	(xsltTransformContextPtr ctxt,
+					 xsltStackElemPtr variable,
+					 int level);
+/*
+ * Hook for the debugger if activated.
+ */
+XSLTPUBFUN void XSLTCALL
+		xslHandleDebugger	(xmlNodePtr cur,
+					 xmlNodePtr node,
+					 xsltTemplatePtr templ,
+					 xsltTransformContextPtr ctxt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_TRANSFORM_H__ */
+
diff --git a/libxslt/trio.h b/libxslt/trio.h
new file mode 100644
index 0000000..941bdd0
--- /dev/null
+++ b/libxslt/trio.h
@@ -0,0 +1,216 @@
+/*************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ *************************************************************************
+ *
+ * http://ctrio.sourceforge.net/
+ *
+ ************************************************************************/
+
+#ifndef TRIO_TRIO_H
+#define TRIO_TRIO_H
+
+#if !defined(WITHOUT_TRIO)
+
+/*
+ * Use autoconf defines if present. Packages using trio must define
+ * HAVE_CONFIG_H as a compiler option themselves.
+ */
+#if defined(HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include "triodef.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#if defined(TRIO_COMPILER_ANCIENT)
+# include <varargs.h>
+#else
+# include <stdarg.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Error codes.
+ *
+ * Remember to add a textual description to trio_strerror.
+ */
+enum {
+  TRIO_EOF      = 1,
+  TRIO_EINVAL   = 2,
+  TRIO_ETOOMANY = 3,
+  TRIO_EDBLREF  = 4,
+  TRIO_EGAP     = 5,
+  TRIO_ENOMEM   = 6,
+  TRIO_ERANGE   = 7,
+  TRIO_ERRNO    = 8,
+  TRIO_ECUSTOM  = 9
+};
+
+/* Error macros */
+#define TRIO_ERROR_CODE(x) ((-(x)) & 0x00FF)
+#define TRIO_ERROR_POSITION(x) ((-(x)) >> 8)
+#define TRIO_ERROR_NAME(x) trio_strerror(x)
+
+typedef int (*trio_outstream_t) TRIO_PROTO((trio_pointer_t, int));
+typedef int (*trio_instream_t) TRIO_PROTO((trio_pointer_t));
+
+TRIO_CONST char *trio_strerror TRIO_PROTO((int));
+
+/*************************************************************************
+ * Print Functions
+ */
+
+int trio_printf TRIO_PROTO((TRIO_CONST char *format, ...));
+int trio_vprintf TRIO_PROTO((TRIO_CONST char *format, va_list args));
+int trio_printfv TRIO_PROTO((TRIO_CONST char *format, void **args));
+
+int trio_fprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...));
+int trio_vfprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args));
+int trio_fprintfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args));
+
+int trio_dprintf TRIO_PROTO((int fd, TRIO_CONST char *format, ...));
+int trio_vdprintf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args));
+int trio_dprintfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args));
+
+int trio_cprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure,
+			     TRIO_CONST char *format, ...));
+int trio_vcprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure,
+			      TRIO_CONST char *format, va_list args));
+int trio_cprintfv TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure,
+			      TRIO_CONST char *format, void **args));
+
+int trio_sprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, ...));
+int trio_vsprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, va_list args));
+int trio_sprintfv TRIO_PROTO((char *buffer, TRIO_CONST char *format, void **args));
+
+int trio_snprintf TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...));
+int trio_vsnprintf TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format,
+		   va_list args));
+int trio_snprintfv TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format,
+		   void **args));
+
+int trio_snprintfcat TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...));
+int trio_vsnprintfcat TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format,
+                      va_list args));
+
+char *trio_aprintf TRIO_PROTO((TRIO_CONST char *format, ...));
+char *trio_vaprintf TRIO_PROTO((TRIO_CONST char *format, va_list args));
+
+int trio_asprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, ...));
+int trio_vasprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, va_list args));
+
+/*************************************************************************
+ * Scan Functions
+ */
+int trio_scanf TRIO_PROTO((TRIO_CONST char *format, ...));
+int trio_vscanf TRIO_PROTO((TRIO_CONST char *format, va_list args));
+int trio_scanfv TRIO_PROTO((TRIO_CONST char *format, void **args));
+
+int trio_fscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...));
+int trio_vfscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args));
+int trio_fscanfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args));
+
+int trio_dscanf TRIO_PROTO((int fd, TRIO_CONST char *format, ...));
+int trio_vdscanf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args));
+int trio_dscanfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args));
+
+int trio_cscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure,
+			    TRIO_CONST char *format, ...));
+int trio_vcscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure,
+			     TRIO_CONST char *format, va_list args));
+int trio_cscanfv TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure,
+			     TRIO_CONST char *format, void **args));
+
+int trio_sscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, ...));
+int trio_vsscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, va_list args));
+int trio_sscanfv TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, void **args));
+
+/*************************************************************************
+ * Locale Functions
+ */
+void trio_locale_set_decimal_point TRIO_PROTO((char *decimalPoint));
+void trio_locale_set_thousand_separator TRIO_PROTO((char *thousandSeparator));
+void trio_locale_set_grouping TRIO_PROTO((char *grouping));
+
+/*************************************************************************
+ * Renaming
+ */
+#ifdef TRIO_REPLACE_STDIO
+/* Replace the <stdio.h> functions */
+#ifndef HAVE_PRINTF
+# define printf trio_printf
+#endif
+#ifndef HAVE_VPRINTF
+# define vprintf trio_vprintf
+#endif
+#ifndef HAVE_FPRINTF
+# define fprintf trio_fprintf
+#endif
+#ifndef HAVE_VFPRINTF
+# define vfprintf trio_vfprintf
+#endif
+#ifndef HAVE_SPRINTF
+# define sprintf trio_sprintf
+#endif
+#ifndef HAVE_VSPRINTF
+# define vsprintf trio_vsprintf
+#endif
+#ifndef HAVE_SNPRINTF
+# define snprintf trio_snprintf
+#endif
+#ifndef HAVE_VSNPRINTF
+# define vsnprintf trio_vsnprintf
+#endif
+#ifndef HAVE_SCANF
+# define scanf trio_scanf
+#endif
+#ifndef HAVE_VSCANF
+# define vscanf trio_vscanf
+#endif
+#ifndef HAVE_FSCANF
+# define fscanf trio_fscanf
+#endif
+#ifndef HAVE_VFSCANF
+# define vfscanf trio_vfscanf
+#endif
+#ifndef HAVE_SSCANF
+# define sscanf trio_sscanf
+#endif
+#ifndef HAVE_VSSCANF
+# define vsscanf trio_vsscanf
+#endif
+/* These aren't stdio functions, but we make them look similar */
+#define dprintf trio_dprintf
+#define vdprintf trio_vdprintf
+#define aprintf trio_aprintf
+#define vaprintf trio_vaprintf
+#define asprintf trio_asprintf
+#define vasprintf trio_vasprintf
+#define dscanf trio_dscanf
+#define vdscanf trio_vdscanf
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* WITHOUT_TRIO */
+
+#endif /* TRIO_TRIO_H */
diff --git a/libxslt/triodef.h b/libxslt/triodef.h
new file mode 100644
index 0000000..0fd32fb
--- /dev/null
+++ b/libxslt/triodef.h
@@ -0,0 +1,220 @@
+/*************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 2001 Bjorn Reese <breese@users.sourceforge.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ ************************************************************************/
+
+#ifndef TRIO_TRIODEF_H
+#define TRIO_TRIODEF_H
+
+/*************************************************************************
+ * Platform and compiler support detection
+ */
+#if defined(__GNUC__)
+# define TRIO_COMPILER_GCC
+#elif defined(__SUNPRO_C)
+# define TRIO_COMPILER_SUNPRO
+#elif defined(__SUNPRO_CC)
+# define TRIO_COMPILER_SUNPRO
+# define __SUNPRO_C __SUNPRO_CC
+#elif defined(__xlC__) || defined(__IBMC__) || defined(__IBMCPP__)
+# define TRIO_COMPILER_XLC
+#elif defined(_AIX) && !defined(__GNUC__)
+# define TRIO_COMPILER_XLC /* Workaround for old xlc */
+#elif defined(__DECC) || defined(__DECCXX)
+# define TRIO_COMPILER_DECC
+#elif defined(__osf__) && defined(__LANGUAGE_C__)
+# define TRIO_COMPILER_DECC /* Workaround for old DEC C compilers */
+#elif defined(_MSC_VER)
+# define TRIO_COMPILER_MSVC
+#elif defined(__BORLANDC__)
+# define TRIO_COMPILER_BCB
+#endif
+
+#if defined(VMS) || defined(__VMS)
+/*
+ * VMS is placed first to avoid identifying the platform as Unix
+ * based on the DECC compiler later on.
+ */
+# define TRIO_PLATFORM_VMS
+#elif defined(unix) || defined(__unix) || defined(__unix__)
+# define TRIO_PLATFORM_UNIX
+#elif defined(TRIO_COMPILER_XLC) || defined(_AIX)
+# define TRIO_PLATFORM_UNIX
+#elif defined(TRIO_COMPILER_DECC) || defined(__osf___)
+# define TRIO_PLATFORM_UNIX
+#elif defined(__NetBSD__)
+# define TRIO_PLATFORM_UNIX
+#elif defined(__QNX__)
+# define TRIO_PLATFORM_UNIX
+# define TRIO_PLATFORM_QNX
+#elif defined(__CYGWIN__)
+# define TRIO_PLATFORM_UNIX
+#elif defined(AMIGA) && defined(TRIO_COMPILER_GCC)
+# define TRIO_PLATFORM_UNIX
+#elif defined(TRIO_COMPILER_MSVC) || defined(WIN32) || defined(_WIN32)
+# define TRIO_PLATFORM_WIN32
+#elif defined(mpeix) || defined(__mpexl)
+# define TRIO_PLATFORM_MPEIX
+#endif
+
+#if defined(_AIX)
+# define TRIO_PLATFORM_AIX
+#elif defined(__hpux)
+# define TRIO_PLATFORM_HPUX
+#elif defined(sun) || defined(__sun__)
+# if defined(__SVR4) || defined(__svr4__)
+#  define TRIO_PLATFORM_SOLARIS
+# else
+#  define TRIO_PLATFORM_SUNOS
+# endif
+#endif
+
+#if defined(__STDC__) || defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB)
+# define TRIO_COMPILER_SUPPORTS_C89
+# if defined(__STDC_VERSION__)
+#  define TRIO_COMPILER_SUPPORTS_C90
+#  if (__STDC_VERSION__ >= 199409L)
+#   define TRIO_COMPILER_SUPPORTS_C94
+#  endif
+#  if (__STDC_VERSION__ >= 199901L)
+#   define TRIO_COMPILER_SUPPORTS_C99
+#  endif
+# elif defined(TRIO_COMPILER_SUNPRO)
+#  if (__SUNPRO_C >= 0x420)
+#   define TRIO_COMPILER_SUPPORTS_C94
+#  endif
+# endif
+#endif
+
+#if defined(_XOPEN_SOURCE)
+# if defined(_XOPEN_SOURCE_EXTENDED)
+#  define TRIO_COMPILER_SUPPORTS_UNIX95
+# endif
+# if (_XOPEN_VERSION >= 500)
+#  define TRIO_COMPILER_SUPPORTS_UNIX98
+# endif
+# if (_XOPEN_VERSION >= 600)
+#  define TRIO_COMPILER_SUPPORTS_UNIX01
+# endif
+#endif
+
+/*************************************************************************
+ * Generic defines
+ */
+
+#if !defined(TRIO_PUBLIC)
+# define TRIO_PUBLIC
+#endif
+#if !defined(TRIO_PRIVATE)
+# define TRIO_PRIVATE static
+#endif
+
+#if !(defined(TRIO_COMPILER_SUPPORTS_C89) || defined(__cplusplus))
+# define TRIO_COMPILER_ANCIENT
+#endif
+
+#if defined(TRIO_COMPILER_ANCIENT)
+# define TRIO_CONST
+# define TRIO_VOLATILE
+# define TRIO_SIGNED
+typedef double trio_long_double_t;
+typedef char * trio_pointer_t;
+# define TRIO_SUFFIX_LONG(x) x
+# define TRIO_PROTO(x) ()
+# define TRIO_NOARGS
+# define TRIO_ARGS1(list,a1) list a1;
+# define TRIO_ARGS2(list,a1,a2) list a1; a2;
+# define TRIO_ARGS3(list,a1,a2,a3) list a1; a2; a3;
+# define TRIO_ARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4;
+# define TRIO_ARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5;
+# define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) list a1; a2; a3; a4; a5; a6;
+# define TRIO_VARGS2(list,a1,a2) list a1; a2
+# define TRIO_VARGS3(list,a1,a2,a3) list a1; a2; a3
+# define TRIO_VARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4
+# define TRIO_VARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5
+# define TRIO_VA_DECL va_dcl
+# define TRIO_VA_START(x,y) va_start(x)
+# define TRIO_VA_END(x) va_end(x)
+#else /* ANSI C */
+# define TRIO_CONST const
+# define TRIO_VOLATILE volatile
+# define TRIO_SIGNED signed
+typedef long double trio_long_double_t;
+typedef void * trio_pointer_t;
+# define TRIO_SUFFIX_LONG(x) x ## L
+# define TRIO_PROTO(x) x
+# define TRIO_NOARGS void
+# define TRIO_ARGS1(list,a1) (a1)
+# define TRIO_ARGS2(list,a1,a2) (a1,a2)
+# define TRIO_ARGS3(list,a1,a2,a3) (a1,a2,a3)
+# define TRIO_ARGS4(list,a1,a2,a3,a4) (a1,a2,a3,a4)
+# define TRIO_ARGS5(list,a1,a2,a3,a4,a5) (a1,a2,a3,a4,a5)
+# define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) (a1,a2,a3,a4,a5,a6)
+# define TRIO_VARGS2 TRIO_ARGS2
+# define TRIO_VARGS3 TRIO_ARGS3
+# define TRIO_VARGS4 TRIO_ARGS4
+# define TRIO_VARGS5 TRIO_ARGS5
+# define TRIO_VA_DECL ...
+# define TRIO_VA_START(x,y) va_start(x,y)
+# define TRIO_VA_END(x) va_end(x)
+#endif
+
+#if defined(TRIO_COMPILER_SUPPORTS_C99) || defined(__cplusplus)
+# define TRIO_INLINE inline
+#elif defined(TRIO_COMPILER_GCC)
+# define TRIO_INLINE __inline__
+#elif defined(TRIO_COMPILER_MSVC)
+# define TRIO_INLINE _inline
+#elif defined(TRIO_COMPILER_BCB)
+# define TRIO_INLINE __inline
+#else
+# define TRIO_INLINE
+#endif
+
+/*************************************************************************
+ * Workarounds
+ */
+
+#if defined(TRIO_PLATFORM_VMS)
+/*
+ * Computations done with constants at compile time can trigger these
+ * even when compiling with IEEE enabled.
+ */
+# pragma message disable (UNDERFLOW, FLOATOVERFL)
+
+# if (__CRTL_VER < 80000000)
+/*
+ * Although the compiler supports C99 language constructs, the C
+ * run-time library does not contain all C99 functions.
+ *
+ * This was the case for 70300022. Update the 80000000 value when
+ * it has been accurately determined what version of the library
+ * supports C99.
+ */
+#  if defined(TRIO_COMPILER_SUPPORTS_C99)
+#   undef TRIO_COMPILER_SUPPORTS_C99
+#  endif
+# endif
+#endif
+
+/*
+ * Not all preprocessors supports the LL token.
+ */
+#if defined(TRIO_COMPILER_BCB)
+#else
+# define TRIO_COMPILER_SUPPORTS_LL
+#endif
+
+#endif /* TRIO_TRIODEF_H */
diff --git a/libxslt/variables.c b/libxslt/variables.c
new file mode 100644
index 0000000..43a6156
--- /dev/null
+++ b/libxslt/variables.c
@@ -0,0 +1,2312 @@
+/*
+ * variables.c: Implementation of the variable storage and lookup
+ *
+ * Reference:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+#include <libxml/hash.h>
+#include <libxml/xmlerror.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/parserInternals.h>
+#include <libxml/dict.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "variables.h"
+#include "transform.h"
+#include "imports.h"
+#include "preproc.h"
+#include "keys.h"
+
+#ifdef WITH_XSLT_DEBUG
+ #define WITH_XSLT_DEBUG_VARIABLE
+#endif
+
+#ifdef XSLT_REFACTORED
+const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt";
+#endif
+
+const xmlChar *xsltComputingGlobalVarMarker =
+ (const xmlChar *) " var/param being computed";
+
+#define XSLT_VAR_GLOBAL 1<<0
+#define XSLT_VAR_IN_SELECT 1<<1
+#define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable)
+
+/************************************************************************
+ *									*
+ *  Result Value Tree (Result Tree Fragment) interfaces			*
+ *									*
+ ************************************************************************/
+/**
+ * xsltCreateRVT:
+ * @ctxt:  an XSLT transformation context
+ *
+ * Creates a Result Value Tree
+ * (the XSLT 1.0 term for this is "Result Tree Fragment") 
+ *
+ * Returns the result value tree or NULL in case of API or internal errors.
+ */
+xmlDocPtr
+xsltCreateRVT(xsltTransformContextPtr ctxt)
+{
+    xmlDocPtr container;
+
+    /*
+    * Question: Why is this function public?
+    * Answer: It is called by the EXSLT module.
+    */    
+    if (ctxt == NULL)
+	return(NULL);
+
+    /*
+    * Reuse a RTF from the cache if available.
+    */
+    if (ctxt->cache->RVT) {
+	container = ctxt->cache->RVT;
+	ctxt->cache->RVT = (xmlDocPtr) container->next;
+	/* clear the internal pointers */
+	container->next = NULL;
+	container->prev = NULL;
+	if (ctxt->cache->nbRVT > 0)
+	    ctxt->cache->nbRVT--;
+#ifdef XSLT_DEBUG_PROFILE_CACHE
+	ctxt->cache->dbgReusedRVTs++;
+#endif
+	return(container);
+    }
+
+    container = xmlNewDoc(NULL);
+    if (container == NULL)
+	return(NULL);
+    container->dict = ctxt->dict;
+    xmlDictReference(container->dict);
+    XSLT_MARK_RES_TREE_FRAG(container);
+    container->doc = container;
+    container->parent = NULL;
+    return(container);
+}
+
+/**
+ * xsltRegisterTmpRVT:
+ * @ctxt:  an XSLT transformation context
+ * @RVT:  a result value tree (Result Tree Fragment)
+ *
+ * Registers the result value tree (XSLT 1.0 term: Result Tree Fragment)
+ * in the garbage collector.
+ * The fragment will be freed at the exit of the currently
+ * instantiated xsl:template.
+ * Obsolete; this function might produce massive memory overhead,
+ * since the fragment is only freed when the current xsl:template
+ * exits. Use xsltRegisterLocalRVT() instead.
+ *
+ * Returns 0 in case of success and -1 in case of API or internal errors.
+ */
+int
+xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
+{
+    if ((ctxt == NULL) || (RVT == NULL))
+	return(-1);
+
+    /*
+    * We'll restrict the lifetime of user-created fragments
+    * insinde an xsl:variable and xsl:param to the lifetime of the
+    * var/param itself.
+    */
+    if (ctxt->contextVariable != NULL) {
+	RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
+	XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
+	return(0);
+    }
+
+    RVT->next = (xmlNodePtr) ctxt->tmpRVT;
+    if (ctxt->tmpRVT != NULL)
+	ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
+    ctxt->tmpRVT = RVT;
+    return(0);
+}
+
+/**
+ * xsltRegisterLocalRVT:
+ * @ctxt:  an XSLT transformation context
+ * @RVT:  a result value tree (Result Tree Fragment; xmlDocPtr)
+ *
+ * Registers a result value tree (XSLT 1.0 term: Result Tree Fragment)
+ * in the RVT garbage collector.
+ * The fragment will be freed when the instruction which created the
+ * fragment exits.
+ *
+ * Returns 0 in case of success and -1 in case of API or internal errors.
+ */
+int
+xsltRegisterLocalRVT(xsltTransformContextPtr ctxt,
+		     xmlDocPtr RVT)
+{
+    if ((ctxt == NULL) || (RVT == NULL))
+	return(-1);
+    
+    /*
+    * When evaluating "select" expressions of xsl:variable
+    * and xsl:param, we need to bind newly created tree fragments
+    * to the variable itself; otherwise the tragment will be
+    * freed before we leave the scope of a var.
+    */
+    if ((ctxt->contextVariable != NULL) &&
+	(XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT))
+    {
+	RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment;
+	XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT;
+	return(0);
+    }
+    /*
+    * Store the fragment in the scope of the current instruction.
+    * If not reference by a returning instruction (like EXSLT's function),
+    * then this fragment will be freed, when the instruction exits.
+    */
+    RVT->next = (xmlNodePtr) ctxt->localRVT;
+    if (ctxt->localRVT != NULL)
+	ctxt->localRVT->prev = (xmlNodePtr) RVT;
+    ctxt->localRVT = RVT;
+    /*
+    * We need to keep track of the first registered fragment
+    * for extension instructions which return fragments
+    * (e.g. EXSLT'S function), in order to let
+    * xsltExtensionInstructionResultFinalize() clear the
+    * preserving flag on the fragments.
+    */
+    if (ctxt->localRVTBase == NULL)
+	ctxt->localRVTBase = RVT;
+    return(0);
+}
+
+/**
+ * xsltExtensionInstructionResultFinalize:
+ * @ctxt:  an XSLT transformation context
+ *
+ * Finalizes the data (e.g. result tree fragments) created
+ * within a value-returning process (e.g. EXSLT's function).
+ * Tree fragments marked as being returned by a function are
+ * set to normal state, which means that the fragment garbage
+ * collector will free them after the function-calling process exits.
+ *
+ * Returns 0 in case of success and -1 in case of API or internal errors.
+ */
+int
+xsltExtensionInstructionResultFinalize(xsltTransformContextPtr ctxt)
+{
+    xmlDocPtr cur;
+
+    if (ctxt == NULL)
+	return(-1);
+    if (ctxt->localRVTBase == NULL)
+	return(0);
+    /*
+    * Enable remaining local tree fragments to be freed
+    * by the fragment garbage collector.
+    */
+    cur = ctxt->localRVTBase;
+    do {
+	cur->psvi = NULL;
+	cur = (xmlDocPtr) cur->next;
+    } while (cur != NULL);
+    return(0);
+}
+
+/**
+ * xsltExtensionInstructionResultRegister:
+ * @ctxt: an XSLT transformation context
+ * @obj: an XPath object to be inspected for result tree fragments
+ *
+ * Marks the result of a value-returning extension instruction
+ * in order to avoid it being garbage collected before the
+ * extension instruction exits.
+ * Note that one still has to additionally register any newly created
+ * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT().
+ *
+ * Returns 0 in case of success and -1 in case of error.
+ */
+int
+xsltExtensionInstructionResultRegister(xsltTransformContextPtr ctxt,
+				       xmlXPathObjectPtr obj)
+{
+    int i;
+    xmlNodePtr cur;
+    xmlDocPtr doc;
+
+    if ((ctxt == NULL) || (obj == NULL))
+	return(-1);
+
+    /*
+    * OPTIMIZE TODO: If no local variables/params and no local tree
+    * fragments were created, then we don't need to analyse the XPath
+    * objects for tree fragments.
+    */
+
+    if ((obj->type != XPATH_NODESET) && (obj->type != XPATH_XSLT_TREE))
+	return(0);
+    if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0))
+	return(0);
+
+    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
+	cur = obj->nodesetval->nodeTab[i];
+	if (cur->type == XML_NAMESPACE_DECL) {
+	    /*
+	    * The XPath module sets the owner element of a ns-node on
+	    * the ns->next field.
+	    */
+	    if ((((xmlNsPtr) cur)->next != NULL) &&
+		(((xmlNsPtr) cur)->next->type == XML_ELEMENT_NODE))
+	    {
+		cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
+		doc = cur->doc;	
+	    } else {
+		xsltTransformError(ctxt, NULL, ctxt->inst,
+		    "Internal error in "
+		    "xsltExtensionInstructionResultRegister(): "
+		    "Cannot retrieve the doc of a namespace node.\n");
+		goto error;
+	    }
+	} else {
+	    doc = cur->doc;
+	}
+	if (doc == NULL) {
+	    xsltTransformError(ctxt, NULL, ctxt->inst,
+		"Internal error in "
+		"xsltExtensionInstructionResultRegister(): "
+		"Cannot retrieve the doc of a node.\n");
+	    goto error;
+	}
+	if (doc->name && (doc->name[0] == ' ')) {
+	    /*
+	    * This is a result tree fragment.
+	    * We'll use the @psvi field for reference counting.
+	    * TODO: How do we know if this is a value of a
+	    *  global variable or a doc acquired via the
+	    *  document() function?
+	    */
+	    doc->psvi = (void *) ((long) 1);
+	}
+    }
+
+    return(0);
+error:
+    return(-1);
+}
+
+/**
+ * xsltReleaseRVT:
+ * @ctxt:  an XSLT transformation context
+ * @RVT:  a result value tree (Result Tree Fragment)
+ *
+ * Either frees the RVT (which is an xmlDoc) or stores
+ * it in the context's cache for later reuse.
+ */
+void
+xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
+{
+    if (RVT == NULL)
+	return;
+
+    if (ctxt && (ctxt->cache->nbRVT < 40)) {
+	/*
+	* Store the Result Tree Fragment.
+	* Free the document info.
+	*/
+	if (RVT->_private != NULL) {
+	    xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
+	    xmlFree(RVT->_private);
+	    RVT->_private = NULL;
+	}
+	/*
+	* Clear the document tree.
+	* REVISIT TODO: Do we expect ID/IDREF tables to be existent?	
+	*/
+	if (RVT->children != NULL) {
+	    xmlFreeNodeList(RVT->children);
+	    RVT->children = NULL;
+	    RVT->last = NULL;
+	}
+	if (RVT->ids != NULL) {
+	    xmlFreeIDTable((xmlIDTablePtr) RVT->ids);
+	    RVT->ids = NULL;
+	}
+	if (RVT->refs != NULL) {
+	    xmlFreeRefTable((xmlRefTablePtr) RVT->refs);
+	    RVT->refs = NULL;
+	}
+
+	/*
+	* Reset the reference counter.
+	*/
+	RVT->psvi = 0;
+
+	RVT->next = (xmlNodePtr) ctxt->cache->RVT;
+	ctxt->cache->RVT = RVT;
+
+	ctxt->cache->nbRVT++;
+
+#ifdef XSLT_DEBUG_PROFILE_CACHE
+	ctxt->cache->dbgCachedRVTs++;
+#endif
+	return;
+    }
+    /*
+    * Free it.
+    */
+    if (RVT->_private != NULL) {
+	xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private);
+	xmlFree(RVT->_private);
+    }
+    xmlFreeDoc(RVT);
+}
+
+/**
+ * xsltRegisterPersistRVT:
+ * @ctxt:  an XSLT transformation context
+ * @RVT:  a result value tree (Result Tree Fragment)
+ *
+ * Register the result value tree (XSLT 1.0 term: Result Tree Fragment)
+ * in the fragment garbage collector.
+ * The fragment will be freed when the transformation context is
+ * freed.
+ *
+ * Returns 0 in case of success and -1 in case of error.
+ */
+int
+xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
+{
+    if ((ctxt == NULL) || (RVT == NULL)) return(-1);
+
+    RVT->next = (xmlNodePtr) ctxt->persistRVT;
+    if (ctxt->persistRVT != NULL)
+	ctxt->persistRVT->prev = (xmlNodePtr) RVT;
+    ctxt->persistRVT = RVT;
+    return(0);
+}
+
+/**
+ * xsltFreeRVTs:
+ * @ctxt:  an XSLT transformation context
+ *
+ * Frees all registered result value trees (Result Tree Fragments)
+ * of the transformation. Internal function; should not be called
+ * by user-code.
+ */
+void
+xsltFreeRVTs(xsltTransformContextPtr ctxt)
+{
+    xmlDocPtr cur, next;
+
+    if (ctxt == NULL)
+	return;
+    /*
+    * Local fragments.
+    */
+    cur = ctxt->localRVT;
+    while (cur != NULL) {
+        next = (xmlDocPtr) cur->next;
+	if (cur->_private != NULL) {
+	    xsltFreeDocumentKeys(cur->_private);
+	    xmlFree(cur->_private);
+	}
+	xmlFreeDoc(cur);
+	cur = next;
+    }
+    ctxt->localRVT = NULL;
+    /*
+    * User-created per-template fragments.
+    */
+    cur = ctxt->tmpRVT;
+    while (cur != NULL) {
+        next = (xmlDocPtr) cur->next;
+	if (cur->_private != NULL) {
+	    xsltFreeDocumentKeys(cur->_private);
+	    xmlFree(cur->_private);
+	}
+	xmlFreeDoc(cur);
+	cur = next;
+    }
+    ctxt->tmpRVT = NULL;
+    /*
+    * Global fragments.
+    */
+    cur = ctxt->persistRVT;
+    while (cur != NULL) {
+        next = (xmlDocPtr) cur->next;
+	if (cur->_private != NULL) {
+	    xsltFreeDocumentKeys(cur->_private);
+	    xmlFree(cur->_private);
+	}
+	xmlFreeDoc(cur);
+	cur = next;
+    }
+    ctxt->persistRVT = NULL;
+}
+
+/************************************************************************
+ *									*
+ *			Module interfaces				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltNewStackElem:
+ *
+ * Create a new XSLT ParserContext
+ *
+ * Returns the newly allocated xsltParserStackElem or NULL in case of error
+ */
+static xsltStackElemPtr
+xsltNewStackElem(xsltTransformContextPtr ctxt)
+{
+    xsltStackElemPtr ret;
+    /*
+    * Reuse a stack item from the cache if available.
+    */
+    if (ctxt && ctxt->cache->stackItems) {
+	ret = ctxt->cache->stackItems;
+	ctxt->cache->stackItems = ret->next;
+	ret->next = NULL;
+	ctxt->cache->nbStackItems--;
+#ifdef XSLT_DEBUG_PROFILE_CACHE
+	ctxt->cache->dbgReusedVars++;
+#endif
+	return(ret);
+    }
+    ret = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
+    if (ret == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+		"xsltNewStackElem : malloc failed\n");
+	return(NULL);
+    }
+    memset(ret, 0, sizeof(xsltStackElem));
+    ret->context = ctxt;
+    return(ret);
+}
+
+/**
+ * xsltCopyStackElem:
+ * @elem:  an XSLT stack element
+ *
+ * Makes a copy of the stack element
+ *
+ * Returns the copy of NULL
+ */
+static xsltStackElemPtr
+xsltCopyStackElem(xsltStackElemPtr elem) {
+    xsltStackElemPtr cur;
+
+    cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem));
+    if (cur == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+		"xsltCopyStackElem : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltStackElem));
+    cur->context = elem->context;
+    cur->name = elem->name;
+    cur->nameURI = elem->nameURI;
+    cur->select = elem->select;
+    cur->tree = elem->tree;
+    cur->comp = elem->comp;    
+    return(cur);
+}
+
+/**
+ * xsltFreeStackElem:
+ * @elem:  an XSLT stack element
+ *
+ * Free up the memory allocated by @elem
+ */
+static void
+xsltFreeStackElem(xsltStackElemPtr elem) {
+    if (elem == NULL)
+	return;
+    if (elem->value != NULL)
+	xmlXPathFreeObject(elem->value);
+    /*
+    * Release the list of temporary Result Tree Fragments.
+    */
+    if (elem->fragment) {
+	xmlDocPtr cur;
+
+	while (elem->fragment != NULL) {
+	    cur = elem->fragment;
+	    elem->fragment = (xmlDocPtr) cur->next;
+
+	    if (elem->context &&
+		(cur->psvi == (void *) ((long) 1)))
+	    {
+		/*
+		* This fragment is a result of an extension instruction
+		* (e.g. XSLT's function) and needs to be preserved until
+		* the instruction exits.
+		* Example: The fragment of the variable must not be freed
+		*  since it is returned by the EXSLT function:
+		*  <f:function name="foo">
+		*   <xsl:variable name="bar">
+		*     <bar/>
+		*   </xsl:variable>
+		*   <f:result select="$bar"/>
+		*  </f:function>
+		* 
+		*/
+		xsltRegisterLocalRVT(elem->context, cur);
+	    } else {
+		xsltReleaseRVT((xsltTransformContextPtr) elem->context,
+		    cur);
+	    }	    
+	}
+    }
+    /*
+    * Cache or free the variable structure.
+    */
+    if (elem->context && (elem->context->cache->nbStackItems < 50)) {
+	/*
+	* Store the item in the cache.
+	*/
+	xsltTransformContextPtr ctxt = elem->context;
+	memset(elem, 0, sizeof(xsltStackElem));
+	elem->context = ctxt;
+	elem->next = ctxt->cache->stackItems;
+	ctxt->cache->stackItems = elem;	
+	ctxt->cache->nbStackItems++;
+#ifdef XSLT_DEBUG_PROFILE_CACHE
+	ctxt->cache->dbgCachedVars++;
+#endif
+	return;
+    }
+    xmlFree(elem);
+}
+
+/**
+ * xsltFreeStackElemList:
+ * @elem:  an XSLT stack element
+ *
+ * Free up the memory allocated by @elem
+ */
+void
+xsltFreeStackElemList(xsltStackElemPtr elem) {
+    xsltStackElemPtr next;
+    
+    while (elem != NULL) {
+	next = elem->next;
+	xsltFreeStackElem(elem);
+	elem = next;
+    }
+}
+
+/**
+ * xsltStackLookup:
+ * @ctxt:  an XSLT transformation context
+ * @name:  the local part of the name
+ * @nameURI:  the URI part of the name
+ *
+ * Locate an element in the stack based on its name.
+ */
+#if 0 /* TODO: Those seem to have been used for debugging. */
+static int stack_addr = 0;
+static int stack_cmp = 0;
+#endif
+
+static xsltStackElemPtr
+xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
+	        const xmlChar *nameURI) {
+    int i;
+    xsltStackElemPtr cur;
+
+    if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0))
+	return(NULL);
+
+    /*
+     * Do the lookup from the top of the stack, but
+     * don't use params being computed in a call-param
+     * First lookup expects the variable name and URI to
+     * come from the disctionnary and hence pointer comparison.
+     */
+    for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
+	cur = ctxt->varsTab[i-1];
+	while (cur != NULL) {
+	    if ((cur->name == name) && (cur->nameURI == nameURI)) {
+#if 0
+		stack_addr++;
+#endif
+		return(cur);
+	    }
+	    cur = cur->next;
+	}
+    }
+
+    /*
+     * Redo the lookup with interned string compares
+     * to avoid string compares.
+     */
+    name = xmlDictLookup(ctxt->dict, name, -1);
+    if (nameURI != NULL)
+        nameURI = xmlDictLookup(ctxt->dict, nameURI, -1);
+
+    for (i = ctxt->varsNr; i > ctxt->varsBase; i--) {
+	cur = ctxt->varsTab[i-1];
+	while (cur != NULL) {
+	    if ((cur->name == name) && (cur->nameURI == nameURI)) {
+#if 0
+		stack_cmp++;
+#endif
+		return(cur);
+	    }
+	    cur = cur->next;
+	}
+    }
+
+    return(NULL);
+}
+
+/**
+ * xsltCheckStackElem:
+ * @ctxt:  xn XSLT transformation context
+ * @name:  the variable name
+ * @nameURI:  the variable namespace URI
+ *
+ * Checks whether a variable or param is already defined.
+ *
+ * URGENT TODO: Checks for redefinition of vars/params should be
+ *  done only at compilation time.
+ *
+ * Returns 1 if variable is present, 2 if param is present, 3 if this
+ *         is an inherited param, 0 if not found, -1 in case of failure.
+ */
+static int
+xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name,
+	           const xmlChar *nameURI) {
+    xsltStackElemPtr cur;
+
+    if ((ctxt == NULL) || (name == NULL))
+	return(-1);
+
+    cur = xsltStackLookup(ctxt, name, nameURI);
+    if (cur == NULL)
+        return(0);
+    if (cur->comp != NULL) {
+        if (cur->comp->type == XSLT_FUNC_WITHPARAM)
+	    return(3);
+	else if (cur->comp->type == XSLT_FUNC_PARAM)
+	    return(2);
+    }
+    
+    return(1);
+}
+
+/**
+ * xsltAddStackElem:
+ * @ctxt:  xn XSLT transformation context
+ * @elem:  a stack element
+ *
+ * Push an element (or list) onto the stack.
+ * In case of a list, each member will be pushed into
+ * a seperate slot; i.e. there's always 1 stack entry for
+ * 1 stack element.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+static int
+xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem)
+{
+    if ((ctxt == NULL) || (elem == NULL))
+	return(-1);
+
+    do {
+	if (ctxt->varsMax == 0) {
+	    ctxt->varsMax = 10;
+	    ctxt->varsTab =
+		(xsltStackElemPtr *) xmlMalloc(ctxt->varsMax *
+		sizeof(ctxt->varsTab[0]));
+	    if (ctxt->varsTab == NULL) {
+		xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
+		return (-1);
+	    }
+	}
+	if (ctxt->varsNr >= ctxt->varsMax) {
+	    ctxt->varsMax *= 2;
+	    ctxt->varsTab =
+		(xsltStackElemPtr *) xmlRealloc(ctxt->varsTab,
+		ctxt->varsMax *
+		sizeof(ctxt->varsTab[0]));
+	    if (ctxt->varsTab == NULL) {
+		xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
+		return (-1);
+	    }
+	}
+	ctxt->varsTab[ctxt->varsNr++] = elem;
+	ctxt->vars = elem;
+	
+	elem = elem->next;
+    } while (elem != NULL);
+    
+    return(0);
+}
+
+/**
+ * xsltAddStackElemList:
+ * @ctxt:  xn XSLT transformation context
+ * @elems:  a stack element list
+ *
+ * Push an element list onto the stack.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems)
+{
+    return(xsltAddStackElem(ctxt, elems));
+}
+
+/************************************************************************
+ *									*
+ *			Module interfaces				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltEvalVariable:
+ * @ctxt:  the XSLT transformation context
+ * @variable:  the variable or parameter item
+ * @comp: the compiled XSLT instruction
+ *
+ * Evaluate a variable value.
+ *
+ * Returns the XPath Object value or NULL in case of error
+ */
+static xmlXPathObjectPtr
+xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable,
+	         xsltStylePreCompPtr castedComp)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleItemVariablePtr comp =
+	(xsltStyleItemVariablePtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif   
+    xmlXPathObjectPtr result = NULL;
+    xmlNodePtr oldInst;
+
+    if ((ctxt == NULL) || (variable == NULL))
+	return(NULL);
+
+    /*
+    * A variable or parameter are evaluated on demand; thus the
+    * context (of XSLT and XPath) need to be temporarily adjusted and
+    * restored on exit.
+    */
+    oldInst = ctxt->inst;
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+	"Evaluating variable '%s'\n", variable->name));
+#endif
+    if (variable->select != NULL) {
+	xmlXPathCompExprPtr xpExpr = NULL;
+	xmlDocPtr oldXPDoc;
+	xmlNodePtr oldXPContextNode;
+	int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
+	xmlNsPtr *oldXPNamespaces;
+	xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
+	xsltStackElemPtr oldVar = ctxt->contextVariable;
+
+	if ((comp != NULL) && (comp->comp != NULL)) {
+	    xpExpr = comp->comp;
+	} else {
+	    xpExpr = xmlXPathCompile(variable->select);
+	}
+	if (xpExpr == NULL)
+	    return(NULL);
+	/*
+	* Save context states.
+	*/
+	oldXPDoc = xpctxt->doc;
+	oldXPContextNode = xpctxt->node;
+	oldXPProximityPosition = xpctxt->proximityPosition;
+	oldXPContextSize = xpctxt->contextSize;
+	oldXPNamespaces = xpctxt->namespaces;
+	oldXPNsNr = xpctxt->nsNr;
+		
+	xpctxt->node = ctxt->node;
+	/*
+	* OPTIMIZE TODO: Lame try to set the context doc.
+	*   Get rid of this somehow in xpath.c.
+	*/
+	if ((ctxt->node->type != XML_NAMESPACE_DECL) &&
+	    ctxt->node->doc)
+	    xpctxt->doc = ctxt->node->doc;
+	/*
+	* BUG TODO: The proximity position and the context size will
+	*  potentially be wrong.
+	*  Example: 
+	*  <xsl:template select="foo">
+	*    <xsl:variable name="pos" select="position()"/>
+	*    <xsl:for-each select="bar">
+	*      <xsl:value-of select="$pos"/>
+	*    </xsl:for-each>
+	*  </xsl:template>
+	*  Here the proximity position and context size are changed
+	*  to the context of <xsl:for-each select="bar">, but
+	*  the variable needs to be evaluated in the context of
+	*  <xsl:template select="foo">.
+	*/	
+	if (comp != NULL) {
+	    
+#ifdef XSLT_REFACTORED
+	    if (comp->inScopeNs != NULL) {
+		xpctxt->namespaces = comp->inScopeNs->list;
+		xpctxt->nsNr = comp->inScopeNs->xpathNumber;
+	    } else {
+		xpctxt->namespaces = NULL;
+		xpctxt->nsNr = 0;
+	    }
+#else
+	    xpctxt->namespaces = comp->nsList;
+	    xpctxt->nsNr = comp->nsNr;
+#endif
+	} else {
+	    xpctxt->namespaces = NULL;
+	    xpctxt->nsNr = 0;
+	}
+
+	/*
+	* We need to mark that we are "selecting" a var's value;
+	* if any tree fragments are created inside the expression,
+	* then those need to be stored inside the variable; otherwise
+	* we'll eventually free still referenced fragments, before
+	* we leave the scope of the variable.
+	*/
+	ctxt->contextVariable = variable;	
+	variable->flags |= XSLT_VAR_IN_SELECT;	
+	
+	result = xmlXPathCompiledEval(xpExpr, xpctxt);
+
+	variable->flags ^= XSLT_VAR_IN_SELECT;
+	/*
+	* Restore Context states.
+	*/
+	ctxt->contextVariable = oldVar;
+
+	xpctxt->doc = oldXPDoc;
+	xpctxt->node = oldXPContextNode;
+	xpctxt->contextSize = oldXPContextSize;
+	xpctxt->proximityPosition = oldXPProximityPosition;
+	xpctxt->namespaces = oldXPNamespaces;
+	xpctxt->nsNr = oldXPNsNr;
+
+	if ((comp == NULL) || (comp->comp == NULL))
+	    xmlXPathFreeCompExpr(xpExpr);
+	if (result == NULL) {
+	    xsltTransformError(ctxt, NULL,
+		(comp != NULL) ? comp->inst : NULL,
+		"Failed to evaluate the expression of variable '%s'.\n",
+		variable->name);
+	    ctxt->state = XSLT_STATE_STOPPED;
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+#ifdef LIBXML_DEBUG_ENABLED
+	} else {
+	    if ((xsltGenericDebugContext == stdout) ||
+		(xsltGenericDebugContext == stderr))
+		xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
+					result, 0);
+#endif
+#endif
+	}
+    } else {
+	if (variable->tree == NULL) {
+	    result = xmlXPathNewCString("");
+	} else {	    
+	    if (variable->tree) {
+		xmlDocPtr container;
+		xmlNodePtr oldInsert;
+		xmlDocPtr  oldOutput;
+		xsltStackElemPtr oldVar = ctxt->contextVariable;
+
+		/*
+		* Generate a result tree fragment.
+		*/
+		container = xsltCreateRVT(ctxt);
+		if (container == NULL)
+		    goto error;
+		/*
+		* NOTE: Local Result Tree Fragments of params/variables
+		* are not registered globally anymore; the life-time
+		* is not directly dependant of the param/variable itself.
+		*
+		* OLD: xsltRegisterTmpRVT(ctxt, container);
+		*/
+		/*
+		* Attach the Result Tree Fragment to the variable;
+		* when the variable is freed, it will also free 
+		* the Result Tree Fragment.
+		*/
+		variable->fragment = container;
+		
+		oldOutput = ctxt->output;
+		oldInsert = ctxt->insert;		
+		
+		ctxt->output = container;
+		ctxt->insert = (xmlNodePtr) container;
+		ctxt->contextVariable = variable;
+		/*
+		* Process the sequence constructor (variable->tree).
+		* The resulting tree will be held by @container.
+		*/
+		xsltApplyOneTemplate(ctxt, ctxt->node, variable->tree,
+		    NULL, NULL);
+
+		ctxt->contextVariable = oldVar;		
+		ctxt->insert = oldInsert;
+		ctxt->output = oldOutput;
+		
+		result = xmlXPathNewValueTree((xmlNodePtr) container);
+	    }
+	    if (result == NULL) {
+		result = xmlXPathNewCString("");
+	    } else {
+		/*
+		* Freeing is not handled there anymore.
+		* QUESTION TODO: What does the above comment mean?
+		*/
+	        result->boolval = 0; 
+	    }
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+#ifdef LIBXML_DEBUG_ENABLED
+
+	    if ((xsltGenericDebugContext == stdout) ||
+		(xsltGenericDebugContext == stderr))
+		xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
+					result, 0);
+#endif
+#endif
+	}
+    }
+
+error:
+    ctxt->inst = oldInst;
+    return(result);
+}
+
+/**
+ * xsltEvalGlobalVariable:
+ * @elem:  the variable or parameter
+ * @ctxt:  the XSLT transformation context
+ *
+ * Evaluates a the value of a global xsl:variable or
+ * xsl:param declaration.
+ *
+ * Returns the XPath Object value or NULL in case of error
+ */
+static xmlXPathObjectPtr
+xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt)
+{
+    xmlXPathObjectPtr result = NULL;
+    xmlNodePtr oldInst;
+    const xmlChar* oldVarName;
+
+#ifdef XSLT_REFACTORED
+    xsltStyleBasicItemVariablePtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((ctxt == NULL) || (elem == NULL))
+	return(NULL);
+    if (elem->computed)
+	return(elem->value);
+
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+	"Evaluating global variable %s\n", elem->name));
+#endif
+
+#ifdef WITH_DEBUGGER
+    if ((ctxt->debugStatus != XSLT_DEBUG_NONE) &&
+        elem->comp && elem->comp->inst)
+        xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt);
+#endif
+
+    oldInst = ctxt->inst;
+    comp = elem->comp;
+    oldVarName = elem->name;
+    elem->name = xsltComputingGlobalVarMarker;
+    /*
+    * OPTIMIZE TODO: We should consider instantiating global vars/params
+    *  on-demand. The vars/params don't need to be evaluated if never
+    *  called; and in the case of global params, if values for such params
+    *  are provided by the user.
+    */
+    if (elem->select != NULL) {		
+	xmlXPathCompExprPtr xpExpr = NULL;
+	xmlDocPtr oldXPDoc;
+	xmlNodePtr oldXPContextNode;
+	int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
+	xmlNsPtr *oldXPNamespaces;
+	xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
+
+	if ((comp != NULL) && (comp->comp != NULL)) {
+	    xpExpr = comp->comp;
+	} else {
+	    xpExpr = xmlXPathCompile(elem->select);
+	}
+	if (xpExpr == NULL)
+	    goto error;
+	
+	
+	if (comp != NULL)
+	    ctxt->inst = comp->inst;
+	else
+	    ctxt->inst = NULL;
+	/*
+	* SPEC XSLT 1.0:
+	* "At top-level, the expression or template specifying the
+	*  variable value is evaluated with the same context as that used
+	*  to process the root node of the source document: the current
+	*  node is the root node of the source document and the current
+	*  node list is a list containing just the root node of the source
+	*  document."	
+	*/
+	/*
+	* Save context states.
+	*/
+	oldXPDoc = xpctxt->doc;
+	oldXPContextNode = xpctxt->node;
+	oldXPProximityPosition = xpctxt->proximityPosition;
+	oldXPContextSize = xpctxt->contextSize;
+	oldXPNamespaces = xpctxt->namespaces;
+	oldXPNsNr = xpctxt->nsNr;
+		
+	xpctxt->node = ctxt->initialContextNode;
+	xpctxt->doc = ctxt->initialContextDoc;
+	xpctxt->contextSize = 1;
+	xpctxt->proximityPosition = 1;
+		
+	if (comp != NULL) {
+	    
+#ifdef XSLT_REFACTORED
+	    if (comp->inScopeNs != NULL) {
+		xpctxt->namespaces = comp->inScopeNs->list;
+		xpctxt->nsNr = comp->inScopeNs->xpathNumber;
+	    } else {
+		xpctxt->namespaces = NULL;
+		xpctxt->nsNr = 0;
+	    }
+#else
+	    xpctxt->namespaces = comp->nsList;
+	    xpctxt->nsNr = comp->nsNr;
+#endif
+	} else {
+	    xpctxt->namespaces = NULL;
+	    xpctxt->nsNr = 0;
+	}
+	
+	result = xmlXPathCompiledEval(xpExpr, xpctxt);
+
+	/*
+	* Restore Context states.
+	*/
+	xpctxt->doc = oldXPDoc;
+	xpctxt->node = oldXPContextNode;
+	xpctxt->contextSize = oldXPContextSize;
+	xpctxt->proximityPosition = oldXPProximityPosition;
+	xpctxt->namespaces = oldXPNamespaces;
+	xpctxt->nsNr = oldXPNsNr;
+
+	if ((comp == NULL) || (comp->comp == NULL))
+	    xmlXPathFreeCompExpr(xpExpr);
+	if (result == NULL) {
+	    if (comp == NULL)
+		xsltTransformError(ctxt, NULL, NULL,
+		    "Evaluating global variable %s failed\n", elem->name);
+	    else
+		xsltTransformError(ctxt, NULL, comp->inst,
+		    "Evaluating global variable %s failed\n", elem->name);
+	    ctxt->state = XSLT_STATE_STOPPED;
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+#ifdef LIBXML_DEBUG_ENABLED
+	} else {
+	    if ((xsltGenericDebugContext == stdout) ||
+		(xsltGenericDebugContext == stderr))
+		xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
+					result, 0);
+#endif
+#endif
+	}
+    } else {
+	if (elem->tree == NULL) {
+	    result = xmlXPathNewCString("");
+	} else {
+	    xmlDocPtr container;
+	    xmlNodePtr oldInsert;
+	    xmlDocPtr  oldOutput, oldXPDoc;	    
+	    /*
+	    * Generate a result tree fragment.
+	    */
+	    container = xsltCreateRVT(ctxt);
+	    if (container == NULL)
+		goto error;
+	    /*
+	    * Let the lifetime of the tree fragment be handled by
+	    * the Libxslt's garbage collector.
+	    */
+	    xsltRegisterPersistRVT(ctxt, container);	    
+
+	    oldOutput = ctxt->output;
+	    oldInsert = ctxt->insert;
+
+	    oldXPDoc = ctxt->xpathCtxt->doc;
+	    
+	    ctxt->output = container;	    
+	    ctxt->insert = (xmlNodePtr) container;
+
+	    ctxt->xpathCtxt->doc = ctxt->initialContextDoc;
+	    /*
+	    * Process the sequence constructor.
+	    */
+	    xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL);
+
+	    ctxt->xpathCtxt->doc = oldXPDoc;
+
+	    ctxt->insert = oldInsert;
+	    ctxt->output = oldOutput;
+	    
+	    result = xmlXPathNewValueTree((xmlNodePtr) container);
+	    if (result == NULL) {
+		result = xmlXPathNewCString("");
+	    } else {
+	        result->boolval = 0; /* Freeing is not handled there anymore */
+	    }
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+#ifdef LIBXML_DEBUG_ENABLED
+	    if ((xsltGenericDebugContext == stdout) ||
+		(xsltGenericDebugContext == stderr))
+		xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
+					result, 0);
+#endif
+#endif
+	}
+    }
+
+error:
+    elem->name = oldVarName;
+    ctxt->inst = oldInst;
+    if (result != NULL) {
+	elem->value = result;
+	elem->computed = 1;
+    }
+    return(result);
+}
+
+/**
+ * xsltEvalGlobalVariables:
+ * @ctxt:  the XSLT transformation context
+ *
+ * Evaluates all global variables and parameters of a stylesheet.
+ * For internal use only. This is called at start of a transformation.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) {
+    xsltStackElemPtr elem;
+    xsltStylesheetPtr style;    
+
+    if ((ctxt == NULL) || (ctxt->document == NULL))
+	return(-1);
+ 
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+	"Registering global variables\n"));
+#endif
+    /*
+     * Walk the list from the stylesheets and populate the hash table
+     */
+    style = ctxt->style;
+    while (style != NULL) {
+	elem = style->variables;
+	
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+	if ((style->doc != NULL) && (style->doc->URL != NULL)) {
+	    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+			     "Registering global variables from %s\n",
+		             style->doc->URL));
+	}
+#endif
+
+	while (elem != NULL) {
+	    xsltStackElemPtr def;
+
+	    /*
+	     * Global variables are stored in the variables pool.
+	     */
+	    def = (xsltStackElemPtr) 
+		    xmlHashLookup2(ctxt->globalVars,
+		                 elem->name, elem->nameURI);
+	    if (def == NULL) {
+
+		def = xsltCopyStackElem(elem);
+		xmlHashAddEntry2(ctxt->globalVars,
+				 elem->name, elem->nameURI, def);
+	    } else if ((elem->comp != NULL) &&
+		       (elem->comp->type == XSLT_FUNC_VARIABLE)) {
+		/*
+		 * Redefinition of variables from a different stylesheet
+		 * should not generate a message.
+		 */
+		if ((elem->comp->inst != NULL) &&
+		    (def->comp != NULL) && (def->comp->inst != NULL) &&
+		    (elem->comp->inst->doc == def->comp->inst->doc))
+		{
+		    xsltTransformError(ctxt, style, elem->comp->inst,
+			"Global variable %s already defined\n", elem->name);
+		    if (style != NULL) style->errors++;
+		}
+	    }
+	    elem = elem->next;
+	}
+
+	style = xsltNextImport(style);
+    }
+
+    /*
+     * This part does the actual evaluation
+     */    
+    xmlHashScan(ctxt->globalVars,
+	        (xmlHashScanner) xsltEvalGlobalVariable, ctxt);
+
+    return(0);
+}
+
+/**
+ * xsltRegisterGlobalVariable:
+ * @style:  the XSLT transformation context
+ * @name:  the variable name
+ * @ns_uri:  the variable namespace URI
+ * @sel:  the expression which need to be evaluated to generate a value
+ * @tree:  the subtree if sel is NULL
+ * @comp:  the precompiled value
+ * @value:  the string value if available
+ *
+ * Register a new variable value. If @value is NULL it unregisters
+ * the variable
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+static int
+xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name,
+		     const xmlChar *ns_uri, const xmlChar *sel,
+		     xmlNodePtr tree, xsltStylePreCompPtr comp,
+		     const xmlChar *value) {
+    xsltStackElemPtr elem, tmp;
+    if (style == NULL)
+	return(-1);
+    if (name == NULL)
+	return(-1);
+    if (comp == NULL)
+	return(-1);
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    if (comp->type == XSLT_FUNC_PARAM)
+	xsltGenericDebug(xsltGenericDebugContext,
+			 "Defining global param %s\n", name);
+    else
+	xsltGenericDebug(xsltGenericDebugContext,
+			 "Defining global variable %s\n", name);
+#endif
+
+    elem = xsltNewStackElem(NULL);
+    if (elem == NULL)
+	return(-1);
+    elem->comp = comp;
+    elem->name = xmlDictLookup(style->dict, name, -1);
+    elem->select = xmlDictLookup(style->dict, sel, -1);
+    if (ns_uri)
+	elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1);
+    elem->tree = tree;
+    tmp = style->variables;
+    if (tmp == NULL) {
+	elem->next = NULL;
+	style->variables = elem;
+    } else {
+	while (tmp != NULL) {
+	    if ((elem->comp->type == XSLT_FUNC_VARIABLE) &&
+		(tmp->comp->type == XSLT_FUNC_VARIABLE) &&
+		(xmlStrEqual(elem->name, tmp->name)) &&
+		((elem->nameURI == tmp->nameURI) ||
+		 (xmlStrEqual(elem->nameURI, tmp->nameURI))))
+	    {
+		xsltTransformError(NULL, style, comp->inst,
+		"redefinition of global variable %s\n", elem->name);
+		style->errors++;
+	    }
+	    if (tmp->next == NULL)
+	        break;
+	    tmp = tmp->next;
+	}
+	elem->next = NULL;
+	tmp->next = elem;
+    }
+    if (value != NULL) {
+	elem->computed = 1;
+	elem->value = xmlXPathNewString(value);
+    }
+    return(0);
+}
+
+/**
+ * xsltProcessUserParamInternal
+ *
+ * @ctxt:  the XSLT transformation context
+ * @name:  a null terminated parameter name
+ * @value: a null terminated value (may be an XPath expression)
+ * @eval:  0 to treat the value literally, else evaluate as XPath expression
+ *
+ * If @eval is 0 then @value is treated literally and is stored in the global
+ * parameter/variable table without any change.
+ *
+ * Uf @eval is 1 then @value is treated as an XPath expression and is
+ * evaluated.  In this case, if you want to pass a string which will be
+ * interpreted literally then it must be enclosed in single or double quotes.
+ * If the string contains single quotes (double quotes) then it cannot be
+ * enclosed single quotes (double quotes).  If the string which you want to
+ * be treated literally contains both single and double quotes (e.g. Meet
+ * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable
+ * quoting character.  You cannot use &apos; or &quot; inside the string
+ * because the replacement of character entities with their equivalents is
+ * done at a different stage of processing.  The solution is to call
+ * xsltQuoteUserParams or xsltQuoteOneUserParam.
+ *
+ * This needs to be done on parsed stylesheets before starting to apply
+ * transformations.  Normally this will be called (directly or indirectly)
+ * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams,
+ * or xsltQuoteOneUserParam.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+
+static
+int
+xsltProcessUserParamInternal(xsltTransformContextPtr ctxt,
+		             const xmlChar * name,
+			     const xmlChar * value,
+			     int eval) {
+
+    xsltStylesheetPtr style;
+    const xmlChar *prefix;
+    const xmlChar *href;
+    xmlXPathCompExprPtr xpExpr;
+    xmlXPathObjectPtr result;
+    
+    xsltStackElemPtr elem;
+    int res;
+    void *res_ptr;
+
+    if (ctxt == NULL)
+	return(-1);
+    if (name == NULL)
+	return(0);
+    if (value == NULL)
+	return(0);
+
+    style = ctxt->style;
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+	    "Evaluating user parameter %s=%s\n", name, value));
+#endif
+
+    /*
+     * Name lookup
+     */
+
+    name = xsltSplitQName(ctxt->dict, name, &prefix);
+    href = NULL;
+    if (prefix != NULL) {
+	xmlNsPtr ns;
+
+	ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc),
+			 prefix);
+	if (ns == NULL) {
+	    xsltTransformError(ctxt, style, NULL,
+	    "user param : no namespace bound to prefix %s\n", prefix);
+	    href = NULL;
+	} else {
+	    href = ns->href;
+	}
+    }
+
+    if (name == NULL)
+	return (-1);
+
+    res_ptr = xmlHashLookup2(ctxt->globalVars, name, href);
+    if (res_ptr != 0) {
+	xsltTransformError(ctxt, style, NULL,
+	    "Global parameter %s already defined\n", name);
+    }
+    if (ctxt->globalVars == NULL)
+	ctxt->globalVars = xmlHashCreate(20);
+
+    /*
+     * do not overwrite variables with parameters from the command line
+     */
+    while (style != NULL) {
+        elem = ctxt->style->variables;
+	while (elem != NULL) {
+	    if ((elem->comp != NULL) &&
+	        (elem->comp->type == XSLT_FUNC_VARIABLE) &&
+		(xmlStrEqual(elem->name, name)) &&
+		(xmlStrEqual(elem->nameURI, href))) {
+		return(0);
+	    }
+            elem = elem->next;
+	}
+        style = xsltNextImport(style);
+    }
+    style = ctxt->style;
+    elem = NULL;
+
+    /*
+     * Do the evaluation if @eval is non-zero.
+     */
+
+    result = NULL;
+    if (eval != 0) {
+        xpExpr = xmlXPathCompile(value);
+	if (xpExpr != NULL) {
+	    xmlDocPtr oldXPDoc;
+	    xmlNodePtr oldXPContextNode;
+	    int oldXPProximityPosition, oldXPContextSize, oldXPNsNr;
+	    xmlNsPtr *oldXPNamespaces;
+	    xmlXPathContextPtr xpctxt = ctxt->xpathCtxt;
+	   
+	    /*
+	    * Save context states.
+	    */
+	    oldXPDoc = xpctxt->doc;
+	    oldXPContextNode = xpctxt->node;
+	    oldXPProximityPosition = xpctxt->proximityPosition;
+	    oldXPContextSize = xpctxt->contextSize;
+	    oldXPNamespaces = xpctxt->namespaces;
+	    oldXPNsNr = xpctxt->nsNr;
+
+	    /*
+	    * SPEC XSLT 1.0:
+	    * "At top-level, the expression or template specifying the
+	    *  variable value is evaluated with the same context as that used
+	    *  to process the root node of the source document: the current
+	    *  node is the root node of the source document and the current
+	    *  node list is a list containing just the root node of the source
+	    *  document."
+	    */
+	    xpctxt->doc = ctxt->initialContextDoc;	    
+	    xpctxt->node = ctxt->initialContextNode;	    
+	    xpctxt->contextSize = 1;
+	    xpctxt->proximityPosition = 1;
+	    /* 
+	    * There is really no in scope namespace for parameters on the
+	    * command line.
+	    */
+	    xpctxt->namespaces = NULL;
+	    xpctxt->nsNr = 0;	   
+	    
+	    result = xmlXPathCompiledEval(xpExpr, xpctxt);
+	    
+	    /*
+	    * Restore Context states.
+	    */
+	    xpctxt->doc = oldXPDoc;
+	    xpctxt->node = oldXPContextNode;
+	    xpctxt->contextSize = oldXPContextSize;
+	    xpctxt->proximityPosition = oldXPProximityPosition;
+	    xpctxt->namespaces = oldXPNamespaces;
+	    xpctxt->nsNr = oldXPNsNr;
+	    
+	    xmlXPathFreeCompExpr(xpExpr);
+	}
+	if (result == NULL) {
+	    xsltTransformError(ctxt, style, NULL,
+		"Evaluating user parameter %s failed\n", name);
+	    ctxt->state = XSLT_STATE_STOPPED;
+	    return(-1);
+	}
+    }
+
+    /* 
+     * If @eval is 0 then @value is to be taken literally and result is NULL
+     * 
+     * If @eval is not 0, then @value is an XPath expression and has been
+     * successfully evaluated and result contains the resulting value and
+     * is not NULL.
+     *
+     * Now create an xsltStackElemPtr for insertion into the context's
+     * global variable/parameter hash table.
+     */
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+#ifdef LIBXML_DEBUG_ENABLED
+    if ((xsltGenericDebugContext == stdout) ||
+        (xsltGenericDebugContext == stderr))
+	    xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext,
+				    result, 0);
+#endif
+#endif
+
+    elem = xsltNewStackElem(NULL);
+    if (elem != NULL) {
+	elem->name = name;
+	elem->select = xmlDictLookup(ctxt->dict, value, -1);
+	if (href != NULL)
+	    elem->nameURI = xmlDictLookup(ctxt->dict, href, -1);
+	elem->tree = NULL;
+	elem->computed = 1;
+	if (eval == 0) {
+	    elem->value = xmlXPathNewString(value);
+	} 
+	else {
+	    elem->value = result;
+	}
+    }
+
+    /*
+     * Global parameters are stored in the XPath context variables pool.
+     */
+
+    res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem);
+    if (res != 0) {
+	xsltFreeStackElem(elem);
+	xsltTransformError(ctxt, style, NULL,
+	    "Global parameter %s already defined\n", name);
+    }
+    return(0);
+}
+
+/**
+ * xsltEvalUserParams:
+ *
+ * @ctxt:  the XSLT transformation context
+ * @params:  a NULL terminated array of parameters name/value tuples
+ *
+ * Evaluate the global variables of a stylesheet. This needs to be
+ * done on parsed stylesheets before starting to apply transformations.
+ * Each of the parameters is evaluated as an XPath expression and stored
+ * in the global variables/parameter hash table.  If you want your
+ * parameter used literally, use xsltQuoteUserParams.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+ 
+int
+xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) {
+    int indx = 0;
+    const xmlChar *name;
+    const xmlChar *value;
+
+    if (params == NULL)
+	return(0);
+    while (params[indx] != NULL) {
+	name = (const xmlChar *) params[indx++];
+	value = (const xmlChar *) params[indx++];
+    	if (xsltEvalOneUserParam(ctxt, name, value) != 0) 
+	    return(-1);
+    }
+    return 0;
+}
+
+/**
+ * xsltQuoteUserParams:
+ *
+ * @ctxt:  the XSLT transformation context
+ * @params:  a NULL terminated arry of parameters names/values tuples
+ *
+ * Similar to xsltEvalUserParams, but the values are treated literally and
+ * are * *not* evaluated as XPath expressions. This should be done on parsed
+ * stylesheets before starting to apply transformations.
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+ 
+int
+xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) {
+    int indx = 0;
+    const xmlChar *name;
+    const xmlChar *value;
+
+    if (params == NULL)
+	return(0);
+    while (params[indx] != NULL) {
+	name = (const xmlChar *) params[indx++];
+	value = (const xmlChar *) params[indx++];
+    	if (xsltQuoteOneUserParam(ctxt, name, value) != 0) 
+	    return(-1);
+    }
+    return 0;
+}
+
+/**
+ * xsltEvalOneUserParam:
+ * @ctxt:  the XSLT transformation context
+ * @name:  a null terminated string giving the name of the parameter
+ * @value:  a null terminated string giving the XPath expression to be evaluated
+ *
+ * This is normally called from xsltEvalUserParams to process a single
+ * parameter from a list of parameters.  The @value is evaluated as an
+ * XPath expression and the result is stored in the context's global
+ * variable/parameter hash table.
+ *
+ * To have a parameter treated literally (not as an XPath expression)
+ * use xsltQuoteUserParams (or xsltQuoteOneUserParam).  For more
+ * details see description of xsltProcessOneUserParamInternal.
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+
+int
+xsltEvalOneUserParam(xsltTransformContextPtr ctxt,
+    		     const xmlChar * name,
+		     const xmlChar * value) {
+    return xsltProcessUserParamInternal(ctxt, name, value,
+		                        1 /* xpath eval ? */);
+}
+
+/**
+ * xsltQuoteOneUserParam:
+ * @ctxt:  the XSLT transformation context
+ * @name:  a null terminated string giving the name of the parameter
+ * @value:  a null terminated string giving the parameter value
+ *
+ * This is normally called from xsltQuoteUserParams to process a single
+ * parameter from a list of parameters.  The @value is stored in the
+ * context's global variable/parameter hash table.
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+
+int
+xsltQuoteOneUserParam(xsltTransformContextPtr ctxt,
+			 const xmlChar * name,
+			 const xmlChar * value) {
+    return xsltProcessUserParamInternal(ctxt, name, value,
+					0 /* xpath eval ? */);
+}
+
+/**
+ * xsltBuildVariable:
+ * @ctxt:  the XSLT transformation context
+ * @comp:  the precompiled form
+ * @tree:  the tree if select is NULL
+ *
+ * Computes a new variable value.
+ *
+ * Returns the xsltStackElemPtr or NULL in case of error
+ */
+static xsltStackElemPtr
+xsltBuildVariable(xsltTransformContextPtr ctxt,
+		  xsltStylePreCompPtr castedComp,
+		  xmlNodePtr tree)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleBasicItemVariablePtr comp =
+	(xsltStyleBasicItemVariablePtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+#endif 
+    xsltStackElemPtr elem;
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+		     "Building variable %s", comp->name));
+    if (comp->select != NULL)
+	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+			 " select %s", comp->select));
+    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n"));
+#endif
+
+    elem = xsltNewStackElem(ctxt);
+    if (elem == NULL)
+	return(NULL);
+    elem->comp = (xsltStylePreCompPtr) comp;
+    elem->name = comp->name;
+    elem->select = comp->select;
+    elem->nameURI = comp->ns;
+    elem->tree = tree;
+    elem->value = xsltEvalVariable(ctxt, elem,
+	(xsltStylePreCompPtr) comp);
+    if (elem->value != NULL)
+	elem->computed = 1;
+    return(elem);
+}
+
+/**
+ * xsltRegisterVariable:
+ * @ctxt:  the XSLT transformation context
+ * @comp: the compiled XSLT-variable (or param) instruction
+ * @tree:  the tree if select is NULL
+ * @isParam:  indicates if this is a parameter
+ *
+ * Computes and registers a new variable.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+static int
+xsltRegisterVariable(xsltTransformContextPtr ctxt,
+		     xsltStylePreCompPtr castedComp,
+		     xmlNodePtr tree, int isParam)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleBasicItemVariablePtr comp =
+	(xsltStyleBasicItemVariablePtr) castedComp;
+#else
+    xsltStylePreCompPtr comp = castedComp;
+    int present;
+#endif
+    xsltStackElemPtr variable;    
+    
+#ifdef XSLT_REFACTORED
+    /*
+    * REFACTORED NOTE: Redefinitions of vars/params are checked
+    *  at compilation time in the refactored code.
+    * xsl:with-param parameters are checked in xsltApplyXSLTTemplate().
+    */
+#else
+    present = xsltCheckStackElem(ctxt, comp->name, comp->ns);
+    if (isParam == 0) {	
+	if ((present != 0) && (present != 3)) {
+	    /* TODO: report QName. */
+	    xsltTransformError(ctxt, NULL, comp->inst,
+		"XSLT-variable: Redefinition of variable '%s'.\n", comp->name);
+	    return(0);
+	}
+    } else if (present != 0) {
+	if ((present == 1) || (present == 2)) {
+	    /* TODO: report QName. */
+	    xsltTransformError(ctxt, NULL, comp->inst,
+		"XSLT-param: Redefinition of parameter '%s'.\n", comp->name);
+	    return(0);
+	}
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+		 "param %s defined by caller\n", comp->name));
+#endif
+	return(0);
+    }
+#endif /* else of XSLT_REFACTORED */
+
+    variable = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
+    xsltAddStackElem(ctxt, variable);
+    return(0);
+}
+
+/**
+ * xsltGlobalVariableLookup:
+ * @ctxt:  the XSLT transformation context
+ * @name:  the variable name
+ * @ns_uri:  the variable namespace URI
+ *
+ * Search in the Variable array of the context for the given
+ * variable value.
+ *
+ * Returns the value or NULL if not found
+ */
+static xmlXPathObjectPtr
+xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
+		         const xmlChar *ns_uri) {
+    xsltStackElemPtr elem;
+    xmlXPathObjectPtr ret = NULL;
+
+    /*
+     * Lookup the global variables in XPath global variable hash table
+     */
+    if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL))
+	return(NULL);
+    elem = (xsltStackElemPtr)
+	    xmlHashLookup2(ctxt->globalVars, name, ns_uri);
+    if (elem == NULL) {
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+			 "global variable not found %s\n", name));
+#endif
+	return(NULL);
+    }
+    /*
+    * URGENT TODO: Move the detection of recursive definitions
+    * to compile-time.
+    */
+    if (elem->computed == 0) {
+	if (elem->name == xsltComputingGlobalVarMarker) {
+	    xsltTransformError(ctxt, NULL, elem->comp->inst,
+		"Recursive definition of %s\n", name);
+	    return(NULL);
+	}
+	ret = xsltEvalGlobalVariable(elem, ctxt);
+    } else
+	ret = elem->value;
+    return(xmlXPathObjectCopy(ret));
+}
+
+/**
+ * xsltVariableLookup:
+ * @ctxt:  the XSLT transformation context
+ * @name:  the variable name
+ * @ns_uri:  the variable namespace URI
+ *
+ * Search in the Variable array of the context for the given
+ * variable value.
+ *
+ * Returns the value or NULL if not found
+ */
+xmlXPathObjectPtr
+xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name,
+		   const xmlChar *ns_uri) {
+    xsltStackElemPtr elem;
+
+    if (ctxt == NULL)
+	return(NULL);
+
+    elem = xsltStackLookup(ctxt, name, ns_uri);
+    if (elem == NULL) {
+	return(xsltGlobalVariableLookup(ctxt, name, ns_uri));
+    }
+    if (elem->computed == 0) {
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+		         "uncomputed variable %s\n", name));
+#endif
+        elem->value = xsltEvalVariable(ctxt, elem, NULL);
+	elem->computed = 1;
+    }
+    if (elem->value != NULL)
+	return(xmlXPathObjectCopy(elem->value));
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+		     "variable not found %s\n", name));
+#endif
+    return(NULL);
+}
+
+/**
+ * xsltParseStylesheetCallerParam:
+ * @ctxt:  the XSLT transformation context 
+ * @inst:  the xsl:with-param instruction element
+ *
+ * Processes an xsl:with-param instruction at transformation time.
+ * The value is compute, but not recorded.
+ * NOTE that this is also called with an *xsl:param* element
+ * from exsltFuncFunctionFunction(). 
+ *
+ * Returns the new xsltStackElemPtr or NULL
+ */
+
+xsltStackElemPtr
+xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleBasicItemVariablePtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+    xmlNodePtr tree = NULL; /* The first child node of the instruction or
+                               the instruction itself. */
+    xsltStackElemPtr param = NULL;
+    
+    if ((ctxt == NULL) || (inst == NULL))
+	return(NULL);
+
+#ifdef XSLT_REFACTORED
+    comp = (xsltStyleBasicItemVariablePtr) inst->psvi;
+#else
+    comp = (xsltStylePreCompPtr) inst->psvi;
+#endif
+    
+    if (comp == NULL) {
+        xsltTransformError(ctxt, NULL, inst,
+	    "Internal error in xsltParseStylesheetCallerParam(): "
+	    "The XSLT 'with-param' instruction was not compiled.\n");
+        return(NULL);
+    }
+    if (comp->name == NULL) {
+	xsltTransformError(ctxt, NULL, inst,
+	    "Internal error in xsltParseStylesheetCallerParam(): "
+	    "XSLT 'with-param': The attribute 'name' was not compiled.\n");
+	return(NULL);
+    }
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+	    "Handling xsl:with-param %s\n", comp->name));
+#endif
+
+    if (comp->select == NULL) {
+	tree = inst->children;
+    } else {
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+	XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+	    "        select %s\n", comp->select));
+#endif
+	tree = inst;
+    }
+
+    param = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree);
+
+    return(param);
+}
+
+/**
+ * xsltParseGlobalVariable:
+ * @style:  the XSLT stylesheet
+ * @cur:  the "variable" element
+ *
+ * Parses a global XSLT 'variable' declaration at compilation time
+ * and registers it
+ */
+void
+xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleItemVariablePtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((cur == NULL) || (style == NULL))
+	return;
+    
+#ifdef XSLT_REFACTORED
+    /*
+    * Note that xsltStylePreCompute() will be called from
+    * xslt.c only.
+    */
+    comp = (xsltStyleItemVariablePtr) cur->psvi;
+#else
+    xsltStylePreCompute(style, cur);
+    comp = (xsltStylePreCompPtr) cur->psvi;
+#endif
+    if (comp == NULL) {
+	xsltTransformError(NULL, style, cur,
+	     "xsl:variable : compilation failed\n");
+	return;
+    }
+
+    if (comp->name == NULL) {
+	xsltTransformError(NULL, style, cur,
+	    "xsl:variable : missing name attribute\n");
+	return;
+    }
+
+    /*
+    * Parse the content (a sequence constructor) of xsl:variable.
+    */
+    if (cur->children != NULL) {
+#ifdef XSLT_REFACTORED	
+        xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
+#else
+        xsltParseTemplateContent(style, cur);
+#endif
+    }
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    xsltGenericDebug(xsltGenericDebugContext,
+	"Registering global variable %s\n", comp->name);
+#endif
+
+    xsltRegisterGlobalVariable(style, comp->name, comp->ns,
+	comp->select, cur->children, (xsltStylePreCompPtr) comp,
+	NULL);
+}
+
+/**
+ * xsltParseGlobalParam:
+ * @style:  the XSLT stylesheet
+ * @cur:  the "param" element
+ *
+ * parse an XSLT transformation param declaration and record
+ * its value.
+ */
+
+void
+xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemParamPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((cur == NULL) || (style == NULL))
+	return;
+    
+#ifdef XSLT_REFACTORED
+    /*
+    * Note that xsltStylePreCompute() will be called from
+    * xslt.c only.
+    */
+    comp = (xsltStyleItemParamPtr) cur->psvi;
+#else
+    xsltStylePreCompute(style, cur);
+    comp = (xsltStylePreCompPtr) cur->psvi;
+#endif    
+    if (comp == NULL) {
+	xsltTransformError(NULL, style, cur,
+	     "xsl:param : compilation failed\n");
+	return;
+    }
+
+    if (comp->name == NULL) {
+	xsltTransformError(NULL, style, cur,
+	    "xsl:param : missing name attribute\n");
+	return;
+    }
+
+    /*
+    * Parse the content (a sequence constructor) of xsl:param.
+    */
+    if (cur->children != NULL) {
+#ifdef XSLT_REFACTORED	
+        xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children);
+#else
+        xsltParseTemplateContent(style, cur);
+#endif
+    }
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    xsltGenericDebug(xsltGenericDebugContext,
+	"Registering global param %s\n", comp->name);
+#endif
+
+    xsltRegisterGlobalVariable(style, comp->name, comp->ns,
+	comp->select, cur->children, (xsltStylePreCompPtr) comp,
+	NULL);
+}
+
+/**
+ * xsltParseStylesheetVariable:
+ * @ctxt:  the XSLT transformation context
+ * @inst:  the xsl:variable instruction element
+ *
+ * Registers a local XSLT 'variable' instruction at transformation time
+ * and evaluates its value.
+ */
+void
+xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleItemVariablePtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((inst == NULL) || (ctxt == NULL))
+	return;
+
+    comp = inst->psvi;
+    if (comp == NULL) {
+        xsltTransformError(ctxt, NULL, inst,
+	    "Internal error in xsltParseStylesheetVariable(): "
+	    "The XSLT 'variable' instruction was not compiled.\n");
+        return;
+    }
+    if (comp->name == NULL) {
+	xsltTransformError(ctxt, NULL, inst,
+	    "Internal error in xsltParseStylesheetVariable(): "
+	    "The attribute 'name' was not compiled.\n");
+	return;
+    }
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+	"Registering variable '%s'\n", comp->name));
+#endif
+
+    xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, inst->children, 0);
+}
+
+/**
+ * xsltParseStylesheetParam:
+ * @ctxt:  the XSLT transformation context
+ * @cur:  the XSLT 'param' element
+ *
+ * Registers a local XSLT 'param' declaration at transformation time and
+ * evaluates its value.
+ */
+void
+xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur)
+{
+#ifdef XSLT_REFACTORED
+    xsltStyleItemParamPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+
+    if ((cur == NULL) || (ctxt == NULL))
+	return;
+
+    comp = cur->psvi;
+    if ((comp == NULL) || (comp->name == NULL)) {
+	xsltTransformError(ctxt, NULL, cur,
+	    "Internal error in xsltParseStylesheetParam(): "
+	    "The XSLT 'param' declaration was not compiled correctly.\n");
+	return;
+    }
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+	"Registering param %s\n", comp->name));
+#endif
+
+    xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1);
+}
+
+/**
+ * xsltFreeGlobalVariables:
+ * @ctxt:  the XSLT transformation context
+ *
+ * Free up the data associated to the global variables
+ * its value.
+ */
+
+void
+xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) {
+    xmlHashFree(ctxt->globalVars, (xmlHashDeallocator) xsltFreeStackElem);
+}
+
+/**
+ * xsltXPathVariableLookup:
+ * @ctxt:  a void * but the the XSLT transformation context actually
+ * @name:  the variable name
+ * @ns_uri:  the variable namespace URI
+ *
+ * This is the entry point when a varibale is needed by the XPath
+ * interpretor.
+ *
+ * Returns the value or NULL if not found
+ */
+xmlXPathObjectPtr
+xsltXPathVariableLookup(void *ctxt, const xmlChar *name,
+	                const xmlChar *ns_uri) {
+    xsltTransformContextPtr tctxt;
+    xmlXPathObjectPtr valueObj = NULL;
+
+    if ((ctxt == NULL) || (name == NULL))
+	return(NULL);
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+	    "Lookup variable '%s'\n", name));
+#endif
+    
+    tctxt = (xsltTransformContextPtr) ctxt;
+    /*
+    * Local variables/params ---------------------------------------------
+    *
+    * Do the lookup from the top of the stack, but
+    * don't use params being computed in a call-param
+    * First lookup expects the variable name and URI to
+    * come from the disctionnary and hence pointer comparison.
+    */
+    if (tctxt->varsNr != 0) {
+	int i;
+	xsltStackElemPtr variable = NULL, cur;
+
+	for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
+	    cur = tctxt->varsTab[i-1];
+	    if ((cur->name == name) && (cur->nameURI == ns_uri)) {
+#if 0
+		stack_addr++;
+#endif
+		variable = cur;
+		goto local_variable_found;
+	    }
+	    cur = cur->next;
+	}	
+	/*
+	* Redo the lookup with interned strings to avoid string comparison.
+	*
+	* OPTIMIZE TODO: The problem here is, that if we request a
+	*  global variable, then this will be also executed.
+	*/
+	{
+	    const xmlChar *tmpName = name, *tmpNsName = ns_uri;
+
+	    name = xmlDictLookup(tctxt->dict, name, -1);
+	    if (ns_uri)
+		ns_uri = xmlDictLookup(tctxt->dict, ns_uri, -1);
+	    if ((tmpName != name) || (tmpNsName != ns_uri)) {		
+		for (i = tctxt->varsNr; i > tctxt->varsBase; i--) {
+		    cur = tctxt->varsTab[i-1];
+		    if ((cur->name == name) && (cur->nameURI == ns_uri)) {
+#if 0
+			stack_cmp++;
+#endif
+			variable = cur;
+			goto local_variable_found;
+		    }
+		}
+	    }
+	}
+
+local_variable_found:
+
+	if (variable) {
+	    if (variable->computed == 0) {
+		
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+		XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+		    "uncomputed variable '%s'\n", name));
+#endif
+		variable->value = xsltEvalVariable(tctxt, variable, NULL);
+		variable->computed = 1;
+	    }
+	    if (variable->value != NULL) {
+		valueObj = xmlXPathObjectCopy(variable->value); 
+	    }
+	    return(valueObj);
+	}
+    }
+    /*
+    * Global variables/params --------------------------------------------
+    */    
+    if (tctxt->globalVars) {
+	valueObj = xsltGlobalVariableLookup(tctxt, name, ns_uri);
+    }
+
+    if (valueObj == NULL) {
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+    XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+		     "variable not found '%s'\n", name));
+#endif
+
+	if (ns_uri) {
+	    xsltTransformError(tctxt, NULL, tctxt->inst,
+		"Variable '{%s}%s' has not been declared.\n", ns_uri, name);
+	} else {
+	    xsltTransformError(tctxt, NULL, tctxt->inst,
+		"Variable '%s' has not been declared.\n", name);
+	}
+    } else {
+
+#ifdef WITH_XSLT_DEBUG_VARIABLE
+	XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext,
+	    "found variable '%s'\n", name));
+#endif
+    }
+
+    return(valueObj);
+}
+
+
diff --git a/libxslt/variables.h b/libxslt/variables.h
new file mode 100644
index 0000000..85055e4
--- /dev/null
+++ b/libxslt/variables.h
@@ -0,0 +1,91 @@
+/*
+ * Summary: interface for the variable matching and lookup.
+ * Description: interface for the variable matching and lookup.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_VARIABLES_H__
+#define __XML_XSLT_VARIABLES_H__
+
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include "xsltexports.h"
+#include "xsltInternals.h"
+#include "functions.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * XSLT_REGISTER_VARIABLE_LOOKUP:
+ *
+ * Registering macro, not general purpose at all but used in different modules.
+ */
+
+#define XSLT_REGISTER_VARIABLE_LOOKUP(ctxt)			\
+    xmlXPathRegisterVariableLookup((ctxt)->xpathCtxt,		\
+	       xsltXPathVariableLookup,	(void *)(ctxt));	\
+    xsltRegisterAllFunctions((ctxt)->xpathCtxt);		\
+    xsltRegisterAllElement(ctxt);				\
+    (ctxt)->xpathCtxt->extra = ctxt
+
+/*
+ * Interfaces for the variable module.
+ */
+
+XSLTPUBFUN int XSLTCALL		
+		xsltEvalGlobalVariables		(xsltTransformContextPtr ctxt);
+XSLTPUBFUN int XSLTCALL		
+		xsltEvalUserParams		(xsltTransformContextPtr ctxt,
+						 const char **params);
+XSLTPUBFUN int XSLTCALL		
+    		xsltQuoteUserParams		(xsltTransformContextPtr ctxt,
+						 const char **params);
+XSLTPUBFUN int XSLTCALL		
+		xsltEvalOneUserParam		(xsltTransformContextPtr ctxt,
+    						 const xmlChar * name,
+						 const xmlChar * value);
+XSLTPUBFUN int XSLTCALL		
+    		xsltQuoteOneUserParam		(xsltTransformContextPtr ctxt,
+    						 const xmlChar * name,
+						 const xmlChar * value);
+
+XSLTPUBFUN void XSLTCALL		
+    		xsltParseGlobalVariable		(xsltStylesheetPtr style,
+						 xmlNodePtr cur);
+XSLTPUBFUN void XSLTCALL		
+    		xsltParseGlobalParam		(xsltStylesheetPtr style,
+						 xmlNodePtr cur);
+XSLTPUBFUN void XSLTCALL		
+    		xsltParseStylesheetVariable	(xsltTransformContextPtr ctxt,
+						 xmlNodePtr cur);
+XSLTPUBFUN void XSLTCALL		
+    		xsltParseStylesheetParam	(xsltTransformContextPtr ctxt,
+						 xmlNodePtr cur);
+XSLTPUBFUN xsltStackElemPtr XSLTCALL 
+		xsltParseStylesheetCallerParam	(xsltTransformContextPtr ctxt,
+						 xmlNodePtr cur);
+XSLTPUBFUN int XSLTCALL		
+    		xsltAddStackElemList		(xsltTransformContextPtr ctxt,
+						 xsltStackElemPtr elems);
+XSLTPUBFUN void XSLTCALL		
+    		xsltFreeGlobalVariables		(xsltTransformContextPtr ctxt);
+XSLTPUBFUN xmlXPathObjectPtr XSLTCALL	
+		xsltVariableLookup		(xsltTransformContextPtr ctxt,
+						 const xmlChar *name,
+						 const xmlChar *ns_uri);
+XSLTPUBFUN xmlXPathObjectPtr XSLTCALL	
+		xsltXPathVariableLookup		(void *ctxt,
+						 const xmlChar *name,
+						 const xmlChar *ns_uri);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_VARIABLES_H__ */
+
diff --git a/libxslt/xslt.c b/libxslt/xslt.c
new file mode 100644
index 0000000..55f505b
--- /dev/null
+++ b/libxslt/xslt.c
@@ -0,0 +1,6997 @@
+/*
+ * xslt.c: Implemetation of an XSL Transformation 1.0 engine
+ *
+ * Reference:
+ *   XSLT specification
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ *   Associating Style Sheets with XML documents
+ *   http://www.w3.org/1999/06/REC-xml-stylesheet-19990629
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+#include <libxml/hash.h>
+#include <libxml/uri.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parserInternals.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/xpath.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "pattern.h"
+#include "variables.h"
+#include "namespaces.h"
+#include "attributes.h"
+#include "xsltutils.h"
+#include "imports.h"
+#include "keys.h"
+#include "documents.h"
+#include "extensions.h"
+#include "preproc.h"
+#include "extra.h"
+#include "security.h"
+
+#ifdef WITH_XSLT_DEBUG
+#define WITH_XSLT_DEBUG_PARSING
+/* #define WITH_XSLT_DEBUG_BLANKS */
+#endif
+
+const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA;
+const int xsltLibxsltVersion = LIBXSLT_VERSION;
+const int xsltLibxmlVersion = LIBXML_VERSION;
+
+#ifdef XSLT_REFACTORED
+
+const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE;
+
+#define XSLT_ELEMENT_CATEGORY_XSLT 0
+#define XSLT_ELEMENT_CATEGORY_EXTENSION 1
+#define XSLT_ELEMENT_CATEGORY_LRE 2
+
+/*
+* xsltLiteralResultMarker:
+* Marker for Literal result elements, in order to avoid multiple attempts
+* to recognize such elements in the stylesheet's tree.
+* This marker is set on node->psvi during the initial traversal
+* of a stylesheet's node tree.
+*
+const xmlChar *xsltLiteralResultMarker =
+    (const xmlChar *) "Literal Result Element";
+*/
+
+/*
+* xsltXSLTTextMarker:
+* Marker for xsl:text elements. Used to recognize xsl:text elements
+* for post-processing of the stylesheet's tree, where those
+* elements are removed from the tree.
+*/
+const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
+
+/*
+* xsltXSLTAttrMarker:
+* Marker for XSLT attribute on Literal Result Elements.
+*/
+const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
+
+#endif
+
+#ifdef XSLT_LOCALE_WINAPI
+extern xmlRMutexPtr xsltLocaleMutex;
+#endif
+/*
+ * Harmless but avoiding a problem when compiling against a
+ * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
+ */
+#ifndef LIBXML_DEBUG_ENABLED
+double xmlXPathStringEvalNumber(const xmlChar *str);
+#endif
+/*
+ * Useful macros
+ */
+
+#ifdef  IS_BLANK
+#undef	IS_BLANK
+#endif
+#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||	\
+                     ((c) == 0x0D))
+
+#ifdef	IS_BLANK_NODE
+#undef	IS_BLANK_NODE
+#endif
+#define IS_BLANK_NODE(n)						\
+    (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
+
+/**
+ * xsltParseContentError:
+ *
+ * @style: the stylesheet
+ * @node: the node where the error occured
+ *
+ * Compile-time error function.
+ */
+static void
+xsltParseContentError(xsltStylesheetPtr style,
+		       xmlNodePtr node)
+{
+    if ((style == NULL) || (node == NULL))
+	return;
+
+    if (IS_XSLT_ELEM(node))
+	xsltTransformError(NULL, style, node,
+	    "The XSLT-element '%s' is not allowed at this position.\n",
+	    node->name);
+    else
+	xsltTransformError(NULL, style, node,
+	    "The element '%s' is not allowed at this position.\n",
+	    node->name);
+    style->errors++;
+}
+
+#ifdef XSLT_REFACTORED
+#else
+/**
+ * exclPrefixPush:
+ * @style: the transformation stylesheet
+ * @value:  the excluded namespace name to push on the stack
+ *
+ * Push an excluded namespace name on the stack
+ *
+ * Returns the new index in the stack or -1 if already present or
+ * in case of error
+ */
+static int
+exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)
+{
+    int i;
+
+    if (style->exclPrefixMax == 0) {
+        style->exclPrefixMax = 4;
+        style->exclPrefixTab =
+            (xmlChar * *)xmlMalloc(style->exclPrefixMax *
+                                   sizeof(style->exclPrefixTab[0]));
+        if (style->exclPrefixTab == NULL) {
+            xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
+            return (-1);
+        }
+    }
+    /* do not push duplicates */
+    for (i = 0;i < style->exclPrefixNr;i++) {
+        if (xmlStrEqual(style->exclPrefixTab[i], value))
+	    return(-1);
+    }
+    if (style->exclPrefixNr >= style->exclPrefixMax) {
+        style->exclPrefixMax *= 2;
+        style->exclPrefixTab =
+            (xmlChar * *)xmlRealloc(style->exclPrefixTab,
+                                    style->exclPrefixMax *
+                                    sizeof(style->exclPrefixTab[0]));
+        if (style->exclPrefixTab == NULL) {
+            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
+            return (-1);
+        }
+    }
+    style->exclPrefixTab[style->exclPrefixNr] = value;
+    style->exclPrefix = value;
+    return (style->exclPrefixNr++);
+}
+/**
+ * exclPrefixPop:
+ * @style: the transformation stylesheet
+ *
+ * Pop an excluded prefix value from the stack
+ *
+ * Returns the stored excluded prefix value
+ */
+static xmlChar *
+exclPrefixPop(xsltStylesheetPtr style)
+{
+    xmlChar *ret;
+
+    if (style->exclPrefixNr <= 0)
+        return (0);
+    style->exclPrefixNr--;
+    if (style->exclPrefixNr > 0)
+        style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
+    else
+        style->exclPrefix = NULL;
+    ret = style->exclPrefixTab[style->exclPrefixNr];
+    style->exclPrefixTab[style->exclPrefixNr] = 0;
+    return (ret);
+}
+#endif
+
+/************************************************************************
+ *									*
+ *			Helper functions				*
+ *									*
+ ************************************************************************/
+
+static int initialized = 0;
+/**
+ * xsltInit:
+ *
+ * Initializes the processor (e.g. registers built-in extensions,
+ * etc.)
+ */
+void
+xsltInit (void) {
+    if (initialized == 0) {
+	initialized = 1;
+#ifdef XSLT_LOCALE_WINAPI
+	xsltLocaleMutex = xmlNewRMutex();
+#endif
+        xsltRegisterAllExtras();
+    }
+}
+
+/**
+ * xsltUninit:
+ *
+ * Uninitializes the processor.
+ */
+void
+xsltUninit (void) {
+    initialized = 0;
+}
+
+/**
+ * xsltIsBlank:
+ * @str:  a string
+ *
+ * Check if a string is ignorable
+ *
+ * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
+ */
+int
+xsltIsBlank(xmlChar *str) {
+    if (str == NULL)
+	return(1);
+    while (*str != 0) {
+	if (!(IS_BLANK(*str))) return(0);
+	str++;
+    }
+    return(1);
+}
+
+/************************************************************************
+ *									*
+ *		Routines to handle XSLT data structures			*
+ *									*
+ ************************************************************************/
+static xsltDecimalFormatPtr
+xsltNewDecimalFormat(xmlChar *name)
+{
+    xsltDecimalFormatPtr self;
+    /* UTF-8 for 0x2030 */
+    static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};
+
+    self = xmlMalloc(sizeof(xsltDecimalFormat));
+    if (self != NULL) {
+	self->next = NULL;
+	self->name = name;
+	
+	/* Default values */
+	self->digit = xmlStrdup(BAD_CAST("#"));
+	self->patternSeparator = xmlStrdup(BAD_CAST(";"));
+	self->decimalPoint = xmlStrdup(BAD_CAST("."));
+	self->grouping = xmlStrdup(BAD_CAST(","));
+	self->percent = xmlStrdup(BAD_CAST("%"));
+	self->permille = xmlStrdup(BAD_CAST(permille));
+	self->zeroDigit = xmlStrdup(BAD_CAST("0"));
+	self->minusSign = xmlStrdup(BAD_CAST("-"));
+	self->infinity = xmlStrdup(BAD_CAST("Infinity"));
+	self->noNumber = xmlStrdup(BAD_CAST("NaN"));
+    }
+    return self;
+}
+
+static void
+xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
+{
+    if (self != NULL) {
+	if (self->digit)
+	    xmlFree(self->digit);
+	if (self->patternSeparator)
+	    xmlFree(self->patternSeparator);
+	if (self->decimalPoint)
+	    xmlFree(self->decimalPoint);
+	if (self->grouping)
+	    xmlFree(self->grouping);
+	if (self->percent)
+	    xmlFree(self->percent);
+	if (self->permille)
+	    xmlFree(self->permille);
+	if (self->zeroDigit)
+	    xmlFree(self->zeroDigit);
+	if (self->minusSign)
+	    xmlFree(self->minusSign);
+	if (self->infinity)
+	    xmlFree(self->infinity);
+	if (self->noNumber)
+	    xmlFree(self->noNumber);
+	if (self->name)
+	    xmlFree(self->name);
+	xmlFree(self);
+    }
+}
+
+static void
+xsltFreeDecimalFormatList(xsltStylesheetPtr self)
+{
+    xsltDecimalFormatPtr iter;
+    xsltDecimalFormatPtr tmp;
+
+    if (self == NULL)
+	return;
+    
+    iter = self->decimalFormat;
+    while (iter != NULL) {
+	tmp = iter->next;
+	xsltFreeDecimalFormat(iter);
+	iter = tmp;
+    }
+}
+
+/**
+ * xsltDecimalFormatGetByName:
+ * @style: the XSLT stylesheet
+ * @name: the decimal-format name to find
+ *
+ * Find decimal-format by name
+ *
+ * Returns the xsltDecimalFormatPtr
+ */
+xsltDecimalFormatPtr
+xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
+{
+    xsltDecimalFormatPtr result = NULL;
+
+    if (name == NULL)
+	return style->decimalFormat;
+
+    while (style != NULL) {
+	for (result = style->decimalFormat->next;
+	     result != NULL;
+	     result = result->next) {
+	    if (xmlStrEqual(name, result->name))
+		return result;
+	}
+	style = xsltNextImport(style);
+    }
+    return result;
+}
+
+
+/**
+ * xsltNewTemplate:
+ *
+ * Create a new XSLT Template
+ *
+ * Returns the newly allocated xsltTemplatePtr or NULL in case of error
+ */
+static xsltTemplatePtr
+xsltNewTemplate(void) {
+    xsltTemplatePtr cur;
+
+    cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
+    if (cur == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+		"xsltNewTemplate : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltTemplate));
+    cur->priority = XSLT_PAT_NO_PRIORITY;
+    return(cur);
+}
+
+/**
+ * xsltFreeTemplate:
+ * @template:  an XSLT template
+ *
+ * Free up the memory allocated by @template
+ */
+static void
+xsltFreeTemplate(xsltTemplatePtr template) {
+    if (template == NULL)
+	return;
+    if (template->match) xmlFree(template->match);
+/*
+*   NOTE: @name and @nameURI are put into the string dict now.
+*   if (template->name) xmlFree(template->name);
+*   if (template->nameURI) xmlFree(template->nameURI);
+*/
+/*
+    if (template->mode) xmlFree(template->mode);
+    if (template->modeURI) xmlFree(template->modeURI);
+ */
+    if (template->inheritedNs) xmlFree(template->inheritedNs);
+    memset(template, -1, sizeof(xsltTemplate));
+    xmlFree(template);
+}
+
+/**
+ * xsltFreeTemplateList:
+ * @template:  an XSLT template list
+ *
+ * Free up the memory allocated by all the elements of @template
+ */
+static void
+xsltFreeTemplateList(xsltTemplatePtr template) {
+    xsltTemplatePtr cur;
+
+    while (template != NULL) {
+	cur = template;
+	template = template->next;
+	xsltFreeTemplate(cur);
+    }
+}
+
+#ifdef XSLT_REFACTORED
+
+static void
+xsltFreeNsAliasList(xsltNsAliasPtr item)
+{
+    xsltNsAliasPtr tmp;
+    
+    while (item) {
+	tmp = item;
+	item = item->next;
+	xmlFree(tmp);
+    } 
+    return;
+}
+
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+static void
+xsltFreeNamespaceMap(xsltNsMapPtr item)
+{
+    xsltNsMapPtr tmp;
+    
+    while (item) {
+	tmp = item;
+	item = item->next;
+	xmlFree(tmp);
+    } 
+    return;
+}
+
+static xsltNsMapPtr
+xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
+			xmlDocPtr doc,
+			xmlNsPtr ns,
+			xmlNodePtr elem)
+{
+    xsltNsMapPtr ret;
+
+    if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
+	return(NULL);
+
+    ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
+    if (ret == NULL) {
+	xsltTransformError(NULL, cctxt->style, elem,
+	    "Internal error: (xsltNewNamespaceMapItem) "
+	    "memory allocation failed.\n");
+	return(NULL);
+    }
+    memset(ret, 0, sizeof(xsltNsMap));
+    ret->doc = doc;
+    ret->ns = ns;
+    ret->origNsName = ns->href;
+    /*
+    * Store the item at current stylesheet-level.
+    */
+    if (cctxt->psData->nsMap != NULL)
+	ret->next = cctxt->psData->nsMap;
+    cctxt->psData->nsMap = ret;
+
+    return(ret);
+}
+#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
+
+/**
+ * xsltCompilerVarInfoFree: 
+ * @cctxt: the compilation context
+ * 
+ * Frees the list of information for vars/params.
+ */
+static void
+xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)
+{
+    xsltVarInfoPtr ivar = cctxt->ivars, ivartmp;    
+
+    while (ivar) {
+	ivartmp = ivar;
+	ivar = ivar->next;
+	xmlFree(ivartmp);
+    }
+}
+
+/**
+ * xsltCompilerCtxtFree:
+ *
+ * Free an XSLT compiler context. 
+ */
+static void
+xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
+{    
+    if (cctxt == NULL)
+	return;
+#ifdef WITH_XSLT_DEBUG_PARSING
+    xsltGenericDebug(xsltGenericDebugContext,
+	"Freeing compilation context\n");
+    xsltGenericDebug(xsltGenericDebugContext,
+	"### Max inodes: %d\n", cctxt->maxNodeInfos);
+    xsltGenericDebug(xsltGenericDebugContext,
+	"### Max LREs  : %d\n", cctxt->maxLREs);
+#endif
+    /*
+    * Free node-infos.
+    */
+    if (cctxt->inodeList != NULL) {
+	xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
+	while (cur != NULL) {
+	    tmp = cur;
+	    cur = cur->next;
+	    xmlFree(tmp);
+	}
+    }
+    if (cctxt->tmpList != NULL)
+	xsltPointerListFree(cctxt->tmpList);
+#ifdef XSLT_REFACTORED_XPATHCOMP
+    if (cctxt->xpathCtxt != NULL)
+	xmlXPathFreeContext(cctxt->xpathCtxt);
+#endif
+    if (cctxt->nsAliases != NULL)
+	xsltFreeNsAliasList(cctxt->nsAliases);
+
+    if (cctxt->ivars)
+	xsltCompilerVarInfoFree(cctxt);
+
+    xmlFree(cctxt);
+}
+
+/**
+ * xsltCompilerCreate:
+ *
+ * Creates an XSLT compiler context.
+ *
+ * Returns the pointer to the created xsltCompilerCtxt or
+ *         NULL in case of an internal error.
+ */
+static xsltCompilerCtxtPtr
+xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
+    xsltCompilerCtxtPtr ret;
+
+    ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
+    if (ret == NULL) {
+	xsltTransformError(NULL, style, NULL,
+	    "xsltCompilerCreate: allocation of compiler "
+	    "context failed.\n");
+	return(NULL);
+    }
+    memset(ret, 0, sizeof(xsltCompilerCtxt));
+
+    ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
+    ret->tmpList = xsltPointerListCreate(20);
+    if (ret->tmpList == NULL) {
+	goto internal_err;
+    }
+#ifdef XSLT_REFACTORED_XPATHCOMP
+    /*
+    * Create the XPath compilation context in order
+    * to speed up precompilation of XPath expressions.
+    */
+    ret->xpathCtxt = xmlXPathNewContext(NULL);
+    if (ret->xpathCtxt == NULL)
+	goto internal_err;
+#endif
+    
+    return(ret);
+
+internal_err:
+    xsltCompilationCtxtFree(ret);
+    return(NULL);
+}
+
+static void
+xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
+{
+    xsltEffectiveNsPtr tmp;
+
+    while (first != NULL) {
+	tmp = first;
+	first = first->nextInStore;
+	xmlFree(tmp);
+    }
+}
+
+static void
+xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
+{
+    if (data == NULL)
+	return;
+
+    if (data->inScopeNamespaces != NULL) {
+	int i;
+	xsltNsListContainerPtr nsi;
+	xsltPointerListPtr list =
+	    (xsltPointerListPtr) data->inScopeNamespaces;
+
+	for (i = 0; i < list->number; i++) {
+	    /*
+	    * REVISIT TODO: Free info of in-scope namespaces.
+	    */
+	    nsi = (xsltNsListContainerPtr) list->items[i];
+	    if (nsi->list != NULL)
+		xmlFree(nsi->list);
+	    xmlFree(nsi);
+	}
+	xsltPointerListFree(list);
+	data->inScopeNamespaces = NULL;
+    }
+
+    if (data->exclResultNamespaces != NULL) {
+	int i;
+	xsltPointerListPtr list = (xsltPointerListPtr)
+	    data->exclResultNamespaces;	
+	
+	for (i = 0; i < list->number; i++)
+	    xsltPointerListFree((xsltPointerListPtr) list->items[i]);
+	
+	xsltPointerListFree(list);
+	data->exclResultNamespaces = NULL;
+    }
+
+    if (data->extElemNamespaces != NULL) {
+	xsltPointerListPtr list = (xsltPointerListPtr)
+	    data->extElemNamespaces;
+	int i;
+
+	for (i = 0; i < list->number; i++)
+	    xsltPointerListFree((xsltPointerListPtr) list->items[i]);
+
+	xsltPointerListFree(list);
+	data->extElemNamespaces = NULL;
+    }
+    if (data->effectiveNs) {
+	xsltLREEffectiveNsNodesFree(data->effectiveNs);
+	data->effectiveNs = NULL;
+    }
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+    xsltFreeNamespaceMap(data->nsMap);
+#endif
+    xmlFree(data);
+}
+
+static xsltPrincipalStylesheetDataPtr
+xsltNewPrincipalStylesheetData(void)
+{
+    xsltPrincipalStylesheetDataPtr ret;
+
+    ret = (xsltPrincipalStylesheetDataPtr)
+	xmlMalloc(sizeof(xsltPrincipalStylesheetData));
+    if (ret == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+	    "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
+	return(NULL);
+    }
+    memset(ret, 0, sizeof(xsltPrincipalStylesheetData));
+    
+    /*
+    * Global list of in-scope namespaces.
+    */    
+    ret->inScopeNamespaces = xsltPointerListCreate(-1);
+    if (ret->inScopeNamespaces == NULL)
+	goto internal_err;
+    /*
+    * Global list of excluded result ns-decls.
+    */
+    ret->exclResultNamespaces = xsltPointerListCreate(-1);
+    if (ret->exclResultNamespaces == NULL)
+	goto internal_err;
+    /*
+    * Global list of extension instruction namespace names.
+    */    
+    ret->extElemNamespaces = xsltPointerListCreate(-1);
+    if (ret->extElemNamespaces == NULL)
+	goto internal_err;
+
+    return(ret);
+
+internal_err:
+
+    return(NULL);
+}
+
+#endif
+
+/**
+ * xsltNewStylesheet:
+ *
+ * Create a new XSLT Stylesheet
+ *
+ * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
+ */
+xsltStylesheetPtr
+xsltNewStylesheet(void) {
+    xsltStylesheetPtr ret = NULL;    
+
+    ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
+    if (ret == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+		"xsltNewStylesheet : malloc failed\n");
+	goto internal_err;
+    }
+    memset(ret, 0, sizeof(xsltStylesheet));
+
+    ret->omitXmlDeclaration = -1;
+    ret->standalone = -1;
+    ret->decimalFormat = xsltNewDecimalFormat(NULL);
+    ret->indent = -1;
+    ret->errors = 0;
+    ret->warnings = 0;
+    ret->exclPrefixNr = 0;
+    ret->exclPrefixMax = 0;
+    ret->exclPrefixTab = NULL;
+    ret->extInfos = NULL;
+    ret->extrasNr = 0;
+    ret->internalized = 1;
+    ret->literal_result = 0;
+    ret->dict = xmlDictCreate();
+#ifdef WITH_XSLT_DEBUG
+    xsltGenericDebug(xsltGenericDebugContext,
+	"creating dictionary for stylesheet\n");
+#endif
+
+    xsltInit();
+
+    return(ret);
+
+internal_err:
+    if (ret != NULL)
+	xsltFreeStylesheet(ret);
+    return(NULL);
+}
+
+/**
+ * xsltAllocateExtra:
+ * @style:  an XSLT stylesheet
+ *
+ * Allocate an extra runtime information slot statically while compiling
+ * the stylesheet and return its number
+ *
+ * Returns the number of the slot
+ */
+int
+xsltAllocateExtra(xsltStylesheetPtr style)
+{
+    return(style->extrasNr++);
+}
+
+/**
+ * xsltAllocateExtraCtxt:
+ * @ctxt:  an XSLT transformation context
+ *
+ * Allocate an extra runtime information slot at run-time
+ * and return its number
+ * This make sure there is a slot ready in the transformation context
+ *
+ * Returns the number of the slot
+ */
+int
+xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
+{
+    if (ctxt->extrasNr >= ctxt->extrasMax) {
+	int i;
+	if (ctxt->extrasNr == 0) {
+	    ctxt->extrasMax = 20;
+	    ctxt->extras = (xsltRuntimeExtraPtr)
+		xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
+	    if (ctxt->extras == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"xsltAllocateExtraCtxt: out of memory\n");
+		ctxt->state = XSLT_STATE_ERROR;
+		return(0);
+	    }
+	    for (i = 0;i < ctxt->extrasMax;i++) {
+		ctxt->extras[i].info = NULL;
+		ctxt->extras[i].deallocate = NULL;
+		ctxt->extras[i].val.ptr = NULL;
+	    }
+
+	} else {
+	    xsltRuntimeExtraPtr tmp;
+
+	    ctxt->extrasMax += 100;
+	    tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
+		            ctxt->extrasMax * sizeof(xsltRuntimeExtra));
+	    if (tmp == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"xsltAllocateExtraCtxt: out of memory\n");
+		ctxt->state = XSLT_STATE_ERROR;
+		return(0);
+	    }
+	    ctxt->extras = tmp;
+	    for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
+		ctxt->extras[i].info = NULL;
+		ctxt->extras[i].deallocate = NULL;
+		ctxt->extras[i].val.ptr = NULL;
+	    }
+	}
+    }
+    return(ctxt->extrasNr++);
+}
+
+/**
+ * xsltFreeStylesheetList:
+ * @style:  an XSLT stylesheet list
+ *
+ * Free up the memory allocated by the list @style
+ */
+static void
+xsltFreeStylesheetList(xsltStylesheetPtr style) {
+    xsltStylesheetPtr next;
+
+    while (style != NULL) {
+	next = style->next;
+	xsltFreeStylesheet(style);
+	style = next;
+    }
+}
+
+/**
+ * xsltCleanupStylesheetTree:
+ *
+ * @doc: the document-node
+ * @node: the element where the stylesheet is rooted at
+ *
+ * Actually @node need not be the document-element, but
+ * currently Libxslt does not support embedded stylesheets.
+ *
+ * Returns 0 if OK, -1 on API or internal errors.
+ */
+static int
+xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED,
+			  xmlNodePtr rootElem ATTRIBUTE_UNUSED)
+{    
+#if 0 /* TODO: Currently disabled, since probably not needed. */
+    xmlNodePtr cur;
+
+    if ((doc == NULL) || (rootElem == NULL) ||
+	(rootElem->type != XML_ELEMENT_NODE) ||
+	(doc != rootElem->doc))
+	return(-1);
+
+    /*
+    * Cleanup was suggested by Aleksey Sanin:
+    * Clear the PSVI field to avoid problems if the
+    * node-tree of the stylesheet is intended to be used for
+    * further processing by the user (e.g. for compiling it
+    * once again - although not recommended).
+    */
+
+    cur = rootElem;
+    while (cur != NULL) {
+	if (cur->type == XML_ELEMENT_NODE) {
+	    /*
+	    * Clear the PSVI field.
+	    */
+	    cur->psvi = NULL;
+	    if (cur->children) {
+		cur = cur->children;
+		continue;
+	    }
+	}
+
+leave_node:
+	if (cur == rootElem)
+	    break;
+	if (cur->next != NULL)
+	    cur = cur->next;
+	else {
+	    cur = cur->parent;
+	    if (cur == NULL)
+		break;
+	    goto leave_node;
+	}
+    }
+#endif /* #if 0 */
+    return(0);
+}
+
+/**
+ * xsltFreeStylesheet:
+ * @style:  an XSLT stylesheet
+ *
+ * Free up the memory allocated by @style
+ */
+void
+xsltFreeStylesheet(xsltStylesheetPtr style)
+{
+    if (style == NULL)
+        return;
+    
+#ifdef XSLT_REFACTORED
+    /*
+    * Start with a cleanup of the main stylesheet's doc.
+    */
+    if ((style->principal == style) && (style->doc))
+	xsltCleanupStylesheetTree(style->doc,
+	    xmlDocGetRootElement(style->doc));
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+    /*
+    * Restore changed ns-decls before freeing the document.
+    */
+    if ((style->doc != NULL) &&
+	XSLT_HAS_INTERNAL_NSMAP(style))
+    {
+	xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
+	    style->doc);	
+    }
+#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
+#else
+    /*
+    * Start with a cleanup of the main stylesheet's doc.
+    */
+    if ((style->parent == NULL) && (style->doc))
+	xsltCleanupStylesheetTree(style->doc,
+	    xmlDocGetRootElement(style->doc));
+#endif /* XSLT_REFACTORED */
+
+    xsltFreeKeys(style);
+    xsltFreeExts(style);
+    xsltFreeTemplateHashes(style);
+    xsltFreeDecimalFormatList(style);
+    xsltFreeTemplateList(style->templates);
+    xsltFreeAttributeSetsHashes(style);
+    xsltFreeNamespaceAliasHashes(style);
+    xsltFreeStylePreComps(style);
+    /*
+    * Free documents of all included stylsheet modules of this
+    * stylesheet level.
+    */
+    xsltFreeStyleDocuments(style);
+    /*
+    * TODO: Best time to shutdown extension stuff?
+    */
+    xsltShutdownExts(style);
+       
+    if (style->variables != NULL)
+        xsltFreeStackElemList(style->variables);
+    if (style->cdataSection != NULL)
+        xmlHashFree(style->cdataSection, NULL);
+    if (style->stripSpaces != NULL)
+        xmlHashFree(style->stripSpaces, NULL);
+    if (style->nsHash != NULL)
+        xmlHashFree(style->nsHash, NULL);
+    if (style->exclPrefixTab != NULL)
+        xmlFree(style->exclPrefixTab);
+    if (style->method != NULL)
+        xmlFree(style->method);
+    if (style->methodURI != NULL)
+        xmlFree(style->methodURI);
+    if (style->version != NULL)
+        xmlFree(style->version);
+    if (style->encoding != NULL)
+        xmlFree(style->encoding);
+    if (style->doctypePublic != NULL)
+        xmlFree(style->doctypePublic);
+    if (style->doctypeSystem != NULL)
+        xmlFree(style->doctypeSystem);
+    if (style->mediaType != NULL)
+        xmlFree(style->mediaType);
+    if (style->attVTs)
+        xsltFreeAVTList(style->attVTs);
+    if (style->imports != NULL)
+        xsltFreeStylesheetList(style->imports);
+
+#ifdef XSLT_REFACTORED
+    /*
+    * If this is the principal stylesheet, then
+    * free its internal data.
+    */
+    if (style->principal == style) {
+	if (style->principalData) {
+	    xsltFreePrincipalStylesheetData(style->principalData);
+	    style->principalData = NULL;
+	}
+    }    
+#endif
+    /*
+    * Better to free the main document of this stylesheet level
+    * at the end - so here.
+    */
+    if (style->doc != NULL) {	
+        xmlFreeDoc(style->doc);
+    }
+
+#ifdef WITH_XSLT_DEBUG
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "freeing dictionary from stylesheet\n");
+#endif
+    xmlDictFree(style->dict);
+
+    memset(style, -1, sizeof(xsltStylesheet));
+    xmlFree(style);
+}
+
+/************************************************************************
+ *									*
+ *		Parsing of an XSLT Stylesheet				*
+ *									*
+ ************************************************************************/
+
+#ifdef XSLT_REFACTORED
+    /*
+    * This is now performed in an optimized way in xsltParseXSLTTemplate.
+    */
+#else
+/**
+ * xsltGetInheritedNsList:
+ * @style:  the stylesheet
+ * @template: the template
+ * @node:  the current node
+ *
+ * Search all the namespace applying to a given element except the ones 
+ * from excluded output prefixes currently in scope. Initialize the
+ * template inheritedNs list with it.
+ *
+ * Returns the number of entries found
+ */
+static int
+xsltGetInheritedNsList(xsltStylesheetPtr style,
+	               xsltTemplatePtr template,
+	               xmlNodePtr node)
+{
+    xmlNsPtr cur;
+    xmlNsPtr *ret = NULL;
+    int nbns = 0;
+    int maxns = 10;
+    int i;    
+
+    if ((style == NULL) || (template == NULL) || (node == NULL) ||
+	(template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
+	return(0);
+    while (node != NULL) {
+        if (node->type == XML_ELEMENT_NODE) {
+            cur = node->nsDef;
+            while (cur != NULL) {
+		if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
+		    goto skip_ns;
+
+		if ((cur->prefix != NULL) &&
+		    (xsltCheckExtPrefix(style, cur->prefix)))
+		    goto skip_ns;
+		/*
+		* Check if this namespace was excluded.
+		* Note that at this point only the exclusions defined
+		* on the topmost stylesheet element are in the exclusion-list.
+		*/
+		for (i = 0;i < style->exclPrefixNr;i++) {
+		    if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
+			goto skip_ns;
+		}
+                if (ret == NULL) {
+                    ret =
+                        (xmlNsPtr *) xmlMalloc((maxns + 1) *
+                                               sizeof(xmlNsPtr));
+                    if (ret == NULL) {
+                        xmlGenericError(xmlGenericErrorContext,
+                                        "xsltGetInheritedNsList : out of memory!\n");
+                        return(0);
+                    }
+                    ret[nbns] = NULL;
+                }
+		/*
+		* Skip shadowed namespace bindings.
+		*/
+                for (i = 0; i < nbns; i++) {
+                    if ((cur->prefix == ret[i]->prefix) ||
+                        (xmlStrEqual(cur->prefix, ret[i]->prefix)))
+                        break;
+                }
+                if (i >= nbns) {
+                    if (nbns >= maxns) {
+                        maxns *= 2;
+                        ret = (xmlNsPtr *) xmlRealloc(ret,
+                                                      (maxns +
+                                                       1) *
+                                                      sizeof(xmlNsPtr));
+                        if (ret == NULL) {
+                            xmlGenericError(xmlGenericErrorContext,
+                                            "xsltGetInheritedNsList : realloc failed!\n");
+                            return(0);
+                        }
+                    }
+                    ret[nbns++] = cur;
+                    ret[nbns] = NULL;
+                }
+skip_ns:
+                cur = cur->next;
+            }
+        }
+        node = node->parent;
+    }
+    if (nbns != 0) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+        xsltGenericDebug(xsltGenericDebugContext,
+                         "template has %d inherited namespaces\n", nbns);
+#endif
+	template->inheritedNsNr = nbns;
+	template->inheritedNs = ret;
+    }
+    return (nbns);
+}
+#endif /* else of XSLT_REFACTORED */
+
+/**
+ * xsltParseStylesheetOutput:
+ * @style:  the XSLT stylesheet
+ * @cur:  the "output" element
+ *
+ * parse an XSLT stylesheet output element and record
+ * information related to the stylesheet output
+ */
+
+void
+xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
+{
+    xmlChar *elements,
+     *prop;
+    xmlChar *element,
+     *end;
+
+    if ((cur == NULL) || (style == NULL))
+        return;
+   
+    prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
+    if (prop != NULL) {
+        if (style->version != NULL)
+            xmlFree(style->version);
+        style->version = prop;
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
+    if (prop != NULL) {
+        if (style->encoding != NULL)
+            xmlFree(style->encoding);
+        style->encoding = prop;
+    }
+
+    /* relaxed to support xt:document
+    * TODO KB: What does "relaxed to support xt:document" mean?
+    */
+    prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL);
+    if (prop != NULL) {
+        const xmlChar *URI;
+
+        if (style->method != NULL)
+            xmlFree(style->method);
+        style->method = NULL;
+        if (style->methodURI != NULL)
+            xmlFree(style->methodURI);
+        style->methodURI = NULL;
+
+	/*
+	* TODO: Don't use xsltGetQNameURI().
+	*/
+	URI = xsltGetQNameURI(cur, &prop);
+	if (prop == NULL) {
+	    if (style != NULL) style->errors++;
+	} else if (URI == NULL) {
+            if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
+                (xmlStrEqual(prop, (const xmlChar *) "html")) ||
+                (xmlStrEqual(prop, (const xmlChar *) "text"))) {
+                style->method = prop;
+            } else {
+		xsltTransformError(NULL, style, cur,
+                                 "invalid value for method: %s\n", prop);
+                if (style != NULL) style->warnings++;
+            }
+	} else {
+	    style->method = prop;
+	    style->methodURI = xmlStrdup(URI);
+	}
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
+    if (prop != NULL) {
+        if (style->doctypeSystem != NULL)
+            xmlFree(style->doctypeSystem);
+        style->doctypeSystem = prop;
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
+    if (prop != NULL) {
+        if (style->doctypePublic != NULL)
+            xmlFree(style->doctypePublic);
+        style->doctypePublic = prop;
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL);
+    if (prop != NULL) {
+        if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
+            style->standalone = 1;
+        } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
+            style->standalone = 0;
+        } else {
+	    xsltTransformError(NULL, style, cur,
+                             "invalid value for standalone: %s\n", prop);
+            style->errors++;
+        }
+        xmlFree(prop);
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL);
+    if (prop != NULL) {
+        if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
+            style->indent = 1;
+        } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
+            style->indent = 0;
+        } else {
+	    xsltTransformError(NULL, style, cur,
+                             "invalid value for indent: %s\n", prop);
+            style->errors++;
+        }
+        xmlFree(prop);
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL);
+    if (prop != NULL) {
+        if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
+            style->omitXmlDeclaration = 1;
+        } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
+            style->omitXmlDeclaration = 0;
+        } else {
+	    xsltTransformError(NULL, style, cur,
+                             "invalid value for omit-xml-declaration: %s\n",
+                             prop);
+            style->errors++;
+        }
+        xmlFree(prop);
+    }
+
+    elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
+	NULL);
+    if (elements != NULL) {
+        if (style->cdataSection == NULL)
+            style->cdataSection = xmlHashCreate(10);
+        if (style->cdataSection == NULL)
+            return;
+
+        element = elements;
+        while (*element != 0) {
+            while (IS_BLANK(*element))
+                element++;
+            if (*element == 0)
+                break;
+            end = element;
+            while ((*end != 0) && (!IS_BLANK(*end)))
+                end++;
+            element = xmlStrndup(element, end - element);
+            if (element) {		
+#ifdef WITH_XSLT_DEBUG_PARSING
+                xsltGenericDebug(xsltGenericDebugContext,
+                                 "add cdata section output element %s\n",
+                                 element);
+#endif
+		if (xmlValidateQName(BAD_CAST element, 0) != 0) {
+		    xsltTransformError(NULL, style, cur,
+			"Attribute 'cdata-section-elements': The value "
+			"'%s' is not a valid QName.\n", element);
+		    xmlFree(element);
+		    style->errors++;
+		} else {
+		    const xmlChar *URI;
+
+		    /*
+		    * TODO: Don't use xsltGetQNameURI().
+		    */
+		    URI = xsltGetQNameURI(cur, &element);
+		    if (element == NULL) {
+			/*
+			* TODO: We'll report additionally an error
+			*  via the stylesheet's error handling.			
+			*/
+			xsltTransformError(NULL, style, cur,
+			    "Attribute 'cdata-section-elements': The value "
+			    "'%s' is not a valid QName.\n", element);
+			style->errors++;
+		    } else {
+			xmlNsPtr ns;
+			
+			/*
+			* XSLT-1.0 "Each QName is expanded into an
+			*  expanded-name using the namespace declarations in
+			*  effect on the xsl:output element in which the QName
+			*  occurs; if there is a default namespace, it is used
+			*  for QNames that do not have a prefix"
+			* NOTE: Fix of bug #339570.
+			*/
+			if (URI == NULL) {
+			    ns = xmlSearchNs(style->doc, cur, NULL);
+			    if (ns != NULL)
+				URI = ns->href;
+			}		   
+			xmlHashAddEntry2(style->cdataSection, element, URI,
+			    (void *) "cdata");
+			xmlFree(element);
+		    }
+		}
+            }
+            element = end;
+        }
+        xmlFree(elements);
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
+    if (prop != NULL) {
+	if (style->mediaType)
+	    xmlFree(style->mediaType);
+	style->mediaType = prop;
+    }
+    if (cur->children != NULL) {
+	xsltParseContentError(style, cur->children);
+    }
+}
+
+/**
+ * xsltParseStylesheetDecimalFormat:
+ * @style:  the XSLT stylesheet
+ * @cur:  the "decimal-format" element
+ *
+ * <!-- Category: top-level-element -->
+ * <xsl:decimal-format
+ *   name = qname, decimal-separator = char, grouping-separator = char,
+ *   infinity = string, minus-sign = char, NaN = string, percent = char
+ *   per-mille = char, zero-digit = char, digit = char,
+ * pattern-separator = char />
+ *
+ * parse an XSLT stylesheet decimal-format element and
+ * and record the formatting characteristics
+ */
+static void
+xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
+{
+    xmlChar *prop;
+    xsltDecimalFormatPtr format;
+    xsltDecimalFormatPtr iter;
+    
+    if ((cur == NULL) || (style == NULL))
+	return;
+
+    format = style->decimalFormat;
+    
+    prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
+    if (prop != NULL) {
+	format = xsltDecimalFormatGetByName(style, prop);
+	if (format != NULL) {
+	    xsltTransformError(NULL, style, cur,
+	 "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
+	    if (style != NULL) style->warnings++;
+	    return;
+	}
+	format = xsltNewDecimalFormat(prop);
+	if (format == NULL) {
+	    xsltTransformError(NULL, style, cur,
+     "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
+	    if (style != NULL) style->errors++;
+	    return;
+	}
+	/* Append new decimal-format structure */
+	for (iter = style->decimalFormat; iter->next; iter = iter->next)
+	    ;
+	if (iter)
+	    iter->next = format;
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
+    if (prop != NULL) {
+	if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
+	format->decimalPoint  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
+    if (prop != NULL) {
+	if (format->grouping != NULL) xmlFree(format->grouping);
+	format->grouping  = prop;
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
+    if (prop != NULL) {
+	if (format->infinity != NULL) xmlFree(format->infinity);
+	format->infinity  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
+    if (prop != NULL) {
+	if (format->minusSign != NULL) xmlFree(format->minusSign);
+	format->minusSign  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
+    if (prop != NULL) {
+	if (format->noNumber != NULL) xmlFree(format->noNumber);
+	format->noNumber  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
+    if (prop != NULL) {
+	if (format->percent != NULL) xmlFree(format->percent);
+	format->percent  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
+    if (prop != NULL) {
+	if (format->permille != NULL) xmlFree(format->permille);
+	format->permille  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
+    if (prop != NULL) {
+	if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
+	format->zeroDigit  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
+    if (prop != NULL) {
+	if (format->digit != NULL) xmlFree(format->digit);
+	format->digit  = prop;
+    }
+    
+    prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
+    if (prop != NULL) {
+	if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
+	format->patternSeparator  = prop;
+    }
+    if (cur->children != NULL) {
+	xsltParseContentError(style, cur->children);
+    }
+}
+
+/**
+ * xsltParseStylesheetPreserveSpace:
+ * @style:  the XSLT stylesheet
+ * @cur:  the "preserve-space" element
+ *
+ * parse an XSLT stylesheet preserve-space element and record
+ * elements needing preserving
+ */
+
+static void
+xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
+    xmlChar *elements;
+    xmlChar *element, *end;
+
+    if ((cur == NULL) || (style == NULL))
+	return;
+
+    elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
+    if (elements == NULL) {
+	xsltTransformError(NULL, style, cur,
+	    "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
+	if (style != NULL) style->warnings++;
+	return;
+    }
+
+    if (style->stripSpaces == NULL)
+	style->stripSpaces = xmlHashCreate(10);
+    if (style->stripSpaces == NULL)
+	return;
+
+    element = elements;
+    while (*element != 0) {
+	while (IS_BLANK(*element)) element++;
+	if (*element == 0)
+	    break;
+        end = element;
+	while ((*end != 0) && (!IS_BLANK(*end))) end++;
+	element = xmlStrndup(element, end - element);
+	if (element) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+	    xsltGenericDebug(xsltGenericDebugContext,
+		"add preserved space element %s\n", element);
+#endif
+	    if (xmlStrEqual(element, (const xmlChar *)"*")) {
+		style->stripAll = -1;
+	    } else {
+		const xmlChar *URI;
+
+		/*
+		* TODO: Don't use xsltGetQNameURI().
+		*/
+                URI = xsltGetQNameURI(cur, &element);
+
+		xmlHashAddEntry2(style->stripSpaces, element, URI,
+				(xmlChar *) "preserve");
+	    }
+	    xmlFree(element);
+	}
+	element = end;
+    }
+    xmlFree(elements);
+    if (cur->children != NULL) {
+	xsltParseContentError(style, cur->children);
+    }
+}
+
+#ifdef XSLT_REFACTORED
+#else
+/**
+ * xsltParseStylesheetExtPrefix:
+ * @style:  the XSLT stylesheet
+ * @template:  the "extension-element-prefixes" prefix
+ *
+ * parse an XSLT stylesheet's "extension-element-prefix" attribute value
+ * and register the namespaces of extension instruction.
+ * SPEC "A namespace is designated as an extension namespace by using
+ *   an extension-element-prefixes attribute on:
+ *   1) an xsl:stylesheet element
+ *   2) an xsl:extension-element-prefixes attribute on a
+ *      literal result element 
+ *   3) an extension instruction."
+ */
+static void
+xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,
+			     int isXsltElem) {
+    xmlChar *prefixes;
+    xmlChar *prefix, *end;
+
+    if ((cur == NULL) || (style == NULL))
+	return;
+
+    if (isXsltElem) {
+	/* For xsl:stylesheet/xsl:transform. */
+	prefixes = xmlGetNsProp(cur,
+	    (const xmlChar *)"extension-element-prefixes", NULL);
+    } else {
+	/* For literal result elements and extension instructions. */
+	prefixes = xmlGetNsProp(cur,
+	    (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
+    }
+    if (prefixes == NULL) {
+	return;
+    }
+
+    prefix = prefixes;
+    while (*prefix != 0) {
+	while (IS_BLANK(*prefix)) prefix++;
+	if (*prefix == 0)
+	    break;
+        end = prefix;
+	while ((*end != 0) && (!IS_BLANK(*end))) end++;
+	prefix = xmlStrndup(prefix, end - prefix);
+	if (prefix) {
+	    xmlNsPtr ns;
+
+	    if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
+		ns = xmlSearchNs(style->doc, cur, NULL);
+	    else
+		ns = xmlSearchNs(style->doc, cur, prefix);
+	    if (ns == NULL) {
+		xsltTransformError(NULL, style, cur,
+	    "xsl:extension-element-prefix : undefined namespace %s\n",
+	                         prefix);
+		if (style != NULL) style->warnings++;
+	    } else {
+#ifdef WITH_XSLT_DEBUG_PARSING
+		xsltGenericDebug(xsltGenericDebugContext,
+		    "add extension prefix %s\n", prefix);
+#endif
+		xsltRegisterExtPrefix(style, prefix, ns->href);
+	    }
+	    xmlFree(prefix);
+	}
+	prefix = end;
+    }
+    xmlFree(prefixes);
+}
+#endif /* else of XSLT_REFACTORED */
+
+/**
+ * xsltParseStylesheetStripSpace:
+ * @style:  the XSLT stylesheet
+ * @cur:  the "strip-space" element
+ *
+ * parse an XSLT stylesheet's strip-space element and record
+ * the elements needing stripping
+ */
+
+static void
+xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
+    xmlChar *elements;
+    xmlChar *element, *end;
+
+    if ((cur == NULL) || (style == NULL))
+	return;
+
+    elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
+    if (elements == NULL) {
+	xsltTransformError(NULL, style, cur,
+	    "xsltParseStylesheetStripSpace: missing elements attribute\n");
+	if (style != NULL) style->warnings++;
+	return;
+    }
+
+    if (style->stripSpaces == NULL)
+	style->stripSpaces = xmlHashCreate(10);
+    if (style->stripSpaces == NULL)
+	return;
+
+    element = elements;
+    while (*element != 0) {
+	while (IS_BLANK(*element)) element++;
+	if (*element == 0)
+	    break;
+        end = element;
+	while ((*end != 0) && (!IS_BLANK(*end))) end++;
+	element = xmlStrndup(element, end - element);
+	if (element) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+	    xsltGenericDebug(xsltGenericDebugContext,
+		"add stripped space element %s\n", element);
+#endif
+	    if (xmlStrEqual(element, (const xmlChar *)"*")) {
+		style->stripAll = 1;
+	    } else {
+		const xmlChar *URI;
+
+		/*
+		* TODO: Don't use xsltGetQNameURI().
+		*/
+                URI = xsltGetQNameURI(cur, &element);
+
+		xmlHashAddEntry2(style->stripSpaces, element, URI,
+			        (xmlChar *) "strip");
+	    }
+	    xmlFree(element);
+	}
+	element = end;
+    }
+    xmlFree(elements);
+    if (cur->children != NULL) {
+	xsltParseContentError(style, cur->children);
+    }
+}
+
+#ifdef XSLT_REFACTORED
+#else
+/**
+ * xsltParseStylesheetExcludePrefix:
+ * @style:  the XSLT stylesheet
+ * @cur:  the current point in the stylesheet
+ *
+ * parse an XSLT stylesheet exclude prefix and record
+ * namespaces needing stripping
+ *
+ * Returns the number of Excluded prefixes added at that level
+ */
+
+static int
+xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur,
+				 int isXsltElem)
+{
+    int nb = 0;
+    xmlChar *prefixes;
+    xmlChar *prefix, *end;
+
+    if ((cur == NULL) || (style == NULL))
+	return(0);
+
+    if (isXsltElem)
+	prefixes = xmlGetNsProp(cur,
+	    (const xmlChar *)"exclude-result-prefixes", NULL);
+    else
+	prefixes = xmlGetNsProp(cur,
+	    (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);
+
+    if (prefixes == NULL) {
+	return(0);
+    }
+
+    prefix = prefixes;
+    while (*prefix != 0) {
+	while (IS_BLANK(*prefix)) prefix++;
+	if (*prefix == 0)
+	    break;
+        end = prefix;
+	while ((*end != 0) && (!IS_BLANK(*end))) end++;
+	prefix = xmlStrndup(prefix, end - prefix);
+	if (prefix) {
+	    xmlNsPtr ns;
+
+	    if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
+		ns = xmlSearchNs(style->doc, cur, NULL);
+	    else
+		ns = xmlSearchNs(style->doc, cur, prefix);
+	    if (ns == NULL) {
+		xsltTransformError(NULL, style, cur,
+	    "xsl:exclude-result-prefixes : undefined namespace %s\n",
+	                         prefix);
+		if (style != NULL) style->warnings++;
+	    } else {
+		if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+		    xsltGenericDebug(xsltGenericDebugContext,
+			"exclude result prefix %s\n", prefix);
+#endif
+		    nb++;
+		}
+	    }
+	    xmlFree(prefix);
+	}
+	prefix = end;
+    }
+    xmlFree(prefixes);
+    return(nb);
+}
+#endif /* else of XSLT_REFACTORED */
+
+#ifdef XSLT_REFACTORED
+
+/*
+* xsltTreeEnsureXMLDecl:
+* @doc: the doc
+* 
+* BIG NOTE:
+*  This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
+* Ensures that there is an XML namespace declaration on the doc.
+* 
+* Returns the XML ns-struct or NULL on API and internal errors.
+*/
+static xmlNsPtr
+xsltTreeEnsureXMLDecl(xmlDocPtr doc)
+{
+    if (doc == NULL)
+	return (NULL);
+    if (doc->oldNs != NULL)
+	return (doc->oldNs);
+    {
+	xmlNsPtr ns;
+	ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
+	if (ns == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		"xsltTreeEnsureXMLDecl: Failed to allocate "
+		"the XML namespace.\n");	
+	    return (NULL);
+	}
+	memset(ns, 0, sizeof(xmlNs));
+	ns->type = XML_LOCAL_NAMESPACE;
+	/*
+	* URGENT TODO: revisit this.
+	*/
+#ifdef LIBXML_NAMESPACE_DICT
+	if (doc->dict)
+	    ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
+	else
+	    ns->href = xmlStrdup(XML_XML_NAMESPACE);
+#else
+	ns->href = xmlStrdup(XML_XML_NAMESPACE); 
+#endif
+	ns->prefix = xmlStrdup((const xmlChar *)"xml");
+	doc->oldNs = ns;
+	return (ns);
+    }
+}
+
+/*
+* xsltTreeAcquireStoredNs:
+* @doc: the doc
+* @nsName: the namespace name
+* @prefix: the prefix
+* 
+* BIG NOTE:
+*  This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
+* Creates or reuses an xmlNs struct on doc->oldNs with
+* the given prefix and namespace name.
+* 
+* Returns the aquired ns struct or NULL in case of an API
+*         or internal error.
+*/
+static xmlNsPtr
+xsltTreeAcquireStoredNs(xmlDocPtr doc,
+			const xmlChar *nsName,
+			const xmlChar *prefix)
+{
+    xmlNsPtr ns;
+
+    if (doc == NULL)
+	return (NULL);
+    if (doc->oldNs != NULL)
+	ns = doc->oldNs;
+    else
+	ns = xsltTreeEnsureXMLDecl(doc);
+    if (ns == NULL)
+	return (NULL);
+    if (ns->next != NULL) {
+	/* Reuse. */
+	ns = ns->next;
+	while (ns != NULL) {
+	    if ((ns->prefix == NULL) != (prefix == NULL)) {
+		/* NOP */
+	    } else if (prefix == NULL) {
+		if (xmlStrEqual(ns->href, nsName))
+		    return (ns);
+	    } else {
+		if ((ns->prefix[0] == prefix[0]) &&
+		     xmlStrEqual(ns->prefix, prefix) &&
+		     xmlStrEqual(ns->href, nsName))
+		    return (ns);
+		
+	    }
+	    if (ns->next == NULL)
+		break;
+	    ns = ns->next;
+	}
+    }
+    /* Create. */
+    ns->next = xmlNewNs(NULL, nsName, prefix);
+    return (ns->next);
+}
+
+/**
+ * xsltLREBuildEffectiveNs:
+ *
+ * Apply ns-aliasing on the namespace of the given @elem and
+ * its attributes.
+ */
+static int
+xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
+			xmlNodePtr elem)
+{
+    xmlNsPtr ns;
+    xsltNsAliasPtr alias;
+
+    if ((cctxt == NULL) || (elem == NULL))
+	return(-1);
+    if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
+	return(0);
+
+    alias = cctxt->nsAliases;    		
+    while (alias != NULL) {
+	if ( /* If both namespaces are NULL... */
+	    ( (elem->ns == NULL) &&
+	    ((alias->literalNs == NULL) ||
+	    (alias->literalNs->href == NULL)) ) ||
+	    /* ... or both namespace are equal */
+	    ( (elem->ns != NULL) &&
+	    (alias->literalNs != NULL) &&
+	    xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
+	{
+	    if ((alias->targetNs != NULL) &&
+		(alias->targetNs->href != NULL))
+	    {
+		/*
+		* Convert namespace.
+		*/
+		if (elem->doc == alias->docOfTargetNs) {
+		    /*
+		    * This is the nice case: same docs.
+		    * This will eventually assign a ns-decl which
+		    * is shadowed, but this has no negative effect on
+		    * the generation of the result tree.
+		    */
+		    elem->ns = alias->targetNs;
+		} else {
+		    /*
+		    * This target xmlNs originates from a different
+		    * stylesheet tree. Try to locate it in the
+		    * in-scope namespaces.
+		    * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
+		    */
+		    ns = xmlSearchNs(elem->doc, elem,
+			alias->targetNs->prefix);		    
+		    /*
+		    * If no matching ns-decl found, then assign a
+		    * ns-decl stored in xmlDoc.
+		    */
+		    if ((ns == NULL) ||
+			(! xmlStrEqual(ns->href, alias->targetNs->href)))
+		    {
+			/*
+			* BIG NOTE: The use of xsltTreeAcquireStoredNs()
+			*  is not very efficient, but currently I don't
+			*  see an other way of *safely* changing a node's
+			*  namespace, since the xmlNs struct in
+			*  alias->targetNs might come from an other
+			*  stylesheet tree. So we need to anchor it in the
+			*  current document, without adding it to the tree,
+			*  which would otherwise change the in-scope-ns
+			*  semantic of the tree.
+			*/
+			ns = xsltTreeAcquireStoredNs(elem->doc,
+			    alias->targetNs->href,
+			    alias->targetNs->prefix);
+			
+			if (ns == NULL) {
+			    xsltTransformError(NULL, cctxt->style, elem,
+				"Internal error in "
+				"xsltLREBuildEffectiveNs(): "
+				"failed to acquire a stored "
+				"ns-declaration.\n");
+			    cctxt->style->errors++;
+			    return(-1);
+			    
+			}
+		    }
+		    elem->ns = ns;
+		}		   
+	    } else {
+		/*
+		* Move into or leave in the NULL namespace.
+		*/
+		elem->ns = NULL;
+	    }
+	    break;
+	}
+	alias = alias->next;
+    }
+    /*
+    * Same with attributes of literal result elements.
+    */
+    if (elem->properties != NULL) {
+	xmlAttrPtr attr = elem->properties;
+	
+	while (attr != NULL) {
+	    if (attr->ns == NULL) {
+		attr = attr->next;
+		continue;
+	    }
+	    alias = cctxt->nsAliases;
+	    while (alias != NULL) {
+		if ( /* If both namespaces are NULL... */
+		    ( (elem->ns == NULL) &&
+		    ((alias->literalNs == NULL) ||
+		    (alias->literalNs->href == NULL)) ) ||
+		    /* ... or both namespace are equal */
+		    ( (elem->ns != NULL) &&
+		    (alias->literalNs != NULL) &&
+		    xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
+		{
+		    if ((alias->targetNs != NULL) &&
+			(alias->targetNs->href != NULL))
+		    {		    
+			if (elem->doc == alias->docOfTargetNs) {
+			    elem->ns = alias->targetNs;
+			} else {
+			    ns = xmlSearchNs(elem->doc, elem,
+				alias->targetNs->prefix);
+			    if ((ns == NULL) ||
+				(! xmlStrEqual(ns->href, alias->targetNs->href)))
+			    {
+				ns = xsltTreeAcquireStoredNs(elem->doc,
+				    alias->targetNs->href,
+				    alias->targetNs->prefix);
+				
+				if (ns == NULL) {
+				    xsltTransformError(NULL, cctxt->style, elem,
+					"Internal error in "
+					"xsltLREBuildEffectiveNs(): "
+					"failed to acquire a stored "
+					"ns-declaration.\n");
+				    cctxt->style->errors++;
+				    return(-1);
+				    
+				}
+			    }
+			    elem->ns = ns;
+			}
+		    } else {
+		    /*
+		    * Move into or leave in the NULL namespace.
+			*/
+			elem->ns = NULL;
+		    }
+		    break;
+		}
+		alias = alias->next;
+	    }
+	    
+	    attr = attr->next;
+	}
+    }
+    return(0);
+}
+
+/**
+ * xsltLREBuildEffectiveNsNodes:
+ *
+ * Computes the effective namespaces nodes for a literal result
+ * element.
+ * @effectiveNs is the set of effective ns-nodes
+ *  on the literal result element, which will be added to the result
+ *  element if not already existing in the result tree.
+ *  This means that excluded namespaces (via exclude-result-prefixes,
+ *  extension-element-prefixes and the XSLT namespace) not added
+ *  to the set.
+ *  Namespace-aliasing was applied on the @effectiveNs.
+ */
+static int
+xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
+			     xsltStyleItemLRElementInfoPtr item,
+			     xmlNodePtr elem,
+			     int isLRE)
+{
+    xmlNsPtr ns, tmpns;
+    xsltEffectiveNsPtr effNs, lastEffNs = NULL;
+    int i, j, holdByElem;
+    xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
+    xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
+
+    if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
+	(item == NULL) || (item->effectiveNs != NULL))
+	return(-1);
+
+    if (item->inScopeNs == NULL)    
+	return(0);
+
+    extElemNs = cctxt->inode->extElemNs;
+    exclResultNs = cctxt->inode->exclResultNs;
+
+    for (i = 0; i < item->inScopeNs->totalNumber; i++) {
+	ns = item->inScopeNs->list[i];
+	/*
+	* Skip namespaces designated as excluded namespaces
+	* -------------------------------------------------
+	*
+	* XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
+	*  which are target namespaces of namespace-aliases
+	*  regardless if designated as excluded.
+	*
+	* Exclude the XSLT namespace.
+	*/
+	if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
+	    goto skip_ns;
+
+	/*
+	* Apply namespace aliasing
+	* ------------------------
+	*
+	* SPEC XSLT 2.0
+	*  "- A namespace node whose string value is a literal namespace
+	*     URI is not copied to the result tree.
+	*   - A namespace node whose string value is a target namespace URI
+	*     is copied to the result tree, whether or not the URI
+	*     identifies an excluded namespace."
+	* 
+	* NOTE: The ns-aliasing machanism is non-cascading.
+	*  (checked with Saxon, Xalan and MSXML .NET).
+	* URGENT TODO: is style->nsAliases the effective list of
+	*  ns-aliases, or do we need to lookup the whole
+	*  import-tree?
+	* TODO: Get rid of import-tree lookup.
+	*/
+	if (cctxt->hasNsAliases) {
+	    xsltNsAliasPtr alias;
+	    /*
+	    * First check for being a target namespace.
+	    */
+	    alias = cctxt->nsAliases;
+	    do {
+		/*
+		* TODO: Is xmlns="" handled already?
+		*/
+		if ((alias->targetNs != NULL) &&
+		    (xmlStrEqual(alias->targetNs->href, ns->href)))
+		{
+		    /*
+		    * Recognized as a target namespace; use it regardless
+		    * if excluded otherwise.
+		    */
+		    goto add_effective_ns;
+		}
+		alias = alias->next;
+	    } while (alias != NULL);
+
+	    alias = cctxt->nsAliases;
+	    do {
+		/*
+		* TODO: Is xmlns="" handled already?
+		*/
+		if ((alias->literalNs != NULL) &&
+		    (xmlStrEqual(alias->literalNs->href, ns->href)))
+		{
+		    /*
+		    * Recognized as an namespace alias; do not use it.
+		    */
+		    goto skip_ns;
+		}
+		alias = alias->next;
+	    } while (alias != NULL);
+	}
+	
+	/*
+	* Exclude excluded result namespaces.
+	*/
+	if (exclResultNs) {
+	    for (j = 0; j < exclResultNs->number; j++)
+		if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
+		    goto skip_ns;
+	}
+	/*
+	* Exclude extension-element namespaces.
+	*/
+	if (extElemNs) {
+	    for (j = 0; j < extElemNs->number; j++)
+		if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
+		    goto skip_ns;
+	}
+
+add_effective_ns:
+	/*
+	* OPTIMIZE TODO: This information may not be needed.
+	*/
+	if (isLRE && (elem->nsDef != NULL)) {
+	    holdByElem = 0;
+	    tmpns = elem->nsDef;
+	    do {
+		if (tmpns == ns) {
+		    holdByElem = 1;
+		    break;
+		}
+		tmpns = tmpns->next;
+	    } while (tmpns != NULL);	    
+	} else
+	    holdByElem = 0;
+	
+	
+	/*
+	* Add the effective namespace declaration.
+	*/
+	effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
+	if (effNs == NULL) {
+	    xsltTransformError(NULL, cctxt->style, elem,
+		"Internal error in xsltLREBuildEffectiveNs(): "
+		"failed to allocate memory.\n");
+	    cctxt->style->errors++;
+	    return(-1);
+	}
+	if (cctxt->psData->effectiveNs == NULL) {
+	    cctxt->psData->effectiveNs = effNs;
+	    effNs->nextInStore = NULL;	 
+	} else {
+	    effNs->nextInStore = cctxt->psData->effectiveNs;
+	    cctxt->psData->effectiveNs = effNs;
+	}
+
+	effNs->next = NULL;
+	effNs->prefix = ns->prefix;
+	effNs->nsName = ns->href;
+	effNs->holdByElem = holdByElem;
+	
+	if (lastEffNs == NULL)
+	    item->effectiveNs = effNs;
+	else
+	    lastEffNs->next = effNs;
+	lastEffNs = effNs;
+	
+skip_ns:
+	{}
+    }
+    return(0);
+}
+
+
+/**
+ * xsltLREInfoCreate:
+ *
+ * @isLRE: indicates if the given @elem is a literal result element
+ *
+ * Creates a new info for a literal result element.
+ */
+static int
+xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
+		  xmlNodePtr elem,
+		  int isLRE)
+{
+    xsltStyleItemLRElementInfoPtr item;
+
+    if ((cctxt == NULL) || (cctxt->inode == NULL))
+	return(-1);
+
+    item = (xsltStyleItemLRElementInfoPtr)
+	xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
+    if (item == NULL) {
+	xsltTransformError(NULL, cctxt->style, NULL,
+	    "Internal error in xsltLREInfoCreate(): "
+	    "memory allocation failed.\n");
+	cctxt->style->errors++;
+	return(-1);
+    }
+    memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
+    item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
+    /*
+    * Store it in the stylesheet.
+    */
+    item->next = cctxt->style->preComps;
+    cctxt->style->preComps = (xsltElemPreCompPtr) item;
+    /*
+    * @inScopeNs are used for execution of XPath expressions
+    *  in AVTs.
+    */
+    item->inScopeNs = cctxt->inode->inScopeNs;
+    
+    if (elem)
+	xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);
+
+    cctxt->inode->litResElemInfo = item;
+    cctxt->inode->nsChanged = 0;
+    cctxt->maxLREs++;
+    return(0);
+}
+
+/**
+ * xsltCompilerVarInfoPush: 
+ * @cctxt: the compilation context
+ * 
+ * Pushes a new var/param info onto the stack.
+ *
+ * Returns the acquired variable info.
+ */ 
+static xsltVarInfoPtr
+xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,
+				  xmlNodePtr inst,
+				  const xmlChar *name,
+				  const xmlChar *nsName)
+{
+    xsltVarInfoPtr ivar;
+
+    if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) {
+	ivar = cctxt->ivar->next;
+    } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) {
+	ivar = cctxt->ivars;
+    } else {
+	ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo));
+	if (ivar == NULL) {
+	    xsltTransformError(NULL, cctxt->style, inst,
+		"xsltParseInScopeVarPush: xmlMalloc() failed!\n");
+	    cctxt->style->errors++;
+	    return(NULL);
+	}
+	/* memset(retVar, 0, sizeof(xsltInScopeVar)); */
+	if (cctxt->ivars == NULL) {
+	    cctxt->ivars = ivar;
+	    ivar->prev = NULL;
+	} else {
+	    cctxt->ivar->next = ivar;
+	    ivar->prev = cctxt->ivar;
+	}
+	cctxt->ivar = ivar;
+	ivar->next = NULL;
+    }
+    ivar->depth = cctxt->depth;
+    ivar->name = name;
+    ivar->nsName = nsName;
+    return(ivar);
+}
+
+/**
+ * xsltCompilerVarInfoPop: 
+ * @cctxt: the compilation context
+ * 
+ * Pops all var/param infos from the stack, which
+ * have the current depth.
+ */ 
+static void
+xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)
+{
+
+    while ((cctxt->ivar != NULL) &&
+	(cctxt->ivar->depth > cctxt->depth))
+    {
+	cctxt->ivar = cctxt->ivar->prev;
+    }
+}
+
+/*
+* xsltCompilerNodePush:
+*
+* @cctxt: the compilation context
+* @node: the node to be pushed (this can also be the doc-node)
+*
+* 
+*
+* Returns the current node info structure or
+*         NULL in case of an internal error.
+*/
+static xsltCompilerNodeInfoPtr
+xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
+{    
+    xsltCompilerNodeInfoPtr inode, iprev;
+
+    if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {	
+	inode = cctxt->inode->next;
+    } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {
+	inode = cctxt->inodeList;	
+    } else {
+	/*
+	* Create a new node-info.
+	*/
+	inode = (xsltCompilerNodeInfoPtr)
+	    xmlMalloc(sizeof(xsltCompilerNodeInfo));
+	if (inode == NULL) {
+	    xsltTransformError(NULL, cctxt->style, NULL,
+		"xsltCompilerNodePush: malloc failed.\n");
+	    return(NULL);
+	}
+	memset(inode, 0, sizeof(xsltCompilerNodeInfo));
+	if (cctxt->inodeList == NULL)
+	    cctxt->inodeList = inode;
+	else {
+	    cctxt->inodeLast->next = inode;
+	    inode->prev = cctxt->inodeLast;
+	}
+	cctxt->inodeLast = inode;
+	cctxt->maxNodeInfos++;	
+	if (cctxt->inode == NULL) {
+	    cctxt->inode = inode;
+	    /*
+	    * Create an initial literal result element info for
+	    * the root of the stylesheet.
+	    */
+	    xsltLREInfoCreate(cctxt, NULL, 0);
+	} 
+    }       
+    cctxt->depth++;
+    cctxt->inode = inode;
+    /*
+    * REVISIT TODO: Keep the reset always complete.    
+    * NOTE: Be carefull with the @node, since it might be
+    *  a doc-node.
+    */
+    inode->node = node;
+    inode->depth = cctxt->depth;
+    inode->templ = NULL;
+    inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
+    inode->type = 0;
+    inode->item = NULL;
+    inode->curChildType = 0;
+    inode->extContentHandled = 0;
+    inode->isRoot = 0;
+    
+    if (inode->prev != NULL) {
+	iprev = inode->prev;
+	/*
+	* Inherit the following information:
+	* ---------------------------------
+	*
+	* In-scope namespaces
+	*/
+	inode->inScopeNs = iprev->inScopeNs;
+	/*
+	* Info for literal result elements
+	*/
+	inode->litResElemInfo = iprev->litResElemInfo;
+	inode->nsChanged = iprev->nsChanged;
+	/*
+	* Excluded result namespaces
+	*/
+	inode->exclResultNs = iprev->exclResultNs;
+	/*
+	* Extension instruction namespaces
+	*/
+	inode->extElemNs = iprev->extElemNs;
+	/*
+	* Whitespace preservation
+	*/
+	inode->preserveWhitespace = iprev->preserveWhitespace;
+	/*
+	* Forwards-compatible mode
+	*/
+	inode->forwardsCompat = iprev->forwardsCompat;	
+    } else {
+	inode->inScopeNs = NULL;
+	inode->exclResultNs = NULL;
+	inode->extElemNs = NULL;
+	inode->preserveWhitespace = 0;
+	inode->forwardsCompat = 0;
+    }
+    
+    return(inode);
+}
+
+/*
+* xsltCompilerNodePop:
+*
+* @cctxt: the compilation context
+* @node: the node to be pushed (this can also be the doc-node)
+*
+* Pops the current node info.
+*/
+static void
+xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
+{    
+    if (cctxt->inode == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+	    "xsltCompilerNodePop: Top-node mismatch.\n");
+	return;
+    }
+    /*
+    * NOTE: Be carefull with the @node, since it might be
+    *  a doc-node.
+    */
+    if (cctxt->inode->node != node) {
+	xmlGenericError(xmlGenericErrorContext,
+	"xsltCompilerNodePop: Node mismatch.\n");
+	goto mismatch;
+    }
+    if (cctxt->inode->depth != cctxt->depth) {
+	xmlGenericError(xmlGenericErrorContext,
+	"xsltCompilerNodePop: Depth mismatch.\n");
+	goto mismatch;
+    }
+    /*
+    * Pop information of variables.
+    */
+    if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))
+	xsltCompilerVarInfoPop(cctxt);
+
+    cctxt->depth--;
+    cctxt->inode = cctxt->inode->prev;
+    if (cctxt->inode != NULL)
+	cctxt->inode->curChildType = 0;
+    return;
+
+mismatch:
+    {
+	const xmlChar *nsName = NULL, *name = NULL;
+	const xmlChar *infnsName = NULL, *infname = NULL;
+	
+	if (node) {
+	    if (node->type == XML_ELEMENT_NODE) {
+		name = node->name;
+		if (node->ns != NULL)
+		    nsName = node->ns->href;
+		else
+		    nsName = BAD_CAST "";
+	    } else {
+		name = BAD_CAST "#document";
+		nsName = BAD_CAST "";
+	    }
+	} else
+	    name = BAD_CAST "Not given";
+
+	if (cctxt->inode->node) {
+	    if (node->type == XML_ELEMENT_NODE) {
+		infname = cctxt->inode->node->name;
+		if (cctxt->inode->node->ns != NULL)
+		    infnsName = cctxt->inode->node->ns->href;
+		else
+		    infnsName = BAD_CAST "";
+	    } else {
+		infname = BAD_CAST "#document";
+		infnsName = BAD_CAST "";
+	    }
+	} else
+	    infname = BAD_CAST "Not given";
+
+	
+	xmlGenericError(xmlGenericErrorContext,
+	    "xsltCompilerNodePop: Given   : '%s' URI '%s'\n",
+	    name, nsName);
+	xmlGenericError(xmlGenericErrorContext,
+	    "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
+	    infname, infnsName);
+    }
+}
+
+/*
+* xsltCompilerBuildInScopeNsList:
+*
+* Create and store the list of in-scope namespaces for the given
+* node in the stylesheet. If there are no changes in the in-scope
+* namespaces then the last ns-info of the ancestor axis will be returned.
+* Compilation-time only.
+*
+* Returns the ns-info or NULL if there are no namespaces in scope.
+*/
+static xsltNsListContainerPtr
+xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
+{
+    xsltNsListContainerPtr nsi = NULL;
+    xmlNsPtr *list = NULL, ns;
+    int i, maxns = 5;
+    /*
+    * Create a new ns-list for this position in the node-tree.
+    * xmlGetNsList() will return NULL, if there are no ns-decls in the
+    * tree. Note that the ns-decl for the XML namespace is not added
+    * to the resulting list; the XPath module handles the XML namespace
+    * internally.
+    */
+    while (node != NULL) {
+        if (node->type == XML_ELEMENT_NODE) {
+            ns = node->nsDef;
+            while (ns != NULL) {
+                if (nsi == NULL) {
+		    nsi = (xsltNsListContainerPtr)
+			xmlMalloc(sizeof(xsltNsListContainer));
+		    if (nsi == NULL) {
+			xsltTransformError(NULL, cctxt->style, NULL,
+			    "xsltCompilerBuildInScopeNsList: "
+			    "malloc failed!\n");
+			goto internal_err;
+		    }
+		    memset(nsi, 0, sizeof(xsltNsListContainer));
+                    nsi->list =
+                        (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
+                    if (nsi->list == NULL) {
+			xsltTransformError(NULL, cctxt->style, NULL,
+			    "xsltCompilerBuildInScopeNsList: "
+			    "malloc failed!\n");
+			goto internal_err;
+                    }
+                    nsi->list[0] = NULL;
+                }
+		/*
+		* Skip shadowed namespace bindings.
+		*/
+                for (i = 0; i < nsi->totalNumber; i++) {
+                    if ((ns->prefix == nsi->list[i]->prefix) ||
+                        (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
+		    break;
+                }
+                if (i >= nsi->totalNumber) {
+                    if (nsi->totalNumber +1 >= maxns) {
+                        maxns *= 2;
+			nsi->list =
+			    (xmlNsPtr *) xmlRealloc(nsi->list,
+				maxns * sizeof(xmlNsPtr));
+                        if (nsi->list == NULL) {
+                            xsltTransformError(NULL, cctxt->style, NULL,
+				"xsltCompilerBuildInScopeNsList: "
+				"realloc failed!\n");
+				goto internal_err;
+                        }
+                    }
+                    nsi->list[nsi->totalNumber++] = ns;
+                    nsi->list[nsi->totalNumber] = NULL;
+                }
+
+                ns = ns->next;
+            }
+        }
+        node = node->parent;
+    }
+    if (nsi == NULL)
+	return(NULL);
+    /*
+    * Move the default namespace to last position.
+    */
+    nsi->xpathNumber = nsi->totalNumber;
+    for (i = 0; i < nsi->totalNumber; i++) {
+	if (nsi->list[i]->prefix == NULL) {
+	    ns = nsi->list[i];
+	    nsi->list[i] = nsi->list[nsi->totalNumber-1];
+	    nsi->list[nsi->totalNumber-1] = ns;
+	    nsi->xpathNumber--;
+	    break;
+	}
+    }
+    /*
+    * Store the ns-list in the stylesheet.
+    */
+    if (xsltPointerListAddSize(
+	(xsltPointerListPtr)cctxt->psData->inScopeNamespaces,
+	(void *) nsi, 5) == -1)
+    {	
+	xmlFree(nsi);
+	nsi = NULL;
+	xsltTransformError(NULL, cctxt->style, NULL,
+	    "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
+	goto internal_err;
+    }
+    /*
+    * Notify of change in status wrt namespaces.
+    */
+    if (cctxt->inode != NULL)
+	cctxt->inode->nsChanged = 1;
+
+    return(nsi);
+
+internal_err:
+    if (list != NULL)
+	xmlFree(list);    
+    cctxt->style->errors++;
+    return(NULL);
+}
+
+static int
+xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
+		      xsltPointerListPtr list,
+		      xmlNodePtr node,
+		      const xmlChar *value)
+{
+    xmlChar *cur, *end;
+    xmlNsPtr ns;
+    
+    if ((cctxt == NULL) || (value == NULL) || (list == NULL))
+	return(-1);
+
+    list->number = 0;
+
+    cur = (xmlChar *) value;
+    while (*cur != 0) {
+	while (IS_BLANK(*cur)) cur++;
+	if (*cur == 0)
+	    break;
+	end = cur;
+	while ((*end != 0) && (!IS_BLANK(*end))) end++;
+	cur = xmlStrndup(cur, end - cur);
+	if (cur == NULL) {
+	    cur = end;
+	    continue;
+	}		
+	/*
+	* TODO: Export and use xmlSearchNsByPrefixStrict()
+	*   in Libxml2, tree.c, since xmlSearchNs() is in most
+	*   cases not efficient and in some cases not correct.
+	*
+	* XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
+	*/
+	if ((cur[0] == '#') &&
+	    xmlStrEqual(cur, (const xmlChar *)"#default"))
+	    ns = xmlSearchNs(cctxt->style->doc, node, NULL);
+	else
+	    ns = xmlSearchNs(cctxt->style->doc, node, cur);	    
+
+	if (ns == NULL) {
+	    /*
+	    * TODO: Better to report the attr-node, otherwise
+	    *  the user won't know which attribute was invalid.
+	    */
+	    xsltTransformError(NULL, cctxt->style, node,
+		"No namespace binding in scope for prefix '%s'.\n", cur);
+	    /*
+	    * XSLT-1.0: "It is an error if there is no namespace
+	    *  bound to the prefix on the element bearing the
+	    *  exclude-result-prefixes or xsl:exclude-result-prefixes
+	    *  attribute."
+	    */
+	    cctxt->style->errors++;
+	} else {
+#ifdef WITH_XSLT_DEBUG_PARSING
+	    xsltGenericDebug(xsltGenericDebugContext,
+		"resolved prefix '%s'\n", cur);
+#endif
+	    /*
+	    * Note that we put the namespace name into the dict.
+	    */
+	    if (xsltPointerListAddSize(list,
+		(void *) xmlDictLookup(cctxt->style->dict,
+		ns->href, -1), 5) == -1)
+	    {
+		xmlFree(cur);
+		goto internal_err;
+	    }
+	}
+	xmlFree(cur);
+		
+	cur = end;
+    }
+    return(0);
+
+internal_err:
+    cctxt->style->errors++;
+    return(-1);
+}
+
+/**
+ * xsltCompilerUtilsCreateMergedList:
+ * @dest: the destination list (optional)
+ * @first: the first list
+ * @second: the second list (optional)
+ *
+ * Appends the content of @second to @first into @destination.
+ * If @destination is NULL a new list will be created.
+ *
+ * Returns the merged list of items or NULL if there's nothing to merge.
+ */
+static xsltPointerListPtr
+xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,
+			    xsltPointerListPtr second)
+{
+    xsltPointerListPtr ret;
+    size_t num;
+
+    if (first)
+	num = first->number;
+    else
+	num = 0;
+    if (second)
+	num += second->number;    
+    if (num == 0)
+	return(NULL);
+    ret = xsltPointerListCreate(num);
+    if (ret == NULL)
+	return(NULL);
+    /*
+    * Copy contents.
+    */
+    if ((first != NULL) &&  (first->number != 0)) {
+	memcpy(ret->items, first->items,
+	    first->number * sizeof(void *));
+	if ((second != NULL) && (second->number != 0))
+	    memcpy(ret->items + first->number, second->items,
+		second->number * sizeof(void *));
+    } else if ((second != NULL) && (second->number != 0))
+	memcpy(ret->items, (void *) second->items,
+	    second->number * sizeof(void *));
+    ret->number = num;
+    return(ret);
+}
+
+/*
+* xsltParseExclResultPrefixes:
+*
+* Create and store the list of in-scope namespaces for the given
+* node in the stylesheet. If there are no changes in the in-scope
+* namespaces then the last ns-info of the ancestor axis will be returned.
+* Compilation-time only.
+*
+* Returns the ns-info or NULL if there are no namespaces in scope.
+*/
+static xsltPointerListPtr
+xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
+			    xsltPointerListPtr def,
+			    int instrCategory)
+{    
+    xsltPointerListPtr list = NULL;
+    xmlChar *value;
+    xmlAttrPtr attr;
+
+    if ((cctxt == NULL) || (node == NULL))
+	return(NULL);
+
+    if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
+	attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
+    else
+	attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
+	    XSLT_NAMESPACE);
+    if (attr == NULL)	
+	return(def);
+
+    if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
+	/*
+	* Mark the XSLT attr.
+	*/
+	attr->psvi = (void *) xsltXSLTAttrMarker;
+    }
+
+    if ((attr->children != NULL) &&	
+	(attr->children->content != NULL))
+	value = attr->children->content;
+    else {
+	xsltTransformError(NULL, cctxt->style, node,
+	    "Attribute 'exclude-result-prefixes': Invalid value.\n");
+	cctxt->style->errors++;
+	return(def);
+    }        
+
+    if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
+	BAD_CAST value) != 0)
+	goto exit;
+    if (cctxt->tmpList->number == 0)	
+	goto exit;    
+    /*
+    * Merge the list with the inherited list.
+    */
+    list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
+    if (list == NULL)
+	goto exit;    
+    /*
+    * Store the list in the stylesheet/compiler context.
+    */
+    if (xsltPointerListAddSize(
+	cctxt->psData->exclResultNamespaces, list, 5) == -1)
+    {
+	xsltPointerListFree(list);
+	list = NULL;
+	goto exit;
+    }
+    /*
+    * Notify of change in status wrt namespaces.
+    */
+    if (cctxt->inode != NULL)
+	cctxt->inode->nsChanged = 1;
+
+exit:    
+    if (list != NULL)
+	return(list);
+    else
+	return(def);
+}
+
+/*
+* xsltParseExtElemPrefixes:
+*
+* Create and store the list of in-scope namespaces for the given
+* node in the stylesheet. If there are no changes in the in-scope
+* namespaces then the last ns-info of the ancestor axis will be returned.
+* Compilation-time only.
+*
+* Returns the ns-info or NULL if there are no namespaces in scope.
+*/
+static xsltPointerListPtr
+xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
+			 xsltPointerListPtr def,
+			 int instrCategory)
+{    
+    xsltPointerListPtr list = NULL;
+    xmlAttrPtr attr;
+    xmlChar *value;
+    int i;
+
+    if ((cctxt == NULL) || (node == NULL))
+	return(NULL);
+
+    if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
+	attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
+    else
+	attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
+	    XSLT_NAMESPACE);
+    if (attr == NULL)	
+	return(def);
+
+    if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
+	/*
+	* Mark the XSLT attr.
+	*/
+	attr->psvi = (void *) xsltXSLTAttrMarker;
+    }
+
+    if ((attr->children != NULL) &&	
+	(attr->children->content != NULL))
+	value = attr->children->content;
+    else {
+	xsltTransformError(NULL, cctxt->style, node,
+	    "Attribute 'extension-element-prefixes': Invalid value.\n");
+	cctxt->style->errors++;
+	return(def);
+    }
+
+
+    if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
+	BAD_CAST value) != 0)
+	goto exit;
+
+    if (cctxt->tmpList->number == 0)
+	goto exit;    
+    /*
+    * REVISIT: Register the extension namespaces.
+    */
+    for (i = 0; i < cctxt->tmpList->number; i++)
+	xsltRegisterExtPrefix(cctxt->style, NULL,
+	BAD_CAST cctxt->tmpList->items[i]);
+    /*
+    * Merge the list with the inherited list.
+    */
+    list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
+    if (list == NULL)
+	goto exit;
+    /*
+    * Store the list in the stylesheet.
+    */
+    if (xsltPointerListAddSize(
+	cctxt->psData->extElemNamespaces, list, 5) == -1)
+    {
+	xsltPointerListFree(list);
+	list = NULL;
+	goto exit;
+    }
+    /*
+    * Notify of change in status wrt namespaces.
+    */
+    if (cctxt->inode != NULL)
+	cctxt->inode->nsChanged = 1;
+
+exit:    
+    if (list != NULL)
+	return(list);
+    else
+	return(def);
+}
+
+/*
+* xsltParseAttrXSLTVersion:
+*
+* @cctxt: the compilation context
+* @node: the element-node
+* @isXsltElem: whether this is an XSLT element
+*
+* Parses the attribute xsl:version.
+*
+* Returns 1 if there was such an attribute, 0 if not and
+*         -1 if an internal or API error occured.
+*/
+static int
+xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,			 
+			 int instrCategory)
+{
+    xmlChar *value;
+    xmlAttrPtr attr;
+
+    if ((cctxt == NULL) || (node == NULL))
+	return(-1);
+
+    if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
+	attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
+    else
+	attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
+
+    if (attr == NULL)	
+	return(0);
+
+    attr->psvi = (void *) xsltXSLTAttrMarker;
+
+    if ((attr->children != NULL) &&	
+	(attr->children->content != NULL))
+	value = attr->children->content;
+    else {
+	xsltTransformError(NULL, cctxt->style, node,
+	    "Attribute 'version': Invalid value.\n");
+	cctxt->style->errors++;
+	return(1);
+    }
+    
+    if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
+	cctxt->inode->forwardsCompat = 1;
+	/*
+	* TODO: To what extent do we support the
+	*  forwards-compatible mode?
+	*/
+	/*
+	* Report this only once per compilation episode.
+	*/
+	if (! cctxt->hasForwardsCompat) {
+	    cctxt->hasForwardsCompat = 1;
+	    cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;
+	    xsltTransformError(NULL, cctxt->style, node,
+		"Warning: the attribute xsl:version specifies a value "
+		"different from '1.0'. Switching to forwards-compatible "
+		"mode. Only features of XSLT 1.0 are supported by this "
+		"processor.\n");
+	    cctxt->style->warnings++;
+	    cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
+	}	
+    } else {
+	cctxt->inode->forwardsCompat = 0;
+    }
+
+    if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
+	/*
+	* Set a marker on XSLT attributes.
+	*/
+	attr->psvi = (void *) xsltXSLTAttrMarker;
+    }
+    return(1);
+}
+
+static int
+xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
+{
+    xmlNodePtr deleteNode, cur, txt, textNode = NULL;
+    xmlDocPtr doc;
+    xsltStylesheetPtr style;
+    int internalize = 0, findSpaceAttr;
+    int xsltStylesheetElemDepth;
+    xmlAttrPtr attr;
+    xmlChar *value;
+    const xmlChar *name, *nsNameXSLT = NULL;
+    int strictWhitespace, inXSLText = 0;
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+    xsltNsMapPtr nsMapItem;
+#endif
+
+    if ((cctxt == NULL) || (cctxt->style == NULL) ||
+	(node == NULL) || (node->type != XML_ELEMENT_NODE))
+        return(-1);
+
+    doc = node->doc;
+    if (doc == NULL)
+	goto internal_err;
+
+    style = cctxt->style;
+    if ((style->dict != NULL) && (doc->dict == style->dict))
+	internalize = 1;
+    else
+        style->internalized = 0;
+
+    /*
+    * Init value of xml:space. Since this might be an embedded
+    * stylesheet, this is needed to be performed on the element
+    * where the stylesheet is rooted at, taking xml:space of
+    * ancestors into account.
+    */
+    if (! cctxt->simplified)
+	xsltStylesheetElemDepth = cctxt->depth +1;
+    else
+	xsltStylesheetElemDepth = 0;
+
+    if (xmlNodeGetSpacePreserve(node) != 1)
+	cctxt->inode->preserveWhitespace = 0;
+    else
+	cctxt->inode->preserveWhitespace = 1; 
+    
+    /*
+    * Eval if we should keep the old incorrect behaviour.
+    */
+    strictWhitespace = (cctxt->strict != 0) ? 1 : 0;
+
+    nsNameXSLT = xsltConstNamespaceNameXSLT;
+
+    deleteNode = NULL;
+    cur = node;
+    while (cur != NULL) {
+	if (deleteNode != NULL)	{
+
+#ifdef WITH_XSLT_DEBUG_BLANKS
+	    xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltParsePreprocessStylesheetTree: removing node\n");
+#endif
+	    xmlUnlinkNode(deleteNode);
+	    xmlFreeNode(deleteNode);
+	    deleteNode = NULL;
+	}
+	if (cur->type == XML_ELEMENT_NODE) {
+	    
+	    /*
+	    * Clear the PSVI field.
+	    */
+	    cur->psvi = NULL;
+
+	    xsltCompilerNodePush(cctxt, cur);
+
+	    inXSLText = 0;
+	    textNode = NULL;	    
+	    findSpaceAttr = 1;	    
+	    cctxt->inode->stripWhitespace = 0;
+	    /*
+	    * TODO: I'd love to use a string pointer comparison here :-/
+	    */
+	    if (IS_XSLT_ELEM(cur)) {
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+		if (cur->ns->href != nsNameXSLT) {
+		    nsMapItem = xsltNewNamespaceMapItem(cctxt,
+			doc, cur->ns, cur);
+		    if (nsMapItem == NULL)
+			goto internal_err;
+		    cur->ns->href = nsNameXSLT;
+		}
+#endif
+
+		if (cur->name == NULL)
+		    goto process_attributes;
+		/*
+		* Mark the XSLT element for later recognition.
+		* TODO: Using the marker is still too dangerous, since if
+		*   the parsing mechanism leaves out an XSLT element, then
+		*   this might hit the transformation-mechanism, which
+		*   will break if it doesn't expect such a marker.
+		*/
+		/* cur->psvi = (void *) xsltXSLTElemMarker; */
+
+		/*
+		* XSLT 2.0: "Any whitespace text node whose parent is
+		* one of the following elements is removed from the "
+		* tree, regardless of any xml:space attributes:..."
+		* xsl:apply-imports, 
+		* xsl:apply-templates,
+		* xsl:attribute-set,
+		* xsl:call-template, 
+		* xsl:choose,
+		* xsl:stylesheet, xsl:transform.
+		* XSLT 2.0: xsl:analyze-string,
+		*           xsl:character-map,
+		*           xsl:next-match		
+		*
+		* TODO: I'd love to use a string pointer comparison here :-/
+		*/		
+		name = cur->name;
+		switch (*name) {
+		    case 't':
+			if ((name[0] == 't') && (name[1] == 'e') &&
+			    (name[2] == 'x') && (name[3] == 't') &&
+			    (name[4] == 0))
+			{
+			    /*
+			    * Process the xsl:text element.
+			    * ----------------------------
+			    * Mark it for later recognition.
+			    */
+			    cur->psvi = (void *) xsltXSLTTextMarker;
+			    /*
+			    * For stylesheets, the set of
+			    * whitespace-preserving element names
+			    * consists of just xsl:text.
+			    */
+			    findSpaceAttr = 0;
+			    cctxt->inode->preserveWhitespace = 1;
+			    inXSLText = 1;
+			}			    
+			break;
+		    case 'c':
+			if (xmlStrEqual(name, BAD_CAST "choose") ||
+			    xmlStrEqual(name, BAD_CAST "call-template"))
+			    cctxt->inode->stripWhitespace = 1;
+			break;
+		    case 'a':
+			if (xmlStrEqual(name, BAD_CAST "apply-templates") ||
+			    xmlStrEqual(name, BAD_CAST "apply-imports") ||
+			    xmlStrEqual(name, BAD_CAST "attribute-set"))
+
+			    cctxt->inode->stripWhitespace = 1;
+			break;
+		    default:
+			if (xsltStylesheetElemDepth == cctxt->depth) {
+			    /*
+			    * This is a xsl:stylesheet/xsl:transform.
+			    */
+			    cctxt->inode->stripWhitespace = 1;
+			    break;
+			}
+
+			if ((cur->prev != NULL) &&
+			    (cur->prev->type == XML_TEXT_NODE))
+			{
+			    /*
+			    * XSLT 2.0 : "Any whitespace text node whose
+			    *  following-sibling node is an xsl:param or
+			    *  xsl:sort element is removed from the tree,
+			    *  regardless of any xml:space attributes."
+			    */
+			    if (((*name == 'p') || (*name == 's')) &&
+				(xmlStrEqual(name, BAD_CAST "param") ||
+				 xmlStrEqual(name, BAD_CAST "sort")))
+			    {
+				do {
+				    if (IS_BLANK_NODE(cur->prev)) {
+					txt = cur->prev;
+					xmlUnlinkNode(txt);
+					xmlFreeNode(txt);
+				    } else {
+					/*
+					* This will result in a content
+					* error, when hitting the parsing
+					* functions.
+					*/
+					break;
+				    }
+				} while (cur->prev);				    
+			    }
+			}
+			break;
+		}
+	    }
+
+process_attributes:
+	    /*
+	    * Process attributes.
+	    * ------------------
+	    */
+	    if (cur->properties != NULL) {
+		if (cur->children == NULL)
+		    findSpaceAttr = 0;
+		attr = cur->properties;
+		do {
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+		    if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
+			xmlStrEqual(attr->ns->href, nsNameXSLT))
+		    {			
+			nsMapItem = xsltNewNamespaceMapItem(cctxt,
+			    doc, attr->ns, cur);
+			if (nsMapItem == NULL)
+			    goto internal_err;
+			attr->ns->href = nsNameXSLT;
+		    }		    
+#endif
+		    if (internalize) {
+			/*
+			* Internalize the attribute's value; the goal is to
+			* speed up operations and minimize used space by
+			* compiled stylesheets.
+			*/
+			txt = attr->children;
+			/*
+			* NOTE that this assumes only one
+			*  text-node in the attribute's content.
+			*/
+			if ((txt != NULL) && (txt->content != NULL) &&
+			    (!xmlDictOwns(style->dict, txt->content)))
+			{
+			    value = (xmlChar *) xmlDictLookup(style->dict,
+				txt->content, -1);
+			    xmlNodeSetContent(txt, NULL);
+			    txt->content = value;
+			}
+		    }
+		    /*
+		    * Process xml:space attributes.
+		    * ----------------------------
+		    */
+		    if ((findSpaceAttr != 0) &&
+			(attr->ns != NULL) &&
+			(attr->name != NULL) &&
+			(attr->name[0] == 's') &&			
+			(attr->ns->prefix != NULL) &&
+			(attr->ns->prefix[0] == 'x') &&
+			(attr->ns->prefix[1] == 'm') &&
+			(attr->ns->prefix[2] == 'l') &&
+			(attr->ns->prefix[3] == 0))
+		    {
+			value = xmlGetNsProp(cur, BAD_CAST "space",
+			    XML_XML_NAMESPACE);
+			if (value != NULL) {
+			    if (xmlStrEqual(value, BAD_CAST "preserve")) {
+				cctxt->inode->preserveWhitespace = 1;				
+			    } else if (xmlStrEqual(value, BAD_CAST "default")) {
+				cctxt->inode->preserveWhitespace = 0;
+			    } else {
+				/* Invalid value for xml:space. */
+				xsltTransformError(NULL, style, cur,
+				    "Attribute xml:space: Invalid value.\n");
+				cctxt->style->warnings++;
+			    }
+			    findSpaceAttr = 0;
+			    xmlFree(value);
+			}
+			
+		    }
+		    attr = attr->next;
+		} while (attr != NULL);
+	    }
+	    /*
+	    * We'll descend into the children of element nodes only.
+	    */
+	    if (cur->children != NULL) {
+		cur = cur->children;
+		continue;
+	    }
+	} else if ((cur->type == XML_TEXT_NODE) ||
+		(cur->type == XML_CDATA_SECTION_NODE))
+	{
+	    /*
+	    * Merge adjacent text/CDATA-section-nodes
+	    * ---------------------------------------	    
+	    * In order to avoid breaking of existing stylesheets,
+	    * if the old behaviour is wanted (strictWhitespace == 0),
+	    * then we *won't* merge adjacent text-nodes
+	    * (except in xsl:text); this will ensure that whitespace-only
+	    * text nodes are (incorrectly) not stripped in some cases.
+	    * 
+	    * Example:               : <foo>  <!-- bar -->zoo</foo>
+	    * Corrent (strict) result: <foo>  zoo</foo>
+	    * Incorrect (old) result : <foo>zoo</foo>
+	    *    
+	    * NOTE that we *will* merge adjacent text-nodes if
+	    * they are in xsl:text.
+	    * Example, the following:
+	    * <xsl:text>  <!-- bar -->zoo<xsl:text>
+	    * will result in both cases in:
+	    * <xsl:text>  zoo<xsl:text>
+	    */
+	    cur->type = XML_TEXT_NODE;
+	    if ((strictWhitespace != 0) || (inXSLText != 0)) {
+		/*
+		* New behaviour; merge nodes.
+		*/
+		if (textNode == NULL)
+		    textNode = cur;
+		else {
+		    if (cur->content != NULL)
+			xmlNodeAddContent(textNode, cur->content);
+		    deleteNode = cur;
+		}
+		if ((cur->next == NULL) ||
+		    (cur->next->type == XML_ELEMENT_NODE))
+		    goto end_of_text;
+		else
+		    goto next_sibling;
+	    } else {
+		/*
+		* Old behaviour.
+		*/
+		if (textNode == NULL)
+		    textNode = cur;
+		goto end_of_text;
+	    }	    	   
+	} else if ((cur->type == XML_COMMENT_NODE) ||
+	    (cur->type == XML_PI_NODE))
+	{	    
+	    /*
+	    * Remove processing instructions and comments.
+	    */
+	    deleteNode = cur;
+	    if ((cur->next == NULL) ||
+		(cur->next->type == XML_ELEMENT_NODE))
+		goto end_of_text;
+	    else
+		goto next_sibling;
+	} else {
+	    textNode = NULL;
+	    /*
+	    * Invalid node-type for this data-model.
+	    */
+	    xsltTransformError(NULL, style, cur,
+		"Invalid type of node for the XSLT data model.\n");
+	    cctxt->style->errors++;
+	    goto next_sibling;
+	}
+
+end_of_text:
+	if (textNode) {
+	    value = textNode->content;
+	    /*
+	    * At this point all adjacent text/CDATA-section nodes
+	    * have been merged.
+	    *
+	    * Strip whitespace-only text-nodes.
+	    * (cctxt->inode->stripWhitespace)
+	    */
+	    if ((value == NULL) || (*value == 0) ||
+		(((cctxt->inode->stripWhitespace) ||
+		  (! cctxt->inode->preserveWhitespace)) &&
+		 IS_BLANK(*value) &&
+		 xsltIsBlank(value)))
+	    {		
+		if (textNode != cur) {
+		    xmlUnlinkNode(textNode);
+		    xmlFreeNode(textNode);
+		} else
+		    deleteNode = textNode;
+		textNode = NULL;
+		goto next_sibling;
+	    }
+	    /*
+	    * Convert CDATA-section nodes to text-nodes.
+	    * TODO: Can this produce problems?
+	    */
+	    if (textNode->type != XML_TEXT_NODE) {
+		textNode->type = XML_TEXT_NODE;
+		textNode->name = xmlStringText;
+	    }
+	    if (internalize &&
+		(textNode->content != NULL) &&
+		(!xmlDictOwns(style->dict, textNode->content)))
+	    {
+		/*
+		* Internalize the string.
+		*/
+		value = (xmlChar *) xmlDictLookup(style->dict,
+		    textNode->content, -1);
+		xmlNodeSetContent(textNode, NULL);
+		textNode->content = value;
+	    }
+	    textNode = NULL;
+	    /*
+	    * Note that "disable-output-escaping" of the xsl:text
+	    * element will be applied at a later level, when
+	    * XSLT elements are processed.
+	    */
+	}
+
+next_sibling:
+	if (cur->type == XML_ELEMENT_NODE) {
+	    xsltCompilerNodePop(cctxt, cur);
+	}
+	if (cur == node)
+	    break;
+	if (cur->next != NULL) {
+	    cur = cur->next;
+	} else {
+	    cur = cur->parent;
+	    inXSLText = 0;
+	    goto next_sibling;
+	};
+    }
+    if (deleteNode != NULL) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+	xsltGenericDebug(xsltGenericDebugContext,
+	 "xsltParsePreprocessStylesheetTree: removing node\n");
+#endif
+	xmlUnlinkNode(deleteNode);
+	xmlFreeNode(deleteNode);
+    }
+    return(0);
+
+internal_err:
+    return(-1);
+}
+
+#endif /* XSLT_REFACTORED */
+
+#ifdef XSLT_REFACTORED
+#else
+static void
+xsltPrecomputeStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
+{
+    xmlNodePtr deleteNode, styleelem;
+    int internalize = 0;
+
+    if ((style == NULL) || (cur == NULL))
+        return;
+
+    if ((cur->doc != NULL) && (style->dict != NULL) &&
+        (cur->doc->dict == style->dict))
+	internalize = 1;
+    else
+        style->internalized = 0;
+
+    if ((cur != NULL) && (IS_XSLT_ELEM(cur)) &&
+        (IS_XSLT_NAME(cur, "stylesheet"))) {
+	styleelem = cur;
+    } else {
+        styleelem = NULL;
+    }
+
+    /*
+     * This content comes from the stylesheet
+     * For stylesheets, the set of whitespace-preserving
+     * element names consists of just xsl:text.
+     */
+    deleteNode = NULL;
+    while (cur != NULL) {
+	if (deleteNode != NULL) {
+#ifdef WITH_XSLT_DEBUG_BLANKS
+	    xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltPrecomputeStylesheet: removing ignorable blank node\n");
+#endif
+	    xmlUnlinkNode(deleteNode);
+	    xmlFreeNode(deleteNode);
+	    deleteNode = NULL;
+	}
+	if (cur->type == XML_ELEMENT_NODE) {
+	    int exclPrefixes;
+	    /*
+	     * Internalize attributes values.
+	     */
+	    if ((internalize) && (cur->properties != NULL)) {
+	        xmlAttrPtr attr = cur->properties;
+		xmlNodePtr txt;
+
+		while (attr != NULL) {
+		    txt = attr->children;
+		    if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
+		        (txt->content != NULL) &&
+			(!xmlDictOwns(style->dict, txt->content)))
+		    {
+			xmlChar *tmp;
+
+			/*
+			 * internalize the text string, goal is to speed
+			 * up operations and minimize used space by compiled
+			 * stylesheets.
+			 */
+			tmp = (xmlChar *) xmlDictLookup(style->dict,
+			                                txt->content, -1);
+			if (tmp != txt->content) {
+			    xmlNodeSetContent(txt, NULL);
+			    txt->content = tmp;
+			}
+		    }
+		    attr = attr->next;
+		}
+	    }
+	    if (IS_XSLT_ELEM(cur)) {
+		exclPrefixes = 0;
+		xsltStylePreCompute(style, cur);
+		if (IS_XSLT_NAME(cur, "text")) {
+		    for (;exclPrefixes > 0;exclPrefixes--)
+			exclPrefixPop(style);
+		    goto skip_children;
+		}
+	    } else {
+		exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
+	    }
+	    	     
+	    if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
+		xmlNsPtr ns = cur->nsDef, prev = NULL, next;
+		xmlNodePtr root = NULL;
+		int i, moved;
+
+		root = xmlDocGetRootElement(cur->doc);
+		if ((root != NULL) && (root != cur)) {
+		    while (ns != NULL) {
+			moved = 0;
+			next = ns->next;
+			for (i = 0;i < style->exclPrefixNr;i++) {
+			    if ((ns->prefix != NULL) && 
+			        (xmlStrEqual(ns->href,
+					     style->exclPrefixTab[i]))) {
+				/*
+				 * Move the namespace definition on the root
+				 * element to avoid duplicating it without
+				 * loosing it.
+				 */
+				if (prev == NULL) {
+				    cur->nsDef = ns->next;
+				} else {
+				    prev->next = ns->next;
+				}
+				ns->next = root->nsDef;
+				root->nsDef = ns;
+				moved = 1;
+				break;
+			    }
+			}
+			if (moved == 0)
+			    prev = ns;
+			ns = next;
+		    }
+		}
+	    }
+	    /*
+	     * If we have prefixes locally, recurse and pop them up when
+	     * going back
+	     */
+	    if (exclPrefixes > 0) {
+		xsltPrecomputeStylesheet(style, cur->children);
+		for (;exclPrefixes > 0;exclPrefixes--)
+		    exclPrefixPop(style);
+		goto skip_children;
+	    }
+	} else if (cur->type == XML_TEXT_NODE) {
+	    if (IS_BLANK_NODE(cur)) {
+		if (xmlNodeGetSpacePreserve(cur) != 1) {
+		    deleteNode = cur;
+		}
+	    } else if ((cur->content != NULL) && (internalize) &&
+	               (!xmlDictOwns(style->dict, cur->content))) {
+		xmlChar *tmp;
+
+		/*
+		 * internalize the text string, goal is to speed
+		 * up operations and minimize used space by compiled
+		 * stylesheets.
+		 */
+		tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
+		xmlNodeSetContent(cur, NULL);
+		cur->content = tmp;
+	    }
+	} else if ((cur->type != XML_ELEMENT_NODE) &&
+		   (cur->type != XML_CDATA_SECTION_NODE)) {
+	    deleteNode = cur;
+	    goto skip_children;
+	}
+
+	/*
+	 * Skip to next node. In case of a namespaced element children of
+	 * the stylesheet and not in the XSLT namespace and not an extension
+	 * element, ignore its content.
+	 */
+	if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) &&
+	    (styleelem != NULL) && (cur->parent == styleelem) &&
+	    (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) &&
+	    (!xsltCheckExtURI(style, cur->ns->href))) {
+	    goto skip_children;
+	} else if (cur->children != NULL) {
+	    if ((cur->children->type != XML_ENTITY_DECL) &&
+		(cur->children->type != XML_ENTITY_REF_NODE) &&
+		(cur->children->type != XML_ENTITY_NODE)) {
+		cur = cur->children;
+		continue;
+	    }
+	}
+
+skip_children:
+	if (cur->next != NULL) {
+	    cur = cur->next;
+	    continue;
+	}
+	do {
+
+	    cur = cur->parent;
+	    if (cur == NULL)
+		break;
+	    if (cur == (xmlNodePtr) style->doc) {
+		cur = NULL;
+		break;
+	    }
+	    if (cur->next != NULL) {
+		cur = cur->next;
+		break;
+	    }
+	} while (cur != NULL);
+    }
+    if (deleteNode != NULL) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+	xsltGenericDebug(xsltGenericDebugContext,
+	 "xsltPrecomputeStylesheet: removing ignorable blank node\n");
+#endif
+	xmlUnlinkNode(deleteNode);
+	xmlFreeNode(deleteNode);
+    }
+}
+#endif /* end of else XSLT_REFACTORED */
+
+/**
+ * xsltGatherNamespaces:
+ * @style:  the XSLT stylesheet
+ *
+ * Browse the stylesheet and build the namspace hash table which
+ * will be used for XPath interpretation. If needed do a bit of normalization
+ */
+
+static void
+xsltGatherNamespaces(xsltStylesheetPtr style) {
+    xmlNodePtr cur;
+    const xmlChar *URI;
+
+    if (style == NULL)
+        return;
+    /* 
+     * TODO: basically if the stylesheet uses the same prefix for different
+     *       patterns, well they may be in problem, hopefully they will get
+     *       a warning first.
+     */
+    /*
+    * TODO: Eliminate the use of the hash for XPath expressions.
+    *   An expression should be evaluated in the context of the in-scope
+    *   namespaces; eliminate the restriction of an XML document to contain
+    *   no duplicate prefixes for different namespace names.
+    * 
+    */
+    cur = xmlDocGetRootElement(style->doc);
+    while (cur != NULL) {
+	if (cur->type == XML_ELEMENT_NODE) {
+	    xmlNsPtr ns = cur->nsDef;
+	    while (ns != NULL) {
+		if (ns->prefix != NULL) {
+		    if (style->nsHash == NULL) {
+			style->nsHash = xmlHashCreate(10);
+			if (style->nsHash == NULL) {
+			    xsltTransformError(NULL, style, cur,
+		 "xsltGatherNamespaces: failed to create hash table\n");
+			    style->errors++;
+			    return;
+			}
+		    }
+		    URI = xmlHashLookup(style->nsHash, ns->prefix);
+		    if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
+			xsltTransformError(NULL, style, cur,
+	     "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
+			style->warnings++;
+		    } else if (URI == NULL) {
+			xmlHashUpdateEntry(style->nsHash, ns->prefix,
+			    (void *) ns->href, (xmlHashDeallocator)xmlFree);
+
+#ifdef WITH_XSLT_DEBUG_PARSING
+			xsltGenericDebug(xsltGenericDebugContext,
+		 "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
+#endif
+		    }
+		}
+		ns = ns->next;
+	    }
+	}
+
+	/*
+	 * Skip to next node
+	 */
+	if (cur->children != NULL) {
+	    if (cur->children->type != XML_ENTITY_DECL) {
+		cur = cur->children;
+		continue;
+	    }
+	}
+	if (cur->next != NULL) {
+	    cur = cur->next;
+	    continue;
+	}
+	
+	do {
+	    cur = cur->parent;
+	    if (cur == NULL)
+		break;
+	    if (cur == (xmlNodePtr) style->doc) {
+		cur = NULL;
+		break;
+	    }
+	    if (cur->next != NULL) {
+		cur = cur->next;
+		break;
+	    }
+	} while (cur != NULL);
+    }
+}
+
+#ifdef XSLT_REFACTORED
+
+static xsltStyleType
+xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
+			     xmlNodePtr node)
+{
+    if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
+	(node->name == NULL))
+	return(0);
+
+    if (node->name[0] == 'a') {
+	if (IS_XSLT_NAME(node, "apply-templates"))
+	    return(XSLT_FUNC_APPLYTEMPLATES);
+	else if (IS_XSLT_NAME(node, "attribute"))
+	    return(XSLT_FUNC_ATTRIBUTE);
+	else if (IS_XSLT_NAME(node, "apply-imports"))
+	    return(XSLT_FUNC_APPLYIMPORTS);
+	else if (IS_XSLT_NAME(node, "attribute-set"))
+	    return(0);
+
+    } else if (node->name[0] == 'c') {
+	if (IS_XSLT_NAME(node, "choose"))
+	    return(XSLT_FUNC_CHOOSE);
+	else if (IS_XSLT_NAME(node, "copy"))
+	    return(XSLT_FUNC_COPY);
+	else if (IS_XSLT_NAME(node, "copy-of"))
+	    return(XSLT_FUNC_COPYOF);
+	else if (IS_XSLT_NAME(node, "call-template"))
+	    return(XSLT_FUNC_CALLTEMPLATE);
+	else if (IS_XSLT_NAME(node, "comment"))
+	    return(XSLT_FUNC_COMMENT);
+
+    } else if (node->name[0] == 'd') {
+	if (IS_XSLT_NAME(node, "document"))
+	    return(XSLT_FUNC_DOCUMENT);
+	else if (IS_XSLT_NAME(node, "decimal-format"))
+	    return(0);
+
+    } else if (node->name[0] == 'e') {
+	if (IS_XSLT_NAME(node, "element"))
+	    return(XSLT_FUNC_ELEMENT);
+
+    } else if (node->name[0] == 'f') {
+	if (IS_XSLT_NAME(node, "for-each"))
+	    return(XSLT_FUNC_FOREACH);
+	else if (IS_XSLT_NAME(node, "fallback"))
+	    return(XSLT_FUNC_FALLBACK);
+
+    } else if (*(node->name) == 'i') {
+	if (IS_XSLT_NAME(node, "if"))
+	    return(XSLT_FUNC_IF);
+	else if (IS_XSLT_NAME(node, "include"))
+	    return(0);
+	else if (IS_XSLT_NAME(node, "import"))
+	    return(0);
+
+    } else if (*(node->name) == 'k') {
+	if (IS_XSLT_NAME(node, "key"))
+	    return(0);
+
+    } else if (*(node->name) == 'm') {
+	if (IS_XSLT_NAME(node, "message"))
+	    return(XSLT_FUNC_MESSAGE);
+
+    } else if (*(node->name) == 'n') {
+	if (IS_XSLT_NAME(node, "number"))
+	    return(XSLT_FUNC_NUMBER);
+	else if (IS_XSLT_NAME(node, "namespace-alias"))
+	    return(0);
+
+    } else if (*(node->name) == 'o') {
+	if (IS_XSLT_NAME(node, "otherwise"))
+	    return(XSLT_FUNC_OTHERWISE);
+	else if (IS_XSLT_NAME(node, "output"))
+	    return(0);
+
+    } else if (*(node->name) == 'p') {
+	if (IS_XSLT_NAME(node, "param"))
+	    return(XSLT_FUNC_PARAM);
+	else if (IS_XSLT_NAME(node, "processing-instruction"))
+	    return(XSLT_FUNC_PI);
+	else if (IS_XSLT_NAME(node, "preserve-space"))
+	    return(0);
+
+    } else if (*(node->name) == 's') {
+	if (IS_XSLT_NAME(node, "sort"))
+	    return(XSLT_FUNC_SORT);
+	else if (IS_XSLT_NAME(node, "strip-space"))
+	    return(0);
+	else if (IS_XSLT_NAME(node, "stylesheet"))
+	    return(0);
+
+    } else if (node->name[0] == 't') {
+	if (IS_XSLT_NAME(node, "text"))
+	    return(XSLT_FUNC_TEXT);
+	else if (IS_XSLT_NAME(node, "template"))
+	    return(0);
+	else if (IS_XSLT_NAME(node, "transform"))
+	    return(0);
+
+    } else if (*(node->name) == 'v') {
+	if (IS_XSLT_NAME(node, "value-of"))
+	    return(XSLT_FUNC_VALUEOF);
+	else if (IS_XSLT_NAME(node, "variable"))
+	    return(XSLT_FUNC_VARIABLE);
+
+    } else if (*(node->name) == 'w') {
+	if (IS_XSLT_NAME(node, "when"))
+	    return(XSLT_FUNC_WHEN);
+	if (IS_XSLT_NAME(node, "with-param"))
+	    return(XSLT_FUNC_WITHPARAM);
+    }
+    return(0);
+}
+
+/**
+ * xsltParseAnyXSLTElem:
+ *
+ * @cctxt: the compilation context
+ * @elem: the element node of the XSLT instruction
+ *
+ * Parses, validates the content models and compiles XSLT instructions.
+ *
+ * Returns 0 if everything's fine;
+ *         -1 on API or internal errors.
+ */ 
+int
+xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
+{
+    if ((cctxt == NULL) || (elem == NULL) ||
+	(elem->type != XML_ELEMENT_NODE))
+	return(-1);
+
+    elem->psvi = NULL;
+
+    if (! (IS_XSLT_ELEM_FAST(elem)))
+	return(-1);
+    /*
+    * Detection of handled content of extension instructions.
+    */
+    if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
+	cctxt->inode->extContentHandled = 1;
+    }
+    
+    xsltCompilerNodePush(cctxt, elem);
+    /*
+    * URGENT TODO: Find a way to speed up this annoying redundant
+    *  textual node-name and namespace comparison.
+    */
+    if (cctxt->inode->prev->curChildType != 0)
+	cctxt->inode->type = cctxt->inode->prev->curChildType;
+    else
+	cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem);    
+    /*
+    * Update the in-scope namespaces if needed.
+    */
+    if (elem->nsDef != NULL)
+	cctxt->inode->inScopeNs =
+	    xsltCompilerBuildInScopeNsList(cctxt, elem);
+    /*
+    * xsltStylePreCompute():
+    *  This will compile the information found on the current
+    *  element's attributes. NOTE that this won't process the
+    *  children of the instruction.
+    */
+    xsltStylePreCompute(cctxt->style, elem);
+    /*
+    * TODO: How to react on errors in xsltStylePreCompute() ?
+    */
+
+    /*
+    * Validate the content model of the XSLT-element.
+    */
+    switch (cctxt->inode->type) {	
+	case XSLT_FUNC_APPLYIMPORTS:
+	    /* EMPTY */
+	    goto empty_content;
+	case XSLT_FUNC_APPLYTEMPLATES:
+	    /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
+	    goto apply_templates;	    
+	case XSLT_FUNC_ATTRIBUTE:	    
+	    /* <!-- Content: template --> */
+	    goto sequence_constructor;
+	case XSLT_FUNC_CALLTEMPLATE:
+	    /* <!-- Content: xsl:with-param* --> */
+	    goto call_template;
+	case XSLT_FUNC_CHOOSE:	    
+	    /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
+	    goto choose;
+	case XSLT_FUNC_COMMENT:
+	    /* <!-- Content: template --> */
+	    goto sequence_constructor;	    
+	case XSLT_FUNC_COPY:
+	    /* <!-- Content: template --> */
+	    goto sequence_constructor;	    
+	case XSLT_FUNC_COPYOF:
+	    /* EMPTY */
+	    goto empty_content;	   
+	case XSLT_FUNC_DOCUMENT: /* Extra one */
+	    /* ?? template ?? */
+	    goto sequence_constructor;
+	case XSLT_FUNC_ELEMENT:
+	    /* <!-- Content: template --> */
+	    goto sequence_constructor;
+	case XSLT_FUNC_FALLBACK:
+	    /* <!-- Content: template --> */
+	    goto sequence_constructor;
+	case XSLT_FUNC_FOREACH:
+	    /* <!-- Content: (xsl:sort*, template) --> */
+	    goto for_each;
+	case XSLT_FUNC_IF:
+	    /* <!-- Content: template --> */
+	    goto sequence_constructor;
+	case XSLT_FUNC_OTHERWISE:
+	    /* <!-- Content: template --> */
+	    goto sequence_constructor;
+	case XSLT_FUNC_MESSAGE:
+	    /* <!-- Content: template --> */
+	    goto sequence_constructor;
+	case XSLT_FUNC_NUMBER:
+	    /* EMPTY */
+	    goto empty_content;
+	case XSLT_FUNC_PARAM:
+	    /*
+	    * Check for redefinition.
+	    */
+	    if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
+		xsltVarInfoPtr ivar = cctxt->ivar;
+
+		do {
+		    if ((ivar->name ==
+			 ((xsltStyleItemParamPtr) elem->psvi)->name) &&
+			(ivar->nsName ==
+			 ((xsltStyleItemParamPtr) elem->psvi)->ns))
+		    {
+			elem->psvi = NULL;
+			xsltTransformError(NULL, cctxt->style, elem,
+			    "Redefinition of variable or parameter '%s'.\n",
+			    ivar->name);
+			cctxt->style->errors++;
+			goto error;
+		    }
+		    ivar = ivar->prev;
+		} while (ivar != NULL);
+	    }
+	    /*  <!-- Content: template --> */
+	    goto sequence_constructor;
+	case XSLT_FUNC_PI:
+	    /*  <!-- Content: template --> */
+	    goto sequence_constructor;
+	case XSLT_FUNC_SORT:
+	    /* EMPTY */
+	    goto empty_content;
+	case XSLT_FUNC_TEXT:
+	    /* <!-- Content: #PCDATA --> */
+	    goto text;
+	case XSLT_FUNC_VALUEOF:
+	    /* EMPTY */
+	    goto empty_content;
+	case XSLT_FUNC_VARIABLE:
+	    /*
+	    * Check for redefinition.
+	    */
+	    if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
+		xsltVarInfoPtr ivar = cctxt->ivar;		
+
+		do {
+		    if ((ivar->name ==
+			 ((xsltStyleItemVariablePtr) elem->psvi)->name) &&
+			(ivar->nsName ==
+			 ((xsltStyleItemVariablePtr) elem->psvi)->ns))
+		    {
+			elem->psvi = NULL;
+			xsltTransformError(NULL, cctxt->style, elem,
+			    "Redefinition of variable or parameter '%s'.\n",
+			    ivar->name);
+			cctxt->style->errors++;
+			goto error;
+		    }
+		    ivar = ivar->prev;
+		} while (ivar != NULL);
+	    }
+	    /* <!-- Content: template --> */
+	    goto sequence_constructor;
+	case XSLT_FUNC_WHEN:
+	    /* <!-- Content: template --> */
+	    goto sequence_constructor;
+	case XSLT_FUNC_WITHPARAM:
+	    /* <!-- Content: template --> */
+	    goto sequence_constructor;
+	default:
+#ifdef WITH_XSLT_DEBUG_PARSING
+	    xsltGenericDebug(xsltGenericDebugContext,
+		"xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
+		elem->name);	    
+#endif
+	    xsltTransformError(NULL, cctxt->style, elem,
+		"xsltParseXSLTNode: Internal error; "
+		"unhandled XSLT element '%s'.\n", elem->name);
+	    cctxt->style->errors++;
+	    goto internal_err;
+    }
+
+apply_templates:
+    /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
+    if (elem->children != NULL) {
+	xmlNodePtr child = elem->children;
+	do {
+	    if (child->type == XML_ELEMENT_NODE) {
+		if (IS_XSLT_ELEM_FAST(child)) {
+		    if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
+			cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
+			xsltParseAnyXSLTElem(cctxt, child);
+		    } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
+			cctxt->inode->curChildType = XSLT_FUNC_SORT;
+			xsltParseAnyXSLTElem(cctxt, child);
+		    } else
+			xsltParseContentError(cctxt->style, child);
+		} else
+		    xsltParseContentError(cctxt->style, child);
+	    }
+	    child = child->next;
+	} while (child != NULL);
+    }    
+    goto exit;
+
+call_template:
+    /* <!-- Content: xsl:with-param* --> */
+    if (elem->children != NULL) {
+	xmlNodePtr child = elem->children;
+	do {
+	    if (child->type == XML_ELEMENT_NODE) {
+		if (IS_XSLT_ELEM_FAST(child)) {
+		    xsltStyleType type;
+
+		    type = xsltGetXSLTElementTypeByNode(cctxt, child);
+		    if (type == XSLT_FUNC_WITHPARAM) {
+			cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
+			xsltParseAnyXSLTElem(cctxt, child);
+		    } else {
+			xsltParseContentError(cctxt->style, child);
+		    }
+		} else
+		    xsltParseContentError(cctxt->style, child);
+	    }
+	    child = child->next;
+	} while (child != NULL);
+    }    
+    goto exit;
+
+text:
+    if (elem->children != NULL) {
+	xmlNodePtr child = elem->children;
+	do {
+	    if ((child->type != XML_TEXT_NODE) &&
+		(child->type != XML_CDATA_SECTION_NODE))
+	    {
+		xsltTransformError(NULL, cctxt->style, elem,
+		    "The XSLT 'text' element must have only character "
+		    "data as content.\n");
+	    }
+	    child = child->next;
+	} while (child != NULL);
+    }
+    goto exit;
+
+empty_content:
+    if (elem->children != NULL) {
+	xmlNodePtr child = elem->children;
+	/*
+	* Relaxed behaviour: we will allow whitespace-only text-nodes.
+	*/
+	do {
+	    if (((child->type != XML_TEXT_NODE) &&
+		 (child->type != XML_CDATA_SECTION_NODE)) ||
+		(! IS_BLANK_NODE(child)))
+	    {
+		xsltTransformError(NULL, cctxt->style, elem,
+		    "This XSLT element must have no content.\n");
+		cctxt->style->errors++;
+		break;
+	    }
+	    child = child->next;
+	} while (child != NULL);		
+    }
+    goto exit;
+
+choose:
+    /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
+    /*
+    * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
+    *   The old behaviour did not check this.
+    * NOTE: In XSLT 2.0 they are stripped beforehand
+    *  if whitespace-only (regardless of xml:space).
+    */
+    if (elem->children != NULL) {
+	xmlNodePtr child = elem->children;
+	int nbWhen = 0, nbOtherwise = 0, err = 0;
+	do {
+	    if (child->type == XML_ELEMENT_NODE) {
+		if (IS_XSLT_ELEM_FAST(child)) {
+		    xsltStyleType type;
+		
+		    type = xsltGetXSLTElementTypeByNode(cctxt, child);
+		    if (type == XSLT_FUNC_WHEN) {
+			nbWhen++;
+			if (nbOtherwise) {
+			    xsltParseContentError(cctxt->style, child);
+			    err = 1;
+			    break;
+			}
+			cctxt->inode->curChildType = XSLT_FUNC_WHEN;
+			xsltParseAnyXSLTElem(cctxt, child);
+		    } else if (type == XSLT_FUNC_OTHERWISE) {
+			if (! nbWhen) {
+			    xsltParseContentError(cctxt->style, child);
+			    err = 1;
+			    break;
+			}			
+			if (nbOtherwise) {
+			    xsltTransformError(NULL, cctxt->style, elem,
+				"The XSLT 'choose' element must not contain "
+				"more than one XSLT 'otherwise' element.\n");
+			    cctxt->style->errors++;
+			    err = 1;
+			    break;
+			}
+			nbOtherwise++;
+			cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;
+			xsltParseAnyXSLTElem(cctxt, child);
+		    } else
+			xsltParseContentError(cctxt->style, child);
+		} else
+		    xsltParseContentError(cctxt->style, child);
+	    } 
+	    /*
+		else
+		    xsltParseContentError(cctxt, child);
+	    */
+	    child = child->next;
+	} while (child != NULL);
+	if ((! err) && (! nbWhen)) {
+	    xsltTransformError(NULL, cctxt->style, elem,
+		"The XSLT element 'choose' must contain at least one "
+		"XSLT element 'when'.\n");
+		cctxt->style->errors++;
+	}	
+    }    
+    goto exit;
+
+for_each:
+    /* <!-- Content: (xsl:sort*, template) --> */
+    /*
+    * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
+    *   The old behaviour did not allow this, but it catched this
+    *   only at transformation-time.
+    *   In XSLT 2.0 they are stripped beforehand if whitespace-only
+    *   (regardless of xml:space).
+    */
+    if (elem->children != NULL) {
+	xmlNodePtr child = elem->children;
+	/*
+	* Parse xsl:sort first.
+	*/
+	do {	    
+	    if ((child->type == XML_ELEMENT_NODE) &&
+		IS_XSLT_ELEM_FAST(child))
+	    {		
+		if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
+		    XSLT_FUNC_SORT)
+		{		
+		    cctxt->inode->curChildType = XSLT_FUNC_SORT;
+		    xsltParseAnyXSLTElem(cctxt, child);
+		} else
+		    break;
+	    } else
+		break;
+	    child = child->next;
+	} while (child != NULL);
+	/*
+	* Parse the sequece constructor.
+	*/
+	if (child != NULL)
+	    xsltParseSequenceConstructor(cctxt, child);
+    }    
+    goto exit;
+
+sequence_constructor:
+    /*
+    * Parse the sequence constructor.
+    */
+    if (elem->children != NULL)
+	xsltParseSequenceConstructor(cctxt, elem->children);
+
+    /*
+    * Register information for vars/params. Only needed if there
+    * are any following siblings.
+    */
+    if ((elem->next != NULL) &&
+	((cctxt->inode->type == XSLT_FUNC_VARIABLE) ||
+	 (cctxt->inode->type == XSLT_FUNC_PARAM)))
+    {	
+	if ((elem->psvi != NULL) &&
+	    (((xsltStyleBasicItemVariablePtr) elem->psvi)->name))
+	{	
+	    xsltCompilerVarInfoPush(cctxt, elem,
+		((xsltStyleBasicItemVariablePtr) elem->psvi)->name,
+		((xsltStyleBasicItemVariablePtr) elem->psvi)->ns);
+	}
+    }
+
+error:
+exit:
+    xsltCompilerNodePop(cctxt, elem);
+    return(0);
+
+internal_err:
+    xsltCompilerNodePop(cctxt, elem);
+    return(-1);
+}
+
+/**
+ * xsltForwardsCompatUnkownItemCreate:
+ *
+ * @cctxt: the compilation context 
+ *
+ * Creates a compiled representation of the unknown
+ * XSLT instruction.
+ *
+ * Returns the compiled representation.
+ */ 
+static xsltStyleItemUknownPtr
+xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
+{
+    xsltStyleItemUknownPtr item;
+
+    item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
+    if (item == NULL) {
+	xsltTransformError(NULL, cctxt->style, NULL,
+	    "Internal error in xsltForwardsCompatUnkownItemCreate(): "
+	    "Failed to allocate memory.\n");
+	cctxt->style->errors++;
+	return(NULL);
+    }
+    memset(item, 0, sizeof(xsltStyleItemUknown));
+    item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
+    /*
+    * Store it in the stylesheet.
+    */
+    item->next = cctxt->style->preComps;
+    cctxt->style->preComps = (xsltElemPreCompPtr) item;
+    return(item);
+}
+
+/**
+ * xsltParseUnknownXSLTElem:
+ *
+ * @cctxt: the compilation context
+ * @node: the element of the unknown XSLT instruction
+ *
+ * Parses an unknown XSLT element.
+ * If forwards compatible mode is enabled this will allow
+ * such an unknown XSLT and; otherwise it is rejected.
+ *
+ * Returns 1 in the unknown XSLT instruction is rejected,
+ *         0 if everything's fine and
+ *         -1 on API or internal errors.
+ */ 
+static int
+xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
+			    xmlNodePtr node)
+{
+    if ((cctxt == NULL) || (node == NULL))
+	return(-1);
+
+    /*
+    * Detection of handled content of extension instructions.
+    */
+    if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
+	cctxt->inode->extContentHandled = 1;
+    }    
+    if (cctxt->inode->forwardsCompat == 0) {	
+	/*
+	* We are not in forwards-compatible mode, so raise an error.
+	*/
+	xsltTransformError(NULL, cctxt->style, node,
+	    "Unknown XSLT element '%s'.\n", node->name);
+	cctxt->style->errors++;
+	return(1);
+    }
+    /*
+    * Forwards-compatible mode.
+    * ------------------------
+    *    
+    * Parse/compile xsl:fallback elements.
+    *
+    * QUESTION: Do we have to raise an error if there's no xsl:fallback?
+    * ANSWER: No, since in the stylesheet the fallback behaviour might
+    *  also be provided by using the XSLT function "element-available".
+    */
+    if (cctxt->unknownItem == NULL) {
+	/*
+	* Create a singleton for all unknown XSLT instructions.
+	*/
+	cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
+	if (cctxt->unknownItem == NULL) {
+	    node->psvi = NULL;
+	    return(-1);
+	}
+    }
+    node->psvi = cctxt->unknownItem;
+    if (node->children == NULL)
+	return(0);
+    else {
+	xmlNodePtr child = node->children;
+
+	xsltCompilerNodePush(cctxt, node);
+	/*
+	* Update the in-scope namespaces if needed.
+	*/
+	if (node->nsDef != NULL)
+	    cctxt->inode->inScopeNs =
+		xsltCompilerBuildInScopeNsList(cctxt, node);
+	/*
+	* Parse all xsl:fallback children.
+	*/
+	do {
+	    if ((child->type == XML_ELEMENT_NODE) &&
+		IS_XSLT_ELEM_FAST(child) &&
+		IS_XSLT_NAME(child, "fallback"))
+	    {
+		cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
+		xsltParseAnyXSLTElem(cctxt, child);
+	    }
+	    child = child->next;
+	} while (child != NULL);
+	
+	xsltCompilerNodePop(cctxt, node);
+    }
+    return(0);
+}
+
+/**
+ * xsltParseSequenceConstructor:
+ *
+ * @cctxt: the compilation context
+ * @cur: the start-node of the content to be parsed
+ *
+ * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
+ * This will additionally remove xsl:text elements from the tree.
+ */ 
+void
+xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
+{
+    xsltStyleType type;
+    xmlNodePtr deleteNode = NULL;
+
+    if (cctxt == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+	    "xsltParseSequenceConstructor: Bad arguments\n");
+	cctxt->style->errors++;
+	return;
+    }
+    /*
+    * Detection of handled content of extension instructions.
+    */
+    if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
+	cctxt->inode->extContentHandled = 1;
+    }
+    if (cur == NULL)
+	return;
+    /*
+    * This is the content reffered to as a "template".
+    * E.g. an xsl:element has such content model:
+    * <xsl:element
+    *   name = { qname }
+    *   namespace = { uri-reference }
+    *   use-attribute-sets = qnames>
+    * <!-- Content: template -->
+    *
+    * NOTE that in XSLT-2 the term "template" was abandoned due to
+    *  confusion with xsl:template and the term "sequence constructor"
+    *  was introduced instead.
+    *
+    * The following XSLT-instructions are allowed to appear:
+    *  xsl:apply-templates, xsl:call-template, xsl:apply-imports,
+    *  xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
+    *  xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
+    *  xsl:message, xsl:fallback,
+    *  xsl:processing-instruction, xsl:comment, xsl:element
+    *  xsl:attribute. 
+    * Additional allowed content:
+    * 1) extension instructions
+    * 2) literal result elements
+    * 3) PCDATA
+    *
+    * NOTE that this content model does *not* allow xsl:param.
+    */    
+    while (cur != NULL) {
+	if (deleteNode != NULL)	{
+#ifdef WITH_XSLT_DEBUG_BLANKS
+	    xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltParseSequenceConstructor: removing xsl:text element\n");
+#endif
+	    xmlUnlinkNode(deleteNode);
+	    xmlFreeNode(deleteNode);
+	    deleteNode = NULL;
+	}
+	if (cur->type == XML_ELEMENT_NODE) {	    
+	    
+	    if (cur->psvi == xsltXSLTTextMarker) {
+		/*
+		* xsl:text elements
+		* --------------------------------------------------------
+		*/
+		xmlNodePtr tmp;
+
+		cur->psvi = NULL;
+		/*
+		* Mark the xsl:text element for later deletion.
+		*/
+		deleteNode = cur;
+		/*
+		* Validate content.
+		*/
+		tmp = cur->children;
+		if (tmp) {
+		    /*
+		    * We don't expect more than one text-node in the
+		    * content, since we already merged adjacent
+		    * text/CDATA-nodes and eliminated PI/comment-nodes.
+		    */
+		    if ((tmp->type == XML_TEXT_NODE) ||
+			(tmp->next == NULL))
+		    {
+			/*
+			* Leave the contained text-node in the tree.
+			*/
+			xmlUnlinkNode(tmp);
+			xmlAddPrevSibling(cur, tmp);
+		    } else {
+			tmp = NULL;
+			xsltTransformError(NULL, cctxt->style, cur,
+			    "Element 'xsl:text': Invalid type "
+			    "of node found in content.\n");
+			cctxt->style->errors++;
+		    } 
+		}
+		if (cur->properties) {
+		    xmlAttrPtr attr;
+		    /*
+		    * TODO: We need to report errors for
+		    *  invalid attrs.
+		    */
+		    attr = cur->properties;
+		    do {
+			if ((attr->ns == NULL) &&
+			    (attr->name != NULL) &&
+			    (attr->name[0] == 'd') &&
+			    xmlStrEqual(attr->name,
+			    BAD_CAST "disable-output-escaping"))
+			{
+			    /*
+			    * Attr "disable-output-escaping".
+			    * XSLT-2: This attribute is deprecated.
+			    */
+			    if ((attr->children != NULL) &&
+				xmlStrEqual(attr->children->content,
+				BAD_CAST "yes"))
+			    {
+				/*
+				* Disable output escaping for this
+				* text node.
+				*/
+				if (tmp)
+				    tmp->name = xmlStringTextNoenc;
+			    } else if ((attr->children == NULL) ||
+				(attr->children->content == NULL) ||
+				(!xmlStrEqual(attr->children->content,
+				BAD_CAST "no")))
+			    {
+				xsltTransformError(NULL, cctxt->style,
+				    cur,
+				    "Attribute 'disable-output-escaping': "
+				    "Invalid value. Expected is "
+				    "'yes' or 'no'.\n");
+				cctxt->style->errors++;
+			    }
+			    break;
+			}
+			attr = attr->next;
+		    } while (attr != NULL);
+		}
+	    } else if (IS_XSLT_ELEM_FAST(cur)) {
+		/*
+		* TODO: Using the XSLT-marker is still not stable yet.
+		*/
+		/* if (cur->psvi == xsltXSLTElemMarker) { */	    
+		/*
+		* XSLT instructions
+		* --------------------------------------------------------
+		*/
+		cur->psvi = NULL;
+		type = xsltGetXSLTElementTypeByNode(cctxt, cur);
+		switch (type) {
+		    case XSLT_FUNC_APPLYIMPORTS:
+		    case XSLT_FUNC_APPLYTEMPLATES:
+		    case XSLT_FUNC_ATTRIBUTE:
+		    case XSLT_FUNC_CALLTEMPLATE:
+		    case XSLT_FUNC_CHOOSE:
+		    case XSLT_FUNC_COMMENT:
+		    case XSLT_FUNC_COPY:
+		    case XSLT_FUNC_COPYOF:
+		    case XSLT_FUNC_DOCUMENT: /* Extra one */
+		    case XSLT_FUNC_ELEMENT:
+		    case XSLT_FUNC_FALLBACK:
+		    case XSLT_FUNC_FOREACH:
+		    case XSLT_FUNC_IF:
+		    case XSLT_FUNC_MESSAGE:
+		    case XSLT_FUNC_NUMBER:
+		    case XSLT_FUNC_PI:
+		    case XSLT_FUNC_TEXT:
+		    case XSLT_FUNC_VALUEOF:
+		    case XSLT_FUNC_VARIABLE:
+			/*
+			* Parse the XSLT element.
+			*/
+			cctxt->inode->curChildType = type;
+			xsltParseAnyXSLTElem(cctxt, cur);
+			break;
+		    default:
+			xsltParseUnknownXSLTElem(cctxt, cur);			
+			cur = cur->next;
+			continue;
+		}
+	    } else {
+		/*
+		* Non-XSLT elements
+		* -----------------
+		*/
+		xsltCompilerNodePush(cctxt, cur);
+		/*
+		* Update the in-scope namespaces if needed.
+		*/
+		if (cur->nsDef != NULL)
+		    cctxt->inode->inScopeNs =
+			xsltCompilerBuildInScopeNsList(cctxt, cur);
+		/*
+		* The current element is either a literal result element
+		* or an extension instruction.
+		*
+		* Process attr "xsl:extension-element-prefixes".
+		* FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
+		* processed by the implementor of the extension function;
+		* i.e., it won't be handled by the XSLT processor.
+		*/
+		/* SPEC 1.0:
+		*   "exclude-result-prefixes" is only allowed on literal
+		*   result elements and "xsl:exclude-result-prefixes"
+		*   on xsl:stylesheet/xsl:transform.
+		* SPEC 2.0:
+		*   "There are a number of standard attributes
+		*   that may appear on any XSLT element: specifically
+		*   version, exclude-result-prefixes,
+		*   extension-element-prefixes, xpath-default-namespace,
+		*   default-collation, and use-when."
+		*
+		* SPEC 2.0:
+		*   For literal result elements:
+		*   "xsl:version, xsl:exclude-result-prefixes,
+		*    xsl:extension-element-prefixes,
+		*    xsl:xpath-default-namespace,
+		*    xsl:default-collation, or xsl:use-when."
+		*/
+		if (cur->properties)
+		    cctxt->inode->extElemNs =
+			xsltParseExtElemPrefixes(cctxt,
+			    cur, cctxt->inode->extElemNs,
+			    XSLT_ELEMENT_CATEGORY_LRE);
+		/*
+		* Eval if we have an extension instruction here.
+		*/
+		if ((cur->ns != NULL) &&
+		    (cctxt->inode->extElemNs != NULL) &&
+		    (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
+		{
+		    /*
+		    * Extension instructions
+		    * ----------------------------------------------------
+		    * Mark the node information.
+		    */
+		    cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
+		    cctxt->inode->extContentHandled = 0;
+		    if (cur->psvi != NULL) {
+			cur->psvi = NULL;
+			/*
+			* TODO: Temporary sanity check.
+			*/
+			xsltTransformError(NULL, cctxt->style, cur,
+			    "Internal error in xsltParseSequenceConstructor(): "
+			    "Occupied PSVI field.\n");
+			cctxt->style->errors++;
+			cur = cur->next;
+			continue;
+		    }
+		    cur->psvi = (void *)
+			xsltPreComputeExtModuleElement(cctxt->style, cur);
+		    
+		    if (cur->psvi == NULL) {
+			/*
+			* OLD COMMENT: "Unknown element, maybe registered
+			*  at the context level. Mark it for later
+			*  recognition."
+			* QUESTION: What does the xsltExtMarker mean?
+			*  ANSWER: It is used in
+			*   xsltApplySequenceConstructor() at
+			*   transformation-time to look out for extension
+			*   registered in the transformation context.
+			*/
+			cur->psvi = (void *) xsltExtMarker;
+		    }
+		    /*
+		    * BIG NOTE: Now the ugly part. In previous versions
+		    *  of Libxslt (until 1.1.16), all the content of an
+		    *  extension instruction was processed and compiled without
+		    *  the need of the extension-author to explicitely call
+		    *  such a processing;.We now need to mimic this old
+		    *  behaviour in order to avoid breaking old code
+		    *  on the extension-author's side.
+		    * The mechanism:
+		    *  1) If the author does *not* set the
+		    *    compile-time-flag @extContentHandled, then we'll
+		    *    parse the content assuming that it's a "template"
+		    *    (or "sequence constructor in XSLT 2.0 terms).
+		    *    NOTE: If the extension is registered at
+		    *    transformation-time only, then there's no way of
+		    *    knowing that content shall be valid, and we'll
+		    *    process the content the same way.
+		    *  2) If the author *does* set the flag, then we'll assume
+		    *   that the author has handled the parsing him/herself
+		    *   (e.g. called xsltParseSequenceConstructor(), etc.
+		    *   explicitely in his/her code).
+		    */
+		    if ((cur->children != NULL) &&
+			(cctxt->inode->extContentHandled == 0))
+		    {
+			/*
+			* Default parsing of the content using the
+			* sequence-constructor model.
+			*/
+			xsltParseSequenceConstructor(cctxt, cur->children);
+		    }
+		} else {
+		    /*
+		    * Literal result element
+		    * ----------------------------------------------------
+		    * Allowed XSLT attributes:
+		    *  xsl:extension-element-prefixes CDATA #IMPLIED
+		    *  xsl:exclude-result-prefixes CDATA #IMPLIED
+		    *  TODO: xsl:use-attribute-sets %qnames; #IMPLIED
+		    *  xsl:version NMTOKEN #IMPLIED
+		    */
+		    cur->psvi = NULL;
+		    cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
+		    if (cur->properties != NULL) {
+			xmlAttrPtr attr = cur->properties;
+			/*
+			* Attribute "xsl:exclude-result-prefixes".
+			*/
+			cctxt->inode->exclResultNs =
+			    xsltParseExclResultPrefixes(cctxt, cur,
+				cctxt->inode->exclResultNs,
+				XSLT_ELEMENT_CATEGORY_LRE);
+			/*
+			* Attribute "xsl:version".
+			*/
+			xsltParseAttrXSLTVersion(cctxt, cur,
+			    XSLT_ELEMENT_CATEGORY_LRE);
+			/*
+			* Report invalid XSLT attributes.			
+			* For XSLT 1.0 only xsl:use-attribute-sets is allowed
+			* next to xsl:version, xsl:exclude-result-prefixes and
+			* xsl:extension-element-prefixes.
+			*
+			* Mark all XSLT attributes, in order to skip such
+			* attributes when instantiating the LRE.
+			*/
+			do {
+			    if ((attr->psvi != xsltXSLTAttrMarker) &&
+				IS_XSLT_ATTR_FAST(attr))
+			    {				    
+				if (! xmlStrEqual(attr->name,
+				    BAD_CAST "use-attribute-sets"))
+				{				
+				    xsltTransformError(NULL, cctxt->style,
+					cur,
+					"Unknown XSLT attribute '%s'.\n",
+					attr->name);
+				    cctxt->style->errors++;
+				} else {
+				    /*
+				    * XSLT attr marker.
+				    */
+				    attr->psvi = (void *) xsltXSLTAttrMarker;
+				}
+			    }
+			    attr = attr->next;
+			} while (attr != NULL);
+		    }
+		    /*
+		    * Create/reuse info for the literal result element.
+		    */
+		    if (cctxt->inode->nsChanged)
+			xsltLREInfoCreate(cctxt, cur, 1);
+		    cur->psvi = cctxt->inode->litResElemInfo;
+		    /*
+		    * Apply ns-aliasing on the element and on its attributes.
+		    */
+		    if (cctxt->hasNsAliases)
+			xsltLREBuildEffectiveNs(cctxt, cur);
+		    /*
+		    * Compile attribute value templates (AVT).
+		    */
+		    if (cur->properties) {
+			xmlAttrPtr attr = cur->properties;
+			
+			while (attr != NULL) {
+			    xsltCompileAttr(cctxt->style, attr);
+			    attr = attr->next;
+			}
+		    }
+		    /*
+		    * Parse the content, which is defined to be a "template"
+		    * (or "sequence constructor" in XSLT 2.0 terms).
+		    */
+		    if (cur->children != NULL) {
+			xsltParseSequenceConstructor(cctxt, cur->children);
+		    }
+		}
+		/*
+		* Leave the non-XSLT element.
+		*/
+		xsltCompilerNodePop(cctxt, cur);
+	    }
+	}
+	cur = cur->next;
+    }
+    if (deleteNode != NULL) {
+#ifdef WITH_XSLT_DEBUG_BLANKS
+	xsltGenericDebug(xsltGenericDebugContext,
+	    "xsltParseSequenceConstructor: removing xsl:text element\n");
+#endif
+	xmlUnlinkNode(deleteNode);
+	xmlFreeNode(deleteNode);
+	deleteNode = NULL;
+    }
+}
+
+/**
+ * xsltParseTemplateContent:
+ * @style:  the XSLT stylesheet
+ * @templ:  the node containing the content to be parsed
+ *
+ * Parses and compiles the content-model of an xsl:template element.
+ * Note that this is *not* the "template" content model (or "sequence
+ *  constructor" in XSLT 2.0); it it allows addional xsl:param
+ *  elements as immediate children of @templ.
+ *
+ * Called by: 
+ *   exsltFuncFunctionComp() (EXSLT, functions.c)
+ *   So this is intended to be called from extension functions.
+ */
+void
+xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
+    if ((style == NULL) || (templ == NULL))
+	return;
+
+    /*
+    * Detection of handled content of extension instructions.
+    */
+    if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
+	XSLT_CCTXT(style)->inode->extContentHandled = 1;
+    }
+
+    if (templ->children != NULL) {	
+	xmlNodePtr child = templ->children;
+	/*
+	* Process xsl:param elements, which can only occur as the
+	* immediate children of xsl:template (well, and of any
+	* user-defined extension instruction if needed).
+	*/	
+	do {
+	    if ((child->type == XML_ELEMENT_NODE) &&
+		IS_XSLT_ELEM_FAST(child) &&
+		IS_XSLT_NAME(child, "param"))
+	    {
+		XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
+		xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
+	    } else
+		break;
+	    child = child->next;
+	} while (child != NULL);
+	/*
+	* Parse the content and register the pattern.
+	*/
+	xsltParseSequenceConstructor(XSLT_CCTXT(style), child);
+    }
+}
+
+#else /* XSLT_REFACTORED */
+
+/**
+ * xsltParseTemplateContent:
+ * @style:  the XSLT stylesheet
+ * @templ:  the container node (can be a document for literal results)
+ *
+ * parse a template content-model
+ * Clean-up the template content from unwanted ignorable blank nodes
+ * and process xslt:text
+ */
+void
+xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
+    xmlNodePtr cur, delete;
+    /*
+     * This content comes from the stylesheet
+     * For stylesheets, the set of whitespace-preserving
+     * element names consists of just xsl:text.
+     */
+    cur = templ->children;
+    delete = NULL;
+    while (cur != NULL) {
+	if (delete != NULL) {
+#ifdef WITH_XSLT_DEBUG_BLANKS
+	    xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltParseTemplateContent: removing text\n");
+#endif
+	    xmlUnlinkNode(delete);
+	    xmlFreeNode(delete);
+	    delete = NULL;
+	}
+	if (IS_XSLT_ELEM(cur)) {
+	    if (IS_XSLT_NAME(cur, "text")) {
+		/*
+		* TODO: Processing of xsl:text should be moved to
+		*   xsltPrecomputeStylesheet(), since otherwise this
+		*   will be performed for every multiply included
+		*   stylesheet; i.e. this here is not skipped with
+		*   the use of the style->nopreproc flag.
+		*/
+		if (cur->children != NULL) {
+		    xmlChar *prop;
+		    xmlNodePtr text = cur->children, next;
+		    int noesc = 0;
+			
+		    prop = xmlGetNsProp(cur,
+			(const xmlChar *)"disable-output-escaping",
+			NULL);
+		    if (prop != NULL) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+			xsltGenericDebug(xsltGenericDebugContext,
+			     "Disable escaping: %s\n", text->content);
+#endif
+			if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
+			    noesc = 1;
+			} else if (!xmlStrEqual(prop,
+						(const xmlChar *)"no")){
+			    xsltTransformError(NULL, style, cur,
+	     "xsl:text: disable-output-escaping allows only yes or no\n");
+			    style->warnings++;
+
+			}
+			xmlFree(prop);
+		    }
+
+		    while (text != NULL) {
+			if (text->type == XML_COMMENT_NODE) {
+			    text = text->next;
+			    continue;
+			}
+			if ((text->type != XML_TEXT_NODE) &&
+			     (text->type != XML_CDATA_SECTION_NODE)) {
+			    xsltTransformError(NULL, style, cur,
+		 "xsltParseTemplateContent: xslt:text content problem\n");
+			    style->errors++;
+			    break;
+			}
+			if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
+			    text->name = xmlStringTextNoenc;
+			text = text->next;
+		    }
+
+		    /*
+		     * replace xsl:text by the list of childs
+		     */
+		    if (text == NULL) {
+			text = cur->children;
+			while (text != NULL) {
+			    if ((style->internalized) &&
+			        (text->content != NULL) &&
+			        (!xmlDictOwns(style->dict, text->content))) {
+
+				/*
+				 * internalize the text string
+				 */
+				if (text->doc->dict != NULL) {
+				    const xmlChar *tmp;
+				    
+				    tmp = xmlDictLookup(text->doc->dict,
+				                        text->content, -1);
+				    if (tmp != text->content) {
+				        xmlNodeSetContent(text, NULL);
+					text->content = (xmlChar *) tmp;
+				    }
+				}
+			    }
+
+			    next = text->next;
+			    xmlUnlinkNode(text);
+			    xmlAddPrevSibling(cur, text);
+			    text = next;
+			}
+		    }
+		}
+		delete = cur;
+		goto skip_children;
+	    }
+	}
+	else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
+	    (xsltCheckExtPrefix(style, cur->ns->prefix)))
+	{
+	    /*
+	     * okay this is an extension element compile it too
+	     */
+	    xsltStylePreCompute(style, cur);
+	}
+	else if (cur->type == XML_ELEMENT_NODE)
+	{
+	    /*
+	     * This is an element which will be output as part of the
+	     * template exectution, precompile AVT if found.
+	     */
+	    if ((cur->ns == NULL) && (style->defaultAlias != NULL)) {
+		cur->ns = xmlSearchNsByHref(cur->doc, cur,
+			style->defaultAlias);
+	    }
+	    if (cur->properties != NULL) {
+	        xmlAttrPtr attr = cur->properties;
+
+		while (attr != NULL) {
+		    xsltCompileAttr(style, attr);
+		    attr = attr->next;
+		}
+	    }
+	}
+	/*
+	 * Skip to next node
+	 */
+	if (cur->children != NULL) {
+	    if (cur->children->type != XML_ENTITY_DECL) {
+		cur = cur->children;
+		continue;
+	    }
+	}
+skip_children:
+	if (cur->next != NULL) {
+	    cur = cur->next;
+	    continue;
+	}
+	
+	do {
+	    cur = cur->parent;
+	    if (cur == NULL)
+		break;
+	    if (cur == templ) {
+		cur = NULL;
+		break;
+	    }
+	    if (cur->next != NULL) {
+		cur = cur->next;
+		break;
+	    }
+	} while (cur != NULL);
+    }
+    if (delete != NULL) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+	xsltGenericDebug(xsltGenericDebugContext,
+	 "xsltParseTemplateContent: removing text\n");
+#endif
+	xmlUnlinkNode(delete);
+	xmlFreeNode(delete);
+	delete = NULL;
+    }
+
+    /*
+     * Skip the first params
+     */
+    cur = templ->children;
+    while (cur != NULL) {
+	if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
+	    break;
+	cur = cur->next;
+    }
+
+    /*
+     * Browse the remainder of the template
+     */
+    while (cur != NULL) {
+	if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
+	    xmlNodePtr param = cur;
+
+	    xsltTransformError(NULL, style, cur,
+		"xsltParseTemplateContent: ignoring misplaced param element\n");
+	    if (style != NULL) style->warnings++;
+            cur = cur->next;
+	    xmlUnlinkNode(param);
+	    xmlFreeNode(param);
+	} else
+	    break;
+    }
+}
+
+#endif /* else XSLT_REFACTORED */
+
+/**
+ * xsltParseStylesheetKey:
+ * @style:  the XSLT stylesheet
+ * @key:  the "key" element
+ *
+ * <!-- Category: top-level-element -->
+ * <xsl:key name = qname, match = pattern, use = expression />
+ *
+ * parse an XSLT stylesheet key definition and register it
+ */
+
+static void
+xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
+    xmlChar *prop = NULL;
+    xmlChar *use = NULL;
+    xmlChar *match = NULL;
+    xmlChar *name = NULL;
+    xmlChar *nameURI = NULL;
+
+    if ((style == NULL) || (key == NULL))
+	return;
+
+    /*
+     * Get arguments
+     */
+    prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
+    if (prop != NULL) {
+        const xmlChar *URI;
+
+	/*
+	* TODO: Don't use xsltGetQNameURI().
+	*/
+	URI = xsltGetQNameURI(key, &prop);
+	if (prop == NULL) {
+	    if (style != NULL) style->errors++;
+	    goto error;
+	} else {
+	    name = prop;
+	    if (URI != NULL)
+		nameURI = xmlStrdup(URI);
+	}
+#ifdef WITH_XSLT_DEBUG_PARSING
+	xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltParseStylesheetKey: name %s\n", name);
+#endif
+    } else {
+	xsltTransformError(NULL, style, key,
+	    "xsl:key : error missing name\n");
+	if (style != NULL) style->errors++;
+	goto error;
+    }
+
+    match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
+    if (match == NULL) {
+	xsltTransformError(NULL, style, key,
+	    "xsl:key : error missing match\n");
+	if (style != NULL) style->errors++;
+	goto error;
+    }
+
+    use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
+    if (use == NULL) {
+	xsltTransformError(NULL, style, key,
+	    "xsl:key : error missing use\n");
+	if (style != NULL) style->errors++;
+	goto error;
+    }
+
+    /*
+     * register the keys
+     */
+    xsltAddKey(style, name, nameURI, match, use, key);
+
+
+error:
+    if (use != NULL)
+	xmlFree(use);
+    if (match != NULL)
+	xmlFree(match);
+    if (name != NULL)
+	xmlFree(name);
+    if (nameURI != NULL)
+	xmlFree(nameURI);
+
+    if (key->children != NULL) {
+	xsltParseContentError(style, key->children);
+    }
+}
+
+#ifdef XSLT_REFACTORED
+/**
+ * xsltParseXSLTTemplate:
+ * @style:  the XSLT stylesheet
+ * @template:  the "template" element
+ *
+ * parse an XSLT stylesheet template building the associated structures
+ * TODO: Is @style ever expected to be NULL?
+ *
+ * Called from:
+ *   xsltParseXSLTStylesheet()
+ *   xsltParseStylesheetTop()
+ */
+
+static void
+xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
+    xsltTemplatePtr templ;
+    xmlChar *prop;    
+    double  priority;    
+
+    if ((cctxt == NULL) || (templNode == NULL))
+	return;
+
+    /*
+     * Create and link the structure
+     */
+    templ = xsltNewTemplate();
+    if (templ == NULL)
+	return;
+
+    xsltCompilerNodePush(cctxt, templNode);
+    if (templNode->nsDef != NULL)
+	cctxt->inode->inScopeNs =
+	    xsltCompilerBuildInScopeNsList(cctxt, templNode);
+
+    templ->next = cctxt->style->templates;
+    cctxt->style->templates = templ;
+    templ->style = cctxt->style;  
+
+    /*
+    * Attribute "mode".
+    */
+    prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);
+    if (prop != NULL) {	
+        const xmlChar *modeURI;
+
+	/*
+	* TODO: We need a standardized function for extraction
+	*  of namespace names and local names from QNames.
+	*  Don't use xsltGetQNameURI() as it cannot channeö
+	*  reports through the context.
+	*/
+	modeURI = xsltGetQNameURI(templNode, &prop);
+	if (prop == NULL) {
+	    cctxt->style->errors++;
+	    goto error;
+	}
+	templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);
+	xmlFree(prop);
+	prop = NULL;
+	if (xmlValidateNCName(templ->mode, 0)) {
+	    xsltTransformError(NULL, cctxt->style, templNode,
+		"xsl:template: Attribute 'mode': The local part '%s' "
+		"of the value is not a valid NCName.\n", templ->name);
+	    cctxt->style->errors++;
+	    goto error;
+	}
+	if (modeURI != NULL)
+	    templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);
+#ifdef WITH_XSLT_DEBUG_PARSING
+	xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltParseXSLTTemplate: mode %s\n", templ->mode);
+#endif
+    }
+    /*
+    * Attribute "match".
+    */
+    prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);
+    if (prop != NULL) {
+	templ->match  = prop;
+	prop = NULL;
+    }
+    /*
+    * Attribute "priority".
+    */
+    prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);
+    if (prop != NULL) {
+	priority = xmlXPathStringEvalNumber(prop);
+	templ->priority = (float) priority;
+	xmlFree(prop);
+	prop = NULL;
+    }
+    /*
+    * Attribute "name".
+    */
+    prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);
+    if (prop != NULL) {
+        const xmlChar *nameURI;
+	xsltTemplatePtr curTempl;
+	
+	/*
+	* TODO: Don't use xsltGetQNameURI().
+	*/
+	nameURI = xsltGetQNameURI(templNode, &prop);
+	if (prop == NULL) {
+	    cctxt->style->errors++;
+	    goto error;
+	}
+	templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);
+	xmlFree(prop);
+	prop = NULL;
+	if (xmlValidateNCName(templ->name, 0)) {
+	    xsltTransformError(NULL, cctxt->style, templNode,
+		"xsl:template: Attribute 'name': The local part '%s' of "
+		"the value is not a valid NCName.\n", templ->name);
+	    cctxt->style->errors++;
+	    goto error;
+	} 	
+	if (nameURI != NULL)
+	    templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);
+	curTempl = templ->next;
+	while (curTempl != NULL) {
+	    if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&
+		xmlStrEqual(curTempl->nameURI, nameURI) ) ||
+		(nameURI == NULL && curTempl->nameURI == NULL &&
+		xmlStrEqual(curTempl->name, templ->name)))
+	    {
+		xsltTransformError(NULL, cctxt->style, templNode,
+		    "xsl:template: error duplicate name '%s'\n", templ->name);
+		cctxt->style->errors++;
+		goto error;
+	    }
+	    curTempl = curTempl->next;
+	}
+    }
+    if (templNode->children != NULL) {
+	xsltParseTemplateContent(cctxt->style, templNode);	
+	/*
+	* MAYBE TODO: Custom behaviour: In order to stay compatible with
+	* Xalan and MSXML(.NET), we could allow whitespace
+	* to appear before an xml:param element; this whitespace
+	* will additionally become part of the "template".
+	* NOTE that this is totally deviates from the spec, but
+	* is the de facto behaviour of Xalan and MSXML(.NET).
+	* Personally I wouldn't allow this, since if we have:
+	* <xsl:template ...xml:space="preserve">
+	*   <xsl:param name="foo"/>
+	*   <xsl:param name="bar"/>
+	*   <xsl:param name="zoo"/>
+	* ... the whitespace between every xsl:param would be
+	* added to the result tree.
+	*/		
+    }    
+    
+    templ->elem = templNode;
+    templ->content = templNode->children;
+    xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI);
+
+error:
+    xsltCompilerNodePop(cctxt, templNode);
+    return;
+}
+
+#else /* XSLT_REFACTORED */
+
+/**
+ * xsltParseStylesheetTemplate:
+ * @style:  the XSLT stylesheet
+ * @template:  the "template" element
+ *
+ * parse an XSLT stylesheet template building the associated structures
+ */
+
+static void
+xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
+    xsltTemplatePtr ret;
+    xmlChar *prop;
+    xmlChar *mode = NULL;
+    xmlChar *modeURI = NULL;
+    double  priority;
+
+    if (template == NULL)
+	return;
+
+    /*
+     * Create and link the structure
+     */
+    ret = xsltNewTemplate();
+    if (ret == NULL)
+	return;
+    ret->next = style->templates;
+    style->templates = ret;
+    ret->style = style;
+   
+    /*
+     * Get inherited namespaces
+     */
+    /*
+    * TODO: Apply the optimized in-scope-namespace mechanism
+    *   as for the other XSLT instructions.
+    */
+    xsltGetInheritedNsList(style, ret, template);
+
+    /*
+     * Get arguments
+     */
+    prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);
+    if (prop != NULL) {
+        const xmlChar *URI;
+
+	/*
+	* TODO: Don't use xsltGetQNameURI().
+	*/
+	URI = xsltGetQNameURI(template, &prop);
+	if (prop == NULL) {
+	    if (style != NULL) style->errors++;
+	    goto error;
+	} else {
+	    mode = prop;
+	    if (URI != NULL)
+		modeURI = xmlStrdup(URI);
+	}
+	ret->mode = xmlDictLookup(style->dict, mode, -1);
+	ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);
+#ifdef WITH_XSLT_DEBUG_PARSING
+	xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltParseStylesheetTemplate: mode %s\n", mode);
+#endif
+        if (mode != NULL) xmlFree(mode);
+	if (modeURI != NULL) xmlFree(modeURI);
+    }
+    prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);
+    if (prop != NULL) {
+	if (ret->match != NULL) xmlFree(ret->match);
+	ret->match  = prop;
+    }
+
+    prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);
+    if (prop != NULL) {
+	priority = xmlXPathStringEvalNumber(prop);
+	ret->priority = (float) priority;
+	xmlFree(prop);
+    }
+
+    prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);
+    if (prop != NULL) {
+        const xmlChar *URI;
+	xsltTemplatePtr cur;
+	
+	/*
+	* TODO: Don't use xsltGetQNameURI().
+	*/
+	URI = xsltGetQNameURI(template, &prop);
+	if (prop == NULL) {
+	    if (style != NULL) style->errors++;
+	    goto error;
+	} else {
+	    if (xmlValidateNCName(prop,0)) {
+	        xsltTransformError(NULL, style, template,
+	            "xsl:template : error invalid name '%s'\n", prop);
+		if (style != NULL) style->errors++;
+		goto error;
+	    }
+	    ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
+	    xmlFree(prop);
+	    prop = NULL;
+	    if (URI != NULL)
+		ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);
+	    else
+		ret->nameURI = NULL;
+	    cur = ret->next;
+	    while (cur != NULL) {
+	        if ((URI != NULL && xmlStrEqual(cur->name, ret->name) &&
+				xmlStrEqual(cur->nameURI, URI) ) ||
+		    (URI == NULL && cur->nameURI == NULL &&
+				xmlStrEqual(cur->name, ret->name))) {
+		    xsltTransformError(NULL, style, template,
+		        "xsl:template: error duplicate name '%s'\n", ret->name);
+		    style->errors++;
+		    goto error;
+		}
+		cur = cur->next;
+	    }
+	}
+    }
+
+    /*
+     * parse the content and register the pattern
+     */
+    xsltParseTemplateContent(style, template);
+    ret->elem = template;
+    ret->content = template->children;
+    xsltAddTemplate(style, ret, ret->mode, ret->modeURI);
+
+error:
+    return;
+}
+
+#endif /* else XSLT_REFACTORED */
+
+#ifdef XSLT_REFACTORED
+
+/**
+ * xsltIncludeComp:
+ * @cctxt: the compilation contenxt
+ * @node:  the xsl:include node
+ *
+ * Process the xslt include node on the source node
+ */
+static xsltStyleItemIncludePtr
+xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) {
+    xsltStyleItemIncludePtr item;
+
+    if ((cctxt == NULL) || (node == NULL))
+	return(NULL);
+
+    node->psvi = NULL;
+    item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude));
+    if (item == NULL) {
+	xsltTransformError(NULL, cctxt->style, node,
+		"xsltIncludeComp : malloc failed\n");
+	cctxt->style->errors++;
+	return(NULL);
+    }
+    memset(item, 0, sizeof(xsltStyleItemInclude));
+
+    node->psvi = item;
+    item->inst = node;
+    item->type = XSLT_FUNC_INCLUDE;
+
+    item->next = cctxt->style->preComps;
+    cctxt->style->preComps = (xsltElemPreCompPtr) item;
+
+    return(item);
+}
+
+/**
+ * xsltParseFindTopLevelElem:
+ */
+static int
+xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,
+			      xmlNodePtr cur,
+			      const xmlChar *name,
+			      const xmlChar *namespaceURI,
+			      int breakOnOtherElem,			      
+			      xmlNodePtr *resultNode)
+{
+    if (name == NULL)
+	return(-1);
+
+    *resultNode = NULL;
+    while (cur != NULL) {
+	if (cur->type == XML_ELEMENT_NODE) {
+	    if ((cur->ns != NULL) && (cur->name != NULL)) {
+		if ((*(cur->name) == *name) &&
+		    xmlStrEqual(cur->name, name) &&
+		    xmlStrEqual(cur->ns->href, namespaceURI))		    
+		{
+		    *resultNode = cur;
+		    return(1);
+		}
+	    }
+	    if (breakOnOtherElem)
+		break;
+	}
+	cur = cur->next;
+    }
+    *resultNode = cur;
+    return(0);
+}
+
+static int
+xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,
+			  xmlNodePtr node,
+			  xsltStyleType type)
+{
+    int ret = 0;
+
+    /*
+    * TODO: The reason why this function exists:
+    *  due to historical reasons some of the
+    *  top-level declarations are processed by functions
+    *  in other files. Since we need still to set
+    *  up the node-info and generate information like
+    *  in-scope namespaces, this is a wrapper around
+    *  those old parsing functions.
+    */
+    xsltCompilerNodePush(cctxt, node);
+    if (node->nsDef != NULL)
+	cctxt->inode->inScopeNs =
+	    xsltCompilerBuildInScopeNsList(cctxt, node);
+    cctxt->inode->type = type;
+
+    switch (type) {
+	case XSLT_FUNC_INCLUDE:
+	    {
+		int oldIsInclude;
+
+		if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL)
+		    goto exit;		
+		/*
+		* Mark this stylesheet tree as being currently included.
+		*/
+		oldIsInclude = cctxt->isInclude;
+		cctxt->isInclude = 1;
+						
+		if (xsltParseStylesheetInclude(cctxt->style, node) != 0) {
+		    cctxt->style->errors++;
+		}
+		cctxt->isInclude = oldIsInclude;
+	    }
+	    break;
+	case XSLT_FUNC_PARAM:
+	    xsltStylePreCompute(cctxt->style, node);
+	    xsltParseGlobalParam(cctxt->style, node);
+	    break;
+	case XSLT_FUNC_VARIABLE:
+	    xsltStylePreCompute(cctxt->style, node);
+	    xsltParseGlobalVariable(cctxt->style, node);
+	    break;
+	case XSLT_FUNC_ATTRSET:
+	    xsltParseStylesheetAttributeSet(cctxt->style, node);
+	    break;
+	default:
+	    xsltTransformError(NULL, cctxt->style, node,
+		"Internal error: (xsltParseTopLevelXSLTElem) "
+		"Cannot handle this top-level declaration.\n");
+	    cctxt->style->errors++;
+	    ret = -1;
+    }
+
+exit:
+    xsltCompilerNodePop(cctxt, node);
+
+    return(ret);
+}
+
+#if 0
+static int
+xsltParseRemoveWhitespace(xmlNodePtr node)
+{
+    if ((node == NULL) || (node->children == NULL))
+	return(0);
+    else {
+	xmlNodePtr delNode = NULL, child = node->children;
+
+	do {
+	    if (delNode) {
+		xmlUnlinkNode(delNode);
+		xmlFreeNode(delNode);
+		delNode = NULL;
+	    }
+	    if (((child->type == XML_TEXT_NODE) ||
+		 (child->type == XML_CDATA_SECTION_NODE)) &&
+		(IS_BLANK_NODE(child)))
+		delNode = child;	    
+	    child = child->next;
+	} while (child != NULL);
+	if (delNode) {
+	    xmlUnlinkNode(delNode);
+	    xmlFreeNode(delNode);
+	    delNode = NULL;
+	}
+    }
+    return(0);
+}
+#endif
+
+static int
+xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
+{
+#ifdef WITH_XSLT_DEBUG_PARSING
+    int templates = 0;
+#endif
+    xmlNodePtr cur, start = NULL;
+    xsltStylesheetPtr style;
+
+    if ((cctxt == NULL) || (node == NULL) ||
+	(node->type != XML_ELEMENT_NODE))
+	return(-1);    
+
+    style = cctxt->style;    
+    /*
+    * At this stage all import declarations of all stylesheet modules
+    * with the same stylesheet level have been processed.
+    * Now we can safely parse the rest of the declarations.
+    */
+    if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include"))
+    {
+	xsltDocumentPtr include;
+	/*
+	* URGENT TODO: Make this work with simplified stylesheets!
+	*   I.e., when we won't find an xsl:stylesheet element.
+	*/
+	/*
+	* This is as include declaration.
+	*/
+	include = ((xsltStyleItemIncludePtr) node->psvi)->include;
+	if (include == NULL) {
+	    /* TODO: raise error? */
+	    return(-1);
+	}
+	/*
+	* TODO: Actually an xsl:include should locate an embedded
+	*  stylesheet as well; so the document-element won't always
+	*  be the element where the actual stylesheet is rooted at.
+	*  But such embedded stylesheets are not supported by Libxslt yet.
+	*/
+	node = xmlDocGetRootElement(include->doc);
+	if (node == NULL) {
+	    return(-1);
+	}
+    }    
+    
+    if (node->children == NULL)
+	return(0);
+    /*
+    * Push the xsl:stylesheet/xsl:transform element.
+    */  
+    xsltCompilerNodePush(cctxt, node);
+    cctxt->inode->isRoot = 1;
+    cctxt->inode->nsChanged = 0;
+    /*
+    * Start with the naked dummy info for literal result elements.
+    */
+    cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;
+
+    /*
+    * In every case, we need to have
+    * the in-scope namespaces of the element, where the
+    * stylesheet is rooted at, regardless if it's an XSLT
+    * instruction or a literal result instruction (or if
+    * this is an embedded stylesheet).
+    */		
+    cctxt->inode->inScopeNs =
+	xsltCompilerBuildInScopeNsList(cctxt, node);
+
+    /*
+    * Process attributes of xsl:stylesheet/xsl:transform.
+    * --------------------------------------------------
+    * Allowed are:
+    *  id = id
+    *  extension-element-prefixes = tokens
+    *  exclude-result-prefixes = tokens
+    *  version = number (mandatory)    
+    */
+    if (xsltParseAttrXSLTVersion(cctxt, node,
+	XSLT_ELEMENT_CATEGORY_XSLT) == 0)
+    {    
+	/*
+	* Attribute "version".
+	* XSLT 1.0: "An xsl:stylesheet element *must* have a version
+	*  attribute, indicating the version of XSLT that the
+	*  stylesheet requires".
+	* The root element of a simplified stylesheet must also have
+	* this attribute.
+	*/
+#ifdef XSLT_REFACTORED_MANDATORY_VERSION
+	if (isXsltElem)
+	    xsltTransformError(NULL, cctxt->style, node,
+		"The attribute 'version' is missing.\n");
+	cctxt->style->errors++;	
+#else
+	/* OLD behaviour. */
+	xsltTransformError(NULL, cctxt->style, node,
+	    "xsl:version is missing: document may not be a stylesheet\n");
+	cctxt->style->warnings++;
+#endif
+    }    
+    /*
+    * The namespaces declared by the attributes
+    *  "extension-element-prefixes" and
+    *  "exclude-result-prefixes" are local to *this*
+    *  stylesheet tree; i.e., they are *not* visible to
+    *  other stylesheet-modules, whether imported or included.
+    * 
+    * Attribute "extension-element-prefixes".
+    */
+    cctxt->inode->extElemNs =
+	xsltParseExtElemPrefixes(cctxt, node, NULL,
+	    XSLT_ELEMENT_CATEGORY_XSLT);
+    /*
+    * Attribute "exclude-result-prefixes".
+    */
+    cctxt->inode->exclResultNs =
+	xsltParseExclResultPrefixes(cctxt, node, NULL,
+	    XSLT_ELEMENT_CATEGORY_XSLT);
+    /*
+    * Create/reuse info for the literal result element.
+    */
+    if (cctxt->inode->nsChanged)
+	xsltLREInfoCreate(cctxt, node, 0);
+    /*
+    * Processed top-level elements:
+    * ----------------------------
+    *  xsl:variable, xsl:param (QName, in-scope ns,
+    *    expression (vars allowed))
+    *  xsl:attribute-set (QName, in-scope ns)
+    *  xsl:strip-space, xsl:preserve-space (XPath NameTests,
+    *    in-scope ns)
+    *    I *think* global scope, merge with includes
+    *  xsl:output (QName, in-scope ns)
+    *  xsl:key (QName, in-scope ns, pattern,
+    *    expression (vars *not* allowed))
+    *  xsl:decimal-format (QName, needs in-scope ns)
+    *  xsl:namespace-alias (in-scope ns)
+    *    global scope, merge with includes
+    *  xsl:template (last, QName, pattern)
+    *
+    * (whitespace-only text-nodes have *not* been removed
+    *  yet; this will be done in xsltParseSequenceConstructor)
+    *
+    * Report misplaced child-nodes first.
+    */
+    cur = node->children;
+    while (cur != NULL) {
+	if (cur->type == XML_TEXT_NODE) {
+	    xsltTransformError(NULL, style, cur,
+		"Misplaced text node (content: '%s').\n",
+		(cur->content != NULL) ? cur->content : BAD_CAST "");
+	    style->errors++;
+	} else if (cur->type != XML_ELEMENT_NODE) {
+	    xsltTransformError(NULL, style, cur, "Misplaced node.\n");
+	    style->errors++;
+	}
+	cur = cur->next;
+    }
+    /*
+    * Skip xsl:import elements; they have been processed
+    * already.
+    */
+    cur = node->children;
+    while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur,
+	    BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
+	cur = cur->next;
+    if (cur == NULL)
+	goto exit;
+
+    start = cur;
+    /*
+    * Process all top-level xsl:param elements.
+    */
+    while ((cur != NULL) &&
+	xsltParseFindTopLevelElem(cctxt, cur,
+	BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1)
+    {
+	xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM);	
+	cur = cur->next;
+    }  
+    /*
+    * Process all top-level xsl:variable elements.
+    */
+    cur = start;
+    while ((cur != NULL) &&
+	xsltParseFindTopLevelElem(cctxt, cur,
+	BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1)
+    {
+	xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE);
+	cur = cur->next;
+    }   
+    /*
+    * Process all the rest of top-level elements.
+    */
+    cur = start;
+    while (cur != NULL) {	
+	/*
+	* Process element nodes.
+	*/
+	if (cur->type == XML_ELEMENT_NODE) {	    
+	    if (cur->ns == NULL) {
+		xsltTransformError(NULL, style, cur,
+		    "Unexpected top-level element in no namespace.\n");
+		style->errors++;
+		cur = cur->next;
+		continue;
+	    }
+	    /*
+	    * Process all XSLT elements.
+	    */
+	    if (IS_XSLT_ELEM_FAST(cur)) {
+		/*
+		* xsl:import is only allowed at the beginning.
+		*/
+		if (IS_XSLT_NAME(cur, "import")) {
+		    xsltTransformError(NULL, style, cur,
+			"Misplaced xsl:import element.\n");
+		    style->errors++;
+		    cur = cur->next;
+		    continue;
+		}
+		/* 
+		* TODO: Change the return type of the parsing functions
+		*  to int.
+		*/
+		if (IS_XSLT_NAME(cur, "template")) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+		    templates++;
+#endif
+		    /*
+		    * TODO: Is the position of xsl:template in the
+		    *  tree significant? If not it would be easier to
+		    *  parse them at a later stage.
+		    */
+		    xsltParseXSLTTemplate(cctxt, cur);
+		} else if (IS_XSLT_NAME(cur, "variable")) {
+		    /* NOP; done already */
+		} else if (IS_XSLT_NAME(cur, "param")) {
+		    /* NOP; done already */
+		} else if (IS_XSLT_NAME(cur, "include")) {		    
+		    if (cur->psvi != NULL)		    
+			xsltParseXSLTStylesheetElemCore(cctxt, cur);
+		    else {
+			xsltTransformError(NULL, style, cur,
+			    "Internal error: "
+			    "(xsltParseXSLTStylesheetElemCore) "
+			    "The xsl:include element was not compiled.\n");
+			style->errors++;
+		    }
+		} else if (IS_XSLT_NAME(cur, "strip-space")) {
+		    /* No node info needed. */
+		    xsltParseStylesheetStripSpace(style, cur);
+		} else if (IS_XSLT_NAME(cur, "preserve-space")) {
+		    /* No node info needed. */
+		    xsltParseStylesheetPreserveSpace(style, cur);
+		} else if (IS_XSLT_NAME(cur, "output")) {
+		    /* No node-info needed. */
+		    xsltParseStylesheetOutput(style, cur);
+		} else if (IS_XSLT_NAME(cur, "key")) {
+		    /* TODO: node-info needed for expressions ? */
+		    xsltParseStylesheetKey(style, cur);
+		} else if (IS_XSLT_NAME(cur, "decimal-format")) {
+		    /* No node-info needed. */		     
+		    xsltParseStylesheetDecimalFormat(style, cur);
+		} else if (IS_XSLT_NAME(cur, "attribute-set")) {		    
+		    xsltParseTopLevelXSLTElem(cctxt, cur,
+			XSLT_FUNC_ATTRSET);		
+		} else if (IS_XSLT_NAME(cur, "namespace-alias")) {
+		    /* NOP; done already */		    
+		} else {
+		    if (cctxt->inode->forwardsCompat) {
+			/*
+			* Forwards-compatible mode:
+			*
+			* XSLT-1: "if it is a top-level element and
+			*  XSLT 1.0 does not allow such elements as top-level
+			*  elements, then the element must be ignored along
+			*  with its content;"
+			*/
+			/*
+			* TODO: I don't think we should generate a warning.
+			*/
+			xsltTransformError(NULL, style, cur,
+			    "Forwards-compatible mode: Ignoring unknown XSLT "
+			    "element '%s'.\n", cur->name);
+			style->warnings++;
+		    } else {
+			xsltTransformError(NULL, style, cur,
+			    "Unknown XSLT element '%s'.\n", cur->name);
+			style->errors++;
+		    }
+		}
+	    } else {
+		xsltTopLevelFunction function;
+
+		/*
+		* Process non-XSLT elements, which are in a
+		*  non-NULL namespace.
+		*/
+		/*
+		* QUESTION: What does xsltExtModuleTopLevelLookup()
+		*  do exactly?
+		*/
+		function = xsltExtModuleTopLevelLookup(cur->name,
+		    cur->ns->href);
+		if (function != NULL)
+		    function(style, cur);
+#ifdef WITH_XSLT_DEBUG_PARSING
+		xsltGenericDebug(xsltGenericDebugContext,
+		    "xsltParseXSLTStylesheetElemCore : User-defined "
+		    "data element '%s'.\n", cur->name);
+#endif
+	    }
+	}
+	cur = cur->next;
+    }
+
+exit:
+
+#ifdef WITH_XSLT_DEBUG_PARSING
+    xsltGenericDebug(xsltGenericDebugContext,
+	"### END of parsing top-level elements of doc '%s'.\n",
+	node->doc->URL);
+    xsltGenericDebug(xsltGenericDebugContext,
+	"### Templates: %d\n", templates);
+#ifdef XSLT_REFACTORED
+    xsltGenericDebug(xsltGenericDebugContext,
+	"### Max inodes: %d\n", cctxt->maxNodeInfos);
+    xsltGenericDebug(xsltGenericDebugContext,
+	"### Max LREs  : %d\n", cctxt->maxLREs);
+#endif /* XSLT_REFACTORED */
+#endif /* WITH_XSLT_DEBUG_PARSING */
+
+    xsltCompilerNodePop(cctxt, node);
+    return(0);
+}
+
+/**
+ * xsltParseXSLTStylesheet:
+ * @cctxt: the compiler context
+ * @node: the xsl:stylesheet/xsl:transform element-node
+ *
+ * Parses the xsl:stylesheet and xsl:transform element. 
+ *
+ * <xsl:stylesheet
+ *  id = id
+ *  extension-element-prefixes = tokens
+ *  exclude-result-prefixes = tokens
+ *  version = number>
+ *  <!-- Content: (xsl:import*, top-level-elements) -->
+ * </xsl:stylesheet>
+ *
+ * BIG TODO: The xsl:include stuff.
+ * 
+ * Called by xsltParseStylesheetTree()
+ *
+ * Returns 0 on success, a positive result on errors and
+ *         -1 on API or internal errors.
+ */
+static int
+xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
+{
+    xmlNodePtr cur, start;
+
+    if ((cctxt == NULL) || (node == NULL))
+	return(-1);
+    
+    if (node->children == NULL)
+	goto exit;
+
+    /*
+    * Process top-level elements:
+    *  xsl:import (must be first)
+    *  xsl:include (this is just a pre-processing)
+    */
+    cur = node->children;
+    /*
+    * Process xsl:import elements.
+    * XSLT 1.0: "The xsl:import element children must precede all
+    *  other element children of an xsl:stylesheet element,
+    *  including any xsl:include element children."
+    */    
+    while ((cur != NULL) &&
+	xsltParseFindTopLevelElem(cctxt, cur,
+	    BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
+    {
+	if (xsltParseStylesheetImport(cctxt->style, cur) != 0) {
+	    cctxt->style->errors++;
+	}
+	cur = cur->next;
+    }
+    if (cur == NULL)
+	goto exit;
+    start = cur;
+    /*
+    * Pre-process all xsl:include elements.
+    */
+    cur = start;
+    while ((cur != NULL) &&
+	xsltParseFindTopLevelElem(cctxt, cur,
+	    BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1)
+    {
+	xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE);
+	cur = cur->next;
+    }
+    /*
+    * Pre-process all xsl:namespace-alias elements.
+    * URGENT TODO: This won't work correctly: the order of included
+    *  aliases and aliases defined here is significant.
+    */
+    cur = start;
+    while ((cur != NULL) &&
+	xsltParseFindTopLevelElem(cctxt, cur,
+	    BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1)
+    {
+	xsltNamespaceAlias(cctxt->style, cur);
+	cur = cur->next;
+    }
+
+    if (cctxt->isInclude) {
+	/*
+	* If this stylesheet is intended for inclusion, then
+	* we will process only imports and includes. 
+	*/
+	goto exit;
+    } 
+    /*
+    * Now parse the rest of the top-level elements.
+    */
+    xsltParseXSLTStylesheetElemCore(cctxt, node); 	
+exit:
+
+    return(0);
+}
+
+#else /* XSLT_REFACTORED */
+
+/**
+ * xsltParseStylesheetTop:
+ * @style:  the XSLT stylesheet
+ * @top:  the top level "stylesheet" or "transform" element
+ *
+ * scan the top level elements of an XSL stylesheet
+ */
+static void
+xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
+    xmlNodePtr cur;
+    xmlChar *prop;
+#ifdef WITH_XSLT_DEBUG_PARSING
+    int templates = 0;
+#endif
+
+    if (top == NULL)
+	return;
+
+    prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL);
+    if (prop == NULL) {
+	xsltTransformError(NULL, style, top,
+	    "xsl:version is missing: document may not be a stylesheet\n");
+	if (style != NULL) style->warnings++;
+    } else {
+	if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
+            (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
+	    xsltTransformError(NULL, style, top,
+		"xsl:version: only 1.0 features are supported\n");
+	     /* TODO set up compatibility when not XSLT 1.0 */
+	    if (style != NULL) style->warnings++;
+	}
+	xmlFree(prop);
+    }
+
+    /*
+     * process xsl:import elements
+     */
+    cur = top->children;
+    while (cur != NULL) {
+	    if (IS_BLANK_NODE(cur)) {
+		    cur = cur->next;
+		    continue;
+	    }
+	    if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
+		    if (xsltParseStylesheetImport(style, cur) != 0)
+			    if (style != NULL) style->errors++;
+	    } else
+		    break;
+	    cur = cur->next;
+    }
+
+    /*
+     * process other top-level elements
+     */
+    while (cur != NULL) {
+	if (IS_BLANK_NODE(cur)) {
+	    cur = cur->next;
+	    continue;
+	}
+	if (cur->type == XML_TEXT_NODE) {
+	    if (cur->content != NULL) {
+		xsltTransformError(NULL, style, cur,
+		    "misplaced text node: '%s'\n", cur->content);
+	    }
+	    if (style != NULL) style->errors++;
+            cur = cur->next;
+	    continue;
+	}
+	if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
+	    xsltGenericError(xsltGenericErrorContext,
+		     "Found a top-level element %s with null namespace URI\n",
+		     cur->name);
+	    if (style != NULL) style->errors++;
+	    cur = cur->next;
+	    continue;
+	}
+	if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
+	    xsltTopLevelFunction function;
+
+	    function = xsltExtModuleTopLevelLookup(cur->name,
+						   cur->ns->href);
+	    if (function != NULL)
+		function(style, cur);
+
+#ifdef WITH_XSLT_DEBUG_PARSING
+	    xsltGenericDebug(xsltGenericDebugContext,
+		    "xsltParseStylesheetTop : found foreign element %s\n",
+		    cur->name);
+#endif
+            cur = cur->next;
+	    continue;
+	}
+	if (IS_XSLT_NAME(cur, "import")) {
+	    xsltTransformError(NULL, style, cur,
+			"xsltParseStylesheetTop: ignoring misplaced import element\n");
+	    if (style != NULL) style->errors++;
+    } else if (IS_XSLT_NAME(cur, "include")) {
+	    if (xsltParseStylesheetInclude(style, cur) != 0)
+		if (style != NULL) style->errors++;
+    } else if (IS_XSLT_NAME(cur, "strip-space")) {
+	    xsltParseStylesheetStripSpace(style, cur);
+    } else if (IS_XSLT_NAME(cur, "preserve-space")) {
+	    xsltParseStylesheetPreserveSpace(style, cur);
+    } else if (IS_XSLT_NAME(cur, "output")) {
+	    xsltParseStylesheetOutput(style, cur);
+    } else if (IS_XSLT_NAME(cur, "key")) {
+	    xsltParseStylesheetKey(style, cur);
+    } else if (IS_XSLT_NAME(cur, "decimal-format")) {
+	    xsltParseStylesheetDecimalFormat(style, cur);
+    } else if (IS_XSLT_NAME(cur, "attribute-set")) {
+	    xsltParseStylesheetAttributeSet(style, cur);
+    } else if (IS_XSLT_NAME(cur, "variable")) {
+	    xsltParseGlobalVariable(style, cur);
+    } else if (IS_XSLT_NAME(cur, "param")) {
+	    xsltParseGlobalParam(style, cur);
+    } else if (IS_XSLT_NAME(cur, "template")) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+	    templates++;
+#endif
+	    xsltParseStylesheetTemplate(style, cur);
+    } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
+	    xsltNamespaceAlias(style, cur);
+	} else {
+	    /*
+	    * BUG TODO: The version of the *doc* is irrelevant for
+	    *  the forwards-compatible mode.
+	    */
+            if ((style != NULL) && (style->doc->version != NULL) &&
+	        (!strncmp((const char *) style->doc->version, "1.0", 3))) {
+	        xsltTransformError(NULL, style, cur,
+			"xsltParseStylesheetTop: unknown %s element\n",
+			cur->name);
+	        if (style != NULL) style->errors++;
+	    }
+	    else {
+                /* do Forwards-Compatible Processing */
+	        xsltTransformError(NULL, style, cur,
+			"xsltParseStylesheetTop: ignoring unknown %s element\n",
+			cur->name);
+	        if (style != NULL) style->warnings++;
+            }
+	}
+	cur = cur->next;
+    }
+#ifdef WITH_XSLT_DEBUG_PARSING
+    xsltGenericDebug(xsltGenericDebugContext,
+		    "parsed %d templates\n", templates);
+#endif
+}
+
+#endif /* else of XSLT_REFACTORED */
+
+#ifdef XSLT_REFACTORED
+/**
+ * xsltParseSimplifiedStylesheetTree:
+ *
+ * @style: the stylesheet (TODO: Change this to the compiler context)
+ * @doc: the document containing the stylesheet.
+ * @node: the node where the stylesheet is rooted at
+ *
+ * Returns 0 in case of success, a positive result if an error occurred
+ *         and -1 on API and internal errors.
+ */
+static int
+xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt,
+				  xmlDocPtr doc,
+				  xmlNodePtr node)
+{
+    xsltTemplatePtr templ;
+    
+    if ((cctxt == NULL) || (node == NULL))
+	return(-1);
+
+    if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE)
+    {
+	/*
+	* TODO: Adjust report, since this might be an
+	* embedded stylesheet.
+	*/
+	xsltTransformError(NULL, cctxt->style, node,
+	    "The attribute 'xsl:version' is missing; cannot identify "
+	    "this document as an XSLT stylesheet document.\n");
+	cctxt->style->errors++;
+	return(1);
+    }
+    
+#ifdef WITH_XSLT_DEBUG_PARSING
+    xsltGenericDebug(xsltGenericDebugContext,
+	"xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
+#endif        
+    
+    /*
+    * Create and link the template
+    */
+    templ = xsltNewTemplate();
+    if (templ == NULL) {
+	return(-1);
+    }
+    templ->next = cctxt->style->templates;
+    cctxt->style->templates = templ;
+    templ->match = xmlStrdup(BAD_CAST "/");
+
+    /*
+    * Note that we push the document-node in this special case.
+    */
+    xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
+    /*
+    * In every case, we need to have
+    * the in-scope namespaces of the element, where the
+    * stylesheet is rooted at, regardless if it's an XSLT
+    * instruction or a literal result instruction (or if
+    * this is an embedded stylesheet).
+    */
+    cctxt->inode->inScopeNs =
+	xsltCompilerBuildInScopeNsList(cctxt, node);
+    /*
+    * Parse the content and register the match-pattern.
+    */
+    xsltParseSequenceConstructor(cctxt, node);
+    xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
+
+    templ->elem = (xmlNodePtr) doc;
+    templ->content = node;
+    xsltAddTemplate(cctxt->style, templ, NULL, NULL);
+    cctxt->style->literal_result = 1;
+    return(0);
+}
+
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+/**
+ * xsltRestoreDocumentNamespaces:
+ * @ns: map of namespaces
+ * @doc: the document
+ *
+ * Restore the namespaces for the document
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+int
+xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc)
+{
+    if (doc == NULL)
+	return(-1);
+    /*
+    * Revert the changes we have applied to the namespace-URIs of
+    * ns-decls.
+    */    
+    while (ns != NULL) {
+	if ((ns->doc == doc) && (ns->ns != NULL)) {
+	    ns->ns->href = ns->origNsName;
+	    ns->origNsName = NULL;
+	    ns->ns = NULL;	    
+	}
+	ns = ns->next;
+    }
+    return(0);
+}
+#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
+
+/**
+ * xsltParseStylesheetProcess:
+ * @style:  the XSLT stylesheet (the current stylesheet-level)
+ * @doc:  and xmlDoc parsed XML
+ *
+ * Parses an XSLT stylesheet, adding the associated structures.
+ * Called by:
+ *  xsltParseStylesheetImportedDoc() (xslt.c)
+ *  xsltParseStylesheetInclude() (imports.c)
+ *
+ * Returns the value of the @style parameter if everything
+ * went right, NULL if something went amiss.
+ */
+xsltStylesheetPtr
+xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc)
+{
+    xsltCompilerCtxtPtr cctxt;
+    xmlNodePtr cur;
+    int oldIsSimplifiedStylesheet;
+
+    xsltInitGlobals();
+
+    if ((style == NULL) || (doc == NULL))
+	return(NULL);
+
+    cctxt = XSLT_CCTXT(style);
+
+    cur = xmlDocGetRootElement(doc);
+    if (cur == NULL) {
+	xsltTransformError(NULL, style, (xmlNodePtr) doc,
+		"xsltParseStylesheetProcess : empty stylesheet\n");
+	return(NULL);
+    }
+    oldIsSimplifiedStylesheet = cctxt->simplified;
+
+    if ((IS_XSLT_ELEM(cur)) && 
+	((IS_XSLT_NAME(cur, "stylesheet")) ||
+	 (IS_XSLT_NAME(cur, "transform")))) {	
+#ifdef WITH_XSLT_DEBUG_PARSING
+	xsltGenericDebug(xsltGenericDebugContext,
+		"xsltParseStylesheetProcess : found stylesheet\n");
+#endif
+	cctxt->simplified = 0;
+	style->literal_result = 0;
+    } else {
+	cctxt->simplified = 1;
+	style->literal_result = 1;
+    }
+    /*
+    * Pre-process the stylesheet if not already done before.
+    *  This will remove PIs and comments, merge adjacent
+    *  text nodes, internalize strings, etc.
+    */
+    if (! style->nopreproc)
+	xsltParsePreprocessStylesheetTree(cctxt, cur);
+    /*
+    * Parse and compile the stylesheet.
+    */
+    if (style->literal_result == 0) {
+	if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0)
+	    return(NULL);
+    } else {
+	if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0)
+	    return(NULL);
+    }    
+
+    cctxt->simplified = oldIsSimplifiedStylesheet;
+
+    return(style);
+}
+
+#else /* XSLT_REFACTORED */
+
+/**
+ * xsltParseStylesheetProcess:
+ * @ret:  the XSLT stylesheet (the current stylesheet-level)
+ * @doc:  and xmlDoc parsed XML
+ *
+ * Parses an XSLT stylesheet, adding the associated structures.
+ * Called by:
+ *  xsltParseStylesheetImportedDoc() (xslt.c)
+ *  xsltParseStylesheetInclude() (imports.c)
+ *
+ * Returns the value of the @style parameter if everything
+ * went right, NULL if something went amiss.
+ */
+xsltStylesheetPtr
+xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
+    xmlNodePtr cur;
+
+    xsltInitGlobals();
+
+    if (doc == NULL)
+	return(NULL);
+    if (ret == NULL)
+	return(ret);
+    
+    /*
+     * First steps, remove blank nodes,
+     * locate the xsl:stylesheet element and the
+     * namespace declaration.
+     */
+    cur = xmlDocGetRootElement(doc);
+    if (cur == NULL) {
+	xsltTransformError(NULL, ret, (xmlNodePtr) doc,
+		"xsltParseStylesheetProcess : empty stylesheet\n");
+	return(NULL);
+    }
+
+    if ((IS_XSLT_ELEM(cur)) && 
+	((IS_XSLT_NAME(cur, "stylesheet")) ||
+	 (IS_XSLT_NAME(cur, "transform")))) {	
+#ifdef WITH_XSLT_DEBUG_PARSING
+	xsltGenericDebug(xsltGenericDebugContext,
+		"xsltParseStylesheetProcess : found stylesheet\n");
+#endif
+	ret->literal_result = 0;
+	xsltParseStylesheetExcludePrefix(ret, cur, 1);
+	xsltParseStylesheetExtPrefix(ret, cur, 1);
+    } else {
+	xsltParseStylesheetExcludePrefix(ret, cur, 0);
+	xsltParseStylesheetExtPrefix(ret, cur, 0);
+	ret->literal_result = 1;
+    }
+    if (!ret->nopreproc) {
+	xsltPrecomputeStylesheet(ret, cur);
+    }
+    if (ret->literal_result == 0) {
+	xsltParseStylesheetTop(ret, cur);
+    } else {
+	xmlChar *prop;
+	xsltTemplatePtr template;
+
+	/*
+	 * the document itself might be the template, check xsl:version
+	 */
+	prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
+	if (prop == NULL) {
+	    xsltTransformError(NULL, ret, cur,
+		"xsltParseStylesheetProcess : document is not a stylesheet\n");
+	    return(NULL);
+	}
+
+#ifdef WITH_XSLT_DEBUG_PARSING
+        xsltGenericDebug(xsltGenericDebugContext,
+		"xsltParseStylesheetProcess : document is stylesheet\n");
+#endif
+	
+	if (!xmlStrEqual(prop, (const xmlChar *)"1.0")) {
+	    xsltTransformError(NULL, ret, cur,
+		"xsl:version: only 1.0 features are supported\n");
+	     /* TODO set up compatibility when not XSLT 1.0 */
+	    ret->warnings++;
+	}
+	xmlFree(prop);
+
+	/*
+	 * Create and link the template
+	 */
+	template = xsltNewTemplate();
+	if (template == NULL) {
+	    return(NULL);
+	}
+	template->next = ret->templates;
+	ret->templates = template;
+	template->match = xmlStrdup((const xmlChar *)"/");
+
+	/*
+	 * parse the content and register the pattern
+	 */
+	xsltParseTemplateContent(ret, (xmlNodePtr) doc);
+	template->elem = (xmlNodePtr) doc;
+	template->content = doc->children;
+	xsltAddTemplate(ret, template, NULL, NULL);
+	ret->literal_result = 1;	
+    }
+
+    return(ret);
+}
+
+#endif /* else of XSLT_REFACTORED */
+
+/**
+ * xsltParseStylesheetImportedDoc:
+ * @doc:  an xmlDoc parsed XML
+ * @parentStyle: pointer to the parent stylesheet (if it exists)
+ *
+ * parse an XSLT stylesheet building the associated structures
+ * except the processing not needed for imported documents.
+ *
+ * Returns a new XSLT stylesheet structure.
+ */
+
+xsltStylesheetPtr
+xsltParseStylesheetImportedDoc(xmlDocPtr doc,
+			       xsltStylesheetPtr parentStyle) {
+    xsltStylesheetPtr retStyle;
+
+    if (doc == NULL)
+	return(NULL);
+
+    retStyle = xsltNewStylesheet();
+    if (retStyle == NULL)
+	return(NULL);
+    /*
+    * Set the importing stylesheet module; also used to detect recursion.
+    */
+    retStyle->parent = parentStyle;
+    /*
+    * Adjust the string dict.
+    */
+    if (doc->dict != NULL) {
+        xmlDictFree(retStyle->dict);
+	retStyle->dict = doc->dict;
+#ifdef WITH_XSLT_DEBUG
+        xsltGenericDebug(xsltGenericDebugContext,
+	    "reusing dictionary from %s for stylesheet\n",
+	    doc->URL);
+#endif
+	xmlDictReference(retStyle->dict);
+    }    	
+    
+    /*
+    * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
+    *  the stylesheet to containt distinct namespace prefixes.
+    */
+    xsltGatherNamespaces(retStyle);
+
+#ifdef XSLT_REFACTORED
+    {
+	xsltCompilerCtxtPtr cctxt;
+	xsltStylesheetPtr oldCurSheet;
+	    
+	if (parentStyle == NULL) {
+	    xsltPrincipalStylesheetDataPtr principalData;
+	    /*
+	    * Principal stylesheet
+	    * --------------------
+	    */
+	    retStyle->principal = retStyle;
+	    /*
+	    * Create extra data for the principal stylesheet.
+	    */
+	    principalData = xsltNewPrincipalStylesheetData();
+	    if (principalData == NULL) {
+		xsltFreeStylesheet(retStyle);
+		return(NULL);
+	    }
+	    retStyle->principalData = principalData;
+	    /*
+	    * Create the compilation context
+	    * ------------------------------
+	    * (only once; for the principal stylesheet).
+	    * This is currently the only function where the
+	    * compilation context is created.
+	    */
+	    cctxt = xsltCompilationCtxtCreate(retStyle);
+	    if (cctxt == NULL) {
+		xsltFreeStylesheet(retStyle);
+		return(NULL);
+	    }	    	    
+	    retStyle->compCtxt = (void *) cctxt;
+	    cctxt->style = retStyle;
+	    cctxt->dict = retStyle->dict;
+	    cctxt->psData = principalData;
+	    /*
+	    * Push initial dummy node info.
+	    */
+	    cctxt->depth = -1;
+	    xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
+	} else {
+	    /*
+	    * Imported stylesheet.
+	    */
+	    retStyle->principal = parentStyle->principal;
+	    cctxt = parentStyle->compCtxt;
+	    retStyle->compCtxt = cctxt;
+	}
+	/*
+	* Save the old and set the current stylesheet structure in the
+	* compilation context.
+	*/
+	oldCurSheet = cctxt->style;
+	cctxt->style = retStyle;
+	
+	retStyle->doc = doc;
+	xsltParseStylesheetProcess(retStyle, doc);
+	
+	cctxt->style = oldCurSheet;
+	if (parentStyle == NULL) {
+	    /*
+	    * Pop the initial dummy node info.
+	    */
+	    xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
+	} else {
+	    /*
+	    * Clear the compilation context of imported
+	    * stylesheets.
+	    * TODO: really?
+	    */
+	    /* retStyle->compCtxt = NULL; */
+	}
+	/*
+	* Free the stylesheet if there were errors.
+	*/
+	if (retStyle != NULL) {
+	    if (retStyle->errors != 0) {
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+		/*
+		* Restore all changes made to namespace URIs of ns-decls.
+		*/
+		if (cctxt->psData->nsMap)		
+		    xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
+#endif
+		/*
+		* Detach the doc from the stylesheet; otherwise the doc
+		* will be freed in xsltFreeStylesheet().
+		*/
+		retStyle->doc = NULL;
+		/*
+		* Cleanup the doc if its the main stylesheet.
+		*/
+		if (parentStyle == NULL) {
+		    xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
+		    if (retStyle->compCtxt != NULL) {			
+			xsltCompilationCtxtFree(retStyle->compCtxt);
+			retStyle->compCtxt = NULL;
+		    }
+		}
+
+		xsltFreeStylesheet(retStyle);
+		retStyle = NULL;
+	    }
+	}
+    }
+        
+#else /* XSLT_REFACTORED */
+    /*
+    * Old behaviour.
+    */
+    retStyle->doc = doc;
+    if (xsltParseStylesheetProcess(retStyle, doc) == NULL) {
+		retStyle->doc = NULL;
+		xsltFreeStylesheet(retStyle);
+		retStyle = NULL;
+    }
+    if (retStyle != NULL) {
+	if (retStyle->errors != 0) {
+	    retStyle->doc = NULL;
+	    if (parentStyle == NULL)
+		xsltCleanupStylesheetTree(doc,
+		    xmlDocGetRootElement(doc));
+	    xsltFreeStylesheet(retStyle);
+	    retStyle = NULL;
+	}
+    }
+#endif /* else of XSLT_REFACTORED */
+        
+    return(retStyle);
+}
+
+/**
+ * xsltParseStylesheetDoc:
+ * @doc:  and xmlDoc parsed XML
+ *
+ * parse an XSLT stylesheet, building the associated structures.  doc
+ * is kept as a reference within the returned stylesheet, so changes
+ * to doc after the parsing will be reflected when the stylesheet
+ * is applied, and the doc is automatically freed when the
+ * stylesheet is closed.
+ *
+ * Returns a new XSLT stylesheet structure.
+ */
+
+xsltStylesheetPtr
+xsltParseStylesheetDoc(xmlDocPtr doc) {
+    xsltStylesheetPtr ret;
+
+    xsltInitGlobals();
+
+    ret = xsltParseStylesheetImportedDoc(doc, NULL);
+    if (ret == NULL)
+	return(NULL);
+
+    xsltResolveStylesheetAttributeSet(ret);
+#ifdef XSLT_REFACTORED
+    /*
+    * Free the compilation context.
+    * TODO: Check if it's better to move this cleanup to
+    *   xsltParseStylesheetImportedDoc().
+    */
+    if (ret->compCtxt != NULL) {
+	xsltCompilationCtxtFree(XSLT_CCTXT(ret));
+	ret->compCtxt = NULL;
+    }
+#endif
+    return(ret);
+}
+
+/**
+ * xsltParseStylesheetFile:
+ * @filename:  the filename/URL to the stylesheet
+ *
+ * Load and parse an XSLT stylesheet
+ *
+ * Returns a new XSLT stylesheet structure.
+ */
+
+xsltStylesheetPtr
+xsltParseStylesheetFile(const xmlChar* filename) {
+    xsltSecurityPrefsPtr sec;
+    xsltStylesheetPtr ret;
+    xmlDocPtr doc;
+    
+    xsltInitGlobals();
+
+    if (filename == NULL)
+	return(NULL);
+
+#ifdef WITH_XSLT_DEBUG_PARSING
+    xsltGenericDebug(xsltGenericDebugContext,
+	    "xsltParseStylesheetFile : parse %s\n", filename);
+#endif
+
+    /*
+     * Security framework check
+     */
+    sec = xsltGetDefaultSecurityPrefs();
+    if (sec != NULL) {
+	int res;
+
+	res = xsltCheckRead(sec, NULL, filename);
+	if (res == 0) {
+	    xsltTransformError(NULL, NULL, NULL,
+		 "xsltParseStylesheetFile: read rights for %s denied\n",
+			     filename);
+	    return(NULL);
+	}
+    }
+
+    doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,
+                               NULL, XSLT_LOAD_START);
+    if (doc == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+		"xsltParseStylesheetFile : cannot parse %s\n", filename);
+	return(NULL);
+    }
+    ret = xsltParseStylesheetDoc(doc);
+    if (ret == NULL) {
+	xmlFreeDoc(doc);
+	return(NULL);
+    }
+
+    return(ret);
+}
+
+/************************************************************************
+ *									*
+ *			Handling of Stylesheet PI			*
+ *									*
+ ************************************************************************/
+
+#define CUR (*cur)
+#define SKIP(val) cur += (val)
+#define NXT(val) cur[(val)]
+#define SKIP_BLANKS						\
+    while (IS_BLANK(CUR)) NEXT
+#define NEXT ((*cur) ?  cur++ : cur)
+
+/**
+ * xsltParseStylesheetPI:
+ * @value: the value of the PI
+ *
+ * This function checks that the type is text/xml and extracts
+ * the URI-Reference for the stylesheet
+ *
+ * Returns the URI-Reference for the stylesheet or NULL (it need to
+ *         be freed by the caller)
+ */
+static xmlChar *
+xsltParseStylesheetPI(const xmlChar *value) {
+    const xmlChar *cur;
+    const xmlChar *start;
+    xmlChar *val;
+    xmlChar tmp;
+    xmlChar *href = NULL;
+    int isXml = 0;
+
+    if (value == NULL)
+	return(NULL);
+
+    cur = value;
+    while (CUR != 0) {
+	SKIP_BLANKS;
+	if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
+	    (NXT(3) == 'e')) {
+	    SKIP(4);
+	    SKIP_BLANKS;
+	    if (CUR != '=')
+		continue;
+	    NEXT;
+	    if ((CUR != '\'') && (CUR != '"'))
+		continue;
+	    tmp = CUR;
+	    NEXT;
+	    start = cur;
+	    while ((CUR != 0) && (CUR != tmp))
+		NEXT;
+	    if (CUR != tmp)
+		continue;
+	    val = xmlStrndup(start, cur - start);
+	    NEXT;
+	    if (val == NULL) 
+		return(NULL);
+	    if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
+		(xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
+                xmlFree(val);
+		break;
+	    }
+	    isXml = 1;
+	    xmlFree(val);
+	} else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
+	    (NXT(3) == 'f')) {
+	    SKIP(4);
+	    SKIP_BLANKS;
+	    if (CUR != '=')
+		continue;
+	    NEXT;
+	    if ((CUR != '\'') && (CUR != '"'))
+		continue;
+	    tmp = CUR;
+	    NEXT;
+	    start = cur;
+	    while ((CUR != 0) && (CUR != tmp))
+		NEXT;
+	    if (CUR != tmp)
+		continue;
+	    if (href == NULL)
+		href = xmlStrndup(start, cur - start);
+	    NEXT;
+	} else {
+	    while ((CUR != 0) && (!IS_BLANK(CUR)))
+		NEXT;
+	}
+            
+    }
+
+    if (!isXml) {
+	if (href != NULL)
+	    xmlFree(href);
+	href = NULL;
+    }
+    return(href);
+}
+
+/**
+ * xsltLoadStylesheetPI:
+ * @doc:  a document to process
+ *
+ * This function tries to locate the stylesheet PI in the given document
+ * If found, and if contained within the document, it will extract 
+ * that subtree to build the stylesheet to process @doc (doc itself will
+ * be modified). If found but referencing an external document it will
+ * attempt to load it and generate a stylesheet from it. In both cases,
+ * the resulting stylesheet and the document need to be freed once the
+ * transformation is done.
+ *
+ * Returns a new XSLT stylesheet structure or NULL if not found.
+ */
+xsltStylesheetPtr
+xsltLoadStylesheetPI(xmlDocPtr doc) {
+    xmlNodePtr child;
+    xsltStylesheetPtr ret = NULL;
+    xmlChar *href = NULL;
+    xmlURIPtr URI;
+
+    xsltInitGlobals();
+
+    if (doc == NULL)
+	return(NULL);
+
+    /*
+     * Find the text/xml stylesheet PI id any before the root
+     */
+    child = doc->children;
+    while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
+	if ((child->type == XML_PI_NODE) &&
+	    (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
+	    href = xsltParseStylesheetPI(child->content);
+	    if (href != NULL)
+		break;
+	}
+	child = child->next;
+    }
+
+    /*
+     * If found check the href to select processing
+     */
+    if (href != NULL) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+	xsltGenericDebug(xsltGenericDebugContext,
+		"xsltLoadStylesheetPI : found PI href=%s\n", href);
+#endif
+	URI = xmlParseURI((const char *) href);
+	if (URI == NULL) {
+	    xsltTransformError(NULL, NULL, child,
+		    "xml-stylesheet : href %s is not valid\n", href);
+	    xmlFree(href);
+	    return(NULL);
+	}
+	if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
+            (URI->opaque == NULL) && (URI->authority == NULL) &&
+            (URI->server == NULL) && (URI->user == NULL) &&
+            (URI->path == NULL) && (URI->query == NULL)) {
+	    xmlAttrPtr ID;
+
+#ifdef WITH_XSLT_DEBUG_PARSING
+	    xsltGenericDebug(xsltGenericDebugContext,
+		    "xsltLoadStylesheetPI : Reference to ID %s\n", href);
+#endif
+	    if (URI->fragment[0] == '#')
+		ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
+	    else
+		ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
+	    if (ID == NULL) {
+		xsltTransformError(NULL, NULL, child,
+		    "xml-stylesheet : no ID %s found\n", URI->fragment);
+	    } else {
+		xmlDocPtr fake;
+		xmlNodePtr subtree, newtree;
+		xmlNsPtr ns;
+
+#ifdef WITH_XSLT_DEBUG
+		xsltGenericDebug(xsltGenericDebugContext,
+		    "creating new document from %s for embedded stylesheet\n",
+		    doc->URL);
+#endif
+		/*
+		 * move the subtree in a new document passed to
+		 * the stylesheet analyzer
+		 */
+		subtree = ID->parent;
+		fake = xmlNewDoc(NULL);
+		if (fake != NULL) {
+		    /*
+		    * Should the dictionary still be shared even though
+		    * the nodes are being copied rather than moved?
+		    */
+		    fake->dict = doc->dict;
+		    xmlDictReference(doc->dict);
+#ifdef WITH_XSLT_DEBUG
+		    xsltGenericDebug(xsltGenericDebugContext,
+			"reusing dictionary from %s for embedded stylesheet\n",
+			doc->URL);
+#endif
+
+		    newtree = xmlDocCopyNode(subtree, fake, 1);
+
+		    fake->URL = xmlNodeGetBase(doc, subtree->parent);
+#ifdef WITH_XSLT_DEBUG
+		    xsltGenericDebug(xsltGenericDebugContext,
+			"set base URI for embedded stylesheet as %s\n",
+			fake->URL);
+#endif
+
+		    /*
+		    * Add all namespaces in scope of embedded stylesheet to
+		    * root element of newly created stylesheet document
+		    */
+		    while ((subtree = subtree->parent) != (xmlNodePtr)doc) {
+			for (ns = subtree->ns; ns; ns = ns->next) {
+			    xmlNewNs(newtree,  ns->href, ns->prefix);
+			}
+		    }
+
+		    xmlAddChild((xmlNodePtr)fake, newtree);
+		    ret = xsltParseStylesheetDoc(fake);
+		    if (ret == NULL)
+			xmlFreeDoc(fake);
+		}
+	    }
+	} else {
+	    xmlChar *URL, *base;
+
+	    /*
+	     * Reference to an external stylesheet
+	     */
+
+	    base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
+	    URL = xmlBuildURI(href, base);
+	    if (URL != NULL) {
+#ifdef WITH_XSLT_DEBUG_PARSING
+		xsltGenericDebug(xsltGenericDebugContext,
+			"xsltLoadStylesheetPI : fetching %s\n", URL);
+#endif
+		ret = xsltParseStylesheetFile(URL);
+		xmlFree(URL);
+	    } else {
+#ifdef WITH_XSLT_DEBUG_PARSING
+		xsltGenericDebug(xsltGenericDebugContext,
+			"xsltLoadStylesheetPI : fetching %s\n", href);
+#endif
+		ret = xsltParseStylesheetFile(href);
+	    }
+	    if (base != NULL)
+		xmlFree(base);
+	}
+	xmlFreeURI(URI);
+	xmlFree(href);
+    }
+    return(ret);
+}
diff --git a/libxslt/xslt.h b/libxslt/xslt.h
new file mode 100644
index 0000000..849b03c
--- /dev/null
+++ b/libxslt/xslt.h
@@ -0,0 +1,103 @@
+/*
+ * Summary: Interfaces, constants and types related to the XSLT engine
+ * Description: Interfaces, constants and types related to the XSLT engine
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_H__
+#define __XML_XSLT_H__
+
+#include <libxml/tree.h>
+#include "xsltexports.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * XSLT_DEFAULT_VERSION:
+ *
+ * The default version of XSLT supported.
+ */
+#define XSLT_DEFAULT_VERSION     "1.0"
+
+/**
+ * XSLT_DEFAULT_VENDOR:
+ *
+ * The XSLT "vendor" string for this processor.
+ */
+#define XSLT_DEFAULT_VENDOR      "libxslt"
+
+/**
+ * XSLT_DEFAULT_URL:
+ *
+ * The XSLT "vendor" URL for this processor.
+ */
+#define XSLT_DEFAULT_URL         "http://xmlsoft.org/XSLT/"
+
+/**
+ * XSLT_NAMESPACE:
+ *
+ * The XSLT specification namespace.
+ */
+#define XSLT_NAMESPACE ((xmlChar *) "http://www.w3.org/1999/XSL/Transform")
+
+/**
+ * XSLT_PARSE_OPTIONS:
+ *
+ * The set of options to pass to an xmlReadxxx when loading files for
+ * XSLT consumption.
+ */
+#define XSLT_PARSE_OPTIONS \
+ XML_PARSE_NOENT | XML_PARSE_DTDLOAD | XML_PARSE_DTDATTR | XML_PARSE_NOCDATA
+
+/**
+ * xsltMaxDepth:
+ *
+ * This value is used to detect templates loops.
+ */
+XSLTPUBVAR int xsltMaxDepth;
+
+/**
+ * xsltEngineVersion:
+ *
+ * The version string for libxslt.
+ */
+XSLTPUBVAR const char *xsltEngineVersion;
+
+/**
+ * xsltLibxsltVersion:
+ *
+ * The version of libxslt compiled.
+ */
+XSLTPUBVAR const int xsltLibxsltVersion;
+
+/**
+ * xsltLibxmlVersion:
+ *
+ * The version of libxml libxslt was compiled against.
+ */
+XSLTPUBVAR const int xsltLibxmlVersion;
+
+/*
+ * Global initialization function.
+ */
+
+XSLTPUBFUN void XSLTCALL
+		xsltInit		(void);
+
+/*
+ * Global cleanup function.
+ */
+XSLTPUBFUN void XSLTCALL	
+		xsltCleanupGlobals	(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_H__ */
+
diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h
new file mode 100644
index 0000000..e991a93
--- /dev/null
+++ b/libxslt/xsltInternals.h
@@ -0,0 +1,1967 @@
+/*
+ * Summary: internal data structures, constants and functions
+ * Description: Internal data structures, constants and functions used
+ *              by the XSLT engine. 
+ *              They are not part of the API or ABI, i.e. they can change
+ *              without prior notice, use carefully.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLT_INTERNALS_H__
+#define __XML_XSLT_INTERNALS_H__
+
+#include <libxml/tree.h>
+#include <libxml/hash.h>
+#include <libxml/xpath.h>
+#include <libxml/xmlerror.h>
+#include <libxml/dict.h>
+#include <libxml/xmlstring.h>
+#include <libxslt/xslt.h>
+#include "xsltexports.h"
+#include "xsltlocale.h"
+#include "numbersInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* #define XSLT_DEBUG_PROFILE_CACHE */
+
+/**
+ * XSLT_IS_TEXT_NODE:
+ *
+ * check if the argument is a text node
+ */
+#define XSLT_IS_TEXT_NODE(n) ((n != NULL) && \
+    (((n)->type == XML_TEXT_NODE) || \
+     ((n)->type == XML_CDATA_SECTION_NODE)))
+
+
+/**
+ * XSLT_MARK_RES_TREE_FRAG:
+ *
+ * internal macro to set up tree fragments
+ */
+#define XSLT_MARK_RES_TREE_FRAG(n) \
+    (n)->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");
+
+/**
+ * XSLT_IS_RES_TREE_FRAG:
+ *
+ * internal macro to test tree fragments
+ */
+#define XSLT_IS_RES_TREE_FRAG(n) \
+    ((n != NULL) && ((n)->type == XML_DOCUMENT_NODE) && \
+     ((n)->name != NULL) && ((n)->name[0] == ' '))
+
+/**
+ * XSLT_REFACTORED_KEYCOMP:
+ *
+ * Internal define to enable on-demand xsl:key computation.
+ * That's the only mode now but the define is kept for compatibility
+ */
+#define XSLT_REFACTORED_KEYCOMP
+
+/**
+ * XSLT_FAST_IF:
+ *
+ * Internal define to enable usage of xmlXPathCompiledEvalToBoolean()
+ * for XSLT "tests"; e.g. in <xsl:if test="/foo/bar">
+ */
+#define XSLT_FAST_IF
+
+/**
+ * XSLT_REFACTORED:
+ *
+ * Internal define to enable the refactored parts of Libxslt.
+ */
+/* #define XSLT_REFACTORED */
+/* ==================================================================== */
+
+/**
+ * XSLT_REFACTORED_VARS:
+ *
+ * Internal define to enable the refactored variable part of libxslt
+ */
+#define XSLT_REFACTORED_VARS
+
+#ifdef XSLT_REFACTORED
+
+extern const xmlChar *xsltXSLTAttrMarker;
+
+
+/* TODO: REMOVE: #define XSLT_REFACTORED_EXCLRESNS */
+
+/* TODO: REMOVE: #define XSLT_REFACTORED_NSALIAS */
+
+/**
+ * XSLT_REFACTORED_XSLT_NSCOMP
+ *
+ * Internal define to enable the pointer-comparison of
+ * namespaces of XSLT elements. 
+ */
+/* #define XSLT_REFACTORED_XSLT_NSCOMP */
+
+/**
+ * XSLT_REFACTORED_XPATHCOMP:
+ *
+ * Internal define to enable the optimization of the
+ * compilation of XPath expressions.
+ */
+#define XSLT_REFACTORED_XPATHCOMP
+
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+
+extern const xmlChar *xsltConstNamespaceNameXSLT;
+
+/**
+ * IS_XSLT_ELEM_FAST:
+ *
+ * quick test to detect XSLT elements
+ */
+#define IS_XSLT_ELEM_FAST(n) \
+    (((n) != NULL) && ((n)->ns != NULL) && \
+    ((n)->ns->href == xsltConstNamespaceNameXSLT))
+
+/**
+ * IS_XSLT_ATTR_FAST:
+ *
+ * quick test to detect XSLT attributes
+ */
+#define IS_XSLT_ATTR_FAST(a) \
+    (((a) != NULL) && ((a)->ns != NULL) && \
+    ((a)->ns->href == xsltConstNamespaceNameXSLT))
+
+/**
+ * XSLT_HAS_INTERNAL_NSMAP:
+ *
+ * check for namespace mapping
+ */
+#define XSLT_HAS_INTERNAL_NSMAP(s) \
+    (((s) != NULL) && ((s)->principal) && \
+     ((s)->principal->principalData) && \
+     ((s)->principal->principalData->nsMap))
+
+/**
+ * XSLT_GET_INTERNAL_NSMAP:
+ *
+ * get pointer to namespace map
+ */
+#define XSLT_GET_INTERNAL_NSMAP(s) ((s)->principal->principalData->nsMap)
+
+#else /* XSLT_REFACTORED_XSLT_NSCOMP */
+
+/**
+ * IS_XSLT_ELEM_FAST:
+ *
+ * quick check whether this is an xslt element
+ */
+#define IS_XSLT_ELEM_FAST(n) \
+    (((n) != NULL) && ((n)->ns != NULL) && \
+     (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE)))
+
+/**
+ * IS_XSLT_ATTR_FAST:
+ *
+ * quick check for xslt namespace attribute
+ */
+#define IS_XSLT_ATTR_FAST(a) \
+    (((a) != NULL) && ((a)->ns != NULL) && \
+     (xmlStrEqual((a)->ns->href, XSLT_NAMESPACE)))
+
+
+#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
+
+
+/**
+ * XSLT_REFACTORED_MANDATORY_VERSION:
+ *
+ * TODO: Currently disabled to surpress regression test failures, since
+ *  the old behaviour was that a missing version attribute
+ *  produced a only a warning and not an error, which was incerrect.
+ *  So the regression tests need to be fixed if this is enabled.
+ */
+/* #define XSLT_REFACTORED_MANDATORY_VERSION */
+
+/**
+ * xsltPointerList:
+ *
+ * Pointer-list for various purposes.
+ */
+typedef struct _xsltPointerList xsltPointerList;
+typedef xsltPointerList *xsltPointerListPtr;
+struct _xsltPointerList {
+    void **items;
+    int number;
+    int size;
+};
+
+#endif
+
+/**
+ * XSLT_REFACTORED_PARSING:
+ *
+ * Internal define to enable the refactored parts of Libxslt
+ * related to parsing.
+ */
+/* #define XSLT_REFACTORED_PARSING */
+
+/**
+ * XSLT_MAX_SORT:
+ *
+ * Max number of specified xsl:sort on an element.
+ */
+#define XSLT_MAX_SORT 15
+
+/**
+ * XSLT_PAT_NO_PRIORITY:
+ *
+ * Specific value for pattern without priority expressed.
+ */
+#define XSLT_PAT_NO_PRIORITY -12345789
+
+/**
+ * xsltRuntimeExtra:
+ *
+ * Extra information added to the transformation context.
+ */
+typedef struct _xsltRuntimeExtra xsltRuntimeExtra;
+typedef xsltRuntimeExtra *xsltRuntimeExtraPtr;
+struct _xsltRuntimeExtra {
+    void       *info;		/* pointer to the extra data */
+    xmlFreeFunc deallocate;	/* pointer to the deallocation routine */
+    union {			/* dual-purpose field */
+        void   *ptr;		/* data not needing deallocation */
+	int    ival;		/* integer value storage */
+    } val;
+};
+
+/**
+ * XSLT_RUNTIME_EXTRA_LST:
+ * @ctxt: the transformation context
+ * @nr: the index
+ *
+ * Macro used to access extra information stored in the context
+ */
+#define XSLT_RUNTIME_EXTRA_LST(ctxt, nr) (ctxt)->extras[(nr)].info
+/**
+ * XSLT_RUNTIME_EXTRA_FREE:
+ * @ctxt: the transformation context
+ * @nr: the index
+ *
+ * Macro used to free extra information stored in the context
+ */
+#define XSLT_RUNTIME_EXTRA_FREE(ctxt, nr) (ctxt)->extras[(nr)].deallocate
+/**
+ * XSLT_RUNTIME_EXTRA:
+ * @ctxt: the transformation context
+ * @nr: the index
+ *
+ * Macro used to define extra information stored in the context
+ */
+#define	XSLT_RUNTIME_EXTRA(ctxt, nr, typ) (ctxt)->extras[(nr)].val.typ
+
+/**
+ * xsltTemplate:
+ *
+ * The in-memory structure corresponding to an XSLT Template.
+ */
+typedef struct _xsltTemplate xsltTemplate;
+typedef xsltTemplate *xsltTemplatePtr;
+struct _xsltTemplate {
+    struct _xsltTemplate *next;/* chained list sorted by priority */
+    struct _xsltStylesheet *style;/* the containing stylesheet */
+    xmlChar *match;	/* the matching string */
+    float priority;	/* as given from the stylesheet, not computed */
+    const xmlChar *name; /* the local part of the name QName */
+    const xmlChar *nameURI; /* the URI part of the name QName */
+    const xmlChar *mode;/* the local part of the mode QName */
+    const xmlChar *modeURI;/* the URI part of the mode QName */
+    xmlNodePtr content;	/* the template replacement value */
+    xmlNodePtr elem;	/* the source element */
+
+    /*
+    * TODO: @inheritedNsNr and @inheritedNs won't be used in the
+    *  refactored code.
+    */
+    int inheritedNsNr;  /* number of inherited namespaces */
+    xmlNsPtr *inheritedNs;/* inherited non-excluded namespaces */
+
+    /* Profiling informations */
+    int nbCalls;        /* the number of time the template was called */
+    unsigned long time; /* the time spent in this template */
+    void *params;       /* xsl:param instructions */
+};
+
+/**
+ * xsltDecimalFormat:
+ *
+ * Data structure of decimal-format.
+ */
+typedef struct _xsltDecimalFormat xsltDecimalFormat;
+typedef xsltDecimalFormat *xsltDecimalFormatPtr;
+struct _xsltDecimalFormat {
+    struct _xsltDecimalFormat *next; /* chained list */
+    xmlChar *name;
+    /* Used for interpretation of pattern */
+    xmlChar *digit;
+    xmlChar *patternSeparator;
+    /* May appear in result */
+    xmlChar *minusSign;
+    xmlChar *infinity;
+    xmlChar *noNumber; /* Not-a-number */
+    /* Used for interpretation of pattern and may appear in result */
+    xmlChar *decimalPoint;
+    xmlChar *grouping;
+    xmlChar *percent;
+    xmlChar *permille;
+    xmlChar *zeroDigit;
+};
+
+/**
+ * xsltDocument:
+ *
+ * Data structure associated to a parsed document.
+ */
+typedef struct _xsltDocument xsltDocument;
+typedef xsltDocument *xsltDocumentPtr;
+struct _xsltDocument {
+    struct _xsltDocument *next;	/* documents are kept in a chained list */
+    int main;			/* is this the main document */
+    xmlDocPtr doc;		/* the parsed document */
+    void *keys;			/* key tables storage */
+    struct _xsltDocument *includes; /* subsidiary includes */
+    int preproc;		/* pre-processing already done */
+    int nbKeysComputed;
+};
+
+/**
+ * xsltKeyDef:
+ *
+ * Representation of an xsl:key.
+ */
+typedef struct _xsltKeyDef xsltKeyDef;
+typedef xsltKeyDef *xsltKeyDefPtr;
+struct _xsltKeyDef {
+    struct _xsltKeyDef *next;
+    xmlNodePtr inst;
+    xmlChar *name;
+    xmlChar *nameURI;
+    xmlChar *match;
+    xmlChar *use;
+    xmlXPathCompExprPtr comp;
+    xmlXPathCompExprPtr usecomp;
+    xmlNsPtr *nsList;           /* the namespaces in scope */
+    int nsNr;                   /* the number of namespaces in scope */
+};
+
+/**
+ * xsltKeyTable:
+ *
+ * Holds the computed keys for key definitions of the same QName.
+ * Is owned by an xsltDocument.
+ */
+typedef struct _xsltKeyTable xsltKeyTable;
+typedef xsltKeyTable *xsltKeyTablePtr;
+struct _xsltKeyTable {
+    struct _xsltKeyTable *next;
+    xmlChar *name;
+    xmlChar *nameURI;
+    xmlHashTablePtr keys;
+};
+
+/*
+ * The in-memory structure corresponding to an XSLT Stylesheet.
+ * NOTE: most of the content is simply linked from the doc tree
+ *       structure, no specific allocation is made.
+ */
+typedef struct _xsltStylesheet xsltStylesheet;
+typedef xsltStylesheet *xsltStylesheetPtr;
+
+typedef struct _xsltTransformContext xsltTransformContext;
+typedef xsltTransformContext *xsltTransformContextPtr;
+
+/**
+ * xsltElemPreComp:
+ *
+ * The in-memory structure corresponding to element precomputed data,
+ * designed to be extended by extension implementors.
+ */
+typedef struct _xsltElemPreComp xsltElemPreComp;
+typedef xsltElemPreComp *xsltElemPreCompPtr;
+
+/**
+ * xsltTransformFunction:
+ * @ctxt: the XSLT transformation context
+ * @node: the input node
+ * @inst: the stylesheet node
+ * @comp: the compiled information from the stylesheet
+ *
+ * Signature of the function associated to elements part of the
+ * stylesheet language like xsl:if or xsl:apply-templates.
+ */
+typedef void (*xsltTransformFunction) (xsltTransformContextPtr ctxt,
+	                               xmlNodePtr node,
+				       xmlNodePtr inst,
+			               xsltElemPreCompPtr comp);
+
+/**
+ * xsltSortFunc:
+ * @ctxt:    a transformation context
+ * @sorts:   the node-set to sort
+ * @nbsorts: the number of sorts
+ *
+ * Signature of the function to use during sorting
+ */
+typedef void (*xsltSortFunc) (xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
+			      int nbsorts);
+
+typedef enum {
+    XSLT_FUNC_COPY=1,
+    XSLT_FUNC_SORT,
+    XSLT_FUNC_TEXT,
+    XSLT_FUNC_ELEMENT,
+    XSLT_FUNC_ATTRIBUTE,
+    XSLT_FUNC_COMMENT,
+    XSLT_FUNC_PI,
+    XSLT_FUNC_COPYOF,
+    XSLT_FUNC_VALUEOF,
+    XSLT_FUNC_NUMBER,
+    XSLT_FUNC_APPLYIMPORTS,
+    XSLT_FUNC_CALLTEMPLATE,
+    XSLT_FUNC_APPLYTEMPLATES,
+    XSLT_FUNC_CHOOSE,
+    XSLT_FUNC_IF,
+    XSLT_FUNC_FOREACH,
+    XSLT_FUNC_DOCUMENT,
+    XSLT_FUNC_WITHPARAM,
+    XSLT_FUNC_PARAM,
+    XSLT_FUNC_VARIABLE,
+    XSLT_FUNC_WHEN,
+    XSLT_FUNC_EXTENSION
+#ifdef XSLT_REFACTORED
+    ,
+    XSLT_FUNC_OTHERWISE,
+    XSLT_FUNC_FALLBACK,
+    XSLT_FUNC_MESSAGE,
+    XSLT_FUNC_INCLUDE,
+    XSLT_FUNC_ATTRSET,
+    XSLT_FUNC_LITERAL_RESULT_ELEMENT,
+    XSLT_FUNC_UNKOWN_FORWARDS_COMPAT
+#endif
+} xsltStyleType;
+
+/**
+ * xsltElemPreCompDeallocator:
+ * @comp:  the #xsltElemPreComp to free up
+ *
+ * Deallocates an #xsltElemPreComp structure.
+ */
+typedef void (*xsltElemPreCompDeallocator) (xsltElemPreCompPtr comp);
+
+/**
+ * xsltElemPreComp:
+ *
+ * The basic structure for compiled items of the AST of the XSLT processor.
+ * This structure is also intended to be extended by extension implementors.
+ * TODO: This is somehow not nice, since it has a "free" field, which
+ *   derived stylesheet-structs do not have.
+ */
+struct _xsltElemPreComp {
+    xsltElemPreCompPtr next;		/* next item in the global chained
+					   list hold by xsltStylesheet. */
+    xsltStyleType type;		/* type of the element */
+    xsltTransformFunction func; 	/* handling function */
+    xmlNodePtr inst;			/* the node in the stylesheet's tree
+					   corresponding to this item */
+
+    /* end of common part */
+    xsltElemPreCompDeallocator free;	/* the deallocator */
+};
+
+/**
+ * xsltStylePreComp:
+ *
+ * The abstract basic structure for items of the XSLT processor.
+ * This includes:
+ * 1) compiled forms of XSLT instructions (xsl:if, xsl:attribute, etc.)
+ * 2) compiled forms of literal result elements
+ * 3) compiled forms of extension elements
+ */
+typedef struct _xsltStylePreComp xsltStylePreComp;
+typedef xsltStylePreComp *xsltStylePreCompPtr;
+
+#ifdef XSLT_REFACTORED
+
+/*
+* Some pointer-list utility functions.
+*/
+XSLTPUBFUN xsltPointerListPtr XSLTCALL
+		xsltPointerListCreate		(int initialSize);
+XSLTPUBFUN void XSLTCALL
+		xsltPointerListFree		(xsltPointerListPtr list);
+XSLTPUBFUN void XSLTCALL
+		xsltPointerListClear		(xsltPointerListPtr list);
+XSLTPUBFUN int XSLTCALL
+		xsltPointerListAddSize		(xsltPointerListPtr list,						 
+						 void *item,
+						 int initialSize);
+
+/************************************************************************
+ *									*
+ * Refactored structures                                                *
+ *									*
+ ************************************************************************/
+
+typedef struct _xsltNsListContainer xsltNsListContainer;
+typedef xsltNsListContainer *xsltNsListContainerPtr;
+struct _xsltNsListContainer {
+    xmlNsPtr *list;
+    int totalNumber;
+    int xpathNumber;    
+};
+
+/**
+ * XSLT_ITEM_COMPATIBILITY_FIELDS:
+ * 
+ * Fields for API compatibility to the structure
+ * _xsltElemPreComp which is used for extension functions.
+ * Note that @next is used for storage; it does not reflect a next
+ * sibling in the tree.
+ * TODO: Evaluate if we really need such a compatibility.
+ */
+#define XSLT_ITEM_COMPATIBILITY_FIELDS \
+    xsltElemPreCompPtr next;\
+    xsltStyleType type;\
+    xsltTransformFunction func;\
+    xmlNodePtr inst;
+
+/**
+ * XSLT_ITEM_NAVIGATION_FIELDS:
+ *
+ * Currently empty.
+ * TODO: It is intended to hold navigational fields in the future.
+ */
+#define XSLT_ITEM_NAVIGATION_FIELDS
+/*
+    xsltStylePreCompPtr parent;\
+    xsltStylePreCompPtr children;\
+    xsltStylePreCompPtr nextItem; 
+*/
+
+/**
+ * XSLT_ITEM_NSINSCOPE_FIELDS:
+ *
+ * The in-scope namespaces.
+ */
+#define XSLT_ITEM_NSINSCOPE_FIELDS xsltNsListContainerPtr inScopeNs;
+
+/**
+ * XSLT_ITEM_COMMON_FIELDS:
+ *
+ * Common fields used for all items.
+ */
+#define XSLT_ITEM_COMMON_FIELDS \
+    XSLT_ITEM_COMPATIBILITY_FIELDS \
+    XSLT_ITEM_NAVIGATION_FIELDS \
+    XSLT_ITEM_NSINSCOPE_FIELDS
+
+/**
+ * _xsltStylePreComp: 
+ *
+ * The abstract basic structure for items of the XSLT processor.
+ * This includes:
+ * 1) compiled forms of XSLT instructions (e.g. xsl:if, xsl:attribute, etc.)
+ * 2) compiled forms of literal result elements
+ * 3) various properties for XSLT instructions (e.g. xsl:when,
+ *    xsl:with-param)
+ *
+ * REVISIT TODO: Keep this structure equal to the fields
+ *   defined by XSLT_ITEM_COMMON_FIELDS
+ */
+struct _xsltStylePreComp {
+    xsltElemPreCompPtr next;    /* next item in the global chained
+				   list hold by xsltStylesheet */
+    xsltStyleType type;         /* type of the item */ 
+    xsltTransformFunction func; /* handling function */
+    xmlNodePtr inst;		/* the node in the stylesheet's tree
+				   corresponding to this item. */
+    /* Currently no navigational fields. */
+    xsltNsListContainerPtr inScopeNs;
+};
+
+/**
+ * xsltStyleBasicEmptyItem:
+ * 
+ * Abstract structure only used as a short-cut for
+ * XSLT items with no extra fields.
+ * NOTE that it is intended that this structure looks the same as
+ *  _xsltStylePreComp.
+ */
+typedef struct _xsltStyleBasicEmptyItem xsltStyleBasicEmptyItem;
+typedef xsltStyleBasicEmptyItem *xsltStyleBasicEmptyItemPtr;
+
+struct _xsltStyleBasicEmptyItem {
+    XSLT_ITEM_COMMON_FIELDS
+};
+
+/**
+ * xsltStyleBasicExpressionItem:
+ * 
+ * Abstract structure only used as a short-cut for
+ * XSLT items with just an expression.
+ */
+typedef struct _xsltStyleBasicExpressionItem xsltStyleBasicExpressionItem;
+typedef xsltStyleBasicExpressionItem *xsltStyleBasicExpressionItemPtr;
+
+struct _xsltStyleBasicExpressionItem {
+    XSLT_ITEM_COMMON_FIELDS
+
+    const xmlChar *select; /* TODO: Change this to "expression". */
+    xmlXPathCompExprPtr comp; /* TODO: Change this to compExpr. */
+};
+
+/************************************************************************
+ *									*
+ * XSLT-instructions/declarations                                       *
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltStyleItemElement:
+ * 
+ * <!-- Category: instruction -->
+ * <xsl:element
+ *  name = { qname }
+ *  namespace = { uri-reference }
+ *  use-attribute-sets = qnames>
+ *  <!-- Content: template -->
+ * </xsl:element>
+ */
+typedef struct _xsltStyleItemElement xsltStyleItemElement;
+typedef xsltStyleItemElement *xsltStyleItemElementPtr;
+
+struct _xsltStyleItemElement {
+    XSLT_ITEM_COMMON_FIELDS 
+
+    const xmlChar *use;
+    int      has_use;
+    const xmlChar *name;    
+    int      has_name;
+    const xmlChar *ns;
+    const xmlChar *nsPrefix;
+    int      has_ns;
+};
+
+/**
+ * xsltStyleItemAttribute:
+ *
+ * <!-- Category: instruction -->
+ * <xsl:attribute
+ *  name = { qname }
+ *  namespace = { uri-reference }>
+ *  <!-- Content: template -->
+ * </xsl:attribute>
+ */
+typedef struct _xsltStyleItemAttribute xsltStyleItemAttribute;
+typedef xsltStyleItemAttribute *xsltStyleItemAttributePtr;
+
+struct _xsltStyleItemAttribute {
+    XSLT_ITEM_COMMON_FIELDS
+    const xmlChar *name;
+    int      has_name;
+    const xmlChar *ns;
+    const xmlChar *nsPrefix;
+    int      has_ns;
+};
+
+/**
+ * xsltStyleItemText:
+ *
+ * <!-- Category: instruction -->
+ * <xsl:text
+ *  disable-output-escaping = "yes" | "no">
+ *  <!-- Content: #PCDATA -->
+ * </xsl:text>
+ */
+typedef struct _xsltStyleItemText xsltStyleItemText;
+typedef xsltStyleItemText *xsltStyleItemTextPtr;
+
+struct _xsltStyleItemText {
+    XSLT_ITEM_COMMON_FIELDS
+    int      noescape;		/* text */
+};
+
+/**
+ * xsltStyleItemComment:
+ *
+ * <!-- Category: instruction -->
+ *  <xsl:comment>
+ *  <!-- Content: template -->
+ * </xsl:comment>
+ */
+typedef xsltStyleBasicEmptyItem xsltStyleItemComment;
+typedef xsltStyleItemComment *xsltStyleItemCommentPtr;
+
+/**
+ * xsltStyleItemPI:
+ *
+ * <!-- Category: instruction -->
+ *  <xsl:processing-instruction
+ *  name = { ncname }>
+ *  <!-- Content: template -->
+ * </xsl:processing-instruction>
+ */
+typedef struct _xsltStyleItemPI xsltStyleItemPI;
+typedef xsltStyleItemPI *xsltStyleItemPIPtr;
+
+struct _xsltStyleItemPI {
+    XSLT_ITEM_COMMON_FIELDS
+    const xmlChar *name;
+    int      has_name;
+};
+
+/**
+ * xsltStyleItemApplyImports:
+ *
+ * <!-- Category: instruction -->
+ * <xsl:apply-imports />
+ */
+typedef xsltStyleBasicEmptyItem xsltStyleItemApplyImports;
+typedef xsltStyleItemApplyImports *xsltStyleItemApplyImportsPtr;
+
+/**
+ * xsltStyleItemApplyTemplates:
+ *
+ * <!-- Category: instruction -->
+ *  <xsl:apply-templates
+ *  select = node-set-expression
+ *  mode = qname>
+ *  <!-- Content: (xsl:sort | xsl:with-param)* -->
+ * </xsl:apply-templates>
+ */
+typedef struct _xsltStyleItemApplyTemplates xsltStyleItemApplyTemplates;
+typedef xsltStyleItemApplyTemplates *xsltStyleItemApplyTemplatesPtr;
+
+struct _xsltStyleItemApplyTemplates {
+    XSLT_ITEM_COMMON_FIELDS
+
+    const xmlChar *mode;	/* apply-templates */
+    const xmlChar *modeURI;	/* apply-templates */
+    const xmlChar *select;	/* sort, copy-of, value-of, apply-templates */
+    xmlXPathCompExprPtr comp;	/* a precompiled XPath expression */
+    /* TODO: with-params */
+};
+
+/**
+ * xsltStyleItemCallTemplate:
+ *
+ * <!-- Category: instruction -->
+ *  <xsl:call-template
+ *  name = qname>
+ *  <!-- Content: xsl:with-param* -->
+ * </xsl:call-template>
+ */
+typedef struct _xsltStyleItemCallTemplate xsltStyleItemCallTemplate;
+typedef xsltStyleItemCallTemplate *xsltStyleItemCallTemplatePtr;
+
+struct _xsltStyleItemCallTemplate {
+    XSLT_ITEM_COMMON_FIELDS
+
+    xsltTemplatePtr templ;	/* call-template */
+    const xmlChar *name;	/* element, attribute, pi */
+    int      has_name;		/* element, attribute, pi */
+    const xmlChar *ns;		/* element */
+    int      has_ns;		/* element */
+    /* TODO: with-params */
+};
+
+/**
+ * xsltStyleItemCopy:
+ *
+ * <!-- Category: instruction -->
+ * <xsl:copy
+ *  use-attribute-sets = qnames>
+ *  <!-- Content: template -->
+ * </xsl:copy>
+ */
+typedef struct _xsltStyleItemCopy xsltStyleItemCopy;
+typedef xsltStyleItemCopy *xsltStyleItemCopyPtr;
+
+struct _xsltStyleItemCopy {
+   XSLT_ITEM_COMMON_FIELDS
+    const xmlChar *use;		/* copy, element */
+    int      has_use;		/* copy, element */    
+};
+
+/**
+ * xsltStyleItemIf:
+ *
+ * <!-- Category: instruction -->
+ *  <xsl:if
+ *  test = boolean-expression>
+ *  <!-- Content: template -->
+ * </xsl:if>
+ */
+typedef struct _xsltStyleItemIf xsltStyleItemIf;
+typedef xsltStyleItemIf *xsltStyleItemIfPtr;
+
+struct _xsltStyleItemIf {
+    XSLT_ITEM_COMMON_FIELDS
+
+    const xmlChar *test;	/* if */
+    xmlXPathCompExprPtr comp;	/* a precompiled XPath expression */
+};
+
+
+/**
+ * xsltStyleItemCopyOf:
+ *
+ * <!-- Category: instruction -->
+ * <xsl:copy-of
+ *  select = expression />
+ */
+typedef xsltStyleBasicExpressionItem xsltStyleItemCopyOf;
+typedef xsltStyleItemCopyOf *xsltStyleItemCopyOfPtr;
+
+/**
+ * xsltStyleItemValueOf:
+ *
+ * <!-- Category: instruction -->
+ * <xsl:value-of
+ *  select = string-expression
+ *  disable-output-escaping = "yes" | "no" />
+ */
+typedef struct _xsltStyleItemValueOf xsltStyleItemValueOf;
+typedef xsltStyleItemValueOf *xsltStyleItemValueOfPtr;
+
+struct _xsltStyleItemValueOf {
+    XSLT_ITEM_COMMON_FIELDS
+
+    const xmlChar *select;
+    xmlXPathCompExprPtr comp;	/* a precompiled XPath expression */
+    int      noescape;
+};
+
+/**
+ * xsltStyleItemNumber:
+ *
+ * <!-- Category: instruction -->
+ *  <xsl:number
+ *  level = "single" | "multiple" | "any"
+ *  count = pattern
+ *  from = pattern
+ *  value = number-expression
+ *  format = { string }
+ *  lang = { nmtoken }
+ *  letter-value = { "alphabetic" | "traditional" }
+ *  grouping-separator = { char }
+ *  grouping-size = { number } />
+ */
+typedef struct _xsltStyleItemNumber xsltStyleItemNumber;
+typedef xsltStyleItemNumber *xsltStyleItemNumberPtr;
+
+struct _xsltStyleItemNumber {
+    XSLT_ITEM_COMMON_FIELDS
+    xsltNumberData numdata;	/* number */
+};
+
+/**
+ * xsltStyleItemChoose:
+ *
+ * <!-- Category: instruction -->
+ *  <xsl:choose>
+ *  <!-- Content: (xsl:when+, xsl:otherwise?) -->
+ * </xsl:choose>
+ */
+typedef xsltStyleBasicEmptyItem xsltStyleItemChoose;
+typedef xsltStyleItemChoose *xsltStyleItemChoosePtr;
+
+/**
+ * xsltStyleItemFallback:
+ *
+ * <!-- Category: instruction -->
+ *  <xsl:fallback>
+ *  <!-- Content: template -->
+ * </xsl:fallback>
+ */
+typedef xsltStyleBasicEmptyItem xsltStyleItemFallback;
+typedef xsltStyleItemFallback *xsltStyleItemFallbackPtr;
+
+/**
+ * xsltStyleItemForEach:
+ *
+ * <!-- Category: instruction -->
+ * <xsl:for-each
+ *   select = node-set-expression>
+ *   <!-- Content: (xsl:sort*, template) -->
+ * </xsl:for-each>
+ */
+typedef xsltStyleBasicExpressionItem xsltStyleItemForEach;
+typedef xsltStyleItemForEach *xsltStyleItemForEachPtr;
+
+/**
+ * xsltStyleItemMessage:
+ *
+ * <!-- Category: instruction -->
+ * <xsl:message
+ *   terminate = "yes" | "no">
+ *   <!-- Content: template -->
+ * </xsl:message>
+ */
+typedef struct _xsltStyleItemMessage xsltStyleItemMessage;
+typedef xsltStyleItemMessage *xsltStyleItemMessagePtr;
+
+struct _xsltStyleItemMessage {
+    XSLT_ITEM_COMMON_FIELDS    
+    int terminate;
+};
+
+/**
+ * xsltStyleItemDocument:
+ *
+ * NOTE: This is not an instruction of XSLT 1.0.
+ */
+typedef struct _xsltStyleItemDocument xsltStyleItemDocument;
+typedef xsltStyleItemDocument *xsltStyleItemDocumentPtr;
+
+struct _xsltStyleItemDocument {
+    XSLT_ITEM_COMMON_FIELDS
+    int      ver11;		/* assigned: in xsltDocumentComp;
+                                  read: nowhere;
+                                  TODO: Check if we need. */
+    const xmlChar *filename;	/* document URL */
+    int has_filename;
+};   
+
+/************************************************************************
+ *									*
+ * Non-instructions (actually properties of instructions/declarations)  *
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltStyleBasicItemVariable:
+ *
+ * Basic struct for xsl:variable, xsl:param and xsl:with-param.
+ * It's currently important to have equal fields, since
+ * xsltParseStylesheetCallerParam() is used with xsl:with-param from
+ * the xslt side and with xsl:param from the exslt side (in
+ * exsltFuncFunctionFunction()).
+ *
+ * FUTURE NOTE: In XSLT 2.0 xsl:param, xsl:variable and xsl:with-param
+ *   have additional different fields.
+ */
+typedef struct _xsltStyleBasicItemVariable xsltStyleBasicItemVariable;
+typedef xsltStyleBasicItemVariable *xsltStyleBasicItemVariablePtr;
+
+struct _xsltStyleBasicItemVariable {
+    XSLT_ITEM_COMMON_FIELDS
+
+    const xmlChar *select;
+    xmlXPathCompExprPtr comp;
+
+    const xmlChar *name;
+    int      has_name;
+    const xmlChar *ns;
+    int      has_ns;
+};
+
+/**
+ * xsltStyleItemVariable:
+ *
+ * <!-- Category: top-level-element -->
+ * <xsl:param
+ *   name = qname
+ *   select = expression>
+ *   <!-- Content: template -->
+ * </xsl:param>
+ */
+typedef xsltStyleBasicItemVariable xsltStyleItemVariable;
+typedef xsltStyleItemVariable *xsltStyleItemVariablePtr;
+
+/**
+ * xsltStyleItemParam:
+ *
+ * <!-- Category: top-level-element -->
+ * <xsl:param
+ *   name = qname
+ *   select = expression>
+ *   <!-- Content: template -->
+ * </xsl:param>
+ */
+typedef struct _xsltStyleItemParam xsltStyleItemParam;
+typedef xsltStyleItemParam *xsltStyleItemParamPtr;
+
+struct _xsltStyleItemParam {
+    XSLT_ITEM_COMMON_FIELDS
+
+    const xmlChar *select;
+    xmlXPathCompExprPtr comp;
+
+    const xmlChar *name;
+    int      has_name;
+    const xmlChar *ns;
+    int      has_ns;    
+};
+
+/**
+ * xsltStyleItemWithParam:
+ *
+ * <xsl:with-param
+ *  name = qname
+ *  select = expression>
+ *  <!-- Content: template -->
+ * </xsl:with-param>
+ */
+typedef xsltStyleBasicItemVariable xsltStyleItemWithParam;
+typedef xsltStyleItemWithParam *xsltStyleItemWithParamPtr;
+
+/**
+ * xsltStyleItemSort:
+ *
+ * Reflects the XSLT xsl:sort item.
+ * Allowed parents: xsl:apply-templates, xsl:for-each
+ * <xsl:sort
+ *   select = string-expression
+ *   lang = { nmtoken }
+ *   data-type = { "text" | "number" | qname-but-not-ncname }
+ *   order = { "ascending" | "descending" }
+ *   case-order = { "upper-first" | "lower-first" } />
+ */
+typedef struct _xsltStyleItemSort xsltStyleItemSort;
+typedef xsltStyleItemSort *xsltStyleItemSortPtr;
+
+struct _xsltStyleItemSort {
+    XSLT_ITEM_COMMON_FIELDS
+
+    const xmlChar *stype;       /* sort */
+    int      has_stype;		/* sort */
+    int      number;		/* sort */
+    const xmlChar *order;	/* sort */
+    int      has_order;		/* sort */
+    int      descending;	/* sort */
+    const xmlChar *lang;	/* sort */
+    int      has_lang;		/* sort */
+    xsltLocale locale;		/* sort */
+    const xmlChar *case_order;	/* sort */
+    int      lower_first;	/* sort */
+
+    const xmlChar *use;
+    int      has_use;
+
+    const xmlChar *select;	/* sort, copy-of, value-of, apply-templates */
+
+    xmlXPathCompExprPtr comp;	/* a precompiled XPath expression */
+};
+
+
+/**
+ * xsltStyleItemWhen:
+ * 
+ * <xsl:when
+ *   test = boolean-expression>
+ *   <!-- Content: template -->
+ * </xsl:when>
+ * Allowed parent: xsl:choose
+ */
+typedef struct _xsltStyleItemWhen xsltStyleItemWhen;
+typedef xsltStyleItemWhen *xsltStyleItemWhenPtr;
+
+struct _xsltStyleItemWhen {
+    XSLT_ITEM_COMMON_FIELDS
+
+    const xmlChar *test;
+    xmlXPathCompExprPtr comp;
+};
+
+/**
+ * xsltStyleItemOtherwise:
+ *
+ * Allowed parent: xsl:choose
+ * <xsl:otherwise>
+ *   <!-- Content: template -->
+ * </xsl:otherwise>
+ */
+typedef struct _xsltStyleItemOtherwise xsltStyleItemOtherwise;
+typedef xsltStyleItemOtherwise *xsltStyleItemOtherwisePtr;
+
+struct _xsltStyleItemOtherwise {
+    XSLT_ITEM_COMMON_FIELDS
+};
+
+typedef struct _xsltStyleItemInclude xsltStyleItemInclude;
+typedef xsltStyleItemInclude *xsltStyleItemIncludePtr;
+
+struct _xsltStyleItemInclude {
+    XSLT_ITEM_COMMON_FIELDS
+    xsltDocumentPtr include;
+};
+
+/************************************************************************
+ *									*
+ *  XSLT elements in forwards-compatible mode                           *
+ *									*
+ ************************************************************************/
+
+typedef struct _xsltStyleItemUknown xsltStyleItemUknown;
+typedef xsltStyleItemUknown *xsltStyleItemUknownPtr;
+struct _xsltStyleItemUknown {
+    XSLT_ITEM_COMMON_FIELDS
+};
+
+
+/************************************************************************
+ *									*
+ *  Extension elements                                                  *
+ *									*
+ ************************************************************************/
+
+/*
+ * xsltStyleItemExtElement:
+ *
+ * Reflects extension elements.
+ *
+ * NOTE: Due to the fact that the structure xsltElemPreComp is most
+ * probably already heavily in use out there by users, so we cannot
+ * easily change it, we'll create an intermediate structure which will
+ * hold an xsltElemPreCompPtr.
+ * BIG NOTE: The only problem I see here is that the user processes the
+ *  content of the stylesheet tree, possibly he'll lookup the node->psvi
+ *  fields in order to find subsequent extension functions.
+ *  In this case, the user's code will break, since the node->psvi
+ *  field will hold now the xsltStyleItemExtElementPtr and not
+ *  the xsltElemPreCompPtr.
+ *  However the place where the structure is anchored in the node-tree,
+ *  namely node->psvi, has beed already once been moved from node->_private
+ *  to node->psvi, so we have a precedent here, which, I think, should allow
+ *  us to change such semantics without headaches.
+ */
+typedef struct _xsltStyleItemExtElement xsltStyleItemExtElement;
+typedef xsltStyleItemExtElement *xsltStyleItemExtElementPtr;
+struct _xsltStyleItemExtElement {
+    XSLT_ITEM_COMMON_FIELDS
+    xsltElemPreCompPtr item;   
+};
+
+/************************************************************************
+ *									*
+ *  Literal result elements                                             *
+ *									*
+ ************************************************************************/
+
+typedef struct _xsltEffectiveNs xsltEffectiveNs;
+typedef xsltEffectiveNs *xsltEffectiveNsPtr;
+struct _xsltEffectiveNs {
+    xsltEffectiveNsPtr nextInStore; /* storage next */
+    xsltEffectiveNsPtr next; /* next item in the list */
+    const xmlChar *prefix;
+    const xmlChar *nsName;
+    /* 
+    * Indicates if eclared on the literal result element; dunno if really
+    * needed.
+    */
+    int holdByElem;
+};
+
+/*
+ * Info for literal result elements.
+ * This will be set on the elem->psvi field and will be
+ * shared by literal result elements, which have the same
+ * excluded result namespaces; i.e., this *won't* be created uniquely
+ * for every literal result element.
+ */
+typedef struct _xsltStyleItemLRElementInfo xsltStyleItemLRElementInfo;
+typedef xsltStyleItemLRElementInfo *xsltStyleItemLRElementInfoPtr;
+struct _xsltStyleItemLRElementInfo {
+    XSLT_ITEM_COMMON_FIELDS
+    /*
+    * @effectiveNs is the set of effective ns-nodes
+    *  on the literal result element, which will be added to the result
+    *  element if not already existing in the result tree.
+    *  This means that excluded namespaces (via exclude-result-prefixes,
+    *  extension-element-prefixes and the XSLT namespace) not added
+    *  to the set.
+    *  Namespace-aliasing was applied on the @effectiveNs.
+    */
+    xsltEffectiveNsPtr effectiveNs;
+
+};
+
+#ifdef XSLT_REFACTORED
+
+typedef struct _xsltNsAlias xsltNsAlias;
+typedef xsltNsAlias *xsltNsAliasPtr;
+struct _xsltNsAlias {
+    xsltNsAliasPtr next; /* next in the list */    
+    xmlNsPtr literalNs;
+    xmlNsPtr targetNs;
+    xmlDocPtr docOfTargetNs;
+};
+#endif
+
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+
+typedef struct _xsltNsMap xsltNsMap;
+typedef xsltNsMap *xsltNsMapPtr;
+struct _xsltNsMap {
+    xsltNsMapPtr next; /* next in the list */
+    xmlDocPtr doc;
+    xmlNodePtr elem; /* the element holding the ns-decl */
+    xmlNsPtr ns; /* the xmlNs structure holding the XML namespace name */
+    const xmlChar *origNsName; /* the original XML namespace name */
+    const xmlChar *newNsName; /* the mapped XML namespace name */    
+};
+#endif
+
+/************************************************************************
+ *									*
+ *  Compile-time structures for *internal* use only                     *
+ *									*
+ ************************************************************************/
+
+typedef struct _xsltPrincipalStylesheetData xsltPrincipalStylesheetData;
+typedef xsltPrincipalStylesheetData *xsltPrincipalStylesheetDataPtr;
+
+typedef struct _xsltNsList xsltNsList;
+typedef xsltNsList *xsltNsListPtr;
+struct _xsltNsList {
+    xsltNsListPtr next; /* next in the list */
+    xmlNsPtr ns;
+};
+
+/*
+* xsltVarInfo:
+*
+* Used at compilation time for parameters and variables.
+*/
+typedef struct _xsltVarInfo xsltVarInfo;
+typedef xsltVarInfo *xsltVarInfoPtr;
+struct _xsltVarInfo {
+    xsltVarInfoPtr next; /* next in the list */
+    xsltVarInfoPtr prev;
+    int depth; /* the depth in the tree */
+    const xmlChar *name;
+    const xmlChar *nsName;
+};
+
+/**
+ * xsltCompilerNodeInfo:
+ *
+ * Per-node information during compile-time.
+ */
+typedef struct _xsltCompilerNodeInfo xsltCompilerNodeInfo;
+typedef xsltCompilerNodeInfo *xsltCompilerNodeInfoPtr;
+struct _xsltCompilerNodeInfo {
+    xsltCompilerNodeInfoPtr next;
+    xsltCompilerNodeInfoPtr prev;
+    xmlNodePtr node;
+    int depth;
+    xsltTemplatePtr templ;   /* The owning template */
+    int category;	     /* XSLT element, LR-element or
+                                extension element */
+    xsltStyleType type;
+    xsltElemPreCompPtr item; /* The compiled information */
+    /* The current in-scope namespaces */
+    xsltNsListContainerPtr inScopeNs;
+    /* The current excluded result namespaces */
+    xsltPointerListPtr exclResultNs; 
+    /* The current extension instruction namespaces */
+    xsltPointerListPtr extElemNs;
+
+    /* The current info for literal result elements. */
+    xsltStyleItemLRElementInfoPtr litResElemInfo;
+    /* 
+    * Set to 1 if in-scope namespaces changed,
+    *  or excluded result namespaces changed,
+    *  or extension element namespaces changed.
+    * This will trigger creation of new infos
+    *  for literal result elements.
+    */
+    int nsChanged;
+    int preserveWhitespace;
+    int stripWhitespace;
+    int isRoot; /* whether this is the stylesheet's root node */
+    int forwardsCompat; /* whether forwards-compatible mode is enabled */
+    /* whether the content of an extension element was processed */
+    int extContentHandled;
+    /* the type of the current child */
+    xsltStyleType curChildType;    
+};
+
+/**
+ * XSLT_CCTXT:
+ *
+ * get pointer to compiler context
+ */
+#define XSLT_CCTXT(style) ((xsltCompilerCtxtPtr) style->compCtxt) 
+
+typedef enum {
+    XSLT_ERROR_SEVERITY_ERROR = 0,
+    XSLT_ERROR_SEVERITY_WARNING
+} xsltErrorSeverityType;
+
+typedef struct _xsltCompilerCtxt xsltCompilerCtxt;
+typedef xsltCompilerCtxt *xsltCompilerCtxtPtr;
+struct _xsltCompilerCtxt {
+    void *errorCtxt;            /* user specific error context */
+    /*
+    * used for error/warning reports; e.g. XSLT_ERROR_SEVERITY_WARNING */
+    xsltErrorSeverityType errSeverity;		
+    int warnings;		/* TODO: number of warnings found at
+                                   compilation */
+    int errors;			/* TODO: number of errors found at
+                                   compilation */
+    xmlDictPtr dict;
+    xsltStylesheetPtr style;
+    int simplified; /* whether this is a simplified stylesheet */
+    /* TODO: structured/unstructured error contexts. */
+    int depth; /* Current depth of processing */
+    
+    xsltCompilerNodeInfoPtr inode;
+    xsltCompilerNodeInfoPtr inodeList;
+    xsltCompilerNodeInfoPtr inodeLast;
+    xsltPointerListPtr tmpList; /* Used for various purposes */
+    /*
+    * The XSLT version as specified by the stylesheet's root element.
+    */
+    int isInclude;
+    int hasForwardsCompat; /* whether forwards-compatible mode was used
+			     in a parsing episode */
+    int maxNodeInfos; /* TEMP TODO: just for the interest */
+    int maxLREs;  /* TEMP TODO: just for the interest */
+    /* 
+    * In order to keep the old behaviour, applying strict rules of
+    * the spec can be turned off. This has effect only on special
+    * mechanisms like whitespace-stripping in the stylesheet.
+    */
+    int strict;
+    xsltPrincipalStylesheetDataPtr psData;
+#ifdef XSLT_REFACTORED_XPATHCOMP
+    xmlXPathContextPtr xpathCtxt;
+#endif
+    xsltStyleItemUknownPtr unknownItem;
+    int hasNsAliases; /* Indicator if there was an xsl:namespace-alias. */
+    xsltNsAliasPtr nsAliases;
+    xsltVarInfoPtr ivars; /* Storage of local in-scope variables/params. */
+    xsltVarInfoPtr ivar; /* topmost local variable/param. */
+};   
+
+#else /* XSLT_REFACTORED */
+/*
+* The old structures before refactoring.
+*/
+
+/**
+ * _xsltStylePreComp:
+ *
+ * The in-memory structure corresponding to XSLT stylesheet constructs
+ * precomputed data.
+ */
+struct _xsltStylePreComp {
+    xsltElemPreCompPtr next;	/* chained list */
+    xsltStyleType type;		/* type of the element */
+    xsltTransformFunction func; /* handling function */
+    xmlNodePtr inst;		/* the instruction */
+
+    /*
+     * Pre computed values.
+     */
+
+    const xmlChar *stype;       /* sort */
+    int      has_stype;		/* sort */
+    int      number;		/* sort */
+    const xmlChar *order;	/* sort */
+    int      has_order;		/* sort */
+    int      descending;	/* sort */
+    const xmlChar *lang;	/* sort */
+    int      has_lang;		/* sort */
+    xsltLocale locale;		/* sort */
+    const xmlChar *case_order;	/* sort */
+    int      lower_first;	/* sort */
+
+    const xmlChar *use;		/* copy, element */
+    int      has_use;		/* copy, element */
+
+    int      noescape;		/* text */
+
+    const xmlChar *name;	/* element, attribute, pi */
+    int      has_name;		/* element, attribute, pi */
+    const xmlChar *ns;		/* element */
+    int      has_ns;		/* element */
+
+    const xmlChar *mode;	/* apply-templates */
+    const xmlChar *modeURI;	/* apply-templates */
+
+    const xmlChar *test;	/* if */
+
+    xsltTemplatePtr templ;	/* call-template */
+
+    const xmlChar *select;	/* sort, copy-of, value-of, apply-templates */
+
+    int      ver11;		/* document */
+    const xmlChar *filename;	/* document URL */
+    int      has_filename;	/* document */
+
+    xsltNumberData numdata;	/* number */
+
+    xmlXPathCompExprPtr comp;	/* a precompiled XPath expression */
+    xmlNsPtr *nsList;		/* the namespaces in scope */
+    int nsNr;			/* the number of namespaces in scope */
+};
+
+#endif /* XSLT_REFACTORED */
+
+
+/*
+ * The in-memory structure corresponding to an XSLT Variable
+ * or Param.
+ */
+typedef struct _xsltStackElem xsltStackElem;
+typedef xsltStackElem *xsltStackElemPtr;
+struct _xsltStackElem {
+    struct _xsltStackElem *next;/* chained list */
+    xsltStylePreCompPtr comp;   /* the compiled form */
+    int computed;		/* was the evaluation done */
+    const xmlChar *name;	/* the local part of the name QName */
+    const xmlChar *nameURI;	/* the URI part of the name QName */
+    const xmlChar *select;	/* the eval string */
+    xmlNodePtr tree;		/* the sequence constructor if no eval
+				    string or the location */
+    xmlXPathObjectPtr value;	/* The value if computed */
+    xmlDocPtr fragment;		/* The Result Tree Fragments (needed for XSLT 1.0)
+				   which are bound to the variable's lifetime. */
+    int level;                  /* the depth in the tree;
+                                   -1 if persistent (e.g. a given xsl:with-param) */
+    xsltTransformContextPtr context; /* The transformation context; needed to cache
+                                        the variables */
+    int flags;
+};
+
+#ifdef XSLT_REFACTORED
+
+struct _xsltPrincipalStylesheetData {
+    /*
+    * Namespace dictionary for ns-prefixes and ns-names:
+    * TODO: Shared between stylesheets, and XPath mechanisms.
+    *   Not used yet.
+    */
+    xmlDictPtr namespaceDict;
+    /*
+    * Global list of in-scope namespaces.
+    */
+    xsltPointerListPtr inScopeNamespaces;
+    /*
+    * Global list of information for [xsl:]excluded-result-prefixes.
+    */
+    xsltPointerListPtr exclResultNamespaces;
+    /*
+    * Global list of information for [xsl:]extension-element-prefixes.
+    */
+    xsltPointerListPtr extElemNamespaces;
+    xsltEffectiveNsPtr effectiveNs;
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+    /*
+    * Namespace name map to get rid of string comparison of namespace names.
+    */
+    xsltNsMapPtr nsMap;
+#endif
+};
+
+    
+#endif
+/*
+ * Note that we added a @compCtxt field to anchor an stylesheet compilation
+ * context, since, due to historical reasons, various compile-time function
+ * take only the stylesheet as argument and not a compilation context.
+ */
+struct _xsltStylesheet {
+    /*
+     * The stylesheet import relation is kept as a tree.
+     */
+    struct _xsltStylesheet *parent;
+    struct _xsltStylesheet *next;
+    struct _xsltStylesheet *imports;
+
+    xsltDocumentPtr docList;		/* the include document list */
+
+    /*
+     * General data on the style sheet document.
+     */
+    xmlDocPtr doc;		/* the parsed XML stylesheet */
+    xmlHashTablePtr stripSpaces;/* the hash table of the strip-space and
+				   preserve space elements */
+    int             stripAll;	/* strip-space * (1) preserve-space * (-1) */
+    xmlHashTablePtr cdataSection;/* the hash table of the cdata-section */
+
+    /*
+     * Global variable or parameters.
+     */
+    xsltStackElemPtr variables; /* linked list of param and variables */
+
+    /*
+     * Template descriptions.
+     */
+    xsltTemplatePtr templates;	/* the ordered list of templates */
+    void *templatesHash;	/* hash table or wherever compiled templates
+				   informations are stored */
+    void *rootMatch;		/* template based on / */
+    void *keyMatch;		/* template based on key() */
+    void *elemMatch;		/* template based on * */
+    void *attrMatch;		/* template based on @* */
+    void *parentMatch;		/* template based on .. */
+    void *textMatch;		/* template based on text() */
+    void *piMatch;		/* template based on processing-instruction() */
+    void *commentMatch;		/* template based on comment() */
+    
+    /*
+     * Namespace aliases.
+     * NOTE: Not used in the refactored code.
+     */
+    xmlHashTablePtr nsAliases;	/* the namespace alias hash tables */
+
+    /*
+     * Attribute sets.
+     */
+    xmlHashTablePtr attributeSets;/* the attribute sets hash tables */
+
+    /*
+     * Namespaces.
+     * TODO: Eliminate this.
+     */
+    xmlHashTablePtr nsHash;     /* the set of namespaces in use:
+                                   ATTENTION: This is used for
+                                   execution of XPath expressions; unfortunately
+                                   it restricts the stylesheet to have distinct
+                                   prefixes.
+				   TODO: We need to get rid of this.    
+				 */
+    void           *nsDefs;     /* ATTENTION TODO: This is currently used to store
+				   xsltExtDefPtr (in extensions.c) and
+                                   *not* xmlNsPtr.
+				 */
+
+    /*
+     * Key definitions.
+     */
+    void *keys;			/* key definitions */
+
+    /*
+     * Output related stuff.
+     */
+    xmlChar *method;		/* the output method */
+    xmlChar *methodURI;		/* associated namespace if any */
+    xmlChar *version;		/* version string */
+    xmlChar *encoding;		/* encoding string */
+    int omitXmlDeclaration;     /* omit-xml-declaration = "yes" | "no" */
+
+    /* 
+     * Number formatting.
+     */
+    xsltDecimalFormatPtr decimalFormat;
+    int standalone;             /* standalone = "yes" | "no" */
+    xmlChar *doctypePublic;     /* doctype-public string */
+    xmlChar *doctypeSystem;     /* doctype-system string */
+    int indent;			/* should output being indented */
+    xmlChar *mediaType;		/* media-type string */
+
+    /*
+     * Precomputed blocks.
+     */
+    xsltElemPreCompPtr preComps;/* list of precomputed blocks */
+    int warnings;		/* number of warnings found at compilation */
+    int errors;			/* number of errors found at compilation */
+
+    xmlChar  *exclPrefix;	/* last excluded prefixes */
+    xmlChar **exclPrefixTab;	/* array of excluded prefixes */
+    int       exclPrefixNr;	/* number of excluded prefixes in scope */
+    int       exclPrefixMax;	/* size of the array */
+
+    void     *_private;		/* user defined data */
+
+    /*
+     * Extensions.
+     */
+    xmlHashTablePtr extInfos;	/* the extension data */
+    int		    extrasNr;	/* the number of extras required */
+
+    /*
+     * For keeping track of nested includes
+     */
+    xsltDocumentPtr includes;	/* points to last nested include */
+
+    /*
+     * dictionary: shared between stylesheet, context and documents.
+     */
+    xmlDictPtr dict;
+    /*
+     * precompiled attribute value templates.
+     */
+    void *attVTs;
+    /*
+     * if namespace-alias has an alias for the default stylesheet prefix
+     * NOTE: Not used in the refactored code.
+     */
+    const xmlChar *defaultAlias;
+    /*
+     * bypass pre-processing (already done) (used in imports)
+     */
+    int nopreproc;
+    /*
+     * all document text strings were internalized
+     */
+    int internalized;
+    /*
+     * Literal Result Element as Stylesheet c.f. section 2.3
+     */
+    int literal_result;
+    /*
+    * The principal stylesheet
+    */
+    xsltStylesheetPtr principal;
+#ifdef XSLT_REFACTORED
+    /*
+    * Compilation context used during compile-time.
+    */
+    xsltCompilerCtxtPtr compCtxt; /* TODO: Change this to (void *). */
+
+    xsltPrincipalStylesheetDataPtr principalData;    
+#endif
+};
+
+typedef struct _xsltTransformCache xsltTransformCache;
+typedef xsltTransformCache *xsltTransformCachePtr;
+struct _xsltTransformCache {
+    xmlDocPtr RVT;
+    int nbRVT;
+    xsltStackElemPtr stackItems;
+    int nbStackItems;
+#ifdef XSLT_DEBUG_PROFILE_CACHE
+    int dbgCachedRVTs;
+    int dbgReusedRVTs;
+    int dbgCachedVars;
+    int dbgReusedVars;
+#endif
+};
+
+/*
+ * The in-memory structure corresponding to an XSLT Transformation.
+ */
+typedef enum {
+    XSLT_OUTPUT_XML = 0,
+    XSLT_OUTPUT_HTML,
+    XSLT_OUTPUT_TEXT
+} xsltOutputType;
+
+typedef enum {
+    XSLT_STATE_OK = 0,
+    XSLT_STATE_ERROR,
+    XSLT_STATE_STOPPED
+} xsltTransformState;
+
+struct _xsltTransformContext {
+    xsltStylesheetPtr style;		/* the stylesheet used */
+    xsltOutputType type;		/* the type of output */
+
+    xsltTemplatePtr  templ;		/* the current template */
+    int              templNr;		/* Nb of templates in the stack */
+    int              templMax;		/* Size of the templtes stack */
+    xsltTemplatePtr *templTab;		/* the template stack */
+
+    xsltStackElemPtr  vars;		/* the current variable list */
+    int               varsNr;		/* Nb of variable list in the stack */
+    int               varsMax;		/* Size of the variable list stack */
+    xsltStackElemPtr *varsTab;		/* the variable list stack */
+    int               varsBase;		/* the var base for current templ */
+
+    /*
+     * Extensions
+     */
+    xmlHashTablePtr   extFunctions;	/* the extension functions */
+    xmlHashTablePtr   extElements;	/* the extension elements */
+    xmlHashTablePtr   extInfos;		/* the extension data */
+
+    const xmlChar *mode;		/* the current mode */
+    const xmlChar *modeURI;		/* the current mode URI */
+
+    xsltDocumentPtr docList;		/* the document list */
+
+    xsltDocumentPtr document;		/* the current source document; can be NULL if an RTF */
+    xmlNodePtr node;			/* the current node being processed */
+    xmlNodeSetPtr nodeList;		/* the current node list */
+    /* xmlNodePtr current;			the node */
+
+    xmlDocPtr output;			/* the resulting document */
+    xmlNodePtr insert;			/* the insertion node */
+
+    xmlXPathContextPtr xpathCtxt;	/* the XPath context */
+    xsltTransformState state;		/* the current state */
+
+    /*
+     * Global variables
+     */
+    xmlHashTablePtr   globalVars;	/* the global variables and params */
+
+    xmlNodePtr inst;			/* the instruction in the stylesheet */
+
+    int xinclude;			/* should XInclude be processed */
+
+    const char *      outputFile;	/* the output URI if known */
+
+    int profile;                        /* is this run profiled */
+    long             prof;		/* the current profiled value */
+    int              profNr;		/* Nb of templates in the stack */
+    int              profMax;		/* Size of the templtaes stack */
+    long            *profTab;		/* the profile template stack */
+
+    void            *_private;		/* user defined data */
+
+    int              extrasNr;		/* the number of extras used */
+    int              extrasMax;		/* the number of extras allocated */
+    xsltRuntimeExtraPtr extras;		/* extra per runtime informations */
+
+    xsltDocumentPtr  styleList;		/* the stylesheet docs list */
+    void                 * sec;		/* the security preferences if any */
+
+    xmlGenericErrorFunc  error;		/* a specific error handler */
+    void              * errctx;		/* context for the error handler */
+
+    xsltSortFunc      sortfunc;		/* a ctxt specific sort routine */
+
+    /*
+     * handling of temporary Result Value Tree
+     * (XSLT 1.0 term: "Result Tree Fragment")
+     */
+    xmlDocPtr       tmpRVT;		/* list of RVT without persistance */
+    xmlDocPtr       persistRVT;		/* list of persistant RVTs */
+    int             ctxtflags;          /* context processing flags */
+
+    /*
+     * Speed optimization when coalescing text nodes
+     */
+    const xmlChar  *lasttext;		/* last text node content */
+    unsigned int    lasttsize;		/* last text node size */
+    unsigned int    lasttuse;		/* last text node use */
+    /*
+     * Per Context Debugging
+     */
+    int debugStatus;			/* the context level debug status */
+    unsigned long* traceCode;		/* pointer to the variable holding the mask */
+
+    int parserOptions;			/* parser options xmlParserOption */
+
+    /*
+     * dictionary: shared between stylesheet, context and documents.
+     */
+    xmlDictPtr dict;
+    xmlDocPtr		tmpDoc; /* Obsolete; not used in the library. */
+    /*
+     * all document text strings are internalized
+     */
+    int internalized;
+    int nbKeys;
+    int hasTemplKeyPatterns;
+    xsltTemplatePtr currentTemplateRule; /* the Current Template Rule */
+    xmlNodePtr initialContextNode;
+    xmlDocPtr initialContextDoc;
+    xsltTransformCachePtr cache;
+    void *contextVariable; /* the current variable item */
+    xmlDocPtr localRVT; /* list of local tree fragments; will be freed when
+			   the instruction which created the fragment
+                           exits */
+    xmlDocPtr localRVTBase;
+    int keyInitLevel;   /* Needed to catch recursive keys issues */
+    int funcLevel;      /* Needed to catch recursive functions issues */
+};
+
+/**
+ * CHECK_STOPPED:
+ *
+ * Macro to check if the XSLT processing should be stopped.
+ * Will return from the function.
+ */
+#define CHECK_STOPPED if (ctxt->state == XSLT_STATE_STOPPED) return;
+
+/**
+ * CHECK_STOPPEDE:
+ *
+ * Macro to check if the XSLT processing should be stopped.
+ * Will goto the error: label.
+ */
+#define CHECK_STOPPEDE if (ctxt->state == XSLT_STATE_STOPPED) goto error;
+
+/**
+ * CHECK_STOPPED0:
+ *
+ * Macro to check if the XSLT processing should be stopped.
+ * Will return from the function with a 0 value.
+ */
+#define CHECK_STOPPED0 if (ctxt->state == XSLT_STATE_STOPPED) return(0);
+
+/*
+ * The macro XML_CAST_FPTR is a hack to avoid a gcc warning about
+ * possible incompatibilities between function pointers and object
+ * pointers.  It is defined in libxml/hash.h within recent versions
+ * of libxml2, but is put here for compatibility.
+ */
+#ifndef XML_CAST_FPTR
+/**
+ * XML_CAST_FPTR:
+ * @fptr:  pointer to a function
+ *
+ * Macro to do a casting from an object pointer to a
+ * function pointer without encountering a warning from
+ * gcc
+ *
+ * #define XML_CAST_FPTR(fptr) (*(void **)(&fptr))
+ * This macro violated ISO C aliasing rules (gcc4 on s390 broke)
+ * so it is disabled now
+ */
+
+#define XML_CAST_FPTR(fptr) fptr
+#endif
+/*
+ * Functions associated to the internal types
+xsltDecimalFormatPtr	xsltDecimalFormatGetByName(xsltStylesheetPtr sheet,
+						   xmlChar *name);
+ */
+XSLTPUBFUN xsltStylesheetPtr XSLTCALL	
+			xsltNewStylesheet	(void);
+XSLTPUBFUN xsltStylesheetPtr XSLTCALL	
+			xsltParseStylesheetFile	(const xmlChar* filename);
+XSLTPUBFUN void XSLTCALL			
+			xsltFreeStylesheet	(xsltStylesheetPtr style);
+XSLTPUBFUN int XSLTCALL			
+			xsltIsBlank		(xmlChar *str);
+XSLTPUBFUN void XSLTCALL			
+			xsltFreeStackElemList	(xsltStackElemPtr elem);
+XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL	
+			xsltDecimalFormatGetByName(xsltStylesheetPtr style,
+						 xmlChar *name);
+
+XSLTPUBFUN xsltStylesheetPtr XSLTCALL	
+			xsltParseStylesheetProcess(xsltStylesheetPtr ret,
+						 xmlDocPtr doc);
+XSLTPUBFUN void XSLTCALL			
+			xsltParseStylesheetOutput(xsltStylesheetPtr style,
+						 xmlNodePtr cur);
+XSLTPUBFUN xsltStylesheetPtr XSLTCALL	
+			xsltParseStylesheetDoc	(xmlDocPtr doc);
+XSLTPUBFUN xsltStylesheetPtr XSLTCALL	
+			xsltParseStylesheetImportedDoc(xmlDocPtr doc,
+						xsltStylesheetPtr style);
+XSLTPUBFUN xsltStylesheetPtr XSLTCALL	
+			xsltLoadStylesheetPI	(xmlDocPtr doc);
+XSLTPUBFUN void XSLTCALL 			
+			xsltNumberFormat	(xsltTransformContextPtr ctxt,
+						 xsltNumberDataPtr data,
+						 xmlNodePtr node);
+XSLTPUBFUN xmlXPathError XSLTCALL		 
+			xsltFormatNumberConversion(xsltDecimalFormatPtr self,
+						 xmlChar *format,
+						 double number,
+						 xmlChar **result);
+
+XSLTPUBFUN void XSLTCALL			
+			xsltParseTemplateContent(xsltStylesheetPtr style,
+						 xmlNodePtr templ);
+XSLTPUBFUN int XSLTCALL			
+			xsltAllocateExtra	(xsltStylesheetPtr style);
+XSLTPUBFUN int XSLTCALL			
+			xsltAllocateExtraCtxt	(xsltTransformContextPtr ctxt);
+/*
+ * Extra functions for Result Value Trees
+ */
+XSLTPUBFUN xmlDocPtr XSLTCALL		
+			xsltCreateRVT		(xsltTransformContextPtr ctxt);
+XSLTPUBFUN int XSLTCALL			
+			xsltRegisterTmpRVT	(xsltTransformContextPtr ctxt,
+						 xmlDocPtr RVT);
+XSLTPUBFUN int XSLTCALL			
+			xsltRegisterLocalRVT	(xsltTransformContextPtr ctxt,
+						 xmlDocPtr RVT);
+XSLTPUBFUN int XSLTCALL			
+			xsltRegisterPersistRVT	(xsltTransformContextPtr ctxt,
+						 xmlDocPtr RVT);
+XSLTPUBFUN int XSLTCALL
+			xsltExtensionInstructionResultRegister(
+						 xsltTransformContextPtr ctxt,
+						 xmlXPathObjectPtr obj);
+XSLTPUBFUN int XSLTCALL
+			xsltExtensionInstructionResultFinalize(
+						 xsltTransformContextPtr ctxt);
+XSLTPUBFUN void XSLTCALL
+			xsltFreeRVTs		(xsltTransformContextPtr ctxt);
+XSLTPUBFUN void XSLTCALL
+			xsltReleaseRVT		(xsltTransformContextPtr ctxt,
+						 xmlDocPtr RVT);
+XSLTPUBFUN int XSLTCALL
+			xsltTransStorageAdd	(xsltTransformContextPtr ctxt,
+						 void *id,
+						 void *data);
+XSLTPUBFUN void * XSLTCALL
+			xsltTransStorageRemove	(xsltTransformContextPtr ctxt,
+						 void *id);
+
+/*
+ * Extra functions for Attribute Value Templates
+ */
+XSLTPUBFUN void XSLTCALL
+			xsltCompileAttr		(xsltStylesheetPtr style,
+						 xmlAttrPtr attr);
+XSLTPUBFUN xmlChar * XSLTCALL
+			xsltEvalAVT		(xsltTransformContextPtr ctxt,
+						 void *avt,
+						 xmlNodePtr node);
+XSLTPUBFUN void XSLTCALL
+			xsltFreeAVTList		(void *avt);
+
+/*
+ * Extra function for successful xsltCleanupGlobals / xsltInit sequence.
+ */
+
+XSLTPUBFUN void XSLTCALL
+			xsltUninit		(void);
+
+/************************************************************************
+ *									*
+ *  Compile-time functions for *internal* use only                      *
+ *									*
+ ************************************************************************/
+
+#ifdef XSLT_REFACTORED  
+XSLTPUBFUN void XSLTCALL
+			xsltParseSequenceConstructor(
+						 xsltCompilerCtxtPtr cctxt,
+						 xmlNodePtr start);
+XSLTPUBFUN int XSLTCALL
+			xsltParseAnyXSLTElem	(xsltCompilerCtxtPtr cctxt,
+						 xmlNodePtr elem);
+#ifdef XSLT_REFACTORED_XSLT_NSCOMP
+XSLTPUBFUN int XSLTCALL
+			xsltRestoreDocumentNamespaces(
+						 xsltNsMapPtr ns,
+						 xmlDocPtr doc);
+#endif
+#endif /* XSLT_REFACTORED */
+
+/************************************************************************
+ *									*
+ *  Transformation-time functions for *internal* use only               *
+ *									*
+ ************************************************************************/
+XSLTPUBFUN int XSLTCALL
+			xsltInitCtxtKey		(xsltTransformContextPtr ctxt,
+						 xsltDocumentPtr doc,
+						 xsltKeyDefPtr keyd);
+XSLTPUBFUN int XSLTCALL
+			xsltInitAllDocKeys	(xsltTransformContextPtr ctxt);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_H__ */
+
diff --git a/libxslt/xsltconfig.h b/libxslt/xsltconfig.h
new file mode 100644
index 0000000..db20ebd
--- /dev/null
+++ b/libxslt/xsltconfig.h
@@ -0,0 +1,172 @@
+/*
+ * Summary: compile-time version informations for the XSLT engine
+ * Description: compile-time version informations for the XSLT engine
+ *              this module is autogenerated.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLTCONFIG_H__
+#define __XML_XSLTCONFIG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * LIBXSLT_DOTTED_VERSION:
+ *
+ * the version string like "1.2.3"
+ */
+#define LIBXSLT_DOTTED_VERSION "1.1.26"
+
+/**
+ * LIBXSLT_VERSION:
+ *
+ * the version number: 1.2.3 value is 10203
+ */
+#define LIBXSLT_VERSION 10126
+
+/**
+ * LIBXSLT_VERSION_STRING:
+ *
+ * the version number string, 1.2.3 value is "10203"
+ */
+#define LIBXSLT_VERSION_STRING "10126"
+
+/**
+ * LIBXSLT_VERSION_EXTRA:
+ *
+ * extra version information, used to show a CVS compilation
+ */
+#define	LIBXSLT_VERSION_EXTRA "-GITv1.1.26"
+
+/**
+ * WITH_XSLT_DEBUG:
+ *
+ * Activate the compilation of the debug reporting. Speed penalty
+ * is insignifiant and being able to run xsltpoc -v is useful. On
+ * by default unless --without-debug is passed to configure
+ */
+#if 1
+#define WITH_XSLT_DEBUG
+#endif
+
+#if 1
+/**
+ * DEBUG_MEMORY:
+ *
+ * should be activated only when debugging libxslt. It replaces the
+ * allocator with a collect and debug shell to the libc allocator.
+ * Use configure --with-mem-debug to activate it on both library
+ */
+#define DEBUG_MEMORY
+
+/**
+ * DEBUG_MEMORY_LOCATION:
+ *
+ * should be activated only when debugging libxslt.
+ * DEBUG_MEMORY_LOCATION should be activated only when libxml has
+ * been configured with --with-debug-mem too
+ */
+#define DEBUG_MEMORY_LOCATION
+#endif
+
+/**
+ * XSLT_NEED_TRIO:
+ *
+ * should be activated if the existing libc library lacks some of the
+ * string formatting function, in that case reuse the Trio ones already
+ * compiled in the libxml2 library.
+ */
+
+#if 0
+#define XSLT_NEED_TRIO
+#endif
+#ifdef __VMS
+#define HAVE_MATH_H 1
+#define HAVE_SYS_STAT_H 1
+#ifndef XSLT_NEED_TRIO
+#define XSLT_NEED_TRIO
+#endif
+#endif
+
+#ifdef	XSLT_NEED_TRIO
+#define	TRIO_REPLACE_STDIO
+#endif
+
+/**
+ * WITH_XSLT_DEBUGGER:
+ *
+ * Activate the compilation of the debugger support. Speed penalty
+ * is insignifiant.
+ * On by default unless --without-debugger is passed to configure
+ */
+#if 1
+#ifndef WITH_DEBUGGER
+#define WITH_DEBUGGER
+#endif
+#endif
+
+/**
+ * WITH_MODULES:
+ *
+ * Whether module support is configured into libxslt
+ * Note: no default module path for win32 platforms
+ */
+#if 1
+#ifndef WITH_MODULES
+#define WITH_MODULES
+#endif
+#define LIBXSLT_DEFAULT_PLUGINS_PATH() "/usr/lib/libxslt-plugins"
+#endif
+
+/**
+ * Locale support
+ */
+#if 1
+#ifndef XSLT_LOCALE_XLOCALE
+#define XSLT_LOCALE_XLOCALE
+#endif
+#elif 0
+#ifndef XSLT_LOCALE_WINAPI
+#define XSLT_LOCALE_WINAPI
+#endif
+#endif
+
+/**
+ * ATTRIBUTE_UNUSED:
+ *
+ * This macro is used to flag unused function parameters to GCC
+ */
+#ifdef __GNUC__
+#ifdef HAVE_ANSIDECL_H
+#include <ansidecl.h>
+#endif
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED __attribute__((unused))
+#endif
+#else
+#define ATTRIBUTE_UNUSED
+#endif
+
+/**
+ * LIBXSLT_PUBLIC:
+ *
+ * This macro is used to declare PUBLIC variables for Cygwin and for MSC on Windows
+ */
+#if !defined LIBXSLT_PUBLIC
+#if (defined(__CYGWIN__) || defined _MSC_VER) && !defined IN_LIBXSLT && !defined LIBXSLT_STATIC
+#define LIBXSLT_PUBLIC __declspec(dllimport)
+#else
+#define LIBXSLT_PUBLIC
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLTCONFIG_H__ */
diff --git a/libxslt/xsltconfig.h.in b/libxslt/xsltconfig.h.in
new file mode 100644
index 0000000..b4cac6d
--- /dev/null
+++ b/libxslt/xsltconfig.h.in
@@ -0,0 +1,172 @@
+/*
+ * Summary: compile-time version informations for the XSLT engine
+ * Description: compile-time version informations for the XSLT engine
+ *              this module is autogenerated.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLTCONFIG_H__
+#define __XML_XSLTCONFIG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * LIBXSLT_DOTTED_VERSION:
+ *
+ * the version string like "1.2.3"
+ */
+#define LIBXSLT_DOTTED_VERSION "@VERSION@"
+
+/**
+ * LIBXSLT_VERSION:
+ *
+ * the version number: 1.2.3 value is 10203
+ */
+#define LIBXSLT_VERSION @LIBXSLT_VERSION_NUMBER@
+
+/**
+ * LIBXSLT_VERSION_STRING:
+ *
+ * the version number string, 1.2.3 value is "10203"
+ */
+#define LIBXSLT_VERSION_STRING "@LIBXSLT_VERSION_NUMBER@"
+
+/**
+ * LIBXSLT_VERSION_EXTRA:
+ *
+ * extra version information, used to show a CVS compilation
+ */
+#define	LIBXSLT_VERSION_EXTRA "@LIBXSLT_VERSION_EXTRA@"
+
+/**
+ * WITH_XSLT_DEBUG:
+ *
+ * Activate the compilation of the debug reporting. Speed penalty
+ * is insignifiant and being able to run xsltpoc -v is useful. On
+ * by default unless --without-debug is passed to configure
+ */
+#if @WITH_XSLT_DEBUG@
+#define WITH_XSLT_DEBUG
+#endif
+
+#if @WITH_MEM_DEBUG@
+/**
+ * DEBUG_MEMORY:
+ *
+ * should be activated only when debugging libxslt. It replaces the
+ * allocator with a collect and debug shell to the libc allocator.
+ * Use configure --with-mem-debug to activate it on both library
+ */
+#define DEBUG_MEMORY
+
+/**
+ * DEBUG_MEMORY_LOCATION:
+ *
+ * should be activated only when debugging libxslt.
+ * DEBUG_MEMORY_LOCATION should be activated only when libxml has
+ * been configured with --with-debug-mem too
+ */
+#define DEBUG_MEMORY_LOCATION
+#endif
+
+/**
+ * XSLT_NEED_TRIO:
+ *
+ * should be activated if the existing libc library lacks some of the
+ * string formatting function, in that case reuse the Trio ones already
+ * compiled in the libxml2 library.
+ */
+
+#if @WITH_TRIO@
+#define XSLT_NEED_TRIO
+#endif
+#ifdef __VMS
+#define HAVE_MATH_H 1
+#define HAVE_SYS_STAT_H 1
+#ifndef XSLT_NEED_TRIO
+#define XSLT_NEED_TRIO
+#endif
+#endif
+
+#ifdef	XSLT_NEED_TRIO
+#define	TRIO_REPLACE_STDIO
+#endif
+
+/**
+ * WITH_XSLT_DEBUGGER:
+ *
+ * Activate the compilation of the debugger support. Speed penalty
+ * is insignifiant.
+ * On by default unless --without-debugger is passed to configure
+ */
+#if @WITH_DEBUGGER@
+#ifndef WITH_DEBUGGER
+#define WITH_DEBUGGER
+#endif
+#endif
+
+/**
+ * WITH_MODULES:
+ *
+ * Whether module support is configured into libxslt
+ * Note: no default module path for win32 platforms
+ */
+#if @WITH_MODULES@
+#ifndef WITH_MODULES
+#define WITH_MODULES
+#endif
+#define LIBXSLT_DEFAULT_PLUGINS_PATH() "@LIBXSLT_DEFAULT_PLUGINS_PATH@"
+#endif
+
+/**
+ * Locale support
+ */
+#if @XSLT_LOCALE_XLOCALE@
+#ifndef XSLT_LOCALE_XLOCALE
+#define XSLT_LOCALE_XLOCALE
+#endif
+#elif @XSLT_LOCALE_WINAPI@
+#ifndef XSLT_LOCALE_WINAPI
+#define XSLT_LOCALE_WINAPI
+#endif
+#endif
+
+/**
+ * ATTRIBUTE_UNUSED:
+ *
+ * This macro is used to flag unused function parameters to GCC
+ */
+#ifdef __GNUC__
+#ifdef HAVE_ANSIDECL_H
+#include <ansidecl.h>
+#endif
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED __attribute__((unused))
+#endif
+#else
+#define ATTRIBUTE_UNUSED
+#endif
+
+/**
+ * LIBXSLT_PUBLIC:
+ *
+ * This macro is used to declare PUBLIC variables for Cygwin and for MSC on Windows
+ */
+#if !defined LIBXSLT_PUBLIC
+#if (defined(__CYGWIN__) || defined _MSC_VER) && !defined IN_LIBXSLT && !defined LIBXSLT_STATIC
+#define LIBXSLT_PUBLIC __declspec(dllimport)
+#else
+#define LIBXSLT_PUBLIC
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLTCONFIG_H__ */
diff --git a/libxslt/xsltexports.h b/libxslt/xsltexports.h
new file mode 100644
index 0000000..825c122
--- /dev/null
+++ b/libxslt/xsltexports.h
@@ -0,0 +1,142 @@
+/*
+ * Summary: macros for marking symbols as exportable/importable.
+ * Description: macros for marking symbols as exportable/importable.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Igor Zlatkovic <igor@zlatkovic.com>
+ */
+
+#ifndef __XSLT_EXPORTS_H__
+#define __XSLT_EXPORTS_H__
+
+/**
+ * XSLTPUBFUN:
+ * XSLTPUBFUN, XSLTPUBVAR, XSLTCALL
+ *
+ * Macros which declare an exportable function, an exportable variable and
+ * the calling convention used for functions.
+ *
+ * Please use an extra block for every platform/compiler combination when
+ * modifying this, rather than overlong #ifdef lines. This helps
+ * readability as well as the fact that different compilers on the same
+ * platform might need different definitions.
+ */
+
+/**
+ * XSLTPUBFUN:
+ *
+ * Macros which declare an exportable function
+ */
+#define XSLTPUBFUN
+/**
+ * XSLTPUBVAR:
+ *
+ * Macros which declare an exportable variable
+ */
+#define XSLTPUBVAR extern
+/**
+ * XSLTCALL:
+ *
+ * Macros which declare the called convention for exported functions
+ */
+#define XSLTCALL
+
+/** DOC_DISABLE */
+
+/* Windows platform with MS compiler */
+#if defined(_WIN32) && defined(_MSC_VER)
+  #undef XSLTPUBFUN
+  #undef XSLTPUBVAR
+  #undef XSLTCALL
+  #if defined(IN_LIBXSLT) && !defined(LIBXSLT_STATIC)
+    #define XSLTPUBFUN __declspec(dllexport)
+    #define XSLTPUBVAR __declspec(dllexport)
+  #else
+    #define XSLTPUBFUN
+    #if !defined(LIBXSLT_STATIC)
+      #define XSLTPUBVAR __declspec(dllimport) extern
+    #else
+      #define XSLTPUBVAR extern
+    #endif
+  #endif
+  #define XSLTCALL __cdecl
+  #if !defined _REENTRANT
+    #define _REENTRANT
+  #endif
+#endif
+
+/* Windows platform with Borland compiler */
+#if defined(_WIN32) && defined(__BORLANDC__)
+  #undef XSLTPUBFUN
+  #undef XSLTPUBVAR
+  #undef XSLTCALL
+  #if defined(IN_LIBXSLT) && !defined(LIBXSLT_STATIC)
+    #define XSLTPUBFUN __declspec(dllexport)
+    #define XSLTPUBVAR __declspec(dllexport) extern
+  #else
+    #define XSLTPUBFUN
+    #if !defined(LIBXSLT_STATIC)
+      #define XSLTPUBVAR __declspec(dllimport) extern
+    #else
+      #define XSLTPUBVAR extern
+    #endif
+  #endif
+  #define XSLTCALL __cdecl
+  #if !defined _REENTRANT
+    #define _REENTRANT
+  #endif
+#endif
+
+/* Windows platform with GNU compiler (Mingw) */
+#if defined(_WIN32) && defined(__MINGW32__)
+  #undef XSLTPUBFUN
+  #undef XSLTPUBVAR
+  #undef XSLTCALL
+/*
+  #if defined(IN_LIBXSLT) && !defined(LIBXSLT_STATIC)
+*/
+  #if !defined(LIBXSLT_STATIC)
+    #define XSLTPUBFUN __declspec(dllexport)
+    #define XSLTPUBVAR __declspec(dllexport) extern
+  #else
+    #define XSLTPUBFUN
+    #if !defined(LIBXSLT_STATIC)
+      #define XSLTPUBVAR __declspec(dllimport) extern
+    #else
+      #define XSLTPUBVAR extern
+    #endif
+  #endif
+  #define XSLTCALL __cdecl
+  #if !defined _REENTRANT
+    #define _REENTRANT
+  #endif
+#endif
+
+/* Cygwin platform, GNU compiler */
+#if defined(_WIN32) && defined(__CYGWIN__)
+  #undef XSLTPUBFUN
+  #undef XSLTPUBVAR
+  #undef XSLTCALL
+  #if defined(IN_LIBXSLT) && !defined(LIBXSLT_STATIC)
+    #define XSLTPUBFUN __declspec(dllexport)
+    #define XSLTPUBVAR __declspec(dllexport)
+  #else
+    #define XSLTPUBFUN
+    #if !defined(LIBXSLT_STATIC)
+      #define XSLTPUBVAR __declspec(dllimport) extern
+    #else
+      #define XSLTPUBVAR
+    #endif
+  #endif
+  #define XSLTCALL __cdecl
+#endif
+
+/* Compatibility */
+#if !defined(LIBXSLT_PUBLIC)
+#define LIBXSLT_PUBLIC XSLTPUBVAR
+#endif
+
+#endif /* __XSLT_EXPORTS_H__ */
+
+
diff --git a/libxslt/xsltlocale.c b/libxslt/xsltlocale.c
new file mode 100644
index 0000000..ec03cde
--- /dev/null
+++ b/libxslt/xsltlocale.c
@@ -0,0 +1,509 @@
+/*
+ * xsltlocale.c: locale handling
+ *
+ * Reference:
+ * RFC 3066: Tags for the Identification of Languages
+ * http://www.ietf.org/rfc/rfc3066.txt
+ * ISO 639-1, ISO 3166-1
+ *
+ * Author: Nick Wellnhofer
+ * winapi port: Roumen Petrov
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#include <string.h>
+#include <libxml/xmlmemory.h>
+
+#include "xsltlocale.h"
+#include "xsltutils.h"
+
+#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 2
+#define newlocale __newlocale
+#define freelocale __freelocale
+#define strxfrm_l __strxfrm_l
+#define LC_COLLATE_MASK (1 << LC_COLLATE)
+#endif
+
+#define ISALPHA(c) ((c & 0xc0) == 0x40 && (unsigned)((c & 0x1f) - 1) < 26)
+#define TOUPPER(c) (c & ~0x20)
+#define TOLOWER(c) (c | 0x20)
+
+/*without terminating null character*/
+#define XSLTMAX_ISO639LANGLEN		8
+#define XSLTMAX_ISO3166CNTRYLEN		8
+					/* <lang>-<cntry> */
+#define XSLTMAX_LANGTAGLEN		(XSLTMAX_ISO639LANGLEN+1+XSLTMAX_ISO3166CNTRYLEN)
+
+static const xmlChar* xsltDefaultRegion(const xmlChar *localeName);
+
+#ifdef XSLT_LOCALE_WINAPI
+xmlRMutexPtr xsltLocaleMutex = NULL;
+
+struct xsltRFC1766Info_s {
+      /*note typedef unsigned char xmlChar !*/
+    xmlChar    tag[XSLTMAX_LANGTAGLEN+1];
+      /*note typedef LCID xsltLocale !*/
+    xsltLocale lcid;
+};
+typedef struct xsltRFC1766Info_s xsltRFC1766Info;
+
+static int xsltLocaleListSize = 0;
+static xsltRFC1766Info *xsltLocaleList = NULL;
+
+
+static xsltLocale
+xslt_locale_WINAPI(const xmlChar *languageTag) {
+    int k;
+    xsltRFC1766Info *p = xsltLocaleList;
+
+    for (k=0; k<xsltLocaleListSize; k++, p++)
+	if (xmlStrcmp(p->tag, languageTag) == 0) return p->lcid;
+    return((xsltLocale)0);
+}
+
+static void xsltEnumSupportedLocales(void);
+#endif
+
+/**
+ * xsltNewLocale:
+ * @languageTag: RFC 3066 language tag
+ *
+ * Creates a new locale of an opaque system dependent type based on the
+ * language tag.
+ *
+ * Returns the locale or NULL on error or if no matching locale was found
+ */
+xsltLocale
+xsltNewLocale(const xmlChar *languageTag) {
+#ifdef XSLT_LOCALE_XLOCALE
+    xsltLocale locale;
+    char localeName[XSLTMAX_LANGTAGLEN+6]; /* 6 chars for ".utf8\0" */
+    const xmlChar *p = languageTag;
+    const char *region = NULL;
+    char *q = localeName;
+    int i, llen;
+    
+    /* Convert something like "pt-br" to "pt_BR.utf8" */
+    
+    if (languageTag == NULL)
+    	return(NULL);
+    
+    for (i=0; i<XSLTMAX_ISO639LANGLEN && ISALPHA(*p); ++i)
+	*q++ = TOLOWER(*p++);
+    
+    if (i == 0)
+    	return(NULL);
+    
+    llen = i;
+    *q++ = '_';
+    
+    if (*p) {
+    	if (*p++ != '-')
+    	    return(NULL);
+	
+	for (i=0; i<XSLTMAX_ISO3166CNTRYLEN && ISALPHA(*p); ++i)
+	    *q++ = TOUPPER(*p++);
+    
+    	if (i == 0 || *p)
+    	    return(NULL);
+    	
+        memcpy(q, ".utf8", 6);
+        locale = newlocale(LC_COLLATE_MASK, localeName, NULL);
+        if (locale != NULL)
+            return(locale);
+        
+        /* Continue without using country code */
+        
+        q = localeName + llen + 1;
+    }
+    
+    /* Try locale without territory, e.g. for Esperanto (eo) */
+
+    memcpy(q, ".utf8", 6);
+    locale = newlocale(LC_COLLATE_MASK, localeName, NULL);
+    if (locale != NULL)
+        return(locale);
+
+    /* Try to find most common country for language */
+    
+    if (llen != 2)
+        return(NULL);
+
+    region = (char *)xsltDefaultRegion((xmlChar *)localeName);
+    if (region == NULL)
+        return(NULL);
+     
+    q = localeName + llen + 1;
+    *q++ = region[0];
+    *q++ = region[1];
+    memcpy(q, ".utf8", 6);
+    locale = newlocale(LC_COLLATE_MASK, localeName, NULL);
+    
+    return(locale);
+#endif
+
+#ifdef XSLT_LOCALE_WINAPI
+{
+    xsltLocale    locale = (xsltLocale)0;
+    xmlChar       localeName[XSLTMAX_LANGTAGLEN+1];
+    xmlChar       *q = localeName;
+    const xmlChar *p = languageTag;
+    int           i, llen;
+    const xmlChar *region = NULL;
+
+    if (languageTag == NULL) goto end;
+
+    xsltEnumSupportedLocales();
+
+    for (i=0; i<XSLTMAX_ISO639LANGLEN && ISALPHA(*p); ++i)
+	*q++ = TOLOWER(*p++);
+    if (i == 0) goto end;
+
+    llen = i;
+    *q++ = '-';
+    if (*p) { /*if country tag is given*/
+	if (*p++ != '-') goto end;
+	
+	for (i=0; i<XSLTMAX_ISO3166CNTRYLEN && ISALPHA(*p); ++i)
+	    *q++ = TOUPPER(*p++);
+	if (i == 0 || *p) goto end;
+
+	*q = '\0';
+	locale = xslt_locale_WINAPI(localeName);
+	if (locale != (xsltLocale)0) goto end;
+    }
+    /* Try to find most common country for language */
+    region = xsltDefaultRegion(localeName);
+    if (region == NULL) goto end;
+
+    strcpy(localeName + llen + 1, region);
+    locale = xslt_locale_WINAPI(localeName);
+end:
+    return(locale);
+}
+#endif
+
+#ifdef XSLT_LOCALE_NONE
+    return(NULL);
+#endif
+}
+
+static const xmlChar*
+xsltDefaultRegion(const xmlChar *localeName) {
+    xmlChar c;
+    /* region should be xmlChar, but gcc warns on all string assignments */
+    const char *region = NULL;
+    
+    c = localeName[1];
+    /* This is based on the locales from glibc 2.3.3 */
+    
+    switch (localeName[0]) {
+        case 'a':
+            if (c == 'a' || c == 'm') region = "ET";
+            else if (c == 'f') region = "ZA";
+            else if (c == 'n') region = "ES";
+            else if (c == 'r') region = "AE";
+            else if (c == 'z') region = "AZ";
+            break;
+        case 'b':
+            if (c == 'e') region = "BY";
+            else if (c == 'g') region = "BG";
+            else if (c == 'n') region = "BD";
+            else if (c == 'r') region = "FR";
+            else if (c == 's') region = "BA";
+            break;
+        case 'c':
+            if (c == 'a') region = "ES";
+            else if (c == 's') region = "CZ";
+            else if (c == 'y') region = "GB";
+            break;
+        case 'd':
+            if (c == 'a') region = "DK";
+            else if (c == 'e') region = "DE";
+            break;
+        case 'e':
+            if (c == 'l') region = "GR";
+            else if (c == 'n' || c == 'o') region = "US";
+            else if (c == 's' || c == 'u') region = "ES";
+            else if (c == 't') region = "EE";
+            break;
+        case 'f':
+            if (c == 'a') region = "IR";
+            else if (c == 'i') region = "FI";
+            else if (c == 'o') region = "FO";
+            else if (c == 'r') region = "FR";
+            break;
+        case 'g':
+            if (c == 'a') region = "IE";
+            else if (c == 'l') region = "ES";
+            else if (c == 'v') region = "GB";
+            break;
+        case 'h':
+            if (c == 'e') region = "IL";
+            else if (c == 'i') region = "IN";
+            else if (c == 'r') region = "HT";
+            else if (c == 'u') region = "HU";
+            break;
+        case 'i':
+            if (c == 'd') region = "ID";
+            else if (c == 's') region = "IS";
+            else if (c == 't') region = "IT";
+            else if (c == 'w') region = "IL";
+            break;
+        case 'j':
+            if (c == 'a') region = "JP";
+            break;
+        case 'k':
+            if (c == 'l') region = "GL";
+            else if (c == 'o') region = "KR";
+            else if (c == 'w') region = "GB";
+            break;
+        case 'l':
+            if (c == 't') region = "LT";
+            else if (c == 'v') region = "LV";
+            break;
+        case 'm':
+            if (c == 'k') region = "MK";
+            else if (c == 'l' || c == 'r') region = "IN";
+            else if (c == 'n') region = "MN";
+            else if (c == 's') region = "MY";
+            else if (c == 't') region = "MT";
+            break;
+        case 'n':
+            if (c == 'b' || c == 'n' || c == 'o') region = "NO";
+            else if (c == 'e') region = "NP";
+            else if (c == 'l') region = "NL";
+            break;
+        case 'o':
+            if (c == 'm') region = "ET";
+            break;
+        case 'p':
+            if (c == 'a') region = "IN";
+            else if (c == 'l') region = "PL";
+            else if (c == 't') region = "PT";
+            break;
+        case 'r':
+            if (c == 'o') region = "RO";
+            else if (c == 'u') region = "RU";
+            break;
+        case 's':
+            switch (c) {
+                case 'e': region = "NO"; break;
+                case 'h': region = "YU"; break;
+                case 'k': region = "SK"; break;
+                case 'l': region = "SI"; break;
+                case 'o': region = "ET"; break;
+                case 'q': region = "AL"; break;
+                case 't': region = "ZA"; break;
+                case 'v': region = "SE"; break;
+            }
+            break;
+        case 't':
+            if (c == 'a' || c == 'e') region = "IN";
+            else if (c == 'h') region = "TH";
+            else if (c == 'i') region = "ER";
+            else if (c == 'r') region = "TR";
+            else if (c == 't') region = "RU";
+            break;
+        case 'u':
+            if (c == 'k') region = "UA";
+            else if (c == 'r') region = "PK";
+            break;
+        case 'v':
+            if (c == 'i') region = "VN";
+            break;
+        case 'w':
+            if (c == 'a') region = "BE";
+            break;
+        case 'x':
+            if (c == 'h') region = "ZA";
+            break;
+        case 'z':
+            if (c == 'h') region = "CN";
+            else if (c == 'u') region = "ZA";
+            break;
+    }
+    return((xmlChar *)region);
+}
+
+/**
+ * xsltFreeLocale:
+ * @locale: the locale to free
+ *
+ * Frees a locale created with xsltNewLocale
+ */
+void
+xsltFreeLocale(xsltLocale locale) {
+#ifdef XSLT_LOCALE_XLOCALE
+    freelocale(locale);
+#endif
+}
+
+/**
+ * xsltStrxfrm:
+ * @locale: locale created with xsltNewLocale
+ * @string: UTF-8 string to transform
+ *
+ * Transforms a string according to locale. The transformed string must then be
+ * compared with xsltLocaleStrcmp and freed with xmlFree.
+ *
+ * Returns the transformed string or NULL on error
+ */
+xsltLocaleChar *
+xsltStrxfrm(xsltLocale locale, const xmlChar *string)
+{
+#ifdef XSLT_LOCALE_NONE
+    return(NULL);
+#else
+    size_t xstrlen, r;
+    xsltLocaleChar *xstr;
+    
+#ifdef XSLT_LOCALE_XLOCALE
+    xstrlen = strxfrm_l(NULL, (const char *)string, 0, locale) + 1;
+    xstr = (xsltLocaleChar *) xmlMalloc(xstrlen);
+    if (xstr == NULL) {
+	xsltTransformError(NULL, NULL, NULL,
+	    "xsltStrxfrm : out of memory error\n");
+	return(NULL);
+    }
+
+    r = strxfrm_l((char *)xstr, (const char *)string, xstrlen, locale);
+#endif
+
+#ifdef XSLT_LOCALE_WINAPI
+    xstrlen = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0);
+    if (xstrlen == 0) {
+        xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar check failed\n");
+        return(NULL);
+    }
+    xstr = (xsltLocaleChar*) xmlMalloc(xstrlen * sizeof(xsltLocaleChar));
+    if (xstr == NULL) {
+        xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : out of memory\n");
+        return(NULL);
+    }
+    r = MultiByteToWideChar(CP_UTF8, 0, string, -1, xstr, xstrlen);
+    if (r == 0) {
+        xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar failed\n");
+        xmlFree(xstr);
+        return(NULL);
+    }
+    return(xstr);
+#endif /* XSLT_LOCALE_WINAPI */
+
+    if (r >= xstrlen) {
+	xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : strxfrm failed\n");
+        xmlFree(xstr);
+        return(NULL);
+    }
+
+    return(xstr);
+#endif /* XSLT_LOCALE_NONE */
+}
+
+/**
+ * xsltLocaleStrcmp:
+ * @locale: a locale identifier
+ * @str1: a string transformed with xsltStrxfrm
+ * @str2: a string transformed with xsltStrxfrm
+ *
+ * Compares two strings transformed with xsltStrxfrm
+ *
+ * Returns a value < 0 if str1 sorts before str2,
+ *         a value > 0 if str1 sorts after str2,
+ *         0 if str1 and str2 are equal wrt sorting
+ */
+int
+xsltLocaleStrcmp(xsltLocale locale, const xsltLocaleChar *str1, const xsltLocaleChar *str2) {
+    (void)locale;
+#ifdef XSLT_LOCALE_WINAPI
+{
+    int ret;
+    if (str1 == str2) return(0);
+    if (str1 == NULL) return(-1);
+    if (str2 == NULL) return(1);
+    ret = CompareStringW(locale, 0, str1, -1, str2, -1);
+    if (ret == 0) {
+        xsltTransformError(NULL, NULL, NULL, "xsltLocaleStrcmp : CompareStringW fail\n");
+        return(0);
+    }
+    return(ret - 2);
+}
+#else
+    return(xmlStrcmp(str1, str2));
+#endif
+}
+
+#ifdef XSLT_LOCALE_WINAPI
+/**
+ * xsltCountSupportedLocales:
+ * @lcid: not used
+ *
+ * callback used to count locales
+ *
+ * Returns TRUE
+ */
+BOOL CALLBACK
+xsltCountSupportedLocales(LPSTR lcid) {
+    (void) lcid;
+    ++xsltLocaleListSize;
+    return(TRUE);
+}
+
+/**
+ * xsltIterateSupportedLocales:
+ * @lcid: not used
+ *
+ * callback used to track locales
+ *
+ * Returns TRUE if not at the end of the array
+ */
+BOOL CALLBACK
+xsltIterateSupportedLocales(LPSTR lcid) {
+    static int count = 0;
+    xmlChar    iso639lang [XSLTMAX_ISO639LANGLEN  +1];
+    xmlChar    iso3136ctry[XSLTMAX_ISO3166CNTRYLEN+1];
+    int        k, l;
+    xsltRFC1766Info *p = xsltLocaleList + count;
+
+    k = sscanf(lcid, "%lx", (long*)&p->lcid);
+    if (k < 1) goto end;
+    /*don't count terminating null character*/
+    k = GetLocaleInfoA(p->lcid, LOCALE_SISO639LANGNAME , iso639lang , sizeof(iso639lang ));
+    if (--k < 1) goto end;
+    l = GetLocaleInfoA(p->lcid, LOCALE_SISO3166CTRYNAME, iso3136ctry, sizeof(iso3136ctry));
+    if (--l < 1) goto end;
+
+    {  /*fill results*/
+	xmlChar    *q = p->tag;
+	memcpy(q, iso639lang, k);
+	q += k;
+	*q++ = '-';
+	memcpy(q, iso3136ctry, l);
+	q += l;
+	*q = '\0';
+    }
+    ++count;
+end:
+    return((count < xsltLocaleListSize) ? TRUE : FALSE);
+}
+
+
+static void
+xsltEnumSupportedLocales(void) {
+    xmlRMutexLock(xsltLocaleMutex);
+    if (xsltLocaleListSize <= 0) {
+	size_t len;
+
+	EnumSystemLocalesA(xsltCountSupportedLocales, LCID_SUPPORTED);
+
+	len = xsltLocaleListSize * sizeof(xsltRFC1766Info);
+	xsltLocaleList = xmlMalloc(len);
+	memset(xsltLocaleList, 0, len);
+	EnumSystemLocalesA(xsltIterateSupportedLocales, LCID_SUPPORTED);
+    }
+    xmlRMutexUnlock(xsltLocaleMutex);
+}
+
+#endif /*def XSLT_LOCALE_WINAPI*/
diff --git a/libxslt/xsltlocale.h b/libxslt/xsltlocale.h
new file mode 100644
index 0000000..59343b0
--- /dev/null
+++ b/libxslt/xsltlocale.h
@@ -0,0 +1,57 @@
+/*
+ * Summary: Locale handling
+ * Description: Interfaces for locale handling. Needed for language dependent
+ *              sorting.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Nick Wellnhofer
+ */
+
+#ifndef __XML_XSLTLOCALE_H__
+#define __XML_XSLTLOCALE_H__
+
+#include <libxml/xmlstring.h>
+
+#ifdef XSLT_LOCALE_XLOCALE
+
+#include <locale.h>
+#include <xlocale.h>
+
+#ifdef __GLIBC__
+/*locale_t is defined only if _GNU_SOURCE is defined*/
+typedef __locale_t xsltLocale;
+#else
+typedef locale_t xsltLocale;
+#endif
+typedef xmlChar xsltLocaleChar;
+
+#elif defined(XSLT_LOCALE_WINAPI)
+
+#include <windows.h>
+#include <winnls.h>
+
+typedef LCID xsltLocale;
+typedef wchar_t xsltLocaleChar;
+
+#else
+
+/*
+ * XSLT_LOCALE_NONE:
+ * Macro indicating that locale are not supported
+ */
+#ifndef XSLT_LOCALE_NONE
+#define XSLT_LOCALE_NONE
+#endif
+
+typedef void *xsltLocale;
+typedef xmlChar xsltLocaleChar;
+
+#endif
+
+xsltLocale xsltNewLocale(const xmlChar *langName);
+void xsltFreeLocale(xsltLocale locale);
+xsltLocaleChar *xsltStrxfrm(xsltLocale locale, const xmlChar *string);
+int xsltLocaleStrcmp(xsltLocale locale, const xsltLocaleChar *str1, const xsltLocaleChar *str2);
+
+#endif /* __XML_XSLTLOCALE_H__ */
diff --git a/libxslt/xsltutils.c b/libxslt/xsltutils.c
new file mode 100644
index 0000000..9565e15
--- /dev/null
+++ b/libxslt/xsltutils.c
@@ -0,0 +1,2281 @@
+/*
+ * xsltutils.c: Utilities for the XSL Transformation 1.0 engine
+ *
+ * Reference:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#define IN_LIBXSLT
+#include "libxslt.h"
+
+#ifndef	XSLT_NEED_TRIO
+#include <stdio.h>
+#else
+#include <trio.h>
+#endif
+
+#include <string.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/HTMLtree.h>
+#include <libxml/xmlerror.h>
+#include <libxml/xmlIO.h>
+#include "xsltutils.h"
+#include "templates.h"
+#include "xsltInternals.h"
+#include "imports.h"
+#include "transform.h"
+
+/* gettimeofday on Windows ??? */
+#if defined(WIN32) && !defined(__CYGWIN__)
+#ifdef _MSC_VER
+#include <winsock2.h>
+#pragma comment(lib, "ws2_32.lib")
+#define gettimeofday(p1,p2)
+#define HAVE_GETTIMEOFDAY
+#define XSLT_WIN32_PERFORMANCE_COUNTER
+#endif /* _MS_VER */
+#endif /* WIN32 */
+
+/************************************************************************
+ * 									*
+ * 			Convenience function				*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltGetCNsProp:
+ * @style: the stylesheet
+ * @node:  the node
+ * @name:  the attribute name
+ * @nameSpace:  the URI of the namespace
+ *
+ * Similar to xmlGetNsProp() but with a slightly different semantic
+ *
+ * Search and get the value of an attribute associated to a node
+ * This attribute has to be anchored in the namespace specified,
+ * or has no namespace and the element is in that namespace.
+ *
+ * This does the entity substitution.
+ * This function looks in DTD attribute declaration for #FIXED or
+ * default declaration values unless DTD use has been turned off.
+ *
+ * Returns the attribute value or NULL if not found. The string is allocated
+ *         in the stylesheet dictionary.
+ */
+const xmlChar *
+xsltGetCNsProp(xsltStylesheetPtr style, xmlNodePtr node,
+              const xmlChar *name, const xmlChar *nameSpace) {
+    xmlAttrPtr prop;
+    xmlDocPtr doc;
+    xmlNsPtr ns;
+    xmlChar *tmp;
+    const xmlChar *ret;
+
+    if ((node == NULL) || (style == NULL) || (style->dict == NULL))
+	return(NULL);
+
+    prop = node->properties;
+    if (nameSpace == NULL) {
+        return xmlGetProp(node, name);
+    }
+    while (prop != NULL) {
+	/*
+	 * One need to have
+	 *   - same attribute names
+	 *   - and the attribute carrying that namespace
+	 */
+        if ((xmlStrEqual(prop->name, name)) &&
+	    (((prop->ns == NULL) && (node->ns != NULL) &&
+	      (xmlStrEqual(node->ns->href, nameSpace))) ||
+	     ((prop->ns != NULL) &&
+	      (xmlStrEqual(prop->ns->href, nameSpace))))) {
+
+	    tmp = xmlNodeListGetString(node->doc, prop->children, 1);
+	    if (tmp == NULL)
+	        ret = xmlDictLookup(style->dict, BAD_CAST "", 0);
+	    else {
+	        ret = xmlDictLookup(style->dict, tmp, -1);
+		xmlFree(tmp);
+	    }
+	    return ret;
+        }
+	prop = prop->next;
+    }
+    tmp = NULL;
+    /*
+     * Check if there is a default declaration in the internal
+     * or external subsets
+     */
+    doc =  node->doc;
+    if (doc != NULL) {
+        if (doc->intSubset != NULL) {
+	    xmlAttributePtr attrDecl;
+
+	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
+		
+	    if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
+	        /*
+		 * The DTD declaration only allows a prefix search
+		 */
+		ns = xmlSearchNs(doc, node, attrDecl->prefix);
+		if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
+		    return(xmlDictLookup(style->dict,
+		                         attrDecl->defaultValue, -1));
+	    }
+	}
+    }
+    return(NULL);
+}
+/**
+ * xsltGetNsProp:
+ * @node:  the node
+ * @name:  the attribute name
+ * @nameSpace:  the URI of the namespace
+ *
+ * Similar to xmlGetNsProp() but with a slightly different semantic
+ *
+ * Search and get the value of an attribute associated to a node
+ * This attribute has to be anchored in the namespace specified,
+ * or has no namespace and the element is in that namespace.
+ *
+ * This does the entity substitution.
+ * This function looks in DTD attribute declaration for #FIXED or
+ * default declaration values unless DTD use has been turned off.
+ *
+ * Returns the attribute value or NULL if not found.
+ *     It's up to the caller to free the memory.
+ */
+xmlChar *
+xsltGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
+    xmlAttrPtr prop;
+    xmlDocPtr doc;
+    xmlNsPtr ns;
+
+    if (node == NULL)
+	return(NULL);
+
+    prop = node->properties;
+    /*
+    * TODO: Substitute xmlGetProp() for xmlGetNsProp(), since the former
+    * is not namespace-aware and will return an attribute with equal
+    * name regardless of its namespace.
+    * Example:
+    *   <xsl:element foo:name="myName"/>
+    *   So this would return "myName" even if an attribute @name
+    *   in the XSLT was requested.
+    */
+    if (nameSpace == NULL)
+	return(xmlGetProp(node, name));
+    while (prop != NULL) {
+	/*
+	 * One need to have
+	 *   - same attribute names
+	 *   - and the attribute carrying that namespace
+	 */
+        if ((xmlStrEqual(prop->name, name)) &&
+	    (((prop->ns == NULL) && (node->ns != NULL) &&
+	      (xmlStrEqual(node->ns->href, nameSpace))) ||
+	     ((prop->ns != NULL) &&
+	      (xmlStrEqual(prop->ns->href, nameSpace))))) {
+	    xmlChar *ret;
+
+	    ret = xmlNodeListGetString(node->doc, prop->children, 1);
+	    if (ret == NULL) return(xmlStrdup((xmlChar *)""));
+	    return(ret);
+        }
+	prop = prop->next;
+    }
+
+    /*
+     * Check if there is a default declaration in the internal
+     * or external subsets
+     */
+    doc =  node->doc;
+    if (doc != NULL) {
+        if (doc->intSubset != NULL) {
+	    xmlAttributePtr attrDecl;
+
+	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
+		
+	    if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
+	        /*
+		 * The DTD declaration only allows a prefix search
+		 */
+		ns = xmlSearchNs(doc, node, attrDecl->prefix);
+		if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
+		    return(xmlStrdup(attrDecl->defaultValue));
+	    }
+	}
+    }
+    return(NULL);
+}
+
+/**
+ * xsltGetUTF8Char:
+ * @utf:  a sequence of UTF-8 encoded bytes
+ * @len:  a pointer to @bytes len
+ *
+ * Read one UTF8 Char from @utf
+ * Function copied from libxml2 xmlGetUTF8Char() ... to discard ultimately
+ * and use the original API
+ *
+ * Returns the char value or -1 in case of error and update @len with the
+ *        number of bytes used
+ */
+int
+xsltGetUTF8Char(const unsigned char *utf, int *len) {
+    unsigned int c;
+
+    if (utf == NULL)
+	goto error;
+    if (len == NULL)
+	goto error;
+    if (*len < 1)
+	goto error;
+
+    c = utf[0];
+    if (c & 0x80) {
+	if (*len < 2)
+	    goto error;
+	if ((utf[1] & 0xc0) != 0x80)
+	    goto error;
+	if ((c & 0xe0) == 0xe0) {
+	    if (*len < 3)
+		goto error;
+	    if ((utf[2] & 0xc0) != 0x80)
+		goto error;
+	    if ((c & 0xf0) == 0xf0) {
+		if (*len < 4)
+		    goto error;
+		if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
+		    goto error;
+		*len = 4;
+		/* 4-byte code */
+		c = (utf[0] & 0x7) << 18;
+		c |= (utf[1] & 0x3f) << 12;
+		c |= (utf[2] & 0x3f) << 6;
+		c |= utf[3] & 0x3f;
+	    } else {
+	      /* 3-byte code */
+		*len = 3;
+		c = (utf[0] & 0xf) << 12;
+		c |= (utf[1] & 0x3f) << 6;
+		c |= utf[2] & 0x3f;
+	    }
+	} else {
+	  /* 2-byte code */
+	    *len = 2;
+	    c = (utf[0] & 0x1f) << 6;
+	    c |= utf[1] & 0x3f;
+	}
+    } else {
+	/* 1-byte code */
+	*len = 1;
+    }
+    return(c);
+
+error:
+    if (len != NULL)
+	*len = 0;
+    return(-1);
+}
+
+#ifdef XSLT_REFACTORED
+
+/**
+ * xsltPointerListAddSize:
+ * @list: the pointer list structure
+ * @item: the item to be stored
+ * @initialSize: the initial size of the list
+ *
+ * Adds an item to the list.
+ *
+ * Returns the position of the added item in the list or
+ *         -1 in case of an error.
+ */
+int
+xsltPointerListAddSize(xsltPointerListPtr list,		       
+		       void *item,
+		       int initialSize)
+{
+    if (list->items == NULL) {
+	if (initialSize <= 0)
+	    initialSize = 1;
+	list->items = (void **) xmlMalloc(
+	    initialSize * sizeof(void *));
+	if (list->items == NULL) {
+	    xsltGenericError(xsltGenericErrorContext,
+	     "xsltPointerListAddSize: memory allocation failure.\n");
+	    return(-1);
+	}
+	list->number = 0;
+	list->size = initialSize;
+    } else if (list->size <= list->number) {
+	list->size *= 2;
+	list->items = (void **) xmlRealloc(list->items,
+	    list->size * sizeof(void *));
+	if (list->items == NULL) {
+	    xsltGenericError(xsltGenericErrorContext,
+	     "xsltPointerListAddSize: memory re-allocation failure.\n");
+	    list->size = 0;
+	    return(-1);
+	}
+    }
+    list->items[list->number++] = item;
+    return(0);
+}
+
+/**
+ * xsltPointerListCreate:
+ * @initialSize: the initial size for the list
+ *
+ * Creates an xsltPointerList structure.
+ *
+ * Returns a xsltPointerList structure or NULL in case of an error.
+ */
+xsltPointerListPtr
+xsltPointerListCreate(int initialSize)
+{
+    xsltPointerListPtr ret;
+
+    ret = xmlMalloc(sizeof(xsltPointerList));
+    if (ret == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	     "xsltPointerListCreate: memory allocation failure.\n");
+	return (NULL);
+    }
+    memset(ret, 0, sizeof(xsltPointerList));
+    if (initialSize > 0) {
+	xsltPointerListAddSize(ret, NULL, initialSize);
+	ret->number = 0;
+    }
+    return (ret);
+}
+
+/**
+ * xsltPointerListFree:
+ * @list: pointer to the list to be freed
+ *
+ * Frees the xsltPointerList structure. This does not free
+ * the content of the list.
+ */
+void
+xsltPointerListFree(xsltPointerListPtr list)
+{
+    if (list == NULL)
+	return;
+    if (list->items != NULL)
+	xmlFree(list->items);
+    xmlFree(list);
+}
+
+/**
+ * xsltPointerListClear:
+ * @list: pointer to the list to be cleared
+ *
+ * Resets the list, but does not free the allocated array
+ * and does not free the content of the list.
+ */
+void
+xsltPointerListClear(xsltPointerListPtr list)
+{
+    if (list->items != NULL) {
+	xmlFree(list->items);
+	list->items = NULL;
+    }
+    list->number = 0;
+    list->size = 0;
+}
+
+#endif /* XSLT_REFACTORED */
+
+/************************************************************************
+ * 									*
+ * 		Handling of XSLT stylesheets messages			*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltMessage:
+ * @ctxt:  an XSLT processing context
+ * @node:  The current node
+ * @inst:  The node containing the message instruction
+ *
+ * Process and xsl:message construct
+ */
+void
+xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) {
+    xmlGenericErrorFunc error = xsltGenericError;
+    void *errctx = xsltGenericErrorContext;
+    xmlChar *prop, *message;
+    int terminate = 0;
+
+    if ((ctxt == NULL) || (inst == NULL))
+	return;
+
+    if (ctxt->error != NULL) {
+	error = ctxt->error;
+	errctx = ctxt->errctx;
+    }
+
+    prop = xmlGetNsProp(inst, (const xmlChar *)"terminate", NULL);
+    if (prop != NULL) {
+	if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
+	    terminate = 1;
+	} else if (xmlStrEqual(prop, (const xmlChar *)"no")) {
+	    terminate = 0;
+	} else {
+	    error(errctx,
+		"xsl:message : terminate expecting 'yes' or 'no'\n");
+	    ctxt->state = XSLT_STATE_ERROR;
+	}
+	xmlFree(prop);
+    }
+    message = xsltEvalTemplateString(ctxt, node, inst);
+    if (message != NULL) {
+	int len = xmlStrlen(message);
+
+	error(errctx, "%s", (const char *)message);
+	if ((len > 0) && (message[len - 1] != '\n'))
+	    error(errctx, "\n");
+	xmlFree(message);
+    }
+    if (terminate)
+	ctxt->state = XSLT_STATE_STOPPED;
+}
+
+/************************************************************************
+ * 									*
+ * 		Handling of out of context errors			*
+ * 									*
+ ************************************************************************/
+
+#define XSLT_GET_VAR_STR(msg, str) {				\
+    int       size;						\
+    int       chars;						\
+    char      *larger;						\
+    va_list   ap;						\
+								\
+    str = (char *) xmlMalloc(150);				\
+    if (str == NULL) 						\
+	return;							\
+								\
+    size = 150;							\
+								\
+    while (size < 64000) {					\
+	va_start(ap, msg);					\
+  	chars = vsnprintf(str, size, msg, ap);			\
+	va_end(ap);						\
+	if ((chars > -1) && (chars < size))			\
+	    break;						\
+	if (chars > -1)						\
+	    size += chars + 1;					\
+	else							\
+	    size += 100;					\
+	if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\
+	    xmlFree(str);					\
+	    return;						\
+	}							\
+	str = larger;						\
+    }								\
+}
+/**
+ * xsltGenericErrorDefaultFunc:
+ * @ctx:  an error context
+ * @msg:  the message to display/transmit
+ * @...:  extra parameters for the message display
+ * 
+ * Default handler for out of context error messages.
+ */
+static void
+xsltGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
+    va_list args;
+
+    if (xsltGenericErrorContext == NULL)
+	xsltGenericErrorContext = (void *) stderr;
+
+    va_start(args, msg);
+    vfprintf((FILE *)xsltGenericErrorContext, msg, args);
+    va_end(args);
+}
+
+xmlGenericErrorFunc xsltGenericError = xsltGenericErrorDefaultFunc;
+void *xsltGenericErrorContext = NULL;
+
+
+/**
+ * xsltSetGenericErrorFunc:
+ * @ctx:  the new error handling context
+ * @handler:  the new handler function
+ *
+ * Function to reset the handler and the error context for out of
+ * context error messages.
+ * This simply means that @handler will be called for subsequent
+ * error messages while not parsing nor validating. And @ctx will
+ * be passed as first argument to @handler
+ * One can simply force messages to be emitted to another FILE * than
+ * stderr by setting @ctx to this file handle and @handler to NULL.
+ */
+void
+xsltSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
+    xsltGenericErrorContext = ctx;
+    if (handler != NULL)
+	xsltGenericError = handler;
+    else
+	xsltGenericError = xsltGenericErrorDefaultFunc;
+}
+
+/**
+ * xsltGenericDebugDefaultFunc:
+ * @ctx:  an error context
+ * @msg:  the message to display/transmit
+ * @...:  extra parameters for the message display
+ * 
+ * Default handler for out of context error messages.
+ */
+static void
+xsltGenericDebugDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
+    va_list args;
+
+    if (xsltGenericDebugContext == NULL)
+	return;
+
+    va_start(args, msg);
+    vfprintf((FILE *)xsltGenericDebugContext, msg, args);
+    va_end(args);
+}
+
+xmlGenericErrorFunc xsltGenericDebug = xsltGenericDebugDefaultFunc;
+void *xsltGenericDebugContext = NULL;
+
+
+/**
+ * xsltSetGenericDebugFunc:
+ * @ctx:  the new error handling context
+ * @handler:  the new handler function
+ *
+ * Function to reset the handler and the error context for out of
+ * context error messages.
+ * This simply means that @handler will be called for subsequent
+ * error messages while not parsing or validating. And @ctx will
+ * be passed as first argument to @handler
+ * One can simply force messages to be emitted to another FILE * than
+ * stderr by setting @ctx to this file handle and @handler to NULL.
+ */
+void
+xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) {
+    xsltGenericDebugContext = ctx;
+    if (handler != NULL)
+	xsltGenericDebug = handler;
+    else
+	xsltGenericDebug = xsltGenericDebugDefaultFunc;
+}
+
+/**
+ * xsltPrintErrorContext:
+ * @ctxt:  the transformation context
+ * @style:  the stylesheet
+ * @node:  the current node being processed
+ *
+ * Display the context of an error.
+ */
+void
+xsltPrintErrorContext(xsltTransformContextPtr ctxt,
+	              xsltStylesheetPtr style, xmlNodePtr node) {
+    int line = 0;
+    const xmlChar *file = NULL;
+    const xmlChar *name = NULL;
+    const char *type = "error";
+    xmlGenericErrorFunc error = xsltGenericError;
+    void *errctx = xsltGenericErrorContext;
+
+    if (ctxt != NULL) {
+	ctxt->state = XSLT_STATE_ERROR;
+	if (ctxt->error != NULL) {
+	    error = ctxt->error;
+	    errctx = ctxt->errctx;
+	}
+    }
+    if ((node == NULL) && (ctxt != NULL))
+	node = ctxt->inst;
+
+    if (node != NULL)  {
+	if ((node->type == XML_DOCUMENT_NODE) ||
+	    (node->type == XML_HTML_DOCUMENT_NODE)) {
+	    xmlDocPtr doc = (xmlDocPtr) node;
+
+	    file = doc->URL;
+	} else {
+	    line = xmlGetLineNo(node);
+	    if ((node->doc != NULL) && (node->doc->URL != NULL))
+		file = node->doc->URL;
+	    if (node->name != NULL)
+		name = node->name;
+	}
+    } 
+    
+    if (ctxt != NULL)
+	type = "runtime error";
+    else if (style != NULL) {
+#ifdef XSLT_REFACTORED
+	if (XSLT_CCTXT(style)->errSeverity == XSLT_ERROR_SEVERITY_WARNING)
+	    type = "compilation warning";
+	else
+	    type = "compilation error";
+#else
+	type = "compilation error";
+#endif
+    }
+
+    if ((file != NULL) && (line != 0) && (name != NULL))
+	error(errctx, "%s: file %s line %d element %s\n",
+	      type, file, line, name);
+    else if ((file != NULL) && (name != NULL))
+	error(errctx, "%s: file %s element %s\n", type, file, name);
+    else if ((file != NULL) && (line != 0))
+	error(errctx, "%s: file %s line %d\n", type, file, line);
+    else if (file != NULL)
+	error(errctx, "%s: file %s\n", type, file);
+    else if (name != NULL)
+	error(errctx, "%s: element %s\n", type, name);
+    else
+	error(errctx, "%s\n", type);
+}
+
+/**
+ * xsltSetTransformErrorFunc:
+ * @ctxt:  the XSLT transformation context
+ * @ctx:  the new error handling context
+ * @handler:  the new handler function
+ *
+ * Function to reset the handler and the error context for out of
+ * context error messages specific to a given XSLT transromation.
+ *
+ * This simply means that @handler will be called for subsequent
+ * error messages while running the transformation.
+ */
+void
+xsltSetTransformErrorFunc(xsltTransformContextPtr ctxt,
+                          void *ctx, xmlGenericErrorFunc handler)
+{
+    ctxt->error = handler;
+    ctxt->errctx = ctx;
+}
+
+/**
+ * xsltTransformError:
+ * @ctxt:  an XSLT transformation context
+ * @style:  the XSLT stylesheet used
+ * @node:  the current node in the stylesheet
+ * @msg:  the message to display/transmit
+ * @...:  extra parameters for the message display
+ *
+ * Display and format an error messages, gives file, line, position and
+ * extra parameters, will use the specific transformation context if available
+ */
+void
+xsltTransformError(xsltTransformContextPtr ctxt,
+		   xsltStylesheetPtr style,
+		   xmlNodePtr node,
+		   const char *msg, ...) {
+    xmlGenericErrorFunc error = xsltGenericError;
+    void *errctx = xsltGenericErrorContext;
+    char * str;
+
+    if (ctxt != NULL) {
+	ctxt->state = XSLT_STATE_ERROR;
+	if (ctxt->error != NULL) {
+	    error = ctxt->error;
+	    errctx = ctxt->errctx;
+	}
+    }
+    if ((node == NULL) && (ctxt != NULL))
+	node = ctxt->inst;
+    xsltPrintErrorContext(ctxt, style, node);
+    XSLT_GET_VAR_STR(msg, str);
+    error(errctx, "%s", str);
+    if (str != NULL)
+	xmlFree(str);
+}
+
+/************************************************************************
+ * 									*
+ * 				QNames					*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltSplitQName:
+ * @dict: a dictionary
+ * @name:  the full QName
+ * @prefix: the return value
+ *
+ * Split QNames into prefix and local names, both allocated from a dictionary.
+ *
+ * Returns: the localname or NULL in case of error.
+ */
+const xmlChar *
+xsltSplitQName(xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix) {
+    int len = 0;
+    const xmlChar *ret = NULL;
+
+    *prefix = NULL;
+    if ((name == NULL) || (dict == NULL)) return(NULL);
+    if (name[0] == ':')
+        return(xmlDictLookup(dict, name, -1));
+    while ((name[len] != 0) && (name[len] != ':')) len++;
+    if (name[len] == 0) return(xmlDictLookup(dict, name, -1));
+    *prefix = xmlDictLookup(dict, name, len);
+    ret = xmlDictLookup(dict, &name[len + 1], -1);
+    return(ret);
+}
+
+/**
+ * xsltGetQNameURI:
+ * @node:  the node holding the QName
+ * @name:  pointer to the initial QName value
+ *
+ * This function analyzes @name, if the name contains a prefix,
+ * the function seaches the associated namespace in scope for it.
+ * It will also replace @name value with the NCName, the old value being
+ * freed.
+ * Errors in the prefix lookup are signalled by setting @name to NULL.
+ *
+ * NOTE: the namespace returned is a pointer to the place where it is
+ *       defined and hence has the same lifespan as the document holding it.
+ *
+ * Returns the namespace URI if there is a prefix, or NULL if @name is
+ *         not prefixed.
+ */
+const xmlChar *
+xsltGetQNameURI(xmlNodePtr node, xmlChar ** name)
+{
+    int len = 0;
+    xmlChar *qname;
+    xmlNsPtr ns;
+
+    if (name == NULL)
+	return(NULL);
+    qname = *name;
+    if ((qname == NULL) || (*qname == 0))
+	return(NULL);
+    if (node == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+		         "QName: no element for namespace lookup %s\n",
+			 qname);
+	xmlFree(qname);
+	*name = NULL;
+	return(NULL);
+    }
+
+    /* nasty but valid */
+    if (qname[0] == ':')
+	return(NULL);
+
+    /*
+     * we are not trying to validate but just to cut, and yes it will
+     * work even if this is a set of UTF-8 encoded chars
+     */
+    while ((qname[len] != 0) && (qname[len] != ':')) 
+	len++;
+    
+    if (qname[len] == 0)
+	return(NULL);
+
+    /*
+     * handle xml: separately, this one is magical
+     */
+    if ((qname[0] == 'x') && (qname[1] == 'm') &&
+        (qname[2] == 'l') && (qname[3] == ':')) {
+	if (qname[4] == 0)
+	    return(NULL);
+        *name = xmlStrdup(&qname[4]);
+	xmlFree(qname);
+	return(XML_XML_NAMESPACE);
+    }
+
+    qname[len] = 0;
+    ns = xmlSearchNs(node->doc, node, qname);
+    if (ns == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+		"%s:%s : no namespace bound to prefix %s\n",
+		         qname, &qname[len + 1], qname);
+	*name = NULL;
+	xmlFree(qname);
+	return(NULL);
+    }
+    *name = xmlStrdup(&qname[len + 1]);
+    xmlFree(qname);
+    return(ns->href);
+}
+
+/**
+ * xsltGetQNameURI2:
+ * @style:  stylesheet pointer
+ * @node:   the node holding the QName
+ * @name:   pointer to the initial QName value
+ *
+ * This function is similar to xsltGetQNameURI, but is used when
+ * @name is a dictionary entry.
+ *
+ * Returns the namespace URI if there is a prefix, or NULL if @name is
+ * not prefixed.
+ */
+const xmlChar *
+xsltGetQNameURI2(xsltStylesheetPtr style, xmlNodePtr node,
+		 const xmlChar **name) {
+    int len = 0;
+    xmlChar *qname;
+    xmlNsPtr ns;
+
+    if (name == NULL)
+        return(NULL);
+    qname = (xmlChar *)*name;
+    if ((qname == NULL) || (*qname == 0))
+        return(NULL);
+    if (node == NULL) {
+        xsltGenericError(xsltGenericErrorContext,
+                         "QName: no element for namespace lookup %s\n",
+                          qname);
+	*name = NULL;
+	return(NULL);
+    }
+
+    /*
+     * we are not trying to validate but just to cut, and yes it will
+     * work even if this is a set of UTF-8 encoded chars
+     */
+    while ((qname[len] != 0) && (qname[len] != ':'))
+        len++;
+
+    if (qname[len] == 0)
+        return(NULL);
+
+    /*
+     * handle xml: separately, this one is magical
+     */
+    if ((qname[0] == 'x') && (qname[1] == 'm') &&
+        (qname[2] == 'l') && (qname[3] == ':')) {
+        if (qname[4] == 0)
+            return(NULL);
+        *name = xmlDictLookup(style->dict, &qname[4], -1);
+        return(XML_XML_NAMESPACE);
+    }
+
+    qname = xmlStrndup(*name, len);
+    ns = xmlSearchNs(node->doc, node, qname);
+    if (ns == NULL) {
+	if (style) {
+	    xsltTransformError(NULL, style, node,
+		"No namespace bound to prefix '%s'.\n",
+		qname);
+	    style->errors++;
+	} else {
+	    xsltGenericError(xsltGenericErrorContext,
+                "%s : no namespace bound to prefix %s\n",
+		*name, qname);
+	}
+        *name = NULL;
+        xmlFree(qname);
+        return(NULL);
+    }
+    *name = xmlDictLookup(style->dict, (*name)+len+1, -1);
+    xmlFree(qname);
+    return(ns->href);
+}
+										      
+/************************************************************************
+ * 									*
+ * 				Sorting					*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltDocumentSortFunction:
+ * @list:  the node set
+ *
+ * reorder the current node list @list accordingly to the document order
+ * This function is slow, obsolete and should not be used anymore.
+ */
+void
+xsltDocumentSortFunction(xmlNodeSetPtr list) {
+    int i, j;
+    int len, tst;
+    xmlNodePtr node;
+
+    if (list == NULL)
+	return;
+    len = list->nodeNr;
+    if (len <= 1)
+	return;
+    /* TODO: sort is really not optimized, does it needs to ? */
+    for (i = 0;i < len -1;i++) {
+	for (j = i + 1; j < len; j++) {
+	    tst = xmlXPathCmpNodes(list->nodeTab[i], list->nodeTab[j]);
+	    if (tst == -1) {
+		node = list->nodeTab[i];
+		list->nodeTab[i] = list->nodeTab[j];
+		list->nodeTab[j] = node;
+	    }
+	}
+    }
+}
+
+/**
+ * xsltComputeSortResult:
+ * @ctxt:  a XSLT process context
+ * @sort:  node list
+ *
+ * reorder the current node list accordingly to the set of sorting
+ * requirement provided by the array of nodes.
+ *
+ * Returns a ordered XPath nodeset or NULL in case of error.
+ */
+xmlXPathObjectPtr *
+xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemSortPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+    xmlXPathObjectPtr *results = NULL;
+    xmlNodeSetPtr list = NULL;
+    xmlXPathObjectPtr res;
+    int len = 0;
+    int i;    
+    xmlNodePtr oldNode;
+    xmlNodePtr oldInst;
+    int	oldPos, oldSize ;
+    int oldNsNr;
+    xmlNsPtr *oldNamespaces;
+
+    comp = sort->psvi;
+    if (comp == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	     "xsl:sort : compilation failed\n");
+	return(NULL);
+    }
+
+    if ((comp->select == NULL) || (comp->comp == NULL))
+	return(NULL);
+
+    list = ctxt->nodeList;
+    if ((list == NULL) || (list->nodeNr <= 1))
+	return(NULL);
+
+    len = list->nodeNr;
+
+    /* TODO: xsl:sort lang attribute */
+    /* TODO: xsl:sort case-order attribute */
+
+
+    results = xmlMalloc(len * sizeof(xmlXPathObjectPtr));
+    if (results == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	     "xsltComputeSortResult: memory allocation failure\n");
+	return(NULL);
+    }
+
+    oldNode = ctxt->node;
+    oldInst = ctxt->inst;
+    oldPos = ctxt->xpathCtxt->proximityPosition;
+    oldSize = ctxt->xpathCtxt->contextSize;
+    oldNsNr = ctxt->xpathCtxt->nsNr;
+    oldNamespaces = ctxt->xpathCtxt->namespaces;
+    for (i = 0;i < len;i++) {
+	ctxt->inst = sort;
+	ctxt->xpathCtxt->contextSize = len;
+	ctxt->xpathCtxt->proximityPosition = i + 1;
+	ctxt->node = list->nodeTab[i];
+	ctxt->xpathCtxt->node = ctxt->node;
+#ifdef XSLT_REFACTORED
+	if (comp->inScopeNs != NULL) {
+	    ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
+	    ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
+	} else {
+	    ctxt->xpathCtxt->namespaces = NULL;
+	    ctxt->xpathCtxt->nsNr = 0;
+	}
+#else
+	ctxt->xpathCtxt->namespaces = comp->nsList;
+	ctxt->xpathCtxt->nsNr = comp->nsNr;
+#endif
+	res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
+	if (res != NULL) {
+	    if (res->type != XPATH_STRING)
+		res = xmlXPathConvertString(res);
+	    if (comp->number)
+		res = xmlXPathConvertNumber(res);
+	    res->index = i;	/* Save original pos for dupl resolv */
+	    if (comp->number) {
+		if (res->type == XPATH_NUMBER) {
+		    results[i] = res;
+		} else {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		    xsltGenericDebug(xsltGenericDebugContext,
+			"xsltComputeSortResult: select didn't evaluate to a number\n");
+#endif
+		    results[i] = NULL;
+		}
+	    } else {
+		if (res->type == XPATH_STRING) {
+		    if (comp->locale != (xsltLocale)0) {
+			xmlChar *str = res->stringval;
+			res->stringval = (xmlChar *) xsltStrxfrm(comp->locale, str);
+			xmlFree(str);
+		    }
+
+		    results[i] = res;
+		} else {
+#ifdef WITH_XSLT_DEBUG_PROCESS
+		    xsltGenericDebug(xsltGenericDebugContext,
+			"xsltComputeSortResult: select didn't evaluate to a string\n");
+#endif
+		    results[i] = NULL;
+		}
+	    }
+	} else {
+	    ctxt->state = XSLT_STATE_STOPPED;
+	    results[i] = NULL;
+	}
+    }
+    ctxt->node = oldNode;
+    ctxt->inst = oldInst;
+    ctxt->xpathCtxt->contextSize = oldSize;
+    ctxt->xpathCtxt->proximityPosition = oldPos;
+    ctxt->xpathCtxt->nsNr = oldNsNr;
+    ctxt->xpathCtxt->namespaces = oldNamespaces;
+
+    return(results);
+}
+
+/**
+ * xsltDefaultSortFunction:
+ * @ctxt:  a XSLT process context
+ * @sorts:  array of sort nodes
+ * @nbsorts:  the number of sorts in the array
+ *
+ * reorder the current node list accordingly to the set of sorting
+ * requirement provided by the arry of nodes.
+ */
+void	
+xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
+	           int nbsorts) {
+#ifdef XSLT_REFACTORED
+    xsltStyleItemSortPtr comp;
+#else
+    xsltStylePreCompPtr comp;
+#endif
+    xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];
+    xmlXPathObjectPtr *results = NULL, *res;
+    xmlNodeSetPtr list = NULL;
+    int descending, number, desc, numb;
+    int len = 0;
+    int i, j, incr;
+    int tst;
+    int depth;
+    xmlNodePtr node;
+    xmlXPathObjectPtr tmp;    
+    int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
+
+    if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
+	(nbsorts >= XSLT_MAX_SORT))
+	return;
+    if (sorts[0] == NULL)
+	return;
+    comp = sorts[0]->psvi;
+    if (comp == NULL)
+	return;
+
+    list = ctxt->nodeList;
+    if ((list == NULL) || (list->nodeNr <= 1))
+	return; /* nothing to do */
+
+    for (j = 0; j < nbsorts; j++) {
+	comp = sorts[j]->psvi;
+	tempstype[j] = 0;
+	if ((comp->stype == NULL) && (comp->has_stype != 0)) {
+	    comp->stype =
+		xsltEvalAttrValueTemplate(ctxt, sorts[j],
+					  (const xmlChar *) "data-type",
+					  XSLT_NAMESPACE);
+	    if (comp->stype != NULL) {
+		tempstype[j] = 1;
+		if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
+		    comp->number = 0;
+		else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
+		    comp->number = 1;
+		else {
+		    xsltTransformError(ctxt, NULL, sorts[j],
+			  "xsltDoSortFunction: no support for data-type = %s\n",
+				     comp->stype);
+		    comp->number = 0; /* use default */
+		}
+	    }
+	}
+	temporder[j] = 0;
+	if ((comp->order == NULL) && (comp->has_order != 0)) {
+	    comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],
+						    (const xmlChar *) "order",
+						    XSLT_NAMESPACE);
+	    if (comp->order != NULL) {
+		temporder[j] = 1;
+		if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
+		    comp->descending = 0;
+		else if (xmlStrEqual(comp->order,
+				     (const xmlChar *) "descending"))
+		    comp->descending = 1;
+		else {
+		    xsltTransformError(ctxt, NULL, sorts[j],
+			     "xsltDoSortFunction: invalid value %s for order\n",
+				     comp->order);
+		    comp->descending = 0; /* use default */
+		}
+	    }
+	}
+    }
+
+    len = list->nodeNr;
+
+    resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]);
+    for (i = 1;i < XSLT_MAX_SORT;i++)
+	resultsTab[i] = NULL;
+
+    results = resultsTab[0];
+
+    comp = sorts[0]->psvi;
+    descending = comp->descending;
+    number = comp->number;
+    if (results == NULL)
+	return;
+
+    /* Shell's sort of node-set */
+    for (incr = len / 2; incr > 0; incr /= 2) {
+	for (i = incr; i < len; i++) {
+	    j = i - incr;
+	    if (results[i] == NULL)
+		continue;
+	    
+	    while (j >= 0) {
+		if (results[j] == NULL)
+		    tst = 1;
+		else {
+		    if (number) {
+			/* We make NaN smaller than number in accordance
+			   with XSLT spec */
+			if (xmlXPathIsNaN(results[j]->floatval)) {
+			    if (xmlXPathIsNaN(results[j + incr]->floatval))
+				tst = 0;
+			    else
+				tst = -1;
+			} else if (xmlXPathIsNaN(results[j + incr]->floatval))
+			    tst = 1;
+			else if (results[j]->floatval ==
+				results[j + incr]->floatval)
+			    tst = 0;
+			else if (results[j]->floatval > 
+				results[j + incr]->floatval)
+			    tst = 1;
+			else tst = -1;
+		    } else if(comp->locale != (xsltLocale)0) {
+			tst = xsltLocaleStrcmp(
+			    comp->locale,
+			    (xsltLocaleChar *) results[j]->stringval,
+			    (xsltLocaleChar *) results[j + incr]->stringval); 
+		    } else {
+			tst = xmlStrcmp(results[j]->stringval,
+				     results[j + incr]->stringval); 
+		    }
+		    if (descending)
+			tst = -tst;
+		}
+		if (tst == 0) {
+		    /*
+		     * Okay we need to use multi level sorts
+		     */
+		    depth = 1;
+		    while (depth < nbsorts) {
+			if (sorts[depth] == NULL)
+			    break;
+			comp = sorts[depth]->psvi;
+			if (comp == NULL)
+			    break;
+			desc = comp->descending;
+			numb = comp->number;
+
+			/*
+			 * Compute the result of the next level for the
+			 * full set, this might be optimized ... or not
+			 */
+			if (resultsTab[depth] == NULL) 
+			    resultsTab[depth] = xsltComputeSortResult(ctxt,
+				                        sorts[depth]);
+			res = resultsTab[depth];
+			if (res == NULL) 
+			    break;
+			if (res[j] == NULL) {
+			    if (res[j+incr] != NULL)
+				tst = 1;
+			} else {
+			    if (numb) {
+				/* We make NaN smaller than number in
+				   accordance with XSLT spec */
+				if (xmlXPathIsNaN(res[j]->floatval)) {
+				    if (xmlXPathIsNaN(res[j +
+				    		incr]->floatval))
+					tst = 0;
+				    else
+				        tst = -1;
+				} else if (xmlXPathIsNaN(res[j + incr]->
+						floatval))
+				    tst = 1;
+				else if (res[j]->floatval == res[j + incr]->
+						floatval)
+				    tst = 0;
+				else if (res[j]->floatval > 
+					res[j + incr]->floatval)
+				    tst = 1;
+				else tst = -1;
+			    } else if(comp->locale != (xsltLocale)0) {
+				tst = xsltLocaleStrcmp(
+				    comp->locale,
+				    (xsltLocaleChar *) res[j]->stringval,
+				    (xsltLocaleChar *) res[j + incr]->stringval); 
+			    } else {
+				tst = xmlStrcmp(res[j]->stringval,
+					     res[j + incr]->stringval); 
+			    }
+			    if (desc)
+				tst = -tst;
+			}
+
+			/*
+			 * if we still can't differenciate at this level
+			 * try one level deeper.
+			 */
+			if (tst != 0)
+			    break;
+			depth++;
+		    }
+		}
+		if (tst == 0) {
+		    tst = results[j]->index > results[j + incr]->index;
+		}
+		if (tst > 0) {
+		    tmp = results[j];
+		    results[j] = results[j + incr];
+		    results[j + incr] = tmp;
+		    node = list->nodeTab[j];
+		    list->nodeTab[j] = list->nodeTab[j + incr];
+		    list->nodeTab[j + incr] = node;
+		    depth = 1;
+		    while (depth < nbsorts) {
+			if (sorts[depth] == NULL)
+			    break;
+			if (resultsTab[depth] == NULL)
+			    break;
+			res = resultsTab[depth];
+			tmp = res[j];
+			res[j] = res[j + incr];
+			res[j + incr] = tmp;
+			depth++;
+		    }
+		    j -= incr;
+		} else
+		    break;
+	    }
+	}
+    }
+
+    for (j = 0; j < nbsorts; j++) {
+	comp = sorts[j]->psvi;
+	if (tempstype[j] == 1) {
+	    /* The data-type needs to be recomputed each time */
+	    xmlFree((void *)(comp->stype));
+	    comp->stype = NULL;
+	}
+	if (temporder[j] == 1) {
+	    /* The order needs to be recomputed each time */
+	    xmlFree((void *)(comp->order));
+	    comp->order = NULL;
+	}
+	if (resultsTab[j] != NULL) {
+	    for (i = 0;i < len;i++)
+		xmlXPathFreeObject(resultsTab[j][i]);
+	    xmlFree(resultsTab[j]);
+	}
+    }
+}
+
+
+static xsltSortFunc xsltSortFunction = xsltDefaultSortFunction;
+
+/**
+ * xsltDoSortFunction:
+ * @ctxt:  a XSLT process context
+ * @sorts:  array of sort nodes
+ * @nbsorts:  the number of sorts in the array
+ *
+ * reorder the current node list accordingly to the set of sorting
+ * requirement provided by the arry of nodes.
+ * This is a wrapper function, the actual function used is specified
+ * using xsltSetCtxtSortFunc() to set the context specific sort function,
+ * or xsltSetSortFunc() to set the global sort function.
+ * If a sort function is set on the context, this will get called.
+ * Otherwise the global sort function is called.
+ */
+void
+xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts,
+                   int nbsorts)
+{
+    if (ctxt->sortfunc != NULL)
+	(ctxt->sortfunc)(ctxt, sorts, nbsorts);
+    else if (xsltSortFunction != NULL)
+        xsltSortFunction(ctxt, sorts, nbsorts);
+}
+
+/**
+ * xsltSetSortFunc:
+ * @handler:  the new handler function
+ *
+ * Function to reset the global handler for XSLT sorting.
+ * If the handler is NULL, the default sort function will be used.
+ */
+void
+xsltSetSortFunc(xsltSortFunc handler) {
+    if (handler != NULL)
+	xsltSortFunction = handler;
+    else
+	xsltSortFunction = xsltDefaultSortFunction;
+}
+
+/**
+ * xsltSetCtxtSortFunc:
+ * @ctxt:  a XSLT process context
+ * @handler:  the new handler function
+ *
+ * Function to set the handler for XSLT sorting
+ * for the specified context. 
+ * If the handler is NULL, then the global
+ * sort function will be called
+ */
+void 
+xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) {
+    ctxt->sortfunc = handler;
+}
+
+/************************************************************************
+ * 									*
+ * 				Parsing options				*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltSetCtxtParseOptions:
+ * @ctxt:  a XSLT process context
+ * @options:  a combination of libxml2 xmlParserOption
+ * 
+ * Change the default parser option passed by the XSLT engine to the 
+ * parser when using document() loading.
+ *
+ * Returns the previous options or -1 in case of error
+ */
+int 
+xsltSetCtxtParseOptions(xsltTransformContextPtr ctxt, int options)
+{
+    int oldopts;
+
+    if (ctxt == NULL)
+        return(-1);
+    oldopts = ctxt->parserOptions;
+    if (ctxt->xinclude)
+        oldopts |= XML_PARSE_XINCLUDE;
+    ctxt->parserOptions = options;
+    if (options & XML_PARSE_XINCLUDE)
+        ctxt->xinclude = 1;
+    else
+        ctxt->xinclude = 0;
+    return(oldopts);
+}
+
+/************************************************************************
+ * 									*
+ * 				Output					*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltSaveResultTo:
+ * @buf:  an output buffer
+ * @result:  the result xmlDocPtr
+ * @style:  the stylesheet
+ *
+ * Save the result @result obtained by applying the @style stylesheet
+ * to an I/O output channel @buf
+ *
+ * Returns the number of byte written or -1 in case of failure.
+ */
+int
+xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
+	       xsltStylesheetPtr style) {
+    const xmlChar *encoding;
+    int base;
+    const xmlChar *method;
+    int indent;
+
+    if ((buf == NULL) || (result == NULL) || (style == NULL))
+	return(-1);
+    if ((result->children == NULL) ||
+	((result->children->type == XML_DTD_NODE) &&
+	 (result->children->next == NULL)))
+	return(0);
+
+    if ((style->methodURI != NULL) &&
+	((style->method == NULL) ||
+	 (!xmlStrEqual(style->method, (const xmlChar *) "xhtml")))) {
+        xsltGenericError(xsltGenericErrorContext,
+		"xsltSaveResultTo : unknown ouput method\n");
+        return(-1);
+    }
+
+    base = buf->written;
+
+    XSLT_GET_IMPORT_PTR(method, style, method)
+    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
+    XSLT_GET_IMPORT_INT(indent, style, indent);
+
+    if ((method == NULL) && (result->type == XML_HTML_DOCUMENT_NODE))
+	method = (const xmlChar *) "html";
+
+    if ((method != NULL) &&
+	(xmlStrEqual(method, (const xmlChar *) "html"))) {
+	if (encoding != NULL) {
+	    htmlSetMetaEncoding(result, (const xmlChar *) encoding);
+	} else {
+	    htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
+	}
+	if (indent == -1)
+	    indent = 1;
+	htmlDocContentDumpFormatOutput(buf, result, (const char *) encoding,
+		                       indent);
+	xmlOutputBufferFlush(buf);
+    } else if ((method != NULL) &&
+	(xmlStrEqual(method, (const xmlChar *) "xhtml"))) {
+	if (encoding != NULL) {
+	    htmlSetMetaEncoding(result, (const xmlChar *) encoding);
+	} else {
+	    htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
+	}
+	htmlDocContentDumpOutput(buf, result, (const char *) encoding);
+	xmlOutputBufferFlush(buf);
+    } else if ((method != NULL) &&
+	       (xmlStrEqual(method, (const xmlChar *) "text"))) {
+	xmlNodePtr cur;
+
+	cur = result->children;
+	while (cur != NULL) {
+	    if (cur->type == XML_TEXT_NODE)
+		xmlOutputBufferWriteString(buf, (const char *) cur->content);
+
+	    /*
+	     * Skip to next node
+	     */
+	    if (cur->children != NULL) {
+		if ((cur->children->type != XML_ENTITY_DECL) &&
+		    (cur->children->type != XML_ENTITY_REF_NODE) &&
+		    (cur->children->type != XML_ENTITY_NODE)) {
+		    cur = cur->children;
+		    continue;
+		}
+	    }
+	    if (cur->next != NULL) {
+		cur = cur->next;
+		continue;
+	    }
+	    
+	    do {
+		cur = cur->parent;
+		if (cur == NULL)
+		    break;
+		if (cur == (xmlNodePtr) style->doc) {
+		    cur = NULL;
+		    break;
+		}
+		if (cur->next != NULL) {
+		    cur = cur->next;
+		    break;
+		}
+	    } while (cur != NULL);
+	}
+	xmlOutputBufferFlush(buf);
+    } else {
+	int omitXmlDecl;
+	int standalone;
+
+	XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration);
+	XSLT_GET_IMPORT_INT(standalone, style, standalone);
+
+	if (omitXmlDecl != 1) {
+	    xmlOutputBufferWriteString(buf, "<?xml version=");
+	    if (result->version != NULL) 
+		xmlBufferWriteQuotedString(buf->buffer, result->version);
+	    else
+		xmlOutputBufferWriteString(buf, "\"1.0\"");
+	    if (encoding == NULL) {
+		if (result->encoding != NULL)
+		    encoding = result->encoding;
+		else if (result->charset != XML_CHAR_ENCODING_UTF8)
+		    encoding = (const xmlChar *)
+			       xmlGetCharEncodingName((xmlCharEncoding)
+			                              result->charset);
+	    }
+	    if (encoding != NULL) {
+		xmlOutputBufferWriteString(buf, " encoding=");
+		xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
+	    }
+	    switch (standalone) {
+		case 0:
+		    xmlOutputBufferWriteString(buf, " standalone=\"no\"");
+		    break;
+		case 1:
+		    xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
+		    break;
+		default:
+		    break;
+	    }
+	    xmlOutputBufferWriteString(buf, "?>\n");
+	}
+	if (result->children != NULL) {
+	    xmlNodePtr child = result->children;
+
+	    while (child != NULL) {
+		xmlNodeDumpOutput(buf, result, child, 0, (indent == 1),
+			          (const char *) encoding);
+		if ((child->type == XML_DTD_NODE) ||
+		    ((child->type == XML_COMMENT_NODE) &&
+		     (child->next != NULL)))
+		    xmlOutputBufferWriteString(buf, "\n");
+		child = child->next;
+	    }
+	    xmlOutputBufferWriteString(buf, "\n");
+	}
+	xmlOutputBufferFlush(buf);
+    }
+    return(buf->written - base);
+}
+
+/**
+ * xsltSaveResultToFilename:
+ * @URL:  a filename or URL
+ * @result:  the result xmlDocPtr
+ * @style:  the stylesheet
+ * @compression:  the compression factor (0 - 9 included)
+ *
+ * Save the result @result obtained by applying the @style stylesheet
+ * to a file or @URL
+ *
+ * Returns the number of byte written or -1 in case of failure.
+ */
+int
+xsltSaveResultToFilename(const char *URL, xmlDocPtr result,
+			 xsltStylesheetPtr style, int compression) {
+    xmlOutputBufferPtr buf;
+    const xmlChar *encoding;
+    int ret;
+
+    if ((URL == NULL) || (result == NULL) || (style == NULL))
+	return(-1);
+    if (result->children == NULL)
+	return(0);
+
+    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
+    if (encoding != NULL) {
+	xmlCharEncodingHandlerPtr encoder;
+
+	encoder = xmlFindCharEncodingHandler((char *)encoding);
+	if ((encoder != NULL) &&
+	    (xmlStrEqual((const xmlChar *)encoder->name,
+			 (const xmlChar *) "UTF-8")))
+	    encoder = NULL;
+	buf = xmlOutputBufferCreateFilename(URL, encoder, compression);
+    } else {
+	buf = xmlOutputBufferCreateFilename(URL, NULL, compression);
+    }
+    if (buf == NULL)
+	return(-1);
+    xsltSaveResultTo(buf, result, style);
+    ret = xmlOutputBufferClose(buf);
+    return(ret);
+}
+
+/**
+ * xsltSaveResultToFile:
+ * @file:  a FILE * I/O
+ * @result:  the result xmlDocPtr
+ * @style:  the stylesheet
+ *
+ * Save the result @result obtained by applying the @style stylesheet
+ * to an open FILE * I/O.
+ * This does not close the FILE @file
+ *
+ * Returns the number of bytes written or -1 in case of failure.
+ */
+int
+xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {
+    xmlOutputBufferPtr buf;
+    const xmlChar *encoding;
+    int ret;
+
+    if ((file == NULL) || (result == NULL) || (style == NULL))
+	return(-1);
+    if (result->children == NULL)
+	return(0);
+
+    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
+    if (encoding != NULL) {
+	xmlCharEncodingHandlerPtr encoder;
+
+	encoder = xmlFindCharEncodingHandler((char *)encoding);
+	if ((encoder != NULL) &&
+	    (xmlStrEqual((const xmlChar *)encoder->name,
+			 (const xmlChar *) "UTF-8")))
+	    encoder = NULL;
+	buf = xmlOutputBufferCreateFile(file, encoder);
+    } else {
+	buf = xmlOutputBufferCreateFile(file, NULL);
+    }
+
+    if (buf == NULL)
+	return(-1);
+    xsltSaveResultTo(buf, result, style);
+    ret = xmlOutputBufferClose(buf);
+    return(ret);
+}
+
+/**
+ * xsltSaveResultToFd:
+ * @fd:  a file descriptor
+ * @result:  the result xmlDocPtr
+ * @style:  the stylesheet
+ *
+ * Save the result @result obtained by applying the @style stylesheet
+ * to an open file descriptor
+ * This does not close the descriptor.
+ *
+ * Returns the number of bytes written or -1 in case of failure.
+ */
+int
+xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) {
+    xmlOutputBufferPtr buf;
+    const xmlChar *encoding;
+    int ret;
+
+    if ((fd < 0) || (result == NULL) || (style == NULL))
+	return(-1);
+    if (result->children == NULL)
+	return(0);
+
+    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
+    if (encoding != NULL) {
+	xmlCharEncodingHandlerPtr encoder;
+
+	encoder = xmlFindCharEncodingHandler((char *)encoding);
+	if ((encoder != NULL) &&
+	    (xmlStrEqual((const xmlChar *)encoder->name,
+			 (const xmlChar *) "UTF-8")))
+	    encoder = NULL;
+	buf = xmlOutputBufferCreateFd(fd, encoder);
+    } else {
+	buf = xmlOutputBufferCreateFd(fd, NULL);
+    }
+    if (buf == NULL)
+	return(-1);
+    xsltSaveResultTo(buf, result, style);
+    ret = xmlOutputBufferClose(buf);
+    return(ret);
+}
+
+/**
+ * xsltSaveResultToString:
+ * @doc_txt_ptr:  Memory pointer for allocated XML text
+ * @doc_txt_len:  Length of the generated XML text
+ * @result:  the result xmlDocPtr
+ * @style:  the stylesheet
+ *
+ * Save the result @result obtained by applying the @style stylesheet
+ * to a new allocated string.
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+int
+xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len, 
+		       xmlDocPtr result, xsltStylesheetPtr style) {
+    xmlOutputBufferPtr buf;
+    const xmlChar *encoding;
+
+    *doc_txt_ptr = NULL;
+    *doc_txt_len = 0;
+    if (result->children == NULL)
+	return(0);
+
+    XSLT_GET_IMPORT_PTR(encoding, style, encoding)
+    if (encoding != NULL) {
+	xmlCharEncodingHandlerPtr encoder;
+
+	encoder = xmlFindCharEncodingHandler((char *)encoding);
+	if ((encoder != NULL) &&
+	    (xmlStrEqual((const xmlChar *)encoder->name,
+			 (const xmlChar *) "UTF-8")))
+	    encoder = NULL;
+	buf = xmlAllocOutputBuffer(encoder);
+    } else {
+	buf = xmlAllocOutputBuffer(NULL);
+    }
+    if (buf == NULL)
+	return(-1);
+    xsltSaveResultTo(buf, result, style);
+    if (buf->conv != NULL) {
+	*doc_txt_len = buf->conv->use;
+	*doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len);
+    } else {
+	*doc_txt_len = buf->buffer->use;
+	*doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len);
+    }
+    (void)xmlOutputBufferClose(buf);
+    return 0;
+}
+
+/************************************************************************
+ * 									*
+ * 		Generating profiling informations			*
+ * 									*
+ ************************************************************************/
+
+static long calibration = -1;
+
+/**
+ * xsltCalibrateTimestamps:
+ *
+ * Used for to calibrate the xsltTimestamp() function
+ * Should work if launched at startup and we don't loose our quantum :-)
+ *
+ * Returns the number of milliseconds used by xsltTimestamp()
+ */
+static long
+xsltCalibrateTimestamps(void) {
+    register int i;
+
+    for (i = 0;i < 999;i++)
+	xsltTimestamp();
+    return(xsltTimestamp() / 1000);
+}
+
+/**
+ * xsltCalibrateAdjust:
+ * @delta:  a negative dealy value found
+ *
+ * Used for to correct the calibration for xsltTimestamp()
+ */
+void
+xsltCalibrateAdjust(long delta) {
+    calibration += delta;
+}
+
+/**
+ * xsltTimestamp:
+ *
+ * Used for gathering profiling data
+ *
+ * Returns the number of tenth of milliseconds since the beginning of the
+ * profiling
+ */
+long
+xsltTimestamp(void)
+{
+#ifdef XSLT_WIN32_PERFORMANCE_COUNTER
+    BOOL ok;
+    LARGE_INTEGER performanceCount;
+    LARGE_INTEGER performanceFrequency;
+    LONGLONG quadCount;
+    double seconds;
+    static LONGLONG startupQuadCount = 0;
+    static LONGLONG startupQuadFreq = 0;
+
+    ok = QueryPerformanceCounter(&performanceCount);
+    if (!ok)
+        return 0;
+    quadCount = performanceCount.QuadPart;
+    if (calibration < 0) {
+        calibration = 0;
+        ok = QueryPerformanceFrequency(&performanceFrequency);
+        if (!ok)
+            return 0;
+        startupQuadFreq = performanceFrequency.QuadPart;
+        startupQuadCount = quadCount;
+        return (0);
+    }
+    if (startupQuadFreq == 0)
+        return 0;
+    seconds = (quadCount - startupQuadCount) / (double) startupQuadFreq;
+    return (long) (seconds * XSLT_TIMESTAMP_TICS_PER_SEC);
+
+#else /* XSLT_WIN32_PERFORMANCE_COUNTER */
+#ifdef HAVE_GETTIMEOFDAY
+    static struct timeval startup;
+    struct timeval cur;
+    long tics;
+
+    if (calibration < 0) {
+        gettimeofday(&startup, NULL);
+        calibration = 0;
+        calibration = xsltCalibrateTimestamps();
+        gettimeofday(&startup, NULL);
+        return (0);
+    }
+
+    gettimeofday(&cur, NULL);
+    tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
+    tics += (cur.tv_usec - startup.tv_usec) /
+                          (1000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
+    
+    tics -= calibration;
+    return(tics);
+#else
+
+    /* Neither gettimeofday() nor Win32 performance counter available */
+
+    return (0);
+
+#endif /* HAVE_GETTIMEOFDAY */
+#endif /* XSLT_WIN32_PERFORMANCE_COUNTER */
+}
+
+#define MAX_TEMPLATES 10000
+
+/**
+ * xsltSaveProfiling:
+ * @ctxt:  an XSLT context
+ * @output:  a FILE * for saving the informations
+ *
+ * Save the profiling informations on @output
+ */
+void
+xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) {
+    int nb, i,j;
+    int max;
+    int total;
+    long totalt;
+    xsltTemplatePtr *templates;
+    xsltStylesheetPtr style;
+    xsltTemplatePtr template;
+
+    if ((output == NULL) || (ctxt == NULL))
+	return;
+    if (ctxt->profile == 0)
+	return;
+
+    nb = 0;
+    max = MAX_TEMPLATES;
+    templates = xmlMalloc(max * sizeof(xsltTemplatePtr));
+    if (templates == NULL)
+	return;
+
+    style = ctxt->style;
+    while (style != NULL) {
+	template = style->templates;
+	while (template != NULL) {
+	    if (nb >= max)
+		break;
+
+	    if (template->nbCalls > 0)
+		templates[nb++] = template;
+	    template = template->next;
+	}
+
+	style = xsltNextImport(style);
+    }
+
+    for (i = 0;i < nb -1;i++) {
+	for (j = i + 1; j < nb; j++) {
+	    if ((templates[i]->time <= templates[j]->time) ||
+		((templates[i]->time == templates[j]->time) &&
+	         (templates[i]->nbCalls <= templates[j]->nbCalls))) {
+		template = templates[j];
+		templates[j] = templates[i];
+		templates[i] = template;
+	    }
+	}
+    }
+
+    fprintf(output, "%6s%20s%20s%10s  Calls Tot 100us Avg\n\n",
+	    "number", "match", "name", "mode");
+    total = 0;
+    totalt = 0;
+    for (i = 0;i < nb;i++) {
+	fprintf(output, "%5d ", i);
+	if (templates[i]->match != NULL) {
+	    if (xmlStrlen(templates[i]->match) > 20)
+		fprintf(output, "%s\n%26s", templates[i]->match, "");
+	    else
+		fprintf(output, "%20s", templates[i]->match);
+	} else {
+	    fprintf(output, "%20s", "");
+	}
+	if (templates[i]->name != NULL) {
+	    if (xmlStrlen(templates[i]->name) > 20)
+		fprintf(output, "%s\n%46s", templates[i]->name, "");
+	    else
+		fprintf(output, "%20s", templates[i]->name);
+	} else {
+	    fprintf(output, "%20s", "");
+	}
+	if (templates[i]->mode != NULL) {
+	    if (xmlStrlen(templates[i]->mode) > 10)
+		fprintf(output, "%s\n%56s", templates[i]->mode, "");
+	    else
+		fprintf(output, "%10s", templates[i]->mode);
+	} else {
+	    fprintf(output, "%10s", "");
+	}
+	fprintf(output, " %6d", templates[i]->nbCalls);
+	fprintf(output, " %6ld %6ld\n", templates[i]->time,
+		templates[i]->time / templates[i]->nbCalls);
+	total += templates[i]->nbCalls;
+	totalt += templates[i]->time;
+    }
+    fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt);
+
+    xmlFree(templates);
+}
+
+/************************************************************************
+ * 									*
+ * 		Fetching profiling informations				*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltGetProfileInformation:
+ * @ctxt:  a transformation context
+ *
+ * This function should be called after the transformation completed
+ * to extract template processing profiling informations if availble.
+ * The informations are returned as an XML document tree like
+ * <?xml version="1.0"?>
+ * <profile>
+ * <template rank="1" match="*" name=""
+ *         mode="" calls="6" time="48" average="8"/>
+ * <template rank="2" match="item2|item3" name=""
+ *         mode="" calls="10" time="30" average="3"/>
+ * <template rank="3" match="item1" name=""
+ *         mode="" calls="5" time="17" average="3"/>
+ * </profile>
+ * The caller will need to free up the returned tree with xmlFreeDoc()
+ *
+ * Returns the xmlDocPtr corresponding to the result or NULL if not available.
+ */
+
+xmlDocPtr
+xsltGetProfileInformation(xsltTransformContextPtr ctxt)
+{
+    xmlDocPtr ret = NULL;
+    xmlNodePtr root, child;
+    char buf[100];
+
+    xsltStylesheetPtr style;
+    xsltTemplatePtr *templates;
+    xsltTemplatePtr templ;
+    int nb = 0, max = 0, i, j;
+
+    if (!ctxt)
+        return NULL;
+
+    if (!ctxt->profile)
+        return NULL;
+
+    nb = 0;
+    max = 10000;
+    templates =
+        (xsltTemplatePtr *) xmlMalloc(max * sizeof(xsltTemplatePtr));
+    if (templates == NULL)
+        return NULL;
+
+    /*
+     * collect all the templates in an array
+     */
+    style = ctxt->style;
+    while (style != NULL) {
+        templ = style->templates;
+        while (templ != NULL) {
+            if (nb >= max)
+                break;
+
+            if (templ->nbCalls > 0)
+                templates[nb++] = templ;
+            templ = templ->next;
+        }
+
+        style = (xsltStylesheetPtr) xsltNextImport(style);
+    }
+
+    /*
+     * Sort the array by time spent
+     */
+    for (i = 0; i < nb - 1; i++) {
+        for (j = i + 1; j < nb; j++) {
+            if ((templates[i]->time <= templates[j]->time) ||
+                ((templates[i]->time == templates[j]->time) &&
+                 (templates[i]->nbCalls <= templates[j]->nbCalls))) {
+                templ = templates[j];
+                templates[j] = templates[i];
+                templates[i] = templ;
+            }
+        }
+    }
+
+    /*
+     * Generate a document corresponding to the results.
+     */
+    ret = xmlNewDoc(BAD_CAST "1.0");
+    root = xmlNewDocNode(ret, NULL, BAD_CAST "profile", NULL);
+    xmlDocSetRootElement(ret, root);
+
+    for (i = 0; i < nb; i++) {
+        child = xmlNewChild(root, NULL, BAD_CAST "template", NULL);
+        sprintf(buf, "%d", i + 1);
+        xmlSetProp(child, BAD_CAST "rank", BAD_CAST buf);
+        xmlSetProp(child, BAD_CAST "match", BAD_CAST templates[i]->match);
+        xmlSetProp(child, BAD_CAST "name", BAD_CAST templates[i]->name);
+        xmlSetProp(child, BAD_CAST "mode", BAD_CAST templates[i]->mode);
+
+        sprintf(buf, "%d", templates[i]->nbCalls);
+        xmlSetProp(child, BAD_CAST "calls", BAD_CAST buf);
+
+        sprintf(buf, "%ld", templates[i]->time);
+        xmlSetProp(child, BAD_CAST "time", BAD_CAST buf);
+
+        sprintf(buf, "%ld", templates[i]->time / templates[i]->nbCalls);
+        xmlSetProp(child, BAD_CAST "average", BAD_CAST buf);
+    };
+
+    xmlFree(templates);
+
+    return ret;
+}
+
+/************************************************************************
+ * 									*
+ * 		Hooks for libxml2 XPath					*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltXPathCompile:
+ * @style: the stylesheet
+ * @str:  the XPath expression
+ *
+ * Compile an XPath expression
+ *
+ * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
+ *         the caller has to free the object.
+ */
+xmlXPathCompExprPtr
+xsltXPathCompile(xsltStylesheetPtr style, const xmlChar *str) {
+    xmlXPathContextPtr xpathCtxt;
+    xmlXPathCompExprPtr ret;
+
+    if (style != NULL) {
+#ifdef XSLT_REFACTORED_XPATHCOMP
+	if (XSLT_CCTXT(style)) {
+	    /*
+	    * Proposed by Jerome Pesenti
+	    * --------------------------
+	    * For better efficiency we'll reuse the compilation
+	    * context's XPath context. For the common stylesheet using
+	    * XPath expressions this will reduce compilation time to
+	    * about 50%.
+	    *
+	    * See http://mail.gnome.org/archives/xslt/2006-April/msg00037.html
+	    */
+	    xpathCtxt = XSLT_CCTXT(style)->xpathCtxt;
+	    xpathCtxt->doc = style->doc;
+	} else
+	    xpathCtxt = xmlXPathNewContext(style->doc);
+#else
+	xpathCtxt = xmlXPathNewContext(style->doc);
+#endif
+	if (xpathCtxt == NULL)
+	    return NULL;
+	xpathCtxt->dict = style->dict;
+    } else {
+	xpathCtxt = xmlXPathNewContext(NULL);
+	if (xpathCtxt == NULL)
+	    return NULL;
+    }
+    /*
+    * Compile the expression.
+    */
+    ret = xmlXPathCtxtCompile(xpathCtxt, str);
+
+#ifdef XSLT_REFACTORED_XPATHCOMP
+    if ((style == NULL) || (! XSLT_CCTXT(style))) {
+	xmlXPathFreeContext(xpathCtxt);
+    }
+#else
+    xmlXPathFreeContext(xpathCtxt);
+#endif
+    /*
+     * TODO: there is a lot of optimizations which should be possible
+     *       like variable slot precomputations, function precomputations, etc.
+     */
+
+    return(ret);
+}
+
+/************************************************************************
+ * 									*
+ * 		Hooks for the debugger					*
+ * 									*
+ ************************************************************************/
+
+/*
+ * There is currently only 3 debugging callback defined
+ * Debugger callbacks are disabled by default
+ */
+#define XSLT_CALLBACK_NUMBER 3
+
+typedef struct _xsltDebuggerCallbacks xsltDebuggerCallbacks;
+typedef xsltDebuggerCallbacks *xsltDebuggerCallbacksPtr;
+struct _xsltDebuggerCallbacks {
+    xsltHandleDebuggerCallback handler;
+    xsltAddCallCallback add;
+    xsltDropCallCallback drop;
+};
+
+static xsltDebuggerCallbacks xsltDebuggerCurrentCallbacks = {
+    NULL, /* handler */
+    NULL, /* add */
+    NULL  /* drop */
+};
+
+int xslDebugStatus;
+
+/**
+ * xsltSetDebuggerStatus:
+ * @value : the value to be set
+ * 
+ * This function sets the value of xslDebugStatus.
+ */
+void
+xsltSetDebuggerStatus(int value)
+{
+    xslDebugStatus = value;	
+}
+
+/**
+ * xsltGetDebuggerStatus: 
+ * 
+ * Get xslDebugStatus.
+ *
+ * Returns the value of xslDebugStatus.
+ */
+int
+xsltGetDebuggerStatus(void)
+{
+    return(xslDebugStatus);	
+}
+
+/**
+ * xsltSetDebuggerCallbacks:
+ * @no : number of callbacks
+ * @block : the block of callbacks
+ * 
+ * This function allow to plug a debugger into the XSLT library
+ * @block points to a block of memory containing the address of @no 
+ * callback routines.
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+int
+xsltSetDebuggerCallbacks(int no, void *block)
+{
+    xsltDebuggerCallbacksPtr callbacks;
+
+    if ((block == NULL) || (no != XSLT_CALLBACK_NUMBER))
+	return(-1);
+
+    callbacks = (xsltDebuggerCallbacksPtr) block;
+    xsltDebuggerCurrentCallbacks.handler = callbacks->handler;
+    xsltDebuggerCurrentCallbacks.add  = callbacks->add;
+    xsltDebuggerCurrentCallbacks.drop  = callbacks->drop;
+    return(0);
+}
+
+/**
+ * xslHandleDebugger:
+ * @cur : source node being executed
+ * @node : data node being processed
+ * @templ : temlate that applies to node
+ * @ctxt : the xslt transform context 
+ * 
+ * If either cur or node are a breakpoint, or xslDebugStatus in state 
+ *   where debugging must occcur at this time then transfer control
+ *   to the xslDebugBreak function
+ */
+void
+xslHandleDebugger(xmlNodePtr cur, xmlNodePtr node, xsltTemplatePtr templ,
+	          xsltTransformContextPtr ctxt)
+{
+    if (xsltDebuggerCurrentCallbacks.handler != NULL)
+	xsltDebuggerCurrentCallbacks.handler(cur, node, templ, ctxt);
+}
+
+/**
+ * xslAddCall:
+ * @templ : current template being applied
+ * @source : the source node being processed
+ *
+ * Add template "call" to call stack
+ * Returns : 1 on sucess 0 otherwise an error may be printed if 
+ *            WITH_XSLT_DEBUG_BREAKPOINTS is defined
+ */
+int
+xslAddCall(xsltTemplatePtr templ, xmlNodePtr source)
+{
+    if (xsltDebuggerCurrentCallbacks.add != NULL)
+	return(xsltDebuggerCurrentCallbacks.add(templ, source));
+    return(0);
+}
+
+/**
+ * xslDropCall:
+ *
+ * Drop the topmost item off the call stack
+ */
+void
+xslDropCall(void)
+{
+    if (xsltDebuggerCurrentCallbacks.drop != NULL)
+	xsltDebuggerCurrentCallbacks.drop();
+}
+
diff --git a/libxslt/xsltutils.h b/libxslt/xsltutils.h
new file mode 100644
index 0000000..3886be3
--- /dev/null
+++ b/libxslt/xsltutils.h
@@ -0,0 +1,309 @@
+/*
+ * Summary: set of utilities for the XSLT engine
+ * Description: interfaces for the utilities module of the XSLT engine.
+ *              things like message handling, profiling, and other
+ *              generally useful routines.
+ *
+ * Copy: See Copyright for the status of this software.
+ *
+ * Author: Daniel Veillard
+ */
+
+#ifndef __XML_XSLTUTILS_H__
+#define __XML_XSLTUTILS_H__
+
+#include <libxslt/xsltconfig.h>
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#include <libxml/xpath.h>
+#include <libxml/dict.h>
+#include <libxml/xmlerror.h>
+#include "xsltexports.h"
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * XSLT_TODO:
+ *
+ * Macro to flag unimplemented blocks.
+ */
+#define XSLT_TODO 							\
+    xsltGenericError(xsltGenericErrorContext,				\
+	    "Unimplemented block at %s:%d\n",				\
+            __FILE__, __LINE__);
+
+/**
+ * XSLT_STRANGE:
+ *
+ * Macro to flag that a problem was detected internally.
+ */
+#define XSLT_STRANGE 							\
+    xsltGenericError(xsltGenericErrorContext,				\
+	    "Internal error at %s:%d\n",				\
+            __FILE__, __LINE__);
+
+/**
+ * IS_XSLT_ELEM:
+ *
+ * Checks that the element pertains to XSLT namespace.
+ */
+#define IS_XSLT_ELEM(n)							\
+    (((n) != NULL) && ((n)->ns != NULL) &&				\
+     (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE)))
+
+/**
+ * IS_XSLT_NAME:
+ *
+ * Checks the value of an element in XSLT namespace.
+ */
+#define IS_XSLT_NAME(n, val)						\
+    (xmlStrEqual((n)->name, (const xmlChar *) (val)))
+
+/**
+ * IS_XSLT_REAL_NODE:
+ *
+ * Check that a node is a 'real' one: document, element, text or attribute.
+ */
+#define IS_XSLT_REAL_NODE(n)						\
+    (((n) != NULL) &&							\
+     (((n)->type == XML_ELEMENT_NODE) ||				\
+      ((n)->type == XML_TEXT_NODE) ||					\
+      ((n)->type == XML_CDATA_SECTION_NODE) ||				\
+      ((n)->type == XML_ATTRIBUTE_NODE) ||				\
+      ((n)->type == XML_DOCUMENT_NODE) ||				\
+      ((n)->type == XML_HTML_DOCUMENT_NODE) ||				\
+      ((n)->type == XML_COMMENT_NODE) ||				\
+      ((n)->type == XML_PI_NODE)))      
+
+/*
+ * Our own version of namespaced atributes lookup.
+ */
+XSLTPUBFUN xmlChar * XSLTCALL
+		xsltGetNsProp	(xmlNodePtr node,
+				 const xmlChar *name,
+				 const xmlChar *nameSpace);
+XSLTPUBFUN const xmlChar * XSLTCALL
+		xsltGetCNsProp	(xsltStylesheetPtr style,
+				 xmlNodePtr node,
+				 const xmlChar *name,
+				 const xmlChar *nameSpace);
+XSLTPUBFUN int XSLTCALL
+		xsltGetUTF8Char	(const unsigned char *utf,
+				 int *len);
+
+/*
+ * XSLT Debug Tracing Tracing Types
+ */
+typedef enum {
+	XSLT_TRACE_ALL =		-1,
+	XSLT_TRACE_NONE = 		0,
+	XSLT_TRACE_COPY_TEXT = 		1<<0,
+	XSLT_TRACE_PROCESS_NODE = 	1<<1,
+	XSLT_TRACE_APPLY_TEMPLATE = 	1<<2,
+	XSLT_TRACE_COPY = 		1<<3,
+	XSLT_TRACE_COMMENT = 		1<<4,
+	XSLT_TRACE_PI = 		1<<5,
+	XSLT_TRACE_COPY_OF = 		1<<6,
+	XSLT_TRACE_VALUE_OF = 		1<<7,
+	XSLT_TRACE_CALL_TEMPLATE = 	1<<8,
+	XSLT_TRACE_APPLY_TEMPLATES = 	1<<9,
+	XSLT_TRACE_CHOOSE = 		1<<10,
+	XSLT_TRACE_IF = 		1<<11,
+	XSLT_TRACE_FOR_EACH = 		1<<12,
+	XSLT_TRACE_STRIP_SPACES = 	1<<13,
+	XSLT_TRACE_TEMPLATES = 		1<<14,
+	XSLT_TRACE_KEYS = 		1<<15,
+	XSLT_TRACE_VARIABLES = 		1<<16
+} xsltDebugTraceCodes;
+
+/**
+ * XSLT_TRACE:
+ *
+ * Control the type of xsl debugtrace messages emitted.
+ */
+#define XSLT_TRACE(ctxt,code,call)	\
+	if (ctxt->traceCode && (*(ctxt->traceCode) & code)) \
+	    call
+
+XSLTPUBFUN void XSLTCALL
+		xsltDebugSetDefaultTrace(xsltDebugTraceCodes val);
+XSLTPUBFUN xsltDebugTraceCodes XSLTCALL
+		xsltDebugGetDefaultTrace(void);
+
+/*
+ * XSLT specific error and debug reporting functions.
+ */
+XSLTPUBVAR xmlGenericErrorFunc xsltGenericError;
+XSLTPUBVAR void *xsltGenericErrorContext;
+XSLTPUBVAR xmlGenericErrorFunc xsltGenericDebug;
+XSLTPUBVAR void *xsltGenericDebugContext;
+
+XSLTPUBFUN void XSLTCALL		
+		xsltPrintErrorContext		(xsltTransformContextPtr ctxt,
+	                                         xsltStylesheetPtr style,
+						 xmlNodePtr node);
+XSLTPUBFUN void XSLTCALL		
+    		xsltMessage			(xsltTransformContextPtr ctxt,
+						 xmlNodePtr node,
+						 xmlNodePtr inst);
+XSLTPUBFUN void XSLTCALL		
+    		xsltSetGenericErrorFunc		(void *ctx,
+						 xmlGenericErrorFunc handler);
+XSLTPUBFUN void XSLTCALL		
+    		xsltSetGenericDebugFunc		(void *ctx,
+						 xmlGenericErrorFunc handler);
+XSLTPUBFUN void XSLTCALL		
+    		xsltSetTransformErrorFunc	(xsltTransformContextPtr ctxt,
+						 void *ctx,
+						 xmlGenericErrorFunc handler);
+XSLTPUBFUN void XSLTCALL		
+    		xsltTransformError		(xsltTransformContextPtr ctxt,
+						 xsltStylesheetPtr style,
+						 xmlNodePtr node,
+						 const char *msg,
+						 ...);
+
+XSLTPUBFUN int XSLTCALL
+		xsltSetCtxtParseOptions		(xsltTransformContextPtr ctxt,
+						 int options);
+/*
+ * Sorting.
+ */
+
+XSLTPUBFUN void XSLTCALL		
+    		xsltDocumentSortFunction	(xmlNodeSetPtr list);
+XSLTPUBFUN void XSLTCALL		
+    		xsltSetSortFunc			(xsltSortFunc handler);
+XSLTPUBFUN void XSLTCALL		
+    		xsltSetCtxtSortFunc		(xsltTransformContextPtr ctxt,
+						 xsltSortFunc handler);
+XSLTPUBFUN void XSLTCALL		
+    		xsltDefaultSortFunction		(xsltTransformContextPtr ctxt,
+						 xmlNodePtr *sorts,
+						 int nbsorts);
+XSLTPUBFUN void XSLTCALL		
+    		xsltDoSortFunction		(xsltTransformContextPtr ctxt,
+						 xmlNodePtr * sorts,
+						 int nbsorts);
+XSLTPUBFUN xmlXPathObjectPtr * XSLTCALL 
+    		xsltComputeSortResult		(xsltTransformContextPtr ctxt,
+						 xmlNodePtr sort);
+
+/*
+ * QNames handling.
+ */
+
+XSLTPUBFUN const xmlChar * XSLTCALL
+		xsltSplitQName			(xmlDictPtr dict,
+						 const xmlChar *name,
+						 const xmlChar **prefix);
+XSLTPUBFUN const xmlChar * XSLTCALL 
+    		xsltGetQNameURI			(xmlNodePtr node,
+						 xmlChar **name);
+
+XSLTPUBFUN const xmlChar * XSLTCALL
+		xsltGetQNameURI2		(xsltStylesheetPtr style,
+						 xmlNodePtr node,
+						 const xmlChar **name);
+
+/*
+ * Output, reuse libxml I/O buffers.
+ */
+XSLTPUBFUN int XSLTCALL		
+    		xsltSaveResultTo		(xmlOutputBufferPtr buf,
+						 xmlDocPtr result,
+						 xsltStylesheetPtr style);
+XSLTPUBFUN int XSLTCALL		
+    		xsltSaveResultToFilename	(const char *URI,
+						 xmlDocPtr result,
+						 xsltStylesheetPtr style,
+						 int compression);
+XSLTPUBFUN int XSLTCALL		
+    		xsltSaveResultToFile		(FILE *file,
+						 xmlDocPtr result,
+						 xsltStylesheetPtr style);
+XSLTPUBFUN int XSLTCALL		
+    		xsltSaveResultToFd		(int fd,
+						 xmlDocPtr result,
+						 xsltStylesheetPtr style);
+XSLTPUBFUN int XSLTCALL             
+    		xsltSaveResultToString          (xmlChar **doc_txt_ptr, 
+                                                 int * doc_txt_len, 
+                                                 xmlDocPtr result, 
+                                                 xsltStylesheetPtr style);
+
+/*
+ * XPath interface
+ */
+XSLTPUBFUN xmlXPathCompExprPtr XSLTCALL
+		xsltXPathCompile		(xsltStylesheetPtr style,
+						 const xmlChar *str);
+
+/*
+ * Profiling.
+ */
+XSLTPUBFUN void XSLTCALL		
+    		xsltSaveProfiling		(xsltTransformContextPtr ctxt,
+						 FILE *output);
+XSLTPUBFUN xmlDocPtr XSLTCALL	
+    		xsltGetProfileInformation	(xsltTransformContextPtr ctxt);
+
+XSLTPUBFUN long XSLTCALL		
+    		xsltTimestamp			(void);
+XSLTPUBFUN void XSLTCALL		
+    		xsltCalibrateAdjust		(long delta);
+
+/**
+ * XSLT_TIMESTAMP_TICS_PER_SEC:
+ *
+ * Sampling precision for profiling
+ */
+#define XSLT_TIMESTAMP_TICS_PER_SEC 100000l
+
+/*
+ * Hooks for the debugger.
+ */
+
+typedef enum {
+    XSLT_DEBUG_NONE = 0, /* no debugging allowed */
+    XSLT_DEBUG_INIT,
+    XSLT_DEBUG_STEP,
+    XSLT_DEBUG_STEPOUT,
+    XSLT_DEBUG_NEXT,
+    XSLT_DEBUG_STOP,
+    XSLT_DEBUG_CONT,
+    XSLT_DEBUG_RUN,
+    XSLT_DEBUG_RUN_RESTART,
+    XSLT_DEBUG_QUIT
+} xsltDebugStatusCodes;
+
+XSLTPUBVAR int xslDebugStatus;
+
+typedef void (*xsltHandleDebuggerCallback) (xmlNodePtr cur, xmlNodePtr node,
+			xsltTemplatePtr templ, xsltTransformContextPtr ctxt);
+typedef int (*xsltAddCallCallback) (xsltTemplatePtr templ, xmlNodePtr source);
+typedef void (*xsltDropCallCallback) (void);
+
+XSLTPUBFUN void XSLTCALL
+		xsltSetDebuggerStatus		(int value);
+XSLTPUBFUN int XSLTCALL
+		xsltGetDebuggerStatus		(void);
+XSLTPUBFUN int XSLTCALL		
+		xsltSetDebuggerCallbacks	(int no, void *block);
+XSLTPUBFUN int XSLTCALL		
+		xslAddCall			(xsltTemplatePtr templ,
+						 xmlNodePtr source);
+XSLTPUBFUN void XSLTCALL		
+		xslDropCall			(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLTUTILS_H__ */
+
+