# HG changeset patch
# User Daniel Veillard <veillard@src.gnome.org>
# Date 979244006 0
#      Thu Jan 11 20:13:26 2001 +0000
# Node ID 599d0cf40b07f7d6590abbe215b8caf20fcc1538
# Parent  4d0df190b512a475570dd93d556c8d173beaa042
I generate a root node, I assume it's significant progress !
* libxslt/transform.[ch] Makefile.am: started adding the
  transformation module
* pattern.[ch] xslt.c: more work...
Daniel

diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Thu Jan 11 21:10:59 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+	* libxslt/transform.[ch] Makefile.am: started adding the
+	  transformation module
+	* pattern.[ch] xslt.c: more work...
+
 Thu Jan 11 14:02:03 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
 	* libxslt/pattern.c: started adding xsltTestCompMatch()
diff --git a/libxslt/Makefile.am b/libxslt/Makefile.am
--- a/libxslt/Makefile.am
+++ b/libxslt/Makefile.am
@@ -8,6 +8,8 @@
 	xslt.h				\
 	pattern.c			\
 	pattern.h			\
+	transform.c			\
+	transform.h			\
 	xsltInternals.h
 
 
diff --git a/libxslt/pattern.c b/libxslt/pattern.c
--- a/libxslt/pattern.c
+++ b/libxslt/pattern.c
@@ -73,6 +73,7 @@
 struct _xsltCompMatch {
     struct _xsltCompMatch *next; /* siblings in the name hash */
     int priority;                /* the priority */
+    xsltTemplatePtr template;    /* the associated template */
 
     /* TODO fix the statically allocated size */
     int nbStep;
@@ -125,8 +126,18 @@
  */
 void
 xsltFreeCompMatch(xsltCompMatchPtr comp) {
+    xsltStepOpPtr op;
+    int i;
+
     if (comp == NULL)
 	return;
+    for (i = 0;i < comp->nbStep;i++) {
+	op = &comp->steps[i];
+	if (op->value != NULL)
+	    xmlFree(op->value);
+	if (op->value2 != NULL)
+	    xmlFree(op->value2);
+    }
     memset(comp, -1, sizeof(xsltCompMatch));
     xmlFree(comp);
 }
@@ -680,6 +691,7 @@
     pat = xsltCompilePattern(cur->match);
     if (pat == NULL)
 	return(-1);
+    pat->template = cur;
     if (cur->priority != XSLT_PAT_NO_PRIORITY)
 	pat->priority = cur->priority;
 
@@ -746,14 +758,14 @@
 	     */
 	    if (list->priority <= pat->priority) {
 		pat->next = list;
-		xmlHashAddEntry(style->templatesHash, name, pat);
+		xmlHashUpdateEntry(style->templatesHash, name, pat, NULL);
 #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)
+		    if (list->next->priority <= pat->priority)
 			break;
 		}
 		pat->next = list->next;
@@ -775,6 +787,83 @@
  */
 xsltTemplatePtr
 xsltGetTemplate(xsltStylesheetPtr style, xmlNodePtr node) {
+    const xmlChar *name;
+    xsltCompMatchPtr list;
+
+    if ((style == NULL) || (node == NULL))
+	return(NULL);
+
+    /* TODO : handle IDs/keys here ! */
+    if (style->templatesHash == NULL)
+	return(NULL);
+
+    /*
+     * Use a 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:
+	    name = (const xmlChar *)"/";
+	    break;
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        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:
+        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)
+	return(NULL);
+
+    /*
+     * find the list of appliable expressions based on the name
+     */
+    list = (xsltCompMatchPtr) xmlHashLookup(style->templatesHash, name);
+    if (list == NULL) {
+#ifdef DEBUG_MATCHING
+	xsltGenericError(xsltGenericErrorContext,
+		"xsltGetTemplate: empty set for %s\n", name);
+#endif
+	return(NULL);
+    }
+    while (list != NULL) {
+	if (xsltTestCompMatch(list, node))
+	    return(list->template);
+	list = list->next;
+    }
+
     return(NULL);
 }
 
+
+/**
+ * xsltFreeTemplateHashes:
+ * @style: an XSLT stylesheet
+ *
+ * Free up the memory used by xsltAddTemplate/xsltGetTemplate mechanism
+ */
+void
+xsltFreeTemplateHashes(xsltStylesheetPtr style) {
+    if (style->templatesHash != NULL)
+	xmlHashFree((xmlHashTablePtr) style->templatesHash,
+		    (xmlHashDeallocator) xsltFreeCompMatchList);
+}
+
diff --git a/libxslt/pattern.h b/libxslt/pattern.h
--- a/libxslt/pattern.h
+++ b/libxslt/pattern.h
@@ -19,7 +19,7 @@
 					 xsltTemplatePtr cur);
 xsltTemplatePtr	xsltGetTemplate		(xsltStylesheetPtr style,
 					 xmlNodePtr node);
-
+void		xsltFreeTemplateHashes	(xsltStylesheetPtr style);
 #ifdef __cplusplus
 }
 #endif
diff --git a/libxslt/transform.c b/libxslt/transform.c
new file mode 100644
--- /dev/null
+++ b/libxslt/transform.c
@@ -0,0 +1,187 @@
+/*
+ * transform.c: Implemetation of the XSL Transformation 1.0 engine
+ *            transform part, i.e. applying a Stylesheet to a document
+ *
+ * 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/parser.h>
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+#include <libxml/hash.h>
+#include <libxml/xmlerror.h>
+#include <libxml/xpath.h>
+#include <libxml/HTMLtree.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "pattern.h"
+#include "transform.h"
+
+#define DEBUG_PROCESS
+
+/*
+ * To cleanup
+ */
+xmlChar *xmlSplitQName2(const xmlChar *name, xmlChar **prefix);
+
+/*
+ * There is no XSLT specific error reporting module yet
+ */
+#define xsltGenericError xmlGenericError
+#define xsltGenericErrorContext xmlGenericErrorContext
+
+/*
+ * Useful macros
+ */
+
+#define TODO 								\
+    xsltGenericError(xsltGenericErrorContext,				\
+	    "Unimplemented block at %s:%d\n",				\
+            __FILE__, __LINE__);
+
+#define STRANGE 							\
+    xsltGenericError(xsltGenericErrorContext,				\
+	    "Internal error at %s:%d\n",				\
+            __FILE__, __LINE__);
+
+/*
+ * Types are private:
+ */
+
+typedef enum xsltOutputType {
+    XSLT_OUTPUT_XML = 0,
+    XSLT_OUTPUT_HTML,
+    XSLT_OUTPUT_TEXT
+} xsltOutputType;
+
+typedef struct _xsltTransformContext xsltTransformContext;
+typedef xsltTransformContext *xsltTransformContextPtr;
+struct _xsltTransformContext {
+    xsltOutputType type;		/* the type of output */
+    xmlNodePtr node;			/* the current node */
+    xmlNodeSetPtr nodeList;		/* the current node list */
+
+    xmlNodePtr output;			/* output node */
+
+    xmlXPathContextPtr xpathCtxt;	/* the XPath context */
+};
+
+/************************************************************************
+ *									*
+ *			
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltNewTransformContext:
+ *
+ * Create a new XSLT TransformContext
+ *
+ * Returns the newly allocated xsltTransformContextPtr or NULL in case of error
+ */
+xsltTransformContextPtr
+xsltNewTransformContext(void) {
+    xsltTransformContextPtr cur;
+
+    cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext));
+    if (cur == NULL) {
+        xsltGenericError(xsltGenericErrorContext,
+		"xsltNewTransformContext : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xsltTransformContext));
+    return(cur);
+}
+
+/**
+ * xsltFreeTransformContext:
+ * @ctxt:  an XSLT parser context
+ *
+ * Free up the memory allocated by @ctxt
+ */
+void
+xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
+    if (ctxt == NULL)
+	return;
+    memset(ctxt, -1, sizeof(xsltTransformContext));
+    xmlFree(ctxt);
+}
+
+/************************************************************************
+ *									*
+ *			
+ *									*
+ ************************************************************************/
+
+/**
+ * xsltApplyStylesheet:
+ * @style:  a parsed XSLT stylesheet
+ * @doc:  a parsed XML document
+ *
+ * Apply the stylesheet to the document
+ * NOTE: This may lead to a non-wellformed output XML wise !
+ *
+ * Returns the result document or NULL in case of error
+ */
+xmlDocPtr
+xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc) {
+    xmlDocPtr res = NULL;
+    xsltTransformContextPtr ctxt = NULL;
+
+    if ((style == NULL) || (doc == NULL))
+	return(NULL);
+    ctxt = xsltNewTransformContext();
+    if (ctxt == NULL)
+	return(NULL);
+    if ((style->method != NULL) &&
+	(!xmlStrEqual(style->method, (const xmlChar *) "xml"))) {
+	if (xmlStrEqual(style->method, (const xmlChar *) "html")) {
+	    ctxt->type = XSLT_OUTPUT_HTML;
+	    res = htmlNewDoc(style->doctypePublic, style->doctypeSystem);
+	    if (res == NULL)
+		goto error;
+	} else if (xmlStrEqual(style->method, (const xmlChar *) "text")) {
+	    ctxt->type = XSLT_OUTPUT_TEXT;
+	    TODO
+	    goto error;
+	} else {
+	    xsltGenericError(xsltGenericErrorContext,
+			     "xsltApplyStylesheet: insupported method %s\n",
+		             style->method);
+	    goto error;
+	}
+    } else {
+	ctxt->type = XSLT_OUTPUT_XML;
+	res = xmlNewDoc(style->version);
+	if (res == NULL)
+	    goto error;
+    }
+    if (style->encoding != NULL)
+	doc->encoding = xmlStrdup(style->encoding);
+
+
+    /*
+	res->intSubset = xmlCreateIntSubset(
+     */
+
+    xsltFreeTransformContext(ctxt);
+    return(res);
+
+error:
+    if (res != NULL)
+        xmlFreeDoc(res);
+    if (ctxt != NULL)
+        xsltFreeTransformContext(ctxt);
+    return(NULL);
+}
+
diff --git a/libxslt/transform.h b/libxslt/transform.h
new file mode 100644
--- /dev/null
+++ b/libxslt/transform.h
@@ -0,0 +1,30 @@
+/*
+ * transform.h: Interfaces, constants and types related to the XSLT engine
+ *            transform part.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@imag.fr
+ */
+
+#ifndef __XML_XSLT_TRANSFORM_H__
+#define __XML_XSLT_TRANSFORM_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Interfaces
+ */
+xmlDocPtr	xsltApplyStylesheet	(xsltStylesheetPtr style,
+					 xmlDocPtr doc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_TRANSFORM_H__ */
+
diff --git a/libxslt/xslt.c b/libxslt/xslt.c
--- a/libxslt/xslt.c
+++ b/libxslt/xslt.c
@@ -123,6 +123,11 @@
 xsltFreeTemplate(xsltTemplatePtr template) {
     if (template == NULL)
 	return;
+    if (template->match) xmlFree(template->match);
+    if (template->name) xmlFree(template->name);
+    if (template->nameURI) xmlFree(template->nameURI);
+    if (template->mode) xmlFree(template->mode);
+    if (template->modeURI) xmlFree(template->modeURI);
     memset(template, -1, sizeof(xsltTemplate));
     xmlFree(template);
 }
@@ -178,6 +183,8 @@
 xsltFreeStylesheet(xsltStylesheetPtr sheet) {
     if (sheet == NULL)
 	return;
+
+    xsltFreeTemplateHashes(sheet);
     xsltFreeTemplateList(sheet->templates);
     if (sheet->doc != NULL)
 	xmlFreeDoc(sheet->doc);
diff --git a/libxslt/xsltproc.c b/libxslt/xsltproc.c
--- a/libxslt/xsltproc.c
+++ b/libxslt/xsltproc.c
@@ -7,9 +7,12 @@
  */
 
 #include <string.h>
+#include <libxml/xmlversion.h>
 #include <libxml/xmlmemory.h>
+#include <libxml/debugXML.h>
 #include <libxslt/xslt.h>
 #include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
 
 static int debug = 0;
 
@@ -17,6 +20,7 @@
 main(int argc, char **argv) {
     int i;
     xsltStylesheetPtr cur;
+    xmlDocPtr doc, res;
 
     LIBXML_TEST_VERSION
     for (i = 1; i < argc ; i++) {
@@ -26,11 +30,34 @@
     xmlSubstituteEntitiesDefault(1);
     for (i = 1; i < argc ; i++) {
 	if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
-	    cur = xsltParseStylesheetFile(argv[i]);
-	    xsltFreeStylesheet(cur);
+	    cur = xsltParseStylesheetFile((const xmlChar *)argv[i]);
+	    i++;
 	    break;
 	}
     }
+    for (;i < argc ; i++) {
+	doc = xmlParseFile(argv[i]);
+	if (doc == NULL) {
+	    fprintf(stderr, "unable to parse %s\n", argv[i]);
+	    continue;
+	}
+	res = xsltApplyStylesheet(cur, doc);
+	xmlFreeDoc(doc);
+	if (res == NULL) {
+	    fprintf(stderr, "no result for %s\n", argv[i]);
+	    continue;
+	}
+#ifdef LIBXML_DEBUG_ENABLED
+	if (debug)
+            xmlDebugDumpDocument(stdout, res);
+	else
+#endif
+	    xmlDocDump(stdout, res);
+
+	xmlFreeDoc(res);
+    }
+    if (cur != NULL)
+	xsltFreeStylesheet(cur);
     xmlCleanupParser();
     xmlMemoryDump();
     return(0);