# HG changeset patch
# User Daniel Veillard <veillard@src.gnome.org>
# Date 979303509 0
#      Fri Jan 12 12:45:09 2001 +0000
# Node ID 98ddb4e13c1e61b09c4b43cf9cd6c24c49ae2ff7
# Parent  599d0cf40b07f7d6590abbe215b8caf20fcc1538
This start being interesting...
- transform.c: basic processing in place
- xsltInternals.h: exported one xslt.c function
Daniel

diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Fri Jan 12 13:43:30 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+	* transform.c: basic processing in place
+	* xsltInternals.h: exported one xslt.c function
+
 Thu Jan 11 21:10:59 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
 	* libxslt/transform.[ch] Makefile.am: started adding the
diff --git a/libxslt/transform.c b/libxslt/transform.c
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -19,6 +19,7 @@
 #include <libxml/tree.h>
 #include <libxml/valid.h>
 #include <libxml/hash.h>
+#include <libxml/encoding.h>
 #include <libxml/xmlerror.h>
 #include <libxml/xpath.h>
 #include <libxml/HTMLtree.h>
@@ -54,6 +55,15 @@
 	    "Internal error at %s:%d\n",				\
             __FILE__, __LINE__);
 
+#define IS_XSLT_ELEM(n)							\
+    ((n)->ns != NULL) && (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE))
+
+#define IS_XSLT_NAME(n, val)						\
+    (xmlStrEqual((n)->name, (const xmlChar *) (val)))
+
+#define IS_BLANK_NODE(n)						\
+    (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
+
 /*
  * Types are private:
  */
@@ -67,11 +77,14 @@
 typedef struct _xsltTransformContext xsltTransformContext;
 typedef xsltTransformContext *xsltTransformContextPtr;
 struct _xsltTransformContext {
+    xsltStylesheetPtr style;		/* the stylesheet used */
     xsltOutputType type;		/* the type of output */
+
     xmlNodePtr node;			/* the current node */
     xmlNodeSetPtr nodeList;		/* the current node list */
 
-    xmlNodePtr output;			/* output node */
+    xmlDocPtr output;			/* the resulting document */
+    xmlNodePtr insert;			/* the insertion node */
 
     xmlXPathContextPtr xpathCtxt;	/* the XPath context */
 };
@@ -123,6 +136,177 @@
  *									*
  ************************************************************************/
 
+void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node);
+
+/**
+ * xsltDefaultProcessOneNode:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ *
+ * Process the source node with the default built-in template rule:
+ * <xsl:template match="*|/">
+ *   <xsl:apply-templates/>
+ * </xsl:template>
+ */
+void
+xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
+    xmlNodePtr copy;
+    switch (node->type) {
+	case XML_DOCUMENT_NODE:
+	case XML_HTML_DOCUMENT_NODE:
+	case XML_ELEMENT_NODE:
+	    break;
+	default:
+	    return;
+    }
+    node = node->children;
+    while (node != NULL) {
+	switch (node->type) {
+	    case XML_DOCUMENT_NODE:
+	    case XML_HTML_DOCUMENT_NODE:
+	    case XML_ELEMENT_NODE:
+		xsltProcessOneNode(ctxt, node);
+		break;
+	    case XML_TEXT_NODE:
+		/* TODO: check the whitespace stripping rules ! */
+		if (IS_BLANK_NODE(node))
+		    break;
+	    case XML_CDATA_SECTION_NODE:
+		copy = xmlCopyNode(node, 0);
+		if (copy != NULL) {
+		    xmlAddChild(ctxt->insert, copy);
+		} else {
+		    xsltGenericError(xsltGenericErrorContext,
+			"xsltProcessOneNode: text copy failed\n");
+		}
+		break;
+	    default:
+		TODO
+	}
+	node = node->next;
+    }
+}
+
+/**
+ * xsltApplyTemplates:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the apply-templates node
+ *
+ * Process the apply-templates node on the source node
+ */
+void
+xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	           xmlNodePtr inst) {
+    xmlChar *prop;
+
+    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
+	return;
+
+#ifdef DEBUG_PROCESS
+    xsltGenericError(xsltGenericErrorContext,
+	 "xsltApplyTemplates: node: %s\n", node->name);
+#endif
+    prop = xmlGetNsProp(inst, (const xmlChar *)"select", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	TODO
+    } else {
+	xsltDefaultProcessOneNode(ctxt, node);
+    }
+}
+
+/**
+ * xsltProcessOneNode:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ *
+ * Process the source node.
+ */
+void
+xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
+    xsltTemplatePtr template;
+    xmlNodePtr cur, insert, copy;
+    xmlNodePtr oldInsert;
+
+    oldInsert = insert = ctxt->insert;
+    template = xsltGetTemplate(ctxt->style, node);
+    /*
+     * If no template is found, apply the deafult rule.
+     */
+    if (template == NULL) {
+#ifdef DEBUG_PROCESS
+	xsltGenericError(xsltGenericErrorContext,
+	     "xsltProcessOneNode: no template found for %s\n", node->name);
+#endif
+
+	xsltDefaultProcessOneNode(ctxt, node);
+	return;
+    }
+
+    /*
+     * Insert all non-XSLT nodes found in the template
+     */
+    cur = template->content;
+    while (cur != NULL) {
+	if (IS_XSLT_ELEM(cur)) {
+	    if (IS_XSLT_NAME(cur, "apply-templates")) {
+		ctxt->insert = insert;
+		xsltApplyTemplates(ctxt, node, cur);
+		ctxt->insert = oldInsert;
+	    } else {
+#ifdef DEBUG_PROCESS
+		xsltGenericError(xsltGenericErrorContext,
+		     "xsltProcessOneNode: found xslt:%s\n", cur->name);
+#endif
+		TODO
+	    }
+	} else if (!(IS_BLANK_NODE(cur))) {
+#ifdef DEBUG_PROCESS
+	    xsltGenericError(xsltGenericErrorContext,
+		 "xsltProcessOneNode: copy %s\n", cur->name);
+#endif
+	    copy = xmlCopyNode(cur, 0);
+	    if (copy != NULL) {
+		xmlAddChild(insert, copy);
+	    } else {
+		xsltGenericError(xsltGenericErrorContext,
+			"xsltProcessOneNode: copy %s failed\n", cur->name);
+		return;
+	    }
+	}
+	/*
+	 * Skip to next node
+	 */
+
+	if (cur->children != NULL) {
+	    if (cur->children->type != XML_ENTITY_DECL) {
+		cur = cur->children;
+		insert = copy;
+		continue;
+	    }
+	}
+	if (cur->next != NULL) {
+	    cur = cur->next;
+	    continue;
+	}
+	
+	do {
+	    cur = cur->parent;
+	    insert = insert->parent;
+	    if (cur == NULL)
+		break;
+	    if (cur == template->content) {
+		cur = NULL;
+		break;
+	    }
+	    if (cur->next != NULL) {
+		cur = cur->next;
+		break;
+	    }
+	} while (cur != NULL);
+    }
+}
+
 /**
  * xsltApplyStylesheet:
  * @style:  a parsed XSLT stylesheet
@@ -137,12 +321,14 @@
 xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc) {
     xmlDocPtr res = NULL;
     xsltTransformContextPtr ctxt = NULL;
+    xmlNodePtr root;
 
     if ((style == NULL) || (doc == NULL))
 	return(NULL);
     ctxt = xsltNewTransformContext();
     if (ctxt == NULL)
 	return(NULL);
+    ctxt->style = style;
     if ((style->method != NULL) &&
 	(!xmlStrEqual(style->method, (const xmlChar *) "xml"))) {
 	if (xmlStrEqual(style->method, (const xmlChar *) "html")) {
@@ -166,14 +352,35 @@
 	if (res == NULL)
 	    goto error;
     }
+    res->charset = XML_CHAR_ENCODING_UTF8;
     if (style->encoding != NULL)
-	doc->encoding = xmlStrdup(style->encoding);
+	res->encoding = xmlStrdup(style->encoding);
+
+    /*
+     * Start.
+     */
+    root = xmlDocGetRootElement(doc);
+    if (root == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+			 "xsltApplyStylesheet: document has no root\n");
+	goto error;
+    }
+    ctxt->output = res;
+    ctxt->insert = (xmlNodePtr) res;
+    ctxt->node = root;
+    ctxt->nodeList = xmlXPathNodeSetCreate(root);
+    xsltProcessOneNode(ctxt, root);
 
 
-    /*
-	res->intSubset = xmlCreateIntSubset(
-     */
-
+    if ((ctxt->type = XSLT_OUTPUT_XML) &&
+	((style->doctypePublic != NULL) ||
+	 (style->doctypeSystem != NULL))) {
+	root = xmlDocGetRootElement(res);
+	if (root != NULL)
+	    res->intSubset = xmlCreateIntSubset(res, root->name,
+		         style->doctypePublic, style->doctypeSystem);
+    }
+    xmlXPathFreeNodeSet(ctxt->nodeList);
     xsltFreeTransformContext(ctxt);
     return(res);
 
diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h
--- a/libxslt/xsltInternals.h
+++ b/libxslt/xsltInternals.h
@@ -77,6 +77,7 @@
  */
 xsltStylesheetPtr	xsltParseStylesheetFile	(const xmlChar* filename);
 void			xsltFreeStylesheet	(xsltStylesheetPtr sheet);
+int			xsltIsBlank		(xmlChar *str);
 
 #ifdef __cplusplus
 }