001package org.jsoup.select; 002 003import org.jsoup.nodes.Element; 004import org.jspecify.annotations.Nullable; 005 006import java.util.stream.Collectors; 007import java.util.stream.Stream; 008 009/** 010 * Collects a list of elements that match the supplied criteria. 011 * 012 * @author Jonathan Hedley 013 */ 014public class Collector { 015 016 private Collector() {} 017 018 /** 019 Build a list of elements, by visiting the root and every descendant of root, and testing it against the Evaluator. 020 @param eval Evaluator to test elements against 021 @param root root of tree to descend 022 @return list of matches; empty if none 023 */ 024 public static Elements collect(Evaluator eval, Element root) { 025 return stream(eval, root).collect(Collectors.toCollection(Elements::new)); 026 } 027 028 /** 029 Obtain a Stream of elements by visiting the root and every descendant of root and testing it against the evaluator. 030 031 @param evaluator Evaluator to test elements against 032 @param root root of tree to descend 033 @return A {@link Stream} of matches 034 @since 1.19.1 035 */ 036 public static Stream<Element> stream(Evaluator evaluator, Element root) { 037 evaluator.reset(); 038 return root.stream().filter(evaluator.asPredicate(root)); 039 } 040 041 /** 042 Finds the first Element that matches the Evaluator that descends from the root, and stops the query once that first 043 match is found. 044 @param eval Evaluator to test elements against 045 @param root root of tree to descend 046 @return the first match; {@code null} if none 047 */ 048 public static @Nullable Element findFirst(Evaluator eval, Element root) { 049 return stream(eval, root).findFirst().orElse(null); 050 } 051}