001package Torello.HTML; 002 003import java.util.*; 004 005import java.util.function.ObjIntConsumer; 006 007// This is only needed for the Java Doc {@link ...} taglets. 008import Torello.HTML.NodeSearch.TagNodePeekL1Inclusive; 009 010import Torello.Java.LV; 011 012/** 013 * Methods for quickly & efficiently replacing the nodes on a Web-Page. 014 * 015 * <BR /><BR /><EMBED CLASS='external-html' DATA-FILE-ID=REPLACE_NODES> 016 */ 017@Torello.JavaDoc.StaticFunctional 018public class ReplaceNodes 019{ 020 private ReplaceNodes() { } 021 022 /** 023 * Allows a user to quickly alter each <B STYLE='color: red;'>row</B> in an HTML 024 * <B STYLE='color: red;'>table</B>, iteratively, in a manner that offers a tremendous 025 * efficiency-improvement over the HTML {@code Iterator's} in the Node Seach Package. 026 * 027 * <EMBED CLASS='external-html' DATA-FILE-ID=REPL_NODES_FAST DATA-ITEM='table-row'> 028 * 029 * <BR /><BR /><UL CLASS=JDUL> 030 * <LI> {@code 'page'} is not null. 031 * </LI> 032 * <LI> {@code 'table'} is non-null, and has {@link DotPair#start} and {@link DotPair#end} 033 * indices with integer-values smaller than the size of {@code 'page'} 034 * </LI> 035 * <LI> {@code 'table'} has indices which point to {@code TagNode's} in {@code 'page'} that 036 * are opening {@code <TABLE>} and closing {@code </TABLE>} tags. 037 * </LI> 038 * </UL> 039 * 040 * @param page Any HTML Page or sub-page that has a table. 041 * 042 * @param table A pointer to the table start and end index bounds. 043 * 044 * @param tableRowModifier <EMBED CLASS='external-html' DATA-TYPE=Table DATA-ENTITY=Row 045 * DATA-FILE-ID=REPL_NODES_ROW_MOD> 046 * 047 * @return <EMBED CLASS='external-html' DATA-FILE-ID=REPLACEMENT_MRET> 048 * <!-- Bororwed from Replacement.run(...) --> 049 * 050 * @see TagNodePeekL1Inclusive 051 * @see Replacement#run(Vector, Iterable, boolean) 052 * @see DotPair#exceptionCheck(Vector, String[]) 053 * @see SubSection 054 * <!-- In the JD Comments 'external-html/' directory, this is filed under 'r02r03/' --> 055 */ 056 public static Vector<HTMLNode> tableTR( 057 Vector<HTMLNode> page, DotPair table, 058 ObjIntConsumer<Vector<HTMLNode>> tableRowModifier 059 ) 060 { 061 // Ensure that page.elementAt(table.start) contains a "<TABLE>" element, and that 062 // page.elementAt(table.end) contains a "</TABLE>" element. 063 // 064 // If some other type of TagNode, or a non-TagNode is present, this method throws one of 065 // several exceptions to inform the user about the error. 066 067 table.exceptionCheck(page, "table"); 068 069 // Retrieve all "<TR> ... </TR>" elements. The "L1Inclusive" stipulates that any potential 070 // inner-table rows (if there are any inner-tables), should be ignored. 071 072 Vector<SubSection> rows = TagNodePeekL1Inclusive.all(page, table.start, table.end, "tr"); 073 074 // All this does is invoke the user-provided function-pointer on each table-row 075 for (int i=0; i < rows.size(); i++) tableRowModifier.accept(rows.elementAt(i).html, i); 076 077 // Update all Table-Rows. Remove the old Rows, and insert the new ones. This replace 078 // operation does this much more efficiently than most replacement-code. 079 080 return Replacement.run(page, rows, false).a; 081 } 082 083 /** 084 * Allows a user to quickly alter each <B STYLE='color: red;'>item</B> in an HTML 085 * <B STYLE='color: red;'>list</B> ({@code <OL>, <UL>} or {@code <MENU>}), iteratively, in a 086 * manner that offers a tremendous efficiency-improvement over the HTML {@code Iterator's} in 087 * the Node Seach Package. 088 * 089 * <EMBED CLASS='external-html' DATA-FILE-ID=REPL_NODES_FAST DATA-ITEM='list-item'> 090 * 091 * <BR /><BR /><UL CLASS=JDUL> 092 * <LI> {@code 'page'} is not null. 093 * </LI> 094 * <LI> {@code 'list'} is non-null, and has {@link DotPair#start} and {@link DotPair#end} 095 * indices with integer-values smaller than the size of {@code 'page'} 096 * </LI> 097 * <LI> {@code 'list'} has indices which point to {@code TagNode's} in {@code 'page'} that 098 * are opening-and-closing {@code <UL>, <OL>} or {@code <MENU>} tags. 099 * </LI> 100 * </UL> 101 * 102 * @param page Any HTML Page or sub-page that has an {@code <OL>, <UL>} or {@code <MENU>}. 103 * 104 * @param list A pointer to the list start and end index bounds. 105 * 106 * @param listItemModifier <EMBED CLASS='external-html' DATA-TYPE=List DATA-ENTITY=Item 107 * DATA-FILE-ID=REPL_NODES_ROW_MOD> 108 * 109 * @return <EMBED CLASS='external-html' DATA-FILE-ID=REPLACEMENT_MRET> <!-- Bororwed from R01 RET --> 110 * 111 * @see TagNodePeekL1Inclusive 112 * @see Replacement#run(Vector, Iterable, boolean) 113 * @see DotPair#exceptionCheck(Vector, String[]) 114 * @see SubSection 115 * <!-- In the JD Comments 'external-html/' directory, this is filed under 'r02r03/' --> 116 */ 117 public static Vector<HTMLNode> listLI( 118 Vector<HTMLNode> page, DotPair list, 119 ObjIntConsumer<Vector<HTMLNode>> listItemModifier 120 ) 121 { 122 // Ensure that page.elementAt(list.start) contains an "<OL>", "<UL>", or "<MENU>" element, 123 // and that page.elementAt(list.end) contains an "</OL>", "</UL>" or "</MENU>" element. 124 // 125 // If some other type of TagNode, or a non-TagNode is present, this method throws one of 126 // several exceptions to inform the user about the error. 127 128 list.exceptionCheck(page, "ol", "ul", "menu"); 129 130 // Retrieve all "<LI> ... </LI>" elements. The "L1Inclusive" stipulates that any potential 131 // inner-list items (if there are any inner-lists), should be ignored. 132 133 Vector<SubSection> items = TagNodePeekL1Inclusive.all(page, list.start, list.end, "li"); 134 135 // All this does is invoke the user-provided function-pointer on each list-item 136 for (int i=0; i < items.size(); i++) listItemModifier.accept(items.elementAt(i).html, i); 137 138 // Update all items. Remove the old-Items, and insert the new ones. This replace 139 // operation does this much more efficiently than most replacement-code. 140 141 return Replacement.run(page, items, false).a; 142 } 143 144 /** 145 * Iterates the integer-pointer values in {@code int[] posArr}, and replaces the nodes inside 146 * {@code 'html'} that have been identified by the {@code 'posArr'} list with a new node 147 * supplied by the {@code interface ReplaceFunction}. It should be obvious, that lambda 148 * expressions may be used here. 149 * 150 * <BR /><BR /><B CLASS=JDDescLabel>Returning 'null':</B> 151 * 152 * <BR />If the Lambda-Target / Functional-Interface {@link ReplaceFunction} (whose method 153 * is named {@link ReplaceFunction#getReplacement(HTMLNode, int, int)} 154 * <B><I STYLE='color: red;'>actually returns <CODE>'null'</CODE></I></B>, 155 * then null will indeed by inserted into the corresponding {@code Vector} position. 156 * 157 * @param html Any HTML page or section that has been loaded already. 158 * 159 * @param posArr This is usually generated by one of the node-search {@code 'Find.all(...)'} 160 * methods. Each and every one of the {@code 'Find.all(...)'} methods in the search package 161 * will return an array of integers. These integers represent positions/locations in the 162 * passed HTML page {@code Vector}. 163 * 164 * @param rf This is just a class that implements the {@code interface ReplaceFunction}. The 165 * interface has a single-method that will receive the position in the {@code Vector}, along 166 * with the {@code HTMLNode} found at that location. It is expected to produce a new version 167 * of the {@code HTMLNode}. This new node will be substituted into the page or sup-page. 168 * 169 * <BR /><BR />This function-pointer may return null, and when it does, <I>the node located at 170 * the current loop-iteration's {@code Vector}-index will not be replaced</I>. 171 * 172 * @return The number of nodes that were succesfully replaced. This number will be equal to 173 * {@code posArr.length} minus the number of times {@code rf} returned null; 174 * 175 * @throws ArrayIndexOutOfBoundsException <B><SPAN STYLE="color: red;">IMPORTANT 176 * NOTE:</B></SPAN> Usually, a position-{@code array} is generated by one of the search-methods 177 * in the NodeSearch package. If, however, the {@code Vector} has since changed and 178 * {@code posArr} contains stale-data, or if for other reasons there are invalid index-pointers 179 * in {@code posArr}, then an {@code ArrayIndexOutOfBoundsException} will, naturally, be thrown 180 * by java's {@code Vector.setElementAt(...)} method. 181 * 182 * @see ReplaceFunction 183 */ 184 public static int r(Vector<HTMLNode> html, int[] posArr, ReplaceFunction rf) 185 { 186 int counter=0, numReplaced=0; 187 HTMLNode n; 188 189 for (int pos : posArr) 190 191 // pos is the vector-position, counter is the "iteration-count" 192 if ((n = rf.getReplacement(html.elementAt(pos), pos, counter++)) != null) 193 { 194 html.setElementAt(n, pos); 195 numReplaced++; 196 } 197 198 return numReplaced; 199 } 200 201 /** 202 * This will replace <I>each and every node indicated by {@code 'posArr'}</I> with the 203 * exact same replacement node {@code 'n'}. 204 * 205 * @param html Any HTML page or section that has been loaded already. 206 * 207 * @param posArr This is usually generated by one of the node-search {@code 'Find.all(...)'} 208 * methods. Each and every one of the {@code 'Find.all(...)'} methods in the search package 209 * will return an array of integers. These integers represent positions/locations in the 210 * passed HTML page {@code Vector}. 211 * 212 * @param n This may be any non-null {@code HTMLNode}. This node shall be inserted (and will 213 * replace) each node indicated by the parameter {@code 'posArr'}. 214 * 215 * @throws ArrayIndexOutOfBoundsException <B><SPAN STYLE="color: red;">IMPORTANT 216 * NOTE:</B></SPAN> Usually, a position-{@code array} is generated by one of the search-methods 217 * in the NodeSearch package. If, however, the {@code Vector} has since changed and 218 * {@code posArr} contains stale-data, or if for other reasons there are invalid index-pointers 219 * in {@code posArr}, then an {@code ArrayIndexOutOfBoundsException} will, naturally, be thrown 220 * by java's {@code Vector.setElementAt(...)} method. 221 */ 222 public static void r(Vector<HTMLNode> html, int[] posArr, HTMLNode n) 223 { 224 int len= html.size(); 225 226 for (int i=0; i < len; i++) html.setElementAt(n, i); 227 } 228 229 /** 230 * Convenience Method. 231 * <BR />Invokes: {@link #r(Vector, int, int, ReplaceFunction)} 232 * <BR />Passes: Entire Range of {@code html} into {@code sPos & ePos} 233 */ 234 public static int r(Vector<HTMLNode> html, ReplaceFunction rf) 235 { return r(html, 0, -1, rf); } 236 237 /** 238 * Convenience Method. 239 * <BR />Invokes: {@link #r(Vector, int, int, ReplaceFunction)} 240 * <BR />Passes: {@link DotPair#start} & {@link DotPair#end} into {@code sPos & ePos} 241 */ 242 public static int r(Vector<HTMLNode> html, DotPair range, ReplaceFunction rf) 243 { return r(html, range.start, range.end + 1, rf); } 244 245 /** 246 * Iterates <I>the entire html-page, checking every node</I>, replacing them by the 247 * values returned by {@code 'rf'} (the replace function). The {@link ReplaceFunction} 248 * (parameter {@code 'rf'}) is expected to return values that either: 249 * 250 * <BR /><BR /><UL CLASS=JDUL> 251 * <LI>provide a replacement {@code HTMLNode} for the indicated position</LI> 252 * <LI>return null as a value - in which case, <I>no substitution will occur</I></LI> 253 * </UL> 254 * 255 * <BR /><BR /><B CLASS=JDDescLabel>Returning 'null':</B> 256 * 257 * <BR />If the Lambda-Target / Functional-Interface {@link ReplaceFunction} (whose method 258 * is named {@link ReplaceFunction#getReplacement(HTMLNode, int, int)} 259 * <B><I STYLE='color: red;'>returns <CODE>'null'</CODE></I></B>, 260 * then in this particular method (differing from a previous method in this class), the 261 * returned 'null' will be ignored, and no substitution will be performed. 262 * 263 * @param html Any HTML page or section that has been loaded already. 264 * 265 * @param sPos <EMBED CLASS='external-html' DATA-FILE-ID=SPOSVEC> 266 * @param ePos <EMBED CLASS='external-html' DATA-FILE-ID=EPOSVEC> 267 * 268 * @param rf This is just a class that implements the {@code interface ReplaceFunction}. The 269 * interface has a single-method (@code getReplacement(...)} that will receive the position in 270 * the {@code Vector}, along with the {@code HTMLNode} found at that location. It is expected 271 * to return a new version of the {@code HTMLNode}. 272 * 273 * <BR /><BR />This function-pointer may return null, and when it does, <I>the node located at 274 * the current loop-iteration's {@code Vector}-index will not be replaced</I>. 275 * 276 * @return The number of nodes that were succesfully replaced. This number will be equal to 277 * {@code html.size()} minus the number of times {@code rf} returned null; 278 * 279 * @throws IndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=VIOOBEX> 280 * 281 * @see ReplaceFunction 282 * @see HTMLNode 283 */ 284 public static int r(Vector<HTMLNode> html, int sPos, int ePos, ReplaceFunction rf) 285 { 286 LV l = new LV(html, sPos, ePos); 287 int numReplaced = 0; 288 289 for (int i=l.start; i < l.end; i++) 290 { 291 // Here the vector-position and iteration-number are the same 292 HTMLNode n = rf.getReplacement(html.elementAt(i), i, i); 293 294 if (n != null) 295 { 296 html.setElementAt(n, i); 297 numReplaced++; 298 } 299 } 300 301 return numReplaced; 302 } 303 304 /** 305 * Iterates the integer-pointer values listed by {@code 'posArr'}, and replaces every position 306 * in {@code 'html'} with an {@code HTMLNode} from the nodes provided by the {@code 'newNodes'} 307 * parameter. 308 * 309 * @param html Any HTML page or section that has been loaded already. 310 * 311 * @param posArr This is usually generated by one of the node-search {@code 'Find.all(...)'} 312 * methods. Each and every one of the {@code 'Find.all(...)'} methods in the search package 313 * will return an {@code int[] array}. These integers represent positions/locations in the 314 * passed HTML page {@code Vector.} 315 * 316 * @param newNodes This list of new nodes must have a length identical to the 317 * {@code int[] posArr} (pointer-Array) length. 318 * 319 * @throws ArrayIndexOutOfBoundsException This exception will throw if any of the elements of 320 * {@code 'posArr'} point to a position in the {@code Vector<HTMLNode> v} parameter that are 321 * out of bounds for that {@code Vector}. 322 * 323 * @throws IllegalArgumentException if the length of the position array (pointer-array) is not 324 * identical to the length of the new-nodes {@code Vector.} 325 */ 326 public static void r(Vector<HTMLNode> html, int[] posArr, Vector<HTMLNode> newNodes) 327 { 328 if (posArr.length != newNodes.size()) throw new ArrayIndexOutOfBoundsException( 329 "The pointer array 'posArr', and the replacement-node array 'newNodes' do not have " + 330 "equal lengths!\n" + 331 "posArr.length=" + posArr.length + ", newNodes.size()=" + newNodes.size() 332 ); 333 334 int newNodesPos = 0; 335 336 for (int pos : posArr) html.setElementAt(newNodes.elementAt(newNodesPos++), pos); 337 } 338 339 /** 340 * Convenience Method. 341 * <BR />Invokes: {@link #r(Vector, int, int, Vector)} 342 */ 343 public static int r(Vector<HTMLNode> html, DotPair range, Vector<HTMLNode> newNodes) 344 { return r(html, range.start, range.end + 1, newNodes); } 345 346 /** 347 * Replaces the nodes currently within the vectorized HTML parameter {@code 'html'}, in the 348 * sub-range provided by the {@code 'sPos'} and {@code 'ePos'} parameters - <I>using the new 349 * nodes provided by {@code Vector}-Parameter {@code 'newNodes'}.</I> This is, essentially, 350 * a sub-range array-replacement operation. 351 * 352 * <BR /><BR />Unless exactly the same number of nodes that are in the {@code 'replaceRange'} 353 * are also in {@code 'newNodes'}, this method shall have to shorten or lengthen the size of 354 * the HTML {@code Vector}. 355 * 356 * @param html This may be any HTML page or sub-page 357 * @param sPos <EMBED CLASS='external-html' DATA-FILE-ID=SPOSVEC> 358 * @param ePos <EMBED CLASS='external-html' DATA-FILE-ID=EPOSVEC> 359 * @param newNodes These are the new {@code HTMLNode's} that are to replace the old ones. 360 * @return The change in the size (size-delta) of the input {@code html} parameter. 361 * @throws IndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=VIOOBEX> 362 */ 363 public static int r(Vector<HTMLNode> html, int sPos, int ePos, Vector<HTMLNode> newNodes) 364 { 365 // The loop variable is needed because its constructor does all of the error checking. 366 // The constructor also checks for the negative-ePos, and changes it if it is negative 367 // 368 // The original version of this method has been deprected, and left as a private method to 369 // this class. It was before noticing the "mirrored" stipulations about Vector-operation 370 // "subList" View the source-code to see the original replace-range method. 371 372 LV l = new LV(html, sPos, ePos); 373 374 List<HTMLNode> list = html.subList(l.start, l.end); 375 376 // The Sun-Oracle Docs say that changes to the list returned by sub-list are mirrored into 377 // changes in the original vector. This is how sub-range operations are done. 378 379 list.clear(); 380 list.addAll(newNodes); 381 382 return newNodes.size() - (ePos - sPos); // ==> (newSize - originalSize) 383 } 384 385 386 // This was how to do this, until noticing in the Java-Docs that "subList" is "linked" 387 // to the original list! 388 389 private static void rOLD(Vector<HTMLNode> html, int sPos, int ePos, Vector<HTMLNode> newNodes) 390 { 391 LV l = new LV(html, sPos, ePos); 392 393 // Replacement while-loop. This will replace all nodes that can be replaced in the 394 // "replace range" - without growing or shrinking the size of the underlying vector. 395 // 396 // AFTERWARDS If there are still more nodes to insert, they will be inserted by 397 // growing the vector. 398 // 399 // AND ALSO If there were fewer nodes to insert than the number that need to be 400 // removed the Vector will be shortened. 401 402 int i = 0; 403 int j = sPos; 404 405 while ((j < l.end) && (i < newNodes.size())) 406 { 407 html.setElementAt(newNodes.elementAt(i), j); 408 409 i++; j++; 410 } 411 412 413 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 414 // CASE 1: The number of nodes to remove is precisely equal to the number being inserted. 415 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 416 417 if (l.size() == newNodes.size()) return; 418 419 420 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 421 // CASE 2: The number of nodes being removed is greater than the number being inserted 422 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 423 424 // Use Util.removeRange(...) to remove the remaining nodes that weren't replaced. 425 // More nodes need to be removed than the number of nodes that have already been inserted 426 // (in the previous loop). In this case the original HTML Vector will SHRINK in SIZE. 427 428 if (j < l.end) { Util.Remove.range(html, j, l.end); return; } 429 430 431 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 432 // CASE 3: There are more nodes being added than the number of nodes being removed. 433 // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 434 435 // Use Vector.addAll(...) to add the rest which haven't been inserted yet. 436 // The HTML Vector is going to grow. There were fewer nodes removed than the number of 437 // nodes that need to be inserted. 438 // 439 // NOTE: An "intermediate temp Vector" is used since the "Node Shift" is likely done more 440 // efficiently by 'Vector.addAll', than by calling 'Vector.add' multiple times. 441 442 Vector<HTMLNode> temp = new Vector<>(newNodes.size() - i); 443 444 while (i < newNodes.size()) temp.add(newNodes.elementAt(i++)); 445 446 html.addAll(l.end, temp); 447 } 448 449 /** 450 * Convenience Method. 451 * Invokes: {@link #r(Vector, int, int, HTMLNode)} 452 */ 453 public static int r(Vector<HTMLNode> html, DotPair range, HTMLNode newNode) 454 { return r(html, range.start, range.end + 1, newNode); } 455 456 /** 457 * Replaces the nodes currently within the vectorized HTML parameter {@code 'html'}, in the 458 * sub-range provided by the {@code 'sPos'} and {@code 'ePos'} parameters, <I>with a single 459 * new node provided by {@code 'newNode'}.</I> Essentially, this is a <B>Range Removal</B> 460 * Operation, because a complete sublist is removed, and only a single-node replaces it. 461 * 462 * <BR /><BR />Unless the replacement-range (defined by {@code 'sPos'} and {@code 'ePos'}) has 463 * a size equal to {@code '1'}, this operation will (obviously) shorten the size of the input 464 * HTML {@code Vector} by {@code size - 1} nodes. 465 * 466 * @param html This may be any HTML page or sub-page 467 * 468 * @param sPos <EMBED CLASS='external-html' DATA-FILE-ID=SPOSVEC> 469 * @param ePos <EMBED CLASS='external-html' DATA-FILE-ID=EPOSVEC> 470 * 471 * @param newNode This is the new {@code HTMLNode} that is to replace the (entire) list 472 * specified by parameters {@code 'sPos'} and {@code 'ePos'}. 473 * 474 * @return The change in the size (size-delta) of the input {@code html} parameter. 475 * The number returned will always equal {@code 1 - (ePos - sPos)}. This means the return 476 * value for this method will always be negative (i.e. the {@code Vector} shrunk) - unless 477 * {@code sPos} and {@code ePos} had specified a range that was equal to 1. 478 * 479 * @throws IndexOutOfBoundsException <EMBED CLASS='external-html' DATA-FILE-ID=VIOOBEX> 480 */ 481 public static int r(Vector<HTMLNode> html, int sPos, int ePos, HTMLNode newNode) 482 { 483 // This method doesn't have any "for-loops", but the LV class does all the much needed 484 // exception checks, and conversion computations. (ePos < 0 ==> epos = html.size()) 485 486 LV l = new LV(html, sPos, ePos); 487 488 html.setElementAt(newNode, l.start); 489 490 if (l.size() > 1) 491 492 // Util.removeRange(html, l.start + 1, l.end); // OLD-WAY 493 html.subList(l.start + 1, l.end).clear(); // NEW & IMPROVED WAY 494 495 return 1 - (ePos - sPos); // ==> (newSize - originalSize) 496 } 497 498 /** 499 * Replaces the instance of {@code HTMLNode} located at {@code Vector}-index {@code 'pos'} 500 * with the contents of {@code Vector} parameter {@code 'newNodes'}. This removes just 501 * a single instance of {@code HTMLNode}, and replaces it with a list of nodes. 502 * <BR /><BR />Note that this method will, indeed, lengthen the size of the input HTML 503 * {@code Vector} (unless the {@code 'newNodes' Vector} being inserted has only 1 or 0 504 * elements). 505 * 506 * @param html This may be any HTML page or sub-page. 507 * 508 * @param replacePos The position of the {@code HTMLNode} to be removed and replaced with the 509 * list of nodes. 510 * 511 * @param newNodes These are the new {@code HTMLNode's} that are to replace the old instance 512 * of {@code HTMLNode} at position {@code 'pos'}. 513 * 514 * @return The change in the size (size-delta) of the input {@code html} parameter. 515 * The number returned will always equal {@code newNodes.size() - 1} 516 * 517 * @throws ArrayIndexOutOfBoundsException This exception will throw if the specified 518 * {@code 'pos'} parameter is not within the bounds of the {@code Vector}. 519 */ 520 public static int r(Vector<HTMLNode> html, int replacePos, Vector<HTMLNode> newNodes) 521 { 522 if (replacePos < 0) throw new ArrayIndexOutOfBoundsException( 523 "The position passed to this method [" + replacePos + "] is negative." 524 ); 525 526 if (replacePos >= newNodes.size()) throw new ArrayIndexOutOfBoundsException( 527 "The position passed to this method [" + replacePos + "] is greater than or equal " + 528 " to the size of the input HTML Vector parameter, 'html' [" + html.size() + "]" 529 ); 530 531 html.removeElementAt(replacePos); 532 html.addAll(replacePos, newNodes); 533 534 return newNodes.size() - 1; // ==> (newSize - originalSize) 535 } 536}