diff --git a/ChangeLog b/ChangeLog
index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_Q2hhbmdlTG9n..96ed246c7e7da2540cd70b1205c31e900fe7ce42_Q2hhbmdlTG9n 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+Sat Jan 20 23:35:07 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+	* libxslt/Makefile.am libxslt/template.[ch]: added a template
+	  specific module. Added attribute value template, at least in
+	  one spot.
+	* tests/REC2/Makefile.am tests/REC2/svg.xml: the SVG test from
+	  the spec now works too.
+	* libxslt/variables.c: fixed the debug
+	* libxslt/xslt.c: fixed an ugly uninitialized variable
+	* libxslt/transform.c: now using attr template processing
+
 Sat Jan 20 17:59:20 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
 	* libxslt/transform.c libxslt/variables.[ch] libxslt/xslt.c
diff --git a/libxslt/Makefile.am b/libxslt/Makefile.am
index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_bGlieHNsdC9NYWtlZmlsZS5hbQ==..96ed246c7e7da2540cd70b1205c31e900fe7ce42_bGlieHNsdC9NYWtlZmlsZS5hbQ== 100644
--- a/libxslt/Makefile.am
+++ b/libxslt/Makefile.am
@@ -10,6 +10,8 @@
 	xsltutils.h			\
 	pattern.c			\
 	pattern.h			\
+	templates.c			\
+	templates.h			\
 	variables.c			\
 	variables.h			\
 	transform.c			\
diff --git a/libxslt/templates.c b/libxslt/templates.c
new file mode 100644
index 0000000000000000000000000000000000000000..96ed246c7e7da2540cd70b1205c31e900fe7ce42_bGlieHNsdC90ZW1wbGF0ZXMuYw==
--- /dev/null
+++ b/libxslt/templates.c
@@ -0,0 +1,266 @@
+/*
+ * 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@imag.fr
+ */
+
+#include "xsltconfig.h"
+
+#include <string.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/xmlerror.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/parserInternals.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "variables.h"
+#include "templates.h"
+
+#define DEBUG_TEMPLATES
+
+/************************************************************************
+ *									*
+ *			Module interfaces				*
+ *									*
+ ************************************************************************/
+ 
+/**
+ * xsltEvalXPathString:
+ * @ctxt:  the XSLT transformation context
+ * @str:  the 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, const xmlChar *expr) {
+    xmlChar *ret = NULL;
+    xmlXPathObjectPtr res, tmp;
+    xmlXPathParserContextPtr xpathParserCtxt;
+
+    if (ctxt->xpathCtxt == NULL) {
+	xmlXPathInit();
+	ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
+	if (ctxt->xpathCtxt == NULL)
+	    return(NULL);
+	XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
+    }
+    xpathParserCtxt =
+	xmlXPathNewParserContext(expr, ctxt->xpathCtxt);
+    if (xpathParserCtxt == NULL)
+	return(NULL);
+    ctxt->xpathCtxt->node = ctxt->node;
+    xmlXPathEvalExpr(xpathParserCtxt);
+    xmlXPathStringFunction(xpathParserCtxt, 1);
+    res = valuePop(xpathParserCtxt);
+    do {
+        tmp = valuePop(xpathParserCtxt);
+	if (tmp != NULL) {
+	    xmlXPathFreeObject(tmp);
+	}
+    } while (tmp != NULL);
+    if (res != NULL) {
+	if (res->type == XPATH_STRING) {
+            ret = res->stringval;
+	    res->stringval = NULL;
+	} else {
+	    xsltGenericError(xsltGenericErrorContext,
+		 "xpath : string() function didn't returned a String\n");
+	}
+	xmlXPathFreeObject(res);
+    }
+    xmlXPathFreeParserContext(xpathParserCtxt);
+#ifdef DEBUG_TEMPLATES
+    xsltGenericDebug(xsltGenericDebugContext,
+	 "xsltEvalXPathString: %s returns %s\n", expr, ret);
+#endif
+    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) {
+    xmlChar *ret = NULL, *ret2;
+    const xmlChar *cur;
+    xmlChar *expr, *val;
+
+    if (str == NULL) return(NULL);
+    cur = str;
+    while (*cur != 0) {
+	if (*cur == '{') {
+	    ret2 = xmlStrncat(ret, str, cur - str);
+	    if (ret != NULL)
+		xmlFree(ret);
+	    ret = ret2;
+	    str = cur;
+	    cur++;
+	    while ((*cur != 0) && (*cur != '}')) cur++;
+	    if (*cur == 0) {
+		ret2 = xmlStrncat(ret, str, cur - str);
+		xmlFree(ret);
+		return(ret2);
+	    }
+	    str++;
+	    expr = xmlStrndup(str, cur - str);
+	    if (expr == NULL)
+		return(ret);
+	    else {
+                val = xsltEvalXPathString(ctxt, expr);
+		xmlFree(expr);
+		if (val != NULL) {
+		    ret2 = xmlStrcat(ret, val);
+		    if (ret != NULL)
+			xmlFree(ret);
+		    xmlFree(val);
+		    ret = ret2;
+		}
+	    }
+	    cur++;
+	    str = cur;
+	} else
+	    cur++;
+    }
+    if (cur != str) {
+	ret2 = xmlStrncat(ret, str, cur - str);
+	if (ret != NULL)
+	    xmlFree(ret);
+	ret = ret2;
+    }
+
+    return(ret);
+}
+
+/**
+ * xsltAttrTemplateProcess:
+ * @ctxt:  the XSLT transformation context
+ * @target:  the result node
+ * @cur:  the attribute template node
+ *
+ * Process the given attribute and return the new processed copy.
+ *
+ * Returns the attribute replacement.
+ */
+xmlAttrPtr
+xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
+	                xmlAttrPtr cur) {
+    xmlAttrPtr ret;
+    if ((ctxt == NULL) || (cur == NULL))
+	return(NULL);
+    
+    if (cur->type != XML_ATTRIBUTE_NODE)
+	return(NULL);
+
+    if ((cur->ns != NULL) &&
+	(xmlStrEqual(cur->ns->href, XSLT_NAMESPACE))) {
+	/* TODO: check for replacement namespaces */
+	return(NULL);
+    }
+
+    ret = xmlNewDocProp(ctxt->output, cur->name, NULL);
+    if (ret == NULL) return(NULL);
+    ret->parent = target;
+    
+    if ((cur->ns != NULL) && (target != NULL)) {
+	if ((target != NULL) && (target->ns != NULL) &&
+	    (xmlStrEqual(target->ns->href, cur->ns->href))) {
+	    ret->ns = target->ns;
+	} else {
+	    xmlNsPtr ns;
+
+	    ns = xmlSearchNsByHref(ctxt->output, target, cur->ns->href);
+	    if (ns != NULL) {
+		ret->ns = ns;
+	    } else {
+		ns = xmlNewNs(target, cur->ns->href, cur->ns->prefix);
+		ret->ns = ns;
+	    }
+	}
+    } else
+        ret->ns = NULL;
+
+    if (cur->children != NULL) {
+	xmlChar *in = xmlNodeListGetString(ctxt->doc, cur->children, 1);
+	xmlChar *out;
+
+	if (in != NULL) {
+            out = xsltAttrTemplateValueProcess(ctxt, in);
+	    ret->children = xmlNewDocText(ctxt->output, out);
+	    xmlFree(out);
+	    xmlFree(in);
+	} else
+	    ret->children = NULL;
+       
+    } else 
+	ret->children = NULL;
+    return(ret);
+}
+
+
+/**
+ * xsltAttrListTemplateProcess:
+ * @ctxt:  the XSLT transformation context
+ * @target:  the element where the attributes will be grafted
+ * @cur:  the first attribute
+ *
+ * Do a copy of an attribute list with attribute template processing
+ *
+ * Returns: a new xmlAttrPtr, or NULL in case of error.
+ */
+xmlAttrPtr
+xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt, 
+	                    xmlNodePtr target, xmlAttrPtr cur) {
+    xmlAttrPtr ret = NULL;
+    xmlAttrPtr p = NULL,q;
+
+    while (cur != NULL) {
+        q = xsltAttrTemplateProcess(ctxt, target, cur);
+	if (p == NULL) {
+	    ret = p = q;
+	} else {
+	    p->next = q;
+	    q->prev = p;
+	    p = q;
+	}
+	cur = cur->next;
+    }
+    return(ret);
+}
+
+
+/**
+ * xsltTemplateProcess:
+ * @ctxt:  the XSLT transformation context
+ * @node:  the attribute template node
+ *
+ * Process the given node and return the new string value.
+ *
+ * Returns the computed tree replacement
+ */
+xmlNodePtr *
+xsltTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr node) {
+    if (node == NULL)
+	return(NULL);
+    
+    return(0);
+}
+
+
diff --git a/libxslt/templates.h b/libxslt/templates.h
new file mode 100644
index 0000000000000000000000000000000000000000..96ed246c7e7da2540cd70b1205c31e900fe7ce42_bGlieHNsdC90ZW1wbGF0ZXMuaA==
--- /dev/null
+++ b/libxslt/templates.h
@@ -0,0 +1,37 @@
+/*
+ * templates.h: interface for the template processing
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@imag.fr
+ */
+
+#ifndef __XML_XSLT_TEMPLATES_H__
+#define __XML_XSLT_TEMPLATES_H__
+
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+xmlChar *	xsltEvalXPathString		(xsltTransformContextPtr ctxt,
+						 const xmlChar *expr);
+xmlNodePtr *	xsltTemplateProcess		(xsltTransformContextPtr ctxt,
+						 xmlNodePtr node);
+xmlAttrPtr	xsltAttrListTemplateProcess	(xsltTransformContextPtr ctxt,
+						 xmlNodePtr target,
+						 xmlAttrPtr cur);
+xmlAttrPtr	xsltAttrTemplateProcess		(xsltTransformContextPtr ctxt,
+						 xmlNodePtr target,
+						 xmlAttrPtr attr);
+xmlChar *	xsltAttrTemplateValueProcess	(xsltTransformContextPtr ctxt,
+						 const xmlChar* attr);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_TEMPLATES_H__ */
+
diff --git a/libxslt/transform.c b/libxslt/transform.c
index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_bGlieHNsdC90cmFuc2Zvcm0uYw==..96ed246c7e7da2540cd70b1205c31e900fe7ce42_bGlieHNsdC90cmFuc2Zvcm0uYw== 100644
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -30,6 +30,7 @@
 #include "pattern.h"
 #include "transform.h"
 #include "variables.h"
+#include "templates.h"
 
 #define DEBUG_PROCESS
 
@@ -839,7 +840,8 @@
 	     * TODO: Do the substitution of {} XPath expressions !!!
 	     */
 	    if (cur->properties != NULL)
-		copy->properties = xmlCopyPropList(copy, cur->properties);
+		copy->properties = xsltAttrListTemplateProcess(ctxt,
+			                       copy, cur->properties);
 	}
 
 	/*
diff --git a/libxslt/variables.c b/libxslt/variables.c
index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_bGlieHNsdC92YXJpYWJsZXMuYw==..96ed246c7e7da2540cd70b1205c31e900fe7ce42_bGlieHNsdC92YXJpYWJsZXMuYw== 100644
--- a/libxslt/variables.c
+++ b/libxslt/variables.c
@@ -25,7 +25,7 @@
 #include "xsltutils.h"
 #include "variables.h"
 
-#define DEBUG_VARIABLES
+#define DEBUG_VARIABLE
 
 /*
  * Types are private:
@@ -293,6 +293,10 @@
     if (name == NULL)
 	return(-1);
 
+#ifdef DEBUG_VARIABLE
+    xsltGenericDebug(xsltGenericDebugContext,
+		     "Defineing variable %s\n", name);
+#endif
     elem = xsltNewStackElem();
     if (elem == NULL)
 	return(-1);
@@ -310,6 +314,7 @@
 						   ctxt->xpathCtxt);
 	if (xpathParserCtxt == NULL)
 	    goto error;
+	ctxt->xpathCtxt->node = ctxt->node;
 	xmlXPathEvalExpr(xpathParserCtxt);
 	result = valuePop(xpathParserCtxt);
 	do {
@@ -369,6 +374,5 @@
 #endif
 	    TODO /* Variable value computation needed */
     }
-error:
     if (elem->value != NULL)
 	return(xmlXPathObjectCopy(elem->value));
@@ -373,5 +377,9 @@
     if (elem->value != NULL)
 	return(xmlXPathObjectCopy(elem->value));
+#ifdef DEBUG_VARIABLE
+    xsltGenericDebug(xsltGenericDebugContext,
+		     "variable not found %s\n", name);
+#endif
     return(NULL);
 }
 
@@ -426,9 +434,8 @@
     }
 
 #ifdef DEBUG_VARIABLE
-    if (ret != NULL)
-	xsltGenericDebug(xsltGenericDebugContext,
-	    "Parsing variable %s\n", name);
+    xsltGenericDebug(xsltGenericDebugContext,
+	"Parsing variable %s\n", name);
 #endif
 
     select = xmlGetNsProp(cur, (const xmlChar *)"select", XSLT_NAMESPACE);
diff --git a/libxslt/xslt.c b/libxslt/xslt.c
index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_bGlieHNsdC94c2x0LmM=..96ed246c7e7da2540cd70b1205c31e900fe7ce42_bGlieHNsdC94c2x0LmM= 100644
--- a/libxslt/xslt.c
+++ b/libxslt/xslt.c
@@ -713,7 +713,7 @@
     if (top == NULL)
 	return;
 
-    prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
+    prop = xmlGetNsProp(top, (const xmlChar *)"version", XSLT_NAMESPACE);
     if (prop == NULL) {
 	xsltGenericError(xsltGenericErrorContext,
 	    "xsl:version is missing: document may not be a stylesheet\n");
diff --git a/tests/REC2/Makefile.am b/tests/REC2/Makefile.am
index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_dGVzdHMvUkVDMi9NYWtlZmlsZS5hbQ==..96ed246c7e7da2540cd70b1205c31e900fe7ce42_dGVzdHMvUkVDMi9NYWtlZmlsZS5hbQ== 100644
--- a/tests/REC2/Makefile.am
+++ b/tests/REC2/Makefile.am
@@ -8,6 +8,10 @@
 	@($(top_builddir)/libxslt/xsltproc vrml.xsl data.xml > vrml.res ; \
 	diff vrml.xml vrml.res ; \
 	grep "MORY ALLO" .memdump  | grep -v "MEMORY ALLOCATED : 0";\
-	rm -f doc.res)
+	rm -f vrml.res)
+	@($(top_builddir)/libxslt/xsltproc svg.xsl data.xml > svg.res ; \
+	diff svg.xml svg.res ; \
+	grep "MORY ALLO" .memdump  | grep -v "MEMORY ALLOCATED : 0";\
+	rm -f svg.res)
 
 
diff --git a/tests/REC2/svg.xml b/tests/REC2/svg.xml
index 9f140b4e08ad47b826b2ae3e76283d3f52bc80f6_dGVzdHMvUkVDMi9zdmcueG1s..96ed246c7e7da2540cd70b1205c31e900fe7ce42_dGVzdHMvUkVDMi9zdmcueG1s 100644
--- a/tests/REC2/svg.xml
+++ b/tests/REC2/svg.xml
@@ -1,18 +1,18 @@
-<svg width="3in" height="3in"
-     xmlns="http://www.w3.org/Graphics/SVG/svg-19990412.dtd">
-    <g style="stroke: #000000">
-        <line x1="0" x2="150" y1="150" y2="150"/>
-        <line x1="0" x2="0" y1="0" y2="150"/>
-        <text x="0" y="10">Revenue</text>
-        <text x="150" y="165">Division</text>
-        <rect x="10" y="50" width="20" height="100"/>
-        <text x="10" y="165">North</text>
-        <text x="10" y="45">10</text>
-        <rect x="50" y="110" width="20" height="40"/>
-        <text x="50" y="165">South</text>
-        <text x="50" y="105">4</text>
-        <rect x="90" y="90" width="20" height="60"/>
-        <text x="90" y="165">West</text>
-        <text x="90" y="85">6</text>
-    </g>
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/Graphics/SVG/SVG-19990812.dtd" width="3in" height="3in">
+  <g style="stroke: #000000">
+    <line x1="0" x2="150" y1="150" y2="150"/>
+    <line x1="0" x2="0" y1="0" y2="150"/>
+    <text x="0" y="10">Revenue</text>
+    <text x="150" y="165">Division</text>
+    <rect x="10" y="50" width="20" height="100"/>
+    <text x="10" y="165">North</text>
+    <text x="10" y="45">10</text>
+    <rect x="50" y="110" width="20" height="40"/>
+    <text x="50" y="165">South</text>
+    <text x="50" y="105">4</text>
+    <rect x="90" y="90" width="20" height="60"/>
+    <text x="90" y="165">West</text>
+    <text x="90" y="85">6</text>
+  </g>
 </svg>