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&lt;{@link TagNode}&gt;</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}