001 /* 002 * Copyright 2009 - 2010 JEuclid, http://jeuclid.sf.net 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 /* $Id $ */ 018 019 package net.sourceforge.jeuclid.biparser; 020 021 import org.w3c.dom.Node; 022 023 /** 024 * this class is used to store typical information about a xml-node. 025 * 026 * @version $Revision: 0b66106c7ff7 $ 027 * 028 */ 029 public abstract class AbstractBiNode implements IBiNode { 030 031 /** previous node, null if node is root. */ 032 private IBiNode previous; 033 034 /** sibling node, can be null. */ 035 private IBiNode sibling; 036 037 /** reference to node in DOM-tree. */ 038 private Node node; 039 040 /** length of node in characters. */ 041 private int length; 042 043 /** 044 * get previous node, null if node is root. 045 * 046 * @return previous 047 */ 048 public final IBiNode getPrevious() { 049 return this.previous; 050 } 051 052 /** 053 * set previous for this node. 054 * 055 * @param prev 056 * previous node for this node 057 */ 058 public final void setPrevious(final IBiNode prev) { 059 this.previous = prev; 060 } 061 062 /** 063 * get parent node for this node. 064 * 065 * @return parent 066 */ 067 public final BiNode getParent() { 068 // check if previous isn't a "real parent" 069 if (this.previous != null && this.previous.getSibling() == this) { 070 return this.previous.getParent(); 071 } else { 072 // previous is "real parent" or null 073 return (BiNode) this.previous; 074 } 075 } 076 077 /** 078 * get sibling node, can be null. 079 * 080 * @return sibling 081 */ 082 public final IBiNode getSibling() { 083 return this.sibling; 084 } 085 086 /** 087 * set sibling for this node and set previous of sibling to this. 088 * 089 * @param sibl 090 * new sibling for this node 091 */ 092 public final void setSibling(final IBiNode sibl) { 093 if (sibl != null) { 094 sibl.setPrevious(this); 095 } 096 097 this.sibling = sibl; 098 } 099 100 /** 101 * add sibling to a node, not possible at a textnode. if node already has a 102 * sibling, forward to sibling. 103 * 104 * @param sibl 105 * new sibling for this node 106 */ 107 public final void addSibling(final IBiNode sibl) { 108 if (this.sibling == null) { 109 // 2nd child 110 this.setSibling(sibl); 111 } else { 112 // forward(3rd - nth child) 113 this.sibling.addSibling(sibl); 114 } 115 } 116 117 /** 118 * get reference to node in DOM-tree. 119 * 120 * @return node in DOM-tree 121 */ 122 public final Node getNode() { 123 return this.node; 124 } 125 126 /** 127 * set reference to node in DOM-tree. 128 * 129 * @param n 130 * reference in DOM-tree 131 */ 132 public final void setNode(final Node n) { 133 this.node = n; 134 } 135 136 /** 137 * get length of node (number of characters). 138 * 139 * @return length of node 140 */ 141 public final int getLength() { 142 return this.length; 143 } 144 145 /** 146 * set length of node. 147 * 148 * @param len 149 * to set 150 */ 151 public final void setLength(final int len) { 152 this.length = len; 153 } 154 155 /** 156 * change length of node and recursive of all parents. 157 * 158 * @param change 159 * changevalue (can be positive or negative) 160 */ 161 public final void changeLengthRec(final int change) { 162 if (change == 0) { 163 return; 164 } 165 166 this.length += change; 167 168 if (this.getParent() != null) { 169 this.getParent().changeLengthRec(change); 170 } 171 } 172 173 /** 174 * helper method to insert or remove characters. 175 * 176 * @param insert 177 * if true call insert-method else remove-method 178 * @param biTree 179 * reference to BiTree to which this node contains 180 * @param offset 181 * position to insert/remove characters 182 * @param len 183 * number of characters to insert/remove 184 * @param totalOffset 185 * offset of node to begin of text 186 * @throws ReparseException 187 * if a reparse at upper level is needed 188 * @throws NonIncrementalElementException 189 * if the subtree contains an element which cannot be 190 * incrementally updated. 191 */ 192 public void forwardToSibling(final boolean insert, final BiTree biTree, 193 final int offset, final int len, final int totalOffset) 194 throws ReparseException, NonIncrementalElementException { 195 196 if (this.getSibling() == null) { 197 // reparsing 198 throw new ReparseException(); 199 } else { 200 if (insert) { 201 this.getSibling().insert(biTree, offset, len, totalOffset); 202 } else { 203 this.getSibling().remove(biTree, offset, len, totalOffset); 204 } 205 } 206 } 207 208 /** 209 * search a DOM node in this node. if nodes are equal return offset to begin 210 * of inputtext, else null 211 * 212 * @param n 213 * DOM node to search for 214 * @param totalOffset 215 * offset of node to begin of inputtext 216 * @return position of node in inputtext 217 */ 218 public TextPosition searchNode(final Node n, final int totalOffset) { 219 if (this.node != null && this.node.equals(n)) { 220 return new TextPosition(totalOffset, this.length); 221 } 222 223 return null; 224 } 225 226 /** 227 * helper method for outputting the length of node. 228 * 229 * @return formatted output of length 230 */ 231 public String formatLength() { 232 int i; 233 final int max = 3; 234 final StringBuffer sb = new StringBuffer(); 235 236 for (i = 1; i <= max && 1 > this.getLength() / Math.pow(10, max - i); i++) { 237 238 if (i == 1 && this.getLength() == 0) { 239 continue; 240 } 241 sb.append(' '); 242 } 243 244 sb.append(this.length); 245 246 return sb.toString(); 247 } 248 }