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 }