fixing bug #134500 on namespace lookup for attribute which sometimes lead
authorDaniel Veillard <veillard@src.gnome.org>
Sun, 16 May 2004 23:40:08 +0000 (23:40 +0000)
committerDaniel Veillard <veillard@src.gnome.org>
Sun, 16 May 2004 23:40:08 +0000 (23:40 +0000)
* libxslt/namespaces.c libxslt/namespaces.h libxslt/templates.c
  libxslt/transform.c: fixing bug #134500 on namespace lookup for
  attribute which sometimes lead to default namespace
* tests/general/bug-150*, tests/docs/bug-150.xml,
  tests/general/Makefile.am, tests/docs/Makefile.am: added
  regression test for bug #134500
Daniel

ChangeLog
libxslt/namespaces.c
libxslt/namespaces.h
libxslt/templates.c
libxslt/transform.c
tests/docs/Makefile.am
tests/docs/bug-150.xml [new file with mode: 0644]
tests/general/Makefile.am
tests/general/bug-150.out [new file with mode: 0644]
tests/general/bug-150.xsl [new file with mode: 0644]

index e3d0d59..f1cd512 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Sun May 16 19:39:44 CEST 2004 Daniel Veillard <daniel@veillard.com>
+
+       * libxslt/namespaces.c libxslt/namespaces.h libxslt/templates.c
+         libxslt/transform.c: fixing bug #134500 on namespace lookup for
+         attribute which sometimes lead to default namespace
+       * tests/general/bug-150*, tests/docs/bug-150.xml,
+         tests/general/Makefile.am, tests/docs/Makefile.am: added
+         regression test for bug #134500
+
 Sun May 16 18:09:36 CEST 2004 Daniel Veillard <daniel@veillard.com>
 
        * libexslt/date.h: fixing a small portability problem on Solaris
index 1650ff9..8ed2bb2 100644 (file)
@@ -121,6 +121,161 @@ error:
 }
 
 /**
+ * xsltNsInScope:
+ * @doc:  the document
+ * @node:  the current node
+ * @ancestor:  the ancestor carrying the namespace
+ * @prefix:  the namespace prefix
+ *
+ * Copy of xmlNsInScope which is not public ...
+ * 
+ * Returns 1 if true, 0 if false and -1 in case of error.
+ */
+static int
+xsltNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
+             xmlNodePtr ancestor, const xmlChar * prefix)
+{
+    xmlNsPtr tst;
+
+    while ((node != NULL) && (node != ancestor)) {
+        if ((node->type == XML_ENTITY_REF_NODE) ||
+            (node->type == XML_ENTITY_NODE) ||
+            (node->type == XML_ENTITY_DECL))
+            return (-1);
+        if (node->type == XML_ELEMENT_NODE) {
+            tst = node->nsDef;
+            while (tst != NULL) {
+                if ((tst->prefix == NULL)
+                    && (prefix == NULL))
+                    return (0);
+                if ((tst->prefix != NULL)
+                    && (prefix != NULL)
+                    && (xmlStrEqual(tst->prefix, prefix)))
+                    return (0);
+                tst = tst->next;
+            }
+        }
+        node = node->parent;
+    }
+    if (node != ancestor)
+        return (-1);
+    return (1);
+}
+
+/**
+ * xsltSearchPlainNsByHref:
+ * @doc:  the document
+ * @node:  the current node
+ * @href:  the namespace value
+ *
+ * Search a Ns aliasing a given URI and without a NULL prefix.
+ * Recurse on the parents until it finds
+ * the defined namespace or return NULL otherwise.
+ * Returns the namespace pointer or NULL.
+ */
+static xmlNsPtr
+xsltSearchPlainNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
+{
+    xmlNsPtr cur;
+    xmlNodePtr orig = node;
+
+    if ((node == NULL) || (href == NULL))
+        return (NULL);
+
+    while (node != NULL) {
+        if ((node->type == XML_ENTITY_REF_NODE) ||
+            (node->type == XML_ENTITY_NODE) ||
+            (node->type == XML_ENTITY_DECL))
+            return (NULL);
+        if (node->type == XML_ELEMENT_NODE) {
+            cur = node->nsDef;
+            while (cur != NULL) {
+                if ((cur->href != NULL) && (cur->prefix != NULL) &&
+                   (href != NULL) && (xmlStrEqual(cur->href, href))) {
+                   if (xsltNsInScope(doc, orig, node, cur->href) == 1)
+                       return (cur);
+                }
+                cur = cur->next;
+            }
+            if (orig != node) {
+                cur = node->ns;
+                if (cur != NULL) {
+                    if ((cur->href != NULL) && (cur->prefix != NULL) &&
+                       (href != NULL) && (xmlStrEqual(cur->href, href))) {
+                       if (xsltNsInScope(doc, orig, node, cur->href) == 1)
+                           return (cur);
+                    }
+                }
+            }    
+        }
+        node = node->parent;
+    }
+    return (NULL);
+}
+
+/**
+ * xsltGetPlainNamespace:
+ * @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 and make sure the prefix is not NULL, this
+ * is needed for attributes.
+ *
+ * Returns the namespace node to use or NULL
+ */
+xmlNsPtr
+xsltGetPlainNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur,
+                      xmlNsPtr ns, xmlNodePtr out) {
+    xsltStylesheetPtr style;
+    xmlNsPtr ret;
+    const xmlChar *URI = NULL; /* the replacement URI */
+
+    if ((ctxt == NULL) || (cur == NULL) || (out == NULL) || (ns == NULL))
+       return(NULL);
+
+    style = ctxt->style;
+    while (style != NULL) {
+       if (style->nsAliases != NULL)
+           URI = (const xmlChar *) xmlHashLookup(style->nsAliases, ns->href);
+       if (URI != NULL)
+           break;
+
+       style = xsltNextImport(style);
+    }
+
+    if (URI == NULL)
+       URI = ns->href;
+
+    if ((out->parent != NULL) &&
+       (out->parent->type == XML_ELEMENT_NODE) &&
+       (out->parent->ns != NULL) &&
+       (out->parent->ns->prefix != NULL) &&
+       (xmlStrEqual(out->parent->ns->href, URI)))
+       ret = out->parent->ns;
+    else {
+       if (ns->prefix != NULL) {
+           ret = xmlSearchNs(out->doc, out, ns->prefix);
+           if ((ret == NULL) || (!xmlStrEqual(ret->href, URI)) ||
+               (ret->prefix == NULL)) {
+               ret = xsltSearchPlainNsByHref(out->doc, out, URI);
+           }
+       } else {
+           ret = xsltSearchPlainNsByHref(out->doc, out, URI);
+       }
+    }
+
+    if (ret == NULL) {
+       if (out->type == XML_ELEMENT_NODE)
+           ret = xmlNewNs(out, URI, ns->prefix);
+    }
+    return(ret);
+}
+
+/**
  * xsltGetSpecialNamespace:
  * @ctxt:  a transformation context
  * @cur:  the input node
index bf70b46..c92eb1a 100644 (file)
@@ -27,6 +27,11 @@ XSLTPUBFUN xmlNsPtr XSLTCALL
                                         xmlNsPtr ns,
                                         xmlNodePtr out);
 XSLTPUBFUN xmlNsPtr XSLTCALL   
+               xsltGetPlainNamespace   (xsltTransformContextPtr ctxt,
+                                        xmlNodePtr cur,
+                                        xmlNsPtr ns,
+                                        xmlNodePtr out);
+XSLTPUBFUN xmlNsPtr XSLTCALL   
                xsltGetSpecialNamespace (xsltTransformContextPtr ctxt,
                                         xmlNodePtr cur,
                                         const xmlChar *URI,
index e38a068..a2af1b2 100644 (file)
@@ -478,7 +478,7 @@ xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
     } else {
         /* create a new attribute */
        if (cur->ns != NULL)
-           ns = xsltGetNamespace(ctxt, cur->parent, cur->ns, target);
+           ns = xsltGetPlainNamespace(ctxt, cur->parent, cur->ns, target);
        else
            ns = NULL;
        /* TODO output doc->dict, use xmlNewNsPropEatName() instead */
index 20ed119..f99c0f9 100644 (file)
@@ -742,7 +742,7 @@ xsltCopyProp(xsltTransformContextPtr ctxt, xmlNodePtr target,
        return(NULL);
 
     if (attr->ns != NULL) {
-       ns = xsltGetNamespace(ctxt, attr->parent, attr->ns, target);
+       ns = xsltGetPlainNamespace(ctxt, attr->parent, attr->ns, target);
     } else {
        ns = NULL;
     }
index e99d788..a0506eb 100644 (file)
@@ -149,6 +149,7 @@ EXTRA_DIST =        \
        bug-147.xml \
        bug-148.xml \
        bug-149.xml \
+       bug-150.xml \
        character.xml \
        array.xml \
        items.xml
diff --git a/tests/docs/bug-150.xml b/tests/docs/bug-150.xml
new file mode 100644 (file)
index 0000000..69d62f2
--- /dev/null
@@ -0,0 +1 @@
+<doc/>
index e8edbe9..452e97b 100644 (file)
@@ -157,6 +157,7 @@ EXTRA_DIST = \
     bug-147-4.imp bug-147-5.imp bug-147-6.imp \
     bug-148.out bug-148.xsl \
     bug-149.out bug-149.xsl \
+    bug-150.out bug-150.xsl \
     character.out character.xsl \
     character2.out character2.xsl \
     itemschoose.out itemschoose.xsl \
diff --git a/tests/general/bug-150.out b/tests/general/bug-150.out
new file mode 100644 (file)
index 0000000..7a342d6
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<root xmlns="urn:A" xmlns:b="urn:B" xmlns:a="urn:A"><Product a:ID="1001"/></root>
diff --git a/tests/general/bug-150.xsl b/tests/general/bug-150.xsl
new file mode 100644 (file)
index 0000000..e5ace1d
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0">
+  <xsl:template match="/">
+    <root xmlns="urn:A" xmlns:b="urn:B" xmlns:a="urn:A">
+      <Product a:ID="1001"/>
+    </root>
+  </xsl:template>
+</xsl:stylesheet>