That part was complex actually:
authorDaniel Veillard <veillard@src.gnome.org>
Wed, 17 Jan 2001 19:17:12 +0000 (19:17 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Wed, 17 Jan 2001 19:17:12 +0000 (19:17 +0000)
- libxslt/transform.c: modified apply-templates processing
  added select and sort support support.
Daniel

ChangeLog
libxslt/transform.c

index 0a06ccc..53aff54 100644 (file)
--- 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 :-(
index 849795c..fcfd47b 100644 (file)
@@ -120,6 +120,141 @@ void xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr node,
 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 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
        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 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
 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 @@ xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node,
 #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 @@ error:
 }
 
 /**
- * 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 @@ error:
 void
 xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
     xsltTemplatePtr template;
-    template = xsltGetTemplate(ctxt->style, node);
 
+    template = xsltGetTemplate(ctxt->style, node);
     /*
      * If no template is found, apply the default rule.
      */
@@ -975,7 +1113,6 @@ xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node) {
            xsltGenericDebug(xsltGenericDebugContext,
             "xsltProcessOneNode: no template found for %s\n", node->name);
 #endif
-
        xsltDefaultProcessOneNode(ctxt, node);
        return;
     }