package org.nate.internal.dom4j.cssselectors.internal; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Set; import org.dom4j.Branch; import org.dom4j.Node; import org.nate.internal.dom4j.cssselectors.DOMHelper; import se.fishtank.css.selectors.NodeSelectorException; import se.fishtank.css.selectors.Selector; import se.fishtank.css.util.Assert; /** * Simple port of Christer Sandberg's CSS selectors to Dom4j (https://github.com/chrsan/css-selectors) */ public class TagChecker implements NodeTraversalChecker { /** The selector to check against. */ private final Selector selector; /** The set of nodes to check. */ private Set<Branch> nodes; /** The result of the checks. */ private Set<Branch> result; public TagChecker(Selector selector) { Assert.notNull(selector, "selector is null!"); this.selector = selector; } @Override public Set<Branch> check(Set<Branch> nodes) throws NodeSelectorException { Assert.notNull(nodes, "nodes is null!"); this.nodes = nodes; result = new LinkedHashSet<Branch>(); switch (selector.getCombinator()) { case DESCENDANT: getDescentantElements(); break; case CHILD: getChildElements(); break; case ADJACENT_SIBLING: getAdjacentSiblingElements(); break; case GENERAL_SIBLING: getGeneralSiblingElements(); break; } return result; } /** * Get descendant elements. * * @see <a href="http://www.w3.org/TR/css3-selectors/#descendant-combinators">Descendant combinator</a> * * @throws NodeSelectorException If one of the nodes have an illegal type. */ private void getDescentantElements() throws NodeSelectorException { for (Branch node : nodes) { getDescentantElements(node); } } private void getDescentantElements(Branch node) { String tagName = selector.getTagName(); Iterator<Node> nodeIterator = node.nodeIterator(); while (nodeIterator.hasNext()) { Node child = nodeIterator.next(); if (child.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) { if (tagName.equals("*") || child.getName().equals(tagName)) { result.add((Branch) child); } getDescentantElements((Branch) child); } } } /** * Get child elements. * * @see <a href="http://www.w3.org/TR/css3-selectors/#child-combinators">Child combinators</a> */ private void getChildElements() { String tag = selector.getTagName(); for (Branch node : nodes) { Iterator<Node> nodeIterator = node.nodeIterator(); while (nodeIterator.hasNext()) { Node child = nodeIterator.next(); if (child.getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) { continue; } if (tag.equals(child.getName()) || tag.equals(Selector.UNIVERSAL_TAG)) { result.add((Branch) child); } } } } /** * Get adjacent sibling elements. * * @see <a href="http://www.w3.org/TR/css3-selectors/#adjacent-sibling-combinators">Adjacent sibling combinator</a> */ private void getAdjacentSiblingElements() { String tag = selector.getTagName(); for (Branch node : nodes) { Branch n = DOMHelper.getNextSiblingElement(node); if (n != null) { if (tag.equals(n.getName()) || tag.equals(Selector.UNIVERSAL_TAG)) { result.add(n); } } } } /** * Get general sibling elements. * * @see <a href="http://www.w3.org/TR/css3-selectors/#general-sibling-combinators">General sibling combinator</a> */ private void getGeneralSiblingElements() { for (Branch node : nodes) { Branch n = DOMHelper.getNextSiblingElement(node); while (n != null) { if (selector.getTagName().equals(n.getName()) || selector.getTagName().equals(Selector.UNIVERSAL_TAG)) { result.add(n); } n = DOMHelper.getNextSiblingElement(n); } } } }