001 /*
002 * $Id: DOMCategory.java 4201 2006-11-05 10:23:50Z paulk $version Apr 25, 2004 5:18:30 PM $user Exp $
003 *
004 * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
005 *
006 * Redistribution and use of this software and associated documentation
007 * ("Software"), with or without modification, are permitted provided that the
008 * following conditions are met: 1. Redistributions of source code must retain
009 * copyright statements and notices. Redistributions must also contain a copy of
010 * this document. 2. Redistributions in binary form must reproduce the above
011 * copyright notice, this list of conditions and the following disclaimer in the
012 * documentation and/or other materials provided with the distribution. 3. The
013 * name "groovy" must not be used to endorse or promote products derived from
014 * this Software without prior written permission of The Codehaus. For written
015 * permission, please contact info@codehaus.org. 4. Products derived from this
016 * Software may not be called "groovy" nor may "groovy" appear in their names
017 * without prior written permission of The Codehaus. "groovy" is a registered
018 * trademark of The Codehaus. 5. Due credit should be given to The Codehaus -
019 * http://groovy.codehaus.org/
020 *
021 * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
022 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
023 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
024 * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
025 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
026 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
027 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
028 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
029 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
030 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031 *
032 */
033 package groovy.xml.dom;
034
035 import org.w3c.dom.*;
036 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
037
038 import java.util.Iterator;
039 import java.util.List;
040 import java.util.ArrayList;
041 import java.util.Collection;
042
043 /**
044 * @author sam
045 * @author paulk
046 */
047 public class DOMCategory {
048
049 private static boolean trimWhitespace = true;
050
051 public static Object get(Object o, String elementName) {
052 if (o instanceof Element) {
053 return get((Element) o, elementName);
054 }
055 if (o instanceof NodeList) {
056 return get((NodeList) o, elementName);
057 }
058 if (o instanceof NamedNodeMap) {
059 return get((NamedNodeMap) o, elementName);
060 }
061 return null;
062 }
063
064 private static Object get(Element element, String elementName) {
065 return getAt(element, elementName);
066 }
067
068 private static Object get(NodeList nodeList, String elementName) {
069 return getAt(nodeList, elementName);
070 }
071
072 private static Object get(NamedNodeMap nodeMap, String elementName) {
073 return getAt(nodeMap, elementName);
074 }
075
076 private static Object getAt(Element element, String elementName) {
077 if ("..".equals(elementName)) {
078 return parent(element);
079 }
080 if ("**".equals(elementName)) {
081 return depthFirst(element);
082 }
083 if (elementName.startsWith("@")) {
084 return element.getAttribute(elementName.substring(1));
085 }
086 return getChildElements(element, elementName);
087 }
088
089 private static Object getAt(NodeList nodeList, String elementName) {
090 List results = new ArrayList();
091 for (int i = 0; i < nodeList.getLength(); i++) {
092 Node node = nodeList.item(i);
093 if (node instanceof Element) {
094 addResult(results, get(node, elementName));
095 }
096 }
097 if (elementName.startsWith("@")) {
098 return results;
099 }
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(Element element, int i) {
117 if (hasChildElements(element, "*")) {
118 NodeList nodeList = getChildElements(element, "*");
119 return nodeList.item(i);
120 }
121 return null;
122 }
123
124 public static Node getAt(NodeList nodeList, int i) {
125 if (i >= 0 && i < nodeList.getLength()) {
126 return nodeList.item(i);
127 }
128 return null;
129 }
130
131 public static String name(Element element) {
132 return element.getNodeName();
133 }
134
135 public static Node parent(Node node) {
136 return node.getParentNode();
137 }
138
139 public static String text(Object o) {
140 if (o instanceof Element) {
141 return text((Element) o);
142 }
143 if (o instanceof Node) {
144 Node n = (Node) o;
145 if (n.getNodeType() == Node.TEXT_NODE) {
146 return n.getNodeValue();
147 }
148 }
149 if (o instanceof NodeList) {
150 return text((NodeList) o);
151 }
152 return null;
153 }
154
155 private static String text(Element element) {
156 if (!element.hasChildNodes()) {
157 return "";
158 }
159 if (element.getFirstChild().getNodeType() != Node.TEXT_NODE) {
160 return "";
161 }
162 return element.getFirstChild().getNodeValue();
163 }
164
165 private static String text(NodeList nodeList) {
166 StringBuffer sb = new StringBuffer();
167 for (int i = 0; i < nodeList.getLength(); i++) {
168 sb.append(text(nodeList.item(i)));
169 }
170 return sb.toString();
171 }
172
173 public static List list(NodeList self) {
174 List answer = new ArrayList();
175 Iterator it = DefaultGroovyMethods.iterator(self);
176 while (it.hasNext()) {
177 answer.add(it.next());
178 }
179 return answer;
180 }
181
182 public static NodeList depthFirst(Element self) {
183 List result = new ArrayList();
184 result.add(createNodeList(self));
185 result.add(self.getElementsByTagName("*"));
186 return new NodeListsHolder(result);
187 }
188
189 private static NodeList createNodeList(Element self) {
190 List first = new ArrayList();
191 first.add(self);
192 return new NodesHolder(first);
193 }
194
195 public static NodeList breadthFirst(Element self) {
196 List result = new ArrayList();
197 NodeList thisLevel = createNodeList(self);
198 while (thisLevel.getLength() > 0) {
199 result.add(thisLevel);
200 thisLevel = getNextLevel(thisLevel);
201 }
202 return new NodeListsHolder(result);
203 }
204
205 private static NodeList getNextLevel(NodeList thisLevel) {
206 List result = new ArrayList();
207 for (int i = 0; i < thisLevel.getLength(); i++) {
208 Node n = thisLevel.item(i);
209 if (n instanceof Element) {
210 result.add(getChildElements((Element) n, "*"));
211 }
212 }
213 return new NodeListsHolder(result);
214 }
215
216 public static NodeList children(Element self) {
217 return getChildElements(self, "*");
218 }
219
220 private static boolean hasChildElements(Element self, String elementName) {
221 return getChildElements(self, elementName).getLength() > 0;
222 }
223
224 private static NodeList getChildElements(Element self, String elementName) {
225 List result = new ArrayList();
226 NodeList nodeList = self.getChildNodes();
227 for (int i = 0; i < nodeList.getLength(); i++) {
228 Node node = nodeList.item(i);
229 if (node.getNodeType() == Node.ELEMENT_NODE) {
230 Element child = (Element) node;
231 if ("*".equals(elementName) || child.getTagName().equals(elementName)) {
232 result.add(child);
233 }
234 } else if (node.getNodeType() == Node.TEXT_NODE) {
235 String value = node.getNodeValue();
236 if (trimWhitespace) {
237 value = value.trim();
238 }
239 if ("*".equals(elementName) && value.length() > 0) {
240 node.setNodeValue(value);
241 result.add(node);
242 }
243 }
244 }
245 return new NodesHolder(result);
246 }
247
248 public static String toString(Object o) {
249 if (o instanceof Node) {
250 if (((Node) o).getNodeType() == Node.TEXT_NODE) {
251 return ((Node) o).getNodeValue();
252 }
253 }
254 if (o instanceof NodeList) {
255 return toString((NodeList) o);
256 }
257 return o.toString();
258 }
259
260 private static String toString(NodeList self) {
261 StringBuffer sb = new StringBuffer();
262 sb.append("[");
263 Iterator it = DefaultGroovyMethods.iterator(self);
264 while (it.hasNext()) {
265 if (sb.length() > 1) sb.append(", ");
266 sb.append(it.next().toString());
267 }
268 sb.append("]");
269 return sb.toString();
270 }
271
272 public static int size(NodeList self) {
273 return self.getLength();
274 }
275
276 public static boolean isEmpty(NodeList self) {
277 return size(self) == 0;
278 }
279
280 private static void addResult(List results, Object result) {
281 if (result != null) {
282 if (result instanceof Collection) {
283 results.addAll((Collection) result);
284 } else {
285 results.add(result);
286 }
287 }
288 }
289
290 private static class NodeListsHolder implements NodeList {
291 private List nodeLists;
292
293 private NodeListsHolder(List nodeLists) {
294 this.nodeLists = nodeLists;
295 }
296
297 public int getLength() {
298 int length = 0;
299 for (int i = 0; i < nodeLists.size(); i++) {
300 NodeList nl = (NodeList) nodeLists.get(i);
301 length += nl.getLength();
302 }
303 return length;
304 }
305
306 public Node item(int index) {
307 int relativeIndex = index;
308 for (int i = 0; i < nodeLists.size(); i++) {
309 NodeList nl = (NodeList) nodeLists.get(i);
310 if (relativeIndex < nl.getLength()) {
311 return nl.item(relativeIndex);
312 }
313 relativeIndex -= nl.getLength();
314 }
315 return null;
316 }
317
318 public String toString() {
319 return DOMCategory.toString(this);
320 }
321 }
322
323 private static class NodesHolder implements NodeList {
324 private List nodes;
325
326 private NodesHolder(List nodes) {
327 this.nodes = nodes;
328 }
329
330 public int getLength() {
331 return nodes.size();
332 }
333
334 public Node item(int index) {
335 if (index < 0 || index >= getLength()) {
336 return null;
337 }
338 return (Node) nodes.get(index);
339 }
340 }
341 }