001package Torello.HTML.NodeSearch;
002
003import java.util.*;
004import java.util.regex.Pattern;
005import java.util.function.Predicate;
006
007import Torello.HTML.*;
008import Torello.Java.LV;
009
010/**
011 * {@code Static} methods for building and instantiating an
012 * {@link HNLI}<CODE>&lt;</CODE>{@link TagNode}<CODE>&gt;</CODE> (which extends the basic
013 * iterator class) for iterating the tags inside of an HTML-{@code Vector}, using match-critera
014 * which specify attribute name &amp; value requirements.
015 * 
016 * <BR /><BR /><EMBED CLASS='external-html' DATA-FILE-ID=InnerTagIterator> 
017 */
018@Torello.JavaDoc.JDHeaderBackgroundImg
019@Torello.JavaDoc.StaticFunctional
020public class InnerTagIterator
021{
022    private InnerTagIterator() { }
023
024    // **** CRITERIA: htmlTag
025    public static HNLI<TagNode> get(Vector<? extends HTMLNode> html, String htmlTag, String innerTag)
026    { return GET(html, ARGCHECK.htmlTag(htmlTag), ARGCHECK.innerTag(innerTag), ARGCHECK.TRUE); }
027
028    public static HNLI<TagNode> get(Vector<? extends HTMLNode> html, String htmlTag, String innerTag, TextComparitor tc, String... compareStr)
029    { return GET(html, ARGCHECK.htmlTag(htmlTag), ARGCHECK.innerTag(innerTag), ARGCHECK.TC(tc, compareStr)); }
030
031    public static HNLI<TagNode> get(Vector<? extends HTMLNode> html, String htmlTag, String innerTag, Pattern p)
032    { return GET(html, ARGCHECK.htmlTag(htmlTag), ARGCHECK.innerTag(innerTag), ARGCHECK.REGEX(p)); }
033
034    public static HNLI<TagNode> get(Vector<? extends HTMLNode> html, String htmlTag, String innerTag, Predicate<String> attributeValuePred)
035    { return GET(html, ARGCHECK.htmlTag(htmlTag), ARGCHECK.innerTag(innerTag), attributeValuePred); }
036
037    public static HNLI<TagNode> get(Vector<? extends HTMLNode> html, Predicate<TagNode> p, String... htmlTags)
038    { return GET(html, p, ARGCHECK.htmlTags(htmlTags)); }
039
040    // **** CRITERIA, htmlTag null
041    public static HNLI<TagNode> get(Vector<? extends HTMLNode> html, String innerTag)
042    { return GET(html, null, ARGCHECK.innerTag(innerTag), ARGCHECK.TRUE); }
043
044    public static HNLI<TagNode> get(Vector<? extends HTMLNode> html, String innerTag, TextComparitor tc, String... compareStr)
045    { return GET(html, null, ARGCHECK.innerTag(innerTag), ARGCHECK.TC(tc, compareStr)); }
046
047    public static HNLI<TagNode> get(Vector<? extends HTMLNode> html, String innerTag, Pattern p)
048    { return GET(html, null, ARGCHECK.innerTag(innerTag), ARGCHECK.REGEX(p)); }
049
050    public static HNLI<TagNode> get(Vector<? extends HTMLNode> html, String innerTag, Predicate<String> attributeValuePred)
051    { return GET(html, null, ARGCHECK.innerTag(innerTag), attributeValuePred); }
052
053    public static HNLI<TagNode> get(Vector<? extends HTMLNode> html, Predicate<TagNode> p)
054    { return GET(html, p); }
055
056    // ******************************************************************************
057    // private builder methods
058    // ******************************************************************************
059
060    private static HNLI<TagNode> GET
061        (Vector<? extends HTMLNode> html, Predicate<TagNode> p, String... htmlTags)
062    {
063        Predicate<TagNode>  p2 = (htmlTags.length == 0)
064                ? (TagNode tn) -> (! tn.isClosing) && p.test(tn)
065                : (TagNode tn) -> (! tn.isClosing) && tn.isTag(htmlTags) && p.test(tn);
066    
067        return new HNLI<TagNode>(html, p2, TagNode.class);
068    }
069
070    private static HNLI<TagNode> GET
071        (Vector<? extends HTMLNode> html, String htmlTag, String innerTag, Predicate<String> compare)
072    {
073        if (htmlTag == null) return new HNLI<TagNode>(html,
074            tagNode ->
075            {
076                if (tagNode.isClosing) return false;
077
078                String innerTagValue = tagNode.AVOPT(innerTag);
079
080                return (innerTagValue != null) && compare.test(innerTagValue);
081
082            }, TagNode.class
083                // The HNLI expects the last parameter to its constructor to be the class of the
084                // iterator.  This is the solution to the "Java Generics Type Erasure Problem"
085        );
086
087        else return new HNLI<TagNode>(html,
088            tagNode ->
089            {
090                if (tagNode.isClosing) return false;
091
092                if (! htmlTag.equals(tagNode.tok)) return false;
093
094                String innerTagValue = tagNode.AVOPT(innerTag);
095
096                return (innerTagValue != null) && compare.test(innerTagValue);
097
098            }, TagNode.class
099                // REMEMBER, the HNLI<...> Generic class will iterate through
100                // TagNode's, TextNode's and CommentNode's.  The only one of these
101                // three that may be more difficult is the "TagNode" class - because it has
102                // both opening and closing versions of the node, and more data-fields.  The
103                // TextNode and CommentNode classes do not have "extra" data-fields that contain
104                // more information, nor are there "different types" of TextNode's and CommentNode's
105                // The HNLI expects the last parameter to its constructor to be the class of the
106                // iterator. This is the solution to the "Java Generics Type Erasure Problem"
107        );
108    }
109
110}