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 return body == null ? def : body;
134 }
135
136 public Boolean getBooleanBody() {
137 return getBooleanBody(null);
138 }
139
140 public Boolean getBooleanBody(Boolean def) {
141 return body == null ? def : Boolean.valueOf(body);
142 }
143
144 public Integer getIntBody() {
145 return getIntBody(null);
146 }
147
148 public Integer getIntBody(Integer def) {
149 return body == null ? def : Integer.valueOf(body);
150 }
151
152 public Long getLongBody() {
153 return getLongBody(null);
154 }
155
156 public Long getLongBody(Long def) {
157 return body == null ? def : Long.valueOf(body);
158 }
159
160 public Double getDoubleBody() {
161 return getDoubleBody(null);
162 }
163
164 public Double getDoubleBody(Double def) {
165 return body == null ? def : Double.valueOf(body);
166 }
167
168 public Float getFloatBody() {
169 return getFloatBody(null);
170 }
171
172 public Float getFloatBody(Float def) {
173 return body == null ? def : Float.valueOf(body);
174 }
175
176 public <T extends Enum<T>> T getEnumAttribute(Class<T> enumType, String name) {
177 return getEnumAttribute(enumType, name, null);
178 }
179
180 public <T extends Enum<T>> T getEnumAttribute(Class<T> enumType, String name, T def) {
181 String value = getStringAttribute(name);
182 return value == null ? def : Enum.valueOf(enumType,value);
183 }
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198 public String getStringAttribute(String name, Supplier<String> defSupplier) {
199 String value = attributes.getProperty(name);
200 return value == null ? defSupplier.get() : value;
201 }
202
203 public String getStringAttribute(String name) {
204 return getStringAttribute(name, (String) null);
205 }
206
207 public String getStringAttribute(String name, String def) {
208 String value = attributes.getProperty(name);
209 return value == null ? def : value;
210 }
211
212 public Boolean getBooleanAttribute(String name) {
213 return getBooleanAttribute(name, null);
214 }
215
216 public Boolean getBooleanAttribute(String name, Boolean def) {
217 String value = attributes.getProperty(name);
218 return value == null ? def : Boolean.valueOf(value);
219 }
220
221 public Integer getIntAttribute(String name) {
222 return getIntAttribute(name, null);
223 }
224
225 public Integer getIntAttribute(String name, Integer def) {
226 String value = attributes.getProperty(name);
227 return value == null ? def : Integer.valueOf(value);
228 }
229
230 public Long getLongAttribute(String name) {
231 return getLongAttribute(name, null);
232 }
233
234 public Long getLongAttribute(String name, Long def) {
235 String value = attributes.getProperty(name);
236 return value == null ? def : Long.valueOf(value);
237 }
238
239 public Double getDoubleAttribute(String name) {
240 return getDoubleAttribute(name, null);
241 }
242
243 public Double getDoubleAttribute(String name, Double def) {
244 String value = attributes.getProperty(name);
245 return value == null ? def : Double.valueOf(value);
246 }
247
248 public Float getFloatAttribute(String name) {
249 return getFloatAttribute(name, null);
250 }
251
252 public Float getFloatAttribute(String name, Float def) {
253 String value = attributes.getProperty(name);
254 return value == null ? def : Float.valueOf(value);
255 }
256
257 public List<XNode> getChildren() {
258 List<XNode> children = new ArrayList<>();
259 NodeList nodeList = node.getChildNodes();
260 if (nodeList != null) {
261 for (int i = 0, n = nodeList.getLength(); i < n; i++) {
262 Node node = nodeList.item(i);
263 if (node.getNodeType() == Node.ELEMENT_NODE) {
264 children.add(new XNode(xpathParser, node, variables));
265 }
266 }
267 }
268 return children;
269 }
270
271 public Properties getChildrenAsProperties() {
272 Properties properties = new Properties();
273 for (XNode child : getChildren()) {
274 String name = child.getStringAttribute("name");
275 String value = child.getStringAttribute("value");
276 if (name != null && value != null) {
277 properties.setProperty(name, value);
278 }
279 }
280 return properties;
281 }
282
283 @Override
284 public String toString() {
285 StringBuilder builder = new StringBuilder();
286 toString(builder, 0);
287 return builder.toString();
288 }
289
290 private void toString(StringBuilder builder, int level) {
291 builder.append("<");
292 builder.append(name);
293 for (Map.Entry<Object, Object> entry : attributes.entrySet()) {
294 builder.append(" ");
295 builder.append(entry.getKey());
296 builder.append("=\"");
297 builder.append(entry.getValue());
298 builder.append("\"");
299 }
300 List<XNode> children = getChildren();
301 if (!children.isEmpty()) {
302 builder.append(">\n");
303 for (XNode child : children) {
304 indent(builder, level + 1);
305 child.toString(builder, level + 1);
306 }
307 indent(builder, level);
308 builder.append("</");
309 builder.append(name);
310 builder.append(">");
311 } else if (body != null) {
312 builder.append(">");
313 builder.append(body);
314 builder.append("</");
315 builder.append(name);
316 builder.append(">");
317 } else {
318 builder.append("/>");
319 indent(builder, level);
320 }
321 builder.append("\n");
322 }
323
324 private void indent(StringBuilder builder, int level) {
325 for (int i = 0; i < level; i++) {
326 builder.append(" ");
327 }
328 }
329
330 private Properties parseAttributes(Node n) {
331 Properties attributes = new Properties();
332 NamedNodeMap attributeNodes = n.getAttributes();
333 if (attributeNodes != null) {
334 for (int i = 0; i < attributeNodes.getLength(); i++) {
335 Node attribute = attributeNodes.item(i);
336 String value = PropertyParser.parse(attribute.getNodeValue(), variables);
337 attributes.put(attribute.getNodeName(), value);
338 }
339 }
340 return attributes;
341 }
342
343 private String parseBody(Node node) {
344 String data = getBodyData(node);
345 if (data == null) {
346 NodeList children = node.getChildNodes();
347 for (int i = 0; i < children.getLength(); i++) {
348 Node child = children.item(i);
349 data = getBodyData(child);
350 if (data != null) {
351 break;
352 }
353 }
354 }
355 return data;
356 }
357
358 private String getBodyData(Node child) {
359 if (child.getNodeType() == Node.CDATA_SECTION_NODE
360 || child.getNodeType() == Node.TEXT_NODE) {
361 String data = ((CharacterData) child).getData();
362 data = PropertyParser.parse(data, variables);
363 return data;
364 }
365 return null;
366 }
367
368 }