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