001: /*
002: * Copyright (c) 2002-2008 Gargoyle Software Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * 1. Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: * 2. Redistributions in binary form must reproduce the above copyright notice,
010: * this list of conditions and the following disclaimer in the documentation
011: * and/or other materials provided with the distribution.
012: * 3. The end-user documentation included with the redistribution, if any, must
013: * include the following acknowledgment:
014: *
015: * "This product includes software developed by Gargoyle Software Inc.
016: * (http://www.GargoyleSoftware.com/)."
017: *
018: * Alternately, this acknowledgment may appear in the software itself, if
019: * and wherever such third-party acknowledgments normally appear.
020: * 4. The name "Gargoyle Software" must not be used to endorse or promote
021: * products derived from this software without prior written permission.
022: * For written permission, please contact info@GargoyleSoftware.com.
023: * 5. Products derived from this software may not be called "HtmlUnit", nor may
024: * "HtmlUnit" appear in their name, without prior written permission of
025: * Gargoyle Software Inc.
026: *
027: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
028: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
029: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
030: * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
031: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
032: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
033: * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
034: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
035: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
036: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037: */
038: package com.gargoylesoftware.htmlunit.html;
039:
040: import java.util.Iterator;
041: import java.util.NoSuchElementException;
042:
043: /**
044: * Provides some utilities for working on the Html document.
045: *
046: * @version $Revision: 2132 $
047: * @author Marc Guillemot
048: * @author Ahmed Ashour
049: */
050: public final class Util {
051:
052: /** Private constructor to prevent instantiation */
053: private Util() {
054: // does nothing
055: }
056:
057: /**
058: * Get an iterator over all following nodes, depth-first.
059: *
060: * @param contextNode The context node for the following axis.
061: * @return A possibly-empty iterator (not null).
062: */
063: public static Iterator getFollowingSiblingAxisIterator(
064: final DomNode contextNode) {
065: return new NodeIterator(contextNode) {
066: protected DomNode getFirstNode(final DomNode node) {
067: return getNextNode(node);
068: }
069:
070: protected DomNode getNextNode(final DomNode node) {
071: return node.getNextDomSibling();
072: }
073: };
074: }
075:
076: /**
077: * Get an iterator over all preceding siblings.
078: *
079: * @param contextNode The context node for the preceding sibling axis.
080: * @return A possibly-empty iterator (not null).
081: */
082: public static Iterator getPrecedingSiblingAxisIterator(
083: final DomNode contextNode) {
084: return new NodeIterator(contextNode) {
085: protected DomNode getFirstNode(final DomNode node) {
086: return getNextNode(node);
087: }
088:
089: protected DomNode getNextNode(final DomNode node) {
090: return node.getPreviousDomSibling();
091: }
092: };
093: }
094:
095: /**
096: * Get an iterator over all following nodes, depth-first.
097: *
098: * @param contextNode The context node for the following axis.
099: * @return A possibly-empty iterator (not null).
100: */
101: public static Iterator getFollowingAxisIterator(
102: final DomNode contextNode) {
103: return new NodeIterator(contextNode) {
104: protected DomNode getFirstNode(final DomNode node) {
105: if (node == null) {
106: return null;
107: } else {
108: final DomNode sibling = node.getNextDomSibling();
109: if (sibling == null) {
110: return getFirstNode(node.getParentDomNode());
111: } else {
112: return sibling;
113: }
114: }
115: }
116:
117: protected DomNode getNextNode(final DomNode node) {
118: if (node == null) {
119: return null;
120: } else {
121: DomNode n = node.getFirstDomChild();
122: if (n == null) {
123: n = node.getNextDomSibling();
124: }
125: if (n == null) {
126: return getFirstNode(node.getParentDomNode());
127: } else {
128: return n;
129: }
130: }
131: }
132: };
133: }
134:
135: /**
136: * Get an iterator over all preceding nodes, depth-first.
137: *
138: * @param contextNode The context node for the preceding axis.
139: * @return A possibly-empty iterator (not null).
140: */
141: public static Iterator getPrecedingAxisIterator(
142: final DomNode contextNode) {
143: return new NodeIterator(contextNode) {
144: protected DomNode getFirstNode(final DomNode node) {
145: if (node == null) {
146: return null;
147: } else {
148: final DomNode sibling = node
149: .getPreviousDomSibling();
150: if (sibling == null) {
151: return getFirstNode(node.getParentDomNode());
152: } else {
153: return sibling;
154: }
155: }
156: }
157:
158: protected DomNode getNextNode(final DomNode node) {
159: if (node == null) {
160: return null;
161: } else {
162: DomNode n = node.getLastDomChild();
163: if (n == null) {
164: n = node.getPreviousDomSibling();
165: }
166: if (n == null) {
167: return getFirstNode(node.getParentDomNode());
168: } else {
169: return n;
170: }
171: }
172: }
173: };
174: }
175: }
176:
177: /**
178: * A generic iterator over DOM nodes.
179: *
180: * <p>Concrete subclasses must implement the {@link #getFirstNode}
181: * and {@link #getNextNode} methods for a specific iteration
182: * strategy.</p>
183: */
184: abstract class NodeIterator implements Iterator {
185:
186: private DomNode node_;
187:
188: /**
189: * @param contextNode The starting node.
190: */
191: public NodeIterator(final DomNode contextNode) {
192: node_ = getFirstNode(contextNode);
193: }
194:
195: /** @inheritDoc Iterator#hasNext() */
196: public boolean hasNext() {
197: return (node_ != null);
198: }
199:
200: /** @inheritDoc Iterator#next() */
201: public Object next() {
202: if (node_ == null) {
203: throw new NoSuchElementException();
204: }
205: final DomNode ret = node_;
206: node_ = getNextNode(node_);
207: return ret;
208: }
209:
210: /** @inheritDoc Iterator#remove() */
211: public void remove() {
212: throw new UnsupportedOperationException();
213: }
214:
215: /**
216: * Get the first node for iteration.
217: *
218: * <p>This method must derive an initial node for iteration
219: * from a context node.</p>
220: *
221: * @param contextNode The starting node.
222: * @return The first node in the iteration.
223: * @see #getNextNode
224: */
225: protected abstract DomNode getFirstNode(final DomNode contextNode);
226:
227: /**
228: * Get the next node for iteration.
229: *
230: * <p>This method must locate a following node from the
231: * current context node.</p>
232: *
233: * @param contextNode The current node in the iteration.
234: * @return The following node in the iteration, or null
235: * if there is none.
236: * @see #getFirstNode
237: */
238: protected abstract DomNode getNextNode(final DomNode contextNode);
239: }
|