1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 package groovy.xml.dom;
34
35 import org.w3c.dom.*;
36 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
37
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.ArrayList;
41 import java.util.Collection;
42
43 /***
44 * @author sam
45 * @author paulk
46 */
47 public class DOMCategory {
48
49 private static boolean trimWhitespace = true;
50
51 public static Object get(Object o, String elementName) {
52 if (o instanceof Element) {
53 return get((Element) o, elementName);
54 }
55 if (o instanceof NodeList) {
56 return get((NodeList) o, elementName);
57 }
58 if (o instanceof NamedNodeMap) {
59 return get((NamedNodeMap) o, elementName);
60 }
61 return null;
62 }
63
64 private static Object get(Element element, String elementName) {
65 return getAt(element, elementName);
66 }
67
68 private static Object get(NodeList nodeList, String elementName) {
69 return getAt(nodeList, elementName);
70 }
71
72 private static Object get(NamedNodeMap nodeMap, String elementName) {
73 return getAt(nodeMap, elementName);
74 }
75
76 private static Object getAt(Element element, String elementName) {
77 if ("..".equals(elementName)) {
78 return parent(element);
79 }
80 if ("**".equals(elementName)) {
81 return depthFirst(element);
82 }
83 if (elementName.startsWith("@")) {
84 return element.getAttribute(elementName.substring(1));
85 }
86 return getChildElements(element, elementName);
87 }
88
89 private static Object getAt(NodeList nodeList, String elementName) {
90 List results = new ArrayList();
91 for (int i = 0; i < nodeList.getLength(); i++) {
92 Node node = nodeList.item(i);
93 if (node instanceof Element) {
94 addResult(results, get(node, elementName));
95 }
96 }
97 if (elementName.startsWith("@")) {
98 return results;
99 }
100 return new NodeListsHolder(results);
101 }
102
103 public static NamedNodeMap attributes(Element element) {
104 return element.getAttributes();
105 }
106
107 private static String getAt(NamedNodeMap namedNodeMap, String elementName) {
108 Attr a = (Attr) namedNodeMap.getNamedItem(elementName);
109 return a.getValue();
110 }
111
112 public static int size(NamedNodeMap namedNodeMap) {
113 return namedNodeMap.getLength();
114 }
115
116 public static Node getAt(Node o, int i) {
117 return nodeGetAt(o, i);
118 }
119
120 public static Node getAt(NodeListsHolder o, int i) {
121 return nodeGetAt(o, i);
122 }
123
124 public static Node getAt(NodesHolder o, int i) {
125 return nodeGetAt(o, i);
126 }
127
128 private static Node nodeGetAt(Object o, int i) {
129 if (o instanceof Element) {
130 Node n = getAt((Element)o, i);
131 if (n != null) return n;
132 }
133 if (o instanceof NodeList) {
134 return getAt((NodeList)o, i);
135 }
136 return null;
137 }
138
139 private static Node getAt(Element element, int i) {
140 if (hasChildElements(element, "*")) {
141 NodeList nodeList = getChildElements(element, "*");
142 return nodeList.item(i);
143 }
144 return null;
145 }
146
147 private static Node getAt(NodeList nodeList, int i) {
148 if (i >= 0 && i < nodeList.getLength()) {
149 return nodeList.item(i);
150 }
151 return null;
152 }
153
154 public static String name(Element element) {
155 return element.getNodeName();
156 }
157
158 public static Node parent(Node node) {
159 return node.getParentNode();
160 }
161
162 public static String text(Object o) {
163 if (o instanceof Element) {
164 return text((Element) o);
165 }
166 if (o instanceof Node) {
167 Node n = (Node) o;
168 if (n.getNodeType() == Node.TEXT_NODE) {
169 return n.getNodeValue();
170 }
171 }
172 if (o instanceof NodeList) {
173 return text((NodeList) o);
174 }
175 return null;
176 }
177
178 private static String text(Element element) {
179 if (!element.hasChildNodes()) {
180 return "";
181 }
182 if (element.getFirstChild().getNodeType() != Node.TEXT_NODE) {
183 return "";
184 }
185 return element.getFirstChild().getNodeValue();
186 }
187
188 private static String text(NodeList nodeList) {
189 StringBuffer sb = new StringBuffer();
190 for (int i = 0; i < nodeList.getLength(); i++) {
191 sb.append(text(nodeList.item(i)));
192 }
193 return sb.toString();
194 }
195
196 public static List list(NodeList self) {
197 List answer = new ArrayList();
198 Iterator it = DefaultGroovyMethods.iterator(self);
199 while (it.hasNext()) {
200 answer.add(it.next());
201 }
202 return answer;
203 }
204
205 public static NodeList depthFirst(Element self) {
206 List result = new ArrayList();
207 result.add(createNodeList(self));
208 result.add(self.getElementsByTagName("*"));
209 return new NodeListsHolder(result);
210 }
211
212 private static NodeList createNodeList(Element self) {
213 List first = new ArrayList();
214 first.add(self);
215 return new NodesHolder(first);
216 }
217
218 public static NodeList breadthFirst(Element self) {
219 List result = new ArrayList();
220 NodeList thisLevel = createNodeList(self);
221 while (thisLevel.getLength() > 0) {
222 result.add(thisLevel);
223 thisLevel = getNextLevel(thisLevel);
224 }
225 return new NodeListsHolder(result);
226 }
227
228 private static NodeList getNextLevel(NodeList thisLevel) {
229 List result = new ArrayList();
230 for (int i = 0; i < thisLevel.getLength(); i++) {
231 Node n = thisLevel.item(i);
232 if (n instanceof Element) {
233 result.add(getChildElements((Element) n, "*"));
234 }
235 }
236 return new NodeListsHolder(result);
237 }
238
239 public static NodeList children(Element self) {
240 return getChildElements(self, "*");
241 }
242
243 private static boolean hasChildElements(Element self, String elementName) {
244 return getChildElements(self, elementName).getLength() > 0;
245 }
246
247 private static NodeList getChildElements(Element self, String elementName) {
248 List result = new ArrayList();
249 NodeList nodeList = self.getChildNodes();
250 for (int i = 0; i < nodeList.getLength(); i++) {
251 Node node = nodeList.item(i);
252 if (node.getNodeType() == Node.ELEMENT_NODE) {
253 Element child = (Element) node;
254 if ("*".equals(elementName) || child.getTagName().equals(elementName)) {
255 result.add(child);
256 }
257 } else if (node.getNodeType() == Node.TEXT_NODE) {
258 String value = node.getNodeValue();
259 if (trimWhitespace) {
260 value = value.trim();
261 }
262 if ("*".equals(elementName) && value.length() > 0) {
263 node.setNodeValue(value);
264 result.add(node);
265 }
266 }
267 }
268 return new NodesHolder(result);
269 }
270
271 public static String toString(Object o) {
272 if (o instanceof Node) {
273 if (((Node) o).getNodeType() == Node.TEXT_NODE) {
274 return ((Node) o).getNodeValue();
275 }
276 }
277 if (o instanceof NodeList) {
278 return toString((NodeList) o);
279 }
280 return o.toString();
281 }
282
283 private static String toString(NodeList self) {
284 StringBuffer sb = new StringBuffer();
285 sb.append("[");
286 Iterator it = DefaultGroovyMethods.iterator(self);
287 while (it.hasNext()) {
288 if (sb.length() > 1) sb.append(", ");
289 sb.append(it.next().toString());
290 }
291 sb.append("]");
292 return sb.toString();
293 }
294
295 public static int size(NodeList self) {
296 return self.getLength();
297 }
298
299 public static boolean isEmpty(NodeList self) {
300 return size(self) == 0;
301 }
302
303 private static void addResult(List results, Object result) {
304 if (result != null) {
305 if (result instanceof Collection) {
306 results.addAll((Collection) result);
307 } else {
308 results.add(result);
309 }
310 }
311 }
312
313 private static class NodeListsHolder implements NodeList {
314 private List nodeLists;
315
316 private NodeListsHolder(List nodeLists) {
317 this.nodeLists = nodeLists;
318 }
319
320 public int getLength() {
321 int length = 0;
322 for (int i = 0; i < nodeLists.size(); i++) {
323 NodeList nl = (NodeList) nodeLists.get(i);
324 length += nl.getLength();
325 }
326 return length;
327 }
328
329 public Node item(int index) {
330 int relativeIndex = index;
331 for (int i = 0; i < nodeLists.size(); i++) {
332 NodeList nl = (NodeList) nodeLists.get(i);
333 if (relativeIndex < nl.getLength()) {
334 return nl.item(relativeIndex);
335 }
336 relativeIndex -= nl.getLength();
337 }
338 return null;
339 }
340
341 public String toString() {
342 return DOMCategory.toString(this);
343 }
344 }
345
346 private static class NodesHolder implements NodeList {
347 private List nodes;
348
349 private NodesHolder(List nodes) {
350 this.nodes = nodes;
351 }
352
353 public int getLength() {
354 return nodes.size();
355 }
356
357 public Node item(int index) {
358 if (index < 0 || index >= getLength()) {
359 return null;
360 }
361 return (Node) nodes.get(index);
362 }
363 }
364 }