Author: veithen
Date: Tue Dec 16 07:05:37 2008
New Revision: 727061

URL: http://svn.apache.org/viewvc?rev=727061&view=rev
Log:
WSCOMMONS-333: Added methods and constructors that allow to set up the 
namespace context of an AXIOMXPath using an OMElement. The implementation 
follows the same rules as XSLT.

Added:
    
webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/xpath/AXIOMXPathTest2.java
Modified:
    
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/xpath/AXIOMXPath.java

Modified: 
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/xpath/AXIOMXPath.java
URL: 
http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/xpath/AXIOMXPath.java?rev=727061&r1=727060&r2=727061&view=diff
==============================================================================
--- 
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/xpath/AXIOMXPath.java
 (original)
+++ 
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/xpath/AXIOMXPath.java
 Tue Dec 16 07:05:37 2008
@@ -19,11 +19,19 @@
 
 package org.apache.axiom.om.xpath;
 
+import org.apache.axiom.om.OMAttribute;
+import org.apache.axiom.om.OMContainer;
+import org.apache.axiom.om.OMDocument;
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMNamespace;
 import org.jaxen.BaseXPath;
 import org.jaxen.JaxenException;
 
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 public class AXIOMXPath extends BaseXPath {
 
@@ -32,16 +40,46 @@
     private Map namespaces = new HashMap();
 
     /**
-     * Construct given an XPath expression string.
+     * Construct an XPath expression from a given string.
      *
-     * @param xpathExpr the XPath expression.
-     * @throws org.jaxen.JaxenException if there is a syntax error while 
parsing the expression
+     * @param xpathExpr the string representation of the XPath expression.
+     * @throws JaxenException if there is a syntax error while parsing the 
expression
      */
     public AXIOMXPath(String xpathExpr) throws JaxenException {
         super(xpathExpr, new DocumentNavigator());
     }
 
     /**
+     * Construct an XPath expression from a given string and initialize its
+     * namespace context based on a given element.
+     * 
+     * @param element The element that determines the namespace context of the
+     *                XPath expression. See {...@link 
#addNamespaces(OMElement)}
+     *                for more details.
+     * @param xpathExpr the string representation of the XPath expression.
+     * @throws JaxenException if there is a syntax error while parsing the 
expression
+     *                        or if the namespace context could not be set up
+     */
+    public AXIOMXPath(OMElement element, String xpathExpr) throws 
JaxenException {
+        this(xpathExpr);
+        addNamespaces(element);
+    }
+
+    /**
+     * Construct an XPath expression from a given attribute.
+     * The string representation of the expression is taken from the attribute
+     * value, while the attribute's owner element is used to determine the
+     * namespace context of the expression. 
+     * 
+     * @param attribute the attribute to construct the expression from
+     * @throws JaxenException if there is a syntax error while parsing the 
expression
+     *                        or if the namespace context could not be set up
+     */
+    public AXIOMXPath(OMAttribute attribute) throws JaxenException {
+        this(attribute.getOwner(), attribute.getAttributeValue());
+    }
+
+    /**
      * This override captures any added namespaces, as the Jaxen BaseXPath 
class nor
      * NamespaceContext (or SimpleNamespaceContext) exposes thier internal map 
of the prefixes to
      * the namespaces. This method - although is not the ideal solution to the 
issue, attempts to
@@ -63,6 +101,51 @@
     }
 
     /**
+     * Add the namespace declarations of a given {...@link OMElement} to the 
namespace
+     * context of an XPath expression. Typically this method is used with an 
XPath
+     * expression appearing in an attribute of the given element.
+     * <p>
+     * Note that the default namespace is explicitly excluded and not added to 
the
+     * namespace context. This makes the behaviour of this method consistent 
with
+     * the rules followed in XSL stylesheets. Indeed, the XSLT specification 
defines
+     * the namespace context of an XPath expression as follows:
+     * <blockquote>
+     * the set of namespace declarations are those in scope on the element 
which has the
+     * attribute in which the expression occurs; [...] the default namespace
+     * (as declared by xmlns) is not part of this set
+     * </blockquote>
+     * 
+     * @param element the element to retrieve the namespace context from
+     * @throws JaxenException if an error occurred when adding the namespace 
declarations
+     */
+    public void addNamespaces(OMElement element) throws JaxenException {
+        OMElement current = element;
+        // An element can redeclare a namespace prefix that has already been 
declared
+        // by one of its ancestors. Since we visit the tree from child to 
parent, we
+        // need to keep track of the prefixes we have already seen in order to 
avoid
+        // adding namespace declarations that are overridden by a descendant 
of an element.
+        Set seenPrefixes = new HashSet();
+        while (true) {
+            for (Iterator it = current.getAllDeclaredNamespaces(); 
it.hasNext(); ) {
+                OMNamespace ns = (OMNamespace) it.next();
+                if (ns != null) {
+                    String prefix = ns.getPrefix();
+                    // Exclude the default namespace as explained in the 
Javadoc above
+                    if (prefix.length() != 0 && seenPrefixes.add(prefix)) {
+                        addNamespace(ns.getPrefix(), ns.getNamespaceURI());
+                    }
+                }
+            }
+            OMContainer parent = current.getParent();
+            if (parent == null || parent instanceof OMDocument) {
+                break;
+            } else {
+                current = (OMElement)parent;
+            }
+        }
+    }
+
+    /**
      * Expose the prefix to namespace mapping for this expression
      *
      * @return a Map of namespace prefixes to the URIs

Added: 
webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/xpath/AXIOMXPathTest2.java
URL: 
http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/xpath/AXIOMXPathTest2.java?rev=727061&view=auto
==============================================================================
--- 
webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/xpath/AXIOMXPathTest2.java
 (added)
+++ 
webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/xpath/AXIOMXPathTest2.java
 Tue Dec 16 07:05:37 2008
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.axiom.xpath;
+
+import junit.framework.TestCase;
+
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.impl.llom.util.AXIOMUtil;
+import org.apache.axiom.om.xpath.AXIOMXPath;
+
+/**
+ * This class contains Axiom specific tests, while AXIOMXPathTest is
+ * used for the Jaxen test harness.
+ */
+public class AXIOMXPathTest2 extends TestCase {
+    public void testAddNamespaces() throws Exception {
+        OMElement root1 = AXIOMUtil.stringToOM(
+                "<ns1:root xmlns:ns1='urn:ns1'><ns1:child 
xmlns:ns2='urn:ns2'/></root>");
+        OMElement root2 = AXIOMUtil.stringToOM(
+                "<root xmlns='urn:ns1'><child 
xmlns='urn:ns2'>text</child></root>");
+        AXIOMXPath xpath = new AXIOMXPath("/ns1:root/ns2:child");
+        xpath.addNamespaces(root1.getFirstElement());
+        assertEquals("text", xpath.stringValueOf(root2.getParent()));
+    }
+
+    public void testAddNamespaces2() throws Exception {
+        OMElement root1 = AXIOMUtil.stringToOM(
+                "<ns:root xmlns:ns='urn:ns1'><ns:child 
xmlns:ns='urn:ns2'/></root>");
+        OMElement root2 = AXIOMUtil.stringToOM(
+                "<root xmlns='urn:ns1'><child 
xmlns='urn:ns2'>text</child></root>");
+        AXIOMXPath xpath = new AXIOMXPath("//ns:child");
+        xpath.addNamespaces(root1.getFirstElement());
+        assertEquals("text", xpath.stringValueOf(root2.getParent()));
+    }
+}


Reply via email to