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 return PropertyParser.parse(result, variables);
146 }
147
148 public Boolean evalBoolean(String expression) {
149 return evalBoolean(document, expression);
150 }
151
152 public Boolean evalBoolean(Object root, String expression) {
153 return (Boolean) evaluate(expression, root, XPathConstants.BOOLEAN);
154 }
155
156 public Short evalShort(String expression) {
157 return evalShort(document, expression);
158 }
159
160 public Short evalShort(Object root, String expression) {
161 return Short.valueOf(evalString(root, expression));
162 }
163
164 public Integer evalInteger(String expression) {
165 return evalInteger(document, expression);
166 }
167
168 public Integer evalInteger(Object root, String expression) {
169 return Integer.valueOf(evalString(root, expression));
170 }
171
172 public Long evalLong(String expression) {
173 return evalLong(document, expression);
174 }
175
176 public Long evalLong(Object root, String expression) {
177 return Long.valueOf(evalString(root, expression));
178 }
179
180 public Float evalFloat(String expression) {
181 return evalFloat(document, expression);
182 }
183
184 public Float evalFloat(Object root, String expression) {
185 return Float.valueOf(evalString(root, expression));
186 }
187
188 public Double evalDouble(String expression) {
189 return evalDouble(document, expression);
190 }
191
192 public Double evalDouble(Object root, String expression) {
193 return (Double) evaluate(expression, root, XPathConstants.NUMBER);
194 }
195
196 public List<XNode> evalNodes(String expression) {
197 return evalNodes(document, expression);
198 }
199
200 public List<XNode> evalNodes(Object root, String expression) {
201 List<XNode> xnodes = new ArrayList<>();
202 NodeList nodes = (NodeList) evaluate(expression, root, XPathConstants.NODESET);
203 for (int i = 0; i < nodes.getLength(); i++) {
204 xnodes.add(new XNode(this, nodes.item(i), variables));
205 }
206 return xnodes;
207 }
208
209 public XNode evalNode(String expression) {
210 return evalNode(document, expression);
211 }
212
213 public XNode evalNode(Object root, String expression) {
214 Node node = (Node) evaluate(expression, root, XPathConstants.NODE);
215 if (node == null) {
216 return null;
217 }
218 return new XNode(this, node, variables);
219 }
220
221 private Object evaluate(String expression, Object root, QName returnType) {
222 try {
223 return xpath.evaluate(expression, root, returnType);
224 } catch (Exception e) {
225 throw new BuilderException("Error evaluating XPath. Cause: " + e, e);
226 }
227 }
228
229 private Document createDocument(InputSource inputSource) {
230
231 try {
232 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
233 factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
234 factory.setValidating(validation);
235
236 factory.setNamespaceAware(false);
237 factory.setIgnoringComments(true);
238 factory.setIgnoringElementContentWhitespace(false);
239 factory.setCoalescing(false);
240 factory.setExpandEntityReferences(false);
241
242 DocumentBuilder builder = factory.newDocumentBuilder();
243 builder.setEntityResolver(entityResolver);
244 builder.setErrorHandler(new ErrorHandler() {
245 @Override
246 public void error(SAXParseException exception) throws SAXException {
247 throw exception;
248 }
249
250 @Override
251 public void fatalError(SAXParseException exception) throws SAXException {
252 throw exception;
253 }
254
255 @Override
256 public void warning(SAXParseException exception) throws SAXException {
257
258 }
259 });
260 return builder.parse(inputSource);
261 } catch (Exception e) {
262 throw new BuilderException("Error creating document instance. Cause: " + e, e);
263 }
264 }
265
266 private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
267 this.validation = validation;
268 this.entityResolver = entityResolver;
269 this.variables = variables;
270 XPathFactory factory = XPathFactory.newInstance();
271 this.xpath = factory.newXPath();
272 }
273
274 }