Hack, debug, read, hack, debug, read ....
authorDaniel Veillard <veillard@src.gnome.org>
Mon, 15 Jan 2001 14:34:02 +0000 (14:34 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Mon, 15 Jan 2001 14:34:02 +0000 (14:34 +0000)
- transform.c, xslt.c, xsltproc.c: lots of fixes, added
  support of xslt:if and xslt:attribute, need libxml2 interfaces
  present only in CVS.
Daniel

ChangeLog
libxslt/transform.c
libxslt/xslt.c
libxslt/xsltproc.c

index 4678f82..ccf0e54 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Mon Jan 15 15:31:41 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+       * transform.c, xslt.c, xsltproc.c: lots of fixes, added
+         support of xslt:if and xslt:attribute, need libxml2 interfaces
+         present only in CVS.
+
 Sat Jan 13 23:26:21 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
        * test/Makefile.am test/REC*/Makefile.am: added first test
index 8d2d337..8af973e 100644 (file)
@@ -29,7 +29,7 @@
 #include "pattern.h"
 #include "transform.h"
 
-/* #define DEBUG_PROCESS */
+#define DEBUG_PROCESS
 
 /*
  * To cleanup
@@ -143,6 +143,92 @@ xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
 void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node);
 void xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr node,
                 xmlNodePtr inst);
+void xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst);
+
+/**
+ * xsltAttribute:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt attribute node
+ *
+ * Process the xslt attribute node on the source node
+ */
+void
+xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                  xmlNodePtr inst) {
+    xmlChar *prop = NULL;
+    xmlChar *ncname = NULL;
+    xmlChar *prefix = NULL;
+    xmlChar *value = NULL;
+    xmlNsPtr ns = NULL;
+    xmlAttrPtr attr;
+
+
+    if (ctxt->insert == NULL)
+       return;
+    if (ctxt->insert->children != NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+            "xslt:attribute : node has already children\n");
+       return;
+    }
+    prop = xmlGetNsProp(inst, (const xmlChar *)"namespace", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       /* TODO: attribute value template */
+       TODO
+       xmlFree(prop);
+       return;
+    }
+    prop = xmlGetNsProp(inst, (const xmlChar *)"name", XSLT_NAMESPACE);
+    if (prop == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+            "xslt:attribute : name is missing\n");
+       goto error;
+    }
+
+    ncname = xmlSplitQName2(prop, &prefix);
+    if (ncname == NULL) {
+       ncname = prop;
+       prop = NULL;
+       prefix = NULL;
+    }
+    if (xmlStrEqual(ncname, (const xmlChar *) "xmlns")) {
+       xsltGenericError(xsltGenericErrorContext,
+            "xslt:attribute : xmlns forbidden\n");
+       goto error;
+    }
+    if ((prefix != NULL) && (ns == NULL)) {
+       ns = xmlSearchNs(ctxt->insert->doc, ctxt->insert, prefix);
+       if (ns == NULL) {
+           xsltGenericError(xsltGenericErrorContext,
+               "no namespace bound to prefix %s\n", prefix);
+       }
+    }
+
+    value = xmlNodeListGetString(inst->doc, inst->children, 1);
+    if (value == NULL) {
+       if (ns)
+           attr = xmlSetNsProp(ctxt->insert, ncname, ns->href,
+                               (const xmlChar *)"");
+       else
+           attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)"");
+    } else {
+       /* TODO: attribute value template */
+       if (ns)
+           attr = xmlSetNsProp(ctxt->insert, ncname, ns->href, value);
+       else
+           attr = xmlSetProp(ctxt->insert, ncname, value);
+    }
+
+error:
+    if (prop != NULL)
+        xmlFree(prop);
+    if (ncname != NULL)
+        xmlFree(ncname);
+    if (prefix != NULL)
+        xmlFree(prefix);
+    if (value != NULL)
+        xmlFree(value);
+}
 
 /**
  * xsltValueOf:
@@ -469,10 +555,18 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
                ctxt->insert = insert;
                xsltValueOf(ctxt, node, cur);
                ctxt->insert = oldInsert;
+           } else if (IS_XSLT_NAME(cur, "if")) {
+               ctxt->insert = insert;
+               xsltIf(ctxt, node, cur);
+               ctxt->insert = oldInsert;
            } else if (IS_XSLT_NAME(cur, "for-each")) {
                ctxt->insert = insert;
                xsltForEach(ctxt, node, cur);
                ctxt->insert = oldInsert;
+           } else if (IS_XSLT_NAME(cur, "attribute")) {
+               ctxt->insert = insert;
+               xsltAttribute(ctxt, node, cur);
+               ctxt->insert = oldInsert;
            } else {
 #ifdef DEBUG_PROCESS
                xsltGenericError(xsltGenericErrorContext,
@@ -551,6 +645,86 @@ skip_children:
 }
 
 /**
+ * xsltIf:
+ * @ctxt:  a XSLT process context
+ * @node:  the node in the source tree.
+ * @inst:  the xslt if node
+ *
+ * Process the xslt if node on the source node
+ */
+void
+xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                  xmlNodePtr inst) {
+    xmlChar *prop;
+    xmlXPathObjectPtr res, tmp;
+    xmlXPathParserContextPtr xpathParserCtxt;
+    int doit;
+
+    if ((ctxt == NULL) || (node == NULL) || (inst == NULL))
+       return;
+
+    prop = xmlGetNsProp(inst, (const xmlChar *)"test", XSLT_NAMESPACE);
+    if (prop == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+            "xsltIf: test is not defined\n");
+       return;
+    }
+#ifdef DEBUG_PROCESS
+    xsltGenericError(xsltGenericErrorContext,
+        "xsltIf: test %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);
+    xmlXPathBooleanFunction(xpathParserCtxt, 1);
+    res = valuePop(xpathParserCtxt);
+    do {
+        tmp = valuePop(xpathParserCtxt);
+       if (tmp != NULL) {
+           xmlXPathFreeObject(tmp);
+       }
+    } while (tmp != NULL);
+
+    if (res != NULL) {
+       if (res->type == XPATH_BOOLEAN)
+           doit = res->boolval;
+       else {
+#ifdef DEBUG_PROCESS
+           xsltGenericError(xsltGenericErrorContext,
+               "xsltIf: test didn't evaluate to a boolean\n");
+#endif
+           goto error;
+       }
+    }
+
+#ifdef DEBUG_PROCESS
+    xsltGenericError(xsltGenericErrorContext,
+       "xsltIf: test evaluate to %d\n", doit);
+#endif
+    if (doit) {
+       xsltApplyOneTemplate(ctxt, ctxt->node, inst->children);
+    }
+
+error:
+    if (xpathParserCtxt != NULL)
+       xmlXPathFreeParserContext(xpathParserCtxt);
+    if (prop != NULL)
+       xmlFree(prop);
+    if (res != NULL)
+       xmlXPathFreeObject(res);
+}
+
+/**
  * xsltForEach:
  * @ctxt:  a XSLT process context
  * @node:  the node in the source tree.
@@ -702,8 +876,9 @@ xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc) {
                goto error;
        } else if (xmlStrEqual(style->method, (const xmlChar *) "text")) {
            ctxt->type = XSLT_OUTPUT_TEXT;
-           TODO
-           goto error;
+           res = xmlNewDoc(style->version);
+           if (res == NULL)
+               goto error;
        } else {
            xsltGenericError(xsltGenericErrorContext,
                             "xsltApplyStylesheet: insupported method %s\n",
index c6dee96..e400d65 100644 (file)
@@ -467,80 +467,21 @@ xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
 }
 
 /**
- * xsltParseStylesheetTemplate:
+ * xsltParseTemplateContent:
  * @style:  the XSLT stylesheet
- * @template:  the "template" element
+ * @ret:  the "template" structure
+ * @template:  the container node (can be a document for literal results)
  *
- * parse an XSLT stylesheet template building the associated structures
+ * parse an XSLT template element content
+ * Clean-up the template content from unwanted ignorable blank nodes
+ * and process xslt:text
  */
 
 void
-xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
-    xsltTemplatePtr ret;
+xsltParseTemplateContent(xsltStylesheetPtr style, xsltTemplatePtr ret,
+                        xmlNodePtr template) {
     xmlNodePtr cur, delete;
-    xmlChar *prop;
-
-    if (template == NULL)
-       return;
-
-
-    /*
-     * Create and link the structure
-     */
-    ret = xsltNewTemplate();
-    if (ret == NULL)
-       return;
-    ret->next = style->templates;
-    style->templates = ret;
-
     /*
-     * Get arguments
-     */
-    prop = xmlGetNsProp(template, (const xmlChar *)"match", XSLT_NAMESPACE);
-    if (prop != NULL) {
-       if (ret->match != NULL) xmlFree(ret->match);
-       ret->match  = prop;
-    }
-
-    prop = xmlGetNsProp(template, (const xmlChar *)"name", XSLT_NAMESPACE);
-    if (prop != NULL) {
-       xmlChar *ncname;
-       xmlChar *prefix = NULL;
-
-       if (ret->name != NULL) xmlFree(ret->name);
-       ret->name = NULL;
-       if (ret->nameURI != NULL) xmlFree(ret->nameURI);
-       ret->nameURI = NULL;
-
-       ncname = xmlSplitQName2(prop, &prefix);
-       if (ncname != NULL) {
-           if (prefix != NULL) {
-               xmlNsPtr ns;
-
-               ns = xmlSearchNs(cur->doc, cur, prefix);
-               if (ns == NULL) {
-                   xsltGenericError(xsltGenericErrorContext,
-                       "no namespace bound to prefix %s\n", prefix);
-                   xmlFree(prefix);
-                   xmlFree(ncname);
-                   ret->name = prop;
-               } else {
-                   ret->nameURI = xmlStrdup(ns->href);
-                   ret->name = ncname;
-                   xmlFree(prefix);
-                   xmlFree(prop);
-               }
-           } else {
-               ret->name = ncname;
-               xmlFree(prop);
-           }
-       } else {
-           ret->name  = prop;
-       }
-    }
-
-    /*
-     * Clean-up the template content from unwanted ignorable blank nodes
      * This content comes from the stylesheet
      * For stylesheets, the set of whitespace-preserving
      * element names consists of just xsl:text.
@@ -558,8 +499,21 @@ xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
            delete = NULL;
        }
        if (IS_XSLT_ELEM(cur)) {
-           if (IS_XSLT_NAME(cur, "text"))
+           if (IS_XSLT_NAME(cur, "text")) {
+               if (cur->children != NULL) {
+                   if ((cur->children->type != XML_TEXT_NODE) ||
+                       (cur->children->next != NULL)) {
+                       xsltGenericError(xsltGenericErrorContext,
+            "xsltParseStylesheetTemplate: xslt:text content problem\n");
+                   } else {
+                       xmlNodePtr text = cur->children;
+                       xmlUnlinkNode(text);
+                       xmlAddPrevSibling(cur, text);
+                   }
+               }
+               delete = cur;
                goto skip_children;
+           }
        } else if (cur->type == XML_TEXT_NODE) {
            if (IS_BLANK_NODE(cur)) {
                delete = cur;
@@ -597,6 +551,15 @@ skip_children:
            }
        } while (cur != NULL);
     }
+    if (delete != NULL) {
+#ifdef DEBUG_PARSING
+       xsltGenericError(xsltGenericErrorContext,
+        "xsltParseStylesheetTemplate: removing ignorable blank node\n");
+#endif
+       xmlUnlinkNode(delete);
+       xmlFreeNode(delete);
+       delete = NULL;
+    }
 
     /*
      * Find and handle the params
@@ -651,10 +614,83 @@ skip_children:
     }
 
     ret->content = template->children;
+}
+
+/**
+ * xsltParseStylesheetTemplate:
+ * @style:  the XSLT stylesheet
+ * @template:  the "template" element
+ *
+ * parse an XSLT stylesheet template building the associated structures
+ */
+
+void
+xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
+    xsltTemplatePtr ret;
+    xmlChar *prop;
+
+    if (template == NULL)
+       return;
+
+    /*
+     * Create and link the structure
+     */
+    ret = xsltNewTemplate();
+    if (ret == NULL)
+       return;
+    ret->next = style->templates;
+    style->templates = ret;
+
+    /*
+     * Get arguments
+     */
+    prop = xmlGetNsProp(template, (const xmlChar *)"match", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       if (ret->match != NULL) xmlFree(ret->match);
+       ret->match  = prop;
+    }
+
+    prop = xmlGetNsProp(template, (const xmlChar *)"name", XSLT_NAMESPACE);
+    if (prop != NULL) {
+       xmlChar *ncname;
+       xmlChar *prefix = NULL;
+
+       if (ret->name != NULL) xmlFree(ret->name);
+       ret->name = NULL;
+       if (ret->nameURI != NULL) xmlFree(ret->nameURI);
+       ret->nameURI = NULL;
+
+       ncname = xmlSplitQName2(prop, &prefix);
+       if (ncname != NULL) {
+           if (prefix != NULL) {
+               xmlNsPtr ns;
+
+               ns = xmlSearchNs(template->doc, template, prefix);
+               if (ns == NULL) {
+                   xsltGenericError(xsltGenericErrorContext,
+                       "no namespace bound to prefix %s\n", prefix);
+                   xmlFree(prefix);
+                   xmlFree(ncname);
+                   ret->name = prop;
+               } else {
+                   ret->nameURI = xmlStrdup(ns->href);
+                   ret->name = ncname;
+                   xmlFree(prefix);
+                   xmlFree(prop);
+               }
+           } else {
+               ret->name = ncname;
+               xmlFree(prop);
+           }
+       } else {
+           ret->name  = prop;
+       }
+    }
 
     /*
-     * Register pattern
+     * parse the content and register the pattern
      */
+    xsltParseTemplateContent(style, ret, template);
     xsltAddTemplate(style, ret);
 }
 
@@ -794,14 +830,45 @@ xsltParseStylesheetDoc(xmlDocPtr doc) {
 
        xsltParseStylesheetTop(ret, cur);
     } else {
+       xmlChar *prop;
+       xsltTemplatePtr template;
+
        /*
-        * the document itself is the template.
+        * the document itself might be the template, check xsl:version
         */
+       prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
+       if (prop == NULL) {
+           xsltGenericError(xsltGenericErrorContext,
+               "xsltParseStylesheetDoc : document is not a stylesheet\n");
+           xsltFreeStylesheet(ret);
+           return(NULL);
+       }
+
 #ifdef DEBUG_PARSING
         xsltGenericError(xsltGenericErrorContext,
                "xsltParseStylesheetDoc : document is stylesheet\n");
 #endif
-       TODO
+       
+       /* TODO: check the version */
+       xmlFree(prop);
+
+       /*
+        * Create and link the template
+        */
+       template = xsltNewTemplate();
+       if (template == NULL) {
+           xsltFreeStylesheet(ret);
+           return(NULL);
+       }
+       template->next = ret->templates;
+       ret->templates = template;
+       template->match = xmlStrdup((const xmlChar *)"/");
+
+       /*
+        * parse the content and register the pattern
+        */
+       xsltParseTemplateContent(ret, template, (xmlNodePtr) doc);
+       xsltAddTemplate(ret, template);
     }
 
     return(ret);
index ccb060b..644884c 100644 (file)
@@ -32,7 +32,7 @@ main(int argc, char **argv) {
        if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
            cur = xsltParseStylesheetFile((const xmlChar *)argv[i]);
            if (cur != NULL) {
-               if (cur->indent)
+               if (cur->indent == 1)
                    xmlIndentTreeOutput = 1;
                else
                    xmlIndentTreeOutput = 0;