diff --git a/ChangeLog b/ChangeLog
index a835fc05e776428b147b5643247d9a4843fcb0db_Q2hhbmdlTG9n..63a938aeca4e57c5a6467bde530ddbb0a35a9330_Q2hhbmdlTG9n 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Mon Jan 15 15:31:41 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+	* transform.c, xslt.c, xsltproc.c: lots of fixes, added
+	  support of xslt:if and xslt:attribute, need libxml2 interfaces
+	  present only in CVS.
+
 Sat Jan 13 23:26:21 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
 	* test/Makefile.am test/REC*/Makefile.am: added first test
diff --git a/libxslt/transform.c b/libxslt/transform.c
index a835fc05e776428b147b5643247d9a4843fcb0db_bGlieHNsdC90cmFuc2Zvcm0uYw==..63a938aeca4e57c5a6467bde530ddbb0a35a9330_bGlieHNsdC90cmFuc2Zvcm0uYw== 100644
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -29,7 +29,7 @@
 #include "pattern.h"
 #include "transform.h"
 
-/* #define DEBUG_PROCESS */
+#define DEBUG_PROCESS
 
 /*
  * To cleanup
@@ -143,6 +143,92 @@
 void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node);
 void xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr node,
 	         xmlNodePtr inst);
+void xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst);
+
+/**
+ * xsltAttribute:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt attribute node
+ *
+ * Process the xslt attribute node on the source node
+ */
+void
+xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	           xmlNodePtr inst) {
+    xmlChar *prop = NULL;
+    xmlChar *ncname = NULL;
+    xmlChar *prefix = NULL;
+    xmlChar *value = NULL;
+    xmlNsPtr ns = NULL;
+    xmlAttrPtr attr;
+
+
+    if (ctxt->insert == NULL)
+	return;
+    if (ctxt->insert->children != NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	     "xslt:attribute : node has already children\n");
+	return;
+    }
+    prop = xmlGetNsProp(inst, (const xmlChar *)"namespace", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	/* TODO: attribute value template */
+	TODO
+	xmlFree(prop);
+	return;
+    }
+    prop = xmlGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE);
+    if (prop == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	     "xslt:attribute : name is missing\n");
+	goto error;
+    }
+
+    ncname = xmlSplitQName2(prop, &prefix);
+    if (ncname == NULL) {
+	ncname = prop;
+	prop = NULL;
+	prefix = NULL;
+    }
+    if (xmlStrEqual(ncname, (const xmlChar *) "xmlns")) {
+	xsltGenericError(xsltGenericErrorContext,
+	     "xslt:attribute : xmlns forbidden\n");
+	goto error;
+    }
+    if ((prefix != NULL) && (ns == NULL)) {
+	ns = xmlSearchNs(ctxt->insert->doc, ctxt->insert, prefix);
+	if (ns == NULL) {
+	    xsltGenericError(xsltGenericErrorContext,
+		"no namespace bound to prefix %s\n", prefix);
+	}
+    }
+
+    value = xmlNodeListGetString(inst->doc, inst->children, 1);
+    if (value == NULL) {
+	if (ns)
+	    attr = xmlSetNsProp(ctxt->insert, ncname, ns->href,
+		                (const xmlChar *)"");
+	else
+	    attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)"");
+    } else {
+	/* TODO: attribute value template */
+	if (ns)
+	    attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, value);
+	else
+	    attr = xmlSetProp(ctxt->insert, ncname, value);
+    }
+
+error:
+    if (prop != NULL)
+        xmlFree(prop);
+    if (ncname != NULL)
+        xmlFree(ncname);
+    if (prefix != NULL)
+        xmlFree(prefix);
+    if (value != NULL)
+        xmlFree(value);
+}
 
 /**
  * xsltValueOf:
@@ -469,7 +555,11 @@
 		ctxt->insert = insert;
 		xsltValueOf(ctxt, node, cur);
 		ctxt->insert = oldInsert;
+	    } else if (IS_XSLT_NAME(cur, "if")) {
+		ctxt->insert = insert;
+		xsltIf(ctxt, node, cur);
+		ctxt->insert = oldInsert;
 	    } else if (IS_XSLT_NAME(cur, "for-each")) {
 		ctxt->insert = insert;
 		xsltForEach(ctxt, node, cur);
 		ctxt->insert = oldInsert;
@@ -472,7 +562,11 @@
 	    } else if (IS_XSLT_NAME(cur, "for-each")) {
 		ctxt->insert = insert;
 		xsltForEach(ctxt, node, cur);
 		ctxt->insert = oldInsert;
+	    } else if (IS_XSLT_NAME(cur, "attribute")) {
+		ctxt->insert = insert;
+		xsltAttribute(ctxt, node, cur);
+		ctxt->insert = oldInsert;
 	    } else {
 #ifdef DEBUG_PROCESS
 		xsltGenericError(xsltGenericErrorContext,
@@ -551,6 +645,86 @@
 }
 
 /**
+ * xsltIf:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt if node
+ *
+ * Process the xslt if node on the source node
+ */
+void
+xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	           xmlNodePtr inst) {
+    xmlChar *prop;
+    xmlXPathObjectPtr res, tmp;
+    xmlXPathParserContextPtr xpathParserCtxt;
+    int doit;
+
+    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
+	return;
+
+    prop = xmlGetNsProp(inst, (const xmlChar *)"test", XSLT_NAMESPACE);
+    if (prop == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	     "xsltIf: test is not defined\n");
+	return;
+    }
+#ifdef DEBUG_PROCESS
+    xsltGenericError(xsltGenericErrorContext,
+	 "xsltIf: test %s\n", prop);
+#endif
+
+    if (ctxt->xpathCtxt == NULL) {
+	xmlXPathInit();
+	ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
+	if (ctxt->xpathCtxt == NULL)
+	    goto error;
+    }
+    xpathParserCtxt = xmlXPathNewParserContext(prop, ctxt->xpathCtxt);
+    if (xpathParserCtxt == NULL)
+	goto error;
+    ctxt->xpathCtxt->node = node;
+    valuePush(xpathParserCtxt, xmlXPathNewNodeSet(node));
+    xmlXPathEvalExpr(xpathParserCtxt);
+    xmlXPathBooleanFunction(xpathParserCtxt, 1);
+    res = valuePop(xpathParserCtxt);
+    do {
+        tmp = valuePop(xpathParserCtxt);
+	if (tmp != NULL) {
+	    xmlXPathFreeObject(tmp);
+	}
+    } while (tmp != NULL);
+
+    if (res != NULL) {
+	if (res->type == XPATH_BOOLEAN)
+	    doit = res->boolval;
+	else {
+#ifdef DEBUG_PROCESS
+	    xsltGenericError(xsltGenericErrorContext,
+		"xsltIf: test didn't evaluate to a boolean\n");
+#endif
+	    goto error;
+	}
+    }
+
+#ifdef DEBUG_PROCESS
+    xsltGenericError(xsltGenericErrorContext,
+	"xsltIf: test evaluate to %d\n", doit);
+#endif
+    if (doit) {
+	xsltApplyOneTemplate(ctxt, ctxt->node, inst->children);
+    }
+
+error:
+    if (xpathParserCtxt != NULL)
+	xmlXPathFreeParserContext(xpathParserCtxt);
+    if (prop != NULL)
+	xmlFree(prop);
+    if (res != NULL)
+	xmlXPathFreeObject(res);
+}
+
+/**
  * xsltForEach:
  * @ctxt:  a XSLT process context
  * @node:  the node in the source tree.
@@ -702,8 +876,9 @@
 		goto error;
 	} else if (xmlStrEqual(style->method, (const xmlChar *) "text")) {
 	    ctxt->type = XSLT_OUTPUT_TEXT;
-	    TODO
-	    goto error;
+	    res = xmlNewDoc(style->version);
+	    if (res == NULL)
+		goto error;
 	} else {
 	    xsltGenericError(xsltGenericErrorContext,
 			     "xsltApplyStylesheet: insupported method %s\n",
diff --git a/libxslt/xslt.c b/libxslt/xslt.c
index a835fc05e776428b147b5643247d9a4843fcb0db_bGlieHNsdC94c2x0LmM=..63a938aeca4e57c5a6467bde530ddbb0a35a9330_bGlieHNsdC94c2x0LmM= 100644
--- a/libxslt/xslt.c
+++ b/libxslt/xslt.c
@@ -467,5 +467,5 @@
 }
 
 /**
- * xsltParseStylesheetTemplate:
+ * xsltParseTemplateContent:
  * @style:  the XSLT stylesheet
@@ -471,3 +471,4 @@
  * @style:  the XSLT stylesheet
- * @template:  the "template" element
+ * @ret:  the "template" structure
+ * @template:  the container node (can be a document for literal results)
  *
@@ -473,5 +474,7 @@
  *
- * parse an XSLT stylesheet template building the associated structures
+ * parse an XSLT template element content
+ * Clean-up the template content from unwanted ignorable blank nodes
+ * and process xslt:text
  */
 
 void
@@ -475,6 +478,6 @@
  */
 
 void
-xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
-    xsltTemplatePtr ret;
+xsltParseTemplateContent(xsltStylesheetPtr style, xsltTemplatePtr ret,
+	                 xmlNodePtr template) {
     xmlNodePtr cur, delete;
@@ -480,17 +483,2 @@
     xmlNodePtr cur, delete;
-    xmlChar *prop;
-
-    if (template == NULL)
-	return;
-
-
-    /*
-     * Create and link the structure
-     */
-    ret = xsltNewTemplate();
-    if (ret == NULL)
-	return;
-    ret->next = style->templates;
-    style->templates = ret;
-
     /*
@@ -496,51 +484,4 @@
     /*
-     * Get arguments
-     */
-    prop = xmlGetNsProp(template, (const xmlChar *)"match", XSLT_NAMESPACE);
-    if (prop != NULL) {
-	if (ret->match != NULL) xmlFree(ret->match);
-	ret->match  = prop;
-    }
-
-    prop = xmlGetNsProp(template, (const xmlChar *)"name", XSLT_NAMESPACE);
-    if (prop != NULL) {
-	xmlChar *ncname;
-	xmlChar *prefix = NULL;
-
-	if (ret->name != NULL) xmlFree(ret->name);
-	ret->name = NULL;
-	if (ret->nameURI != NULL) xmlFree(ret->nameURI);
-	ret->nameURI = NULL;
-
-	ncname = xmlSplitQName2(prop, &prefix);
-	if (ncname != NULL) {
-	    if (prefix != NULL) {
-		xmlNsPtr ns;
-
-		ns = xmlSearchNs(cur->doc, cur, prefix);
-		if (ns == NULL) {
-		    xsltGenericError(xsltGenericErrorContext,
-			"no namespace bound to prefix %s\n", prefix);
-		    xmlFree(prefix);
-		    xmlFree(ncname);
-		    ret->name = prop;
-		} else {
-		    ret->nameURI = xmlStrdup(ns->href);
-		    ret->name = ncname;
-		    xmlFree(prefix);
-		    xmlFree(prop);
-		}
-	    } else {
-		ret->name = ncname;
-		xmlFree(prop);
-	    }
-	} else {
-	    ret->name  = prop;
-	}
-    }
-
-    /*
-     * Clean-up the template content from unwanted ignorable blank nodes
      * This content comes from the stylesheet
      * For stylesheets, the set of whitespace-preserving
      * element names consists of just xsl:text.
@@ -558,5 +499,17 @@
 	    delete = NULL;
 	}
 	if (IS_XSLT_ELEM(cur)) {
-	    if (IS_XSLT_NAME(cur, "text"))
+	    if (IS_XSLT_NAME(cur, "text")) {
+		if (cur->children != NULL) {
+		    if ((cur->children->type != XML_TEXT_NODE) ||
+			(cur->children->next != NULL)) {
+			xsltGenericError(xsltGenericErrorContext,
+	     "xsltParseStylesheetTemplate: xslt:text content problem\n");
+		    } else {
+			xmlNodePtr text = cur->children;
+			xmlUnlinkNode(text);
+			xmlAddPrevSibling(cur, text);
+		    }
+		}
+		delete = cur;
 		goto skip_children;
@@ -562,4 +515,5 @@
 		goto skip_children;
+	    }
 	} else if (cur->type == XML_TEXT_NODE) {
 	    if (IS_BLANK_NODE(cur)) {
 		delete = cur;
@@ -597,6 +551,15 @@
 	    }
 	} while (cur != NULL);
     }
+    if (delete != NULL) {
+#ifdef DEBUG_PARSING
+	xsltGenericError(xsltGenericErrorContext,
+	 "xsltParseStylesheetTemplate: removing ignorable blank node\n");
+#endif
+	xmlUnlinkNode(delete);
+	xmlFreeNode(delete);
+	delete = NULL;
+    }
 
     /*
      * Find and handle the params
@@ -651,5 +614,31 @@
     }
 
     ret->content = template->children;
+}
+
+/**
+ * xsltParseStylesheetTemplate:
+ * @style:  the XSLT stylesheet
+ * @template:  the "template" element
+ *
+ * parse an XSLT stylesheet template building the associated structures
+ */
+
+void
+xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
+    xsltTemplatePtr ret;
+    xmlChar *prop;
+
+    if (template == NULL)
+	return;
+
+    /*
+     * Create and link the structure
+     */
+    ret = xsltNewTemplate();
+    if (ret == NULL)
+	return;
+    ret->next = style->templates;
+    style->templates = ret;
 
     /*
@@ -654,4 +643,4 @@
 
     /*
-     * Register pattern
+     * Get arguments
      */
@@ -657,4 +646,51 @@
      */
+    prop = xmlGetNsProp(template, (const xmlChar *)"match", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (ret->match != NULL) xmlFree(ret->match);
+	ret->match  = prop;
+    }
+
+    prop = xmlGetNsProp(template, (const xmlChar *)"name", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	xmlChar *ncname;
+	xmlChar *prefix = NULL;
+
+	if (ret->name != NULL) xmlFree(ret->name);
+	ret->name = NULL;
+	if (ret->nameURI != NULL) xmlFree(ret->nameURI);
+	ret->nameURI = NULL;
+
+	ncname = xmlSplitQName2(prop, &prefix);
+	if (ncname != NULL) {
+	    if (prefix != NULL) {
+		xmlNsPtr ns;
+
+		ns = xmlSearchNs(template->doc, template, prefix);
+		if (ns == NULL) {
+		    xsltGenericError(xsltGenericErrorContext,
+			"no namespace bound to prefix %s\n", prefix);
+		    xmlFree(prefix);
+		    xmlFree(ncname);
+		    ret->name = prop;
+		} else {
+		    ret->nameURI = xmlStrdup(ns->href);
+		    ret->name = ncname;
+		    xmlFree(prefix);
+		    xmlFree(prop);
+		}
+	    } else {
+		ret->name = ncname;
+		xmlFree(prop);
+	    }
+	} else {
+	    ret->name  = prop;
+	}
+    }
+
+    /*
+     * parse the content and register the pattern
+     */
+    xsltParseTemplateContent(style, ret, template);
     xsltAddTemplate(style, ret);
 }
 
@@ -794,4 +830,7 @@
 
 	xsltParseStylesheetTop(ret, cur);
     } else {
+	xmlChar *prop;
+	xsltTemplatePtr template;
+
 	/*
@@ -797,3 +836,3 @@
 	/*
-	 * the document itself is the template.
+	 * the document itself might be the template, check xsl:version
 	 */
@@ -799,5 +838,13 @@
 	 */
+	prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
+	if (prop == NULL) {
+	    xsltGenericError(xsltGenericErrorContext,
+		"xsltParseStylesheetDoc : document is not a stylesheet\n");
+	    xsltFreeStylesheet(ret);
+	    return(NULL);
+	}
+
 #ifdef DEBUG_PARSING
         xsltGenericError(xsltGenericErrorContext,
 		"xsltParseStylesheetDoc : document is stylesheet\n");
 #endif
@@ -800,8 +847,28 @@
 #ifdef DEBUG_PARSING
         xsltGenericError(xsltGenericErrorContext,
 		"xsltParseStylesheetDoc : document is stylesheet\n");
 #endif
-	TODO
+	
+	/* TODO: check the version */
+	xmlFree(prop);
+
+	/*
+	 * Create and link the template
+	 */
+	template = xsltNewTemplate();
+	if (template == NULL) {
+	    xsltFreeStylesheet(ret);
+	    return(NULL);
+	}
+	template->next = ret->templates;
+	ret->templates = template;
+	template->match = xmlStrdup((const xmlChar *)"/");
+
+	/*
+	 * parse the content and register the pattern
+	 */
+	xsltParseTemplateContent(ret, template, (xmlNodePtr) doc);
+	xsltAddTemplate(ret, template);
     }
 
     return(ret);
diff --git a/libxslt/xsltproc.c b/libxslt/xsltproc.c
index a835fc05e776428b147b5643247d9a4843fcb0db_bGlieHNsdC94c2x0cHJvYy5j..63a938aeca4e57c5a6467bde530ddbb0a35a9330_bGlieHNsdC94c2x0cHJvYy5j 100644
--- a/libxslt/xsltproc.c
+++ b/libxslt/xsltproc.c
@@ -32,7 +32,7 @@
 	if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
 	    cur = xsltParseStylesheetFile((const xmlChar *)argv[i]);
 	    if (cur != NULL) {
-		if (cur->indent)
+		if (cur->indent == 1)
 		    xmlIndentTreeOutput = 1;
 		else
 		    xmlIndentTreeOutput = 0;