Work done on namespace support:
authorDaniel Veillard <veillard@src.gnome.org>
Sun, 28 Jan 2001 16:27:44 +0000 (16:27 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Sun, 28 Jan 2001 16:27:44 +0000 (16:27 +0000)
- FEATURES TODO: updates
- libxslt/namespaces.[ch] libxslt/templates.c libxslt/transform.c
  libxslt/xslt.c libxslt/xsltInternals.h: added support for
  namespace aliases and cleaned up the overall namespace related
  code. This materialize as a new module.
Daniel

ChangeLog
FEATURES
TODO
libxslt/Makefile.am
libxslt/namespaces.c [new file with mode: 0644]
libxslt/namespaces.h [new file with mode: 0644]
libxslt/templates.c
libxslt/transform.c
libxslt/xslt.c
libxslt/xsltInternals.h

index cd2eefd..ea0627e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Sun Jan 28 17:25:35 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+       * FEATURES TODO: updates
+       * libxslt/namespaces.[ch] libxslt/templates.c libxslt/transform.c
+         libxslt/xslt.c libxslt/xsltInternals.h: added support for
+         namespace aliases and cleaned up the overall namespace related
+         code. This materialize as a new module.
+
 Sun Jan 28 08:41:10 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
        * configure.in libxslt.spec.in: changes needed for libxml2-devel
index 16e2efa..08e00c8 100644 (file)
--- a/FEATURES
+++ b/FEATURES
@@ -45,9 +45,9 @@ YES                   name = qname
 YES                    priority = number 
 NO                     mode = qname
 
-NO                 xsl:namespace-alias
-NO                     stylesheet-prefix = prefix | "#default"
-NO                     result-prefix = prefix | "#default"
+YES                xsl:namespace-alias
+YES                    stylesheet-prefix = prefix | "#default"
+YES                    result-prefix = prefix | "#default"
 
 NO                 xsl:attribute-set
 NO                     name = qname 
@@ -99,7 +99,7 @@ NO                    use-attribute-sets = qnames
 
 YES                xsl:attribute
 YES                    name = { qname }
-YES                    namespace = { uri-reference }
+NO                     namespace = { uri-reference }
 
 YES                xsl:text
 YES                    disable-output-escaping = "yes" | "no"
@@ -193,7 +193,7 @@ YES             Built-in Template Rules
 YES                    match="*|/"
 YES                    match="text()|@*"
 YES                    match="processing-instruction()|comment()"
-NO                     Namespace
+YES                    Namespace
 NO                     Mode
 
 NO                 Extension Elements
diff --git a/TODO b/TODO
index 47d246b..2253637 100644 (file)
--- a/TODO
+++ b/TODO
@@ -5,9 +5,6 @@
                   ********
 
 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:
@@ -92,3 +89,8 @@ Pattern tester:
   -> also put fast lookup for "text()", "comment()", "node()"
      based patterns lists.
   => done
+
+Doc:
+  - put a page at http://xmlsoft.org/XSLT/
+  - generate/transform the DocBook to HTML
+  - add HTML to package
index 6036591..f582bf1 100644 (file)
@@ -12,6 +12,7 @@ xsltinc_HEADERS =                     \
        templates.h                     \
        variables.h                     \
        functions.h                     \
+       namespaces.h                    \
        transform.h                     \
        xsltInternals.h
 
@@ -22,6 +23,7 @@ libxslt_la_SOURCES =                  \
        templates.c                     \
        variables.c                     \
        functions.c                     \
+       namespaces.c                    \
        transform.c
 
 
diff --git a/libxslt/namespaces.c b/libxslt/namespaces.c
new file mode 100644 (file)
index 0000000..9842453
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * namespaces.c: Implementation of the XSLT namespaces handling
+ *
+ * Reference:
+ *   http://www.w3.org/TR/1999/REC-xslt-19991116
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@imag.fr
+ */
+
+#include "xsltconfig.h"
+
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+#ifdef HAVE_NAN_H
+#include <nan.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/hash.h>
+#include <libxml/xmlerror.h>
+#include <libxml/uri.h>
+#include "xslt.h"
+#include "xsltInternals.h"
+#include "xsltutils.h"
+#include "namespaces.h"
+
+
+
+/************************************************************************
+ *                                                                     *
+ *                     Module interfaces                               *
+ *                                                                     *
+ ************************************************************************/
+
+/**
+ * xsltNamespaceAlias:
+ * @style:  the XSLT stylesheet
+ * @node:  the xsl:namespace-alias node
+ *
+ * Read the stylesheet-prefix and result-prefix attributes, register
+ * them as well as the corresponding namespace.
+ */
+void
+xsltNamespaceAlias(xsltStylesheetPtr style, xmlNodePtr node) {
+    xmlChar *sprefix;
+    xmlNsPtr sNs;
+    xmlChar *rprefix;
+    xmlNsPtr rNs;
+
+    sprefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix",
+                          XSLT_NAMESPACE);
+    if (sprefix == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+           "namespace-alias: stylesheet-prefix attribute missing\n");
+       return;
+    }
+    rprefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix",
+                          XSLT_NAMESPACE);
+    if (rprefix == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+           "namespace-alias: result-prefix attribute missing\n");
+       goto error;
+    }
+    if (xmlStrEqual(sprefix, (const xmlChar *)"#default")) {
+       sNs = xmlSearchNs(node->doc, node, NULL);
+    } else {
+       sNs = xmlSearchNs(node->doc, node, sprefix);
+    }
+    if ((sNs == NULL) || (sNs->href == NULL)) {
+       xsltGenericError(xsltGenericErrorContext,
+           "namespace-alias: prefix %s not bound to any namespace\n",
+                        sprefix);
+       goto error;
+    }
+    if (xmlStrEqual(rprefix, (const xmlChar *)"#default")) {
+       rNs = xmlSearchNs(node->doc, node, NULL);
+    } else {
+       rNs = xmlSearchNs(node->doc, node, rprefix);
+    }
+    if ((rNs == NULL) || (rNs->href == NULL)) {
+       xsltGenericError(xsltGenericErrorContext,
+           "namespace-alias: prefix %s not bound to any namespace\n",
+                        rprefix);
+       goto error;
+    }
+    if (style->nsAliases == NULL)
+       style->nsAliases = xmlHashCreate(10);
+    if (style->nsAliases == NULL) {
+       xsltGenericError(xsltGenericErrorContext,
+           "namespace-alias: cannot create hash table\n");
+       goto error;
+    }
+    xmlHashAddEntry((xmlHashTablePtr) style->nsAliases,
+                   sNs->href, (void *) rNs->href);
+
+error:
+    if (sprefix != NULL)
+       xmlFree(sprefix);
+    if (rprefix != NULL)
+       xmlFree(rprefix);
+}
+
+/**
+ * xsltGetNamespace:
+ * @ctxt:  a transformation context
+ * @cur:  the input node
+ * @ns:  the namespace
+ * @out:  the output node (or its parent)
+ *
+ * Find the right namespace value for this prefix, if needed create
+ * and add a new namespace decalaration on the node
+ * Handle namespace aliases
+ *
+ * Returns the namespace node to use or NULL
+ */
+xmlNsPtr
+xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns,
+                xmlNodePtr out) {
+    xmlNsPtr ret;
+    const xmlChar *URI;
+
+    if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (ns == NULL))
+       return(NULL);
+    if ((out->type == XML_ELEMENT_NODE) && (out->ns != NULL) &&
+        ((out->ns->href != NULL) && (ns->href != NULL) &&
+         (xmlStrEqual(out->ns->href, ns->href)))) {
+       return(out->ns);
+    }
+
+    /* TODO apply cascading */
+    if (ctxt->style->nsAliases != NULL) {
+       URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases, ns->href);
+       if (URI == NULL)
+           URI = ns->href;
+    } else
+       URI = ns->href;
+
+    ret = xmlSearchNsByHref(out->doc, out, URI);
+    if (ret == NULL) {
+       if (out->type == XML_ELEMENT_NODE)
+           ret = xmlNewNs(out, ns->href, ns->prefix);
+    }
+    return(ret);
+}
+
+/**
+ * xsltCopyNamespaceList:
+ * @ctxt:  a transformation context
+ * @node:  the target node
+ * @cur:  the first namespace
+ *
+ * Do a copy of an namespace list. If @node is non-NULL the
+ * new namespaces are added automatically. This handles namespaces
+ * aliases
+ *
+ * Returns: a new xmlNsPtr, or NULL in case of error.
+ */
+xmlNsPtr
+xsltCopyNamespaceList(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                     xmlNsPtr cur) {
+    xmlNsPtr ret = NULL;
+    xmlNsPtr p = NULL,q;
+    const xmlChar *URI;
+
+    while (cur != NULL) {
+       if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) {
+           /* TODO apply cascading */
+           URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases,
+                                                 cur->href);
+           if (URI != NULL) {
+               q = xmlNewNs(node, URI, cur->prefix);
+           } else {
+               q = xmlNewNs(node, cur->href, cur->prefix);
+           }
+           if (p == NULL) {
+               ret = p = q;
+           } else {
+               p->next = q;
+               p = q;
+           }
+       }
+       cur = cur->next;
+    }
+    return(ret);
+}
+
diff --git a/libxslt/namespaces.h b/libxslt/namespaces.h
new file mode 100644 (file)
index 0000000..14c2f4d
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * namespaces.h: interface for the XSLT namespace handling
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@imag.fr
+ */
+
+#ifndef __XML_XSLT_NAMESPACES_H__
+#define __XML_XSLT_NAMESPACES_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void           xsltNamespaceAlias      (xsltStylesheetPtr style,
+                                        xmlNodePtr node);
+xmlNsPtr       xsltGetNamespace        (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr cur,
+                                        xmlNsPtr ns,
+                                        xmlNodePtr out);
+xmlNsPtr       xsltCopyNamespaceList   (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr node,
+                                        xmlNsPtr cur);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_XSLT_NAMESPACES_H__ */
+
index ebc0b4d..66d6e40 100644 (file)
@@ -25,6 +25,7 @@
 #include "functions.h"
 #include "templates.h"
 #include "transform.h"
+#include "namespaces.h"
 
 #define DEBUG_TEMPLATES
 
@@ -264,23 +265,7 @@ xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
     if (ret == NULL) return(NULL);
     ret->parent = target;
     
-    if ((cur->ns != NULL) && (target != NULL)) {
-       if ((target != NULL) && (target->ns != NULL) &&
-           (xmlStrEqual(target->ns->href, cur->ns->href))) {
-           ret->ns = target->ns;
-       } else {
-           xmlNsPtr ns;
-
-           ns = xmlSearchNsByHref(ctxt->output, target, cur->ns->href);
-           if (ns != NULL) {
-               ret->ns = ns;
-           } else {
-               ns = xmlNewNs(target, cur->ns->href, cur->ns->prefix);
-               ret->ns = ns;
-           }
-       }
-    } else
-        ret->ns = NULL;
+    ret->ns = xsltGetNamespace(ctxt, cur->parent, cur->ns, target);
 
     if (cur->children != NULL) {
        xmlChar *in = xmlNodeListGetString(ctxt->doc, cur->children, 1);
index 81eb3c9..171e45b 100644 (file)
@@ -30,6 +30,7 @@
 #include "pattern.h"
 #include "transform.h"
 #include "variables.h"
+#include "namespaces.h"
 #include "templates.h"
 
 #define DEBUG_PROCESS
@@ -349,12 +350,6 @@ xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
             "xslt:attribute : node has already children\n");
        return;
     }
-    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"namespace");
-    if (prop != NULL) {
-       TODO /* xsl:attribute namespace */
-       xmlFree(prop);
-       return;
-    }
     prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"name");
     if (prop == NULL) {
        xsltGenericError(xsltGenericErrorContext,
@@ -373,13 +368,23 @@ xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node,
             "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);
+    prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"namespace");
+    if (prop != NULL) {
+       TODO /* xsl:attribute namespace */
+       xmlFree(prop);
+       return;
+    } else {
+       if (prefix != NULL) {
+           ns = xmlSearchNs(inst->doc, inst, prefix);
+           if (ns == NULL) {
+               xsltGenericError(xsltGenericErrorContext,
+                   "no namespace bound to prefix %s\n", prefix);
+           } else {
+               ns = xsltGetNamespace(ctxt, inst, ns, ctxt->insert);
+           }
        }
     }
+    
 
     value = xsltEvalTemplateString(ctxt, node, inst);
     if (value == NULL) {
@@ -528,34 +533,9 @@ xsltCopyNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
         * Add namespaces as they are needed
         */
        if (node->nsDef != NULL)
-           copy->nsDef = xmlCopyNamespaceList(node->nsDef);
+           xsltCopyNamespaceList(ctxt, copy, node->nsDef);
        if (node->ns != NULL) {
-           /*
-            * optimization, if the namespace is already the
-            * on on the parent node, reuse it directly
-            *
-            * TODO: check possible mess with xmlCopyNamespaceList
-            */
-           if ((insert->type == XML_ELEMENT_NODE) &&
-               (insert->ns != NULL) && 
-               (xmlStrEqual(insert->ns->href, node->ns->href))) {
-               copy->ns = insert->ns;
-           } else {
-               xmlNsPtr ns;
-
-               /*
-                * Look in the output tree if the namespace is
-                * already in scope.
-                */
-               ns = xmlSearchNsByHref(ctxt->output, copy,
-                                      node->ns->href);
-               if (ns != NULL)
-                   copy->ns = ns;
-               else {
-                   ns = xmlNewNs(copy, node->ns->href,
-                                 node->ns->prefix);
-               }
-           }
+           copy->ns = xsltGetNamespace(ctxt, node, node->ns, insert);
        }
     } else {
        xsltGenericError(xsltGenericErrorContext,
@@ -697,7 +677,7 @@ xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
     xmlChar *prefix = NULL;
     xmlNsPtr ns = NULL;
     xsltTemplatePtr template;
-    xmlNodePtr cur;
+    xmlNodePtr cur = NULL;
     int has_param = 0;
 
 
index 4d4898c..66a838b 100644 (file)
@@ -24,6 +24,7 @@
 #include "xsltInternals.h"
 #include "pattern.h"
 #include "variables.h"
+#include "namespaces.h"
 #include "xsltutils.h"
 
 #define DEBUG_PARSING
@@ -784,7 +785,7 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
 #endif
            xsltParseStylesheetTemplate(style, cur);
         } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
-           TODO /* Handle namespace-alias */
+           xsltNamespaceAlias(style, cur);
        } else {
            xsltGenericError(xsltGenericErrorContext,
                "xsltParseStylesheetTop: ignoring unknown %s element\n",
index 7250e7c..9056dc5 100644 (file)
@@ -102,6 +102,11 @@ struct _xsltStylesheet {
     void *commentMatch;                /* template based on comment() */
     
     /*
+     * Namespace aliases
+     */
+    xmlHashTablePtr nsAliases; /* the namespace alias hash tables */
+
+    /*
      * Output related stuff.
      */
     xmlChar *method;           /* the output method */