diff options
Diffstat (limited to 'parser/html/java/htmlparser/src/nu/validator/saxtree/ParentNode.java')
-rw-r--r-- | parser/html/java/htmlparser/src/nu/validator/saxtree/ParentNode.java | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/parser/html/java/htmlparser/src/nu/validator/saxtree/ParentNode.java b/parser/html/java/htmlparser/src/nu/validator/saxtree/ParentNode.java new file mode 100644 index 000000000..6cc96003f --- /dev/null +++ b/parser/html/java/htmlparser/src/nu/validator/saxtree/ParentNode.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2007 Henri Sivonen + * Copyright (c) 2008 Mozilla Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package nu.validator.saxtree; + +import org.xml.sax.Locator; + +/** + * Common superclass for parent nodes. + * @version $Id$ + * @author hsivonen + */ +public abstract class ParentNode extends Node { + + /** + * The end locator. + */ + protected Locator endLocator; + + /** + * The first child. + */ + private Node firstChild = null; + + /** + * The last child (for efficiency). + */ + private Node lastChild = null; + + /** + * The constuctor. + * @param locator the locator + */ + ParentNode(Locator locator) { + super(locator); + } + + /** + * Sets the endLocator. + * + * @param endLocator the endLocator to set + */ + public void setEndLocator(Locator endLocator) { + this.endLocator = new LocatorImpl(endLocator); + } + + /** + * Copies the endLocator from another node. + * + * @param another the another node + */ + public void copyEndLocator(ParentNode another) { + this.endLocator = another.endLocator; + } + + /** + * Returns the firstChild. + * + * @return the firstChild + */ + public final Node getFirstChild() { + return firstChild; + } + + /** + * Returns the lastChild. + * + * @return the lastChild + */ + public final Node getLastChild() { + return lastChild; + } + + /** + * Insert a new child before a pre-existing child and return the newly inserted child. + * @param child the new child + * @param sibling the existing child before which to insert (must be a child of this node) or <code>null</code> to append + * @return <code>child</code> + */ + public Node insertBefore(Node child, Node sibling) { + assert sibling == null || this == sibling.getParentNode(); + if (sibling == null) { + return appendChild(child); + } + child.detach(); + child.setParentNode(this); + if (firstChild == sibling) { + child.setNextSibling(sibling); + firstChild = child; + } else { + Node prev = firstChild; + Node next = firstChild.getNextSibling(); + while (next != sibling) { + prev = next; + next = next.getNextSibling(); + } + prev.setNextSibling(child); + child.setNextSibling(next); + } + return child; + } + + public Node insertBetween(Node child, Node prev, Node next) { + assert prev == null || this == prev.getParentNode(); + assert next == null || this == next.getParentNode(); + assert prev != null || next == firstChild; + assert next != null || prev == lastChild; + assert prev == null || next == null || prev.getNextSibling() == next; + if (next == null) { + return appendChild(child); + } + child.detach(); + child.setParentNode(this); + child.setNextSibling(next); + if (prev == null) { + firstChild = child; + } else { + prev.setNextSibling(child); + } + return child; + } + + /** + * Append a child to this node and return the child. + * + * @param child the child to append. + * @return <code>child</code> + */ + public Node appendChild(Node child) { + child.detach(); + child.setParentNode(this); + if (firstChild == null) { + firstChild = child; + } else { + lastChild.setNextSibling(child); + } + lastChild = child; + return child; + } + + /** + * Append the children of another node to this node removing them from the other node . + * @param parent the other node whose children to append to this one + */ + public void appendChildren(Node parent) { + Node child = parent.getFirstChild(); + if (child == null) { + return; + } + ParentNode another = (ParentNode) parent; + if (firstChild == null) { + firstChild = child; + } else { + lastChild.setNextSibling(child); + } + lastChild = another.lastChild; + do { + child.setParentNode(this); + } while ((child = child.getNextSibling()) != null); + another.firstChild = null; + another.lastChild = null; + } + + /** + * Remove a child from this node. + * @param node the child to remove + */ + void removeChild(Node node) { + assert this == node.getParentNode(); + if (firstChild == node) { + firstChild = node.getNextSibling(); + if (lastChild == node) { + lastChild = null; + } + } else { + Node prev = firstChild; + Node next = firstChild.getNextSibling(); + while (next != node) { + prev = next; + next = next.getNextSibling(); + } + prev.setNextSibling(node.getNextSibling()); + if (lastChild == node) { + lastChild = prev; + } + } + } +} |