diff options
Diffstat (limited to 'server/src/org/jsoup/select/Evaluator.java')
-rw-r--r-- | server/src/org/jsoup/select/Evaluator.java | 454 |
1 files changed, 454 insertions, 0 deletions
diff --git a/server/src/org/jsoup/select/Evaluator.java b/server/src/org/jsoup/select/Evaluator.java new file mode 100644 index 0000000000..16a083bd77 --- /dev/null +++ b/server/src/org/jsoup/select/Evaluator.java @@ -0,0 +1,454 @@ +package org.jsoup.select; + +import org.jsoup.helper.Validate; +import org.jsoup.nodes.Element; + +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +/** + * Evaluates that an element matches the selector. + */ +public abstract class Evaluator { + protected Evaluator() { + } + + /** + * Test if the element meets the evaluator's requirements. + * + * @param root Root of the matching subtree + * @param element tested element + */ + public abstract boolean matches(Element root, Element element); + + /** + * Evaluator for tag name + */ + public static final class Tag extends Evaluator { + private String tagName; + + public Tag(String tagName) { + this.tagName = tagName; + } + + @Override + public boolean matches(Element root, Element element) { + return (element.tagName().equals(tagName)); + } + + @Override + public String toString() { + return String.format("%s", tagName); + } + } + + /** + * Evaluator for element id + */ + public static final class Id extends Evaluator { + private String id; + + public Id(String id) { + this.id = id; + } + + @Override + public boolean matches(Element root, Element element) { + return (id.equals(element.id())); + } + + @Override + public String toString() { + return String.format("#%s", id); + } + + } + + /** + * Evaluator for element class + */ + public static final class Class extends Evaluator { + private String className; + + public Class(String className) { + this.className = className; + } + + @Override + public boolean matches(Element root, Element element) { + return (element.hasClass(className)); + } + + @Override + public String toString() { + return String.format(".%s", className); + } + + } + + /** + * Evaluator for attribute name matching + */ + public static final class Attribute extends Evaluator { + private String key; + + public Attribute(String key) { + this.key = key; + } + + @Override + public boolean matches(Element root, Element element) { + return element.hasAttr(key); + } + + @Override + public String toString() { + return String.format("[%s]", key); + } + + } + + /** + * Evaluator for attribute name prefix matching + */ + public static final class AttributeStarting extends Evaluator { + private String keyPrefix; + + public AttributeStarting(String keyPrefix) { + this.keyPrefix = keyPrefix; + } + + @Override + public boolean matches(Element root, Element element) { + List<org.jsoup.nodes.Attribute> values = element.attributes().asList(); + for (org.jsoup.nodes.Attribute attribute : values) { + if (attribute.getKey().startsWith(keyPrefix)) + return true; + } + return false; + } + + @Override + public String toString() { + return String.format("[^%s]", keyPrefix); + } + + } + + /** + * Evaluator for attribute name/value matching + */ + public static final class AttributeWithValue extends AttributeKeyPair { + public AttributeWithValue(String key, String value) { + super(key, value); + } + + @Override + public boolean matches(Element root, Element element) { + return element.hasAttr(key) && value.equalsIgnoreCase(element.attr(key)); + } + + @Override + public String toString() { + return String.format("[%s=%s]", key, value); + } + + } + + /** + * Evaluator for attribute name != value matching + */ + public static final class AttributeWithValueNot extends AttributeKeyPair { + public AttributeWithValueNot(String key, String value) { + super(key, value); + } + + @Override + public boolean matches(Element root, Element element) { + return !value.equalsIgnoreCase(element.attr(key)); + } + + @Override + public String toString() { + return String.format("[%s!=%s]", key, value); + } + + } + + /** + * Evaluator for attribute name/value matching (value prefix) + */ + public static final class AttributeWithValueStarting extends AttributeKeyPair { + public AttributeWithValueStarting(String key, String value) { + super(key, value); + } + + @Override + public boolean matches(Element root, Element element) { + return element.hasAttr(key) && element.attr(key).toLowerCase().startsWith(value); // value is lower case already + } + + @Override + public String toString() { + return String.format("[%s^=%s]", key, value); + } + + } + + /** + * Evaluator for attribute name/value matching (value ending) + */ + public static final class AttributeWithValueEnding extends AttributeKeyPair { + public AttributeWithValueEnding(String key, String value) { + super(key, value); + } + + @Override + public boolean matches(Element root, Element element) { + return element.hasAttr(key) && element.attr(key).toLowerCase().endsWith(value); // value is lower case + } + + @Override + public String toString() { + return String.format("[%s$=%s]", key, value); + } + + } + + /** + * Evaluator for attribute name/value matching (value containing) + */ + public static final class AttributeWithValueContaining extends AttributeKeyPair { + public AttributeWithValueContaining(String key, String value) { + super(key, value); + } + + @Override + public boolean matches(Element root, Element element) { + return element.hasAttr(key) && element.attr(key).toLowerCase().contains(value); // value is lower case + } + + @Override + public String toString() { + return String.format("[%s*=%s]", key, value); + } + + } + + /** + * Evaluator for attribute name/value matching (value regex matching) + */ + public static final class AttributeWithValueMatching extends Evaluator { + String key; + Pattern pattern; + + public AttributeWithValueMatching(String key, Pattern pattern) { + this.key = key.trim().toLowerCase(); + this.pattern = pattern; + } + + @Override + public boolean matches(Element root, Element element) { + return element.hasAttr(key) && pattern.matcher(element.attr(key)).find(); + } + + @Override + public String toString() { + return String.format("[%s~=%s]", key, pattern.toString()); + } + + } + + /** + * Abstract evaluator for attribute name/value matching + */ + public abstract static class AttributeKeyPair extends Evaluator { + String key; + String value; + + public AttributeKeyPair(String key, String value) { + Validate.notEmpty(key); + Validate.notEmpty(value); + + this.key = key.trim().toLowerCase(); + this.value = value.trim().toLowerCase(); + } + } + + /** + * Evaluator for any / all element matching + */ + public static final class AllElements extends Evaluator { + + @Override + public boolean matches(Element root, Element element) { + return true; + } + + @Override + public String toString() { + return "*"; + } + } + + /** + * Evaluator for matching by sibling index number (e < idx) + */ + public static final class IndexLessThan extends IndexEvaluator { + public IndexLessThan(int index) { + super(index); + } + + @Override + public boolean matches(Element root, Element element) { + return element.elementSiblingIndex() < index; + } + + @Override + public String toString() { + return String.format(":lt(%d)", index); + } + + } + + /** + * Evaluator for matching by sibling index number (e > idx) + */ + public static final class IndexGreaterThan extends IndexEvaluator { + public IndexGreaterThan(int index) { + super(index); + } + + @Override + public boolean matches(Element root, Element element) { + return element.elementSiblingIndex() > index; + } + + @Override + public String toString() { + return String.format(":gt(%d)", index); + } + + } + + /** + * Evaluator for matching by sibling index number (e = idx) + */ + public static final class IndexEquals extends IndexEvaluator { + public IndexEquals(int index) { + super(index); + } + + @Override + public boolean matches(Element root, Element element) { + return element.elementSiblingIndex() == index; + } + + @Override + public String toString() { + return String.format(":eq(%d)", index); + } + + } + + /** + * Abstract evaluator for sibling index matching + * + * @author ant + */ + public abstract static class IndexEvaluator extends Evaluator { + int index; + + public IndexEvaluator(int index) { + this.index = index; + } + } + + /** + * Evaluator for matching Element (and its descendants) text + */ + public static final class ContainsText extends Evaluator { + private String searchText; + + public ContainsText(String searchText) { + this.searchText = searchText.toLowerCase(); + } + + @Override + public boolean matches(Element root, Element element) { + return (element.text().toLowerCase().contains(searchText)); + } + + @Override + public String toString() { + return String.format(":contains(%s", searchText); + } + } + + /** + * Evaluator for matching Element's own text + */ + public static final class ContainsOwnText extends Evaluator { + private String searchText; + + public ContainsOwnText(String searchText) { + this.searchText = searchText.toLowerCase(); + } + + @Override + public boolean matches(Element root, Element element) { + return (element.ownText().toLowerCase().contains(searchText)); + } + + @Override + public String toString() { + return String.format(":containsOwn(%s", searchText); + } + } + + /** + * Evaluator for matching Element (and its descendants) text with regex + */ + public static final class Matches extends Evaluator { + private Pattern pattern; + + public Matches(Pattern pattern) { + this.pattern = pattern; + } + + @Override + public boolean matches(Element root, Element element) { + Matcher m = pattern.matcher(element.text()); + return m.find(); + } + + @Override + public String toString() { + return String.format(":matches(%s", pattern); + } + } + + /** + * Evaluator for matching Element's own text with regex + */ + public static final class MatchesOwn extends Evaluator { + private Pattern pattern; + + public MatchesOwn(Pattern pattern) { + this.pattern = pattern; + } + + @Override + public boolean matches(Element root, Element element) { + Matcher m = pattern.matcher(element.ownText()); + return m.find(); + } + + @Override + public String toString() { + return String.format(":matchesOwn(%s", pattern); + } + } +} |