diff options
Diffstat (limited to 'server/src/org/jsoup/select')
-rw-r--r-- | server/src/org/jsoup/select/Collector.java | 58 | ||||
-rw-r--r-- | server/src/org/jsoup/select/CombiningEvaluator.java | 102 | ||||
-rw-r--r-- | server/src/org/jsoup/select/Elements.java | 704 | ||||
-rw-r--r-- | server/src/org/jsoup/select/Evaluator.java | 474 | ||||
-rw-r--r-- | server/src/org/jsoup/select/NodeTraversor.java | 55 | ||||
-rw-r--r-- | server/src/org/jsoup/select/NodeVisitor.java | 39 | ||||
-rw-r--r-- | server/src/org/jsoup/select/QueryParser.java | 334 | ||||
-rw-r--r-- | server/src/org/jsoup/select/Selector.java | 278 | ||||
-rw-r--r-- | server/src/org/jsoup/select/StructuralEvaluator.java | 152 | ||||
-rw-r--r-- | server/src/org/jsoup/select/package-info.java | 4 |
10 files changed, 0 insertions, 2200 deletions
diff --git a/server/src/org/jsoup/select/Collector.java b/server/src/org/jsoup/select/Collector.java deleted file mode 100644 index 20554e8653..0000000000 --- a/server/src/org/jsoup/select/Collector.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.jsoup.select; - -import org.jsoup.nodes.Element; -import org.jsoup.nodes.Node; - -/** - * Collects a list of elements that match the supplied criteria. - * - * @author Jonathan Hedley - */ -public class Collector { - - private Collector() { - } - - /** - * Build a list of elements, by visiting root and every descendant of root, - * and testing it against the evaluator. - * - * @param eval - * Evaluator to test elements against - * @param root - * root of tree to descend - * @return list of matches; empty if none - */ - public static Elements collect(Evaluator eval, Element root) { - Elements elements = new Elements(); - new NodeTraversor(new Accumulator(root, elements, eval)).traverse(root); - return elements; - } - - private static class Accumulator implements NodeVisitor { - private final Element root; - private final Elements elements; - private final Evaluator eval; - - Accumulator(Element root, Elements elements, Evaluator eval) { - this.root = root; - this.elements = elements; - this.eval = eval; - } - - @Override - public void head(Node node, int depth) { - if (node instanceof Element) { - Element el = (Element) node; - if (eval.matches(root, el)) { - elements.add(el); - } - } - } - - @Override - public void tail(Node node, int depth) { - // void - } - } -} diff --git a/server/src/org/jsoup/select/CombiningEvaluator.java b/server/src/org/jsoup/select/CombiningEvaluator.java deleted file mode 100644 index c3f9a8af2e..0000000000 --- a/server/src/org/jsoup/select/CombiningEvaluator.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.jsoup.select; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -import org.jsoup.helper.StringUtil; -import org.jsoup.nodes.Element; - -/** - * Base combining (and, or) evaluator. - */ -abstract class CombiningEvaluator extends Evaluator { - final List<Evaluator> evaluators; - - CombiningEvaluator() { - super(); - evaluators = new ArrayList<Evaluator>(); - } - - CombiningEvaluator(Collection<Evaluator> evaluators) { - this(); - this.evaluators.addAll(evaluators); - } - - Evaluator rightMostEvaluator() { - return evaluators.size() > 0 ? evaluators.get(evaluators.size() - 1) - : null; - } - - void replaceRightMostEvaluator(Evaluator replacement) { - evaluators.set(evaluators.size() - 1, replacement); - } - - static final class And extends CombiningEvaluator { - And(Collection<Evaluator> evaluators) { - super(evaluators); - } - - And(Evaluator... evaluators) { - this(Arrays.asList(evaluators)); - } - - @Override - public boolean matches(Element root, Element node) { - for (Evaluator s : evaluators) { - if (!s.matches(root, node)) { - return false; - } - } - return true; - } - - @Override - public String toString() { - return StringUtil.join(evaluators, " "); - } - } - - static final class Or extends CombiningEvaluator { - /** - * Create a new Or evaluator. The initial evaluators are ANDed together - * and used as the first clause of the OR. - * - * @param evaluators - * initial OR clause (these are wrapped into an AND - * evaluator). - */ - Or(Collection<Evaluator> evaluators) { - super(); - if (evaluators.size() > 1) { - this.evaluators.add(new And(evaluators)); - } else { - this.evaluators.addAll(evaluators); - } - } - - Or() { - super(); - } - - public void add(Evaluator e) { - evaluators.add(e); - } - - @Override - public boolean matches(Element root, Element node) { - for (Evaluator s : evaluators) { - if (s.matches(root, node)) { - return true; - } - } - return false; - } - - @Override - public String toString() { - return String.format(":or%s", evaluators); - } - } -} diff --git a/server/src/org/jsoup/select/Elements.java b/server/src/org/jsoup/select/Elements.java deleted file mode 100644 index cddea67d96..0000000000 --- a/server/src/org/jsoup/select/Elements.java +++ /dev/null @@ -1,704 +0,0 @@ -package org.jsoup.select; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.ListIterator; - -import org.jsoup.helper.Validate; -import org.jsoup.nodes.Element; -import org.jsoup.nodes.Node; - -/** - * A list of {@link Element Elements}, with methods that act on every element in - * the list. - * <p/> - * To get an Elements object, use the {@link Element#select(String)} method. - * - * @author Jonathan Hedley, jonathan@hedley.net - */ -public class Elements implements List<Element>, Cloneable { - private List<Element> contents; - - public Elements() { - contents = new ArrayList<Element>(); - } - - public Elements(int initialCapacity) { - contents = new ArrayList<Element>(initialCapacity); - } - - public Elements(Collection<Element> elements) { - contents = new ArrayList<Element>(elements); - } - - public Elements(List<Element> elements) { - contents = elements; - } - - public Elements(Element... elements) { - this(Arrays.asList(elements)); - } - - @Override - public Elements clone() { - List<Element> elements = new ArrayList<Element>(); - - for (Element e : contents) { - elements.add(e.clone()); - } - - return new Elements(elements); - } - - // attribute methods - /** - * Get an attribute value from the first matched element that has the - * attribute. - * - * @param attributeKey - * The attribute key. - * @return The attribute value from the first matched element that has the - * attribute.. If no elements were matched (isEmpty() == true), or - * if the no elements have the attribute, returns empty string. - * @see #hasAttr(String) - */ - public String attr(String attributeKey) { - for (Element element : contents) { - if (element.hasAttr(attributeKey)) { - return element.attr(attributeKey); - } - } - return ""; - } - - /** - * Checks if any of the matched elements have this attribute set. - * - * @param attributeKey - * attribute key - * @return true if any of the elements have the attribute; false if none do. - */ - public boolean hasAttr(String attributeKey) { - for (Element element : contents) { - if (element.hasAttr(attributeKey)) { - return true; - } - } - return false; - } - - /** - * Set an attribute on all matched elements. - * - * @param attributeKey - * attribute key - * @param attributeValue - * attribute value - * @return this - */ - public Elements attr(String attributeKey, String attributeValue) { - for (Element element : contents) { - element.attr(attributeKey, attributeValue); - } - return this; - } - - /** - * Remove an attribute from every matched element. - * - * @param attributeKey - * The attribute to remove. - * @return this (for chaining) - */ - public Elements removeAttr(String attributeKey) { - for (Element element : contents) { - element.removeAttr(attributeKey); - } - return this; - } - - /** - * Add the class name to every matched element's {@code class} attribute. - * - * @param className - * class name to add - * @return this - */ - public Elements addClass(String className) { - for (Element element : contents) { - element.addClass(className); - } - return this; - } - - /** - * Remove the class name from every matched element's {@code class} - * attribute, if present. - * - * @param className - * class name to remove - * @return this - */ - public Elements removeClass(String className) { - for (Element element : contents) { - element.removeClass(className); - } - return this; - } - - /** - * Toggle the class name on every matched element's {@code class} attribute. - * - * @param className - * class name to add if missing, or remove if present, from every - * element. - * @return this - */ - public Elements toggleClass(String className) { - for (Element element : contents) { - element.toggleClass(className); - } - return this; - } - - /** - * Determine if any of the matched elements have this class name set in - * their {@code class} attribute. - * - * @param className - * class name to check for - * @return true if any do, false if none do - */ - public boolean hasClass(String className) { - for (Element element : contents) { - if (element.hasClass(className)) { - return true; - } - } - return false; - } - - /** - * Get the form element's value of the first matched element. - * - * @return The form element's value, or empty if not set. - * @see Element#val() - */ - public String val() { - if (size() > 0) { - return first().val(); - } else { - return ""; - } - } - - /** - * Set the form element's value in each of the matched elements. - * - * @param value - * The value to set into each matched element - * @return this (for chaining) - */ - public Elements val(String value) { - for (Element element : contents) { - element.val(value); - } - return this; - } - - /** - * Get the combined text of all the matched elements. - * <p> - * Note that it is possible to get repeats if the matched elements contain - * both parent elements and their own children, as the Element.text() method - * returns the combined text of a parent and all its children. - * - * @return string of all text: unescaped and no HTML. - * @see Element#text() - */ - public String text() { - StringBuilder sb = new StringBuilder(); - for (Element element : contents) { - if (sb.length() != 0) { - sb.append(" "); - } - sb.append(element.text()); - } - return sb.toString(); - } - - public boolean hasText() { - for (Element element : contents) { - if (element.hasText()) { - return true; - } - } - return false; - } - - /** - * Get the combined inner HTML of all matched elements. - * - * @return string of all element's inner HTML. - * @see #text() - * @see #outerHtml() - */ - public String html() { - StringBuilder sb = new StringBuilder(); - for (Element element : contents) { - if (sb.length() != 0) { - sb.append("\n"); - } - sb.append(element.html()); - } - return sb.toString(); - } - - /** - * Get the combined outer HTML of all matched elements. - * - * @return string of all element's outer HTML. - * @see #text() - * @see #html() - */ - public String outerHtml() { - StringBuilder sb = new StringBuilder(); - for (Element element : contents) { - if (sb.length() != 0) { - sb.append("\n"); - } - sb.append(element.outerHtml()); - } - return sb.toString(); - } - - /** - * Get the combined outer HTML of all matched elements. Alias of - * {@link #outerHtml()}. - * - * @return string of all element's outer HTML. - * @see #text() - * @see #html() - */ - @Override - public String toString() { - return outerHtml(); - } - - /** - * Update the tag name of each matched element. For example, to change each - * {@code <i>} to a {@code <em>}, do {@code doc.select("i").tagName("em");} - * - * @param tagName - * the new tag name - * @return this, for chaining - * @see Element#tagName(String) - */ - public Elements tagName(String tagName) { - for (Element element : contents) { - element.tagName(tagName); - } - return this; - } - - /** - * Set the inner HTML of each matched element. - * - * @param html - * HTML to parse and set into each matched element. - * @return this, for chaining - * @see Element#html(String) - */ - public Elements html(String html) { - for (Element element : contents) { - element.html(html); - } - return this; - } - - /** - * Add the supplied HTML to the start of each matched element's inner HTML. - * - * @param html - * HTML to add inside each element, before the existing HTML - * @return this, for chaining - * @see Element#prepend(String) - */ - public Elements prepend(String html) { - for (Element element : contents) { - element.prepend(html); - } - return this; - } - - /** - * Add the supplied HTML to the end of each matched element's inner HTML. - * - * @param html - * HTML to add inside each element, after the existing HTML - * @return this, for chaining - * @see Element#append(String) - */ - public Elements append(String html) { - for (Element element : contents) { - element.append(html); - } - return this; - } - - /** - * Insert the supplied HTML before each matched element's outer HTML. - * - * @param html - * HTML to insert before each element - * @return this, for chaining - * @see Element#before(String) - */ - public Elements before(String html) { - for (Element element : contents) { - element.before(html); - } - return this; - } - - /** - * Insert the supplied HTML after each matched element's outer HTML. - * - * @param html - * HTML to insert after each element - * @return this, for chaining - * @see Element#after(String) - */ - public Elements after(String html) { - for (Element element : contents) { - element.after(html); - } - return this; - } - - /** - * Wrap the supplied HTML around each matched elements. For example, with - * HTML {@code <p><b>This</b> is <b>Jsoup</b></p>}, - * <code>doc.select("b").wrap("<i></i>");</code> becomes - * {@code <p><i><b>This</b></i> is <i><b>jsoup</b></i></p>} - * - * @param html - * HTML to wrap around each element, e.g. - * {@code <div class="head"></div>}. Can be arbitrarily deep. - * @return this (for chaining) - * @see Element#wrap - */ - public Elements wrap(String html) { - Validate.notEmpty(html); - for (Element element : contents) { - element.wrap(html); - } - return this; - } - - /** - * Removes the matched elements from the DOM, and moves their children up - * into their parents. This has the effect of dropping the elements but - * keeping their children. - * <p/> - * This is useful for e.g removing unwanted formatting elements but keeping - * their contents. - * <p/> - * E.g. with HTML: - * {@code <div><font>One</font> <font><a href="/">Two</a></font></div>}<br/> - * {@code doc.select("font").unwrap();}<br/> - * HTML = {@code <div>One <a href="/">Two</a></div>} - * - * @return this (for chaining) - * @see Node#unwrap - */ - public Elements unwrap() { - for (Element element : contents) { - element.unwrap(); - } - return this; - } - - /** - * Empty (remove all child nodes from) each matched element. This is similar - * to setting the inner HTML of each element to nothing. - * <p> - * E.g. HTML: {@code <div><p>Hello <b>there</b></p> <p>now</p></div>}<br> - * <code>doc.select("p").empty();</code><br> - * HTML = {@code <div> - * <p></p> - * <p></p> - * </div>} - * - * @return this, for chaining - * @see Element#empty() - * @see #remove() - */ - public Elements empty() { - for (Element element : contents) { - element.empty(); - } - return this; - } - - /** - * Remove each matched element from the DOM. This is similar to setting the - * outer HTML of each element to nothing. - * <p> - * E.g. HTML: {@code <div><p>Hello</p> <p>there</p> <img /></div>}<br> - * <code>doc.select("p").remove();</code><br> - * HTML = {@code <div> <img /></div>} - * <p> - * Note that this method should not be used to clean user-submitted HTML; - * rather, use {@link org.jsoup.safety.Cleaner} to clean HTML. - * - * @return this, for chaining - * @see Element#empty() - * @see #empty() - */ - public Elements remove() { - for (Element element : contents) { - element.remove(); - } - return this; - } - - // filters - - /** - * Find matching elements within this element list. - * - * @param query - * A {@link Selector} query - * @return the filtered list of elements, or an empty list if none match. - */ - public Elements select(String query) { - return Selector.select(query, this); - } - - /** - * Remove elements from this list that match the {@link Selector} query. - * <p> - * E.g. HTML: {@code <div class=logo>One</div> <div>Two</div>}<br> - * <code>Elements divs = doc.select("div").not("#logo");</code><br> - * Result: {@code divs: [<div>Two</div>]} - * <p> - * - * @param query - * the selector query whose results should be removed from these - * elements - * @return a new elements list that contains only the filtered results - */ - public Elements not(String query) { - Elements out = Selector.select(query, this); - return Selector.filterOut(this, out); - } - - /** - * Get the <i>nth</i> matched element as an Elements object. - * <p> - * See also {@link #get(int)} to retrieve an Element. - * - * @param index - * the (zero-based) index of the element in the list to retain - * @return Elements containing only the specified element, or, if that - * element did not exist, an empty list. - */ - public Elements eq(int index) { - return contents.size() > index ? new Elements(get(index)) - : new Elements(); - } - - /** - * Test if any of the matched elements match the supplied query. - * - * @param query - * A selector - * @return true if at least one element in the list matches the query. - */ - public boolean is(String query) { - Elements children = select(query); - return !children.isEmpty(); - } - - /** - * Get all of the parents and ancestor elements of the matched elements. - * - * @return all of the parents and ancestor elements of the matched elements - */ - public Elements parents() { - HashSet<Element> combo = new LinkedHashSet<Element>(); - for (Element e : contents) { - combo.addAll(e.parents()); - } - return new Elements(combo); - } - - // list-like methods - /** - * Get the first matched element. - * - * @return The first matched element, or <code>null</code> if contents is - * empty; - */ - public Element first() { - return contents.isEmpty() ? null : contents.get(0); - } - - /** - * Get the last matched element. - * - * @return The last matched element, or <code>null</code> if contents is - * empty. - */ - public Element last() { - return contents.isEmpty() ? null : contents.get(contents.size() - 1); - } - - /** - * Perform a depth-first traversal on each of the selected elements. - * - * @param nodeVisitor - * the visitor callbacks to perform on each node - * @return this, for chaining - */ - public Elements traverse(NodeVisitor nodeVisitor) { - Validate.notNull(nodeVisitor); - NodeTraversor traversor = new NodeTraversor(nodeVisitor); - for (Element el : contents) { - traversor.traverse(el); - } - return this; - } - - // implements List<Element> delegates: - @Override - public int size() { - return contents.size(); - } - - @Override - public boolean isEmpty() { - return contents.isEmpty(); - } - - @Override - public boolean contains(Object o) { - return contents.contains(o); - } - - @Override - public Iterator<Element> iterator() { - return contents.iterator(); - } - - @Override - public Object[] toArray() { - return contents.toArray(); - } - - @Override - public <T> T[] toArray(T[] a) { - return contents.toArray(a); - } - - @Override - public boolean add(Element element) { - return contents.add(element); - } - - @Override - public boolean remove(Object o) { - return contents.remove(o); - } - - @Override - public boolean containsAll(Collection<?> c) { - return contents.containsAll(c); - } - - @Override - public boolean addAll(Collection<? extends Element> c) { - return contents.addAll(c); - } - - @Override - public boolean addAll(int index, Collection<? extends Element> c) { - return contents.addAll(index, c); - } - - @Override - public boolean removeAll(Collection<?> c) { - return contents.removeAll(c); - } - - @Override - public boolean retainAll(Collection<?> c) { - return contents.retainAll(c); - } - - @Override - public void clear() { - contents.clear(); - } - - @Override - public boolean equals(Object o) { - return contents.equals(o); - } - - @Override - public int hashCode() { - return contents.hashCode(); - } - - @Override - public Element get(int index) { - return contents.get(index); - } - - @Override - public Element set(int index, Element element) { - return contents.set(index, element); - } - - @Override - public void add(int index, Element element) { - contents.add(index, element); - } - - @Override - public Element remove(int index) { - return contents.remove(index); - } - - @Override - public int indexOf(Object o) { - return contents.indexOf(o); - } - - @Override - public int lastIndexOf(Object o) { - return contents.lastIndexOf(o); - } - - @Override - public ListIterator<Element> listIterator() { - return contents.listIterator(); - } - - @Override - public ListIterator<Element> listIterator(int index) { - return contents.listIterator(index); - } - - @Override - public List<Element> subList(int fromIndex, int toIndex) { - return contents.subList(fromIndex, toIndex); - } -} diff --git a/server/src/org/jsoup/select/Evaluator.java b/server/src/org/jsoup/select/Evaluator.java deleted file mode 100644 index 5dd4c91616..0000000000 --- a/server/src/org/jsoup/select/Evaluator.java +++ /dev/null @@ -1,474 +0,0 @@ -package org.jsoup.select; - -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.jsoup.helper.Validate; -import org.jsoup.nodes.Element; - -/** - * Evaluates that an element matches the selector. - */ -public abstract class Evaluator { - protected Evaluator() { - } - - /** - * Test if the element meets the evaluator's requirements. - * - * @param root - * UI 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); - } - } -} diff --git a/server/src/org/jsoup/select/NodeTraversor.java b/server/src/org/jsoup/select/NodeTraversor.java deleted file mode 100644 index f94a7762fc..0000000000 --- a/server/src/org/jsoup/select/NodeTraversor.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.jsoup.select; - -import org.jsoup.nodes.Node; - -/** - * Depth-first node traversor. Use to iterate through all nodes under and - * including the specified root node. - * <p/> - * This implementation does not use recursion, so a deep DOM does not risk - * blowing the stack. - */ -public class NodeTraversor { - private NodeVisitor visitor; - - /** - * Create a new traversor. - * - * @param visitor - * a class implementing the {@link NodeVisitor} interface, to be - * called when visiting each node. - */ - public NodeTraversor(NodeVisitor visitor) { - this.visitor = visitor; - } - - /** - * Start a depth-first traverse of the root and all of its descendants. - * - * @param root - * the root node point to traverse. - */ - public void traverse(Node root) { - Node node = root; - int depth = 0; - - while (node != null) { - visitor.head(node, depth); - if (node.childNodes().size() > 0) { - node = node.childNode(0); - depth++; - } else { - while (node.nextSibling() == null && depth > 0) { - visitor.tail(node, depth); - node = node.parent(); - depth--; - } - visitor.tail(node, depth); - if (node == root) { - break; - } - node = node.nextSibling(); - } - } - } -} diff --git a/server/src/org/jsoup/select/NodeVisitor.java b/server/src/org/jsoup/select/NodeVisitor.java deleted file mode 100644 index 9e827d6c55..0000000000 --- a/server/src/org/jsoup/select/NodeVisitor.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.jsoup.select; - -import org.jsoup.nodes.Node; - -/** - * Node visitor interface. Provide an implementing class to - * {@link NodeTraversor} to iterate through nodes. - * <p/> - * This interface provides two methods, {@code head} and {@code tail}. The head - * method is called when the node is first seen, and the tail method when all of - * the node's children have been visited. As an example, head can be used to - * create a start tag for a node, and tail to create the end tag. - */ -public interface NodeVisitor { - /** - * Callback for when a node is first visited. - * - * @param node - * the node being visited. - * @param depth - * the depth of the node, relative to the root node. E.g., the - * root node has depth 0, and a child node of that will have - * depth 1. - */ - public void head(Node node, int depth); - - /** - * Callback for when a node is last visited, after all of its descendants - * have been visited. - * - * @param node - * the node being visited. - * @param depth - * the depth of the node, relative to the root node. E.g., the - * root node has depth 0, and a child node of that will have - * depth 1. - */ - public void tail(Node node, int depth); -} diff --git a/server/src/org/jsoup/select/QueryParser.java b/server/src/org/jsoup/select/QueryParser.java deleted file mode 100644 index 7a04899d82..0000000000 --- a/server/src/org/jsoup/select/QueryParser.java +++ /dev/null @@ -1,334 +0,0 @@ -package org.jsoup.select; - -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - -import org.jsoup.helper.StringUtil; -import org.jsoup.helper.Validate; -import org.jsoup.parser.TokenQueue; - -/** - * Parses a CSS selector into an Evaluator tree. - */ -class QueryParser { - private final static String[] combinators = { ",", ">", "+", "~", " " }; - - private TokenQueue tq; - private String query; - private List<Evaluator> evals = new ArrayList<Evaluator>(); - - /** - * Create a new QueryParser. - * - * @param query - * CSS query - */ - private QueryParser(String query) { - this.query = query; - tq = new TokenQueue(query); - } - - /** - * Parse a CSS query into an Evaluator. - * - * @param query - * CSS query - * @return Evaluator - */ - public static Evaluator parse(String query) { - QueryParser p = new QueryParser(query); - return p.parse(); - } - - /** - * Parse the query - * - * @return Evaluator - */ - Evaluator parse() { - tq.consumeWhitespace(); - - if (tq.matchesAny(combinators)) { // if starts with a combinator, use - // root as elements - evals.add(new StructuralEvaluator.Root()); - combinator(tq.consume()); - } else { - findElements(); - } - - while (!tq.isEmpty()) { - // hierarchy and extras - boolean seenWhite = tq.consumeWhitespace(); - - if (tq.matchesAny(combinators)) { - combinator(tq.consume()); - } else if (seenWhite) { - combinator(' '); - } else { // E.class, E#id, E[attr] etc. AND - findElements(); // take next el, #. etc off queue - } - } - - if (evals.size() == 1) { - return evals.get(0); - } - - return new CombiningEvaluator.And(evals); - } - - private void combinator(char combinator) { - tq.consumeWhitespace(); - String subQuery = consumeSubQuery(); // support multi > childs - - Evaluator rootEval; // the new topmost evaluator - Evaluator currentEval; // the evaluator the new eval will be combined - // to. could be root, or rightmost or. - Evaluator newEval = parse(subQuery); // the evaluator to add into target - // evaluator - boolean replaceRightMost = false; - - if (evals.size() == 1) { - rootEval = currentEval = evals.get(0); - // make sure OR (,) has precedence: - if (rootEval instanceof CombiningEvaluator.Or && combinator != ',') { - currentEval = ((CombiningEvaluator.Or) currentEval) - .rightMostEvaluator(); - replaceRightMost = true; - } - } else { - rootEval = currentEval = new CombiningEvaluator.And(evals); - } - evals.clear(); - - // for most combinators: change the current eval into an AND of the - // current eval and the new eval - if (combinator == '>') { - currentEval = new CombiningEvaluator.And(newEval, - new StructuralEvaluator.ImmediateParent(currentEval)); - } else if (combinator == ' ') { - currentEval = new CombiningEvaluator.And(newEval, - new StructuralEvaluator.Parent(currentEval)); - } else if (combinator == '+') { - currentEval = new CombiningEvaluator.And(newEval, - new StructuralEvaluator.ImmediatePreviousSibling( - currentEval)); - } else if (combinator == '~') { - currentEval = new CombiningEvaluator.And(newEval, - new StructuralEvaluator.PreviousSibling(currentEval)); - } else if (combinator == ',') { // group or. - CombiningEvaluator.Or or; - if (currentEval instanceof CombiningEvaluator.Or) { - or = (CombiningEvaluator.Or) currentEval; - or.add(newEval); - } else { - or = new CombiningEvaluator.Or(); - or.add(currentEval); - or.add(newEval); - } - currentEval = or; - } else { - throw new Selector.SelectorParseException("Unknown combinator: " - + combinator); - } - - if (replaceRightMost) { - ((CombiningEvaluator.Or) rootEval) - .replaceRightMostEvaluator(currentEval); - } else { - rootEval = currentEval; - } - evals.add(rootEval); - } - - private String consumeSubQuery() { - StringBuilder sq = new StringBuilder(); - while (!tq.isEmpty()) { - if (tq.matches("(")) { - sq.append("(").append(tq.chompBalanced('(', ')')).append(")"); - } else if (tq.matches("[")) { - sq.append("[").append(tq.chompBalanced('[', ']')).append("]"); - } else if (tq.matchesAny(combinators)) { - break; - } else { - sq.append(tq.consume()); - } - } - return sq.toString(); - } - - private void findElements() { - if (tq.matchChomp("#")) { - byId(); - } else if (tq.matchChomp(".")) { - byClass(); - } else if (tq.matchesWord()) { - byTag(); - } else if (tq.matches("[")) { - byAttribute(); - } else if (tq.matchChomp("*")) { - allElements(); - } else if (tq.matchChomp(":lt(")) { - indexLessThan(); - } else if (tq.matchChomp(":gt(")) { - indexGreaterThan(); - } else if (tq.matchChomp(":eq(")) { - indexEquals(); - } else if (tq.matches(":has(")) { - has(); - } else if (tq.matches(":contains(")) { - contains(false); - } else if (tq.matches(":containsOwn(")) { - contains(true); - } else if (tq.matches(":matches(")) { - matches(false); - } else if (tq.matches(":matchesOwn(")) { - matches(true); - } else if (tq.matches(":not(")) { - not(); - } else { - throw new Selector.SelectorParseException( - "Could not parse query '%s': unexpected token at '%s'", - query, tq.remainder()); - } - - } - - private void byId() { - String id = tq.consumeCssIdentifier(); - Validate.notEmpty(id); - evals.add(new Evaluator.Id(id)); - } - - private void byClass() { - String className = tq.consumeCssIdentifier(); - Validate.notEmpty(className); - evals.add(new Evaluator.Class(className.trim().toLowerCase())); - } - - private void byTag() { - String tagName = tq.consumeElementSelector(); - Validate.notEmpty(tagName); - - // namespaces: if element name is "abc:def", selector must be "abc|def", - // so flip: - if (tagName.contains("|")) { - tagName = tagName.replace("|", ":"); - } - - evals.add(new Evaluator.Tag(tagName.trim().toLowerCase())); - } - - private void byAttribute() { - TokenQueue cq = new TokenQueue(tq.chompBalanced('[', ']')); // content - // queue - String key = cq.consumeToAny("=", "!=", "^=", "$=", "*=", "~="); // eq, - // not, - // start, - // end, - // contain, - // match, - // (no - // val) - Validate.notEmpty(key); - cq.consumeWhitespace(); - - if (cq.isEmpty()) { - if (key.startsWith("^")) { - evals.add(new Evaluator.AttributeStarting(key.substring(1))); - } else { - evals.add(new Evaluator.Attribute(key)); - } - } else { - if (cq.matchChomp("=")) { - evals.add(new Evaluator.AttributeWithValue(key, cq.remainder())); - } else if (cq.matchChomp("!=")) { - evals.add(new Evaluator.AttributeWithValueNot(key, cq - .remainder())); - } else if (cq.matchChomp("^=")) { - evals.add(new Evaluator.AttributeWithValueStarting(key, cq - .remainder())); - } else if (cq.matchChomp("$=")) { - evals.add(new Evaluator.AttributeWithValueEnding(key, cq - .remainder())); - } else if (cq.matchChomp("*=")) { - evals.add(new Evaluator.AttributeWithValueContaining(key, cq - .remainder())); - } else if (cq.matchChomp("~=")) { - evals.add(new Evaluator.AttributeWithValueMatching(key, Pattern - .compile(cq.remainder()))); - } else { - throw new Selector.SelectorParseException( - "Could not parse attribute query '%s': unexpected token at '%s'", - query, cq.remainder()); - } - } - } - - private void allElements() { - evals.add(new Evaluator.AllElements()); - } - - // pseudo selectors :lt, :gt, :eq - private void indexLessThan() { - evals.add(new Evaluator.IndexLessThan(consumeIndex())); - } - - private void indexGreaterThan() { - evals.add(new Evaluator.IndexGreaterThan(consumeIndex())); - } - - private void indexEquals() { - evals.add(new Evaluator.IndexEquals(consumeIndex())); - } - - private int consumeIndex() { - String indexS = tq.chompTo(")").trim(); - Validate.isTrue(StringUtil.isNumeric(indexS), "Index must be numeric"); - return Integer.parseInt(indexS); - } - - // pseudo selector :has(el) - private void has() { - tq.consume(":has"); - String subQuery = tq.chompBalanced('(', ')'); - Validate.notEmpty(subQuery, ":has(el) subselect must not be empty"); - evals.add(new StructuralEvaluator.Has(parse(subQuery))); - } - - // pseudo selector :contains(text), containsOwn(text) - private void contains(boolean own) { - tq.consume(own ? ":containsOwn" : ":contains"); - String searchText = TokenQueue.unescape(tq.chompBalanced('(', ')')); - Validate.notEmpty(searchText, ":contains(text) query must not be empty"); - if (own) { - evals.add(new Evaluator.ContainsOwnText(searchText)); - } else { - evals.add(new Evaluator.ContainsText(searchText)); - } - } - - // :matches(regex), matchesOwn(regex) - private void matches(boolean own) { - tq.consume(own ? ":matchesOwn" : ":matches"); - String regex = tq.chompBalanced('(', ')'); // don't unescape, as regex - // bits will be escaped - Validate.notEmpty(regex, ":matches(regex) query must not be empty"); - - if (own) { - evals.add(new Evaluator.MatchesOwn(Pattern.compile(regex))); - } else { - evals.add(new Evaluator.Matches(Pattern.compile(regex))); - } - } - - // :not(selector) - private void not() { - tq.consume(":not"); - String subQuery = tq.chompBalanced('(', ')'); - Validate.notEmpty(subQuery, - ":not(selector) subselect must not be empty"); - - evals.add(new StructuralEvaluator.Not(parse(subQuery))); - } -} diff --git a/server/src/org/jsoup/select/Selector.java b/server/src/org/jsoup/select/Selector.java deleted file mode 100644 index d5ea6f2dc9..0000000000 --- a/server/src/org/jsoup/select/Selector.java +++ /dev/null @@ -1,278 +0,0 @@ -package org.jsoup.select; - -import java.util.Collection; -import java.util.LinkedHashSet; - -import org.jsoup.helper.Validate; -import org.jsoup.nodes.Element; - -/** - * CSS-like element selector, that finds elements matching a query. - * <p/> - * <h2>Selector syntax</h2> - * A selector is a chain of simple selectors, separated by combinators. - * Selectors are case insensitive (including against elements, attributes, and - * attribute values). - * <p/> - * The universal selector (*) is implicit when no element selector is supplied - * (i.e. {@code *.header} and {@code .header} is equivalent). - * <p/> - * <table> - * <tr> - * <th>Pattern</th> - * <th>Matches</th> - * <th>Example</th> - * </tr> - * <tr> - * <td><code>*</code></td> - * <td>any element</td> - * <td><code>*</code></td> - * </tr> - * <tr> - * <td><code>tag</code></td> - * <td>elements with the given tag name</td> - * <td><code>div</code></td> - * </tr> - * <tr> - * <td><code>ns|E</code></td> - * <td>elements of type E in the namespace <i>ns</i></td> - * <td><code>fb|name</code> finds <code><fb:name></code> elements</td> - * </tr> - * <tr> - * <td><code>#id</code></td> - * <td>elements with attribute ID of "id"</td> - * <td><code>div#wrap</code>, <code>#logo</code></td> - * </tr> - * <tr> - * <td><code>.class</code></td> - * <td>elements with a class name of "class"</td> - * <td><code>div.left</code>, <code>.result</code></td> - * </tr> - * <tr> - * <td><code>[attr]</code></td> - * <td>elements with an attribute named "attr" (with any value)</td> - * <td><code>a[href]</code>, <code>[title]</code></td> - * </tr> - * <tr> - * <td><code>[^attrPrefix]</code></td> - * <td>elements with an attribute name starting with "attrPrefix". Use to find - * elements with HTML5 datasets</td> - * <td><code>[^data-]</code>, <code>div[^data-]</code></td> - * </tr> - * <tr> - * <td><code>[attr=val]</code></td> - * <td>elements with an attribute named "attr", and value equal to "val"</td> - * <td><code>img[width=500]</code>, <code>a[rel=nofollow]</code></td> - * </tr> - * <tr> - * <td><code>[attr^=valPrefix]</code></td> - * <td>elements with an attribute named "attr", and value starting with - * "valPrefix"</td> - * <td><code>a[href^=http:]</code></code></td> - * </tr> - * <tr> - * <td><code>[attr$=valSuffix]</code></td> - * <td>elements with an attribute named "attr", and value ending with - * "valSuffix"</td> - * <td><code>img[src$=.png]</code></td> - * </tr> - * <tr> - * <td><code>[attr*=valContaining]</code></td> - * <td>elements with an attribute named "attr", and value containing - * "valContaining"</td> - * <td><code>a[href*=/search/]</code></td> - * </tr> - * <tr> - * <td><code>[attr~=<em>regex</em>]</code></td> - * <td>elements with an attribute named "attr", and value matching the regular - * expression</td> - * <td><code>img[src~=(?i)\\.(png|jpe?g)]</code></td> - * </tr> - * <tr> - * <td></td> - * <td>The above may be combined in any order</td> - * <td><code>div.header[title]</code></td> - * </tr> - * <tr> - * <td> - * <td colspan="3"> - * <h3>Combinators</h3></td> - * </tr> - * <tr> - * <td><code>E F</code></td> - * <td>an F element descended from an E element</td> - * <td><code>div a</code>, <code>.logo h1</code></td> - * </tr> - * <tr> - * <td><code>E > F</code></td> - * <td>an F direct child of E</td> - * <td><code>ol > li</code></td> - * </tr> - * <tr> - * <td><code>E + F</code></td> - * <td>an F element immediately preceded by sibling E</td> - * <td><code>li + li</code>, <code>div.head + div</code></td> - * </tr> - * <tr> - * <td><code>E ~ F</code></td> - * <td>an F element preceded by sibling E</td> - * <td><code>h1 ~ p</code></td> - * </tr> - * <tr> - * <td><code>E, F, G</code></td> - * <td>all matching elements E, F, or G</td> - * <td><code>a[href], div, h3</code></td> - * </tr> - * <tr> - * <td> - * <td colspan="3"> - * <h3>Pseudo selectors</h3></td> - * </tr> - * <tr> - * <td><code>:lt(<em>n</em>)</code></td> - * <td>elements whose sibling index is less than <em>n</em></td> - * <td><code>td:lt(3)</code> finds the first 2 cells of each row</td> - * </tr> - * <tr> - * <td><code>:gt(<em>n</em>)</code></td> - * <td>elements whose sibling index is greater than <em>n</em></td> - * <td><code>td:gt(1)</code> finds cells after skipping the first two</td> - * </tr> - * <tr> - * <td><code>:eq(<em>n</em>)</code></td> - * <td>elements whose sibling index is equal to <em>n</em></td> - * <td><code>td:eq(0)</code> finds the first cell of each row</td> - * </tr> - * <tr> - * <td><code>:has(<em>selector</em>)</code></td> - * <td>elements that contains at least one element matching the - * <em>selector</em></td> - * <td><code>div:has(p)</code> finds divs that contain p elements</td> - * </tr> - * <tr> - * <td><code>:not(<em>selector</em>)</code></td> - * <td>elements that do not match the <em>selector</em>. See also - * {@link Elements#not(String)}</td> - * <td><code>div:not(.logo)</code> finds all divs that do not have the "logo" - * class.<br /> - * <code>div:not(:has(div))</code> finds divs that do not contain divs.</code></td> - * </tr> - * <tr> - * <td><code>:contains(<em>text</em>)</code></td> - * <td>elements that contains the specified text. The search is case - * insensitive. The text may appear in the found element, or any of its - * descendants.</td> - * <td><code>p:contains(jsoup)</code> finds p elements containing the text - * "jsoup".</td> - * </tr> - * <tr> - * <td><code>:matches(<em>regex</em>)</code></td> - * <td>elements whose text matches the specified regular expression. The text - * may appear in the found element, or any of its descendants.</td> - * <td><code>td:matches(\\d+)</code> finds table cells containing digits. - * <code>div:matches((?i)login)</code> finds divs containing the text, case - * insensitively.</td> - * </tr> - * <tr> - * <td><code>:containsOwn(<em>text</em>)</code></td> - * <td>elements that directly contains the specified text. The search is case - * insensitive. The text must appear in the found element, not any of its - * descendants.</td> - * <td><code>p:containsOwn(jsoup)</code> finds p elements with own text "jsoup". - * </td> - * </tr> - * <tr> - * <td><code>:matchesOwn(<em>regex</em>)</code></td> - * <td>elements whose own text matches the specified regular expression. The - * text must appear in the found element, not any of its descendants.</td> - * <td><code>td:matchesOwn(\\d+)</code> finds table cells directly containing - * digits. <code>div:matchesOwn((?i)login)</code> finds divs containing the - * text, case insensitively.</td> - * </tr> - * <tr> - * <td></td> - * <td>The above may be combined in any order and with other selectors</td> - * <td><code>.light:contains(name):eq(0)</code></td> - * </tr> - * </table> - * - * @author Jonathan Hedley, jonathan@hedley.net - * @see Element#select(String) - */ -public class Selector { - private final Evaluator evaluator; - private final Element root; - - private Selector(String query, Element root) { - Validate.notNull(query); - query = query.trim(); - Validate.notEmpty(query); - Validate.notNull(root); - - evaluator = QueryParser.parse(query); - - this.root = root; - } - - /** - * Find elements matching selector. - * - * @param query - * CSS selector - * @param root - * root element to descend into - * @return matching elements, empty if not - */ - public static Elements select(String query, Element root) { - return new Selector(query, root).select(); - } - - /** - * Find elements matching selector. - * - * @param query - * CSS selector - * @param roots - * root elements to descend into - * @return matching elements, empty if not - */ - public static Elements select(String query, Iterable<Element> roots) { - Validate.notEmpty(query); - Validate.notNull(roots); - LinkedHashSet<Element> elements = new LinkedHashSet<Element>(); - - for (Element root : roots) { - elements.addAll(select(query, root)); - } - return new Elements(elements); - } - - private Elements select() { - return Collector.collect(evaluator, root); - } - - // exclude set. package open so that Elements can implement .not() selector. - static Elements filterOut(Collection<Element> elements, - Collection<Element> outs) { - Elements output = new Elements(); - for (Element el : elements) { - boolean found = false; - for (Element out : outs) { - if (el.equals(out)) { - found = true; - break; - } - } - if (!found) { - output.add(el); - } - } - return output; - } - - public static class SelectorParseException extends IllegalStateException { - public SelectorParseException(String msg, Object... params) { - super(String.format(msg, params)); - } - } -} diff --git a/server/src/org/jsoup/select/StructuralEvaluator.java b/server/src/org/jsoup/select/StructuralEvaluator.java deleted file mode 100644 index dea2413fb8..0000000000 --- a/server/src/org/jsoup/select/StructuralEvaluator.java +++ /dev/null @@ -1,152 +0,0 @@ -package org.jsoup.select; - -import org.jsoup.nodes.Element; - -/** - * Base structural evaluator. - */ -abstract class StructuralEvaluator extends Evaluator { - Evaluator evaluator; - - static class Root extends Evaluator { - @Override - public boolean matches(Element root, Element element) { - return root == element; - } - } - - static class Has extends StructuralEvaluator { - public Has(Evaluator evaluator) { - this.evaluator = evaluator; - } - - @Override - public boolean matches(Element root, Element element) { - for (Element e : element.getAllElements()) { - if (e != element && evaluator.matches(root, e)) { - return true; - } - } - return false; - } - - @Override - public String toString() { - return String.format(":has(%s)", evaluator); - } - } - - static class Not extends StructuralEvaluator { - public Not(Evaluator evaluator) { - this.evaluator = evaluator; - } - - @Override - public boolean matches(Element root, Element node) { - return !evaluator.matches(root, node); - } - - @Override - public String toString() { - return String.format(":not%s", evaluator); - } - } - - static class Parent extends StructuralEvaluator { - public Parent(Evaluator evaluator) { - this.evaluator = evaluator; - } - - @Override - public boolean matches(Element root, Element element) { - if (root == element) { - return false; - } - - Element parent = element.parent(); - while (parent != root) { - if (evaluator.matches(root, parent)) { - return true; - } - parent = parent.parent(); - } - return false; - } - - @Override - public String toString() { - return String.format(":parent%s", evaluator); - } - } - - static class ImmediateParent extends StructuralEvaluator { - public ImmediateParent(Evaluator evaluator) { - this.evaluator = evaluator; - } - - @Override - public boolean matches(Element root, Element element) { - if (root == element) { - return false; - } - - Element parent = element.parent(); - return parent != null && evaluator.matches(root, parent); - } - - @Override - public String toString() { - return String.format(":ImmediateParent%s", evaluator); - } - } - - static class PreviousSibling extends StructuralEvaluator { - public PreviousSibling(Evaluator evaluator) { - this.evaluator = evaluator; - } - - @Override - public boolean matches(Element root, Element element) { - if (root == element) { - return false; - } - - Element prev = element.previousElementSibling(); - - while (prev != null) { - if (evaluator.matches(root, prev)) { - return true; - } - - prev = prev.previousElementSibling(); - } - return false; - } - - @Override - public String toString() { - return String.format(":prev*%s", evaluator); - } - } - - static class ImmediatePreviousSibling extends StructuralEvaluator { - public ImmediatePreviousSibling(Evaluator evaluator) { - this.evaluator = evaluator; - } - - @Override - public boolean matches(Element root, Element element) { - if (root == element) { - return false; - } - - Element prev = element.previousElementSibling(); - return prev != null && evaluator.matches(root, prev); - } - - @Override - public String toString() { - return String.format(":prev%s", evaluator); - } - } -} diff --git a/server/src/org/jsoup/select/package-info.java b/server/src/org/jsoup/select/package-info.java deleted file mode 100644 index a6e6a2fa0f..0000000000 --- a/server/src/org/jsoup/select/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - Packages to support the CSS-style element selector. - */ -package org.jsoup.select;
\ No newline at end of file |