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.util.ArrayList;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Properties;
22 import java.util.function.Supplier;
23
24 import org.w3c.dom.CharacterData;
25 import org.w3c.dom.Element;
26 import org.w3c.dom.NamedNodeMap;
27 import org.w3c.dom.Node;
28 import org.w3c.dom.NodeList;
29
30
31
32
33 public class XNode {
34
35 private final Node node;
36 private final String name;
37 private final String body;
38 private final Properties attributes;
39 private final Properties variables;
40 private final XPathParser xpathParser;
41
42 public XNode(XPathParser xpathParser, Node node, Properties variables) {
43 this.xpathParser = xpathParser;
44 this.node = node;
45 this.name = node.getNodeName();
46 this.variables = variables;
47 this.attributes = parseAttributes(node);
48 this.body = parseBody(node);
49 }
50
51 public XNode newXNode(Node node) {
52 return new XNode(xpathParser, node, variables);
53 }
54
55 public XNode getParent() {
56 Node parent = node.getParentNode();
57 if (!(parent instanceof Element)) {
58 return null;
59 } else {
60 return new XNode(xpathParser, parent, variables);
61 }
62 }
63
64 public String getPath() {
65 StringBuilder builder = new StringBuilder();
66 Node current = node;
67 while (current instanceof Element) {
68 if (current != node) {
69 builder.insert(0, "/");
70 }
71 builder.insert(0, current.getNodeName());
72 current = current.getParentNode();
73 }
74 return builder.toString();
75 }
76
77 public String getValueBasedIdentifier() {
78 StringBuilder builder = new StringBuilder();
79 XNode current = this;
80 while (current != null) {
81 if (current != this) {
82 builder.insert(0, "_");
83 }
84 String value = current.getStringAttribute("id",
85 current.getStringAttribute("value",
86 current.getStringAttribute("property", (String) null)));
87 if (value != null) {
88 value = value.replace('.', '_');
89 builder.insert(0, "]");
90 builder.insert(0,
91 value);
92 builder.insert(0, "[");
93 }
94 builder.insert(0, current.getName());
95 current = current.getParent();
96 }
97 return builder.toString();
98 }
99
100 public String evalString(String expression) {
101 return xpathParser.evalString(node, expression);
102 }
103
104 public Boolean evalBoolean(String expression) {
105 return xpathParser.evalBoolean(node, expression);
106 }
107
108 public Double evalDouble(String expression) {
109 return xpathParser.evalDouble(node, expression);
110 }
111
112 public List<XNode> evalNodes(String expression) {
113 return xpathParser.evalNodes(node, expression);
114 }
115
116 public XNode evalNode(String expression) {
117 return xpathParser.evalNode(node, expression);
118 }
119
120 public Node getNode() {
121 return node;
122 }
123
124 public String getName() {
125 return name;
126 }
127
128 public String getStringBody() {
129 return getStringBody(null);
130 }
131
132 public String getStringBody(String def) {
133 if (body == null) {
134 return def;
135 } else {
136 return body;
137 }
138 }
139
140 public Boolean getBooleanBody() {
141 return getBooleanBody(null);
142 }
143
144 public Boolean getBooleanBody(Boolean def) {
145 if (body == null) {
146 return def;
147 } else {
148 return Boolean.valueOf(body);
149 }
150 }
151
152 public Integer getIntBody() {
153 return getIntBody(null);
154 }
155
156 public Integer getIntBody(Integer def) {
157 if (body == null) {
158 return def;
159 } else {
160 return Integer.parseInt(body);
161 }
162 }
163
164 public Long getLongBody() {
165 return getLongBody(null);
166 }
167
168 public Long getLongBody(Long def) {
169 if (body == null) {
170 return def;
171 } else {
172 return Long.parseLong(body);
173 }
174 }
175
176 public Double getDoubleBody() {
177 return getDoubleBody(null);
178 }
179
180 public Double getDoubleBody(Double def) {
181 if (body == null) {
182 return def;
183 } else {
184 return Double.parseDouble(body);
185 }
186 }
187
188 public Float getFloatBody() {
189 return getFloatBody(null);
190 }
191
192 public Float getFloatBody(Float def) {
193 if (body == null) {
194 return def;
195 } else {
196 return Float.parseFloat(body);
197 }
198 }
199
200 public <T extends Enum<T>> T getEnumAttribute(Class<T> enumType, String name) {
201 return getEnumAttribute(enumType, name, null);
202 }
203
204 public <T extends Enum<T>> T getEnumAttribute(Class<T> enumType, String name, T def) {
205 String value = getStringAttribute(name);
206 if (value == null) {
207 return def;
208 } else {
209 return Enum.valueOf(enumType, value);
210 }
211 }
212
213
214
215
216
217
218
219
220
221
222
223
224
225 public String getStringAttribute(String name, Supplier<String> defSupplier) {
226 String value = attributes.getProperty(name);
227 return value == null ? defSupplier.get() : value;
228 }
229
230 public String getStringAttribute(String name) {
231 return getStringAttribute(name, (String) null);
232 }
233
234 public String getStringAttribute(String name, String def) {
235 String value = attributes.getProperty(name);
236 if (value == null) {
237 return def;
238 } else {
239 return value;
240 }
241 }
242
243 public Boolean getBooleanAttribute(String name) {
244 return getBooleanAttribute(name, null);
245 }
246
247 public Boolean getBooleanAttribute(String name, Boolean def) {
248 String value = attributes.getProperty(name);
249 if (value == null) {
250 return def;
251 } else {
252 return Boolean.valueOf(value);
253 }
254 }
255
256 public Integer getIntAttribute(String name) {
257 return getIntAttribute(name, null);
258 }
259
260 public Integer getIntAttribute(String name, Integer def) {
261 String value = attributes.getProperty(name);
262 if (value == null) {
263 return def;
264 } else {
265 return Integer.parseInt(value);
266 }
267 }
268
269 public Long getLongAttribute(String name) {
270 return getLongAttribute(name, null);
271 }
272
273 public Long getLongAttribute(String name, Long def) {
274 String value = attributes.getProperty(name);
275 if (value == null) {
276 return def;
277 } else {
278 return Long.parseLong(value);
279 }
280 }
281
282 public Double getDoubleAttribute(String name) {
283 return getDoubleAttribute(name, null);
284 }
285
286 public Double getDoubleAttribute(String name, Double def) {
287 String value = attributes.getProperty(name);
288 if (value == null) {
289 return def;
290 } else {
291 return Double.parseDouble(value);
292 }
293 }
294
295 public Float getFloatAttribute(String name) {
296 return getFloatAttribute(name, null);
297 }
298
299 public Float getFloatAttribute(String name, Float def) {
300 String value = attributes.getProperty(name);
301 if (value == null) {
302 return def;
303 } else {
304 return Float.parseFloat(value);
305 }
306 }
307
308 public List<XNode> getChildren() {
309 List<XNode> children = new ArrayList<>();
310 NodeList nodeList = node.getChildNodes();
311 if (nodeList != null) {
312 for (int i = 0, n = nodeList.getLength(); i < n; i++) {
313 Node node = nodeList.item(i);
314 if (node.getNodeType() == Node.ELEMENT_NODE) {
315 children.add(new XNode(xpathParser, node, variables));
316 }
317 }
318 }
319 return children;
320 }
321
322 public Properties getChildrenAsProperties() {
323 Properties properties = new Properties();
324 for (XNode child : getChildren()) {
325 String name = child.getStringAttribute("name");
326 String value = child.getStringAttribute("value");
327 if (name != null && value != null) {
328 properties.setProperty(name, value);
329 }
330 }
331 return properties;
332 }
333
334 @Override
335 public String toString() {
336 StringBuilder builder = new StringBuilder();
337 toString(builder, 0);
338 return builder.toString();
339 }
340
341 private void toString(StringBuilder builder, int level) {
342 builder.append("<");
343 builder.append(name);
344 for (Map.Entry<Object, Object> entry : attributes.entrySet()) {
345 builder.append(" ");
346 builder.append(entry.getKey());
347 builder.append("=\"");
348 builder.append(entry.getValue());
349 builder.append("\"");
350 }
351 List<XNode> children = getChildren();
352 if (!children.isEmpty()) {
353 builder.append(">\n");
354 for (XNode child : children) {
355 indent(builder, level + 1);
356 child.toString(builder, level + 1);
357 }
358 indent(builder, level);
359 builder.append("</");
360 builder.append(name);
361 builder.append(">");
362 } else if (body != null) {
363 builder.append(">");
364 builder.append(body);
365 builder.append("</");
366 builder.append(name);
367 builder.append(">");
368 } else {
369 builder.append("/>");
370 indent(builder, level);
371 }
372 builder.append("\n");
373 }
374
375 private void indent(StringBuilder builder, int level) {
376 for (int i = 0; i < level; i++) {
377 builder.append(" ");
378 }
379 }
380
381 private Properties parseAttributes(Node n) {
382 Properties attributes = new Properties();
383 NamedNodeMap attributeNodes = n.getAttributes();
384 if (attributeNodes != null) {
385 for (int i = 0; i < attributeNodes.getLength(); i++) {
386 Node attribute = attributeNodes.item(i);
387 String value = PropertyParser.parse(attribute.getNodeValue(), variables);
388 attributes.put(attribute.getNodeName(), value);
389 }
390 }
391 return attributes;
392 }
393
394 private String parseBody(Node node) {
395 String data = getBodyData(node);
396 if (data == null) {
397 NodeList children = node.getChildNodes();
398 for (int i = 0; i < children.getLength(); i++) {
399 Node child = children.item(i);
400 data = getBodyData(child);
401 if (data != null) {
402 break;
403 }
404 }
405 }
406 return data;
407 }
408
409 private String getBodyData(Node child) {
410 if (child.getNodeType() == Node.CDATA_SECTION_NODE
411 || child.getNodeType() == Node.TEXT_NODE) {
412 String data = ((CharacterData) child).getData();
413 data = PropertyParser.parse(data, variables);
414 return data;
415 }
416 return null;
417 }
418
419 }