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