diff --git a/ChangeLog b/ChangeLog
index b6b38863dca56f285313a794a699305c15c97c87_Q2hhbmdlTG9n..edf652d35df17788cb48390bab49e1c62044b2dd_Q2hhbmdlTG9n 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Tue Jan 16 17:17:17 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+	* TODO: started filling it :-(
+	* libxslt/pattern.c: should now at least compile the full
+	  set of patterns authorized. Default priorities added.
+	* libxslt/transform.c: a bit more work and cleanup.
+
 Mon Jan 15 15:34:17 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
 	* TODO: started adding in there :-(
diff --git a/TODO b/TODO
index b6b38863dca56f285313a794a699305c15c97c87_VE9ETw==..edf652d35df17788cb48390bab49e1c62044b2dd_VE9ETw== 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,25 @@
+Design:
+  - should transforms for a given stylesheet be thread clean,
+    or can a stylesheet be enriched with document specific
+    informations and cleaned up later ?
+    
+Import:
+  -> parse them
+  -> provide functions to circulate in the import tree of stylesheets
+
+Pattern tester:
+  -> try to optimize for ID scan and tests.
+
+Pattern scanner:
+  -> add error checks on all returns
+  -> handle unions
+  -> compute priority
+
+Separate util module:
+  -> macros, config, verbosity ?
+
 Support for disable-output-escaping="yes":
   -> looks problematic, libxml has no support for anything like this,
      and unless adding a new node type :-( or tweaking text node and
      output routines this is gonna be messy ... must be handled at libxml
      level.
@@ -1,5 +21,10 @@
 Support for disable-output-escaping="yes":
   -> looks problematic, libxml has no support for anything like this,
      and unless adding a new node type :-( or tweaking text node and
      output routines this is gonna be messy ... must be handled at libxml
      level.
+
+Error handling:
+  -> check the version stuff, design a separate module for error interfacing
+     and default handling, parsing vs. runtime, fatal / compat / warning,
+     and lack of optionnal features.
diff --git a/libxslt/pattern.c b/libxslt/pattern.c
index b6b38863dca56f285313a794a699305c15c97c87_bGlieHNsdC9wYXR0ZXJuLmM=..edf652d35df17788cb48390bab49e1c62044b2dd_bGlieHNsdC9wYXR0ZXJuLmM= 100644
--- a/libxslt/pattern.c
+++ b/libxslt/pattern.c
@@ -56,6 +56,10 @@
     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;
 
@@ -72,6 +76,6 @@
 typedef xsltCompMatch *xsltCompMatchPtr;
 struct _xsltCompMatch {
     struct _xsltCompMatch *next; /* siblings in the name hash */
-    int priority;                /* the priority */
+    float priority;                /* the priority */
     xsltTemplatePtr template;    /* the associated template */
 
@@ -76,6 +80,6 @@
     xsltTemplatePtr template;    /* the associated template */
 
-    /* TODO fix the statically allocated size */
+    /* TODO fix the statically allocated size steps[] */
     int nbStep;
     int maxStep;
     xsltStepOp steps[20];        /* ops for computation */
@@ -294,7 +298,7 @@
 		/* TODO: Handle namespace ... */
 		continue;
             case XSLT_OP_CHILD:
-		TODO /* Hummm !!! */
+		TODO /* Handle OP_CHILD */
 		return(0);
             case XSLT_OP_ATTR:
 		if (node->type != XML_ATTRIBUTE_NODE)
@@ -351,6 +355,6 @@
 		TODO /* Handle Namespace */
 		break;
             case XSLT_OP_ALL:
-		TODO /* Handle Namespace */
+		TODO /* Handle * */
 		break;
 	    case XSLT_OP_PREDICATE:
@@ -355,6 +359,18 @@
 		break;
 	    case XSLT_OP_PREDICATE:
-		TODO /* Handle Namespace */
+		TODO /* Handle Predicate */
+		break;
+            case XSLT_OP_PI:
+		TODO /* Handle PI() */
+		break;
+            case XSLT_OP_COMMENT:
+		TODO /* Handle Comments() */
+		break;
+            case XSLT_OP_TEXT:
+		TODO /* Handle Text() */
+		break;
+            case XSLT_OP_NODE:
+		TODO /* Handle Node() */
 		break;
 	}
     }
@@ -382,6 +398,66 @@
 #define PUSH(op, val, val2) 						\
     if (xsltCompMatchAdd(ctxt->comp, (op), (val), (val2))) goto error;
 
+#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
+ */
+
+xmlChar *
+xsltScanLiteral(xsltParserContextPtr ctxt) {
+    const xmlChar *q;
+    xmlChar *ret = NULL;
+
+    SKIP_BLANKS;
+    if (CUR == '"') {
+        NEXT;
+	q = CUR_PTR;
+	while ((IS_CHAR(CUR)) && (CUR != '"'))
+	    NEXT;
+	if (!IS_CHAR(CUR)) {
+	    /* XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); */
+	    ctxt->error = 1;
+	    return(NULL);
+	} else {
+	    ret = xmlStrndup(q, CUR_PTR - q);
+	    NEXT;
+        }
+    } else if (CUR == '\'') {
+        NEXT;
+	q = CUR_PTR;
+	while ((IS_CHAR(CUR)) && (CUR != '\''))
+	    NEXT;
+	if (!IS_CHAR(CUR)) {
+	    /* XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); */
+	    ctxt->error = 1;
+	    return(NULL);
+	} else {
+	    ret = xmlStrndup(q, CUR_PTR - q);
+	    NEXT;
+        }
+    } else {
+	/* XP_ERROR(XPATH_START_LITERAL_ERROR); */
+	ctxt->error = 1;
+	return(NULL);
+    }
+    return(ret);
+}
+
 /**
  * xsltScanName:
  * @ctxt:  the XPath Parser context
@@ -433,6 +509,11 @@
     return(xmlStrndup(buf, len));
 }
 /*
- * Compile the XSLT LocationPathPattern
+ * xsltCompileIdKeyPattern:
+ * @comp:  the compilation context
+ * @name:  a preparsed name
+ * @aid:  whether id/key are allowed there
+ *
+ * Compile the XSLT LocationIdKeyPattern
  * [3] IdKeyPattern ::= 'id' '(' Literal ')'
  *                    | 'key' '(' Literal ',' Literal ')'
@@ -437,3 +518,9 @@
  * [3] IdKeyPattern ::= 'id' '(' Literal ')'
  *                    | 'key' '(' Literal ',' Literal ')'
+ *
+ * also handle NodeType and PI from:
+ *
+ * [7]  NodeTest ::= NameTest
+ *                 | NodeType '(' ')'
+ *                 | 'processing-instruction' '(' Literal ')'
  */
@@ -439,4 +526,124 @@
  */
+void
+xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name, int aid) {
+    xmlChar *lit = NULL;
+    xmlChar *lit2 = NULL;
+
+    if (CUR != '(') {
+	xsltGenericError(xsltGenericErrorContext,
+		"xsltCompileIdKeyPattern : ( expected\n");
+	ctxt->error = 1;
+	return;
+    }
+    if ((aid) && (xmlStrEqual(name, (const xmlChar *)"id"))) {
+	NEXT;
+	SKIP_BLANKS;
+        lit = xsltScanLiteral(ctxt);
+	if (ctxt->error)
+	    return;
+	SKIP_BLANKS;
+	if (CUR != ')') {
+	    xsltGenericError(xsltGenericErrorContext,
+		    "xsltCompileIdKeyPattern : ) expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	PUSH(XSLT_OP_ID, lit, NULL);
+    } else if ((aid) && (xmlStrEqual(name, (const xmlChar *)"key"))) {
+	NEXT;
+	SKIP_BLANKS;
+        lit = xsltScanLiteral(ctxt);
+	if (ctxt->error)
+	    return;
+	SKIP_BLANKS;
+	if (CUR != ',') {
+	    xsltGenericError(xsltGenericErrorContext,
+		    "xsltCompileIdKeyPattern : , expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	SKIP_BLANKS;
+        lit2 = xsltScanLiteral(ctxt);
+	if (ctxt->error)
+	    return;
+	SKIP_BLANKS;
+	if (CUR != ')') {
+	    xsltGenericError(xsltGenericErrorContext,
+		    "xsltCompileIdKeyPattern : ) expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	PUSH(XSLT_OP_KEY, lit, NULL);
+    } else if (xmlStrEqual(name, (const xmlChar *)"processing-instruction")) {
+	NEXT;
+	SKIP_BLANKS;
+	if (CUR != ')') {
+	    lit = xsltScanLiteral(ctxt);
+	    if (ctxt->error)
+		return;
+	    SKIP_BLANKS;
+	    if (CUR != ')') {
+		xsltGenericError(xsltGenericErrorContext,
+			"xsltCompileIdKeyPattern : ) expected\n");
+		ctxt->error = 1;
+		return;
+	    }
+	}
+	NEXT;
+	PUSH(XSLT_OP_PI, lit, NULL);
+    } else if (xmlStrEqual(name, (const xmlChar *)"text")) {
+	NEXT;
+	SKIP_BLANKS;
+	if (CUR != ')') {
+	    xsltGenericError(xsltGenericErrorContext,
+		    "xsltCompileIdKeyPattern : ) expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	PUSH(XSLT_OP_TEXT, NULL, NULL);
+    } else if (xmlStrEqual(name, (const xmlChar *)"comment")) {
+	NEXT;
+	SKIP_BLANKS;
+	if (CUR != ')') {
+	    xsltGenericError(xsltGenericErrorContext,
+		    "xsltCompileIdKeyPattern : ) expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	PUSH(XSLT_OP_COMMENT, NULL, NULL);
+    } else if (xmlStrEqual(name, (const xmlChar *)"comment")) {
+	NEXT;
+	SKIP_BLANKS;
+	if (CUR != ')') {
+	    xsltGenericError(xsltGenericErrorContext,
+		    "xsltCompileIdKeyPattern : ) expected\n");
+	    ctxt->error = 1;
+	    return;
+	}
+	NEXT;
+	PUSH(XSLT_OP_NODE, NULL, NULL);
+    } else if (aid) {
+	xsltGenericError(xsltGenericErrorContext,
+	    "xsltCompileIdKeyPattern : expecting 'key' or 'id' or node type\n");
+	ctxt->error = 1;
+	return;
+    } else {
+	xsltGenericError(xsltGenericErrorContext,
+	    "xsltCompileIdKeyPattern : node type\n");
+	ctxt->error = 1;
+	return;
+    }
+error:
+    if (lit != NULL)
+	xmlFree(lit);
+    if (lit2 != NULL)
+	xmlFree(lit2);
+}
 
 /**
  * xsltCompileStepPattern:
@@ -461,6 +668,8 @@
 
 void
 xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token) {
+    xmlChar *name = NULL;
+
     SKIP_BLANKS;
     if ((token == NULL) && (CUR == '@')) {
 	token = xsltScanName(ctxt);
@@ -468,5 +677,5 @@
 	    xsltGenericError(xsltGenericErrorContext,
 		    "xsltCompilePattern : Name expected\n");
 	    ctxt->error = 1;
-	    return;
+	    goto error;
 	}
@@ -472,4 +681,6 @@
 	}
+	PUSH(XSLT_OP_ATTR, token, NULL);
+	return;
     }
     if (token == NULL)
 	token = xsltScanName(ctxt);
@@ -477,7 +688,7 @@
 	xsltGenericError(xsltGenericErrorContext,
 		"xsltCompilePattern : Name expected\n");
         ctxt->error = 1;
-	return;
+	goto error;
     }
     SKIP_BLANKS;
     if (CUR == '(') {
@@ -481,6 +692,7 @@
     }
     SKIP_BLANKS;
     if (CUR == '(') {
-	TODO;
-	/* if (xmlStrEqual(token, "processing-instruction")) */
+	xsltCompileIdKeyPattern(ctxt, token, 0);
+	if (ctxt->error)
+	    goto error;
     } else if (CUR == ':') {
@@ -486,3 +698,37 @@
     } else if (CUR == ':') {
-	TODO;
+	NEXT;
+	if (NXT(1) != ':') {
+	    xsltGenericError(xsltGenericErrorContext,
+		    "xsltCompilePattern : sequence '::' expected\n");
+	    ctxt->error = 1;
+	    goto error;
+	}
+	NEXT;
+	if (xmlStrEqual(token, (const xmlChar *) "child")) {
+	    /* TODO: handle namespace */
+	    name = xsltScanName(ctxt);
+	    if (name == NULL) {
+		xsltGenericError(xsltGenericErrorContext,
+			"xsltCompilePattern : QName expected\n");
+		ctxt->error = 1;
+		goto error;
+	    }
+	    PUSH(XSLT_OP_CHILD, name, NULL);
+	} else if (xmlStrEqual(token, (const xmlChar *) "attribute")) {
+	    /* TODO: handle namespace */
+	    name = xsltScanName(ctxt);
+	    if (name == NULL) {
+		xsltGenericError(xsltGenericErrorContext,
+			"xsltCompilePattern : QName expected\n");
+		ctxt->error = 1;
+		goto error;
+	    }
+	    PUSH(XSLT_OP_ATTR, name, NULL);
+	} else {
+	    xsltGenericError(xsltGenericErrorContext,
+		    "xsltCompilePattern : 'child' or 'attribute' expected\n");
+	    ctxt->error = 1;
+	    goto error;
+	}
+	xmlFree(token);
     } else if (CUR == '*') {
@@ -488,3 +734,4 @@
     } else if (CUR == '*') {
-	TODO;
+	NEXT;
+	PUSH(XSLT_OP_ALL, token, NULL);
     } else {
@@ -490,5 +737,6 @@
     } else {
+	/* TODO: handle namespace */
 	PUSH(XSLT_OP_ELEM, token, NULL);
     }
     SKIP_BLANKS;
     while (CUR == '[') {
@@ -491,8 +739,24 @@
 	PUSH(XSLT_OP_ELEM, token, NULL);
     }
     SKIP_BLANKS;
     while (CUR == '[') {
-	TODO;
+	const xmlChar *q;
+	xmlChar *ret = NULL;
+
+	NEXT;
+	q = CUR_PTR;
+	/* TODO: avoid breaking in strings ... */
+	while ((IS_CHAR(CUR)) && (CUR != ']'))
+	    NEXT;
+	if (!IS_CHAR(CUR)) {
+	    xsltGenericError(xsltGenericErrorContext,
+		    "xsltCompilePattern : ']' expected\n");
+	    ctxt->error = 1;
+	    goto error;
+        }
+	NEXT;
+	ret = xmlStrndup(q, CUR_PTR - q);
+	PUSH(XSLT_OP_PREDICATE, ret, NULL);
     }
     return;
 error:
@@ -496,7 +760,10 @@
     }
     return;
 error:
-    ctxt->error = 1;
+    if (token != NULL)
+	xmlFree(token);
+    if (name != NULL)
+	xmlFree(name);
 }
 
 /**
@@ -586,7 +853,20 @@
 	}
 	SKIP_BLANKS;
 	if (CUR == '(') {
-	    TODO
+	    xsltCompileIdKeyPattern(ctxt, name, 1);
+	    if ((CUR == '/') && (NXT(1) == '/')) {
+		PUSH(XSLT_OP_ANCESTOR, NULL, NULL);
+		NEXT;
+		NEXT;
+		SKIP_BLANKS;
+		xsltCompileRelativePathPattern(ctxt, NULL);
+	    } else if (CUR == '/') {
+		PUSH(XSLT_OP_PARENT, NULL, NULL);
+		NEXT;
+		SKIP_BLANKS;
+		xsltCompileRelativePathPattern(ctxt, NULL);
+	    }
+	    return;
 	}
 	xsltCompileRelativePathPattern(ctxt, name);
     }
@@ -653,6 +933,32 @@
      */
     xsltReverseCompMatch(ret);
 
+    /*
+     * Set-up the priority
+     */
+    if (((ret->steps[0].op == XSLT_OP_ELEM) ||
+	 (ret->steps[0].op == XSLT_OP_ATTR)) &&
+	(ret->steps[0].value != NULL) &&
+	(ret->steps[1].op == XSLT_OP_END)) {
+	ret->priority = 0;
+    } else if ((ret->steps[0].op == XSLT_OP_PI) &&
+	       (ret->steps[0].value != NULL) &&
+	       (ret->steps[1].op == XSLT_OP_END)) {
+	ret->priority = 0;
+    } else if ((ret->steps[0].op == XSLT_OP_NS) &&
+	       (ret->steps[0].value != NULL) &&
+	       (ret->steps[1].op == XSLT_OP_END)) {
+	ret->priority = -0.25;
+    } else if (((ret->steps[0].op == XSLT_OP_PI) ||
+		(ret->steps[0].op == XSLT_OP_TEXT) ||
+		(ret->steps[0].op == XSLT_OP_NODE) ||
+	        (ret->steps[0].op == XSLT_OP_COMMENT)) &&
+	       (ret->steps[1].op == XSLT_OP_END)) {
+	ret->priority = -0.5;
+    } else {
+	ret->priority = 0.5;
+    }
+
     xsltFreeParserContext(ctxt);
     return(ret);
 
@@ -721,6 +1027,22 @@
 		    "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:
+	    name = (const xmlChar *) "processing-instruction()";
+	    break;
+	case XSLT_OP_COMMENT:
+	    name = (const xmlChar *) "comment()";
+	    break;
+	case XSLT_OP_TEXT:
+	    name = (const xmlChar *) "text()";
+	    break;
+	case XSLT_OP_NODE:
+	    name = (const xmlChar *) "node()";
+	    break;
     }
     if (name == NULL) {
 	xsltGenericError(xsltGenericErrorContext,
diff --git a/libxslt/transform.c b/libxslt/transform.c
index b6b38863dca56f285313a794a699305c15c97c87_bGlieHNsdC90cmFuc2Zvcm0uYw==..edf652d35df17788cb48390bab49e1c62044b2dd_bGlieHNsdC90cmFuc2Zvcm0uYw== 100644
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -35,6 +35,7 @@
  * To cleanup
  */
 xmlChar *xmlSplitQName2(const xmlChar *name, xmlChar **prefix);
+void xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs);
 
 /*
  * There is no XSLT specific error reporting module yet
@@ -206,6 +207,7 @@
 
     value = xmlNodeListGetString(inst->doc, inst->children, 1);
     if (value == NULL) {
-	if (ns)
+	if (ns) {
+#if LIBXML_VERSION > 202111
 	    attr = xmlSetNsProp(ctxt->insert, ncname, ns->href,
 		                (const xmlChar *)"");
@@ -210,6 +212,11 @@
 	    attr = xmlSetNsProp(ctxt->insert, ncname, ns->href,
 		                (const xmlChar *)"");
-	else
+#else
+	    xsltGenericError(xsltGenericErrorContext,
+		"xsl:attribute: recompile against newer libxml version\n");
+	    attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)"");
+#endif
+	} else
 	    attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)"");
     } else {
 	/* TODO: attribute value template */
@@ -213,5 +220,6 @@
 	    attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)"");
     } else {
 	/* TODO: attribute value template */
-	if (ns)
+	if (ns) {
+#if LIBXML_VERSION > 202111
 	    attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, value);
@@ -217,5 +225,10 @@
 	    attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, value);
-	else
+#else
+	    xsltGenericError(xsltGenericErrorContext,
+		"xsl:attribute: recompile against newer libxml version\n");
+	    attr = xmlSetProp(ctxt->insert, ncname, value);
+#endif
+	} else
 	    attr = xmlSetProp(ctxt->insert, ncname, value);
     }