001: /*
002: * Copyright 2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.xml.xpath;
018:
019: import java.util.ArrayList;
020: import java.util.List;
021: import java.util.Map;
022: import javax.xml.namespace.QName;
023: import javax.xml.xpath.XPath;
024: import javax.xml.xpath.XPathConstants;
025: import javax.xml.xpath.XPathExpressionException;
026: import javax.xml.xpath.XPathFactory;
027:
028: import org.springframework.xml.namespace.SimpleNamespaceContext;
029: import org.w3c.dom.DOMException;
030: import org.w3c.dom.Node;
031: import org.w3c.dom.NodeList;
032:
033: /**
034: * JAXP 1.3-specific factory creating {@link XPathExpression} objects.
035: *
036: * @author Arjen Poutsma
037: * @see #createXPathExpression(String)
038: * @since 1.0.0
039: */
040: abstract class Jaxp13XPathExpressionFactory {
041:
042: private static XPathFactory xpathFactory;
043:
044: static {
045: xpathFactory = XPathFactory.newInstance();
046: }
047:
048: /**
049: * Creates a JAXP 1.3 <code>XPathExpression</code> from the given string expression.
050: *
051: * @param expression the XPath expression
052: * @return the compiled <code>XPathExpression</code>
053: * @throws XPathParseException when the given expression cannot be parsed
054: */
055: static XPathExpression createXPathExpression(String expression) {
056: try {
057: XPath xpath = xpathFactory.newXPath();
058: javax.xml.xpath.XPathExpression xpathExpression = xpath
059: .compile(expression);
060: return new Jaxp13XPathExpression(xpathExpression);
061: } catch (XPathExpressionException ex) {
062: throw new org.springframework.xml.xpath.XPathParseException(
063: "Could not compile [" + expression
064: + "] to a XPathExpression: "
065: + ex.getMessage(), ex);
066: }
067: }
068:
069: /**
070: * Creates a JAXP 1.3 <code>XPathExpression</code> from the given string expression and namespaces.
071: *
072: * @param expression the XPath expression
073: * @param namespaces the namespaces
074: * @return the compiled <code>XPathExpression</code>
075: * @throws XPathParseException when the given expression cannot be parsed
076: */
077: public static XPathExpression createXPathExpression(
078: String expression, Map namespaces) {
079: try {
080: XPath xpath = xpathFactory.newXPath();
081: SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext();
082: namespaceContext.setBindings(namespaces);
083: xpath.setNamespaceContext(namespaceContext);
084: javax.xml.xpath.XPathExpression xpathExpression = xpath
085: .compile(expression);
086: return new Jaxp13XPathExpression(xpathExpression);
087: } catch (XPathExpressionException ex) {
088: throw new org.springframework.xml.xpath.XPathParseException(
089: "Could not compile [" + expression
090: + "] to a XPathExpression: "
091: + ex.getMessage(), ex);
092: }
093: }
094:
095: /** JAXP 1.3 implementation of the <code>XPathExpression</code> interface. */
096: private static class Jaxp13XPathExpression implements
097: XPathExpression {
098:
099: javax.xml.xpath.XPathExpression xpathExpression;
100:
101: private Jaxp13XPathExpression(
102: javax.xml.xpath.XPathExpression xpathExpression) {
103: this .xpathExpression = xpathExpression;
104: }
105:
106: public String evaluateAsString(Node node) {
107: return (String) evaluate(node, XPathConstants.STRING);
108: }
109:
110: public List evaluateAsNodeList(Node node) {
111: NodeList nodeList = (NodeList) evaluate(node,
112: XPathConstants.NODESET);
113: return toNodeList(nodeList);
114: }
115:
116: private Object evaluate(Node node, QName returnType) {
117: try {
118: // XPathExpression is not thread-safe
119: synchronized (xpathExpression) {
120: return xpathExpression.evaluate(node, returnType);
121: }
122: } catch (XPathExpressionException ex) {
123: throw new XPathException(
124: "Could not evaluate XPath expression:"
125: + ex.getMessage(), ex);
126: }
127: }
128:
129: private List toNodeList(NodeList nodeList) {
130: List result = new ArrayList(nodeList.getLength());
131: for (int i = 0; i < nodeList.getLength(); i++) {
132: result.add(nodeList.item(i));
133: }
134: return result;
135: }
136:
137: public double evaluateAsNumber(Node node) {
138: Double result = (Double) evaluate(node,
139: XPathConstants.NUMBER);
140: return result.doubleValue();
141: }
142:
143: public boolean evaluateAsBoolean(Node node) {
144: Boolean result = (Boolean) evaluate(node,
145: XPathConstants.BOOLEAN);
146: return result.booleanValue();
147: }
148:
149: public Node evaluateAsNode(Node node) {
150: return (Node) evaluate(node, XPathConstants.NODE);
151: }
152:
153: public Object evaluateAsObject(Node node, NodeMapper nodeMapper)
154: throws XPathException {
155: Node result = (Node) evaluate(node, XPathConstants.NODE);
156: if (result != null) {
157: try {
158: return nodeMapper.mapNode(result, 0);
159: } catch (DOMException ex) {
160: throw new XPathException(
161: "Mapping resulted in DOMException", ex);
162: }
163: } else {
164: return null;
165: }
166: }
167:
168: public List evaluate(Node node, NodeMapper nodeMapper)
169: throws XPathException {
170: NodeList nodes = (NodeList) evaluate(node,
171: XPathConstants.NODESET);
172: List results = new ArrayList(nodes.getLength());
173: for (int i = 0; i < nodes.getLength(); i++) {
174: try {
175: results.add(nodeMapper.mapNode(nodes.item(i), i));
176: } catch (DOMException ex) {
177: throw new XPathException(
178: "Mapping resulted in DOMException", ex);
179: }
180: }
181: return results;
182: }
183: }
184:
185: }
|