001 /*
002 * Copyright (c) 2007 Henri Sivonen
003 *
004 * Permission is hereby granted, free of charge, to any person obtaining a
005 * copy of this software and associated documentation files (the "Software"),
006 * to deal in the Software without restriction, including without limitation
007 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
008 * and/or sell copies of the Software, and to permit persons to whom the
009 * Software is furnished to do so, subject to the following conditions:
010 *
011 * The above copyright notice and this permission notice shall be included in
012 * all copies or substantial portions of the Software.
013 *
014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
017 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
019 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
020 * DEALINGS IN THE SOFTWARE.
021 */
022
023 package nu.validator.saxtree;
024
025 import org.xml.sax.Locator;
026
027 public abstract class ParentNode extends Node {
028
029 protected Locator endLocator;
030
031 private Node firstChild = null;
032
033 private Node lastChild = null;
034
035 ParentNode(Locator locator) {
036 super(locator);
037 }
038
039 /**
040 * Sets the endLocator.
041 *
042 * @param endLocator the endLocator to set
043 */
044 public void setEndLocator(Locator endLocator) {
045 this.endLocator = new LocatorImpl(endLocator);
046 }
047
048 /**
049 * Copies the endLocator from another node.
050 *
051 * @param another the another node
052 */
053 public void copyEndLocator(ParentNode another) {
054 this.endLocator = another.endLocator;
055 }
056
057 /**
058 * Returns the firstChild.
059 *
060 * @return the firstChild
061 */
062 public final Node getFirstChild() {
063 return firstChild;
064 }
065
066 /**
067 * Returns the lastChild.
068 *
069 * @return the lastChild
070 */
071 public final Node getLastChild() {
072 return lastChild;
073 }
074
075 public Node insertBefore(Node child, Node sibling) {
076 assert sibling == null || this == sibling.getParentNode();
077 if (sibling == null) {
078 return appendChild(child);
079 }
080 child.detach();
081 child.setParentNode(this);
082 if (firstChild == sibling) {
083 child.setNextSibling(sibling);
084 firstChild = child;
085 } else {
086 Node prev = firstChild;
087 Node next = firstChild.getNextSibling();
088 while (next != sibling) {
089 prev = next;
090 next = next.getNextSibling();
091 }
092 prev.setNextSibling(child);
093 child.setNextSibling(next);
094 }
095 return child;
096 }
097
098 public Node appendChild(Node child) {
099 child.detach();
100 child.setParentNode(this);
101 if (firstChild == null) {
102 firstChild = child;
103 } else {
104 lastChild.setNextSibling(child);
105 }
106 lastChild = child;
107 return child;
108 }
109
110 public void appendChildren(Node parent) {
111 Node child = parent.getFirstChild();
112 if (child == null) {
113 return;
114 }
115 ParentNode another = (ParentNode) parent;
116 if (firstChild == null) {
117 firstChild = child;
118 } else {
119 lastChild.setNextSibling(child);
120 }
121 lastChild = another.lastChild;
122 do {
123 child.setParentNode(this);
124 } while ((child = child.getNextSibling()) != null);
125 another.firstChild = null;
126 another.lastChild = null;
127 }
128
129 void removeChild(Node node) {
130 assert this == node.getParentNode();
131 if (firstChild == node) {
132 firstChild = node.getNextSibling();
133 if (lastChild == node) {
134 lastChild = null;
135 }
136 } else {
137 Node prev = firstChild;
138 Node next = firstChild.getNextSibling();
139 while (next != node) {
140 prev = next;
141 next = next.getNextSibling();
142 }
143 prev.setNextSibling(node.getNextSibling());
144 if (lastChild == node) {
145 lastChild = prev;
146 }
147 }
148 }
149 }