package org.jsoup.select;

import org.jsoup.helper.Validate;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.select.NodeFilter.FilterResult;

Depth-first node traversor. Use to iterate through all nodes under and including the specified root node.

This implementation does not use recursion, so a deep DOM does not risk blowing the stack.

/** * 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. * </p> */
public class NodeTraversor { private NodeVisitor visitor;
Create a new traversor.
Params:
  • visitor – a class implementing the NodeVisitor interface, to be called when visiting each node.
Deprecated:Just use the static filter(NodeFilter, Node) method.
/** * Create a new traversor. * @param visitor a class implementing the {@link NodeVisitor} interface, to be called when visiting each node. * @deprecated Just use the static {@link NodeTraversor#filter(NodeFilter, Node)} method. */
public NodeTraversor(NodeVisitor visitor) { this.visitor = visitor; }
Start a depth-first traverse of the root and all of its descendants.
Params:
  • root – the root node point to traverse.
Deprecated:Just use the static filter(NodeFilter, Node) method.
/** * Start a depth-first traverse of the root and all of its descendants. * @param root the root node point to traverse. * @deprecated Just use the static {@link NodeTraversor#filter(NodeFilter, Node)} method. */
public void traverse(Node root) { traverse(visitor, root); }
Start a depth-first traverse of the root and all of its descendants.
Params:
  • visitor – Node visitor.
  • root – the root node point to traverse.
/** * Start a depth-first traverse of the root and all of its descendants. * @param visitor Node visitor. * @param root the root node point to traverse. */
public static void traverse(NodeVisitor visitor, Node root) { Node node = root; int depth = 0; while (node != null) { visitor.head(node, depth); if (node.childNodeSize() > 0) { node = node.childNode(0); depth++; } else { while (node.nextSibling() == null && depth > 0) { visitor.tail(node, depth); node = node.parentNode(); depth--; } visitor.tail(node, depth); if (node == root) break; node = node.nextSibling(); } } }
Start a depth-first traverse of all elements.
Params:
  • visitor – Node visitor.
  • elements – Elements to filter.
/** * Start a depth-first traverse of all elements. * @param visitor Node visitor. * @param elements Elements to filter. */
public static void traverse(NodeVisitor visitor, Elements elements) { Validate.notNull(visitor); Validate.notNull(elements); for (Element el : elements) traverse(visitor, el); }
Start a depth-first filtering of the root and all of its descendants.
Params:
  • filter – Node visitor.
  • root – the root node point to traverse.
Returns:The filter result of the root node, or FilterResult.STOP.
/** * Start a depth-first filtering of the root and all of its descendants. * @param filter Node visitor. * @param root the root node point to traverse. * @return The filter result of the root node, or {@link FilterResult#STOP}. */
public static FilterResult filter(NodeFilter filter, Node root) { Node node = root; int depth = 0; while (node != null) { FilterResult result = filter.head(node, depth); if (result == FilterResult.STOP) return result; // Descend into child nodes: if (result == FilterResult.CONTINUE && node.childNodeSize() > 0) { node = node.childNode(0); ++depth; continue; } // No siblings, move upwards: while (node.nextSibling() == null && depth > 0) { // 'tail' current node: if (result == FilterResult.CONTINUE || result == FilterResult.SKIP_CHILDREN) { result = filter.tail(node, depth); if (result == FilterResult.STOP) return result; } Node prev = node; // In case we need to remove it below. node = node.parentNode(); depth--; if (result == FilterResult.REMOVE) prev.remove(); // Remove AFTER finding parent. result = FilterResult.CONTINUE; // Parent was not pruned. } // 'tail' current node, then proceed with siblings: if (result == FilterResult.CONTINUE || result == FilterResult.SKIP_CHILDREN) { result = filter.tail(node, depth); if (result == FilterResult.STOP) return result; } if (node == root) return result; Node prev = node; // In case we need to remove it below. node = node.nextSibling(); if (result == FilterResult.REMOVE) prev.remove(); // Remove AFTER finding sibling. } // root == null? return FilterResult.CONTINUE; }
Start a depth-first filtering of all elements.
Params:
  • filter – Node filter.
  • elements – Elements to filter.
/** * Start a depth-first filtering of all elements. * @param filter Node filter. * @param elements Elements to filter. */
public static void filter(NodeFilter filter, Elements elements) { Validate.notNull(filter); Validate.notNull(elements); for (Element el : elements) if (filter(filter, el) == FilterResult.STOP) break; } }