You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@xalan.apache.org by Sc...@lotus.com on 2000/07/21 01:18:07 UTC

Re: Namespace nodes not explicitly declared in a context node

This patch has a bit of a problem.  I think you tested it with the Xerces
DOM, but not with the DTM.  Since the DTM is not mutable, and is a pretty
small subset of the DOM, it breaks badly.  I propose changing your
AttrProxy class to something along the lines of:

  /**
   * Tricky implementation to realize returning correct namespace nodes.
   * // PATCH {blocks} PR:DMAN4KPPSQ Submitted by:<ke...@haun.org>
namespace::* axis fix
   */
  private static class AttrProxy implements Attr {
    String m_name;
    String m_value;
    Element owner;

    AttrProxy(Node owner, Document factory, String name, String value) {
      m_name = name;
      m_value = value;
      this.owner = (Element)owner;
    }

    AttrProxy(AttrProxy copyFrom) {
      m_name = copyFrom.m_name;
      m_value = copyFrom.m_value;
      owner = copyFrom.owner;
    }

    public Element getOwnerElement() {
      return this.owner;
    }

    public String getName() {  return m_name; }
    public boolean getSpecified() {  return false; }
    public String getValue() {  return m_value; }
    public void setValue(String value) {  m_name = value;  }

    public Node appendChild(Node newChild)
    {
      /* never happens... should assert. */
      return null;
    }
    public Node cloneNode(boolean deep)
    {
      return new AttrProxy(this);
    }

    public NamedNodeMap getAttributes() {  return null; /* a problem */  }
    public NodeList getChildNodes() {  return null; /* never happens */  }
    public Node getFirstChild() {  return null;  }
    public Node getLastChild() {  return null;  }
    public String getLocalName()
    {
      return m_name;
    }
    public String getNamespaceURI()
    {
      return null;  // ??
    }
    public Node getNextSibling()
    {
      return null; // ??
    }
    public String getNodeName() {  return m_name;  }

    public short getNodeType() {  return Node.ATTRIBUTE_NODE;  }
    public String getNodeValue() {  return m_value;  }
    public Document getOwnerDocument()
    {  return this.owner.getOwnerDocument();  }
    public Node getParentNode() {  return null;  }
    public String getPrefix() {  return "xmlns"; /* I guess */  }
    public Node getPreviousSibling() {  return null;  }
    public boolean hasChildNodes() {  return false;  }
    public Node insertBefore(Node newChild, Node refChild) {
      return null; /* never happens */  }
    public void normalize() {  /* never happens -- can't mutate */  }
    public Node removeChild(Node oldChild) {  return null;  }
    public Node replaceChild(Node newChild, Node oldChild)
    {
      return null;
    }
    public void setNodeValue(String nodeValue) {  /* never happens -- can't
mutate */  }
    public void setPrefix(String prefix) {  /* never happens -- can't
mutate */  }
    public boolean supports(String feature, String version) {
      return false; /* don't support anything... :-) */  }
  }

The not implemented stuff should really throw an exception.

Can you live with this?

It has another problem in that two invocations won't return the same nodes,
which is a problem for creating unique IDs.   In general, there may be
problems with mixing this proxy with other nodes in terms of the liaison
handling.  I'll have to work on this some more.

-scott






TAMURA Kent <ke...@hauN.org> on 05/29/2000 06:25:55 AM

To:   xalan-dev@xml.apache.org
Subject:  Re: Namespace nodes not explicitly declared in a context node

I wrote:
> In Xalan-J 1.0.1 XPath processing, namespace nodes not explicitly
> declared in a context node are not selected.

> It seems this problem is solved by modifying
> org.apache.xalan.xpath.SimpleNodeLocator.findNamespace().
>
> # I'm not a member of this mailing list.

The following patch fixes this problem.  I don't know whether the patch
make wrong influence :-)
--
TAMURA Kent

Index: xml-xalan/src/org/apache/xalan/xpath/SimpleNodeLocator.java
===================================================================
RCS file:
/home/cvspublic/xml-xalan/src/org/apache/xalan/xpath/SimpleNodeLocator.java,v

retrieving revision 1.23
diff -u -r1.23 SimpleNodeLocator.java
--- xml-xalan/src/org/apache/xalan/xpath/SimpleNodeLocator.java
2000/05/17 22:39:40       1.23
+++ xml-xalan/src/org/apache/xalan/xpath/SimpleNodeLocator.java
2000/05/29 10:18:19
@@ -60,7 +60,8 @@
 import java.io.*;
 import org.w3c.dom.*;
 import org.apache.xalan.xpath.res.XPATHErrorResources;
-import  org.apache.xalan.xpath.xml.ProblemListenerDefault;
+import org.apache.xalan.xpath.xml.ProblemListenerDefault;
+import org.apache.xalan.xpath.xml.PrefixResolverDefault;

 /**
  * <meta name="usage" content="advanced"/>
@@ -675,7 +676,91 @@
     }
     return subQueryResults;
   }
-
+
+  /**
+   * Tricky implementation to realize returning correct namespace nodes.
+   */
+  private static class AttrProxy implements Attr {
+    Attr real;
+    Element owner;
+    AttrProxy(Node owner, Document factory, String name, String value) {
+      this.real = factory.createAttribute(name);
+      this.real.setValue(value);
+      this.owner = (Element)owner;
+    }
+    public Element getOwnerElement() {
+      return this.owner;
+    }
+
+    public String getName() {  return this.real.getName(); }
+    public boolean getSpecified() {  return false; }
+    public String getValue() {  return this.real.getValue(); }
+    public void setValue(String value) {  this.real.setValue(value); }
+
+    public Node appendChild(Node newChild) {  return
this.real.appendChild(newChild);  }
+    public Node cloneNode(boolean deep) {  return
this.real.cloneNode(deep);  }
+    public NamedNodeMap getAttributes() {  return this.real.getAttributes
();  }
+    public NodeList getChildNodes() {  return this.real.getChildNodes();
}
+    public Node getFirstChild() {  return this.real.getFirstChild();  }
+    public Node getLastChild() {  return this.real.getLastChild();  }
+    public String getLocalName() {  return this.real.getLocalName();  }
+    public String getNamespaceURI() {  return this.real.getNamespaceURI();
}
+    public Node getNextSibling() {  return this.real.getNextSibling();  }
+    public String getNodeName() {  return this.real.getNodeName();  }
+    public short getNodeType() {  return this.real.getNodeType();  }
+    public String getNodeValue() {  return this.real.getNodeValue();  }
+    public Document getOwnerDocument() {  return
this.real.getOwnerDocument();  }
+    public Node getParentNode() {  return this.real.getParentNode();  }
+    public String getPrefix() {  return this.real.getPrefix();  }
+    public Node getPreviousSibling() {  return
this.real.getPreviousSibling();  }
+    public boolean hasChildNodes() {  return this.real.hasChildNodes();  }
+    public Node insertBefore(Node newChild, Node refChild) {
+      return this.real.insertBefore(newChild, refChild);  }
+    public void normalize() {  this.real.normalize();  }
+    public Node removeChild(Node oldChild) {  return
this.real.removeChild(oldChild);  }
+    public Node replaceChild(Node newChild, Node oldChild) {
+      return this.real.replaceChild(newChild, oldChild);  }
+    public void setNodeValue(String nodeValue) {
this.real.setNodeValue(nodeValue);  }
+    public void setPrefix(String prefix) {  this.real.setPrefix(prefix);
}
+    public boolean supports(String feature, String version) {
+      return this.real.supports(feature, version);  }
+  }
+
+  private static final String S_XMLNAMESPACEURI =
PrefixResolverDefault.S_XMLNAMESPACEURI;
+  /**
+   * Collects all namespace nodes that are effective in the
<var>startNode<var>.
+   * @param startNode A target element.
+   * @return A hashtable; A key in the result is an attribute names such
as "xmlns", "xmlns:foo".
+   *         An element in the result is an <code>Attr</code> instance.
+   */
+  public static Hashtable collectNamespaceNodesInAnchestors(Node
startNode) {
+    Node node = startNode;
+    Hashtable nsnodes = new Hashtable();
+    Document factory = startNode.getOwnerDocument(); // Null-check is not
needed.
+    nsnodes.put("xmlns:xml", new AttrProxy(startNode, factory,
"xmlns:xml", S_XMLNAMESPACEURI));
+    do {
+      NamedNodeMap attributeList = node.getAttributes();
+      if (attributeList != null) {
+        int nAttrs = attributeList.getLength();
+        for (int j = 0; j < nAttrs; j++) {
+          Attr attr = (Attr)attributeList.item(j);
+          String attrName = attr.getNodeName();
+          if (attrName.equals("xmlns") || attrName.startsWith("xmlns:")) {
+            if (!nsnodes.containsKey(attrName)) {
+              if (node == startNode) {
+                nsnodes.put(attrName, attr);
+              } else {
+                Attr newAttr = new AttrProxy(startNode, factory, attrName,
attr.getNodeValue());
+                nsnodes.put(attrName, newAttr);
+              }
+            }
+          }
+        }
+      }
+    } while ((node = node.getParentNode()) != null);
+    return nsnodes;
+  }
+
   /**
    * Add the namespace node of the context.
    * @param xpath The xpath that is executing.
@@ -696,18 +781,15 @@
     opPos = xpath.getFirstChildPosOfStep(opPos);
     if( (null != context) && (context.getNodeType()==Node.ELEMENT_NODE) )
     {
-      NamedNodeMap attributeList = context.getAttributes();
-      if( attributeList != null )
-      {
-        int nAttrs = attributeList.getLength();
-        for( int j=0; j < nAttrs; j++ )
+      Hashtable nsnodes = collectNamespaceNodesInAnchestors(context);
+      Enumeration enum = nsnodes.keys();
+      while (enum.hasMoreElements()) {
+        String attrName = (String)enum.nextElement();
+        Attr attr = (Attr)nsnodes.get(attrName);
+        if(XPath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, attr,
opPos, argLen, stepType))
         {
-          Attr attr = (Attr)attributeList.item(j);
-          if(XPath.MATCH_SCORE_NONE != nodeTest(xpath, execContext, attr,
opPos, argLen, stepType))
-          {
-            subQueryResults = addNode(subQueryResults, attr);
-            // If we have an attribute name here, we can quit.
-          }
+          subQueryResults = addNode(subQueryResults, attr);
+          // If we have an attribute name here, we can quit.
         }
       }
     }


-scott