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