/** * Copyright (c) 2009-2015, Christer Sandberg */ package se.fishtank.css.selectors; import java.util.LinkedList; import java.util.List; import se.fishtank.css.selectors.dom.DOMNode; import se.fishtank.css.selectors.dom.Traversal; import se.fishtank.css.selectors.dom.Visitor; import se.fishtank.css.selectors.matching.SelectorMatcher; import se.fishtank.css.selectors.matching.SimpleSelectorMatcher; import se.fishtank.css.selectors.parser.ParserException; import se.fishtank.css.selectors.parser.SelectorParser; import se.fishtank.css.selectors.selector.Selector; import se.fishtank.css.selectors.util.Reference; /** * Simplified selectors API. * * @author Christer Sandberg */ public class Selectors<T, U extends DOMNode<U, T>> { /** The root node. */ private final U rootNode; /** The selectors matcher. */ private final SelectorMatcher<U> selectorMatcher; /** * Create a new instance. * * @param rootNode The root node. */ public Selectors(U rootNode) { this(rootNode, null); } /** * Create a new instance. * * @param rootNode The root node. * @param simpleSelectorMatcher A simple selector matcher for custom matching. */ public Selectors(U rootNode, SimpleSelectorMatcher<U> simpleSelectorMatcher) { this.rootNode = rootNode; this.selectorMatcher = new SelectorMatcher<>(simpleSelectorMatcher); } /** * Returns the root node. * * @return The root node. */ public U getRootNode() { return rootNode; } /** * Returns the first matching node or {@code null} if match was found. * * @param selectors A list of selectors. * @return The first matching node or {@code null} */ public T querySelector(final List<Selector> selectors) { final Reference<T> ref = new Reference<>(); final RuntimeException done = new RuntimeException(); try { Traversal.traverseElements(rootNode, new Visitor<U>() { @Override public void visit(U node) { if (selectorMatcher.matchesSelectors(selectors, node)) { ref.referent = node.getUnderlying(); throw done; } } }); } catch (RuntimeException e) { if (e != done) { throw e; } } return ref.referent; } /** * Returns the first matching node or {@code null} if match was found. * * @param selectors A selectors string. * @return The first matching node or {@code null} * @throws ParserException On errors parsing the given selectors string. */ public T querySelector(String selectors) throws ParserException { return querySelector(parse(selectors)); } /** * Returns a list of all the matching nodes. * * @param selectors A list of selectors. * @return A list of all the matching nodes. */ public List<T> querySelectorAll(final List<Selector> selectors) { final LinkedList<T> result = new LinkedList<>(); Traversal.traverseElements(rootNode, new Visitor<U>() { @Override public void visit(U node) { if (selectorMatcher.matchesSelectors(selectors, node)) { result.add(node.getUnderlying()); } } }); return result; } /** * Returns a list of all the matching nodes. * * @param selectors A selectors string. * @return A list of all the matching nodes. * @throws ParserException On errors parsing the given selectors string. */ public List<T> querySelectorAll(String selectors) throws ParserException { return querySelectorAll(parse(selectors)); } /** * Parses the given selectors string and returns a selector list. * * @param selectors The selectors string to parse. * @return A selector list. * @throws ParserException On parsing errors. */ public static List<Selector> parse(String selectors) throws ParserException { return SelectorParser.parse(selectors); } }