001: /*
002: ItsNat Java Web Application Framework
003: Copyright (C) 2007 Innowhere Software Services S.L., Spanish Company
004: Author: Jose Maria Arranz Santamaria
005:
006: This program is free software: you can redistribute it and/or modify
007: it under the terms of the GNU Affero General Public License as published by
008: the Free Software Foundation, either version 3 of the License, or
009: (at your option) any later version. See the GNU Affero General Public
010: License for more details. See the copy of the GNU Affero General Public License
011: included in this program. If not, see <http://www.gnu.org/licenses/>.
012: */
013:
014: package org.itsnat.core.domutil;
015:
016: import org.w3c.dom.Document;
017: import org.w3c.dom.DocumentFragment;
018: import org.w3c.dom.Element;
019: import org.w3c.dom.Node;
020: import org.w3c.dom.Text;
021:
022: /**
023: * Utility class used to easily iterate a DOM tree, specially DOM elements.
024: *
025: * <p>Most of methods have been inspired by <code>org.w3c.dom.traversal.TreeWalker</code>.</p>
026: *
027: * @author Jose Maria Arranz Santamaria
028: */
029: public class ItsNatTreeWalker {
030: /**
031: * Informs whether the specified node has child elements.
032: *
033: * @param node the node to inspect.
034: * @return true if the specified node has child elements.
035: */
036: public static boolean hasChildElements(Node node) {
037: return (getFirstChildElement(node) != null);
038: }
039:
040: /**
041: * Returns the number of child elements of the specified node.
042: *
043: * @param node the node to inspect.
044: * @return the number of child elements.
045: */
046: public static int getChildElementCount(Node node) {
047: // Filtramos los nodos de texto
048: int count = 0;
049: Element child = getFirstChildElement(node);
050: while (child != null) {
051: count++;
052: child = getNextSiblingElement(child);
053: }
054: return count;
055: }
056:
057: /**
058: * Returns the first direct child <code>org.w3c.dom.Element</code> below the specified node.
059: * Any child non-element is ignored.
060: *
061: * @param node the node parent.
062: * @return the first child element. Null if the parent node has no child element.
063: */
064: public static Element getFirstChildElement(Node node) {
065: // node normalmente será un Document o un Element
066: // Evitamos con esto usar un TreeWalker evitando la creación de un objeto
067: Node child = node.getFirstChild();
068: while (child != null) {
069: if (child.getNodeType() == Node.ELEMENT_NODE)
070: return (Element) child;
071:
072: child = child.getNextSibling();
073: }
074: return null;
075: }
076:
077: /**
078: * Returns the last direct child <code>org.w3c.dom.Element</code> below the specified node.
079: * Any child non-element is ignored.
080: *
081: * @param node the node parent.
082: * @return the last child element. Null if the parent node has no child element.
083: */
084: public static Element getLastChildElement(Node node) {
085: // Ver getFirstChildElement()
086:
087: Node child = node.getLastChild();
088: while (child != null) {
089: if (child.getNodeType() == Node.ELEMENT_NODE)
090: return (Element) child;
091:
092: child = child.getPreviousSibling();
093: }
094: return null;
095: }
096:
097: /**
098: * Returns the next sibling <code>org.w3c.dom.Element</code> following the specified node.
099: * Any non-element is ignored.
100: *
101: * @param node the original node.
102: * @return the next sibling element. Null if the node has no next sibling element (last child element).
103: */
104: public static Element getNextSiblingElement(Node node) {
105: // Ver getFirstChildElement()
106: Node sibling = node.getNextSibling();
107: while (sibling != null) {
108: if (sibling.getNodeType() == Node.ELEMENT_NODE)
109: return (Element) sibling;
110:
111: sibling = sibling.getNextSibling();
112: }
113: return null;
114: }
115:
116: /**
117: * Returns the previous sibling <code>org.w3c.dom.Element</code> following the specified node.
118: * Any non-element is ignored.
119: *
120: * @param node the original node.
121: * @return the previous sibling element. Null if the node has no previous sibling element (first child element).
122: */
123: public static Element getPreviousSiblingElement(Node node) {
124: // Ver getFirstChildElement()
125: Node sibling = node.getPreviousSibling();
126: while (sibling != null) {
127: if (sibling.getNodeType() == Node.ELEMENT_NODE)
128: return (Element) sibling;
129:
130: sibling = sibling.getPreviousSibling();
131: }
132: return null;
133: }
134:
135: /**
136: * Returns the first parent <code>org.w3c.dom.Element</code> of specified node.
137: * Any non-element parent is ignored.
138: *
139: * @param node the original node.
140: * @return the first parent element. Null if the node has no parent element (for instance, the document root element).
141: */
142: public static Element getParentElement(Node node) {
143: if (node == null)
144: return null;
145: Node parent = node.getParentNode();
146: if (parent == null)
147: return null;
148: if (parent.getNodeType() == Node.ELEMENT_NODE)
149: return (Element) parent;
150: return null; // Puede ser el caso de que el parent es el Document
151: }
152:
153: /**
154: * Returns the previous <code>org.w3c.dom.Element</code> following the specified node in document order.
155: * Any non-element is ignored.
156: *
157: * @param node the original node.
158: * @return the previous element. Null if the node has no previous element.
159: */
160: public static Element getPreviousElement(Node node) {
161: if (node == null)
162: return null;
163:
164: Element prevSibling = getPreviousSiblingElement(node);
165: if (prevSibling == null) {
166: return getParentElement(node); // puede ser null
167: }
168:
169: Element lastChild = getLastChildElement(prevSibling);
170: if (lastChild == null)
171: return prevSibling; // Sí mismo no tiene elementos hijo
172:
173: Element prevChild;
174: do {
175: prevChild = lastChild;
176: lastChild = getLastChildElement(prevChild);
177: } while (lastChild != null);
178:
179: lastChild = prevChild;
180:
181: return lastChild;
182: }
183:
184: /**
185: * Returns the next <code>org.w3c.dom.Element</code> following the specified node in document order.
186: * Any non-element is ignored.
187: *
188: * @param node the original node.
189: * @return the next element. Null if the node has no next element.
190: */
191: public static Element getNextElement(Node node) {
192: if (node == null)
193: return null;
194:
195: Element result = getFirstChildElement(node);
196: if (result != null)
197: return result;
198:
199: result = getNextSiblingElement(node);
200: if (result != null)
201: return result;
202:
203: // return parent's 1st sibling.
204: Element parent = getParentElement(node);
205: while (parent != null) {
206: result = getNextSiblingElement(parent);
207: if (result != null)
208: return result;
209: else
210: parent = getParentElement(parent);
211: }
212:
213: // end , return null
214: return null;
215: }
216:
217: /**
218: * Returns the previous node following the specified node in document order.
219: *
220: * @param node the original node.
221: * @return the previous node. Null if the node has no previous node.
222: */
223: public static Node getPreviousNode(Node node) {
224: if (node == null)
225: return null;
226:
227: Node prevSibling = node.getPreviousSibling();
228: if (prevSibling == null) {
229: return node.getParentNode(); // puede ser null
230: }
231:
232: Node lastChild = prevSibling.getLastChild();
233: if (lastChild == null)
234: return prevSibling; // Sí mismo no tiene elementos hijo
235:
236: Node prevChild;
237: do {
238: prevChild = lastChild;
239: lastChild = prevChild.getLastChild();
240: } while (lastChild != null);
241:
242: lastChild = prevChild;
243:
244: return lastChild;
245: }
246:
247: /**
248: * Returns the next node following the specified node in document order.
249: *
250: * @param node the original node.
251: * @return the next node. Null if the node has no next node.
252: */
253: public static Node getNextNode(Node node) {
254: if (node == null)
255: return null;
256:
257: Node result = node.getFirstChild();
258: if (result != null)
259: return result;
260:
261: result = node.getNextSibling();
262: if (result != null)
263: return result;
264:
265: // return parent's 1st sibling.
266: Node parent = node.getParentNode();
267: while (parent != null) {
268: result = parent.getNextSibling();
269: if (result != null)
270: return result;
271: else
272: parent = parent.getParentNode();
273: }
274:
275: // end , return null
276: return null;
277: }
278:
279: /**
280: * Returns the first direct child element with the specified tag name.
281: *
282: * @param parent the parent node.
283: * @param tagName the tag name to search for, if an HTML tag use uppercase.
284: * @return the first direct child element with this tag or null if not found.
285: */
286: public static Element getFirstChildElementWithTag(Node parent,
287: String tagName) {
288: // Este método es porque hay métodos tal y como el método HTMLTableElement.getTBodies() que no funciona bien
289: // en el Xerces de la JVM 1.4
290: // Si se usa para buscar elementos HTML pasar tagName en mayúsculas porque
291: // getTagName() en Xerces DOM HTML devuelve en mayúsculas
292:
293: Element child = getFirstChildElement(parent);
294: while (child != null) {
295: String currTagName = child.getTagName(); // Xerces devuelve mayúsculas en HTML
296: if (currTagName.equals(tagName))
297: return child;
298: child = getNextSiblingElement(child);
299: }
300: return null;
301: }
302: }
|