Added support for copy-of:
authorDaniel Veillard <veillard@src.gnome.org>
Sun, 28 Jan 2001 23:55:20 +0000 (23:55 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Sun, 28 Jan 2001 23:55:20 +0000 (23:55 +0000)
- FEATURES: updated
- libxslt/transform.c: added copy-of support
- libxslt/xsltutils.[ch]: added xsltDocumentSortFunction()
Daniel

ChangeLog
FEATURES
libxslt/transform.c
libxslt/xsltutils.c
libxslt/xsltutils.h

index dcd1a94..0e6a8ea 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Mon Jan 29 00:53:25 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+       * FEATURES: updated
+       * libxslt/transform.c: added copy-of support
+       * libxslt/xsltutils.[ch]: added xsltDocumentSortFunction()
+
 Sun Jan 28 21:45:23 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
        * FEATURES TODO: updates
index bc85487..387d37c 100644 (file)
--- a/FEATURES
+++ b/FEATURES
@@ -157,8 +157,8 @@ YES                 name = qname
 YES                    select = expression
 YES                    Content: template
 
-NO                 xsl:copy-of
-NO                     select = expression
+YES                xsl:copy-of
+YES                    select = expression
 
 YES                xsl:with-param
 YES                    name = qname 
index 665d1ea..cc06f0c 100644 (file)
@@ -45,7 +45,7 @@
 
 /************************************************************************
  *                                                                     *
- *                     
+ *                     handling of transformation contexts             *
  *                                                                     *
  ************************************************************************/
 
@@ -97,6 +97,111 @@ xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
 
 /************************************************************************
  *                                                                     *
+ *                     Copy of Nodes in an XSLT fashion                *
+ *                                                                     *
+ ************************************************************************/
+
+xmlNodePtr xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                       xmlNodePtr insert);
+
+/**
+ * xsltCopyNode:
+ * @ctxt:  a XSLT process context
+ * @node:  the element node in the source tree.
+ * @insert:  the parent in the result tree.
+ *
+ * Make a copy of the element node @node
+ * and insert it as last child of @insert
+ *
+ * Returns a pointer to the new node, or NULL in case of error
+ */
+xmlNodePtr
+xsltCopyNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
+            xmlNodePtr insert) {
+    xmlNodePtr copy;
+
+    copy = xmlCopyNode(node, 0);
+    copy->doc = ctxt->output;
+    if (copy != NULL) {
+       xmlAddChild(insert, copy);
+       /*
+        * Add namespaces as they are needed
+        */
+       if (node->nsDef != NULL)
+           xsltCopyNamespaceList(ctxt, copy, node->nsDef);
+       if (node->ns != NULL) {
+           copy->ns = xsltGetNamespace(ctxt, node, node->ns, insert);
+       }
+    } else {
+       xsltGenericError(xsltGenericErrorContext,
+               "xsltCopyNode: copy %s failed\n", node->name);
+    }
+    return(copy);
+}
+
+/**
+ * xsltCopyTreeList:
+ * @ctxt:  a XSLT process context
+ * @list:  the list of element node in the source tree.
+ * @insert:  the parent in the result tree.
+ *
+ * Make a copy of the full list of tree @list
+ * and insert them as last children of @insert
+ *
+ * Returns a pointer to the new list, or NULL in case of error
+ */
+xmlNodePtr
+xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr list,
+            xmlNodePtr insert) {
+    xmlNodePtr copy, ret = NULL;
+
+    while (list != NULL) {
+       copy = xsltCopyTree(ctxt, list, insert);
+       if (ret != NULL)
+           ret = copy;
+       list = list->next;
+    }
+    return(ret);
+}
+
+/**
+ * xsltCopyTree:
+ * @ctxt:  a XSLT process context
+ * @node:  the element node in the source tree.
+ * @insert:  the parent in the result tree.
+ *
+ * Make a copy of the full tree under the element node @node
+ * and insert it as last child of @insert
+ *
+ * Returns a pointer to the new tree, or NULL in case of error
+ */
+xmlNodePtr
+xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node,
+            xmlNodePtr insert) {
+    xmlNodePtr copy;
+
+    copy = xmlCopyNode(node, 0);
+    copy->doc = ctxt->output;
+    if (copy != NULL) {
+       xmlAddChild(insert, copy);
+       /*
+        * Add namespaces as they are needed
+        */
+       if (node->nsDef != NULL)
+           xsltCopyNamespaceList(ctxt, copy, node->nsDef);
+       if (node->ns != NULL) {
+           copy->ns = xsltGetNamespace(ctxt, node, node->ns, insert);
+       }
+       if (node->children != NULL)
+           copy->children = xsltCopyTreeList(ctxt, node->children, copy);
+    } else {
+       xsltGenericError(xsltGenericErrorContext,
+               "xsltCopyTree: copy %s failed\n", node->name);
+    }
+    return(copy);
+}
+/************************************************************************
+ *                                                                     *
  *                     
  *                                                                     *
  ************************************************************************/
@@ -413,12 +518,119 @@ error:
 }
 
 /**
+ * xsltCopyOf:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt copy-of node
+ *
+ * Process the xslt copy-of node on the source node
+ */
+void
+xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                  xmlNodePtr inst) {
+    xmlChar *prop;
+    xmlXPathObjectPtr res = NULL, tmp;
+    xmlXPathParserContextPtr xpathParserCtxt = NULL;
+    xmlNodePtr copy = NULL;
+    xmlNodeSetPtr list = NULL;
+    int i;
+
+    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
+       return;
+
+#ifdef DEBUG_PROCESS
+    xsltGenericDebug(xsltGenericDebugContext,
+        "xsltCopyOf: select %s\n", prop);
+#endif
+
+    if (ctxt->xpathCtxt == NULL) {
+       xmlXPathInit();
+       ctxt->xpathCtxt = xmlXPathNewContext(ctxt->doc);
+       if (ctxt->xpathCtxt == NULL)
+           goto error;
+       XSLT_REGISTER_VARIABLE_LOOKUP(ctxt);
+    }
+    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) || (res->type == XPATH_XSLT_TREE)) {
+           list = res->nodesetval;
+           if (list != NULL) {
+               /* sort the list in document order */
+               xsltDocumentSortFunction(list);
+               /* append everything in this order under ctxt->insert */
+               for (i = 0;i < list->nodeNr;i++) {
+                   if (list->nodeTab[i] == NULL)
+                       continue;
+                   if ((list->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
+                       (list->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) {
+                       xsltCopyTreeList(ctxt, list->nodeTab[i]->children,
+                                        ctxt->insert);
+                   } else {
+                       xsltCopyTree(ctxt, list->nodeTab[i], ctxt->insert);
+                   }
+               }
+           }
+       } else {
+           /* convert to a string */
+           valuePush(xpathParserCtxt, res);
+           xmlXPathStringFunction(xpathParserCtxt, 1);
+           res = valuePop(xpathParserCtxt);
+           if ((res != NULL) && (res->type == XPATH_STRING)) {
+               /* append content as text node */
+               copy = xmlNewText(res->stringval);
+               if (copy != NULL) {
+                   xmlAddChild(ctxt->insert, copy);
+               }
+           }
+           do {
+               tmp = valuePop(xpathParserCtxt);
+               if (tmp != NULL) {
+                   xmlXPathFreeObject(tmp);
+               }
+           } while (tmp != NULL);
+           if (copy == NULL) {
+               xsltGenericError(xsltGenericErrorContext,
+                   "xsltDefaultProcessOneNode: text copy failed\n");
+           }
+#ifdef DEBUG_PROCESS
+           else
+               xsltGenericDebug(xsltGenericDebugContext,
+                    "xslcopyOf: result %s\n", res->stringval);
+#endif
+       }
+    }
+
+error:
+    if (xpathParserCtxt != NULL) {
+       xmlXPathFreeParserContext(xpathParserCtxt);
+        xpathParserCtxt = NULL;
+    }
+    if (prop != NULL)
+       xmlFree(prop);
+    if (res != NULL)
+       xmlXPathFreeObject(res);
+}
+
+/**
  * xsltValueOf:
  * @ctxt:  a XSLT process context
  * @node:  the node in the source tree.
- * @inst:  the xsltValueOf node
+ * @inst:  the xslt value-of node
  *
- * Process the xsltValueOf node on the source node
+ * Process the xslt value-of node on the source node
  */
 void
 xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node,
@@ -509,40 +721,6 @@ error:
        xmlXPathFreeObject(res);
 }
 
-/**
- * xsltCopyNode:
- * @ctxt:  a XSLT process context
- * @node:  the element node in the source tree.
- * @insert:  the parent in the result tree.
- *
- * Make a copy of the element node @node
- * and insert it as last child of @insert
- *
- * Returns a pointer to the new node, or NULL in case of error
- */
-xmlNodePtr
-xsltCopyNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
-            xmlNodePtr insert) {
-    xmlNodePtr copy;
-
-    copy = xmlCopyNode(node, 0);
-    copy->doc = ctxt->output;
-    if (copy != NULL) {
-       xmlAddChild(insert, copy);
-       /*
-        * Add namespaces as they are needed
-        */
-       if (node->nsDef != NULL)
-           xsltCopyNamespaceList(ctxt, copy, node->nsDef);
-       if (node->ns != NULL) {
-           copy->ns = xsltGetNamespace(ctxt, node, node->ns, insert);
-       }
-    } else {
-       xsltGenericError(xsltGenericErrorContext,
-               "xsltCopyNode: copy %s failed\n", node->name);
-    }
-    return(copy);
-}
 
 /**
  * xsltDefaultProcessOneNode:
@@ -946,6 +1124,10 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
                ctxt->insert = insert;
                xsltValueOf(ctxt, node, cur);
                ctxt->insert = oldInsert;
+           } else if (IS_XSLT_NAME(cur, "copy-of")) {
+               ctxt->insert = insert;
+               xsltCopyOf(ctxt, node, cur);
+               ctxt->insert = oldInsert;
            } else if (IS_XSLT_NAME(cur, "if")) {
                ctxt->insert = insert;
                xsltIf(ctxt, node, cur);
index 71fdbba..9d787d1 100644 (file)
@@ -172,6 +172,36 @@ xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) {
  ************************************************************************/
 
 /**
+ * xsltDocumentSortFunction:
+ * @list:  the node set
+ *
+ * reorder the current node list @list accordingly to the document order
+ */
+void
+xsltDocumentSortFunction(xmlNodeSetPtr list) {
+    int i, j;
+    int len, tst;
+    xmlNodePtr node;
+
+    if (list == NULL)
+       return;
+    len = list->nodeNr;
+    if (len <= 1)
+       return;
+    /* TODO: sort is really not optimized, does it needs to ? */
+    for (i = 0;i < len -1;i++) {
+       for (j = i + 1; j < len; j++) {
+           tst = xmlXPathCmpNodes(list->nodeTab[i], list->nodeTab[j]);
+           if (tst == -1) {
+               node = list->nodeTab[i];
+               list->nodeTab[i] = list->nodeTab[j];
+               list->nodeTab[j] = node;
+           }
+       }
+    }
+}
+
+/**
  * xsltSortFunction:
  * @list:  the node set
  * @results:  the results
index 59d06c4..f261b21 100644 (file)
@@ -71,6 +71,7 @@ void          xsltSetGenericDebugFunc         (void *ctx,
  * Sorting ... this is definitely a temporary interface !
  */
 
+void           xsltDocumentSortFunction        (xmlNodeSetPtr list);
 void           xsltSortFunction                (xmlNodeSetPtr list,
                                                 xmlXPathObjectPtr *results,
                                                 int descending,