# HG changeset patch
# User Daniel Veillard <veillard@src.gnome.org>
# Date 979759032 0
#      Wed Jan 17 19:17:12 2001 +0000
# Node ID 034948f3afab893ea8d5a2017a2e87ef10f3a97b
# Parent  866a0e5dc96fa6bf58332592795aa7d782b00b7d
That part was complex actually:
- libxslt/transform.c: modified apply-templates processing
  added select and sort support support.
Daniel

diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Wed Jan 17 20:15:40 CET 2001
+
+	* libxslt/transform.c: modified apply-templates processing
+	  added select and sort support support.
+
 Wed Jan 17 17:45:20 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
 	* TODO: guess what, it's growing :-(
diff --git a/libxslt/transform.c b/libxslt/transform.c
--- a/libxslt/transform.c
+++ b/libxslt/transform.c
@@ -120,6 +120,141 @@
 void xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst);
 
 /**
+ * xsltSort:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt sort node
+ *
+ * Process the xslt sort node on the source node
+ */
+void
+xsltSort(xsltTransformContextPtr ctxt, xmlNodePtr node,
+	           xmlNodePtr inst) {
+    xmlXPathObjectPtr *results = NULL;
+    xmlNodeSetPtr list = NULL;
+    xmlXPathParserContextPtr xpathParserCtxt = NULL;
+    xmlChar *prop;
+    xmlXPathObjectPtr res, tmp;
+    const xmlChar *start;
+    int descending = 0;
+    int number = 0;
+    int len;
+    int i;
+
+    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
+	return;
+
+    list = ctxt->nodeList;
+    if ((list == NULL) || (list->nodeNr <= 1))
+	goto error; /* nothing to do */
+
+    len = list->nodeNr;
+
+    /* TODO: process attributes as attribute value templates */
+    prop = xmlGetNsProp(inst, (const xmlChar *)"data-type", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (xmlStrEqual(prop, (const xmlChar *) "text"))
+	    number = 0;
+	else if (xmlStrEqual(prop, (const xmlChar *) "number"))
+	    number = 1;
+	else {
+	    xsltGenericError(xsltGenericErrorContext,
+		 "xsltSort: no support for data-type = %s\n", prop);
+	    goto error;
+	}
+	xmlFree(prop);
+    }
+    prop = xmlGetNsProp(inst, (const xmlChar *)"order", XSLT_NAMESPACE);
+    if (prop != NULL) {
+	if (xmlStrEqual(prop, (const xmlChar *) "ascending"))
+	    descending = 0;
+	else if (xmlStrEqual(prop, (const xmlChar *) "descending"))
+	    descending = 1;
+	else {
+	    xsltGenericError(xsltGenericErrorContext,
+		 "xsltSort: invalid value %s for order\n", prop);
+	    goto error;
+	}
+	xmlFree(prop);
+    }
+    /* TODO: xsl:sort lang attribute */
+    /* TODO: xsl:sort case-order attribute */
+
+    prop = xmlGetNsProp(inst, (const xmlChar *)"select", XSLT_NAMESPACE);
+    if (prop == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	     "xsltSort: select is not defined\n");
+	return;
+    }
+
+    xpathParserCtxt = xmlXPathNewParserContext(prop, ctxt->xpathCtxt);
+    if (xpathParserCtxt == NULL)
+	goto error;
+    results = xmlMalloc(len * sizeof(xmlXPathObjectPtr));
+    if (results == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+	     "xsltSort: memory allocation failure\n");
+	goto error;
+    }
+
+    start = xpathParserCtxt->cur;
+    for (i = 0;i < len;i++) {
+	xpathParserCtxt->cur = start;
+	node = ctxt->node = list->nodeTab[i];
+	ctxt->xpathCtxt->proximityPosition = i + 1;
+	valuePush(xpathParserCtxt, xmlXPathNewNodeSet(node));
+	xmlXPathEvalExpr(xpathParserCtxt);
+	xmlXPathStringFunction(xpathParserCtxt, 1);
+	if (number)
+	    xmlXPathNumberFunction(xpathParserCtxt, 1);
+	res = valuePop(xpathParserCtxt);
+	do {
+	    tmp = valuePop(xpathParserCtxt);
+	    if (tmp != NULL) {
+		xmlXPathFreeObject(tmp);
+	    }
+	} while (tmp != NULL);
+
+	if (res != NULL) {
+	    if (number) {
+		if (res->type == XPATH_NUMBER) {
+		    results[i] = res;
+		} else {
+#ifdef DEBUG_PROCESS
+		    xsltGenericDebug(xsltGenericDebugContext,
+			"xsltSort: select didn't evaluate to a number\n");
+#endif
+		    results[i] = NULL;
+		}
+	    } else {
+		if (res->type == XPATH_STRING) {
+		    results[i] = res;
+		} else {
+#ifdef DEBUG_PROCESS
+		    xsltGenericDebug(xsltGenericDebugContext,
+			"xsltSort: select didn't evaluate to a string\n");
+#endif
+		    results[i] = NULL;
+		}
+	    }
+	}
+    }
+
+    xsltSortFunction(list, &results[0], descending, number);
+
+error:
+    if (xpathParserCtxt != NULL)
+	xmlXPathFreeParserContext(xpathParserCtxt);
+    if (prop != NULL)
+	xmlFree(prop);
+    if (results != NULL) {
+	for (i = 0;i < len;i++)
+	    xmlXPathFreeObject(results[i]);
+	xmlFree(results);
+    }
+}
+
+/**
  * xsltAttribute:
  * @ctxt:  a XSLT process context
  * @node:  the node in the source tree.
@@ -403,6 +538,15 @@
 	case XML_HTML_DOCUMENT_NODE:
 	case XML_ELEMENT_NODE:
 	    break;
+	case XML_TEXT_NODE:
+	    copy = xmlCopyNode(node, 0);
+	    if (copy != NULL) {
+		xmlAddChild(ctxt->insert, copy);
+	    } else {
+		xsltGenericError(xsltGenericErrorContext,
+		    "xsltDefaultProcessOneNode: text copy failed\n");
+	    }
+	    return;
 	default:
 	    return;
     }
@@ -472,7 +616,13 @@
 void
 xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
 	           xmlNodePtr inst) {
-    xmlChar *prop;
+    xmlChar *prop = NULL;
+    xmlNodePtr cur, delete = NULL;
+    xmlXPathObjectPtr res = NULL, tmp;
+    xmlNodePtr replacement;
+    xmlNodeSetPtr list = NULL, oldlist;
+    xmlXPathParserContextPtr xpathParserCtxt = NULL;
+    int i, oldProximityPosition, oldContextSize;
 
     if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
 	return;
@@ -483,10 +633,133 @@
 #endif
     prop = xmlGetNsProp(inst, (const xmlChar *)"select", XSLT_NAMESPACE);
     if (prop != NULL) {
-	TODO
+#ifdef DEBUG_PROCESS
+	xsltGenericDebug(xsltGenericDebugContext,
+	     "xsltApplyTemplates: select %s\n", prop);
+#endif
+
+	if (ctxt->xpathCtxt == NULL) {
+	    xmlXPathInit();
+	    ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
+	    if (ctxt->xpathCtxt == NULL)
+		goto error;
+	}
+	xpathParserCtxt =
+	    xmlXPathNewParserContext(prop, ctxt->xpathCtxt);
+	if (xpathParserCtxt == NULL)
+	    goto error;
+	ctxt->xpathCtxt->node = node;
+	valuePush(xpathParserCtxt, xmlXPathNewNodeSet(node));
+	xmlXPathEvalExpr(xpathParserCtxt);
+	res = valuePop(xpathParserCtxt);
+	do {
+	    tmp = valuePop(xpathParserCtxt);
+	    if (tmp != NULL) {
+		xmlXPathFreeObject(tmp);
+	    }
+	} while (tmp != NULL);
+	if (res != NULL) {
+	    if (res->type == XPATH_NODESET) {
+		list = res->nodesetval;
+		res->nodesetval = NULL;
+	     } else {
+#ifdef DEBUG_PROCESS
+		xsltGenericDebug(xsltGenericDebugContext,
+		    "xsltApplyTemplates: select didn't evaluate to a node list\n");
+#endif
+		goto error;
+	    }
+	}
     } else {
-	xsltDefaultProcessOneNode(ctxt, node);
+	/*
+	 * Build an XPath nodelist with the children
+	 */
+	list = xmlXPathNodeSetCreate(NULL);
+	cur = node->children;
+	while (cur != NULL) {
+	    switch (cur->type) {
+		case XML_TEXT_NODE:
+		    /* TODO: check the whitespace stripping rules ! */
+		    if ((IS_BLANK_NODE(cur)) &&
+			(cur->parent != NULL) &&
+			(ctxt->style->stripSpaces != NULL)) {
+			const xmlChar *val;
+
+			val = (const xmlChar *)
+			      xmlHashLookup(ctxt->style->stripSpaces,
+					    cur->parent->name);
+			if ((val != NULL) &&
+			    (xmlStrEqual(val, (xmlChar *) "strip"))) {
+			    delete = cur;
+			    break;
+			}
+		    }
+		    /* no break on purpose */
+		case XML_DOCUMENT_NODE:
+		case XML_HTML_DOCUMENT_NODE:
+		case XML_ELEMENT_NODE:
+		case XML_CDATA_SECTION_NODE:
+		    xmlXPathNodeSetAdd(list, cur);
+		    break;
+		default:
+#ifdef DEBUG_PROCESS
+		    xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltApplyTemplates: skipping cur type %d\n",
+				     cur->type);
+#endif
+		    delete = cur;
+	    }
+	    cur = cur->next;
+	    if (delete != NULL) {
+#ifdef DEBUG_PROCESS
+		xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltApplyTemplates: removing ignorable blank cur\n");
+#endif
+		xmlUnlinkNode(delete);
+		xmlFreeNode(delete);
+		delete = NULL;
+	    }
+	}
     }
+
+#ifdef DEBUG_PROCESS
+    xsltGenericDebug(xsltGenericDebugContext,
+	"xsltApplyTemplates: list of %d nodes\n", list->nodeNr);
+#endif
+
+    oldlist = ctxt->nodeList;
+    ctxt->nodeList = list;
+    oldContextSize = ctxt->xpathCtxt->contextSize;
+    oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
+    ctxt->xpathCtxt->contextSize = list->nodeNr;
+
+    /* 
+     * handle and skip the xsl:sort
+     */
+    replacement = inst->children;
+    while (IS_XSLT_ELEM(replacement) && (IS_XSLT_NAME(replacement, "sort"))) {
+	xsltSort(ctxt, node, replacement);
+	replacement = replacement->next;
+    }
+
+    for (i = 0;i < list->nodeNr;i++) {
+	ctxt->node = list->nodeTab[i];
+	ctxt->xpathCtxt->proximityPosition = i + 1;
+	xsltProcessOneNode(ctxt, list->nodeTab[i]);
+    }
+    ctxt->nodeList = oldlist;
+    ctxt->xpathCtxt->contextSize = oldContextSize;
+    ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
+
+error:
+    if (xpathParserCtxt != NULL)
+	xmlXPathFreeParserContext(xpathParserCtxt);
+    if (prop != NULL)
+	xmlFree(prop);
+    if (res != NULL)
+	xmlXPathFreeObject(res);
+    if (list != NULL)
+	xmlXPathFreeNodeSet(list);
 }
 
 /**
@@ -715,141 +988,6 @@
 }
 
 /**
- * xsltSort:
- * @ctxt:  a XSLT process context
- * @node:  the node in the source tree.
- * @inst:  the xslt sort node
- *
- * Process the xslt sort node on the source node
- */
-void
-xsltSort(xsltTransformContextPtr ctxt, xmlNodePtr node,
-	           xmlNodePtr inst) {
-    xmlXPathObjectPtr *results = NULL;
-    xmlNodeSetPtr list = NULL;
-    xmlXPathParserContextPtr xpathParserCtxt = NULL;
-    xmlChar *prop;
-    xmlXPathObjectPtr res, tmp;
-    const xmlChar *start;
-    int descending = 0;
-    int number = 0;
-    int len;
-    int i;
-
-    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
-	return;
-
-    list = ctxt->nodeList;
-    if ((list == NULL) || (list->nodeNr <= 1))
-	goto error; /* nothing to do */
-
-    len = list->nodeNr;
-
-    prop = xmlGetNsProp(inst, (const xmlChar *)"data-type", XSLT_NAMESPACE);
-    if (prop != NULL) {
-	if (xmlStrEqual(prop, (const xmlChar *) "text"))
-	    number = 0;
-	else if (xmlStrEqual(prop, (const xmlChar *) "number"))
-	    number = 1;
-	else {
-	    xsltGenericError(xsltGenericErrorContext,
-		 "xsltSort: no support for data-type = %s\n", prop);
-	    goto error;
-	}
-	xmlFree(prop);
-    }
-    prop = xmlGetNsProp(inst, (const xmlChar *)"order", XSLT_NAMESPACE);
-    if (prop != NULL) {
-	if (xmlStrEqual(prop, (const xmlChar *) "ascending"))
-	    descending = 0;
-	else if (xmlStrEqual(prop, (const xmlChar *) "descending"))
-	    descending = 1;
-	else {
-	    xsltGenericError(xsltGenericErrorContext,
-		 "xsltSort: invalid value %s for order\n", prop);
-	    goto error;
-	}
-	xmlFree(prop);
-    }
-    /* TODO: xsl:sort lang attribute */
-    /* TODO: xsl:sort order attribute */
-    /* TODO: xsl:sort case-order attribute */
-
-    prop = xmlGetNsProp(inst, (const xmlChar *)"select", XSLT_NAMESPACE);
-    if (prop == NULL) {
-	xsltGenericError(xsltGenericErrorContext,
-	     "xsltSort: select is not defined\n");
-	return;
-    }
-
-    xpathParserCtxt = xmlXPathNewParserContext(prop, ctxt->xpathCtxt);
-    if (xpathParserCtxt == NULL)
-	goto error;
-    results = xmlMalloc(len * sizeof(xmlXPathObjectPtr));
-    if (results == NULL) {
-	xsltGenericError(xsltGenericErrorContext,
-	     "xsltSort: memory allocation failure\n");
-	goto error;
-    }
-
-    start = xpathParserCtxt->cur;
-    for (i = 0;i < len;i++) {
-	xpathParserCtxt->cur = start;
-	node = ctxt->node = list->nodeTab[i];
-	ctxt->xpathCtxt->proximityPosition = i + 1;
-	valuePush(xpathParserCtxt, xmlXPathNewNodeSet(node));
-	xmlXPathEvalExpr(xpathParserCtxt);
-	xmlXPathStringFunction(xpathParserCtxt, 1);
-	if (number)
-	    xmlXPathNumberFunction(xpathParserCtxt, 1);
-	res = valuePop(xpathParserCtxt);
-	do {
-	    tmp = valuePop(xpathParserCtxt);
-	    if (tmp != NULL) {
-		xmlXPathFreeObject(tmp);
-	    }
-	} while (tmp != NULL);
-
-	if (res != NULL) {
-	    if (number) {
-		if (res->type == XPATH_NUMBER) {
-		    results[i] = res;
-		} else {
-#ifdef DEBUG_PROCESS
-		    xsltGenericDebug(xsltGenericDebugContext,
-			"xsltSort: select didn't evaluate to a number\n");
-#endif
-		    results[i] = NULL;
-		}
-	    } else {
-		if (res->type == XPATH_STRING) {
-		    results[i] = res;
-		} else {
-#ifdef DEBUG_PROCESS
-		    xsltGenericDebug(xsltGenericDebugContext,
-			"xsltSort: select didn't evaluate to a string\n");
-#endif
-		    results[i] = NULL;
-		}
-	    }
-	}
-    }
-
-    xsltSortFunction(list, &results[0], descending, number);
-
-error:
-    if (xpathParserCtxt != NULL)
-	xmlXPathFreeParserContext(xpathParserCtxt);
-    if (prop != NULL)
-	xmlFree(prop);
-    if (results != NULL) {
-	for (i = 0;i < len;i++)
-	    xmlXPathFreeObject(results[i]);
-	xmlFree(results);
-    }
-}
-
-/**
  * xsltForEach:
  * @ctxt:  a XSLT process context
  * @node:  the node in the source tree.
@@ -961,8 +1099,8 @@
 void
 xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
     xsltTemplatePtr template;
+
     template = xsltGetTemplate(ctxt->style, node);
-
     /*
      * If no template is found, apply the default rule.
      */
@@ -975,7 +1113,6 @@
 	    xsltGenericDebug(xsltGenericDebugContext,
 	     "xsltProcessOneNode: no template found for %s\n", node->name);
 #endif
-
 	xsltDefaultProcessOneNode(ctxt, node);
 	return;
     }