diff --git a/ChangeLog b/ChangeLog
index fd33194f2755e710db9dc80d50d39c5871bf336a_Q2hhbmdlTG9n..451d45f339fe55c818e71c669a5b5bbbc1361719_Q2hhbmdlTG9n 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+Wed Jan 24 16:59:05 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+	* libxslt/xsltInternals.h libxslt/pattern.c: fixed problems
+	  with non-named rules (*, ...) added accelerators
+	* libxslt/templates.[ch]: added xsltEvalTemplateString()
+	  and xsltEvalAttrValueTemplate() high level functions
+	* libxslt/transform.c: fixed the part where attributes
+	  had to be looked at as templates, added comment and
+	  PI generation
+	* TODO FEATURES: updated to reflect the new state
+
 Wed Jan 24 05:33:54 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
 	* libxslt/functions.[ch] Makefile.am: added new module functions
diff --git a/FEATURES b/FEATURES
index fd33194f2755e710db9dc80d50d39c5871bf336a_RkVBVFVSRVM=..451d45f339fe55c818e71c669a5b5bbbc1361719_RkVBVFVSRVM= 100644
--- a/FEATURES
+++ b/FEATURES
@@ -1,3 +1,7 @@
+       Status of implementation of the XSLT 1.0 Features:
+       ==================================================
+
+      $Id$
 
 Stylesheet Constructs:
 ======================
@@ -100,6 +104,6 @@
 YES		    xsl:text
 YES			disable-output-escaping = "yes" | "no"
 
-		    xsl:processing-instruction
-			name = { ncname }
+YES		    xsl:processing-instruction
+YES			name = { ncname }
 
@@ -105,5 +109,5 @@
 
-NO		    xsl:comment
+YES		    xsl:comment
 
 NO		    xsl:copy
 NO			use-attribute-sets = qnames
@@ -208,4 +212,3 @@
 NO		    boolean function-available(string)
 
 Daniel.Veillard@imag.fr
-$Id$
diff --git a/Makefile.am b/Makefile.am
index fd33194f2755e710db9dc80d50d39c5871bf336a_TWFrZWZpbGUuYW0=..451d45f339fe55c818e71c669a5b5bbbc1361719_TWFrZWZpbGUuYW0= 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,7 +25,9 @@
 	       < $(srcdir)/xsltConf.sh.in > xsltConf.tmp \
 	&& mv xsltConf.tmp xsltConf.sh
 
-test tests:
+dummy:
+
+test tests: dummy
 	@(cd tests ; make test)
 
 cleantar:
diff --git a/TODO b/TODO
index fd33194f2755e710db9dc80d50d39c5871bf336a_VE9ETw==..451d45f339fe55c818e71c669a5b5bbbc1361719_VE9ETw== 100644
--- a/TODO
+++ b/TODO
@@ -25,8 +25,6 @@
 
 Pattern tester:
   -> try to optimize for ID scan and tests.
-  -> also put fast lookup for "text()", "comment()", "node()"
-     based patterns lists.
 
 Pattern scanner:
   -> add error checks on all returns
@@ -75,3 +73,8 @@
 Pattern scanner:
   -> compute priority
   => done
+
+Pattern tester:
+  -> also put fast lookup for "text()", "comment()", "node()"
+     based patterns lists.
+  => done
diff --git a/libxslt/pattern.c b/libxslt/pattern.c
index fd33194f2755e710db9dc80d50d39c5871bf336a_bGlieHNsdC9wYXR0ZXJuLmM=..451d45f339fe55c818e71c669a5b5bbbc1361719_bGlieHNsdC9wYXR0ZXJuLmM= 100644
--- a/libxslt/pattern.c
+++ b/libxslt/pattern.c
@@ -732,7 +732,7 @@
 	token = xsltScanName(ctxt);
 	if (token == NULL) {
 	    xsltGenericError(xsltGenericErrorContext,
-		    "xsltCompilePattern : Name expected\n");
+		    "xsltCompileStepPattern : Name expected\n");
 	    ctxt->error = 1;
 	    goto error;
 	}
@@ -742,10 +742,16 @@
     if (token == NULL)
 	token = xsltScanName(ctxt);
     if (token == NULL) {
-	xsltGenericError(xsltGenericErrorContext,
-		"xsltCompilePattern : Name expected\n");
-        ctxt->error = 1;
-	goto error;
+	if (CUR == '*') {
+	    NEXT;
+	    PUSH(XSLT_OP_ALL, token, NULL);
+	    goto parse_predicate;
+	} else {
+	    xsltGenericError(xsltGenericErrorContext,
+		    "xsltCompileStepPattern : Name expected\n");
+	    ctxt->error = 1;
+	    goto error;
+	}
     }
     SKIP_BLANKS;
     if (CUR == '(') {
@@ -756,7 +762,7 @@
 	NEXT;
 	if (NXT(1) != ':') {
 	    xsltGenericError(xsltGenericErrorContext,
-		    "xsltCompilePattern : sequence '::' expected\n");
+		    "xsltCompileStepPattern : sequence '::' expected\n");
 	    ctxt->error = 1;
 	    goto error;
 	}
@@ -766,7 +772,7 @@
 	    name = xsltScanName(ctxt);
 	    if (name == NULL) {
 		xsltGenericError(xsltGenericErrorContext,
-			"xsltCompilePattern : QName expected\n");
+			"xsltCompileStepPattern : QName expected\n");
 		ctxt->error = 1;
 		goto error;
 	    }
@@ -776,10 +782,10 @@
 	    name = xsltScanName(ctxt);
 	    if (name == NULL) {
 		xsltGenericError(xsltGenericErrorContext,
-			"xsltCompilePattern : QName expected\n");
+			"xsltCompileStepPattern : QName expected\n");
 		ctxt->error = 1;
 		goto error;
 	    }
 	    PUSH(XSLT_OP_ATTR, name, NULL);
 	} else {
 	    xsltGenericError(xsltGenericErrorContext,
@@ -780,10 +786,10 @@
 		ctxt->error = 1;
 		goto error;
 	    }
 	    PUSH(XSLT_OP_ATTR, name, NULL);
 	} else {
 	    xsltGenericError(xsltGenericErrorContext,
-		    "xsltCompilePattern : 'child' or 'attribute' expected\n");
+		"xsltCompileStepPattern : 'child' or 'attribute' expected\n");
 	    ctxt->error = 1;
 	    goto error;
 	}
@@ -795,6 +801,7 @@
 	/* TODO: handle namespace */
 	PUSH(XSLT_OP_ELEM, token, NULL);
     }
+parse_predicate:
     SKIP_BLANKS;
     while (CUR == '[') {
 	const xmlChar *q;
@@ -807,7 +814,7 @@
 	    NEXT;
 	if (!IS_CHAR(CUR)) {
 	    xsltGenericError(xsltGenericErrorContext,
-		    "xsltCompilePattern : ']' expected\n");
+		    "xsltCompileStepPattern : ']' expected\n");
 	    ctxt->error = 1;
 	    goto error;
         }
@@ -899,6 +906,8 @@
 	    PUSH(XSLT_OP_PARENT, NULL, NULL);
 	    xsltCompileRelativePathPattern(ctxt, NULL);
 	}
+    } else if (CUR == '*') {
+	xsltCompileRelativePathPattern(ctxt, NULL);
     } else {
 	xmlChar *name;
 	name = xsltScanName(ctxt);
@@ -1044,7 +1053,7 @@
  */
 int
 xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur) {
-    xsltCompMatchPtr pat, list;
+    xsltCompMatchPtr pat, list, *top;
     const xmlChar *name = NULL;
     xmlChar *p, *pattern, tmp;
 
@@ -1083,5 +1092,11 @@
      * 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 = (xsltCompMatchPtr *) &(style->attrMatch);
+	    break;
         case XSLT_OP_ELEM:
         case XSLT_OP_CHILD:
@@ -1086,6 +1101,5 @@
         case XSLT_OP_ELEM:
         case XSLT_OP_CHILD:
-        case XSLT_OP_ATTR:
         case XSLT_OP_PARENT:
         case XSLT_OP_ANCESTOR:
         case XSLT_OP_ID:
@@ -1094,6 +1108,6 @@
              name = pat->steps[0].value;
 	     break;
         case XSLT_OP_ROOT:
-             name = (const xmlChar *) "/";
+             top = (xsltCompMatchPtr *) &(style->rootMatch);
 	     break;
         case XSLT_OP_ALL:
@@ -1098,6 +1112,6 @@
 	     break;
         case XSLT_OP_ALL:
-             name = (const xmlChar *) "*";
+             top = (xsltCompMatchPtr *) &(style->elemMatch);
 	     break;
         case XSLT_OP_END:
 	case XSLT_OP_PREDICATE:
@@ -1110,6 +1124,9 @@
 	 *       would be faster than inclusion in the hash table.
 	 */
 	case XSLT_OP_PI:
-	    name = (const xmlChar *) "processing-instruction()";
+	    if (pat->steps[0].value != NULL)
+		name = pat->steps[0].value;
+	    else
+		top = (xsltCompMatchPtr *) &(style->piMatch);
 	    break;
 	case XSLT_OP_COMMENT:
@@ -1114,5 +1131,5 @@
 	    break;
 	case XSLT_OP_COMMENT:
-	    name = (const xmlChar *) "comment()";
+	    top = (xsltCompMatchPtr *) &(style->commentMatch);
 	    break;
 	case XSLT_OP_TEXT:
@@ -1117,5 +1134,5 @@
 	    break;
 	case XSLT_OP_TEXT:
-	    name = (const xmlChar *) "text()";
+	    top = (xsltCompMatchPtr *) &(style->textMatch);
 	    break;
 	case XSLT_OP_NODE:
@@ -1120,5 +1137,9 @@
 	    break;
 	case XSLT_OP_NODE:
-	    name = (const xmlChar *) "node()";
+	    if (pat->steps[0].value != NULL)
+		name = pat->steps[0].value;
+	    else
+		top = (xsltCompMatchPtr *) &(style->elemMatch);
+	    
 	    break;
     }
@@ -1123,15 +1144,10 @@
 	    break;
     }
-    if (name == NULL) {
-	xsltGenericError(xsltGenericErrorContext,
-		"xsltAddTemplate: invalid compiled pattern\n");
-	xsltFreeCompMatch(pat);
-	return(-1);
-    }
-    if (style->templatesHash == NULL) {
-	style->templatesHash = xmlHashCreate(0);
-        if (style->templatesHash == NULL) {
-	    xsltFreeCompMatch(pat);
-	    return(-1);
-	}
+    if (name != NULL) {
+	if (style->templatesHash == NULL) {
+	    style->templatesHash = xmlHashCreate(0);
+	    if (style->templatesHash == NULL) {
+		xsltFreeCompMatch(pat);
+		return(-1);
+	    }
 #ifdef DEBUG_PARSING
@@ -1137,4 +1153,4 @@
 #ifdef DEBUG_PARSING
-	xsltGenericDebug(xsltGenericDebugContext,
-		"xsltAddTemplate: created template hash\n");
+	    xsltGenericDebug(xsltGenericDebugContext,
+		    "xsltAddTemplate: created template hash\n");
 #endif
@@ -1140,15 +1156,7 @@
 #endif
-	xmlHashAddEntry(style->templatesHash, name, pat);
-#ifdef DEBUG_PARSING
-	xsltGenericDebug(xsltGenericDebugContext,
-		"xsltAddTemplate: added new hash %s\n", name);
-#endif
-    } else {
-	list = (xsltCompMatchPtr) xmlHashLookup(style->templatesHash, name);
-	if (list == NULL) {
 	    xmlHashAddEntry(style->templatesHash, name, pat);
 #ifdef DEBUG_PARSING
 	    xsltGenericDebug(xsltGenericDebugContext,
 		    "xsltAddTemplate: added new hash %s\n", name);
 #endif
 	} else {
@@ -1149,15 +1157,11 @@
 	    xmlHashAddEntry(style->templatesHash, name, pat);
 #ifdef DEBUG_PARSING
 	    xsltGenericDebug(xsltGenericDebugContext,
 		    "xsltAddTemplate: added new hash %s\n", name);
 #endif
 	} 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;
-		xmlHashUpdateEntry(style->templatesHash, name, pat, NULL);
+	    list = (xsltCompMatchPtr) xmlHashLookup(style->templatesHash, name);
+	    if (list == NULL) {
+		xmlHashAddEntry(style->templatesHash, name, pat);
 #ifdef DEBUG_PARSING
 		xsltGenericDebug(xsltGenericDebugContext,
@@ -1162,5 +1166,5 @@
 #ifdef DEBUG_PARSING
 		xsltGenericDebug(xsltGenericDebugContext,
-			"xsltAddTemplate: added head hash for %s\n", name);
+			"xsltAddTemplate: added new hash %s\n", name);
 #endif
 	    } else {
@@ -1165,6 +1169,22 @@
 #endif
 	    } else {
-		while (list->next != NULL) {
-		    if (list->next->priority <= pat->priority)
-			break;
+		/*
+		 * 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;
+		    xmlHashUpdateEntry(style->templatesHash, name, pat, NULL);
+#ifdef DEBUG_PARSING
+		    xsltGenericDebug(xsltGenericDebugContext,
+			    "xsltAddTemplate: added head hash for %s\n", name);
+#endif
+		} else {
+		    while (list->next != NULL) {
+			if (list->next->priority <= pat->priority)
+			    break;
+		    }
+		    pat->next = list->next;
+		    list->next = pat;
 		}
@@ -1170,5 +1190,3 @@
 		}
-		pat->next = list->next;
-		list->next = pat;
 	    }
 	}
@@ -1173,5 +1191,26 @@
 	    }
 	}
+    } 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;
+	    }
+	    pat->next = list->next;
+	    list->next = pat;
+	}
+    } else {
+	xsltGenericError(xsltGenericErrorContext,
+		"xsltAddTemplate: invalid compiled pattern\n");
+	xsltFreeCompMatch(pat);
+	return(-1);
     }
     if (*p != 0)
 	goto next_pattern;
@@ -1189,10 +1228,11 @@
  */
 xsltTemplatePtr
 xsltGetTemplate(xsltStylesheetPtr style, xmlNodePtr node) {
-    const xmlChar *name;
-    xsltCompMatchPtr list;
+    xsltTemplatePtr ret = NULL;
+    const xmlChar *name = NULL;
+    xsltCompMatchPtr list = NULL;
 
     if ((style == NULL) || (node == NULL))
 	return(NULL);
 
     /* TODO : handle IDs/keys here ! */
@@ -1194,9 +1234,54 @@
 
     if ((style == NULL) || (node == NULL))
 	return(NULL);
 
     /* TODO : handle IDs/keys here ! */
-    if (style->templatesHash == NULL)
-	return(NULL);
+    if (style->templatesHash != NULL) {
+	/*
+	 * Use the top name as selector
+	 */
+	switch (node->type) {
+	    case XML_ELEMENT_NODE:
+	    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:
+		return(NULL);
+	    default:
+		return(NULL);
+
+	}
+    }
+    if (name != NULL) {
+	/*
+	 * find the list of appliable expressions based on the name
+	 */
+	list = (xsltCompMatchPtr) xmlHashLookup(style->templatesHash, name);
+    }
+    while (list != NULL) {
+	if (xsltTestCompMatch(list, node)) {
+	    ret = list->template;
+	    break;
+	}
+	list = list->next;
+    }
+    list = NULL;
 
     /*
@@ -1201,6 +1286,6 @@
 
     /*
-     * Use a name as selector
+     * find alternate generic matches
      */
     switch (node->type) {
         case XML_ELEMENT_NODE:
@@ -1204,4 +1289,6 @@
      */
     switch (node->type) {
         case XML_ELEMENT_NODE:
+	    list = style->elemMatch;
+	    break;
         case XML_ATTRIBUTE_NODE:
@@ -1207,2 +1294,4 @@
         case XML_ATTRIBUTE_NODE:
+	    list = style->attrMatch;
+	    break;
         case XML_PI_NODE:
@@ -1208,5 +1297,5 @@
         case XML_PI_NODE:
-	    name = node->name;
+	    list = style->piMatch;
 	    break;
         case XML_DOCUMENT_NODE:
         case XML_HTML_DOCUMENT_NODE:
@@ -1210,7 +1299,7 @@
 	    break;
         case XML_DOCUMENT_NODE:
         case XML_HTML_DOCUMENT_NODE:
-	    name = (const xmlChar *)"/";
+	    list = style->rootMatch;
 	    break;
         case XML_TEXT_NODE:
         case XML_CDATA_SECTION_NODE:
@@ -1214,5 +1303,10 @@
 	    break;
         case XML_TEXT_NODE:
         case XML_CDATA_SECTION_NODE:
+	    list = style->textMatch;
+	    break;
+        case XML_COMMENT_NODE:
+	    list = style->commentMatch;
+	    break;
         case XML_ENTITY_REF_NODE:
         case XML_ENTITY_NODE:
@@ -1217,6 +1311,5 @@
         case XML_ENTITY_REF_NODE:
         case XML_ENTITY_NODE:
-        case XML_COMMENT_NODE:
         case XML_DOCUMENT_TYPE_NODE:
         case XML_DOCUMENT_FRAG_NODE:
         case XML_NOTATION_NODE:
@@ -1227,5 +1320,5 @@
         case XML_NAMESPACE_DECL:
         case XML_XINCLUDE_START:
         case XML_XINCLUDE_END:
-	    return(NULL);
+	    break;
 	default:
@@ -1231,4 +1324,4 @@
 	default:
-	    return(NULL);
+	    break;
 
     }
@@ -1233,16 +1326,9 @@
 
     }
-    if (name == NULL)
-	return(NULL);
-
-    /*
-     * find the list of appliable expressions based on the name
-     */
-    list = (xsltCompMatchPtr) xmlHashLookup(style->templatesHash, name);
-    if (list == NULL) {
-#ifdef DEBUG_MATCHING
-	xsltGenericDebug(xsltGenericDebugContext,
-		"xsltGetTemplate: empty set for %s\n", name);
-#endif
-	return(NULL);
+    while ((list != NULL) &&
+	   ((ret == NULL)  || (list->priority > ret->priority))) {
+	if (xsltTestCompMatch(list, node)) {
+	    ret = list->template;
+	    break;
+	}
     }
@@ -1248,11 +1334,5 @@
     }
-    while (list != NULL) {
-	if (xsltTestCompMatch(list, node))
-	    return(list->template);
-	list = list->next;
-    }
-
-    return(NULL);
+    return(ret);
 }
 
 
@@ -1267,6 +1347,20 @@
     if (style->templatesHash != NULL)
 	xmlHashFree((xmlHashTablePtr) style->templatesHash,
 		    (xmlHashDeallocator) xsltFreeCompMatchList);
+    if (style->rootMatch != NULL)
+        xsltFreeCompMatchList(style->rootMatch);
+    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/templates.c b/libxslt/templates.c
index fd33194f2755e710db9dc80d50d39c5871bf336a_bGlieHNsdC90ZW1wbGF0ZXMuYw==..451d45f339fe55c818e71c669a5b5bbbc1361719_bGlieHNsdC90ZW1wbGF0ZXMuYw== 100644
--- a/libxslt/templates.c
+++ b/libxslt/templates.c
@@ -24,6 +24,7 @@
 #include "variables.h"
 #include "functions.h"
 #include "templates.h"
+#include "transform.h"
 
 #define DEBUG_TEMPLATES
 
@@ -89,6 +90,48 @@
 }
 
 /**
+ * xsltEvalTemplateString:
+ * @ctxt:  the XSLT transformation context
+ * @node:  the stylesheet node
+ * @parent:  the content parent
+ *
+ * Evaluate a template string value, i.e. the parent list is interpreter
+ * as template content and the resulting tree string value is returned
+ * This is needed for example by xsl:comment and xsl:processing-instruction
+ *
+ * Returns the computed string value or NULL, must be deallocated by the
+ *    caller.
+ */
+xmlChar *
+xsltEvalTemplateString(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	               xmlNodePtr parent) {
+    xmlChar *ret;
+    xmlNodePtr oldInsert, insert = NULL;
+
+    if ((ctxt == NULL) || (node == NULL) || (parent == NULL))
+	return(NULL);
+
+    if (parent->children == NULL)
+	return(NULL);
+
+    insert = xmlNewDocNode(ctxt->output, NULL,
+	                   (const xmlChar *)"fake", NULL);
+    if (insert == NULL)
+	return(NULL);
+    oldInsert = ctxt->insert;
+    ctxt->insert = insert;
+
+    xsltApplyOneTemplate(ctxt, node, parent->children);
+
+    ctxt->insert = oldInsert;
+
+    ret = xmlNodeGetContent(insert);
+    if (insert != NULL)
+	xmlFreeNode(insert);
+    return(ret);
+}
+
+/**
  * xsltAttrTemplateValueProcess:
  * @ctxt:  the XSLT transformation context
  * @str:  the attribute template node value
@@ -151,6 +194,47 @@
 }
 
 /**
+ * xsltEvalAttrValueTemplate:
+ * @ctxt:  the XSLT transformation context
+ * @node:  the stylesheet node
+ * @name:  the attribute QName
+ *
+ * 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 node,
+	                  const xmlChar *name) {
+    xmlChar *ret;
+    xmlChar *expr;
+
+    if ((ctxt == NULL) || (node == NULL) || (name == NULL))
+	return(NULL);
+
+    expr = xmlGetNsProp(node, name, XSLT_NAMESPACE);
+    if (expr == NULL)
+	return(NULL);
+
+    /*
+     * TODO: accelerator if there is no AttrValueTemplate in the stylesheet
+     *       return expr directly
+     */
+
+    ret = xsltAttrTemplateValueProcess(ctxt, expr);
+#ifdef DEBUG_TEMPLATES
+    xsltGenericDebug(xsltGenericDebugContext,
+	 "xsltEvalXPathString: %s returns %s\n", expr, ret);
+#endif
+    if (expr != NULL)
+	xmlFree(expr);
+    return(ret);
+}
+
+/**
  * xsltAttrTemplateProcess:
  * @ctxt:  the XSLT transformation context
  * @target:  the result node
@@ -202,6 +286,7 @@
 	xmlChar *in = xmlNodeListGetString(ctxt->doc, cur->children, 1);
 	xmlChar *out;
 
+	/* TODO: optimize if no template value was detected */
 	if (in != NULL) {
 	    xmlNodePtr child;
 
diff --git a/libxslt/templates.h b/libxslt/templates.h
index fd33194f2755e710db9dc80d50d39c5871bf336a_bGlieHNsdC90ZW1wbGF0ZXMuaA==..451d45f339fe55c818e71c669a5b5bbbc1361719_bGlieHNsdC90ZW1wbGF0ZXMuaA== 100644
--- a/libxslt/templates.h
+++ b/libxslt/templates.h
@@ -17,6 +17,12 @@
 extern "C" {
 #endif
 
+xmlChar *	xsltEvalTemplateString		(xsltTransformContextPtr ctxt,
+						 xmlNodePtr node,
+						 xmlNodePtr parent);
+xmlChar *	xsltEvalAttrValueTemplate	(xsltTransformContextPtr ctxt,
+						 xmlNodePtr node,
+						 const xmlChar *name);
 xmlChar *	xsltEvalXPathString		(xsltTransformContextPtr ctxt,
 						 const xmlChar *expr);
 xmlNodePtr *	xsltTemplateProcess		(xsltTransformContextPtr ctxt,
diff --git a/libxslt/transform.c b/libxslt/transform.c
index fd33194f2755e710db9dc80d50d39c5871bf336a_bGlieHNsdC90cmFuc2Zvcm0uYw==..451d45f339fe55c818e71c669a5b5bbbc1361719_bGlieHNsdC90cmFuc2Zvcm0uYw== 100644
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -129,7 +129,7 @@
     len = list->nodeNr;
 
     /* TODO: process attributes as attribute value templates */
-    prop = xmlGetNsProp(inst, (const xmlChar *)"data-type", XSLT_NAMESPACE);
+    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"data-type");
     if (prop != NULL) {
 	if (xmlStrEqual(prop, (const xmlChar *) "text"))
 	    number = 0;
@@ -142,7 +142,7 @@
 	}
 	xmlFree(prop);
     }
-    prop = xmlGetNsProp(inst, (const xmlChar *)"order", XSLT_NAMESPACE);
+    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"order");
     if (prop != NULL) {
 	if (xmlStrEqual(prop, (const xmlChar *) "ascending"))
 	    descending = 0;
@@ -160,9 +160,12 @@
 
     prop = xmlGetNsProp(inst, (const xmlChar *)"select", XSLT_NAMESPACE);
     if (prop == NULL) {
-	xsltGenericError(xsltGenericErrorContext,
-	     "xsltSort: select is not defined\n");
-	return;
+	prop = xmlNodeGetContent(inst);
+	if (prop == NULL) {
+	    xsltGenericError(xsltGenericErrorContext,
+		 "xsltSort: select is not defined\n");
+	    return;
+	}
     }
 
     xpathParserCtxt = xmlXPathNewParserContext(prop, ctxt->xpathCtxt);
@@ -233,6 +236,86 @@
 }
 
 /**
+ * xsltComment:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt comment node
+ *
+ * Process the xslt comment node on the source node
+ */
+void
+xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	           xmlNodePtr inst) {
+    xmlChar *value = NULL;
+    xmlNodePtr comment;
+
+    value = xsltEvalTemplateString(ctxt, node, inst);
+    /* TODO: check that there is no -- sequence and doesn't end up with - */
+#ifdef DEBUG_PROCESS
+    if (value == NULL)
+	xsltGenericDebug(xsltGenericDebugContext,
+	     "xsl:comment: empty\n");
+    else
+	xsltGenericDebug(xsltGenericDebugContext,
+	     "xsl:comment: content %s\n", value);
+#endif
+
+    comment = xmlNewComment(value);
+    xmlAddChild(ctxt->insert, comment);
+
+    if (value != NULL)
+	xmlFree(value);
+}
+
+/**
+ * xsltProcessingInstruction:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt processing-instruction node
+ *
+ * Process the xslt processing-instruction node on the source node
+ */
+void
+xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	           xmlNodePtr inst) {
+    xmlChar *ncname = NULL;
+    xmlChar *value = NULL;
+    xmlNodePtr pi;
+
+
+    if (ctxt->insert == NULL)
+	return;
+    ncname = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"name");
+    if (ncname == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	     "xslt:processing-instruction : name is missing\n");
+	goto error;
+    }
+    /* TODO: check that it's both an an NCName and a PITarget. */
+
+
+    value = xsltEvalTemplateString(ctxt, node, inst);
+    /* TODO: check that there is no ?> sequence */
+#ifdef DEBUG_PROCESS
+    if (value == NULL)
+	xsltGenericDebug(xsltGenericDebugContext,
+	     "xsl:processing-instruction: %s empty\n", ncname);
+    else
+	xsltGenericDebug(xsltGenericDebugContext,
+	     "xsl:processing-instruction: %s content %s\n", ncname, value);
+#endif
+
+    pi = xmlNewPI(ncname, value);
+    xmlAddChild(ctxt->insert, pi);
+
+error:
+    if (ncname != NULL)
+        xmlFree(ncname);
+    if (value != NULL)
+	xmlFree(value);
+}
+
+/**
  * xsltAttribute:
  * @ctxt:  a XSLT process context
  * @node:  the node in the source tree.
@@ -258,5 +341,5 @@
 	     "xslt:attribute : node has already children\n");
 	return;
     }
-    prop = xmlGetNsProp(inst, (const xmlChar *)"namespace", XSLT_NAMESPACE);
+    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"namespace");
     if (prop != NULL) {
@@ -262,6 +345,5 @@
     if (prop != NULL) {
-	/* TODO: attribute value template */
-	TODO
+	TODO /* xsl:attribute namespace */
 	xmlFree(prop);
 	return;
     }
@@ -265,7 +347,7 @@
 	xmlFree(prop);
 	return;
     }
-    prop = xmlGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE);
+    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"name");
     if (prop == NULL) {
 	xsltGenericError(xsltGenericErrorContext,
 	     "xslt:attribute : name is missing\n");
@@ -898,5 +980,6 @@
 		ctxt->insert = insert;
 		xsltAttribute(ctxt, node, cur);
 		ctxt->insert = oldInsert;
+		/*******
 	    } else if (IS_XSLT_NAME(cur, "element")) {
 		ctxt->insert = insert;
@@ -901,6 +984,15 @@
 	    } else if (IS_XSLT_NAME(cur, "element")) {
 		ctxt->insert = insert;
-		xsltAttribute(ctxt, node, cur);
+		xsltElement(ctxt, node, cur);
+		ctxt->insert = oldInsert;
+		*******/
+	    } else if (IS_XSLT_NAME(cur, "comment")) {
+		ctxt->insert = insert;
+		xsltComment(ctxt, node, cur);
+		ctxt->insert = oldInsert;
+	    } else if (IS_XSLT_NAME(cur, "processing-instruction")) {
+		ctxt->insert = insert;
+		xsltProcessingInstruction(ctxt, node, cur);
 		ctxt->insert = oldInsert;
 	    } else if (IS_XSLT_NAME(cur, "variable")) {
 		if (has_variables == 0) {
diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h
index fd33194f2755e710db9dc80d50d39c5871bf336a_bGlieHNsdC94c2x0SW50ZXJuYWxzLmg=..451d45f339fe55c818e71c669a5b5bbbc1361719_bGlieHNsdC94c2x0SW50ZXJuYWxzLmg= 100644
--- a/libxslt/xsltInternals.h
+++ b/libxslt/xsltInternals.h
@@ -93,6 +93,14 @@
     xsltTemplatePtr templates;	/* the ordered list of templates */
     void *templatesHash;	/* hash table or wherever compiled templates
 				   informations are stored */
+    void *rootMatch;		/* template based on / */
+    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() */
+    
     /*
      * Output related stuff.
      */