View Javadoc

1   /*
2    * Copyright 2007 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.xml.xpath;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  import javax.xml.namespace.QName;
22  import javax.xml.transform.Source;
23  import javax.xml.transform.TransformerException;
24  import javax.xml.transform.dom.DOMSource;
25  import javax.xml.transform.sax.SAXSource;
26  import javax.xml.transform.stream.StreamSource;
27  import javax.xml.xpath.XPath;
28  import javax.xml.xpath.XPathConstants;
29  import javax.xml.xpath.XPathFactory;
30  import javax.xml.xpath.XPathFactoryConfigurationException;
31  
32  import org.w3c.dom.DOMException;
33  import org.w3c.dom.Element;
34  import org.w3c.dom.Node;
35  import org.w3c.dom.NodeList;
36  import org.xml.sax.InputSource;
37  
38  import org.springframework.xml.namespace.SimpleNamespaceContext;
39  import org.springframework.xml.transform.TraxUtils;
40  
41  /**
42   * Implementation of {@link XPathOperations} that uses JAXP 1.3. JAXP 1.3 is part of Java SE since 1.5.
43   * <p/>
44   * Namespaces can be set using the <code>namespaces</code> property.
45   *
46   * @author Arjen Poutsma
47   * @see #setNamespaces(java.util.Properties)
48   * @since 1.0.0
49   */
50  public class Jaxp13XPathTemplate extends AbstractXPathTemplate {
51  
52      private XPathFactory xpathFactory;
53  
54      public Jaxp13XPathTemplate() {
55          this(XPathFactory.DEFAULT_OBJECT_MODEL_URI);
56      }
57  
58      public Jaxp13XPathTemplate(String xpathFactoryUri) {
59          try {
60              xpathFactory = XPathFactory.newInstance(xpathFactoryUri);
61          }
62          catch (XPathFactoryConfigurationException ex) {
63              throw new XPathException("Could not create XPathFactory", ex);
64          }
65      }
66  
67      public boolean evaluateAsBoolean(String expression, Source context) throws XPathException {
68          Boolean result = (Boolean) evaluate(expression, context, XPathConstants.BOOLEAN);
69          return result != null && result.booleanValue();
70      }
71  
72      public Node evaluateAsNode(String expression, Source context) throws XPathException {
73          return (Node) evaluate(expression, context, XPathConstants.NODE);
74      }
75  
76      public List evaluateAsNodeList(String expression, Source context) throws XPathException {
77          NodeList result = (NodeList) evaluate(expression, context, XPathConstants.NODESET);
78          List nodes = new ArrayList(result.getLength());
79          for (int i = 0; i < result.getLength(); i++) {
80              nodes.add(result.item(i));
81          }
82          return nodes;
83      }
84  
85      public double evaluateAsDouble(String expression, Source context) throws XPathException {
86          Double result = (Double) evaluate(expression, context, XPathConstants.NUMBER);
87          return result != null ? result.doubleValue() : Double.NaN;
88      }
89  
90      public String evaluateAsString(String expression, Source context) throws XPathException {
91          return (String) evaluate(expression, context, XPathConstants.STRING);
92      }
93  
94      public Object evaluateAsObject(String expression, Source context, NodeMapper nodeMapper) throws XPathException {
95          Node node = evaluateAsNode(expression, context);
96          if (node != null) {
97              try {
98                  return nodeMapper.mapNode(node, 0);
99              }
100             catch (DOMException ex) {
101                 throw new XPathException("Mapping resulted in DOMException", ex);
102             }
103         }
104         else {
105             return null;
106         }
107     }
108 
109     public List evaluate(String expression, Source context, NodeMapper nodeMapper) throws XPathException {
110         NodeList nodes = (NodeList) evaluate(expression, context, XPathConstants.NODESET);
111         List results = new ArrayList(nodes.getLength());
112         for (int i = 0; i < nodes.getLength(); i++) {
113             try {
114                 results.add(nodeMapper.mapNode(nodes.item(i), i));
115             }
116             catch (DOMException ex) {
117                 throw new XPathException("Mapping resulted in DOMException", ex);
118             }
119         }
120         return results;
121     }
122 
123     private Object evaluate(String expression, Source context, QName returnType) throws XPathException {
124         XPath xpath = xpathFactory.newXPath();
125         if (getNamespaces() != null && !getNamespaces().isEmpty()) {
126             SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext();
127             namespaceContext.setBindings(getNamespaces());
128             xpath.setNamespaceContext(namespaceContext);
129         }
130         try {
131             if (TraxUtils.isStaxSource(context)) {
132                 Element element = getRootElement(context);
133                 return xpath.evaluate(expression, element, returnType);
134             }
135             else if (context instanceof SAXSource) {
136                 SAXSource saxSource = (SAXSource) context;
137                 return xpath.evaluate(expression, saxSource.getInputSource(), returnType);
138             }
139             else if (context instanceof DOMSource) {
140                 DOMSource domSource = (DOMSource) context;
141                 return xpath.evaluate(expression, domSource.getNode(), returnType);
142             }
143             else if (context instanceof StreamSource) {
144                 StreamSource streamSource = (StreamSource) context;
145                 InputSource inputSource;
146                 if (streamSource.getInputStream() != null) {
147                     inputSource = new InputSource(streamSource.getInputStream());
148                 }
149                 else if (streamSource.getReader() != null) {
150                     inputSource = new InputSource(streamSource.getReader());
151                 }
152                 else {
153                     throw new IllegalArgumentException("StreamSource contains neither InputStream nor Reader");
154                 }
155                 return xpath.evaluate(expression, inputSource, returnType);
156             }
157             else {
158                 throw new IllegalArgumentException("context type unknown");
159             }
160         }
161         catch (javax.xml.xpath.XPathException ex) {
162             throw new XPathException("Could not evaluate XPath expression [" + expression + "]", ex);
163         }
164         catch (TransformerException ex) {
165             throw new XPathException("Could not transform context to DOM Node", ex);
166         }
167     }
168 
169 }