# HG changeset patch
# User Daniel Veillard <veillard@src.gnome.org>
# Date 979140737 0
#      Wed Jan 10 15:32:17 2001 +0000
# Node ID 690dae4a04566e5c793162603e4540ea149c1dc6
# Parent  0ca1df07b15d53f718494b44e330c3e30e3f18e8
Still not working but makes more noise and leaks memory now:
- libxslt/xslt*: completeted the structures
- libxslt/pattern.[ch]: started adding code to precompile patterns
  and do the lookup
- libxslt/makefile.am: added the new files
Daniel

diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Wed Jan 10 16:29:41 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+	* libxslt/xslt*: completeted the structures
+	* libxslt/pattern.[ch]: started adding code to precompile patterns
+	  and do the lookup
+	* libxslt/makefile.am: added the new files
+
 Mon Jan  8 19:55:18 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
 	* libxslt/xslt.c : small cleanup
diff --git a/libxslt/Makefile.am b/libxslt/Makefile.am
--- a/libxslt/Makefile.am
+++ b/libxslt/Makefile.am
@@ -6,6 +6,8 @@
 libxslt_la_SOURCES = 			\
 	xslt.c				\
 	xslt.h				\
+	pattern.c			\
+	pattern.h			\
 	xsltInternals.h
 
 
diff --git a/libxslt/pattern.c b/libxslt/pattern.c
new file mode 100644
--- /dev/null
+++ b/libxslt/pattern.c
@@ -0,0 +1,408 @@
+/*
+ * 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@imag.fr
+ */
+
+#include "xsltconfig.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 "xslt.h"
+#include "xsltInternals.h"
+
+#define DEBUG_PARSING
+
+/*
+ * To cleanup
+ */
+xmlChar *xmlSplitQName2(const xmlChar *name, xmlChar **prefix);
+
+/*
+ * There is no XSLT specific error reporting module yet
+ */
+#define xsltGenericError xmlGenericError
+#define xsltGenericErrorContext xmlGenericErrorContext
+
+/*
+ * Types are private:
+ */
+
+typedef enum {
+    XSLT_OP_END=0,
+    XSLT_OP_ROOT,
+    XSLT_OP_ELEM,
+    XSLT_OP_CHILD,
+    XSLT_OP_ATTR,
+    XSLT_OP_PARENT,
+    XSLT_OP_ANCESTOR,
+    XSLT_OP_ID,
+    XSLT_OP_KEY,
+    XSLT_OP_NS,
+    XSLT_OP_ALL,
+    XSLT_OP_PREDICATE
+} xsltOp;
+
+typedef union _xsltStepOp xsltStepOp;
+typedef xsltStepOp *xsltStepOpPtr;
+union _xsltStepOp {
+    xsltOp op;
+    xmlChar *value;
+};
+
+typedef struct _xsltCompMatch xsltCompMatch;
+typedef xsltCompMatch *xsltCompMatchPtr;
+struct _xsltCompMatch {
+    struct _xsltCompMatch *next; /* siblings in the name hash */
+    int priority;                /* the priority */
+
+    /* TODO fix the statically allocated size */
+    int nbStep;
+    int maxStep;
+    xsltStepOp steps[20];        /* ops for computation */
+};
+
+
+/************************************************************************
+ * 									*
+ * 			Type functions 					*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xsltNewCompMatch:
+ *
+ * Create a new XSLT CompMatch
+ *
+ * Returns the newly allocated xsltCompMatchPtr or NULL in case of error
+ */
+xsltCompMatchPtr
+xsltNewCompMatch(void) {
+    xsltCompMatchPtr cur;
+
+    cur = (xsltCompMatchPtr) xmlMalloc(sizeof(xsltCompMatch));
+    if (cur == NULL) {
+        xsltGenericError(xsltGenericErrorContext,
+		"xsltNewCompMatch : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltCompMatch));
+    cur->maxStep = 20;
+    return(cur);
+}
+
+/**
+ * xsltFreeCompMatch:
+ * @comp:  an XSLT comp
+ *
+ * Free up the memory allocated by @comp
+ */
+void
+xsltFreeCompMatch(xsltCompMatchPtr comp) {
+    if (comp == NULL)
+	return;
+    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);
+    }
+}
+
+/**
+ * xsltCompMatchAddOp:
+ * @comp:  the compiled match expression
+ * @op:  an op
+ *
+ * Add an step to an XSLT Compiled Match
+ *
+ * Returns -1 in case of failure, 0 otherwise.
+ */
+int
+xsltCompMatchAddOp(xsltCompMatchPtr comp, xsltOp op) {
+    if (comp->nbStep >= 20) {
+        xsltGenericError(xsltGenericErrorContext,
+		"xsltCompMatchAddOp: overflow\n");
+        return(-1);
+    }
+    comp->steps[comp->nbStep++].op = op;
+    return(0);
+}
+
+/**
+ * xsltCompMatchAddValue:
+ * @comp:  the compiled match expression
+ * @val:  a name
+ *
+ * Add an step to an XSLT Compiled Match
+ *
+ * Returns -1 in case of failure, 0 otherwise.
+ */
+int
+xsltCompMatchAddValue(xsltCompMatchPtr comp, xmlChar *val) {
+    if (comp->nbStep >= 20) {
+        xsltGenericError(xsltGenericErrorContext,
+		"xsltCompMatchAddOp: overflow\n");
+        return(-1);
+    }
+    comp->steps[comp->nbStep++].value = val;
+    return(0);
+}
+
+/**
+ * xsltReverseCompMatch:
+ * @comp:  the compiled match expression
+ *
+ * reverse all the stack of expressions
+ */
+void
+xsltReverseCompMatch(xsltCompMatchPtr comp) {
+    int i = 0;
+    int j = comp->nbStep - 1;
+
+    while (j > i) {
+	register xmlChar *tmp;
+	tmp = comp->steps[i].value;
+	comp->steps[i].value = comp->steps[j].value;
+	comp->steps[j].value = tmp;
+	j--;
+	i++;
+    }
+    comp->steps[comp->nbStep].op = XSLT_OP_END;
+}
+
+/************************************************************************
+ *									*
+ *			Dedicated parser for templates			*
+ *									*
+ ************************************************************************/
+
+#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||	\
+                     ((c) == 0x0D))
+
+#define SKIP_BLANKS while (IS_BLANK(*cur)) cur++;
+
+#define CUR (*(cur))
+#define NXT (*(cur + 1))
+#define NEXT cur++
+
+#define PUSH(comp, step) 						\
+    if (xsltCompMatchAddOp((comp), (xsltOp) step)) goto error;
+
+#define PUSHSTR(comp, step)						\
+    if (xsltCompMatchAddValue((comp), (xmlChar *) step)) goto error;
+
+/*
+ * Compile the XSLT LocationPathPattern
+ * [2] LocationPathPattern ::= '/' RelativePathPattern?
+ *                           | IdKeyPattern (('/' | '//') RelativePathPattern)?
+ *                           | '//'? RelativePathPattern
+ * [3] IdKeyPattern ::= 'id' '(' Literal ')'
+ *                    | 'key' '(' Literal ',' Literal ')'
+ * [4] RelativePathPattern ::= StepPattern
+ *                           | RelativePathPattern '/' StepPattern
+ *                           | RelativePathPattern '//' StepPattern
+ * [5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate* 
+ * [6] ChildOrAttributeAxisSpecifier ::= AbbreviatedAxisSpecifier
+ *                                     | ('child' | 'attribute') '::'
+ */
+
+/**
+ * xsltCompilePattern:
+ * @pattern an XSLT pattern
+ *
+ * Compile the XSLT pattern and generates a precompiled form suitable
+ * for fast matching.
+ *
+ * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern
+ * Returns the generated xsltCompMatchPtr or NULL in case of failure
+ */
+
+xsltCompMatchPtr
+xsltCompilePattern(const xmlChar *pattern) {
+    xsltCompMatchPtr ret;
+    const xmlChar *cur;
+
+    if (pattern == NULL) {
+        xsltGenericError(xsltGenericErrorContext,
+		"xsltCompilePattern : NULL pattern\n");
+	return(NULL);
+    }
+
+#ifdef DEBUG_PARSING
+    xsltGenericError(xsltGenericErrorContext,
+	    "xsltCompilePattern : parsing '%s'\n", pattern);
+#endif
+
+    cur = pattern;
+    SKIP_BLANKS;
+    if (*cur == 0) {
+        xsltGenericError(xsltGenericErrorContext,
+		"xsltCompilePattern : NULL pattern\n");
+	return(NULL);
+    }
+    ret = xsltNewCompMatch();
+    if (ret == NULL)
+	return(NULL);
+
+    if ((CUR == '/') && (NXT == '/')) {
+    } else if (CUR == '/') {
+	PUSH(ret, XSLT_OP_ROOT);
+    }
+
+    /*
+     * Reverse for faster interpretation.
+     */
+    xsltReverseCompMatch(ret);
+
+    return(ret);
+
+error:
+    xsltFreeCompMatch(ret);
+    return(NULL);
+
+}
+
+
+/************************************************************************
+ *									*
+ *			Module interfaces				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltAddTemplate:
+ * @style: an XSLT stylesheet
+ * @cur: an XSLT template
+ *
+ * Register the XSLT pattern associated to @cur
+ *
+ * Returns -1 in case of error, 0 otherwise
+ */
+int
+xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur) {
+    xsltCompMatchPtr pat, list;
+    const xmlChar *name;
+
+    /*
+     * get a compiled form of the pattern
+     */
+    /* TODO : handle | in patterns as multple pat !!! */
+    pat = xsltCompilePattern(cur->match);
+    if (pat == NULL)
+	return(-1);
+    if (cur->priority != XSLT_PAT_NO_PRIORITY)
+	pat->priority = cur->priority;
+
+    /*
+     * insert it in the hash table list corresponding to its lookup name
+     */
+    switch (pat->steps[0].op) {
+        case XSLT_OP_ELEM:
+        case XSLT_OP_CHILD:
+        case XSLT_OP_ATTR:
+        case XSLT_OP_PARENT:
+        case XSLT_OP_ANCESTOR:
+        case XSLT_OP_ID:
+        case XSLT_OP_KEY:
+        case XSLT_OP_NS:
+             name = pat->steps[1].value;
+	     break;
+        case XSLT_OP_ROOT:
+             name = (const xmlChar *) "/";
+	     break;
+        case XSLT_OP_ALL:
+             name = (const xmlChar *) "*";
+	     break;
+        case XSLT_OP_END:
+	case XSLT_OP_PREDICATE:
+	    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);
+	}
+#ifdef DEBUG_PARSING
+	xsltGenericError(xsltGenericErrorContext,
+		"xsltAddTemplate: created template hash\n");
+#endif
+	xmlHashAddEntry(style->templatesHash, name, pat);
+#ifdef DEBUG_PARSING
+	xsltGenericError(xsltGenericErrorContext,
+		"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
+	    xsltGenericError(xsltGenericErrorContext,
+		    "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;
+		xmlHashAddEntry(style->templatesHash, name, pat);
+#ifdef DEBUG_PARSING
+		xsltGenericError(xsltGenericErrorContext,
+			"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;
+	    }
+	}
+    }
+    return(0);
+}
+
+/**
+ * xsltAddTemplate:
+ * @style: an XSLT stylesheet
+ * @node: an XML Node
+ *
+ * Finds the template applying to this node
+ *
+ * Returns the xsltTemplatePtr or NULL if not found
+ */
+xsltTemplatePtr
+xsltGetTemplate(xsltStylesheetPtr style, xmlNodePtr node) {
+    return(NULL);
+}
+
diff --git a/libxslt/pattern.h b/libxslt/pattern.h
new file mode 100644
--- /dev/null
+++ b/libxslt/pattern.h
@@ -0,0 +1,28 @@
+/*
+ * pattern.h: interface for the pattern matching used in template matches.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@imag.fr
+ */
+
+#ifndef __XML_XSLT_PATTERN_H__
+#define __XML_XSLT_H__
+
+#include "xsltInternals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int		xsltAddTemplate		(xsltStylesheetPtr style,
+					 xsltTemplatePtr cur);
+xsltTemplatePtr	xsltGetTemplate		(xsltStylesheetPtr style,
+					 xmlNodePtr node);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_H__ */
+
diff --git a/libxslt/xslt.c b/libxslt/xslt.c
--- a/libxslt/xslt.c
+++ b/libxslt/xslt.c
@@ -1,5 +1,5 @@
 /*
- * xslt.h: Implemetation of an XSL Transformation 1.0 engine
+ * xslt.c: Implemetation of an XSL Transformation 1.0 engine
  *
  * Reference:
  *   http://www.w3.org/TR/1999/REC-xslt-19991116
@@ -16,13 +16,21 @@
 #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 "xslt.h"
 #include "xsltInternals.h"
+#include "pattern.h"
 
 #define DEBUG_PARSING
 
 /*
+ * To cleanup
+ */
+xmlChar *xmlSplitQName2(const xmlChar *name, xmlChar **prefix);
+
+/*
  * There is no XSLT specific error reporting module yet
  */
 #define xsltGenericError xmlGenericError
@@ -33,7 +41,10 @@
  */
 
 #define IS_XSLT_ELEM(n)							\
-    ((n)->ns != NULL) && (xmlStrEqual(cur->ns->href, XSLT_NAMESPACE))
+    ((n)->ns != NULL) && (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE))
+
+#define IS_XSLT_NAME(n, val)						\
+    (xmlStrEqual((n)->name, (const xmlChar *) (val)))
 
 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||	\
                      ((c) == 0x0D))
@@ -98,6 +109,7 @@
 	return(NULL);
     }
     memset(cur, 0, sizeof(xsltTemplate));
+    cur->priority = XSLT_PAT_NO_PRIORITY;
     return(cur);
 }
 
@@ -150,6 +162,9 @@
 	return(NULL);
     }
     memset(cur, 0, sizeof(xsltStylesheet));
+    cur->omitXmlDeclaration = -1;
+    cur->standalone = -1;
+    cur->indent = -1;
     return(cur);
 }
 
@@ -166,6 +181,17 @@
     xsltFreeTemplateList(sheet->templates);
     if (sheet->doc != NULL)
 	xmlFreeDoc(sheet->doc);
+    if (sheet->stripSpaces != NULL)
+	xmlHashFree(sheet->stripSpaces, NULL);
+
+    if (sheet->method != NULL) xmlFree(sheet->method);
+    if (sheet->methodURI != NULL) xmlFree(sheet->methodURI);
+    if (sheet->version != NULL) xmlFree(sheet->version);
+    if (sheet->encoding != NULL) xmlFree(sheet->encoding);
+    if (sheet->doctypePublic != NULL) xmlFree(sheet->doctypePublic);
+    if (sheet->doctypeSystem != NULL) xmlFree(sheet->doctypeSystem);
+    if (sheet->mediaType != NULL) xmlFree(sheet->mediaType);
+
     memset(sheet, -1, sizeof(xsltStylesheet));
     xmlFree(sheet);
 }
@@ -177,32 +203,339 @@
  ************************************************************************/
 
 /**
+ * xsltParseStylesheetOutput:
+ * @style:  the XSLT stylesheet
+ * @template:  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", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (style->version != NULL) xmlFree(style->version);
+	style->version  = prop;
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *)"encoding", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (style->encoding != NULL) xmlFree(style->encoding);
+	style->encoding  = prop;
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *)"method", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	xmlChar *ncname;
+	xmlChar *prefix = NULL;
+
+	if (style->method != NULL) xmlFree(style->method);
+	style->method = NULL;
+	if (style->methodURI != NULL) xmlFree(style->methodURI);
+	style->methodURI = 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);
+		    style->method = prop;
+		} else {
+		    style->methodURI = xmlStrdup(ns->href);
+		    style->method = ncname;
+		    xmlFree(prefix);
+		    xmlFree(prop);
+		}
+	    } else {
+		style->method = ncname;
+		xmlFree(prop);
+	    }
+	} else {
+	    if ((xmlStrEqual(prop, (const xmlChar *)"xml")) ||
+		(xmlStrEqual(prop, (const xmlChar *)"html")) ||
+		(xmlStrEqual(prop, (const xmlChar *)"text"))) {
+		style->method  = prop;
+	    } else {
+		xsltGenericError(xsltGenericErrorContext,
+		    "invalid value for method: %s\n", prop);
+	    }
+	}
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *)"doctype-system", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (style->doctypeSystem != NULL) xmlFree(style->doctypeSystem);
+	style->doctypeSystem  = prop;
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *)"doctype-public", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (style->doctypePublic != NULL) xmlFree(style->doctypePublic);
+	style->doctypePublic  = prop;
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *)"standalone",
+	                XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
+	    style->standalone = 1;
+	} else if (xmlStrEqual(prop, (const xmlChar *)"no")) {
+	    style->standalone = 0;
+	} else {
+	    xsltGenericError(xsltGenericErrorContext,
+		"invalid value for standalone: %s\n", prop);
+	}
+	xmlFree(prop);
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *)"indent",
+	                XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
+	    style->indent = 1;
+	} else if (xmlStrEqual(prop, (const xmlChar *)"no")) {
+	    style->indent = 0;
+	} else {
+	    xsltGenericError(xsltGenericErrorContext,
+		"invalid value for indent: %s\n", prop);
+	}
+	xmlFree(prop);
+    }
+
+    prop = xmlGetNsProp(cur, (const xmlChar *)"omit-xml-declaration",
+	                XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
+	    style->omitXmlDeclaration = 1;
+	} else if (xmlStrEqual(prop, (const xmlChar *)"no")) {
+	    style->omitXmlDeclaration = 0;
+	} else {
+	    xsltGenericError(xsltGenericErrorContext,
+		"invalid value for omit-xml-declaration: %s\n", prop);
+	}
+	xmlFree(prop);
+    }
+
+    elements = xmlGetNsProp(cur, (const xmlChar *)"cdata-section-elements",
+	                    XSLT_NAMESPACE);
+    if (elements != NULL) {
+	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 DEBUG_PARSING
+		xsltGenericError(xsltGenericErrorContext,
+		    "add cdata section output element %s\n", element);
+#endif
+		xmlHashAddEntry(style->stripSpaces, element, "cdata");
+		xmlFree(element);
+	    }
+	    element = end;
+	}
+	xmlFree(elements);
+    }
+}
+
+/**
+ * xsltParseStylesheetPreserveSpace:
+ * @style:  the XSLT stylesheet
+ * @template:  the "preserve-space" element
+ *
+ * parse an XSLT stylesheet preserve-space element and record
+ * elements needing preserving
+ */
+
+void
+xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
+    xmlChar *elements;
+    xmlChar *element, *end;
+
+    if ((cur == NULL) || (style == NULL))
+	return;
+
+    elements = xmlGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
+    if (elements == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	    "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
+	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 DEBUG_PARSING
+	    xsltGenericError(xsltGenericErrorContext,
+		"add preserved space element %s\n", element);
+#endif
+	    xmlHashAddEntry(style->stripSpaces, element, "preserve");
+	    xmlFree(element);
+	}
+	element = end;
+    }
+    xmlFree(elements);
+}
+
+/**
+ * xsltParseStylesheetStripSpace:
+ * @style:  the XSLT stylesheet
+ * @template:  the "strip-space" element
+ *
+ * parse an XSLT stylesheet strip-space element and record
+ * elements needing stripping
+ */
+
+void
+xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
+    xmlChar *elements;
+    xmlChar *element, *end;
+
+    if ((cur == NULL) || (style == NULL))
+	return;
+
+    elements = xmlGetNsProp(cur, (const xmlChar *)"elements", XSLT_NAMESPACE);
+    if (elements == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	    "xsltParseStylesheetStripSpace: missing elements attribute\n");
+	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 DEBUG_PARSING
+	    xsltGenericError(xsltGenericErrorContext,
+		"add stripped space element %s\n", element);
+#endif
+	    xmlHashAddEntry(style->stripSpaces, element, "strip");
+	    xmlFree(element);
+	}
+	element = end;
+    }
+    xmlFree(elements);
+}
+
+/**
  * xsltParseStylesheetTemplate:
  * @style:  the XSLT stylesheet
  * @template:  the "template" element
  *
- * parse an XSLT stylesheet building the associated structures
+ * parse an XSLT stylesheet template building the associated structures
  */
 
 void
 xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
     xsltTemplatePtr ret;
     xmlNodePtr cur;
+    xmlChar *prop;
 
     if (template == NULL)
 	return;
 
+
+    /*
+     * Create and link the structure
+     */
     ret = xsltNewTemplate();
     if (ret == NULL)
 	return;
     ret->next = style->templates;
     style->templates = ret;
 
-    cur = template->children;
+    /*
+     * 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;
+	}
+    }
 
     /*
      * Find and handle the params
      */
+    cur = template->children;
     while (cur != NULL) {
 	/*
 	 * Remove Blank nodes found at this level.
@@ -215,7 +548,7 @@
 	    xmlFreeNode(blank);
 	    continue;
 	}
-	if ((IS_XSLT_ELEM(cur)) && (xmlStrEqual(cur->name, "param"))) {
+	if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
 	    TODO /* Handle param */
 	} else
 	    break;
@@ -237,7 +570,7 @@
 	    xmlFreeNode(blank);
 	    continue;
 	}
-	if ((IS_XSLT_ELEM(cur)) && (xmlStrEqual(cur->name, "param"))) {
+	if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
 	    xmlNodePtr param = cur;
 
             cur = cur->next;
@@ -252,6 +585,11 @@
     }
 
     ret->content = template->children;
+
+    /*
+     * Register pattern
+     */
+    xsltAddTemplate(style, ret);
 }
 
 /**
@@ -265,6 +603,9 @@
 void
 xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
     xmlNodePtr cur;
+#ifdef DEBUG_PARSING
+    int templates = 0;
+#endif
 
     if (top == NULL)
 	return;
@@ -284,7 +625,7 @@
             cur = cur->next;
 	    continue;
 	}
-	if (xmlStrEqual(cur->name, "import")) {
+	if (IS_XSLT_NAME(cur, "import")) {
 	    TODO /* Handle import */
 	} else
 	    break;
@@ -304,30 +645,33 @@
             cur = cur->next;
 	    continue;
 	}
-	if (xmlStrEqual(cur->name, "import")) {
+	if (IS_XSLT_NAME(cur, "import")) {
 	    xsltGenericError(xsltGenericErrorContext,
 		"xsltParseStylesheetTop: ignoring misplaced import element\n");
-        } else if (xmlStrEqual(cur->name, "include")) {
+        } else if (IS_XSLT_NAME(cur, "include")) {
 	    TODO /* Handle include */
-        } else if (xmlStrEqual(cur->name, "strip-space")) {
-	    TODO /* Handle strip-space */
-        } else if (xmlStrEqual(cur->name, "preserve-space")) {
-	    TODO /* Handle preserve-space */
-        } else if (xmlStrEqual(cur->name, "output")) {
-	    TODO /* Handle output */
-        } else if (xmlStrEqual(cur->name, "key")) {
+        } 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")) {
 	    TODO /* Handle key */
-        } else if (xmlStrEqual(cur->name, "decimal-format")) {
+        } else if (IS_XSLT_NAME(cur, "decimal-format")) {
 	    TODO /* Handle decimal-format */
-        } else if (xmlStrEqual(cur->name, "attribute-set")) {
+        } else if (IS_XSLT_NAME(cur, "attribute-set")) {
 	    TODO /* Handle attribute-set */
-        } else if (xmlStrEqual(cur->name, "variable")) {
+        } else if (IS_XSLT_NAME(cur, "variable")) {
 	    TODO /* Handle variable */
-        } else if (xmlStrEqual(cur->name, "param")) {
+        } else if (IS_XSLT_NAME(cur, "param")) {
 	    TODO /* Handle param */
-        } else if (xmlStrEqual(cur->name, "template")) {
+        } else if (IS_XSLT_NAME(cur, "template")) {
+#ifdef DEBUG_PARSING
+	    templates++;
+#endif
 	    xsltParseStylesheetTemplate(style, cur);
-        } else if (xmlStrEqual(cur->name, "namespace-alias")) {
+        } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
 	    TODO /* Handle namespace-alias */
 	} else {
 	    xsltGenericError(xsltGenericErrorContext,
@@ -336,6 +680,10 @@
 	}
 	cur = cur->next;
     }
+#ifdef DEBUG_PARSING
+    xsltGenericError(xsltGenericErrorContext,
+		    "parsed %d templates\n", templates);
+#endif
 }
 
 /**
@@ -371,7 +719,7 @@
 	return(NULL);
     }
 
-    if ((IS_XSLT_ELEM(cur)) && (xmlStrEqual(cur->name, "stylesheet"))) {
+    if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "stylesheet"))) {
 #ifdef DEBUG_PARSING
 	xsltGenericError(xsltGenericErrorContext,
 		"xsltParseStylesheetDoc : found stylesheet\n");
@@ -414,7 +762,7 @@
 	    "xsltParseStylesheetFile : parse %s\n", filename);
 #endif
 
-    doc = xmlParseFile(filename);
+    doc = xmlParseFile((const char *) filename);
     if (doc == NULL) {
         xsltGenericError(xsltGenericErrorContext,
 		"xsltParseStylesheetFile : cannot parse %s\n", filename);
diff --git a/libxslt/xslt.h b/libxslt/xslt.h
--- a/libxslt/xslt.h
+++ b/libxslt/xslt.h
@@ -19,7 +19,7 @@
  * Constants.
  */
 #define XSLT_DEFAULT_VERSION     "1.0"
-#define XSLT_NAMESPACE "http://www.w3.org/1999/XSL/Transform"
+#define XSLT_NAMESPACE ((xmlChar *) "http://www.w3.org/1999/XSL/Transform")
 
 #ifdef __cplusplus
 }
diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h
--- a/libxslt/xsltInternals.h
+++ b/libxslt/xsltInternals.h
@@ -23,6 +23,9 @@
  * NOTE: most of the content is simply linked from the doc tree
  *       structure, no specific allocation is made.
  */
+
+#define XSLT_PAT_NO_PRIORITY -12345789
+
 typedef struct _xsltTemplate xsltTemplate;
 typedef xsltTemplate *xsltTemplatePtr;
 struct _xsltTemplate {
@@ -43,7 +46,29 @@
 typedef xsltStylesheet *xsltStylesheetPtr;
 struct _xsltStylesheet {
     xmlDocPtr doc;		/* the parsed XML stylesheet */
+    xmlHashTablePtr stripSpaces;/* the hash table of the strip-space
+				   preserve space and cdata-section elements */
+
+    /*
+     * Template descriptions
+     */
     xsltTemplatePtr templates;	/* the ordered list of templates */
+    void *templatesHash;	/* hash table or wherever compiled templates
+				   informations are stored */
+
+    /*
+     * 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" */
+    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 */
 };