You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commons-dev@ws.apache.org by ve...@apache.org on 2008/12/16 16:05:40 UTC

svn commit: r727061 - in /webservices/commons/trunk/modules/axiom/modules: axiom-api/src/main/java/org/apache/axiom/om/xpath/AXIOMXPath.java axiom-tests/src/test/java/org/apache/axiom/xpath/AXIOMXPathTest2.java

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()));
+    }
+}