View Javadoc
1   /**
2    *    Copyright 2009-2015 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  package org.apache.ibatis.parsing;
17  
18  import java.io.InputStream;
19  import java.io.Reader;
20  import java.io.StringReader;
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.Properties;
24  
25  import javax.xml.namespace.QName;
26  import javax.xml.parsers.DocumentBuilder;
27  import javax.xml.parsers.DocumentBuilderFactory;
28  import javax.xml.xpath.XPath;
29  import javax.xml.xpath.XPathConstants;
30  import javax.xml.xpath.XPathFactory;
31  
32  import org.apache.ibatis.builder.BuilderException;
33  import org.w3c.dom.Document;
34  import org.w3c.dom.Node;
35  import org.w3c.dom.NodeList;
36  import org.xml.sax.EntityResolver;
37  import org.xml.sax.ErrorHandler;
38  import org.xml.sax.InputSource;
39  import org.xml.sax.SAXException;
40  import org.xml.sax.SAXParseException;
41  
42  /**
43   * @author Clinton Begin
44   */
45  public class XPathParser {
46  
47    private Document document;
48    private boolean validation;
49    private EntityResolver entityResolver;
50    private Properties variables;
51    private XPath xpath;
52  
53    public XPathParser(String xml) {
54      commonConstructor(false, null, null);
55      this.document = createDocument(new InputSource(new StringReader(xml)));
56    }
57  
58    public XPathParser(Reader reader) {
59      commonConstructor(false, null, null);
60      this.document = createDocument(new InputSource(reader));
61    }
62  
63    public XPathParser(InputStream inputStream) {
64      commonConstructor(false, null, null);
65      this.document = createDocument(new InputSource(inputStream));
66    }
67  
68    public XPathParser(Document document) {
69      commonConstructor(false, null, null);
70      this.document = document;
71    }
72  
73    public XPathParser(String xml, boolean validation) {
74      commonConstructor(validation, null, null);
75      this.document = createDocument(new InputSource(new StringReader(xml)));
76    }
77  
78    public XPathParser(Reader reader, boolean validation) {
79      commonConstructor(validation, null, null);
80      this.document = createDocument(new InputSource(reader));
81    }
82  
83    public XPathParser(InputStream inputStream, boolean validation) {
84      commonConstructor(validation, null, null);
85      this.document = createDocument(new InputSource(inputStream));
86    }
87  
88    public XPathParser(Document document, boolean validation) {
89      commonConstructor(validation, null, null);
90      this.document = document;
91    }
92  
93    public XPathParser(String xml, boolean validation, Properties variables) {
94      commonConstructor(validation, variables, null);
95      this.document = createDocument(new InputSource(new StringReader(xml)));
96    }
97  
98    public XPathParser(Reader reader, boolean validation, Properties variables) {
99      commonConstructor(validation, variables, null);
100     this.document = createDocument(new InputSource(reader));
101   }
102 
103   public XPathParser(InputStream inputStream, boolean validation, Properties variables) {
104     commonConstructor(validation, variables, null);
105     this.document = createDocument(new InputSource(inputStream));
106   }
107 
108   public XPathParser(Document document, boolean validation, Properties variables) {
109     commonConstructor(validation, variables, null);
110     this.document = document;
111   }
112 
113   public XPathParser(String xml, boolean validation, Properties variables, EntityResolver entityResolver) {
114     commonConstructor(validation, variables, entityResolver);
115     this.document = createDocument(new InputSource(new StringReader(xml)));
116   }
117 
118   public XPathParser(Reader reader, boolean validation, Properties variables, EntityResolver entityResolver) {
119     commonConstructor(validation, variables, entityResolver);
120     this.document = createDocument(new InputSource(reader));
121   }
122 
123   public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
124     commonConstructor(validation, variables, entityResolver);
125     this.document = createDocument(new InputSource(inputStream));
126   }
127 
128   public XPathParser(Document document, boolean validation, Properties variables, EntityResolver entityResolver) {
129     commonConstructor(validation, variables, entityResolver);
130     this.document = document;
131   }
132 
133   public void setVariables(Properties variables) {
134     this.variables = variables;
135   }
136 
137   public String evalString(String expression) {
138     return evalString(document, expression);
139   }
140 
141   public String evalString(Object root, String expression) {
142     String result = (String) evaluate(expression, root, XPathConstants.STRING);
143     result = PropertyParser.parse(result, variables);
144     return result;
145   }
146 
147   public Boolean evalBoolean(String expression) {
148     return evalBoolean(document, expression);
149   }
150 
151   public Boolean evalBoolean(Object root, String expression) {
152     return (Boolean) evaluate(expression, root, XPathConstants.BOOLEAN);
153   }
154 
155   public Short evalShort(String expression) {
156     return evalShort(document, expression);
157   }
158 
159   public Short evalShort(Object root, String expression) {
160     return Short.valueOf(evalString(root, expression));
161   }
162 
163   public Integer evalInteger(String expression) {
164     return evalInteger(document, expression);
165   }
166 
167   public Integer evalInteger(Object root, String expression) {
168     return Integer.valueOf(evalString(root, expression));
169   }
170 
171   public Long evalLong(String expression) {
172     return evalLong(document, expression);
173   }
174 
175   public Long evalLong(Object root, String expression) {
176     return Long.valueOf(evalString(root, expression));
177   }
178 
179   public Float evalFloat(String expression) {
180     return evalFloat(document, expression);
181   }
182 
183   public Float evalFloat(Object root, String expression) {
184     return Float.valueOf(evalString(root, expression));
185   }
186 
187   public Double evalDouble(String expression) {
188     return evalDouble(document, expression);
189   }
190 
191   public Double evalDouble(Object root, String expression) {
192     return (Double) evaluate(expression, root, XPathConstants.NUMBER);
193   }
194 
195   public List<XNode> evalNodes(String expression) {
196     return evalNodes(document, expression);
197   }
198 
199   public List<XNode> evalNodes(Object root, String expression) {
200     List<XNode> xnodes = new ArrayList<XNode>();
201     NodeList nodes = (NodeList) evaluate(expression, root, XPathConstants.NODESET);
202     for (int i = 0; i < nodes.getLength(); i++) {
203       xnodes.add(new XNode(this, nodes.item(i), variables));
204     }
205     return xnodes;
206   }
207 
208   public XNode evalNode(String expression) {
209     return evalNode(document, expression);
210   }
211 
212   public XNode evalNode(Object root, String expression) {
213     Node node = (Node) evaluate(expression, root, XPathConstants.NODE);
214     if (node == null) {
215       return null;
216     }
217     return new XNode(this, node, variables);
218   }
219 
220   private Object evaluate(String expression, Object root, QName returnType) {
221     try {
222       return xpath.evaluate(expression, root, returnType);
223     } catch (Exception e) {
224       throw new BuilderException("Error evaluating XPath.  Cause: " + e, e);
225     }
226   }
227 
228   private Document createDocument(InputSource inputSource) {
229     // important: this must only be called AFTER common constructor
230     try {
231       DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
232       factory.setValidating(validation);
233 
234       factory.setNamespaceAware(false);
235       factory.setIgnoringComments(true);
236       factory.setIgnoringElementContentWhitespace(false);
237       factory.setCoalescing(false);
238       factory.setExpandEntityReferences(true);
239 
240       DocumentBuilder builder = factory.newDocumentBuilder();
241       builder.setEntityResolver(entityResolver);
242       builder.setErrorHandler(new ErrorHandler() {
243         @Override
244         public void error(SAXParseException exception) throws SAXException {
245           throw exception;
246         }
247 
248         @Override
249         public void fatalError(SAXParseException exception) throws SAXException {
250           throw exception;
251         }
252 
253         @Override
254         public void warning(SAXParseException exception) throws SAXException {
255         }
256       });
257       return builder.parse(inputSource);
258     } catch (Exception e) {
259       throw new BuilderException("Error creating document instance.  Cause: " + e, e);
260     }
261   }
262 
263   private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
264     this.validation = validation;
265     this.entityResolver = entityResolver;
266     this.variables = variables;
267     XPathFactory factory = XPathFactory.newInstance();
268     this.xpath = factory.newXPath();
269   }
270 
271 }