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 }
60 return new XNode(xpathParser, parent, variables);
61 }
62
63 public String getPath() {
64 StringBuilder builder = new StringBuilder();
65 Node current = node;
66 while (current instanceof Element) {
67 if (current != node) {
68 builder.insert(0, "/");
69 }
70 builder.insert(0, current.getNodeName());
71 current = current.getParentNode();
72 }
73 return builder.toString();
74 }
75
76 public String getValueBasedIdentifier() {
77 StringBuilder builder = new StringBuilder();
78 XNode current = this;
79 while (current != null) {
80 if (current != this) {
81 builder.insert(0, "_");
82 }
83 String value = current.getStringAttribute("id",
84 current.getStringAttribute("value", current.getStringAttribute("property", (String) null)));
85 if (value != null) {
86 value = value.replace('.', '_');
87 builder.insert(0, "]");
88 builder.insert(0, value);
89 builder.insert(0, "[");
90 }
91 builder.insert(0, current.getName());
92 current = current.getParent();
93 }
94 return builder.toString();
95 }
96
97 public String evalString(String expression) {
98 return xpathParser.evalString(node, expression);
99 }
100
101 public Boolean evalBoolean(String expression) {
102 return xpathParser.evalBoolean(node, expression);
103 }
104
105 public Double evalDouble(String expression) {
106 return xpathParser.evalDouble(node, expression);
107 }
108
109 public List<XNode> evalNodes(String expression) {
110 return xpathParser.evalNodes(node, expression);
111 }
112
113 public XNode evalNode(String expression) {
114 return xpathParser.evalNode(node, expression);
115 }
116
117 public Node getNode() {
118 return node;
119 }
120
121 public String getName() {
122 return name;
123 }
124
125 public String getStringBody() {
126 return getStringBody(null);
127 }
128
129 public String getStringBody(String def) {
130 return body == null ? def : body;
131 }
132
133 public Boolean getBooleanBody() {
134 return getBooleanBody(null);
135 }
136
137 public Boolean getBooleanBody(Boolean def) {
138 return body == null ? def : Boolean.valueOf(body);
139 }
140
141 public Integer getIntBody() {
142 return getIntBody(null);
143 }
144
145 public Integer getIntBody(Integer def) {
146 return body == null ? def : Integer.valueOf(body);
147 }
148
149 public Long getLongBody() {
150 return getLongBody(null);
151 }
152
153 public Long getLongBody(Long def) {
154 return body == null ? def : Long.valueOf(body);
155 }
156
157 public Double getDoubleBody() {
158 return getDoubleBody(null);
159 }
160
161 public Double getDoubleBody(Double def) {
162 return body == null ? def : Double.valueOf(body);
163 }
164
165 public Float getFloatBody() {
166 return getFloatBody(null);
167 }
168
169 public Float getFloatBody(Float def) {
170 return body == null ? def : Float.valueOf(body);
171 }
172
173 public <T extends Enum<T>> T getEnumAttribute(Class<T> enumType, String name) {
174 return getEnumAttribute(enumType, name, null);
175 }
176
177 public <T extends Enum<T>> T getEnumAttribute(Class<T> enumType, String name, T def) {
178 String value = getStringAttribute(name);
179 return value == null ? def : Enum.valueOf(enumType, value);
180 }
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196 public String getStringAttribute(String name, Supplier<String> defSupplier) {
197 String value = attributes.getProperty(name);
198 return value == null ? defSupplier.get() : value;
199 }
200
201 public String getStringAttribute(String name) {
202 return getStringAttribute(name, (String) null);
203 }
204
205 public String getStringAttribute(String name, String def) {
206 String value = attributes.getProperty(name);
207 return value == null ? def : value;
208 }
209
210 public Boolean getBooleanAttribute(String name) {
211 return getBooleanAttribute(name, null);
212 }
213
214 public Boolean getBooleanAttribute(String name, Boolean def) {
215 String value = attributes.getProperty(name);
216 return value == null ? def : Boolean.valueOf(value);
217 }
218
219 public Integer getIntAttribute(String name) {
220 return getIntAttribute(name, null);
221 }
222
223 public Integer getIntAttribute(String name, Integer def) {
224 String value = attributes.getProperty(name);
225 return value == null ? def : Integer.valueOf(value);
226 }
227
228 public Long getLongAttribute(String name) {
229 return getLongAttribute(name, null);
230 }
231
232 public Long getLongAttribute(String name, Long def) {
233 String value = attributes.getProperty(name);
234 return value == null ? def : Long.valueOf(value);
235 }
236
237 public Double getDoubleAttribute(String name) {
238 return getDoubleAttribute(name, null);
239 }
240
241 public Double getDoubleAttribute(String name, Double def) {
242 String value = attributes.getProperty(name);
243 return value == null ? def : Double.valueOf(value);
244 }
245
246 public Float getFloatAttribute(String name) {
247 return getFloatAttribute(name, null);
248 }
249
250 public Float getFloatAttribute(String name, Float def) {
251 String value = attributes.getProperty(name);
252 return value == null ? def : Float.valueOf(value);
253 }
254
255 public List<XNode> getChildren() {
256 List<XNode> children = new ArrayList<>();
257 NodeList nodeList = node.getChildNodes();
258 if (nodeList != null) {
259 for (int i = 0, n = nodeList.getLength(); i < n; i++) {
260 Node node = nodeList.item(i);
261 if (node.getNodeType() == Node.ELEMENT_NODE) {
262 children.add(new XNode(xpathParser, node, variables));
263 }
264 }
265 }
266 return children;
267 }
268
269 public Properties getChildrenAsProperties() {
270 Properties properties = new Properties();
271 for (XNode child : getChildren()) {
272 String name = child.getStringAttribute("name");
273 String value = child.getStringAttribute("value");
274 if (name != null && value != null) {
275 properties.setProperty(name, value);
276 }
277 }
278 return properties;
279 }
280
281 @Override
282 public String toString() {
283 return buildToString(new StringBuilder(), 0).toString();
284 }
285
286 private StringBuilder buildToString(StringBuilder builder, int indentLevel) {
287 indent(builder, indentLevel).append("<").append(name);
288 for (Map.Entry<Object, Object> entry : attributes.entrySet()) {
289 builder.append(" ");
290 builder.append(entry.getKey());
291 builder.append("=\"");
292 builder.append(entry.getValue());
293 builder.append("\"");
294 }
295
296 NodeList nodeList = node.getChildNodes();
297 if (nodeList == null || nodeList.getLength() == 0) {
298 builder.append(" />\n");
299 } else {
300 builder.append(">\n");
301 for (int i = 0, n = nodeList.getLength(); i < n; i++) {
302 Node node = nodeList.item(i);
303 short nodeType = node.getNodeType();
304 if (nodeType == Node.ELEMENT_NODE) {
305 new XNode(xpathParser, node, variables).buildToString(builder, indentLevel + 1);
306 } else {
307 String text = getBodyData(node).trim();
308 if (text.length() > 0) {
309 indent(builder, indentLevel + 1).append(text).append("\n");
310 }
311 }
312 }
313 indent(builder, indentLevel).append("</").append(name).append(">\n");
314 }
315
316 return builder;
317 }
318
319 private StringBuilder indent(StringBuilder builder, int level) {
320 for (int i = 0; i < level; i++) {
321 builder.append(" ");
322 }
323 return builder;
324 }
325
326 private Properties parseAttributes(Node n) {
327 Properties attributes = new Properties();
328 NamedNodeMap attributeNodes = n.getAttributes();
329 if (attributeNodes != null) {
330 for (int i = 0; i < attributeNodes.getLength(); i++) {
331 Node attribute = attributeNodes.item(i);
332 String value = PropertyParser.parse(attribute.getNodeValue(), variables);
333 attributes.put(attribute.getNodeName(), value);
334 }
335 }
336 return attributes;
337 }
338
339 private String parseBody(Node node) {
340 String data = getBodyData(node);
341 if (data == null) {
342 NodeList children = node.getChildNodes();
343 for (int i = 0; i < children.getLength(); i++) {
344 Node child = children.item(i);
345 data = getBodyData(child);
346 if (data != null) {
347 break;
348 }
349 }
350 }
351 return data;
352 }
353
354 private String getBodyData(Node child) {
355 if (child.getNodeType() == Node.CDATA_SECTION_NODE || child.getNodeType() == Node.TEXT_NODE) {
356 String data = ((CharacterData) child).getData();
357 return PropertyParser.parse(data, variables);
358 }
359 return null;
360 }
361
362 }