Hack, hack, hack ... Mostly adding functions:
authorDaniel Veillard <veillard@src.gnome.org>
Thu, 25 Jan 2001 18:51:41 +0000 (18:51 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Thu, 25 Jan 2001 18:51:41 +0000 (18:51 +0000)
- FEATURES TODO README INSTALL: updated
- libxslt/xslt.h: added URL and version/vendor :-)
- libxslt/transform.c: fixed a problem in xsl:attribute, removed
  attempt to support older libxml2 version.
- libxslt/variables.h libxslt/xsltInternals.h: update to structures
  and macros to add/register new document created by document()
- libxslt/functions.c: implemented current(), unparsed-entity-uri()
  system-property(), element-available() and function-available().
  A crippled version of document() has been added too.
Daniel

12 files changed:
ChangeLog
FEATURES
INSTALL
README
TODO
libxslt/functions.c
libxslt/transform.c
libxslt/variables.h
libxslt/xslt.c
libxslt/xslt.h
libxslt/xsltInternals.h
libxslt/xsltutils.c

index 9c22ac3..c091fa8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Thu Jan 25 19:36:45 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+       * FEATURES TODO README INSTALL: updated
+       * libxslt/xslt.h: added URL and version/vendor :-)
+       * libxslt/transform.c: fixed a problem in xsl:attribute, removed
+         attempt to support older libxml2 version.
+       * libxslt/variables.h libxslt/xsltInternals.h: update to structures
+         and macros to add/register new document created by document()
+       * libxslt/functions.c: implemented current(), unparsed-entity-uri()
+         system-property(), element-available() and function-available().
+         A crippled version of document() has been added too.
+
 Thu Jan 25 12:13:04 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
        * functions.[ch]: Bjorn Reese <breese@mail1.stofanet.dk> provided
index 9356fac..16e2efa 100644 (file)
--- a/FEATURES
+++ b/FEATURES
@@ -186,7 +186,9 @@ General:
 ========
 
 YES (w.o import)    Conflict Resolution for Template Rules
+
 YES                Whitespace Stripping
+
 YES                Built-in Template Rules
 YES                    match="*|/"
 YES                    match="text()|@*"
@@ -194,6 +196,10 @@ YES                        match="processing-instruction()|comment()"
 NO                     Namespace
 NO                     Mode
 
+NO                 Extension Elements
+
+NO                 Extension Functions
+
 YES                Attribute Value Templates
 
 YES                Result Tree Fragments
@@ -201,14 +207,14 @@ YES                   Result Tree Fragments
 Functions:
 ==========
 
-NO                 node-set document(object, node-set?)
+PARTIAL                    node-set document(object, node-set?)
 NO                 node-set key(string, object)
 YES                string format-number(number, string, string?)
-NO                 node-set current() 
-NO                 string unparsed-entity-uri(string)
-NO                 string generate-id(node-set?)
-NO                 object system-property(string)
-NO                 boolean element-available(string)
-NO                 boolean function-available(string)
+YES                node-set current() 
+YES                string unparsed-entity-uri(string)
+YES                string generate-id(node-set?)
+YES                object system-property(string)
+YES                boolean element-available(string)
+YES                boolean function-available(string)
 
 Daniel.Veillard@imag.fr
diff --git a/INSTALL b/INSTALL
index 312f2f6..b522e06 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -3,7 +3,7 @@
 Requirements:
 =============
 
-this library requires libxml2 which you can grab from
+this library requires libxml2 >= 2.2.12 which you can grab from
 either the GNOME FTP or the xmlsoft.org server:
 
   ftp://xmlsoft.org/
diff --git a/README b/README
index 37f544a..3f3917a 100644 (file)
--- a/README
+++ b/README
@@ -1,10 +1,14 @@
 
-                  XSLT support for libxml
+                  XSLT support for libxml2
 
                  http://xmlsoft.org/
 
- Requires libxml2 with XPath support.
-Currently unusable, very early steps ...
+ Requires libxml2 >= 2.2.12 with XPath support. It won't even compile
+otherwise.
+ Check the FEATURES file for informations about completeness
+ Check the Changelog too to keep track of progresses.
+
+   report bugs to xml@rpmfind.net or on the bugzilla.gnome.org base.
 
 Daniel Veillard
 
diff --git a/TODO b/TODO
index 57fbb00..47d246b 100644 (file)
--- a/TODO
+++ b/TODO
@@ -3,6 +3,13 @@
                  *  TODO  *
                  *        *
                   ********
+
+Doc:
+  - put a page at http://xmlsoft.org/XSLT/
+  - generate/transform the DocBook to HTML
+  - add HTML to package
+  - manpage and doc for xsltproc
+
 Design:
   - should transforms for a given stylesheet be thread clean,
     or can a stylesheet be enriched with document specific
@@ -15,10 +22,10 @@ Import:
   -> provide functions to circulate in the import tree of stylesheets
 
 Extra functions:
-  -> make a separate module.
   -> document() should not be a problem since Result Tree Fragments are
      implemnted
-  -> others 
+  => started, incomplete
+  -> missing key support
 
 ID and Key support:
   -> Id should be simple, key will probably requires some hash tables.
@@ -36,10 +43,7 @@ Error handling:
      and lack of optionnal features.
 
 Support Attribute value templates:
-  -> starts to be urgent. Design it in flexible ways but try to optimize
-     to handle most of it at the stylesheet parse time ...
-  => Done for the most part need to check all attributes in XSLT constructs
-     using them and use the dedicated readin function.
+  -> optimization by checking their existence at stylesheet parse time.
 
 Sorting:
   -> add support for imbricated sorts
@@ -59,6 +63,16 @@ Contextual error reporting:
                  *        *
                   ********
 
+Extra functions:
+  -> make a separate module.
+  => done functions.[ch]
+
+Support Attribute value templates:
+  -> starts to be urgent. Design it in flexible ways but try to optimize
+     to handle most of it at the stylesheet parse time ...
+  => Done for the most part need to check all attributes in XSLT constructs
+     using them and use the dedicated readin function.
+
 Separate util module:
   -> macros, config, verbosity ?
   => xsltutils.[ch]
index ca041c2..67556c6 100644 (file)
@@ -42,6 +42,7 @@
 #include <libxml/xpath.h>
 #include <libxml/xpathInternals.h>
 #include <libxml/parserInternals.h>
+#include <libxml/uri.h>
 #include "xslt.h"
 #include "xsltInternals.h"
 #include "xsltutils.h"
@@ -110,7 +111,80 @@ isinf(double number)
  */
 void
 xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs){
-    TODO /* function */
+    xmlDocPtr doc;
+    xmlXPathObjectPtr obj;
+    xmlChar *base, *URI;
+
+
+    if ((nargs < 1) || (nargs > 2)) {
+        xsltGenericError(xsltGenericErrorContext,
+               "document() : invalid number of args %d\n", nargs);
+       ctxt->error = XPATH_INVALID_ARITY;
+       return;
+    }
+    if (ctxt->value == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+           "document() : invalid arg value\n");
+       ctxt->error = XPATH_INVALID_TYPE;
+       return;
+    }
+    if (ctxt->value->type == XPATH_NODESET) {
+       TODO
+        xsltGenericError(xsltGenericErrorContext,
+               "document() : with node-sets args not yet supported\n");
+       return;
+    }
+    /*
+     * Make sure it's converted to a string
+     */
+    xmlXPathStringFunction(ctxt, 1);
+    if (ctxt->value->type != XPATH_STRING) {
+       xsltGenericError(xsltGenericErrorContext,
+           "document() : invalid arg expecting a string\n");
+       ctxt->error = XPATH_INVALID_TYPE;
+       return;
+    }
+    obj = valuePop(ctxt);
+    if (obj->stringval == NULL) {
+       valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+    } else {
+        base = xmlNodeGetBase(ctxt->context->doc, ctxt->context->node);
+       URI = xmlBuildURI(obj->stringval, base);
+       if (base != NULL)
+           xmlFree(base);
+        if (URI == NULL) {
+           valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+       } else {
+           doc = xmlParseDoc(URI);
+           if (doc == NULL)
+               valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+           else {
+               xsltTransformContextPtr tctxt;
+
+               /*
+                * link it to the context for cleanup when done
+                */
+               tctxt = (xsltTransformContextPtr) ctxt->context->extra;
+               if (tctxt == NULL) {
+                   xsltGenericError(xsltGenericErrorContext,
+                       "document() : internal error tctxt == NULL\n");
+                   xmlFreeDoc(doc);
+                   valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+               } else {
+                   /*
+                    * Keep a link from the context to be able to deallocate
+                    */
+                   doc->next = (xmlNodePtr) tctxt->extraDocs;
+                   tctxt->extraDocs = doc;
+
+                   /* TODO: use XPointer of HTML location for fragment ID */
+                   /* pbm #xxx can lead to location sets, not nodesets :-) */
+                    valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc));
+               }
+           }
+       }
+    }
+    xmlXPathFreeObject(obj);
 }
 
 /**
@@ -136,7 +210,40 @@ xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
  */
 void
 xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){
-    TODO /* function */
+    xmlXPathObjectPtr obj;
+    xmlChar *str;
+
+    if (nargs != 1) {
+        xsltGenericError(xsltGenericErrorContext,
+               "system-property() : expects one string arg\n");
+       ctxt->error = XPATH_INVALID_ARITY;
+       return;
+    }
+    if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
+       xsltGenericError(xsltGenericErrorContext,
+           "generate-id() : invalid arg expecting a string\n");
+       ctxt->error = XPATH_INVALID_TYPE;
+       return;
+    }
+    obj = valuePop(ctxt);
+    str = obj->stringval;
+    if (str == NULL) {
+       valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
+    } else {
+       xmlEntityPtr entity;
+
+       entity = xmlGetDocEntity(ctxt->context->doc, str);
+       if (entity == NULL) {
+           valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
+       } else {
+           if (entity->URI != NULL)
+               valuePush(ctxt, xmlXPathNewString(entity->URI));
+           else
+               valuePush(ctxt, xmlXPathNewString(
+                           xmlStrdup((const xmlChar *)"")));
+       }
+    }
+    xmlXPathFreeObject(obj);
 }
 
 /**
@@ -376,6 +483,7 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
        break;
     default:
        XP_ERROR(XPATH_INVALID_ARITY);
+       return;
     }
     
     valuePush(ctxt,
@@ -398,7 +506,54 @@ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
  */
 void
 xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){
-    TODO /* function */
+    xmlNodePtr cur = NULL;
+    unsigned int val;
+    xmlChar str[20];
+
+    if (nargs == 0) {
+       cur = ctxt->context->node;
+    } else if (nargs == 1) {
+       xmlXPathObjectPtr obj;
+       xmlNodeSetPtr nodelist;
+       int i, ret;
+
+       if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
+           ctxt->error = XPATH_INVALID_TYPE;
+           xsltGenericError(xsltGenericErrorContext,
+               "generate-id() : invalid arg expecting a node-set\n");
+           return;
+       }
+       obj = valuePop(ctxt);
+       nodelist = obj->nodesetval;
+       if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) {
+           ctxt->error = XPATH_INVALID_TYPE;
+           xsltGenericError(xsltGenericErrorContext,
+               "generate-id() : got an empty node-set\n");
+           xmlXPathFreeObject(obj);
+           return;
+       }
+       cur = nodelist->nodeTab[0];
+       for (i = 2;i <= nodelist->nodeNr;i++) {
+           ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]);
+           if (ret == -1)
+               cur = nodelist->nodeTab[i];
+       }
+       xmlXPathFreeObject(obj);
+    } else {
+        xsltGenericError(xsltGenericErrorContext,
+               "generate-id() : invalid number of args %d\n", nargs);
+       ctxt->error = XPATH_INVALID_ARITY;
+       return;
+    }
+    /*
+     * Okay this is ugly but should work, use the NodePtr address
+     * to forge the ID
+     */
+    val = (unsigned int) cur;
+    val >>= 2;
+    val |= 0xFFFFFF;
+    sprintf((char *)str, "id%10d", val);
+    valuePush(ctxt, xmlXPathNewString(str));
 }
 
 /**
@@ -411,7 +566,39 @@ xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){
  */
 void
 xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){
-    TODO /* function */
+    xmlXPathObjectPtr obj;
+    xmlChar *str;
+
+    if (nargs != 1) {
+        xsltGenericError(xsltGenericErrorContext,
+               "system-property() : expects one string arg\n");
+       ctxt->error = XPATH_INVALID_ARITY;
+       return;
+    }
+    if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
+       xsltGenericError(xsltGenericErrorContext,
+           "generate-id() : invalid arg expecting a string\n");
+       ctxt->error = XPATH_INVALID_TYPE;
+       return;
+    }
+    obj = valuePop(ctxt);
+    str = obj->stringval;
+    if (str == NULL) {
+       valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
+    } else if (!xmlStrcmp(str, (const xmlChar *)"xsl:version")) {
+       valuePush(ctxt, xmlXPathNewString(
+               (const xmlChar *)XSLT_DEFAULT_VERSION));
+    } else if (!xmlStrcmp(str, (const xmlChar *)"xsl:vendor")) {
+       valuePush(ctxt, xmlXPathNewString(
+               (const xmlChar *)XSLT_DEFAULT_VENDOR));
+    } else if (!xmlStrcmp(str, (const xmlChar *)"xsl:vendor-url")) {
+       valuePush(ctxt, xmlXPathNewString(
+               (const xmlChar *)XSLT_DEFAULT_URL));
+    } else {
+       /* TODO cheated with the QName resolution */
+       valuePush(ctxt, xmlXPathNewString((const xmlChar *)""));
+    }
+    xmlXPathFreeObject(obj);
 }
 
 /**
@@ -424,7 +611,23 @@ xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){
  */
 void
 xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
-    TODO /* function */
+    xmlXPathObjectPtr obj;
+
+    if (nargs != 1) {
+        xsltGenericError(xsltGenericErrorContext,
+               "element-available() : expects one string arg\n");
+       ctxt->error = XPATH_INVALID_ARITY;
+       return;
+    }
+    if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
+       xsltGenericError(xsltGenericErrorContext,
+           "element-available invalid arg expecting a string\n");
+       ctxt->error = XPATH_INVALID_TYPE;
+       return;
+    }
+    obj = valuePop(ctxt);
+    xmlXPathFreeObject(obj);
+    valuePush(ctxt, xmlXPathNewBoolean(0));
 }
 
 /**
@@ -437,7 +640,23 @@ xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
  */
 void
 xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
-    TODO /* function */
+    xmlXPathObjectPtr obj;
+
+    if (nargs != 1) {
+        xsltGenericError(xsltGenericErrorContext,
+               "function-available() : expects one string arg\n");
+       ctxt->error = XPATH_INVALID_ARITY;
+       return;
+    }
+    if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
+       xsltGenericError(xsltGenericErrorContext,
+           "function-available invalid arg expecting a string\n");
+       ctxt->error = XPATH_INVALID_TYPE;
+       return;
+    }
+    obj = valuePop(ctxt);
+    xmlXPathFreeObject(obj);
+    valuePush(ctxt, xmlXPathNewBoolean(0));
 }
 
 /**
@@ -450,7 +669,13 @@ xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){
  */
 void
 xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){
-    TODO /* function */
+    if (nargs != 0) {
+        xsltGenericError(xsltGenericErrorContext,
+               "document() : function uses no argument\n");
+       ctxt->error = XPATH_INVALID_ARITY;
+       return;
+    }
+    valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
 }
 
 /**
index 8a42a99..81eb3c9 100644 (file)
@@ -77,8 +77,16 @@ xsltNewTransformContext(void) {
  */
 void
 xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
+    xmlDocPtr doc, next;
+
     if (ctxt == NULL)
        return;
+    doc = ctxt->extraDocs;
+    while (doc != NULL) {
+       next = (xmlDocPtr) doc->next;
+       xmlFreeDoc(doc);
+       doc = next;
+    }
     if (ctxt->xpathCtxt != NULL)
        xmlXPathFreeContext(ctxt->xpathCtxt);
     xsltFreeVariableHashes(ctxt);
@@ -373,29 +381,16 @@ xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
        }
     }
 
-    value = xmlNodeListGetString(inst->doc, inst->children, 1);
+    value = xsltEvalTemplateString(ctxt, node, inst);
     if (value == NULL) {
        if (ns) {
-#if LIBXML_VERSION > 20211
            attr = xmlSetNsProp(ctxt->insert, ns, ncname, 
                                (const xmlChar *)"");
-#else
-           xsltGenericError(xsltGenericErrorContext,
-               "xsl:attribute: recompile against newer libxml version\n");
-           attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)"");
-#endif
        } else
            attr = xmlSetProp(ctxt->insert, ncname, (const xmlChar *)"");
     } else {
-       /* TODO: attribute value template */
        if (ns) {
-#if LIBXML_VERSION > 20211
            attr = xmlSetNsProp(ctxt->insert, ns, ncname, value);
-#else
-           xsltGenericError(xsltGenericErrorContext,
-               "xsl:attribute: recompile against newer libxml version\n");
-           attr = xmlSetProp(ctxt->insert, ncname, value);
-#endif
        } else
            attr = xmlSetProp(ctxt->insert, ncname, value);
        
index cf4b383..bc3e450 100644 (file)
@@ -21,7 +21,8 @@ extern "C" {
 #define XSLT_REGISTER_VARIABLE_LOOKUP(ctxt)                    \
     xmlXPathRegisterVariableLookup((ctxt)->xpathCtxt,          \
               xsltXPathVariableLookup, (void *)(ctxt));        \
-    xsltRegisterAllFunctions((ctxt)->xpathCtxt)
+    xsltRegisterAllFunctions((ctxt)->xpathCtxt);               \
+    (ctxt)->xpathCtxt->extra = ctxt
 
 /*
  * Interfaces for the variable module.
index 7f051ef..4d4898c 100644 (file)
@@ -493,12 +493,7 @@ xsltParseTemplateContent(xsltStylesheetPtr style, xsltTemplatePtr ret,
                                            XSLT_NAMESPACE);
                        if (prop != NULL) {
                            if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
-#if LIBXML_VERSION > 20211
                                text->name = xmlStringTextNoenc;
-#else
-                               xsltGenericError(xsltGenericErrorContext,
-"xsl:text disable-output-escaping need newer > 20211 libxml version\n");
-#endif
                            } else if (!xmlStrEqual(prop,
                                                    (const xmlChar *)"no")){
                                xsltGenericError(xsltGenericErrorContext,
index 02d3524..2c65836 100644 (file)
@@ -19,6 +19,8 @@ extern "C" {
  * Constants.
  */
 #define XSLT_DEFAULT_VERSION     "1.0"
+#define XSLT_DEFAULT_VENDOR      "libxslt"
+#define XSLT_DEFAULT_URL         "http://xmlsoft.org/XSLT/"
 #define XSLT_NAMESPACE ((xmlChar *) "http://www.w3.org/1999/XSL/Transform")
 
 #ifdef __cplusplus
index da00c13..7a64585 100644 (file)
@@ -142,6 +142,7 @@ struct _xsltTransformContext {
     xmlXPathContextPtr xpathCtxt;      /* the XPath context */
     void *variablesHash;               /* hash table or wherever variables
                                           informations are stored */
+    xmlDocPtr extraDocs;               /* extra docs parsed by document() */
 };
 
 /*
index 1858d6e..ba2457a 100644 (file)
@@ -222,12 +222,7 @@ xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
         (xmlStrEqual(style->method, (const xmlChar *) "html"))) ||
        ((root != NULL) &&
         (xmlStrEqual(root->name, (const xmlChar *) "html")))){
-#if LIBXML_VERSION > 20211
        htmlDocContentDumpOutput(buf, result, (const char *) encoding);
-#else
-       xsltGenericError(xsltGenericErrorContext,
-               "HTML output requires libxml version > 2.2.11\n");
-#endif
     } else if ((style->method != NULL) &&
               (xmlStrEqual(style->method, (const xmlChar *) "text"))) {
        xmlNodePtr cur;