aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/org/jsoup/select/Evaluator.java
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/org/jsoup/select/Evaluator.java')
-rw-r--r--server/src/org/jsoup/select/Evaluator.java454
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);
+ }
+ }
+}