Removed the Xalan XPathExpression, since Xalan *is* JAXP 1.3. Added NodeMapper functionality to XPathExpression.
This commit is contained in:
@@ -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 <code>XPathExpression</code> interface.
|
||||
*/
|
||||
/** Jaxen implementation of the <code>XPathExpression</code> 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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 <a href="http://www.w3.org/TR/xpath#booleans">XPath specification</a>
|
||||
*/
|
||||
boolean evaluateAsBoolean(Node node);
|
||||
boolean evaluateAsBoolean(Node node) throws XPathException;
|
||||
|
||||
/**
|
||||
* Evaluates the given expression as a <code>Node</code>. Returns the evaluation of the expression, or
|
||||
* <code>null</code> if it is invalid.
|
||||
* Evaluates the given expression as a {@link Node}. Returns the evaluation of the expression, or <code>null</code>
|
||||
* if it is invalid.
|
||||
*
|
||||
* @param node the starting point
|
||||
* @return the result of the evaluation
|
||||
* @throws XPathException in case of XPath errors
|
||||
* @see <a href="http://www.w3.org/TR/xpath#node-sets">XPath specification</a>
|
||||
*/
|
||||
Node evaluateAsNode(Node node);
|
||||
Node evaluateAsNode(Node node) throws XPathException;
|
||||
|
||||
/**
|
||||
* Evaluates the given expression, and returns all <code>Node</code>s 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 <code>Node</code>s that are selected by the expression
|
||||
* @return a list of <code>Node</code>s that are selected by the expression
|
||||
* @throws XPathException in case of XPath errors
|
||||
* @see <a href="http://www.w3.org/TR/xpath#node-sets">XPath specification</a>
|
||||
*/
|
||||
Node[] evaluateAsNodes(Node node);
|
||||
List evaluateAsNodeList(Node node) throws XPathException;
|
||||
|
||||
/**
|
||||
* Evaluates the given expression as a number (<code>double</code>). Returns the numeric evaluation of the
|
||||
* expression, or <code>Double.NaN</code> 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 <a href="http://www.w3.org/TR/xpath#numbers">XPath specification</a>
|
||||
*/
|
||||
double evaluateAsNumber(Node node);
|
||||
double evaluateAsNumber(Node node) throws XPathException;
|
||||
|
||||
/**
|
||||
* Evaluates the given expression, and returns the first <code>Node</code> that conforms to it. Returns
|
||||
* <code>null</code> if no result could be found.
|
||||
* Evaluates the given expression as a String. Returns <code>null</code> if no result could be found.
|
||||
*
|
||||
* @param node the starting point
|
||||
* @return the first <code>Node</code> that is selected by the expression
|
||||
* @return the result of the evaluation
|
||||
* @throws XPathException in case of XPath errors
|
||||
* @see <a href="http://www.w3.org/TR/xpath#strings">XPath specification</a>
|
||||
*/
|
||||
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 <a href="http://www.w3.org/TR/xpath#node-sets">XPath specification</a>
|
||||
*/
|
||||
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 <a href="http://www.w3.org/TR/xpath#node-sets">XPath specification</a>
|
||||
*/
|
||||
List evaluate(Node node, NodeMapper nodeMapper) throws XPathException;
|
||||
}
|
||||
|
||||
@@ -26,11 +26,11 @@ import org.springframework.util.ClassUtils;
|
||||
import org.springframework.xml.JaxpVersion;
|
||||
|
||||
/**
|
||||
* Factory for compiled <code>XPathExpression</code>s, being aware of JAXP 1.3+ XPath functionality, Jaxen, and Xalan.
|
||||
* Mainly for internal use of the framework.
|
||||
* Factory for compiled <code>XPathExpression</code>s, being aware of JAXP 1.3+ XPath functionality, and Jaxen. Mainly
|
||||
* for internal use of the framework.
|
||||
* <p/>
|
||||
* The goal of this class is to avoid runtime dependencies a specific XPath engine, simply using the best XPath
|
||||
* implementation that is available. Prefers JAXP 1.3+ XPath implementations to Jaxen, and falls back to Xalan.
|
||||
* implementation that is available. Prefers JAXP 1.3+ XPath implementations to Jaxen.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see XPathExpression
|
||||
@@ -39,16 +39,12 @@ public abstract class XPathExpressionFactory {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(XPathExpressionFactory.class);
|
||||
|
||||
private static final String XALAN_XPATH_CLASS_NAME = "org.apache.xpath.XPath";
|
||||
|
||||
private static boolean xalanXPathAvailable;
|
||||
|
||||
private static final String JAXEN_CLASS_NAME = "org.jaxen.XPath";
|
||||
|
||||
private static boolean jaxenAvailable;
|
||||
|
||||
static {
|
||||
// Check whether JAXP 1.3, Resin, Jaxen, or Xalan are available
|
||||
// Check whether JAXP 1.3, or Jaxen are available
|
||||
if (JaxpVersion.getJaxpVersion() >= JaxpVersion.JAXP_13) {
|
||||
logger.info("JAXP 1.3 available");
|
||||
}
|
||||
@@ -60,14 +56,6 @@ public abstract class XPathExpressionFactory {
|
||||
catch (ClassNotFoundException ex) {
|
||||
jaxenAvailable = false;
|
||||
}
|
||||
try {
|
||||
ClassUtils.forName(XALAN_XPATH_CLASS_NAME);
|
||||
xalanXPathAvailable = true;
|
||||
logger.info("Xalan available");
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
xalanXPathAvailable = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,7 +63,7 @@ public abstract class XPathExpressionFactory {
|
||||
*
|
||||
* @param expression the XPath expression
|
||||
* @return the compiled XPath expression
|
||||
* @throws IllegalStateException if neither JAXP 1.3+, Jaxen, or Xalan are available
|
||||
* @throws IllegalStateException if neither JAXP 1.3+, or Jaxen are available
|
||||
* @throws XPathParseException if the given expression cannot be parsed
|
||||
*/
|
||||
public static XPathExpression createXPathExpression(String expression)
|
||||
@@ -90,7 +78,7 @@ public abstract class XPathExpressionFactory {
|
||||
* @param expression the XPath expression
|
||||
* @param namespaces a map that binds string prefixes to string namespaces
|
||||
* @return the compiled XPath expression
|
||||
* @throws IllegalStateException if neither JAXP 1.3+, Jaxen, or Xalan are available
|
||||
* @throws IllegalStateException if neither JAXP 1.3+, or Jaxen are available
|
||||
* @throws XPathParseException if the given expression cannot be parsed
|
||||
*/
|
||||
public static XPathExpression createXPathExpression(String expression, Map namespaces)
|
||||
@@ -104,13 +92,9 @@ public abstract class XPathExpressionFactory {
|
||||
logger.debug("Creating [org.jaxen.XPath]");
|
||||
return JaxenXPathExpressionFactory.createXPathExpression(expression, namespaces);
|
||||
}
|
||||
else if (xalanXPathAvailable) {
|
||||
logger.debug("Creating [org.apache.xpath.XPath]");
|
||||
return XalanXPathExpressionFactory.createXPathExpression(expression, namespaces);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
"Could not create XPathExpression: could not locate JAXP 1.3, Resin, Xalan on the class path");
|
||||
"Could not create XPathExpression: could not locate JAXP 1.3, or Jaxen on the class path");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.springframework.util.Assert;
|
||||
* Spring {@link FactoryBean} for {@link XPathExpression} object. Facilitates injection of XPath expressions into
|
||||
* endpoint beans.
|
||||
* <p/>
|
||||
* Uses {@link XPathExpressionFactory} underneath, so support is provided for JAXP 1.3, Jaxen, and Xalan XPaths.
|
||||
* Uses {@link XPathExpressionFactory} underneath, so support is provided for JAXP 1.3, and Jaxen XPaths.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #setExpression(String)
|
||||
|
||||
@@ -1,173 +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;
|
||||
|
||||
import javax.xml.transform.TransformerException;
|
||||
|
||||
import org.apache.xml.utils.PrefixResolver;
|
||||
import org.apache.xpath.XPath;
|
||||
import org.apache.xpath.XPathContext;
|
||||
import org.apache.xpath.objects.XObject;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.w3c.dom.traversal.NodeIterator;
|
||||
|
||||
/**
|
||||
* Xalan-specific factory creating <code>XPathExpression</code>s.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see #createXPathExpression(String)
|
||||
*/
|
||||
abstract class XalanXPathExpressionFactory {
|
||||
|
||||
/**
|
||||
* Creates a Xalan <code>XPathExpression</code> from the given string expression.
|
||||
*
|
||||
* @param expression the XPath expression
|
||||
* @return the compiled <code>XPathExpression</code>
|
||||
* @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 <code>XPathExpression</code> from the given string expression and namespaces.
|
||||
*
|
||||
* @param expression the XPath expression
|
||||
* @return the compiled <code>XPathExpression</code>
|
||||
* @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 <code>XPathExpression</code> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
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.
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user