001: /*
002: * Copyright 2007 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 javax.xml.namespace.QName;
022: import javax.xml.transform.Source;
023: import javax.xml.transform.TransformerException;
024: import javax.xml.transform.dom.DOMSource;
025: import javax.xml.transform.sax.SAXSource;
026: import javax.xml.transform.stream.StreamSource;
027: import javax.xml.xpath.XPath;
028: import javax.xml.xpath.XPathConstants;
029: import javax.xml.xpath.XPathFactory;
030: import javax.xml.xpath.XPathFactoryConfigurationException;
031:
032: import org.springframework.xml.namespace.SimpleNamespaceContext;
033: import org.springframework.xml.transform.StaxSource;
034: import org.w3c.dom.DOMException;
035: import org.w3c.dom.Element;
036: import org.w3c.dom.Node;
037: import org.w3c.dom.NodeList;
038: import org.xml.sax.InputSource;
039:
040: /**
041: * Implementation of {@link XPathOperations} that uses JAXP 1.3. JAXP 1.3 is part of Java SE since 1.5.
042: * <p/>
043: * Namespaces can be set using the <code>namespaces</code> property.
044: *
045: * @author Arjen Poutsma
046: * @see #setNamespaces(java.util.Properties)
047: * @since 1.0.0
048: */
049: public class Jaxp13XPathTemplate extends AbstractXPathTemplate {
050:
051: private XPathFactory xpathFactory;
052:
053: public Jaxp13XPathTemplate() {
054: this (XPathFactory.DEFAULT_OBJECT_MODEL_URI);
055: }
056:
057: public Jaxp13XPathTemplate(String xpathFactoryUri) {
058: try {
059: xpathFactory = XPathFactory.newInstance(xpathFactoryUri);
060: } catch (XPathFactoryConfigurationException ex) {
061: throw new XPathException("Could not create XPathFactory",
062: ex);
063: }
064: }
065:
066: public boolean evaluateAsBoolean(String expression, Source context)
067: throws XPathException {
068: Boolean result = (Boolean) evaluate(expression, context,
069: XPathConstants.BOOLEAN);
070: return result != null && result.booleanValue();
071: }
072:
073: public Node evaluateAsNode(String expression, Source context)
074: throws XPathException {
075: return (Node) evaluate(expression, context, XPathConstants.NODE);
076: }
077:
078: public List evaluateAsNodeList(String expression, Source context)
079: throws XPathException {
080: NodeList result = (NodeList) evaluate(expression, context,
081: XPathConstants.NODESET);
082: List nodes = new ArrayList(result.getLength());
083: for (int i = 0; i < result.getLength(); i++) {
084: nodes.add(result.item(i));
085: }
086: return nodes;
087: }
088:
089: public double evaluateAsDouble(String expression, Source context)
090: throws XPathException {
091: Double result = (Double) evaluate(expression, context,
092: XPathConstants.NUMBER);
093: return result != null ? result.doubleValue() : Double.NaN;
094: }
095:
096: public String evaluateAsString(String expression, Source context)
097: throws XPathException {
098: return (String) evaluate(expression, context,
099: XPathConstants.STRING);
100: }
101:
102: public Object evaluateAsObject(String expression, Source context,
103: NodeMapper nodeMapper) throws XPathException {
104: Node node = evaluateAsNode(expression, context);
105: if (node != null) {
106: try {
107: return nodeMapper.mapNode(node, 0);
108: } catch (DOMException ex) {
109: throw new XPathException(
110: "Mapping resulted in DOMException", ex);
111: }
112: } else {
113: return null;
114: }
115: }
116:
117: public List evaluate(String expression, Source context,
118: NodeMapper nodeMapper) throws XPathException {
119: NodeList nodes = (NodeList) evaluate(expression, context,
120: XPathConstants.NODESET);
121: List results = new ArrayList(nodes.getLength());
122: for (int i = 0; i < nodes.getLength(); i++) {
123: try {
124: results.add(nodeMapper.mapNode(nodes.item(i), i));
125: } catch (DOMException ex) {
126: throw new XPathException(
127: "Mapping resulted in DOMException", ex);
128: }
129: }
130: return results;
131: }
132:
133: private Object evaluate(String expression, Source context,
134: QName returnType) throws XPathException {
135: XPath xpath = xpathFactory.newXPath();
136: if (getNamespaces() != null && !getNamespaces().isEmpty()) {
137: SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext();
138: namespaceContext.setBindings(getNamespaces());
139: xpath.setNamespaceContext(namespaceContext);
140: }
141: try {
142: if (context instanceof StaxSource) {
143: // StaxSource is a subclass of SAXSource, but it has no InputSource, therefore we handle it differently
144: Element element = getRootElement(context);
145: return xpath.evaluate(expression, element, returnType);
146: } else if (context instanceof SAXSource) {
147: SAXSource saxSource = (SAXSource) context;
148: return xpath.evaluate(expression, saxSource
149: .getInputSource(), returnType);
150: } else if (context instanceof DOMSource) {
151: DOMSource domSource = (DOMSource) context;
152: return xpath.evaluate(expression, domSource.getNode(),
153: returnType);
154: } else if (context instanceof StreamSource) {
155: StreamSource streamSource = (StreamSource) context;
156: InputSource inputSource = null;
157: if (streamSource.getInputStream() != null) {
158: inputSource = new InputSource(streamSource
159: .getInputStream());
160: } else if (streamSource.getReader() != null) {
161: inputSource = new InputSource(streamSource
162: .getReader());
163: } else {
164: throw new IllegalArgumentException(
165: "StreamSource contains neither InputStream nor Reader");
166: }
167: return xpath.evaluate(expression, inputSource,
168: returnType);
169: } else {
170: throw new IllegalArgumentException(
171: "context type unknown");
172: }
173: } catch (javax.xml.xpath.XPathException ex) {
174: throw new XPathException(
175: "Could not evaluate XPath expression ["
176: + expression + "]", ex);
177: } catch (TransformerException ex) {
178: throw new XPathException(
179: "Could not transform context to DOM Node", ex);
180: }
181: }
182:
183: }
|