001package Torello.HTML.NodeSearch; 002 003import java.util.Vector; 004import java.util.function.Predicate; 005import java.util.regex.Pattern; 006 007import Torello.HTML.*; 008import Torello.Java.StrFilter; 009 010/** 011 * A functional-interface / lambda-target, and several {@code static}-builders for generating 012 * instances of them, which extends {@code java.util.function.Predicate} and encapsulates 013 * search-criteria into a <CODE>Predicate<{@link TagNode}></CODE> 014 * 015 * <BR /><BR /><EMBED CLASS='external-html' DATA-FILE-ID=AVT> 016 */ 017@FunctionalInterface 018public interface AVT extends Predicate<TagNode>, java.io.Serializable 019{ 020 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUIDFI> */ 021 public static final long serialVersionUID = 1; 022 023 // ****************************************************************************************** 024 // Functional-Interface Method 025 // ****************************************************************************************** 026 027 /** 028 * <B><SPAN STYLE="color: red;">FUNCTIONAL-INTERFACE BOOLEAN METHOD:</SPAN></B> This is the 029 * method that fulfils this {@code functional-interface 'test'} method. 030 * 031 * @param tn This method will be called - once for each {@code TagNode} found inside of a 032 * vectorized HTML page. 033 * 034 * @return If the {@code TagNode} meets the test's "inclusion requirements", then this method 035 * should return {@code TRUE}. 036 */ 037 public boolean test(TagNode tn); 038 039 // ****************************************************************************************** 040 // TextComparitor factory builders 041 // ****************************************************************************************** 042 043 /** 044 * This is a {@code static} factory method that generates {@code AVT-Predicate's} 045 * ({@code Predicate<TagNode>}). It saves the user of typing the lambda information by hand, 046 * and does a validation check too. The primary use of this class is that the results of one 047 * factory method may be "AND-chained" or "OR-chained" with another to make search requirements 048 * more specific. 049 * 050 * @param innerTag This also goes by the term "attribute" in many HTML specifications. It is 051 * the <B STYLE="color: red;">name</B> of the attribute, not it's 052 * <B STYLE="color: red;">value</B>. The <B STYLE="color: red;">value</B> will be found (if the 053 * {@code TagNode} contains this attribute), and the parameter {@code 'TextComparitor'} will be 054 * used to compare this <B STYLE="color: red;">value</B> - <I>dependent upon which 055 * {@code 'TextComparitor'} is used</I> against the Compare-Strings 056 * 057 * @param tc This may be any of the listed {@code TextComparitor's} in the class. There are 058 * quite a few "pre-defined" {@code static} members in the {@link TextComparitor} class. There 059 * are many that have both long names, and abbreviated names which can be interchangeably used 060 * for readability purposes. 061 * 062 * @param compareStr These are passed to the {@code 'TextComparitor'} when using to perform 063 * tests on the attribute <B STYLE="color: red;">value</B>. 064 * 065 * @return <EMBED CLASS='external-html' DATA-FILE-ID=RETCMP1> 066 * 067 * @see ARGCHECK#innerTag(String) 068 * @see ARGCHECK#TC(TextComparitor, String[]) 069 * @see TagNode#AV(String) 070 * @see TextComparitor#test(String, String[]) 071 * 072 * @throws InnerTagKeyException <EMBED CLASS='external-html' DATA-FILE-ID=ITKEYEX> 073 * @throws NullPointerException If any of the provided input reference parameters are null. 074 */ 075 public static AVT cmp(String innerTag, TextComparitor tc, String... compareStr) 076 { 077 // FAIL-FAST: It is helpful for the user to test the data before building the Predicate. 078 // If these tests fail, the returned predicate would absolutely fail. 079 080 final String innerTagLC = ARGCHECK.innerTag(innerTag); 081 ARGCHECK.TC(tc, compareStr); 082 083 084 // Minimum length for field TagNode.str to have before it could possible contain the attribute 085 // Obviously, the TagNode would have to have a min-length that includes the 086 // attribute-name length + '< ' and '>' 087 088 final int MIN_LEN = innerTag.length() + 3; 089 090 091 // Java's "Lambda-Expression" Syntax (like an "anonymous method"). 092 // AVT extends functional-interface Predicate<TagNode> 093 094 return (TagNode tn) -> 095 { 096 // This eliminates testing any TagNode that simply COULD NOT contain the 097 // specified attribute. (an optimization) 098 099 if (tn.isClosing || (tn.str.length() <= (tn.tok.length() + MIN_LEN))) return false; 100 101 102 // Retrieve the value of the requested "inner-tag" (HTML Attribute) Key-Value Pair 103 // from the input HTML-Element (TagNode) 104 105 String itv = tn.AV(innerTagLC); 106 // REG-EX MATCHER, MORE EXPENSIVE 107 108 109 // If the innerTag's value is null, then the inner-tag was not a key-value 110 // found inside the TagNode: return false. 111 // Otherwise return the 'tc' test-results on that value using the named 'tc' 112 // comparison on the compare-strings. 113 114 return (itv == null) ? false : tc.test(itv, compareStr); 115 }; 116 } 117 118 /** 119 * <EMBED CLASS='external-html' DATA-FILE-ID=CMPKIITNF1> 120 * 121 * @param innerTag This also goes by the term "attribute" in many HTML specifications. It is 122 * the <B STYLE="color: red;">name</B> of the attribute, not it's 123 * <B STYLE="color: red;">value</B>. The <B STYLE="color: red;">value</B> will be found (if the 124 * {@code TagNode} contains this attribute), and the parameter {@link TextComparitor} will be 125 * used to compare this <B STYLE="color: red;">value</B> - <I>dependent upon which 126 * {@code 'TextComparitor'} is used</I> against the Compare-{@code String's} 127 * 128 * @param tc This may be any of the listed {@code TextComparitor's} in the class. There are 129 * quite a few "pre-defined" {@code static} members in the {@code TextComparitor} class. There 130 * are many that have both long names, and abbreviated names which can be interchangeably used 131 * for readability purposes. 132 * 133 * @param compareStr These are passed to the {@code 'TextComparitor'} to perform tests on the 134 * attribute <B STYLE="color: red;">value</B>. 135 * 136 * @return An instance of {@code 'AVT'} that can be passed to the NodeSearch classes 137 * search-methods via any one of the methods that accepts a {@code Predicate<TagNode>} as a 138 * parameter in the search criteria. 139 * 140 * @see #cmp(String, TextComparitor, String[]) 141 * 142 * @throws InnerTagKeyException <EMBED CLASS='external-html' DATA-FILE-ID=ITKEYEX> 143 * @throws NullPointerException If any of the provided input reference parameters are null. 144 */ 145 public static AVT cmpKIITNF(String innerTag, TextComparitor tc, String... compareStr) 146 { 147 // FAIL-FAST: It is helpful for the user to test the data before building the Predicate. 148 // If these tests fail, the returned predicate would absolutely fail. 149 150 final String innerTagLC = ARGCHECK.innerTag(innerTag); 151 ARGCHECK.TC(tc, compareStr); 152 153 154 // Java's "Lambda-Expression" Syntax (like an "anonymous method"). 155 // AVT extends functional-interface Predicate<TagNode> 156 157 return (TagNode tn) -> 158 { 159 // This eliminates testing any TagNode that simply COULD NOT contain 160 // attributes. (an optimization) 161 // 162 // KIITNF -> Empty Opening HTML TagNode Elements cannot be eliminated! 163 // HOWEVER, Closing TagNodes are never included 164 165 if (tn.isClosing) return false; 166 167 168 // Retrieve the value of the requested "inner-tag" (HTML Attribute) Key-Value Pair 169 // from the input HTML-Element (TagNode) 170 171 String itv = tn.AV(innerTagLC); 172 // REG-EX MATCHER, MORE EXPENSIVE 173 174 175 // If the innerTag's value is null, then the inner-tag was not a key-value pair 176 // found inside the TagNode. 177 // 178 // BECAUSE the user requested to "Keep If Inner-Tag Not Found", we must return TRUE 179 // in that case. 180 // In Java '||' uses short-circuit boolean-evaluation, while '|' requires 181 // full-evaluation. 182 // 183 // OTHERWISE return the 'tc' test-results on that value using the named 'tc' comparison 184 // on the compare-strings. 185 186 return (itv == null) || tc.test(itv, compareStr); 187 }; 188 } 189 190 // ******************************************************************************************** 191 // Regular-Expression (Pattern) factory builders. 192 // ******************************************************************************************** 193 194 /** 195 * This is a {@code static} factory method that generates {@code AVT-Predicate's} 196 * ({@code Predicate<TagNode>}). It saves the user of typing the lambda information by hand, 197 * and does a validation check too. The primary use of this class is that the results of one 198 * factory method may be "AND-chained" or "OR-chained" with another to make search requirements 199 * more specific. 200 * 201 * @param innerTag This also goes by the term "attribute" in many HTML specifications. It is 202 * the <B STYLE="color: red;">name</B> of the attribute, not it's 203 * <B STYLE="color: red;">value</B>. The <B STYLE="color: red;">value</B> will be found (if the 204 * {@code TagNode} contains this attribute), and then tested using the Regular-Expression 205 * {@code p.matcher(tag_value).find()} method. 206 * 207 * @param p This may be any regular expression {@code Pattern}. This {@code Pattern} will be 208 * executed against the <B STYLE="color: red;">value</B> of the inner-tag specified by 209 * parameter {@code 'innerTag'}. 210 * 211 * @return <EMBED CLASS='external-html' DATA-FILE-ID=RETCMP2> 212 * 213 * @see ARGCHECK#innerTag(String) 214 * @see ARGCHECK#REGEX(Pattern) 215 * @see TagNode#AV(String) 216 * 217 * @throws InnerTagKeyException <EMBED CLASS='external-html' DATA-FILE-ID=ITKEYEX> 218 * @throws NullPointerException If any of the provided input reference parameters are null. 219 */ 220 public static AVT cmp(String innerTag, Pattern p) 221 { 222 // FAIL-FAST: It is helpful for the user to test the data before building the Predicate. 223 // If these tests fail, the returned predicate would absolutely fail. 224 225 final String innerTagLC = ARGCHECK.innerTag(innerTag); 226 final Predicate<String> pred = ARGCHECK.REGEX(p); 227 228 229 // Minimum length for field TagNode.str to have before it could possible contain the attribute 230 // Obviously, the TagNode would have to have a min-length that includes the attribute-name 231 // length + '< ' and '>' 232 233 final int MIN_LEN = innerTag.length() + 3; 234 235 236 // Java's "Lambda-Expression" Syntax (like an "anonymous method"). 237 // AVT extends functional-interface Predicate<TagNode> 238 239 return (TagNode tn) -> 240 { 241 // This eliminates testing any TagNode that simply COULD NOT contain the 242 // attribute. (an optimization) 243 244 if (tn.isClosing || (tn.str.length() <= (tn.tok.length() + MIN_LEN))) return false; 245 246 247 // Retrieve the value of the requested "inner-tag" (HTML Attribute) Key-Value Pair 248 // from the input HTML-Element (TagNode) 249 // 250 // REG-EX MATCHER, MORE EXPENSIVE 251 252 String itv = tn.AV(innerTagLC); 253 254 255 // If the innerTag's value is null, then the inner-tag was not a key-value pair 256 // found inside the TagNode: return false. 257 // Otherwise return the results of running the Regular-Expression matcher using the 258 // input 'Pattern' instance. 259 260 return (itv == null) ? false : pred.test(itv); 261 }; 262 } 263 264 /** 265 * This is a {@code static} factory method that generates {@code AVT-Predicate's} 266 * ({@code Predicate<TagNode>}). It saves the user of typing the lambda information by hand, 267 * and does a validation check too. The primary use of this class is that the results of one 268 * factory method may be "AND-chained" or "OR-chained" with another to make search requirements 269 * more specific. 270 * 271 * @param innerTag This also goes by the term "attribute" in many HTML specifications. It is 272 * the <B STYLE="color: red;">name</B> of the attribute, not it's 273 * <B STYLE="color: red;">value</B>. The <B STYLE="color: red;">value</B> will be found (if the 274 * {@code TagNode} contains this attribute), and then tested using the Regular-Expression 275 * {@code p.matcher(tag_value).find()} method. 276 * 277 * @param p This may be any regular expression {@code Pattern}. This {@code Pattern} will be 278 * executed against the <B STYLE="color: red;">value</B> of the inner-tag specified by 279 * parameter {@code 'innerTag'}. 280 * 281 * @param keepOnMatch There may be times when it is necessary to specify that a 282 * Regular-Expression match should cause the search-filter to reject a {@code TagNode}, rather 283 * than keeping it as a search-result match. In this case, the programmer can utilize this 284 * variable to indicate whether matches should cause this method to return {@code TRUE} or 285 * {@code FALSE}. If this variable is set to {@code FALSE}, then the {@code Predicate<TagNode>} 286 * that is generated will return {@code FALSE}, whenever the regular-expression matches the 287 * Attribute-<B STYLE="color: red;">Value</B>. 288 * 289 * <BR /><BR /><DIV CLASS=JDHint> 290 * <B STYLE="color: red;">Default Behavior:</B> The classes and methods in this Node Search 291 * Package that accept regular-expressions as search-parameters will always treat a match to 292 * indicate that the {@code TagNode} (or {@code TextNode}) in question <B>has passed</B> the 293 * search-filter criteria. This method, therefore, provides a way to bypass this default 294 * behavior. 295 * </DIV> 296 * 297 * @param keepOnNull This parameter allows the user to specify whether the absence of an HTML 298 * Inner-Tag should indicate that the TagNode being tested should pass or fail (keep or 299 * reject) the search-filter criteria. 300 * 301 * <BR /><BR /><DIV CLASS=JDHint> 302 * <B STYLE="color: red;">Default Behavior:</B> The default filter-results for the search 303 * classes and search methods of the Node-Search Package are such that if an inner-tag is 304 * simply not available ... or 'not present' within an HTML Element, then that element 305 * <B>will not be included</B> in the search results for that class or method. 306 * 307 * <BR /><BR />By using this particular {@code AVT} factory-method, a programmer can by-pass 308 * that default behavior. 309 * </DIV> 310 * 311 * @return An instance of {@code 'AVT'} that can be passed to the NodeSearch classes 312 * search-methods via any one of the methods that accepts a {@code Predicate<TagNode>} as a 313 * parameter in the search criteria. 314 * 315 * @see ARGCHECK#innerTag(String) 316 * @see ARGCHECK#REGEX(Pattern) 317 * @see TagNode#AV(String) 318 * 319 * @throws InnerTagKeyException <EMBED CLASS='external-html' DATA-FILE-ID=ITKEYEX> 320 * @throws NullPointerException If any of the provided input reference parameters are null. 321 */ 322 public static AVT cmp 323 (String innerTag, Pattern p, final boolean keepOnMatch, final boolean keepOnNull) 324 { 325 // FAIL-FAST: It is helpful for the user to test the data before building the Predicate. 326 // If these tests fail, the returned predicate would absolutely fail. 327 328 final String innerTagLC = ARGCHECK.innerTag(innerTag); 329 final Predicate<String> pred = ARGCHECK.REGEX(p); 330 331 332 // Java's "Lambda-Expression" Syntax (like an "anonymous method"). 333 // AVT extends functional-interface Predicate<TagNode> 334 335 return (TagNode tn) -> 336 { 337 // This eliminates testing any TagNode that simply COULD NOT contain 338 // attributes. (an optimization) 339 // 340 // keepOnNull -> Empty Opening HTML TagNode Elements cannot be eliminated! 341 // HOWEVER, Closing TagNodes are never included 342 343 if (tn.isClosing) return false; 344 345 346 // Retrieve the value of the requested "inner-tag" (HTML Attribute) Key-Value Pair 347 // from the input HTML-Element (TagNode) 348 // 349 // REG-EX MATCHER, MORE EXPENSIVE 350 351 String itv = tn.AV(innerTagLC); 352 353 // If the Attribute is simply not present in the HTML Element 354 if (itv == null) return keepOnNull; 355 356 if (pred.test(itv)) return keepOnMatch; // if the Regular-Expression succeeded 357 else return ! keepOnMatch; // If the Regular-Expression failed 358 }; 359 } 360 361 /** 362 * <EMBED CLASS='external-html' DATA-FILE-ID=CMPKIITNF2> 363 * 364 * @param innerTag This also goes by the term "attribute" in many HTML specifications. It is 365 * the <B STYLE="color: red;">name</B> of the attribute, not it's 366 * <B STYLE="color: red;">value</B>. The <B STYLE="color: red;">value</B> will be found (if the 367 * {@code TagNode} contains this attribute), and then tested using the Regular-Expression 368 * {@code p.matcher(tag_value).find()} method. 369 * 370 * @param p This may be any regular expression {@code Pattern}. This {@code Pattern} will be 371 * executed against the <B STYLE="color: red;">value</B> of the inner-tag specified by 372 * parameter {@code 'innerTag'}. 373 * 374 * @return An instance of {@code 'AVT'} that can be passed to the NodeSearch classes 375 * search-methods via any one of the methods that accepts a {@code Predicate<TagNode>} as a 376 * parameter in the search parameter-list. 377 * 378 * @see #cmp(String, Pattern) 379 * 380 * @throws InnerTagKeyException <EMBED CLASS='external-html' DATA-FILE-ID=ITKEYEX> 381 * @throws NullPointerException If any of the provided input reference parameters are null. 382 */ 383 public static AVT cmpKIITNF(String innerTag, Pattern p) 384 { 385 // FAIL-FAST: It is helpful for the user to test the data before building the Predicate. 386 // If these tests fail, the returned predicate would absolutely fail. 387 388 final String innerTagLC = ARGCHECK.innerTag(innerTag); 389 final Predicate<String> pred = ARGCHECK.REGEX(p); 390 391 392 // Java's "Lambda-Expression" Syntax (like an "anonymous method"). 393 // AVT extends functional-interface Predicate<TagNode> 394 395 return (TagNode tn) -> 396 { 397 // This eliminates testing any TagNode that simply COULD NOT contain 398 // attributes. (an optimization) 399 // 400 // KIITNF -> Empty Opening HTML TagNode Elements cannot be eliminated! 401 // HOWEVER, Closing TagNodes are never included 402 403 if (tn.isClosing) return false; 404 405 406 // Retrieve the value of the requested "inner-tag" (HTML Attribute) Key-Value Pair 407 // from the input HTML-Element (TagNode) 408 409 String itv = tn.AV(innerTagLC); 410 // REG-EX MATCHER, MORE EXPENSIVE 411 412 413 // If the innerTag's value is null, then the inner-tag was not a key-value pair 414 // found inside the TagNode. 415 // 416 // BECAUSE the user requested to "Keep If Inner-Tag Not Found", we must return 417 // in that case. 418 // In Java '||' uses short-circuit boolean-evaluation, while '|' requires 419 // full-evaluation. 420 // 421 // OTHERWISE return the results of running the Regular-Expression matcher using the 422 // input 'Pattern' instance. 423 424 return (itv == null) || pred.test(itv); 425 }; 426 } 427 428 // ******************************************************************************************** 429 // Predicate<String> factory builders. 430 // ******************************************************************************************** 431 432 /** 433 * Convenience Method. 434 * <BR />Invokes: {@link #cmp(String, Predicate)} 435 * <BR />Converts: {@link StrFilter} to simple {@code String-Predicate} 436 */ 437 public static AVT cmp(String innerTag, StrFilter innerTagValueTest) 438 { return cmp(innerTag, (Predicate<String>) innerTagValueTest::test); } 439 440 /** 441 * This is a {@code static} factory method that generates {@code AVT-Predicate's} - 442 * ({@code Predicate<TagNode>}). It saves the user of typing the lambda information by hand, 443 * and does a validation check too. The primary use of this class is that the results of one 444 * factory method may be "AND-chained" or "OR-chained" with another to make search requirements 445 * more specific. 446 * 447 * <BR /><BR /><DIV CLASS=JDHint> 448 * The astute observer might wonder why the change from a {@code String-Predicate} to a 449 * {@code TagNode-Predicate}, with the answer being that predicate-chaining on different, 450 * multiple inner-tags (and their <B STYLE="color: red;">values</B>) can only be accomplished 451 * by using a {@code TagNode-Predicate}, rather than a {@code String-Predicate} 452 * </DIV> 453 * 454 * @param innerTag This also goes by the term "attribute" in many HTML specifications. It is 455 * the <B STYLE="color: red;">name</B> of the attribute, not it's 456 * <B STYLE="color: red;">value</B>. The <B STYLE="color: red;">value</B> will be found (if the 457 * {@code TagNode} contains this attribute), and then tested against the 458 * {@code String-Predicate} in parameter {@code 'innerTagValueTest'}. 459 * 460 * @param innerTagValueTest This may be any Java {@code String-Predicate} with a 461 * {@code test(...) / accept} method. It will be used to accept or reject the inner-tag's 462 * <B STYLE="color: red;">value</B> 463 * 464 * @return <EMBED CLASS='external-html' DATA-FILE-ID=RETCMP3> 465 * 466 * @see InnerTagFind 467 * @see ARGCHECK#innerTag(String) 468 * @see TagNode#AV(String) 469 * 470 * @throws InnerTagKeyException <EMBED CLASS='external-html' DATA-FILE-ID=ITKEYEX> 471 * @throws NullPointerException If any of the provided input reference parameters are null. 472 */ 473 public static AVT cmp(String innerTag, Predicate<String> innerTagValueTest) 474 { 475 // FAIL-FAST: It is helpful for the user to test the data before building the Predicate. 476 // If these tests fail, the returned predicate would absolutely fail. 477 478 final String innerTagLC = ARGCHECK.innerTag(innerTag); 479 if (innerTagValueTest == null) throw new NullPointerException 480 ("Parameter innerTagValueTest was passed null, but this is not allowed here."); 481 482 483 // Minimum length for field TagNode.str to have before it could possible contain the attribute 484 // Obviously, the TagNode would have to have a min-length that includes the attribute-name 485 // length + '< ' and '>' 486 487 final int MIN_LEN = innerTag.length() + 3; 488 489 490 // Java's "Lambda-Expression" Syntax (like an "anonymous method"). 491 // AVT extends functional-interface Predicate<TagNode> 492 493 return (TagNode tn) -> 494 { 495 // This eliminates testing any TagNode that simply COULD NOT contain the 496 // attribute. (an optimization) 497 498 if (tn.isClosing || (tn.str.length() <= (tn.tok.length() + MIN_LEN))) return false; 499 500 501 // Retrieve the value of the requested "inner-tag" (HTML Attribute) Key-Value Pair 502 // from the input HTML-Element (TagNode) 503 504 String itv = tn.AV(innerTagLC); 505 // REG-EX MATCHER, MORE EXPENSIVE 506 507 508 // If the innerTag's value is null, then the inner-tag was not a key-value pair 509 // found inside the TagNode: return false. 510 // Otherwise return the results of the Predicate<String> provided on that 511 // attribute-value. 512 513 return (itv == null) ? false : innerTagValueTest.test(itv); 514 }; 515 } 516 517 /** 518 * Convenience Method. 519 * <BR />Invokes: {@link #cmpKIITNF(String, Predicate)} 520 * <BR />Converts: {@link StrFilter} to {@code String-Predicate} 521 */ 522 public static AVT cmpKIITNF(String innerTag, StrFilter innerTagValueTest) 523 { return cmpKIITNF(innerTag, (Predicate<String>) innerTagValueTest::test); } 524 525 /** 526 * <EMBED CLASS='external-html' DATA-FILE-ID=CMPKIITNF3> 527 * 528 * @param innerTag This also goes by the term "attribute" in many HTML specifications. It is 529 * the <B STYLE="color: red;">name</B> of the attribute, not it's 530 * <B STYLE="color: red;">value</B>. The <B STYLE="color: red;">value</B> will be found (if the 531 * {@code TagNode} contains this attribute), and then tested against the 532 * {@code String-Predicate} parameter {@code 'innerTagValueTest'}. 533 * 534 * @param innerTagValueTest This may be any Java {@code String-Predicate} with a 535 * {@code test(...) / accept} method. It will be used to accept or reject the inner-tag's 536 * value. 537 * 538 * @return An instance of {@code 'AVT'} that can be passed to the NodeSearch classes 539 * search-methods via any one of the methods that accepts a {@code Predicate<TagNode>} as a 540 * parameter in the search criteria. 541 * 542 * @see #cmp(String, Predicate) 543 * 544 * @throws InnerTagKeyException <EMBED CLASS='external-html' DATA-FILE-ID=ITKEYEX> 545 * @throws NullPointerException If any of the provided input reference parameters are null. 546 */ 547 public static AVT cmpKIITNF(String innerTag, Predicate<String> innerTagValueTest) 548 { 549 // FAIL-FAST: It is helpful for the user to test the data before building the Predicate. 550 // If these tests fail, the returned predicate would absolutely fail. 551 552 final String innerTagLC = ARGCHECK.innerTag(innerTag); 553 554 if (innerTagValueTest == null) throw new NullPointerException 555 ("Parameter innerTagValueTest was passed null, but this is not allowed here."); 556 557 558 // Java's "Lambda-Expression" Syntax (like an "anonymous method"). 559 // AVT extends functional-interface Predicate<TagNode> 560 561 return (TagNode tn) -> 562 { 563 // This eliminates testing any TagNode that simply COULD NOT contain 564 // attributes. (an optimization) 565 // 566 // KIITNF -> Empty Opening HTML TagNode Elements cannot be eliminated! 567 // HOWEVER, Closing TagNodes are never included 568 569 if (tn.isClosing) return false; 570 571 572 // Retrieve the value of the requested "inner-tag" (HTML Attribute) Key-Value Pair 573 // from the input HTML-Element (TagNode) 574 // 575 // REG-EX MATCHER, MORE EXPENSIVE 576 577 String itv = tn.AV(innerTagLC); 578 579 580 // If the innerTag's value is null, then the inner-tag was not a key-value pair 581 // found inside the TagNode. 582 // 583 // BECAUSE the user requested to "Keep If Inner-Tag Not Found", we must return TRUE 584 // in that case. 585 // In Java '||' uses short-circuit boolean-evaluation, while '|' requires 586 // full-evaluation. 587 // 588 // OTHERWISE return the results of the Predicate<String> provided on that 589 // attribute-value. 590 591 return (itv == null) || innerTagValueTest.test(itv); 592 }; 593 } 594 595 // ******************************************************************************************** 596 // Simple Present-Or-Not-Present test 597 // ******************************************************************************************** 598 599 /** 600 * This is a {@code static} factory method that generates {@code AVT-Predicate's} - 601 * ({@code Predicate<TagNode>}). It saves the user of typing the lambda information by hand, 602 * and does a validation check too. The primary use of this class is that the results of one 603 * factory method may be "AND-chained" or "OR-chained" with another to make search requirements 604 * more specific. 605 * 606 * @param innerTag This also goes by the term "attribute" in many HTML specifications. It is 607 * the <B STYLE="color: red;">name</B> of the attribute, not it's 608 * <B STYLE="color: red;">value</B>. If this attribute is found, this {@code Predicate} will 609 * always return {@code TRUE} regardless of it's <B STYLE="color: red;">value</B> - so long as 610 * it is not null. 611 * 612 * <BR /><BR /><DIV CLASS=JDHint> 613 * There is a subtlety here between inner-tag's that have a <B STYLE="color: red;">value</B> of 614 * {@code the-empty-string, a zero-length-string}, and attributes that are "null" or not found 615 * at all. Though rare, it is sometimes the case that an HTML Attribute may have a 616 * <B STYLE="color: red;">value</B> of {@code <SOME-TAG SOME-INNER-TAG="">}. There can be 617 * other versions that leave the quotes off entirely such as: 618 * {@code <OTHER-ELEMENT OTHER-ATTRIBUTE=>} - where there are no quotes at all. If the 619 * attribute is found, with an equals sign it will evaluate to the 620 * <B>{@code the zero-length-string}</B>, but if the attribute is not found at all, 621 * searching for it will return null, and this {@code Predicate} will return {@code FALSE}. 622 * </DIV> 623 * 624 * @return <EMBED CLASS='external-html' DATA-FILE-ID=RETCMP4> 625 * 626 * @see InnerTagFind 627 * @see ARGCHECK#innerTag(String) 628 * @see TagNode#AV(String) 629 * 630 * @throws InnerTagKeyException <EMBED CLASS='external-html' DATA-FILE-ID=ITKEYEX> 631 * @throws NullPointerException If any of the provided input reference parameters are null. 632 */ 633 public static AVT cmp(String innerTag) 634 { 635 // FAIL-FAST: It is helpful for the user to test the data before building the Predicate. 636 // If this test fails, the returned predicate would absolutely fail. 637 638 final String innerTagLC = ARGCHECK.innerTag(innerTag); 639 640 641 // SIMPLIFIED LAMBDA: The contents of this "anonymous method" can be expressed in a 642 // single-statement. No need for 'return' or 'curly-braces' 643 // Returns TRUE if the HTML Element contained a copy of the named inner-tag, and false 644 // otherwise. 645 646 return (TagNode tn) -> tn.AV(innerTagLC) != null; 647 } 648 649 // ****************************************************************************************** 650 // The basic-required methods, of a "Functional-Interface Predicate" 651 // ****************************************************************************************** 652 653 /** 654 * Generates a new {@code 'AVT'} predicate test that {@code logically-AND's} the results of 655 * {@code 'this' Predicate} with the results of the new, additional passed parameter 656 * {@code Predicate 'additionalTest'}. 657 * 658 * @param additionalTest This is an additional test of the inner-tag 659 * <B STYLE="color: red;">key-value pair</B> (also known as the 660 * <B STYLE="color: red;">"attribute-value pair"</B>) of HTML {@code TagNode's}. 661 * 662 * @return A new {@code Predicate<TagNode>} that will use two tests: 663 * {@code 'this'} and {@code 'additionalTest'} and subsequently perform a logical-AND on the 664 * result. Short-circuit evaluation is used (specifically, the {@code '&&'} operator, 665 * rather than the {@code '&'} operator are utilized). The {@code Predicate} that is returned 666 * will perform the {@code 'this'} test first, and then the {@code 'additionalTest'} second. 667 * The returned {@code Predicate} will return the {@code 'AND'} of both of them. 668 * 669 * @see TagNode 670 * 671 * @throws NullPointerException If any of the provided input reference parameters are null. 672 */ 673 default AVT and(AVT additionalTest) 674 { 675 // FAIL-FAST: It is helpful for the user to test the data before building the Predicate. 676 // If this test fails, the returned predicate would absolutely fail. 677 678 if (additionalTest == null) throw new NullPointerException 679 ("The parameter 'additionalTest' passed to method 'AVT.and(additionalTest)' was null"); 680 681 682 // SIMPLIFIED LAMBDA: The contents of this "anonymous method" can be expressed in a 683 // single-statement. No need for 'return' or 'curly-braces' 684 // Returns TRUE if both 'this' evaluates to true on an input HTML Element, 685 // and 'other' also evaluates to true for the same element. 686 687 return (TagNode tn) -> this.test(tn) && additionalTest.test(tn); 688 } 689 690 /** 691 * Generates a new {@code 'AVT'} predicate test that {@code logically-OR's} the results of 692 * {@code 'this' Predicate} with the results of the new, additional passed parameter 693 * {@code Predicate 'additionalTest'}. 694 * 695 * @param additionalTest This is an additional test of the inner-tag 696 * <B STYLE="color: red;">key-value pair</B> (also known as the 697 * <B STYLE="color: red;">"attribute-value pair"</B>) of HTML {@code TagNode's}. 698 * 699 * @return A new {@code Predicate<TagNode>} that will use two tests: 700 * {@code 'this'} and {@code 'additionalTest'} and subsequently perform a logical-OR on the 701 * result. Short-circuit evaluation is used (specifically, the {@code '||'} operator, 702 * rather than the {@code '|'} operator are utilized). The {@code Predicate} that is returned 703 * will perform the {@code 'this'} test first, and then the {@code 'additionalTest'} second. 704 * The returned {@code Predicate} will return the {@code 'OR'} of both of them. 705 * 706 * @see TagNode 707 * 708 * @throws NullPointerException If any of the provided input reference parameters are null. 709 */ 710 default AVT or(AVT additionalTest) 711 { 712 // FAIL-FAST: It is helpful for the user to test the data before building the Predicate. 713 // If this test fails, the returned predicate would absolutely fail. 714 715 if (additionalTest == null) throw new NullPointerException 716 ("The parameter 'additionalTest' passed to method 'AVT.or(additionalTest)' was null"); 717 718 719 // SIMPLIFIED LAMBDA: The contents of this "anonymous method" can be expressed in a 720 // single-statement. No need for 'return' or 'curly-braces' 721 // Returns TRUE if either 'this' evaluates to true on an input HTML Element, 722 // and 'other' also evaluates to true for the same element. 723 724 return (TagNode tn) -> this.test(tn) || additionalTest.test(tn); 725 } 726 727 /** 728 * Generates a new {@code 'AVT'} predicate test that is the {@code logical-NOT} of 729 * {@code 'this' Predicate}. 730 * 731 * @return A new {@code Predicate<TagNode>} that will simply just calls {@code 'this' 732 * Predicate}, and puts an exclamation point ({@code logical 'NOT'}) in front of the result. 733 * 734 * @see TagNode 735 */ 736 default AVT negate() 737 { 738 // SIMPLIFIED LAMBDA: The contents of this "anonymous method" can be expressed in a 739 // single-statement. No need for 'return' or 'curly-braces' 740 // Returns the opposite of whatever result 'this' evaluates using the input HTML Element. 741 742 return (TagNode tn) -> ! this.test(tn); 743 } 744 745 /** 746 * This is a {@code static} factory method that generates {@code AVT-Predicate's} 747 * ({@code Predicate<TagNode>}). It saves the user of typing the lambda information by hand, 748 * and does a validation check too. 749 * 750 * <BR /><BR />If the {@code expectedTN.equals(tn)} fails - specifically using the 751 * java-built-in equality-test method {@code 'equals(...)'}, then the generated / returned 752 * {@code Predicate} would return {@code TRUE}, and the {@code TagNode} in question would be 753 * included in the results. 754 * 755 * @param expectedTN This is compared against {@code TagNode's} found in the 756 * page-{@code Vector} for equality. 757 * 758 * @return A {@code Predicate<TagNode>} that compares for equality with parameter 759 * {@code 'expectedTN'} 760 * 761 * @see TagNode 762 * 763 * @throws NullPointerException If any of the provided input reference parameters are null. 764 */ 765 public static AVT isEqualKEEP(TagNode expectedTN) 766 { 767 // FAIL-FAST: It is helpful for the user to test the data before building the Predicate. 768 // If this test fails, the returned predicate would absolutely fail. 769 770 if (expectedTN == null) throw new NullPointerException 771 ("The parameter 'expectedTN' passed to method 'AVT.isEqualKEEP(expectedTN)' was null"); 772 773 774 // SIMPLIFIED LAMBDA: The contents of this "anonymous method" can be expressed in a 775 // single-statement. No need for 'return' or 'curly-braces' 776 // Returns true if the HTML Element passed to this (anonymous) method is the same as the 777 // one passed to 'isEqualsKEEP' 778 // Identical to: (TagNode tn) -> tn.str.equals(expectedTN.str); 779 780 return (TagNode tn) -> tn.equals(expectedTN); 781 } 782 783 /** 784 * This is a {@code static} factory method that generates {@code AVT-Predicate's} 785 * ({@code Predicate<TagNode>}). It saves the user of typing the lambda information by hand, 786 * and does a validation check too. 787 * 788 * <BR /><BR />If the {@code expectedTN.equals(tn)} fails - specifically using the 789 * java-built-in equality-test method {@code equals(...)} - then the generated / returned 790 * {@code Predicate} would return {@code FALSE}, and the {@code TagNode} in question would be 791 * filtered from the results. 792 * 793 * @param expectedTN This is compared against {@code TagNode's} found in the 794 * page-{@code Vector} for equality. 795 * 796 * @return A {@code Predicate<TagNode>} that compares for equality with parameter 797 * {@code 'expectedTN'} 798 * 799 * @see TagNode 800 * 801 * @throws NullPointerException If any of the provided input reference parameters are null. 802 */ 803 public static AVT isEqualREJECT(TagNode expectedTN) 804 { 805 // FAIL-FAST: It is helpful for the user to test the data before building the Predicate. 806 // If this test fails, the returned predicate would absolutely fail. 807 808 if (expectedTN == null) throw new NullPointerException( 809 "The parameter 'expectedTN' passed to method 'AVT.isEqualREJECT(expectedTN)' "+ 810 "was null" 811 ); 812 813 814 // SIMPLIFIED LAMBDA: The contents of this "anonymous method" can be expressed in a 815 // single-statement. No need for 'return' or 'curly-braces' 816 // Returns TRUE if the HTML Element passed to this (anonymous) method is the same as the 817 // one passed to 'isEqualsKEEP' 818 // Identical to: (TagNode tn) -> ! tn.str.equals(expectedTN.str); 819 820 return (TagNode tn) -> ! tn.equals(expectedTN); 821 } 822}