diff --git a/core/src/main/java/org/springframework/ws/transport/http/WsdlDefinitionHandlerAdapter.java b/core/src/main/java/org/springframework/ws/transport/http/WsdlDefinitionHandlerAdapter.java
index a5da0b37..c8f26591 100644
--- a/core/src/main/java/org/springframework/ws/transport/http/WsdlDefinitionHandlerAdapter.java
+++ b/core/src/main/java/org/springframework/ws/transport/http/WsdlDefinitionHandlerAdapter.java
@@ -18,6 +18,8 @@ package org.springframework.ws.transport.http;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.Iterator;
+import java.util.List;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -40,7 +42,6 @@ import org.springframework.xml.xpath.XPathExpression;
import org.springframework.xml.xpath.XPathExpressionFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
-import org.w3c.dom.Node;
/**
* Adapter to use the WsdlDefinition interface with the generic DispatcherServlet. Reads the
@@ -73,9 +74,7 @@ import org.w3c.dom.Node;
*/
public class WsdlDefinitionHandlerAdapter extends TransformerObjectSupport implements HandlerAdapter, InitializingBean {
- /**
- * Default XPath expression used for extracting all location attributes from the WSDL definition.
- */
+ /** Default XPath expression used for extracting all location attributes from the WSDL definition. */
public static final String DEFAULT_LOCATION_EXPRESSION = "//@location";
private static final String CONTENT_TYPE = "text/xml";
@@ -191,9 +190,9 @@ public class WsdlDefinitionHandlerAdapter extends TransformerObjectSupport imple
* @see #transformLocation(String,javax.servlet.http.HttpServletRequest)
*/
protected void transformLocations(Document definitionDocument, HttpServletRequest request) throws Exception {
- Node[] locationNodes = locationXPathExpression.evaluateAsNodes(definitionDocument);
- for (int i = 0; i < locationNodes.length; i++) {
- Attr location = (Attr) locationNodes[i];
+ List locationNodes = locationXPathExpression.evaluateAsNodeList(definitionDocument);
+ for (Iterator iterator = locationNodes.iterator(); iterator.hasNext();) {
+ Attr location = (Attr) iterator.next();
if (location != null && StringUtils.hasLength(location.getValue())) {
String newLocation = transformLocation(location.getValue(), request);
logger.debug("Transforming [" + location.getValue() + "] to [" + newLocation + "]");
diff --git a/xml/src/main/java/org/springframework/xml/xpath/JaxenXPathExpressionFactory.java b/xml/src/main/java/org/springframework/xml/xpath/JaxenXPathExpressionFactory.java
index ad8bf0f2..bca4597e 100644
--- a/xml/src/main/java/org/springframework/xml/xpath/JaxenXPathExpressionFactory.java
+++ b/xml/src/main/java/org/springframework/xml/xpath/JaxenXPathExpressionFactory.java
@@ -16,6 +16,7 @@
package org.springframework.xml.xpath;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -23,6 +24,7 @@ import org.jaxen.JaxenException;
import org.jaxen.SimpleNamespaceContext;
import org.jaxen.XPath;
import org.jaxen.dom.DOMXPath;
+import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
/**
@@ -71,9 +73,7 @@ abstract class JaxenXPathExpressionFactory {
}
}
- /**
- * Jaxen implementation of the XPathExpression interface.
- */
+ /** Jaxen implementation of the XPathExpression interface. */
private static class JaxenXpathExpression implements XPathExpression {
private XPath xpath;
@@ -118,10 +118,49 @@ abstract class JaxenXPathExpressionFactory {
}
}
- public Node[] evaluateAsNodes(Node node) {
+ public List evaluateAsNodeList(Node node) {
try {
- List result = xpath.selectNodes(node);
- return (Node[]) result.toArray(new Node[result.size()]);
+ return xpath.selectNodes(node);
+ }
+ catch (JaxenException ex) {
+ throw new XPathException("Could not evaluate XPath expression [" + xpath + "] :" + ex.getMessage(), ex);
+ }
+ }
+
+ public Object evaluateAsObject(Node context, NodeMapper nodeMapper) throws XPathException {
+ try {
+ Node result = (Node) xpath.selectSingleNode(context);
+ if (result != null) {
+ try {
+ return nodeMapper.mapNode(result, 0);
+ }
+ catch (DOMException ex) {
+ throw new XPathException("Mapping resulted in DOMException", ex);
+ }
+ }
+ else {
+ return null;
+ }
+ }
+ catch (JaxenException ex) {
+ throw new XPathException("Could not evaluate XPath expression [" + xpath + "] :" + ex.getMessage(), ex);
+ }
+ }
+
+ public List evaluate(Node context, NodeMapper nodeMapper) throws XPathException {
+ try {
+ List nodes = xpath.selectNodes(context);
+ List results = new ArrayList(nodes.size());
+ for (int i = 0; i < nodes.size(); i++) {
+ Node node = (Node) nodes.get(i);
+ try {
+ results.add(nodeMapper.mapNode(node, i));
+ }
+ catch (DOMException ex) {
+ throw new XPathException("Mapping resulted in DOMException", ex);
+ }
+ }
+ return results;
}
catch (JaxenException ex) {
throw new XPathException("Could not evaluate XPath expression [" + xpath + "] :" + ex.getMessage(), ex);
diff --git a/xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathExpressionFactory.java b/xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathExpressionFactory.java
index f430628d..f0cac8c2 100644
--- a/xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathExpressionFactory.java
+++ b/xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathExpressionFactory.java
@@ -16,6 +16,8 @@
package org.springframework.xml.xpath;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPath;
@@ -24,6 +26,7 @@ import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.springframework.xml.namespace.SimpleNamespaceContext;
+import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@@ -96,9 +99,9 @@ abstract class Jaxp13XPathExpressionFactory {
return (String) evaluate(node, XPathConstants.STRING);
}
- public Node[] evaluateAsNodes(Node node) {
+ public List evaluateAsNodeList(Node node) {
NodeList nodeList = (NodeList) evaluate(node, XPathConstants.NODESET);
- return toNodeArray(nodeList);
+ return toNodeList(nodeList);
}
private Object evaluate(Node node, QName returnType) {
@@ -113,10 +116,10 @@ abstract class Jaxp13XPathExpressionFactory {
}
}
- private Node[] toNodeArray(NodeList nodeList) {
- Node[] result = new Node[nodeList.getLength()];
+ private List toNodeList(NodeList nodeList) {
+ List result = new ArrayList(nodeList.getLength());
for (int i = 0; i < nodeList.getLength(); i++) {
- result[i] = nodeList.item(i);
+ result.add(nodeList.item(i));
}
return result;
}
@@ -134,6 +137,35 @@ abstract class Jaxp13XPathExpressionFactory {
public Node evaluateAsNode(Node node) {
return (Node) evaluate(node, XPathConstants.NODE);
}
+
+ public Object evaluateAsObject(Node node, NodeMapper nodeMapper) throws XPathException {
+ Node result = (Node) evaluate(node, XPathConstants.NODE);
+ if (result != null) {
+ try {
+ return nodeMapper.mapNode(result, 0);
+ }
+ catch (DOMException ex) {
+ throw new XPathException("Mapping resulted in DOMException", ex);
+ }
+ }
+ else {
+ return null;
+ }
+ }
+
+ public List evaluate(Node node, NodeMapper nodeMapper) throws XPathException {
+ NodeList nodes = (NodeList) evaluate(node, XPathConstants.NODESET);
+ List results = new ArrayList(nodes.getLength());
+ for (int i = 0; i < nodes.getLength(); i++) {
+ try {
+ results.add(nodeMapper.mapNode(nodes.item(i), i));
+ }
+ catch (DOMException ex) {
+ throw new XPathException("Mapping resulted in DOMException", ex);
+ }
+ }
+ return results;
+ }
}
}
diff --git a/xml/src/main/java/org/springframework/xml/xpath/NodeMapper.java b/xml/src/main/java/org/springframework/xml/xpath/NodeMapper.java
index 7cf35b19..8122b3b1 100644
--- a/xml/src/main/java/org/springframework/xml/xpath/NodeMapper.java
+++ b/xml/src/main/java/org/springframework/xml/xpath/NodeMapper.java
@@ -27,6 +27,8 @@ import org.w3c.dom.Node;
* @author Arjen Poutsma
* @see XPathOperations#evaluate(String,javax.xml.transform.Source,NodeMapper)
* @see XPathOperations#evaluateAsObject(String,javax.xml.transform.Source,NodeMapper)
+ * @see XPathExpression#evaluate(org.w3c.dom.Node,NodeMapper)
+ * @see XPathExpression#evaluateAsObject(org.w3c.dom.Node,NodeMapper)
*/
public interface NodeMapper {
diff --git a/xml/src/main/java/org/springframework/xml/xpath/XPathExpression.java b/xml/src/main/java/org/springframework/xml/xpath/XPathExpression.java
index 637b3e39..ac50bb49 100644
--- a/xml/src/main/java/org/springframework/xml/xpath/XPathExpression.java
+++ b/xml/src/main/java/org/springframework/xml/xpath/XPathExpression.java
@@ -16,6 +16,8 @@
package org.springframework.xml.xpath;
+import java.util.List;
+
import org.w3c.dom.Node;
/**
@@ -35,48 +37,74 @@ public interface XPathExpression {
*
* @param node the starting point
* @return the result of the evaluation
+ * @throws XPathException in case of XPath errors
* @see XPath specification
*/
- boolean evaluateAsBoolean(Node node);
+ boolean evaluateAsBoolean(Node node) throws XPathException;
/**
- * Evaluates the given expression as a Node. Returns the evaluation of the expression, or
- * null if it is invalid.
+ * Evaluates the given expression as a {@link Node}. Returns the evaluation of the expression, or null
+ * if it is invalid.
*
* @param node the starting point
* @return the result of the evaluation
+ * @throws XPathException in case of XPath errors
* @see XPath specification
*/
- Node evaluateAsNode(Node node);
+ Node evaluateAsNode(Node node) throws XPathException;
/**
- * Evaluates the given expression, and returns all Nodes that conform to it. Returns and empty array if
+ * Evaluates the given expression, and returns all {@link Node} objects that conform to it. Returns an empty list if
* no result could be found.
*
* @param node the starting point
- * @return the Nodes that are selected by the expression
+ * @return a list of Nodes that are selected by the expression
+ * @throws XPathException in case of XPath errors
* @see XPath specification
*/
- Node[] evaluateAsNodes(Node node);
+ List evaluateAsNodeList(Node node) throws XPathException;
/**
* Evaluates the given expression as a number (double). Returns the numeric evaluation of the
- * expression, or Double.NaN if it is invalid.
+ * expression, or {@link Double#NaN} if it is invalid.
*
* @param node the starting point
* @return the result of the evaluation
- * @see Double#NaN
+ * @throws XPathException in case of XPath errors
* @see XPath specification
*/
- double evaluateAsNumber(Node node);
+ double evaluateAsNumber(Node node) throws XPathException;
/**
- * Evaluates the given expression, and returns the first Node that conforms to it. Returns
- * null if no result could be found.
+ * Evaluates the given expression as a String. Returns null if no result could be found.
*
* @param node the starting point
- * @return the first Node that is selected by the expression
+ * @return the result of the evaluation
+ * @throws XPathException in case of XPath errors
* @see XPath specification
*/
- String evaluateAsString(Node node);
+ String evaluateAsString(Node node) throws XPathException;
+
+ /**
+ * Evaluates the given expression, mapping a single {@link Node} result to a Java object via a {@link NodeMapper}.
+ *
+ * @param node the starting point
+ * @param nodeMapper object that will map one object per node
+ * @return the single mapped object
+ * @throws XPathException in case of XPath errors
+ * @see XPath specification
+ */
+ Object evaluateAsObject(Node node, NodeMapper nodeMapper) throws XPathException;
+
+ /**
+ * Evaluates the given expression, mapping each result {@link Node} objects to a Java object via a {@link
+ * NodeMapper}.
+ *
+ * @param node the starting point
+ * @param nodeMapper object that will map one object per node
+ * @return the result list, containing mapped objects
+ * @throws XPathException in case of XPath errors
+ * @see XPath specification
+ */
+ List evaluate(Node node, NodeMapper nodeMapper) throws XPathException;
}
diff --git a/xml/src/main/java/org/springframework/xml/xpath/XPathExpressionFactory.java b/xml/src/main/java/org/springframework/xml/xpath/XPathExpressionFactory.java
index 523871c6..82569e0f 100644
--- a/xml/src/main/java/org/springframework/xml/xpath/XPathExpressionFactory.java
+++ b/xml/src/main/java/org/springframework/xml/xpath/XPathExpressionFactory.java
@@ -26,11 +26,11 @@ import org.springframework.util.ClassUtils;
import org.springframework.xml.JaxpVersion;
/**
- * Factory for compiled XPathExpressions, being aware of JAXP 1.3+ XPath functionality, Jaxen, and Xalan.
- * Mainly for internal use of the framework.
+ * Factory for compiled XPathExpressions, being aware of JAXP 1.3+ XPath functionality, and Jaxen. Mainly
+ * for internal use of the framework.
*
XPathExpressions.
- *
- * @author Arjen Poutsma
- * @see #createXPathExpression(String)
- */
-abstract class XalanXPathExpressionFactory {
-
- /**
- * Creates a Xalan XPathExpression from the given string expression.
- *
- * @param expression the XPath expression
- * @return the compiled XPathExpression
- * @throws XPathParseException when the given expression cannot be parsed
- */
- static XPathExpression createXPathExpression(String expression) {
- try {
- XPath xpath = new XPath(expression, null, null, XPath.SELECT);
- return new XalanXPathExpression(xpath);
- }
- catch (TransformerException ex) {
- throw new org.springframework.xml.xpath.XPathParseException(
- "Could not compile [" + expression + "] to a XPathExpression: " + ex.getMessage(), ex);
- }
- }
-
- /**
- * Creates a Xalan XPathExpression from the given string expression and namespaces.
- *
- * @param expression the XPath expression
- * @return the compiled XPathExpression
- * @throws XPathParseException when the given expression cannot be parsed
- */
- public static XPathExpression createXPathExpression(String expression, Map namespaces) {
- try {
- PrefixResolver prefixResolver = new SimplePrefixResolver(namespaces);
- XPath xpath = new XPath(expression, null, prefixResolver, XPath.SELECT);
- return new XalanXPathExpression(xpath);
- }
- catch (TransformerException ex) {
- throw new org.springframework.xml.xpath.XPathParseException(
- "Could not compile [" + expression + "] to a XPathExpression: " + ex.getMessage(), ex);
- }
- }
-
- /**
- * Xalan implementation of the XPathExpression interface.
- */
- private static class XalanXPathExpression implements XPathExpression {
-
- private XPath xpath;
-
- private XPathContext context = new XPathContext();
-
- private XalanXPathExpression(XPath xpath) {
- this.xpath = xpath;
- }
-
- public Node evaluateAsNode(Node node) {
- try {
- XObject result = xpath.execute(context, node, null);
- NodeIterator iterator = result.nodeset();
- return iterator.nextNode();
- }
- catch (TransformerException ex) {
- throw new XPathException("Could not evaluate XPath expression:" + ex.getMessage(), ex);
- }
- }
-
- public boolean evaluateAsBoolean(Node node) {
- try {
- XObject result = xpath.execute(context, node, null);
- return result.bool();
- }
- catch (TransformerException ex) {
- throw new XPathException("Could not evaluate XPath expression:" + ex.getMessage(), ex);
- }
- }
-
- public double evaluateAsNumber(Node node) {
- try {
- XObject result = xpath.execute(context, node, null);
- return result.num();
- }
- catch (TransformerException ex) {
- throw new XPathException("Could not evaluate XPath expression:" + ex.getMessage(), ex);
- }
- }
-
- public String evaluateAsString(Node node) {
- try {
- XObject result = xpath.execute(context, node, null);
- return result.str();
- }
- catch (TransformerException ex) {
- throw new XPathException("Could not evaluate XPath expression:" + ex.getMessage(), ex);
- }
- }
-
- public Node[] evaluateAsNodes(Node node) {
- try {
- XObject result = xpath.execute(context, node, null);
- return toNodeArray(result.nodelist());
- }
- catch (TransformerException ex) {
- throw new XPathException("Could not evaluate XPath expression:" + ex.getMessage(), ex);
- }
- }
-
- private Node[] toNodeArray(NodeList nodeList) {
- Node[] result = new Node[nodeList.getLength()];
- for (int i = 0; i < nodeList.getLength(); i++) {
- result[i] = nodeList.item(i);
- }
- return result;
- }
- }
-
- private static class SimplePrefixResolver implements PrefixResolver {
-
- private Map namespaces;
-
- private SimplePrefixResolver(Map namespaces) {
- this.namespaces = namespaces;
- }
-
- public String getNamespaceForPrefix(String prefix) {
- return (String) namespaces.get(prefix);
- }
-
- public String getNamespaceForPrefix(String prefix, Node node) {
- return (String) namespaces.get(prefix);
- }
-
- public String getBaseIdentifier() {
- return null;
- }
-
- public boolean handlesNullPrefixes() {
- return false;
- }
- }
-}
diff --git a/xml/src/main/java/org/springframework/xml/xpath/package.html b/xml/src/main/java/org/springframework/xml/xpath/package.html
index 36e7692e..5330ca07 100644
--- a/xml/src/main/java/org/springframework/xml/xpath/package.html
+++ b/xml/src/main/java/org/springframework/xml/xpath/package.html
@@ -1,5 +1,5 @@
-Provides XPathTemplate implementations, and various classes for XPath evaluation using JAXP 1.3, Jaxen, and Xalan.
+Provides XPathTemplate implementations, and various classes for XPath evaluation using JAXP 1.3, and Jaxen.
diff --git a/xml/src/test/java/org/springframework/xml/xpath/AbstractXPathExpressionFactoryTestCase.java b/xml/src/test/java/org/springframework/xml/xpath/AbstractXPathExpressionFactoryTestCase.java
index d535ce13..bc2049ce 100644
--- a/xml/src/test/java/org/springframework/xml/xpath/AbstractXPathExpressionFactoryTestCase.java
+++ b/xml/src/test/java/org/springframework/xml/xpath/AbstractXPathExpressionFactoryTestCase.java
@@ -19,18 +19,18 @@ package org.springframework.xml.xpath;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
-
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import junit.framework.TestCase;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
-import org.springframework.util.StringUtils;
-
public abstract class AbstractXPathExpressionFactoryTestCase extends TestCase {
private Document noNamespacesDocument;
@@ -137,18 +137,18 @@ public abstract class AbstractXPathExpressionFactoryTestCase extends TestCase {
assertEquals("Invalid localname", "child", result.getLocalName());
}
- public void testEvaluateAsNodesNamespaces() throws IOException, SAXException {
+ public void testEvaluateAsNodeListNamespaces() throws IOException, SAXException {
XPathExpression expression = createXPathExpression("/prefix1:root/prefix2:child/*", namespaces);
- Node[] results = expression.evaluateAsNodes(namespacesDocument);
+ List results = expression.evaluateAsNodeList(namespacesDocument);
assertNotNull("Invalid result", results);
- assertEquals("Invalid amount of results", 3, results.length);
+ assertEquals("Invalid amount of results", 3, results.size());
}
- public void testEvaluateAsNodesNoNamespaces() throws IOException, SAXException {
+ public void testEvaluateAsNodeListNoNamespaces() throws IOException, SAXException {
XPathExpression expression = createXPathExpression("/root/child/*");
- Node[] results = expression.evaluateAsNodes(noNamespacesDocument);
+ List results = expression.evaluateAsNodeList(noNamespacesDocument);
assertNotNull("Invalid result", results);
- assertEquals("Invalid amount of results", 3, results.length);
+ assertEquals("Invalid amount of results", 3, results.size());
}
public void testEvaluateAsStringInvalidNamespaces() throws IOException, SAXException {
@@ -176,6 +176,31 @@ public abstract class AbstractXPathExpressionFactoryTestCase extends TestCase {
assertEquals("Invalid result", "text", result);
}
+ public void testEvaluateAsObject() throws Exception {
+ XPathExpression expression = createXPathExpression("/root/child");
+ String result = (String) expression.evaluateAsObject(noNamespacesDocument, new NodeMapper() {
+ public Object mapNode(Node node, int nodeNum) throws DOMException {
+ return node.getLocalName();
+ }
+ });
+ assertNotNull("Invalid result", result);
+ assertEquals("Invalid localname", "child", result);
+ }
+
+ public void testEvaluate() throws Exception {
+ XPathExpression expression = createXPathExpression("/root/child/*");
+ List results = expression.evaluate(noNamespacesDocument, new NodeMapper() {
+ public Object mapNode(Node node, int nodeNum) throws DOMException {
+ return node.getLocalName();
+ }
+ });
+ assertNotNull("Invalid result", results);
+ assertEquals("Invalid amount of results", 3, results.size());
+ assertEquals("Invalid first result", "text", results.get(0));
+ assertEquals("Invalid first result", "number", results.get(1));
+ assertEquals("Invalid first result", "boolean", results.get(2));
+ }
+
public void testInvalidExpression() {
try {
createXPathExpression("\\");
diff --git a/xml/src/test/java/org/springframework/xml/xpath/XalanXPathExpressionFactoryTest.java b/xml/src/test/java/org/springframework/xml/xpath/XalanXPathExpressionFactoryTest.java
deleted file mode 100644
index b2a222d6..00000000
--- a/xml/src/test/java/org/springframework/xml/xpath/XalanXPathExpressionFactoryTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2006 the original author or authors.
- *
- * Licensed 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.springframework.xml.xpath;
-
-import java.util.Map;
-
-/**
- * @author Arjen Poutsma
- */
-public class XalanXPathExpressionFactoryTest extends AbstractXPathExpressionFactoryTestCase {
-
- protected XPathExpression createXPathExpression(String expression) {
- return XalanXPathExpressionFactory.createXPathExpression(expression);
- }
-
- protected XPathExpression createXPathExpression(String expression, Map prefixes) {
- return XalanXPathExpressionFactory.createXPathExpression(expression, prefixes);
- }
-}