001package org.jsoup.nodes;
002
003import org.jsoup.helper.Validate;
004import org.jsoup.internal.LegacyMatching;
005import org.jsoup.internal.CssMatching;
006import org.jsoup.internal.QuietAppendable;
007import org.jsoup.internal.QueryMode;
008import org.jsoup.helper.Regex;
009import org.jsoup.internal.StringUtil;
010import org.jsoup.parser.ParseSettings;
011import org.jsoup.parser.Parser;
012import org.jsoup.parser.Tag;
013import org.jsoup.parser.TokenQueue;
014import org.jsoup.select.Collector;
015import org.jsoup.select.Elements;
016import org.jsoup.select.Evaluator;
017import org.jsoup.select.EvaluatorInternals;
018import org.jsoup.select.NodeFilter;
019import org.jsoup.select.NodeVisitor;
020import org.jsoup.select.Nodes;
021import org.jsoup.select.Selector;
022import org.jspecify.annotations.Nullable;
023
024import java.lang.ref.WeakReference;
025import java.util.ArrayList;
026import java.util.Collection;
027import java.util.Collections;
028import java.util.Iterator;
029import java.util.LinkedHashSet;
030import java.util.List;
031import java.util.Map;
032import java.util.Set;
033import java.util.concurrent.atomic.AtomicBoolean;
034import java.util.function.Consumer;
035import java.util.regex.Pattern;
036import java.util.regex.PatternSyntaxException;
037import java.util.stream.Collectors;
038import java.util.stream.Stream;
039
040import static org.jsoup.internal.Normalizer.asciiLowerCase;
041import static org.jsoup.nodes.Document.OutputSettings.Syntax.html;
042import static org.jsoup.nodes.Document.OutputSettings.Syntax.xml;
043import static org.jsoup.nodes.TextNode.lastCharIsWhitespace;
044import static org.jsoup.parser.Parser.NamespaceHtml;
045import static org.jsoup.parser.TokenQueue.escapeCssIdentifier;
046import static org.jsoup.select.Selector.evaluatorOf;
047
048/**
049 An HTML Element consists of a tag name, attributes, and child nodes (including text nodes and other elements).
050 Case-insensitive name lookups and name trimming use ASCII rules.
051 <p>
052 From an Element, you can extract data, traverse the node graph, and manipulate the HTML.
053 <p>The query and matching methods on this class support an opt-in preview of Web DOM query behavior.
054 See <a href="{@docRoot}/org/jsoup/select/Selector.html#query-compatibility">Query compatibility changes</a> for how to enable it and which behavior changes.</p>
055*/
056public class Element extends Node implements Iterable<Element> {
057    private static final List<Element> EmptyChildren = Collections.emptyList();
058    private static final NodeList EmptyNodeList = new NodeList(0);
059    static final String BaseUriKey = Attributes.internalKey("baseUri");
060    Tag tag;
061    NodeList childNodes;
062    @Nullable Attributes attributes; // field is nullable but all methods for attributes are non-null
063
064    /**
065     * Create a new, standalone element, in the specified namespace.
066     * @param tag tag name
067     * @param namespace namespace for this element
068     */
069    public Element(String tag, String namespace) {
070        this(Tag.valueOf(tag, namespace, ParseSettings.preserveCase), null);
071    }
072
073    /**
074     * Create a new, standalone element, in the HTML namespace.
075     * @param tag tag name
076     * @see #Element(String tag, String namespace)
077     */
078    public Element(String tag) {
079        this(tag, Parser.NamespaceHtml);
080    }
081
082    /**
083     * Create a new, standalone Element. (Standalone in that it has no parent.)
084     *
085     * @param tag tag of this element
086     * @param baseUri the base URI (optional, may be null to inherit from parent, or "" to clear parent's)
087     * @param attributes initial attributes (optional, may be null)
088     * @see #appendChild(Node)
089     * @see #appendElement(String)
090     */
091    public Element(Tag tag, @Nullable String baseUri, @Nullable Attributes attributes) {
092        Validate.notNull(tag);
093        childNodes = EmptyNodeList;
094        this.attributes = attributes;
095        this.tag = tag;
096        if (!StringUtil.isBlank(baseUri)) this.setBaseUri(baseUri);
097    }
098
099    /**
100     * Create a new Element from a Tag and a base URI.
101     *
102     * @param tag element tag
103     * @param baseUri the base URI of this element. Optional, and will inherit from its parent, if any.
104     * @see Tag#valueOf(String, ParseSettings)
105     */
106    public Element(Tag tag, @Nullable String baseUri) {
107        this(tag, baseUri, null);
108    }
109
110    /**
111     Internal test to check if a nodelist object has been created.
112     */
113    protected boolean hasChildNodes() {
114        return childNodes != EmptyNodeList;
115    }
116
117    @Override protected List<Node> ensureChildNodes() {
118        if (childNodes == EmptyNodeList) {
119            childNodes = new NodeList(4);
120        }
121        return childNodes;
122    }
123
124    @Override
125    protected boolean hasAttributes() {
126        return attributes != null;
127    }
128
129    @Override
130    public Attributes attributes() {
131        if (attributes == null) // not using hasAttributes, as doesn't clear warning
132            attributes = new Attributes();
133        return attributes;
134    }
135
136    @Override
137    public String baseUri() {
138        String baseUri = searchUpForAttribute(this, BaseUriKey);
139        return baseUri != null ? baseUri : "";
140    }
141
142    @Nullable
143    static String searchUpForAttribute(final Element start, final String key) {
144        Element el = start;
145        while (el != null) {
146            if (el.attributes != null && el.attributes.hasKey(key))
147                return el.attributes.get(key);
148            el = el.parent();
149        }
150        return null;
151    }
152
153    @Override
154    protected void doSetBaseUri(String baseUri) {
155        attributes().put(BaseUriKey, baseUri);
156    }
157
158    @Override
159    public int childNodeSize() {
160        return childNodes.size();
161    }
162
163    @Override
164    public String nodeName() {
165        return tag.getName();
166    }
167
168    /**
169     * Get the name of the tag for this element. E.g. {@code div}. If you are using {@link ParseSettings#preserveCase
170     * case preserving parsing}, this will return the source's original case.
171     *
172     * @return the tag name
173     */
174    public String tagName() {
175        return tag.getName();
176    }
177
178    /**
179     * Get the normalized name of this Element's tag. For e.g., {@code <DIV>} and {@code <div>} both have a
180     * normal name of {@code div}. See {@link Tag#normalName()}.
181     * @return normal name
182     */
183    @Override
184    public String normalName() {
185        return tag.normalName();
186    }
187
188    /**
189     Test if this Element has the specified normalized name, and is in the specified namespace.
190     * @param normalName a normalized element name (e.g. {@code div}).
191     * @param namespace the namespace
192     * @return true if the element's normal name matches exactly, and is in the specified namespace
193     * @since 1.17.2
194     */
195    public boolean elementIs(String normalName, String namespace) {
196        return tag.normalName().equals(normalName) && tag.namespace().equals(namespace);
197    }
198
199    /**
200     * Change (rename) the tag of this element. For example, convert a {@code <span>} to a {@code <div>} with
201     * {@code el.tagName("div");}.
202     *
203     * @param tagName new tag name for this element
204     * @return this element, for chaining
205     * @see Elements#tagName(String)
206     */
207    public Element tagName(String tagName) {
208        return tagName(tagName, tag.namespace());
209    }
210
211    /**
212     * Change (rename) the tag of this element. For example, convert a {@code <span>} to a {@code <div>} with
213     * {@code el.tagName("div");}.
214     *
215     * @param tagName new tag name for this element
216     * @param namespace the new namespace for this element
217     * @return this element, for chaining
218     * @see Elements#tagName(String)
219     */
220    public Element tagName(String tagName, String namespace) {
221        Validate.notEmptyParam(tagName, "tagName");
222        Validate.notEmptyParam(namespace, "namespace");
223        Parser parser = NodeUtils.parser(this);
224        tag = parser.tagSet().valueOf(tagName, namespace, parser.settings()); // maintains the case option of the original parse
225        return this;
226    }
227
228    /**
229     * Get the Tag for this element.
230     *
231     * @return the tag object
232     */
233    public Tag tag() {
234        return tag;
235    }
236
237    /**
238     Change the Tag of this element.
239     @param tag the new tag
240     @return this element, for chaining
241     @since 1.20.1
242     */
243    public Element tag(Tag tag) {
244        Validate.notNull(tag);
245        this.tag = tag;
246        return this;
247    }
248
249    /**
250     * Test if this element is a block-level element. (E.g. {@code <div> == true} or an inline element
251     * {@code <span> == false}).
252     *
253     * @return true if block, false if not (and thus inline)
254     */
255    public boolean isBlock() {
256        return tag.isBlock();
257    }
258
259    /**
260     * Get the {@code id} attribute of this element.
261     *
262     * @return The id attribute, if present, or an empty string if not.
263     */
264    public String id() {
265        return attributes != null ? attributes.getIgnoreCase("id") :"";
266    }
267
268    /**
269     Set the {@code id} attribute of this element.
270     @param id the ID value to use
271     @return this Element, for chaining
272     */
273    public Element id(String id) {
274        Validate.notNull(id);
275        attr("id", id);
276        return this;
277    }
278
279    /**
280     * Set an attribute value on this element. If this element already has an attribute with the
281     * key, its value is updated; otherwise, a new attribute is added.
282     *
283     * @return this element
284     */
285    @Override public Element attr(String attributeKey, String attributeValue) {
286        super.attr(attributeKey, attributeValue);
287        return this;
288    }
289
290    /**
291     * Set a boolean attribute value on this element. Setting to <code>true</code> sets the attribute value to "" and
292     * marks the attribute as boolean so no value is written out. Setting to <code>false</code> removes the attribute
293     * with the same key if it exists.
294     *
295     * @param attributeKey the attribute key
296     * @param attributeValue the attribute value
297     *
298     * @return this element
299     */
300    public Element attr(String attributeKey, boolean attributeValue) {
301        attributes().put(attributeKey, attributeValue);
302        return this;
303    }
304
305    /**
306     Get an Attribute by key. Changes made via {@link Attribute#setKey(String)}, {@link Attribute#setValue(String)} etc
307     will cascade back to this Element.
308     @param key the (case-sensitive) attribute key
309     @return the Attribute for this key, or null if not present.
310     @since 1.17.2
311     */
312    @Nullable public Attribute attribute(String key) {
313        return hasAttributes() ? attributes().attribute(key) : null;
314    }
315
316    /**
317     * Get this element's HTML5 custom data attributes. Each attribute in the element that has a key
318     * starting with "data-" is included the dataset.
319     * <p>
320     * E.g., the element {@code <div data-package="jsoup" data-language="Java" class="group">...} has the dataset
321     * {@code package=jsoup, language=java}.
322     * <p>
323     * This map is a filtered view of the element's attribute map. Changes to one map (add, remove, update) are reflected
324     * in the other map.
325     * <p>
326     * You can find elements that have data attributes using the {@code [^data-]} attribute key prefix selector.
327     * @return a map of {@code key=value} custom data attributes.
328     */
329    public Map<String, String> dataset() {
330        return attributes().dataset();
331    }
332
333    @Override @Nullable
334    public final Element parent() {
335        return (Element) parentNode;
336    }
337
338    /**
339     * Get this element's parent and ancestors, up to the document root.
340     * @return this element's stack of parents, starting with the closest first.
341     */
342    public Elements parents() {
343        Elements parents = new Elements();
344        Element parent = this.parent();
345        while (parent != null && !parent.nameIs("#root")) {
346            parents.add(parent);
347            parent = parent.parent();
348        }
349        return parents;
350    }
351
352    /**
353     * Get a child element of this element, by its 0-based index number.
354     * <p>
355     * Note that an element can have both mixed Nodes and Elements as children. This method inspects
356     * a filtered list of children that are elements, and the index is based on that filtered list.
357     * </p>
358     *
359     * @param index the index number of the element to retrieve
360     * @return the child element, if it exists, otherwise throws an {@code IndexOutOfBoundsException}
361     * @see #childNode(int)
362     */
363    public Element child(int index) {
364        Validate.isTrue(index >= 0, "Index must be >= 0");
365        List<Element> cached = cachedChildren();
366        if (cached != null) return cached.get(index);
367        // otherwise, iter on elementChild; saves creating list
368        int size = childNodes.size();
369        for (int i = 0, e = 0; i < size; i++) { // direct iter is faster than chasing firstElSib, nextElSibd
370            Node node = childNodes.get(i);
371            if (node instanceof Element) {
372                if (e++ == index) return (Element) node;
373            }
374        }
375        throw new IndexOutOfBoundsException("No child at index: " + index);
376    }
377
378    /**
379     * Get the number of child nodes of this element that are elements.
380     * <p>
381     * This method works on the same filtered list like {@link #child(int)}. Use {@link #childNodes()} and {@link
382     * #childNodeSize()} to get the unfiltered Nodes (e.g. includes TextNodes etc.)
383     * </p>
384     *
385     * @return the number of child nodes that are elements
386     * @see #children()
387     * @see #child(int)
388     */
389    public int childrenSize() {
390        if (childNodeSize() == 0) return 0;
391        return childElementsList().size(); // gets children into cache; faster subsequent child(i) if unmodified
392    }
393
394    /**
395     * Get this element's child elements.
396     * <p>
397     * This is effectively a filter on {@link #childNodes()} to get Element nodes.
398     * </p>
399     * @return child elements. If this element has no children, returns an empty list.
400     * @see #childNodes()
401     */
402    public Elements children() {
403        return new Elements(childElementsList());
404    }
405
406    /**
407     * Maintains a shadow copy of this element's child elements. If the nodelist is changed, this cache is invalidated.
408     * @return a list of child elements
409     */
410    List<Element> childElementsList() {
411        if (childNodeSize() == 0) return EmptyChildren; // short circuit creating empty
412        // set atomically, so works in multi-thread. Calling methods look like reads, so should be thread-safe
413        synchronized (childNodes) { // sync vs re-entrant lock, to save another field
414            List<Element> children = cachedChildren();
415            if (children == null) {
416                children = filterNodes(Element.class);
417                stashChildren(children);
418            }
419            return children;
420        }
421    }
422
423    private static final String childElsKey = "jsoup.childEls";
424    private static final String childElsMod = "jsoup.childElsMod";
425
426    /** returns the cached child els, if they exist, and the modcount of our childnodes matches the stashed modcount */
427    @SuppressWarnings("unchecked")
428    @Nullable List<Element> cachedChildren() {
429        if (attributes == null || !attributes.hasUserData()) return null; // don't create empty userdata
430        Map<String, Object> userData = attributes.userData();
431        WeakReference<List<Element>> ref = (WeakReference<List<Element>>) userData.get(childElsKey);
432        if (ref != null) {
433            List<Element> els = ref.get();
434            if (els != null) {
435                Integer modCount = (Integer) userData.get(childElsMod);
436                if (modCount != null && modCount == childNodes.modCount())
437                    return els;
438            }
439        }
440        return null;
441    }
442
443    /** caches the child els into the Attribute user data. */
444    private void stashChildren(List<Element> els) {
445        Map<String, Object> userData = attributes().userData();
446        WeakReference<List<Element>> ref = new WeakReference<>(els);
447        userData.put(childElsKey, ref);
448        userData.put(childElsMod, childNodes.modCount());
449    }
450
451    /**
452     Returns a Stream of this Element and all of its descendant Elements. The stream has document order.
453     @return a stream of this element and its descendants.
454     @see #nodeStream()
455     @since 1.17.1
456     */
457    public Stream<Element> stream() {
458        return NodeUtils.stream(this, Element.class);
459    }
460
461    private <T> List<T> filterNodes(Class<T> clazz) {
462        return childNodes.stream()
463                .filter(clazz::isInstance)
464                .map(clazz::cast)
465                .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
466    }
467
468    /**
469     * Get this element's child text nodes. The list is unmodifiable but the text nodes may be manipulated.
470     * <p>
471     * This is effectively a filter on {@link #childNodes()} to get Text nodes.
472     * @return child text nodes. If this element has no text nodes, returns an
473     * empty list.
474     * </p>
475     * For example, with the input HTML: {@code <p>One <span>Two</span> Three <br> Four</p>} with the {@code p} element selected:
476     * <ul>
477     *     <li>{@code p.text()} = {@code "One Two Three Four"}</li>
478     *     <li>{@code p.ownText()} = {@code "One Three Four"}</li>
479     *     <li>{@code p.children()} = {@code Elements[<span>, <br>]}</li>
480     *     <li>{@code p.childNodes()} = {@code List<Node>["One ", <span>, " Three ", <br>, " Four"]}</li>
481     *     <li>{@code p.textNodes()} = {@code List<TextNode>["One ", " Three ", " Four"]}</li>
482     * </ul>
483     */
484    public List<TextNode> textNodes() {
485        return filterNodes(TextNode.class);
486    }
487
488    /**
489     * Get this element's child data nodes. The list is unmodifiable but the data nodes may be manipulated.
490     * <p>
491     * This is effectively a filter on {@link #childNodes()} to get Data nodes.
492     * </p>
493     * @return child data nodes. If this element has no data nodes, returns an
494     * empty list.
495     * @see #data()
496     */
497    public List<DataNode> dataNodes() {
498        return filterNodes(DataNode.class);
499    }
500
501    /**
502     * Find elements that match the {@link Selector} CSS query, with this element as the starting context. Matched elements
503     * may include this element, or any of its descendents.
504     * <p>If the query starts with a combinator (e.g. {@code >}), that will combine to this element.</p>
505     * <p>This method is generally more powerful to use than the DOM-type {@code getElementBy*} methods, because
506     * multiple filters can be combined, e.g.:</p>
507     * <ul>
508     * <li>{@code el.select("a[href]")} - finds links ({@code a} tags with {@code href} attributes)</li>
509     * <li>{@code el.select("a[href*=example.com]")} - finds links pointing to example.com (loosely)</li>
510     * <li>{@code el.select("* div")} - finds all divs that descend from this element (and excludes this element)</li>
511     * <li>{@code el.select("> div")} - finds all divs that are direct children of this element (and excludes this element)</li>
512     * </ul>
513     * <p>See the query syntax documentation in {@link org.jsoup.select.Selector}.</p>
514     * <p>Also known as {@code querySelectorAll()} in the Web DOM.</p>
515     *
516     * <p>The <a href="{@docRoot}/org/jsoup/select/Selector.html#query-compatibility">Web DOM query preview</a>
517     * excludes this element from query results.</p>
518     *
519     * @param cssQuery a {@link Selector} CSS-like query
520     * @return an {@link Elements} list containing elements that match the query (empty if none match)
521     * @see Selector selector query syntax
522     * @see #select(Evaluator)
523     * @throws Selector.SelectorParseException (unchecked) on an invalid CSS query.
524     */
525    public Elements select(String cssQuery) {
526        return Selector.select(cssQuery, this);
527    }
528
529    /**
530     * Find elements that match the supplied Evaluator. This has the same functionality as {@link #select(String)}, but
531     * may be useful if you are running the same query many times (on many documents) and want to save the overhead of
532     * repeatedly parsing the CSS query.
533     * @param evaluator an element evaluator
534     * @return an {@link Elements} list containing elements that match the query (empty if none match)
535     * @see Selector#evaluatorOf(String css)
536     */
537    public Elements select(Evaluator evaluator) {
538        return Selector.select(evaluator, this);
539    }
540
541    /**
542     Selects elements from the given root that match the specified {@link Selector} CSS query, with this element as the
543     starting context, and returns them as a lazy Stream. Matched elements may include this element, or any of its
544     children.
545     <p>
546     Unlike {@link #select(String query)}, which returns a complete list of all matching elements, this method returns a
547     {@link Stream} that processes elements lazily as they are needed. The stream operates in a "pull" model — elements
548     are fetched from the root as the stream is traversed. You can use standard {@code Stream} operations such as
549     {@code filter}, {@code map}, or {@code findFirst} to process elements on demand.
550     </p>
551
552     @param cssQuery a {@link Selector} CSS-like query
553     @return a {@link Stream} containing elements that match the query (empty if none match)
554     @throws Selector.SelectorParseException (unchecked) on an invalid CSS query.
555     @see Selector selector query syntax
556     @see #selectStream(Evaluator eval)
557     @since 1.19.1
558     */
559    public Stream<Element> selectStream(String cssQuery) {
560        return Selector.selectStream(cssQuery, this);
561    }
562
563    /**
564     Find a Stream of elements that match the supplied Evaluator.
565
566     @param evaluator an element Evaluator
567     @return a {@link Stream} containing elements that match the query (empty if none match)
568     @see Selector#evaluatorOf(String css)
569     @since 1.19.1
570     */
571    public Stream<Element> selectStream(Evaluator evaluator) {
572        return Selector.selectStream(evaluator, this);
573    }
574
575    /**
576     * Find the first Element that matches the {@link Selector} CSS query, with this element as the starting context.
577     * <p>This is effectively the same as calling {@code element.select(query).first()}, but is more efficient as query
578     * execution stops on the first hit.</p>
579     * <p>Also known as {@code querySelector()} in the Web DOM.</p>
580     * <p>The <a href="{@docRoot}/org/jsoup/select/Selector.html#query-compatibility">Web DOM query preview</a>
581     * excludes this element from query results.</p>
582     *
583     * @param cssQuery cssQuery a {@link Selector} CSS-like query
584     * @return the first matching element, or <b>{@code null}</b> if there is no match.
585     * @see #expectFirst(String)
586     */
587    public @Nullable Element selectFirst(String cssQuery) {
588        return Selector.selectFirst(cssQuery, this);
589    }
590
591    /**
592     * Finds the first Element that matches the supplied Evaluator, with this element as the starting context, or
593     * {@code null} if none match.
594     *
595     * @param evaluator an element evaluator
596     * @return the first matching element (walking down the tree, starting from this element), or {@code null} if none
597     * match.
598     */
599    public @Nullable Element selectFirst(Evaluator evaluator) {
600        return Collector.findFirst(evaluator, this);
601    }
602
603    /**
604     Just like {@link #selectFirst(String)}, but if there is no match, throws an {@link IllegalArgumentException}. This
605     is useful if you want to simply abort processing on a failed match.
606     @param cssQuery a {@link Selector} CSS-like query
607     @return the first matching element
608     @throws IllegalArgumentException if no match is found
609     @since 1.15.2
610     */
611    public Element expectFirst(String cssQuery) {
612        return Validate.expectNotNull(
613            Selector.selectFirst(cssQuery, this),
614            parent() != null ?
615                "No elements matched the query '%s' on element '%s'." :
616                "No elements matched the query '%s' in the document."
617            , cssQuery, this.tagName()
618        );
619    }
620
621    /**
622     Find nodes that match the supplied {@link Evaluator}, with this element as the starting context. Matched
623     nodes may include this element, or any of its descendents.
624
625     @param evaluator an evaluator
626     @return a list of nodes that match the query (empty if none match)
627     @since 1.21.1
628     */
629    public Nodes<Node> selectNodes(Evaluator evaluator) {
630        return selectNodes(evaluator, Node.class);
631    }
632
633    /**
634     Find nodes that match the supplied {@link Selector} CSS query, with this element as the starting context. Matched
635     nodes may include this element, or any of its descendents.
636     <p>To select leaf nodes, the query should specify the node type, e.g. {@code ::text},
637     {@code ::comment}, {@code ::data}, {@code ::pi}, {@code ::leafnode}.</p>
638
639     @param cssQuery a {@link Selector} CSS query
640     @return a list of nodes that match the query (empty if none match)
641     @since 1.21.1
642     */
643    public Nodes<Node> selectNodes(String cssQuery) {
644        return selectNodes(cssQuery, Node.class);
645    }
646
647    /**
648     Find nodes that match the supplied Evaluator, with this element as the starting context. Matched
649     nodes may include this element, or any of its descendents.
650
651     @param evaluator an evaluator
652     @param type the type of node to collect (e.g. {@link Element}, {@link LeafNode}, {@link TextNode} etc)
653     @param <T> the type of node to collect
654     @return a list of nodes that match the query (empty if none match)
655     @since 1.21.1
656     */
657    public <T extends Node> Nodes<T> selectNodes(Evaluator evaluator, Class<T> type) {
658        Validate.notNull(evaluator);
659        return Collector.collectNodes(evaluator, this, type);
660    }
661
662    /**
663     Find nodes that match the supplied {@link Selector} CSS query, with this element as the starting context. Matched
664     nodes may include this element, or any of its descendents.
665     <p>To select specific node types, use {@code ::text}, {@code ::comment}, {@code ::pi}, {@code ::leafnode}, etc. For example, to
666     select all text nodes under {@code p} elements: </p>
667     <pre>    Nodes&lt;TextNode&gt; textNodes = doc.selectNodes("p ::text", TextNode.class);</pre>
668
669     @param cssQuery a {@link Selector} CSS query
670     @param type the type of node to collect (e.g. {@link Element}, {@link LeafNode}, {@link TextNode} etc)
671     @param <T> the type of node to collect
672     @return a list of nodes that match the query (empty if none match)
673     @since 1.21.1
674     */
675    public <T extends Node> Nodes<T> selectNodes(String cssQuery, Class<T> type) {
676        Validate.notEmpty(cssQuery);
677        return selectNodes(evaluatorOf(cssQuery), type);
678    }
679
680    /**
681     Find the first Node that matches the {@link Selector} CSS query, with this element as the starting context.
682     <p>This is effectively the same as calling {@code element.selectNodes(query).first()}, but is more efficient as
683     query
684     execution stops on the first hit.</p>
685     <p>Also known as {@code querySelector()} in the Web DOM.</p>
686
687     @param cssQuery cssQuery a {@link Selector} CSS-like query
688     @return the first matching node, or <b>{@code null}</b> if there is no match.
689     @since 1.21.1
690     @see #expectFirst(String)
691     */
692    public @Nullable <T extends Node> T selectFirstNode(String cssQuery, Class<T> type) {
693        return selectFirstNode(evaluatorOf(cssQuery), type);
694    }
695
696    /**
697     Finds the first Node that matches the supplied Evaluator, with this element as the starting context, or
698     {@code null} if none match.
699
700     @param evaluator an element evaluator
701     @return the first matching node (walking down the tree, starting from this element), or {@code null} if none
702     match.
703     @since 1.21.1
704     */
705    public @Nullable <T extends Node> T selectFirstNode(Evaluator evaluator, Class<T> type) {
706        return Collector.findFirstNode(evaluator, this, type);
707    }
708
709    /**
710     Just like {@link #selectFirstNode(String, Class)}, but if there is no match, throws an
711     {@link IllegalArgumentException}. This is useful if you want to simply abort processing on a failed match.
712
713     @param cssQuery a {@link Selector} CSS-like query
714     @return the first matching node
715     @throws IllegalArgumentException if no match is found
716     @since 1.21.1
717     */
718    public <T extends Node> T expectFirstNode(String cssQuery, Class<T> type) {
719        return Validate.expectNotNull(
720            selectFirstNode(cssQuery, type),
721            parent() != null ?
722                "No nodes matched the query '%s' on element '%s'.":
723                "No nodes matched the query '%s' in the document."
724            , cssQuery, this.tagName()
725        );
726    }
727
728    /**
729     * Checks if this element matches the given {@link Selector} CSS query. Also knows as {@code matches()} in the Web
730     * DOM.
731     *
732     * @param cssQuery a {@link Selector} CSS query
733     * @return if this element matches the query
734     */
735    public boolean is(String cssQuery) {
736        return EvaluatorInternals.matches(cssQuery, this);
737    }
738
739    /**
740     * Check if this element matches the given evaluator.
741     * @param evaluator an element evaluator
742     * @return if this element matches
743     */
744    public boolean is(Evaluator evaluator) {
745        return EvaluatorInternals.matches(evaluator, this);
746    }
747
748    /**
749     * Find the closest element up the tree of parents that matches the specified CSS query. Will return itself, an
750     * ancestor, or {@code null} if there is no such matching element.
751     * @param cssQuery a {@link Selector} CSS query
752     * @return the closest ancestor element (possibly itself) that matches the provided evaluator. {@code null} if not
753     * found.
754     */
755    public @Nullable Element closest(String cssQuery) {
756        return EvaluatorInternals.closest(cssQuery, this);
757    }
758
759    /**
760     * Find the closest element up the tree of parents that matches the specified evaluator. Will return itself, an
761     * ancestor, or {@code null} if there is no such matching element.
762     * @param evaluator a query evaluator
763     * @return the closest ancestor element (possibly itself) that matches the provided evaluator. {@code null} if not
764     * found.
765     */
766    public @Nullable Element closest(Evaluator evaluator) {
767        Validate.notNull(evaluator);
768        return EvaluatorInternals.closest(evaluator, this);
769    }
770
771    /**
772     Find Elements that match the supplied {@index XPath} expression.
773     <p>Note that for convenience of writing the Xpath expression, namespaces are disabled, and queries can be
774     expressed using the element's local name only.</p>
775     <p>By default, XPath 1.0 expressions are supported. If you would to use XPath 2.0 or higher, you can provide an
776     alternate XPathFactory implementation:</p>
777     <ol>
778     <li>Add the implementation to your classpath. E.g. to use <a href="https://www.saxonica.com/products/products.xml">Saxon-HE</a>, add <a href="https://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE">net.sf.saxon:Saxon-HE</a> to your build.</li>
779     <li>Set the system property <code>javax.xml.xpath.XPathFactory:jsoup</code> to the implementing classname. E.g.:<br>
780     <code>System.setProperty(W3CDom.XPathFactoryProperty, "net.sf.saxon.xpath.XPathFactoryImpl");</code>
781     </li>
782     </ol>
783
784     @param xpath XPath expression
785     @return matching elements, or an empty list if none match.
786     @see #selectXpath(String, Class)
787     @since 1.14.3
788     */
789    public Elements selectXpath(String xpath) {
790        return new Elements(NodeUtils.selectXpath(xpath, this, Element.class));
791    }
792
793    /**
794     Find Nodes that match the supplied XPath expression.
795     <p>For example, to select TextNodes under {@code p} elements: </p>
796     <pre>List&lt;TextNode&gt; textNodes = doc.selectXpath("//body//p//text()", TextNode.class);</pre>
797     <p>Note that in the jsoup DOM, Attribute objects are not Nodes. To directly select attribute values, do something
798     like:</p>
799     <pre>List&lt;String&gt; hrefs = doc.selectXpath("//a").eachAttr("href");</pre>
800     @param xpath XPath expression
801     @param nodeType the jsoup node type to return
802     @see #selectXpath(String)
803     @return a list of matching nodes
804     @since 1.14.3
805     */
806    public <T extends Node> List<T> selectXpath(String xpath, Class<T> nodeType) {
807        return NodeUtils.selectXpath(xpath, this, nodeType);
808    }
809
810    /**
811     * Insert a node to the end of this Element's children. The incoming node will be re-parented.
812     *
813     * @param child node to add.
814     * @return this Element, for chaining
815     * @see #prependChild(Node)
816     * @see #insertChildren(int, Collection)
817     */
818    public Element appendChild(Node child) {
819        Validate.notNull(child);
820
821        // was - Node#addChildren(child). short-circuits an array create and a loop.
822        reparentChild(child);
823        ensureChildNodes();
824        childNodes.add(child);
825        child.setSiblingIndex(childNodes.size() - 1);
826        return this;
827    }
828
829    /**
830     Insert the given nodes to the end of this Element's children.
831
832     @param children nodes to add
833     @return this Element, for chaining
834     @see #insertChildren(int, Collection)
835     */
836    public Element appendChildren(Collection<? extends Node> children) {
837        insertChildren(-1, children);
838        return this;
839    }
840
841    /**
842     * Add this element to the supplied parent element, as its next child.
843     *
844     * @param parent element to which this element will be appended
845     * @return this element, so that you can continue modifying the element
846     */
847    public Element appendTo(Element parent) {
848        Validate.notNull(parent);
849        parent.appendChild(this);
850        return this;
851    }
852
853    /**
854     * Add a node to the start of this element's children.
855     *
856     * @param child node to add.
857     * @return this element, so that you can add more child nodes or elements.
858     */
859    public Element prependChild(Node child) {
860        Validate.notNull(child);
861
862        addChildren(0, child);
863        return this;
864    }
865
866    /**
867     Insert the given nodes to the start of this Element's children.
868
869     @param children nodes to add
870     @return this Element, for chaining
871     @see #insertChildren(int, Collection)
872     */
873    public Element prependChildren(Collection<? extends Node> children) {
874        insertChildren(0, children);
875        return this;
876    }
877
878
879    /**
880     * Inserts the given child nodes into this element at the specified index. Current nodes will be shifted to the
881     * right. The inserted nodes will be moved from their current parent. To prevent moving, copy the nodes first.
882     *
883     * @param index 0-based index to insert children at. Specify {@code 0} to insert at the start, {@code -1} at the
884     * end
885     * @param children child nodes to insert
886     * @return this element, for chaining.
887     */
888    public Element insertChildren(int index, Collection<? extends Node> children) {
889        Validate.notNull(children, "Children collection to be inserted must not be null.");
890        int currentSize = childNodeSize();
891        if (index < 0) index += currentSize +1; // roll around
892        Validate.isTrue(index >= 0 && index <= currentSize, "Insert position out of bounds.");
893        addChildren(index, children.toArray(new Node[0]));
894        return this;
895    }
896
897    /**
898     * Inserts the given child nodes into this element at the specified index. Current nodes will be shifted to the
899     * right. The inserted nodes will be moved from their current parent. To prevent moving, copy the nodes first.
900     *
901     * @param index 0-based index to insert children at. Specify {@code 0} to insert at the start, {@code -1} at the
902     * end
903     * @param children child nodes to insert
904     * @return this element, for chaining.
905     */
906    public Element insertChildren(int index, Node... children) {
907        Validate.notNull(children, "Children collection to be inserted must not be null.");
908        int currentSize = childNodeSize();
909        if (index < 0) index += currentSize +1; // roll around
910        Validate.isTrue(index >= 0 && index <= currentSize, "Insert position out of bounds.");
911
912        addChildren(index, children);
913        return this;
914    }
915
916    /**
917     * Create a new element by tag name, and add it as this Element's last child.
918     *
919     * @param tagName the name of the tag (e.g. {@code div}).
920     * @return the new element, to allow you to add content to it, e.g.:
921     *  {@code parent.appendElement("h1").attr("id", "header").text("Welcome");}
922     */
923    public Element appendElement(String tagName) {
924        return appendElement(tagName, tag.namespace());
925    }
926
927    /**
928     * Create a new element by tag name and namespace, add it as this Element's last child.
929     *
930     * @param tagName the name of the tag (e.g. {@code div}).
931     * @param namespace the namespace of the tag (e.g. {@link Parser#NamespaceHtml})
932     * @return the new element, in the specified namespace
933     */
934    public Element appendElement(String tagName, String namespace) {
935        Parser parser = NodeUtils.parser(this);
936        Element child = new Element(parser.tagSet().valueOf(tagName, namespace, parser.settings()), baseUri());
937        appendChild(child);
938        return child;
939    }
940
941    /**
942     * Create a new element by tag name, and add it as this Element's first child.
943     *
944     * @param tagName the name of the tag (e.g. {@code div}).
945     * @return the new element, to allow you to add content to it, e.g.:
946     *  {@code parent.prependElement("h1").attr("id", "header").text("Welcome");}
947     */
948    public Element prependElement(String tagName) {
949        return prependElement(tagName, tag.namespace());
950    }
951
952    /**
953     * Create a new element by tag name and namespace, and add it as this Element's first child.
954     *
955     * @param tagName the name of the tag (e.g. {@code div}).
956     * @param namespace the namespace of the tag (e.g. {@link Parser#NamespaceHtml})
957     * @return the new element, in the specified namespace
958     */
959    public Element prependElement(String tagName, String namespace) {
960        Parser parser = NodeUtils.parser(this);
961        Element child = new Element(parser.tagSet().valueOf(tagName, namespace, parser.settings()), baseUri());
962        prependChild(child);
963        return child;
964    }
965
966    /**
967     * Create and append a new TextNode to this element.
968     *
969     * @param text the (un-encoded) text to add
970     * @return this element
971     */
972    public Element appendText(String text) {
973        Validate.notNull(text);
974        TextNode node = new TextNode(text);
975        appendChild(node);
976        return this;
977    }
978
979    /**
980     * Create and prepend a new TextNode to this element.
981     *
982     * @param text the decoded text to add
983     * @return this element
984     */
985    public Element prependText(String text) {
986        Validate.notNull(text);
987        TextNode node = new TextNode(text);
988        prependChild(node);
989        return this;
990    }
991
992    /**
993     * Add inner HTML to this element. The supplied HTML will be parsed, and each node appended to the end of the children.
994     * @param html HTML to add inside this element, after the existing HTML
995     * @return this element
996     * @see #html(String)
997     */
998    public Element append(String html) {
999        Validate.notNull(html);
1000        List<Node> nodes = NodeUtils.parser(this).parseFragmentInput(html, this, baseUri());
1001        addChildren(nodes.toArray(new Node[0]));
1002        return this;
1003    }
1004
1005    /**
1006     * Add inner HTML into this element. The supplied HTML will be parsed, and each node prepended to the start of the element's children.
1007     * @param html HTML to add inside this element, before the existing HTML
1008     * @return this element
1009     * @see #html(String)
1010     */
1011    public Element prepend(String html) {
1012        Validate.notNull(html);
1013        List<Node> nodes = NodeUtils.parser(this).parseFragmentInput(html, this, baseUri());
1014        addChildren(0, nodes.toArray(new Node[0]));
1015        return this;
1016    }
1017
1018    /**
1019     * Insert the specified HTML into the DOM before this element (as a preceding sibling).
1020     *
1021     * @param html HTML to add before this element
1022     * @return this element, for chaining
1023     * @see #after(String)
1024     */
1025    @Override
1026    public Element before(String html) {
1027        return (Element) super.before(html);
1028    }
1029
1030    /**
1031     * Insert the specified node into the DOM before this node (as a preceding sibling).
1032     * @param node to add before this element
1033     * @return this Element, for chaining
1034     * @see #after(Node)
1035     */
1036    @Override
1037    public Element before(Node node) {
1038        return (Element) super.before(node);
1039    }
1040
1041    /**
1042     * Insert the specified HTML into the DOM after this element (as a following sibling).
1043     *
1044     * @param html HTML to add after this element
1045     * @return this element, for chaining
1046     * @see #before(String)
1047     */
1048    @Override
1049    public Element after(String html) {
1050        return (Element) super.after(html);
1051    }
1052
1053    /**
1054     * Insert the specified node into the DOM after this node (as a following sibling).
1055     * @param node to add after this element
1056     * @return this element, for chaining
1057     * @see #before(Node)
1058     */
1059    @Override
1060    public Element after(Node node) {
1061        return (Element) super.after(node);
1062    }
1063
1064    /**
1065     * Remove all the element's child nodes. Any attributes are left as-is. Each child node has its parent set to
1066     * {@code null}.
1067     * @return this element
1068     */
1069    @Override
1070    public Element empty() {
1071        if (childNodes.isEmpty()) return this;
1072        // Detach each of the children -> parent links:
1073        int size = childNodes.size();
1074        for (int i = 0; i < size; i++)
1075            childNodes.get(i).parentNode = null;
1076        childNodes.clear();
1077        return this;
1078    }
1079
1080    /**
1081     * Wrap the supplied HTML around this element.
1082     *
1083     * @param html HTML to wrap around this element, e.g. {@code <div class="head"></div>}. Can be arbitrarily deep.
1084     * @return this element, for chaining.
1085     */
1086    @Override
1087    public Element wrap(String html) {
1088        return (Element) super.wrap(html);
1089    }
1090
1091    /**
1092     Gets an #id selector for this element, if it has a unique ID. Otherwise, returns an empty string.
1093
1094     @param ownerDoc the document that owns this element, if there is one
1095     */
1096    private String uniqueIdSelector(@Nullable Document ownerDoc) {
1097        String id = id();
1098        if (!id.isEmpty()) { // check if the ID is unique and matches this
1099            String idSel = "#" + escapeCssIdentifier(id);
1100            if (ownerDoc != null) {
1101                Elements els = ownerDoc.select(idSel);
1102                if (els.size() == 1 && els.get(0) == this) return idSel;
1103            } else {
1104                return idSel;
1105            }
1106        }
1107        return EmptyString;
1108    }
1109
1110    /**
1111     Get a CSS selector that will uniquely select this element.
1112     <p>
1113     If the element has an ID, returns #id; otherwise returns the parent (if any) CSS selector, followed by
1114     {@literal '>'}, followed by a unique selector for the element (tag.class.class:nth-child(n)).
1115     </p>
1116
1117     @return the CSS Path that can be used to retrieve the element in a selector.
1118     */
1119    public String cssSelector() {
1120        Document ownerDoc = ownerDocument();
1121        String idSel = uniqueIdSelector(ownerDoc);
1122        if (!idSel.isEmpty()) return idSel;
1123
1124        // No unique ID, work up the parent stack and find either a unique ID to hang from, or just a GP > Parent > Child chain
1125        StringBuilder selector = StringUtil.borrowBuilder();
1126        Element el = this;
1127        while (el != null && !(el instanceof Document)) {
1128            idSel = el.uniqueIdSelector(ownerDoc);
1129            if (!idSel.isEmpty()) {
1130                selector.insert(0, idSel);
1131                break; // found a unique ID to use as ancestor; stop
1132            }
1133            selector.insert(0, el.cssSelectorComponent());
1134            el = el.parent();
1135        }
1136        return StringUtil.releaseBuilder(selector);
1137    }
1138
1139    private String cssSelectorComponent() {
1140        // Escape tagname, and translate HTML namespace ns:tag to CSS namespace syntax ns|tag
1141        String tagName = escapeCssIdentifier(tagName()).replace("\\:", "|");
1142        StringBuilder selector = StringUtil.borrowBuilder().append(tagName);
1143        String classes = classNames().stream().map(TokenQueue::escapeCssIdentifier)
1144                .collect(StringUtil.joining("."));
1145        if (!classes.isEmpty())
1146            selector.append('.').append(classes);
1147
1148        if (parent() == null || parent() instanceof Document) // don't add Document to selector, as will always have a html node
1149            return StringUtil.releaseBuilder(selector);
1150
1151        selector.insert(0, " > ");
1152        if (parent().select(selector.toString()).size() > 1)
1153            selector.append(String.format(
1154                ":nth-child(%d)", elementSiblingIndex() + 1));
1155
1156        return StringUtil.releaseBuilder(selector);
1157    }
1158
1159    /**
1160     * Get sibling elements. If the element has no sibling elements, returns an empty list. An element is not a sibling
1161     * of itself, so will not be included in the returned list.
1162     * @return sibling elements
1163     */
1164    public Elements siblingElements() {
1165        if (parentNode == null)
1166            return new Elements(0);
1167
1168        List<Element> elements = parent().childElementsList();
1169        Elements siblings = new Elements(elements.size() - 1);
1170        for (Element el: elements)
1171            if (el != this)
1172                siblings.add(el);
1173        return siblings;
1174    }
1175
1176
1177
1178    /**
1179     * Get each of the sibling elements that come after this element.
1180     *
1181     * @return each of the element siblings after this element, or an empty list if there are no next sibling elements
1182     */
1183    public Elements nextElementSiblings() {
1184        return nextElementSiblings(true);
1185    }
1186
1187    /**
1188     * Get each of the element siblings before this element.
1189     *
1190     * @return the previous element siblings, or an empty list if there are none.
1191     */
1192    public Elements previousElementSiblings() {
1193        return nextElementSiblings(false);
1194    }
1195
1196    private Elements nextElementSiblings(boolean next) {
1197        Elements els = new Elements();
1198        if (parentNode == null)
1199            return  els;
1200        els.add(this);
1201        return next ?  els.nextAll() : els.prevAll();
1202    }
1203
1204    /**
1205     * Gets the first Element sibling of this element. That may be this element.
1206     * @return the first sibling that is an element (aka the parent's first element child)
1207     */
1208    public Element firstElementSibling() {
1209        if (parent() != null) {
1210            //noinspection DataFlowIssue (not nullable, would be this is no other sibs)
1211            return parent().firstElementChild();
1212        } else
1213            return this; // orphan is its own first sibling
1214    }
1215
1216    /**
1217     * Get the list index of this element in its element sibling list. I.e. if this is the first element
1218     * sibling, returns 0.
1219     * @return position in element sibling list
1220     */
1221    public int elementSiblingIndex() {
1222       if (parent() == null) return 0;
1223       return indexInList(this, parent().childElementsList());
1224    }
1225
1226    /**
1227     * Gets the last element sibling of this element. That may be this element.
1228     * @return the last sibling that is an element (aka the parent's last element child)
1229     */
1230    public Element lastElementSibling() {
1231        if (parent() != null) {
1232            //noinspection DataFlowIssue (not nullable, would be this if no other sibs)
1233            return parent().lastElementChild();
1234        } else
1235            return this;
1236    }
1237
1238    private static <E extends Element> int indexInList(Element search, List<E> elements) {
1239        final int size = elements.size();
1240        for (int i = 0; i < size; i++) {
1241            if (elements.get(i) == search)
1242                return i;
1243        }
1244        return 0;
1245    }
1246
1247    /**
1248     Gets the first child of this Element that is an Element, or {@code null} if there is none.
1249     @return the first Element child node, or null.
1250     @see #firstChild()
1251     @see #lastElementChild()
1252     @since 1.15.2
1253     */
1254    public @Nullable Element firstElementChild() {
1255        int size = childNodes.size();
1256        for (int i = 0; i < size; i++) {
1257            Node node = childNodes.get(i);
1258            if (node instanceof Element) return (Element) node;
1259        }
1260        return null;
1261    }
1262
1263    /**
1264     Gets the last child of this Element that is an Element, or @{code null} if there is none.
1265     @return the last Element child node, or null.
1266     @see #lastChild()
1267     @see #firstElementChild()
1268     @since 1.15.2
1269     */
1270    public @Nullable Element lastElementChild() {
1271        for (int i = childNodes.size() - 1; i >= 0; i--) {
1272            Node node = childNodes.get(i);
1273            if (node instanceof Element) return (Element) node;
1274        }
1275        return null;
1276    }
1277
1278    // DOM type methods
1279
1280    /**
1281     * Finds elements, including and recursively under this element, with the specified tag name.
1282     * @param tagName The tag name to search for (case-insensitive; surrounding whitespace is trimmed).
1283     * @return a matching list of elements. Will be empty if this element and none of its children match.
1284     */
1285    public Elements getElementsByTag(String tagName) {
1286        Validate.notEmpty(tagName);
1287        tagName = StringUtil.trimAsciiWhitespace(tagName);
1288
1289        return Collector.collect(new Evaluator.Tag(tagName), this);
1290    }
1291
1292    /**
1293     * Find an element by ID, including or under this element.
1294     * <p>
1295     * Note that this finds the first matching ID, starting with this element. If you search down from a different
1296     * starting point, it is possible to find a different element by ID. For unique element by ID within a Document,
1297     * use {@link Document#getElementById(String)}
1298     * @param id The ID to search for.
1299     * @return The first matching element by ID, starting with this element, or null if none found.
1300     */
1301    public @Nullable Element getElementById(String id) {
1302        Validate.notEmpty(id);
1303        return Collector.findFirst(EvaluatorInternals.byId(id), this);
1304    }
1305
1306    /**
1307     * Find elements that have this class, including or under this element. Case-insensitive.
1308     * <p>
1309     * Elements can have multiple classes (e.g. {@code <div class="header round first">}). This method
1310     * checks each class, so you can find the above with {@code el.getElementsByClass("header");}.
1311     *
1312     * @param className the name of the class to search for.
1313     * @return elements with the supplied class name, empty if none
1314     * @see #hasClass(String)
1315     * @see #classNames()
1316     */
1317    public Elements getElementsByClass(String className) {
1318        Validate.notEmpty(className);
1319
1320        return Collector.collect(new Evaluator.Class(className), this);
1321    }
1322
1323    /**
1324     * Find elements that have a named attribute set. Case-insensitive.
1325     *
1326     * @param key name of the attribute, e.g. {@code href}
1327     * @return elements that have this attribute, empty if none
1328     */
1329    public Elements getElementsByAttribute(String key) {
1330        Validate.notEmpty(key);
1331        key = key.trim();
1332
1333        return Collector.collect(new Evaluator.Attribute(key), this);
1334    }
1335
1336    /**
1337     * Find elements that have an attribute name starting with the supplied prefix. Use {@code data-} to find elements
1338     * that have HTML5 datasets.
1339     * @param keyPrefix name prefix of the attribute e.g. {@code data-}
1340     * @return elements that have attribute names that start with the prefix, empty if none.
1341     */
1342    public Elements getElementsByAttributeStarting(String keyPrefix) {
1343        Validate.notEmpty(keyPrefix);
1344        keyPrefix = keyPrefix.trim();
1345
1346        return Collector.collect(new Evaluator.AttributeStarting(keyPrefix), this);
1347    }
1348
1349    /**
1350     * Find elements that have an attribute with the specific value. Case-insensitive.
1351     *
1352     * @param key name of the attribute
1353     * @param value value of the attribute
1354     * @return elements that have this attribute with this value, empty if none
1355     */
1356    public Elements getElementsByAttributeValue(String key, String value) {
1357        return Collector.collect(new Evaluator.AttributeWithValue(key, value), this);
1358    }
1359
1360    /**
1361     * Find elements that either do not have this attribute, or have it with a different value. Case-insensitive.
1362     *
1363     * @param key name of the attribute
1364     * @param value value of the attribute
1365     * @return elements that do not have a matching attribute
1366     */
1367    public Elements getElementsByAttributeValueNot(String key, String value) {
1368        return Collector.collect(new Evaluator.AttributeWithValueNot(key, value), this);
1369    }
1370
1371    /**
1372     * Find elements that have attributes that start with the value prefix. Case-insensitive.
1373     *
1374     * @param key name of the attribute
1375     * @param valuePrefix start of attribute value
1376     * @return elements that have attributes that start with the value prefix
1377     */
1378    public Elements getElementsByAttributeValueStarting(String key, String valuePrefix) {
1379        return Collector.collect(new Evaluator.AttributeWithValueStarting(key, valuePrefix), this);
1380    }
1381
1382    /**
1383     * Find elements that have attributes that end with the value suffix. Case-insensitive.
1384     *
1385     * @param key name of the attribute
1386     * @param valueSuffix end of the attribute value
1387     * @return elements that have attributes that end with the value suffix
1388     */
1389    public Elements getElementsByAttributeValueEnding(String key, String valueSuffix) {
1390        return Collector.collect(new Evaluator.AttributeWithValueEnding(key, valueSuffix), this);
1391    }
1392
1393    /**
1394     * Find elements that have attributes whose value contains the match string. Case-insensitive.
1395     *
1396     * @param key name of the attribute
1397     * @param match substring of value to search for
1398     * @return elements that have attributes containing this text
1399     */
1400    public Elements getElementsByAttributeValueContaining(String key, String match) {
1401        return Collector.collect(new Evaluator.AttributeWithValueContaining(key, match), this);
1402    }
1403
1404    /**
1405     * Find elements that have an attribute whose value matches the supplied regular expression.
1406     * @param key name of the attribute
1407     * @param pattern compiled regular expression to match against attribute values
1408     * @return elements that have attributes matching this regular expression
1409     */
1410    public Elements getElementsByAttributeValueMatching(String key, Pattern pattern) {
1411        return Collector.collect(new Evaluator.AttributeWithValueMatching(key, pattern), this);
1412    }
1413
1414    /**
1415     * Find elements that have attributes whose values match the supplied regular expression.
1416     * @param key name of the attribute
1417     * @param regex regular expression to match against attribute values. You can use <a href="http://java.sun.com/docs/books/tutorial/essential/regex/pattern.html#embedded">embedded flags</a> (such as {@code (?i)} and {@code (?m)}) to control regex options.
1418     * @return elements that have attributes matching this regular expression
1419     */
1420    public Elements getElementsByAttributeValueMatching(String key, String regex) {
1421        Regex pattern;
1422        try {
1423            pattern = Regex.compile(regex);
1424        } catch (PatternSyntaxException e) {
1425            throw new IllegalArgumentException("Pattern syntax error: " + regex, e);
1426        }
1427        return Collector.collect(new Evaluator.AttributeWithValueMatching(key, pattern), this);
1428    }
1429
1430    /**
1431     * Find elements whose sibling index is less than the supplied index.
1432     * @param index 0-based index
1433     * @return elements less than index
1434     */
1435    public Elements getElementsByIndexLessThan(int index) {
1436        return Collector.collect(new Evaluator.IndexLessThan(index), this);
1437    }
1438
1439    /**
1440     * Find elements whose sibling index is greater than the supplied index.
1441     * @param index 0-based index
1442     * @return elements greater than index
1443     */
1444    public Elements getElementsByIndexGreaterThan(int index) {
1445        return Collector.collect(new Evaluator.IndexGreaterThan(index), this);
1446    }
1447
1448    /**
1449     * Find elements whose sibling index is equal to the supplied index.
1450     * @param index 0-based index
1451     * @return elements equal to index
1452     */
1453    public Elements getElementsByIndexEquals(int index) {
1454        return Collector.collect(new Evaluator.IndexEquals(index), this);
1455    }
1456
1457    /**
1458     * Find elements that contain the specified string. The search is case-insensitive. The text may appear directly
1459     * in the element, or in any of its descendants.
1460     * @param searchText to look for in the element's text
1461     * @return elements that contain the string, case-insensitive.
1462     * @see Element#text()
1463     */
1464    public Elements getElementsContainingText(String searchText) {
1465        return Collector.collect(new Evaluator.ContainsText(searchText), this);
1466    }
1467
1468    /**
1469     * Find elements that directly contain the specified string. The search is case-insensitive. The text must appear directly
1470     * in the element, not in any of its descendants.
1471     * @param searchText to look for in the element's own text
1472     * @return elements that contain the string, case-insensitive.
1473     * @see Element#ownText()
1474     */
1475    public Elements getElementsContainingOwnText(String searchText) {
1476        return Collector.collect(new Evaluator.ContainsOwnText(searchText), this);
1477    }
1478
1479    /**
1480     * Find elements whose text matches the supplied regular expression.
1481     * @param pattern regular expression to match text against
1482     * @return elements matching the supplied regular expression.
1483     * @see Element#text()
1484     */
1485    public Elements getElementsMatchingText(Pattern pattern) {
1486        return Collector.collect(new Evaluator.Matches(pattern), this);
1487    }
1488
1489    /**
1490     * Find elements whose text matches the supplied regular expression.
1491     * @param regex regular expression to match text against. You can use <a href="http://java.sun.com/docs/books/tutorial/essential/regex/pattern.html#embedded">embedded flags</a> (such as {@code (?i)} and {@code (?m)}) to control regex options.
1492     * @return elements matching the supplied regular expression.
1493     * @see Element#text()
1494     */
1495    public Elements getElementsMatchingText(String regex) {
1496        Regex pattern;
1497        try {
1498            pattern = Regex.compile(regex);
1499        } catch (PatternSyntaxException e) {
1500            throw new IllegalArgumentException("Pattern syntax error: " + regex, e);
1501        }
1502        return Collector.collect(new Evaluator.Matches(pattern), this);
1503    }
1504
1505    /**
1506     * Find elements whose own text matches the supplied regular expression.
1507     * @param pattern regular expression to match text against
1508     * @return elements matching the supplied regular expression.
1509     * @see Element#ownText()
1510     */
1511    public Elements getElementsMatchingOwnText(Pattern pattern) {
1512        return Collector.collect(new Evaluator.MatchesOwn(pattern), this);
1513    }
1514
1515    /**
1516     * Find elements whose own text matches the supplied regular expression.
1517     * @param regex regular expression to match text against. You can use <a href="http://java.sun.com/docs/books/tutorial/essential/regex/pattern.html#embedded">embedded flags</a> (such as {@code (?i)} and {@code (?m)}) to control regex options.
1518     * @return elements matching the supplied regular expression.
1519     * @see Element#ownText()
1520     */
1521    public Elements getElementsMatchingOwnText(String regex) {
1522        Regex pattern;
1523        try {
1524            pattern = Regex.compile(regex);
1525        } catch (PatternSyntaxException e) {
1526            throw new IllegalArgumentException("Pattern syntax error: " + regex, e);
1527        }
1528        return Collector.collect(new Evaluator.MatchesOwn(pattern), this);
1529    }
1530
1531    /**
1532     * Find all elements under this element (including self, and children of children).
1533     *
1534     * @return all elements
1535     */
1536    public Elements getAllElements() {
1537        return Collector.collect(new Evaluator.AllElements(), this);
1538    }
1539
1540    /**
1541     Gets the <b>normalized, combined text</b> of this element and all its children. Whitespace is normalized and
1542     trimmed.
1543     <p>For example, given HTML {@code <p>Hello  <b>there</b> now! </p>}, {@code p.text()} returns {@code "Hello there
1544    now!"}
1545     <p>If you do not want normalized text, use {@link #wholeText()}. If you want just the text of this node (and not
1546     children), use {@link #ownText()}.
1547     <p>This method returns normalized, readable plain text for downstream uses such as data extraction,
1548     indexing, and accessibility-oriented processing. The contents of data nodes (such as
1549     {@code <script>} tags) are not considered text. Use {@link #data()} or {@link #html()} to retrieve
1550     that content.
1551
1552     @return decoded, normalized text, or empty string if none.
1553     @see #wholeText()
1554     @see #ownText()
1555     @see #textNodes()
1556     */
1557    public String text() {
1558        final StringBuilder accum = StringUtil.borrowBuilder();
1559        new TextAccumulator(accum).traverse(this);
1560        return StringUtil.releaseBuilder(accum).trim();
1561    }
1562
1563    private static class TextAccumulator implements NodeVisitor {
1564        private final StringBuilder accum;
1565
1566        public TextAccumulator(StringBuilder accum) {
1567            this.accum = accum;
1568        }
1569
1570        @Override public void head(Node node, int depth) {
1571            if (node instanceof TextNode) {
1572                TextNode textNode = (TextNode) node;
1573                appendNormalisedText(accum, textNode);
1574            } else if (node instanceof Element) {
1575                Element element = (Element) node;
1576                // add a synthetic space before leading blocks and readable boundaries when text would otherwise run together
1577                if (accum.length() > 0 && needsLeadingTextSeparator(element) && !lastCharIsWhitespace(accum))
1578                    accum.append(' ');
1579            }
1580        }
1581
1582        @Override public void tail(Node node, int depth) {
1583            // make sure there is a space between block or readable-boundary tags and immediately following text nodes or inline elements.
1584            if (node instanceof Element) {
1585                Element element = (Element) node;
1586                Node next = node.nextSibling();
1587                if (needsTrailingTextSeparator(element) &&
1588                    (next instanceof TextNode || next instanceof Element && ((Element) next).tag.isInline()) &&
1589                    !lastCharIsWhitespace(accum))
1590                    accum.append(' ');
1591            }
1592
1593        }
1594
1595        /** check if an element should separate preceding text during text() */
1596        private static boolean needsLeadingTextSeparator(Element element) {
1597            return element.isBlock()
1598                || element.nameIs("br")
1599                || element.tag.is(Tag.TextBoundary) && element.childNodeSize() > 0 && element.hasText();
1600        }
1601
1602        /** check if an element should separate following text during text() */
1603        private static boolean needsTrailingTextSeparator(Element element) {
1604            return element.tag.is(Tag.TextBoundary)
1605                || !element.tag.isInline()
1606                || hasBlockChild(element);
1607        }
1608
1609        /** check if an inline wrapper contains direct block children and should close with a separator */
1610        private static boolean hasBlockChild(Element element) {
1611            for (int i = 0; i < element.childNodeSize(); i++) {
1612                Node child = element.childNode(i);
1613                if (child instanceof Element && ((Element) child).isBlock())
1614                    return true;
1615            }
1616            return false;
1617        }
1618    }
1619
1620    /**
1621     Get the decoded text of this element and its children, preserving source whitespace and newlines from text nodes.
1622     Unlike {@link #text()}, no separators are inferred around element boundaries; {@code <br>} elements are returned
1623     as newlines.
1624     @return decoded, non-normalized text
1625     @see #text()
1626     @see #wholeOwnText()
1627     */
1628    public String wholeText() {
1629        return wholeTextOf(nodeStream());
1630    }
1631
1632    /**
1633     An Element's nodeValue is its whole own text.
1634     */
1635    @Override
1636    public String nodeValue() {
1637        return wholeOwnText();
1638    }
1639
1640    private static String wholeTextOf(Stream<Node> stream) {
1641        return stream.map(node -> {
1642            if (node instanceof TextNode) return ((TextNode) node).getWholeText();
1643            if (node.nameIs("br")) return "\n";
1644            return "";
1645        }).collect(StringUtil.joining(""));
1646    }
1647
1648    /**
1649     Get the non-normalized, decoded text of this element, <b>not including</b> any child elements, including any
1650     newlines and spaces present in the original source.
1651     @return decoded, non-normalized text that is a direct child of this Element
1652     @see #text()
1653     @see #wholeText()
1654     @see #ownText()
1655     @since 1.15.1
1656     */
1657    public String wholeOwnText() {
1658        return wholeTextOf(childNodes.stream());
1659    }
1660
1661    /**
1662     * Gets the (normalized) text owned by this element only; does not get the combined text of all children.
1663     * <p>
1664     * For example, given HTML {@code <p>Hello <b>there</b> now!</p>}, {@code p.ownText()} returns {@code "Hello now!"},
1665     * whereas {@code p.text()} returns {@code "Hello there now!"}.
1666     * Note that the text within the {@code b} element is not returned, as it is not a direct child of the {@code p} element.
1667     *
1668     * @return decoded text, or empty string if none.
1669     * @see #text()
1670     * @see #textNodes()
1671     */
1672    public String ownText() {
1673        StringBuilder sb = StringUtil.borrowBuilder();
1674        ownText(sb);
1675        return StringUtil.releaseBuilder(sb).trim();
1676    }
1677
1678    private void ownText(StringBuilder accum) {
1679        for (int i = 0; i < childNodeSize(); i++) {
1680            Node child = childNodes.get(i);
1681            if (child instanceof TextNode) {
1682                TextNode textNode = (TextNode) child;
1683                appendNormalisedText(accum, textNode);
1684            } else if (child.nameIs("br") && !lastCharIsWhitespace(accum)) {
1685                accum.append(" ");
1686            }
1687        }
1688    }
1689
1690    private static void appendNormalisedText(StringBuilder accum, TextNode textNode) {
1691        String text = textNode.getWholeText();
1692        if (preserveWhitespace(textNode.parentNode) || textNode instanceof CDataNode)
1693            accum.append(text);
1694        else
1695            StringUtil.appendNormalisedWhitespace(accum, text, lastCharIsWhitespace(accum));
1696    }
1697
1698    static boolean preserveWhitespace(@Nullable Node node) {
1699        // looks only at this element and five levels up, to prevent recursion & needless stack searches
1700        if (node instanceof Element) {
1701            Element el = (Element) node;
1702            int i = 0;
1703            do {
1704                if (el.tag.preserveWhitespace())
1705                    return true;
1706                el = el.parent();
1707                i++;
1708            } while (i < 6 && el != null);
1709        }
1710        return false;
1711    }
1712
1713    /**
1714     * Set the text of this element. Any existing contents (text or elements) will be cleared.
1715     * <p>As a special case, for {@code <script>} and {@code <style>} tags, the input text will be treated as data,
1716     * not visible text.</p>
1717     * @param text decoded text
1718     * @return this element
1719     */
1720    public Element text(String text) {
1721        Validate.notNull(text);
1722        empty();
1723        // special case for script/style in HTML (or customs): should be data node
1724        if (tag().is(Tag.Data))
1725            appendChild(new DataNode(text));
1726        else
1727            appendChild(new TextNode(text));
1728
1729        return this;
1730    }
1731
1732    /**
1733     Checks if the current element or any of its child elements contain non-whitespace text.
1734     @return {@code true} if the element has non-blank text content, {@code false} otherwise.
1735     */
1736    public boolean hasText() {
1737        AtomicBoolean hasText = new AtomicBoolean(false);
1738        filter((node, depth) -> {
1739            if (node instanceof TextNode) {
1740                TextNode textNode = (TextNode) node;
1741                if (!textNode.isBlank()) {
1742                    hasText.set(true);
1743                    return NodeFilter.FilterResult.STOP;
1744                }
1745            }
1746            return NodeFilter.FilterResult.CONTINUE;
1747        });
1748        return hasText.get();
1749    }
1750
1751    /**
1752     Get the combined data of this element. Data is e.g. the inside of a {@code <script>} tag. Note that data is NOT the
1753     plain text of the element. Use {@link #text()} to get normalized, readable text for extraction, indexing, or
1754     accessibility-oriented processing, and {@code data()} for the contents of scripts, comments, CSS styles, etc.
1755
1756     @return the data, or empty string if none
1757     @see #dataNodes()
1758     */
1759    public String data() {
1760        StringBuilder sb = StringUtil.borrowBuilder();
1761        traverse((childNode, depth) -> {
1762            if (childNode instanceof DataNode) {
1763                DataNode data = (DataNode) childNode;
1764                sb.append(data.getWholeData());
1765            } else if (childNode instanceof Comment) {
1766                Comment comment = (Comment) childNode;
1767                sb.append(comment.getData());
1768            } else if (childNode instanceof CDataNode) {
1769                // this shouldn't really happen because the html parser won't see the cdata as anything special when parsing script.
1770                // but in case another type gets through.
1771                CDataNode cDataNode = (CDataNode) childNode;
1772                sb.append(cDataNode.getWholeText());
1773            }
1774        });
1775        return StringUtil.releaseBuilder(sb);
1776    }
1777
1778    /**
1779     * Gets the literal value of this element's "class" attribute, which may include multiple class names, space
1780     * separated. (E.g. on <code>&lt;div class="header gray"&gt;</code> returns, "<code>header gray</code>")
1781     * @return The literal class attribute, or <b>empty string</b> if no class attribute set.
1782     */
1783    public String className() {
1784        return attr("class").trim();
1785    }
1786
1787    /**
1788     Get each of the element's class names. E.g. on element {@code <div class="header gray">},
1789     returns a set of two elements {@code "header", "gray"}.
1790     <p>Note that modifications to this set are not pushed to the backing {@code class} attribute; use
1791     {@link #classNames(Set)} to persist them.</p>
1792     <p>Use {@link #classList()} for a more efficient, read-only list that preserves duplicate class names.</p>
1793
1794     @return set of class names, empty if no class attribute
1795     @see #classNames(Set)
1796     @see #hasClass(String) 
1797     @see #classList()
1798     */
1799    public Set<String> classNames() {
1800        Set<String> classNames = new LinkedHashSet<>(4);
1801        if (attributes == null) return classNames;
1802
1803        String classAttr = attributes.getIgnoreCase("class");
1804        int len = classAttr.length();
1805        for (int i = 0; i < len; ) {
1806            int start = nextClassStart(classAttr, i, len);
1807            if (start == len) break;
1808
1809            int end = nextClassEnd(classAttr, start, len);
1810            classNames.add(classToken(classAttr, start, end));
1811            i = end;
1812        }
1813        return classNames;
1814    }
1815
1816    /**
1817     Get each of the element's class names, in attribute order. E.g. on element
1818     {@code <div class="header gray">}, returns a list of two elements {@code "header", "gray"}.
1819     <p>This immutable snapshot preserves duplicate class names, and is more memory efficient than
1820     {@link #classNames()} when a read-only result is sufficient, particularly for elements without class names.
1821     Use {@link #classNames()} for a mutable set of unique class names.</p>
1822
1823     @return immutable list of class names, empty if no class attribute
1824     @see #classNames()
1825     @see #hasClass(String)
1826     @since 1.23.1
1827     */
1828    public List<String> classList() {
1829        if (attributes == null) return Collections.emptyList();
1830
1831        String attr = attributes.getIgnoreCase("class");
1832        int len = attr.length();
1833        int start = nextClassStart(attr, 0, len);
1834        if (start == len) return Collections.emptyList();
1835
1836        int end = nextClassEnd(attr, start, len);
1837        String first = classToken(attr, start, end);
1838        start = nextClassStart(attr, end, len);
1839        if (start == len) return Collections.singletonList(first);
1840
1841        List<String> classes = new ArrayList<>(4);
1842        classes.add(first);
1843        do {
1844            end = nextClassEnd(attr, start, len);
1845            classes.add(classToken(attr, start, end));
1846            start = nextClassStart(attr, end, len);
1847        } while (start < len);
1848        return Collections.unmodifiableList(classes);
1849    }
1850
1851    /**
1852     Find the next class token start.
1853     */
1854    private static int nextClassStart(String classAttr, int offset, int len) {
1855        while (offset < len && StringUtil.isWhitespace(classAttr.charAt(offset))) offset++;
1856        return offset;
1857    }
1858
1859    /**
1860     Find the next class token end.
1861     */
1862    private static int nextClassEnd(String classAttr, int offset, int len) {
1863        while (offset < len && !StringUtil.isWhitespace(classAttr.charAt(offset))) offset++;
1864        return offset;
1865    }
1866
1867    /**
1868     Returns the class token while preserving the original string for a single unpadded class.
1869     */
1870    private static String classToken(String classAttr, int start, int end) {
1871        return start == 0 && end == classAttr.length() ? classAttr : classAttr.substring(start, end);
1872    }
1873
1874    /**
1875     Set the element's {@code class} attribute to the supplied class names.
1876     @param classNames set of classes
1877     @return this element, for chaining
1878     */
1879    public Element classNames(Set<String> classNames) {
1880        Validate.notNull(classNames);
1881        if (classNames.isEmpty()) {
1882            attributes().remove("class");
1883        } else {
1884            attributes().put("class", StringUtil.join(classNames, " "));
1885        }
1886        return this;
1887    }
1888
1889    /**
1890     * Tests if this element has a class. Case-insensitive.
1891     * @param className name of class to check for
1892     * @return true if it does, false if not
1893     */
1894    // performance sensitive
1895    public boolean hasClass(String className) {
1896        if (attributes == null) return false;
1897        boolean web = QueryMode.current() == QueryMode.Web;
1898        return web ? CssMatching.hasClass(this, className) : LegacyMatching.hasClass(this, className);
1899    }
1900
1901    /**
1902     Add a class name to this element's {@code class} attribute.
1903     @param className class name to add
1904     @return this element
1905     */
1906    public Element addClass(String className) {
1907        Validate.notNull(className);
1908
1909        Set<String> classes = classNames();
1910        classes.add(className);
1911        classNames(classes);
1912
1913        return this;
1914    }
1915
1916    /**
1917     Remove a class name from this element's {@code class} attribute.
1918     @param className class name to remove
1919     @return this element
1920     */
1921    public Element removeClass(String className) {
1922        Validate.notNull(className);
1923
1924        Set<String> classes = classNames();
1925        classes.remove(className);
1926        classNames(classes);
1927
1928        return this;
1929    }
1930
1931    /**
1932     Toggle a class name on this element's {@code class} attribute: if present, remove it; otherwise add it.
1933     @param className class name to toggle
1934     @return this element
1935     */
1936    public Element toggleClass(String className) {
1937        Validate.notNull(className);
1938
1939        Set<String> classes = classNames();
1940        if (classes.contains(className))
1941            classes.remove(className);
1942        else
1943            classes.add(className);
1944        classNames(classes);
1945
1946        return this;
1947    }
1948
1949    /**
1950     * Get the value of a form element (input, textarea, etc).
1951     * @return the value of the form element, or empty string if not set.
1952     */
1953    public String val() {
1954        if (elementIs("textarea", NamespaceHtml))
1955            return text();
1956        else
1957            return attr("value");
1958    }
1959
1960    /**
1961     * Set the value of a form element (input, textarea, etc).
1962     * @param value value to set
1963     * @return this element (for chaining)
1964     */
1965    public Element val(String value) {
1966        if (elementIs("textarea", NamespaceHtml))
1967            text(value);
1968        else
1969            attr("value", value);
1970        return this;
1971    }
1972
1973    /**
1974     Get the source range (start and end positions) of the end (closing) tag for this Element. Position tracking must be
1975     enabled before parsing the content.
1976     @return the range of the closing tag for this element, or {@code untracked} if its range was not tracked.
1977     @see org.jsoup.parser.Parser#setTrackPosition(boolean)
1978     @see Node#sourceRange()
1979     @see Range#isImplicit()
1980     @since 1.15.2
1981     */
1982    public Range endSourceRange() {
1983        return Range.ofEnd(this);
1984    }
1985
1986    @Override
1987    void outerHtmlHead(final QuietAppendable accum, Document.OutputSettings out) {
1988        String tagName = safeTagName(out.syntax());
1989        accum.append('<').append(tagName);
1990        if (attributes != null) attributes.html(accum, out);
1991
1992        boolean htmlVoid = out.syntax() == html && isHtmlVoid();
1993        if (childNodes.isEmpty() || htmlVoid) {
1994            boolean xmlMode = out.syntax() == xml || !tag.namespace().equals(NamespaceHtml);
1995            if (xmlMode && (tag.is(Tag.SeenSelfClose) || (tag.isKnownTag() && (tag.isEmpty() || tag.isSelfClosing())))) {
1996                accum.append(" />");
1997            } else if (htmlVoid) {
1998                accum.append('>');
1999            } else {
2000                accum.append("></").append(tagName).append('>');
2001            }
2002        } else {
2003            accum.append('>');
2004        }
2005    }
2006
2007    @Override
2008    void outerHtmlTail(QuietAppendable accum, Document.OutputSettings out) {
2009        if (!childNodes.isEmpty())
2010            accum.append("</").append(safeTagName(out.syntax())).append('>');
2011        // if empty, we have already closed in htmlHead
2012    }
2013
2014    /** Tests if this element is an HTML-namespace void tag. */
2015    boolean isHtmlVoid() {
2016        return tag.namespace().equals(NamespaceHtml) && tag.isEmpty();
2017    }
2018
2019    /** Gets the tag name normalized for the output syntax. */
2020    private String safeTagName(Document.OutputSettings.Syntax syntax) {
2021        return syntax == xml ? Attribute.getValidKey(tagName(), xml) : tagName();
2022    }
2023
2024    /**
2025     Get the inner HTML of this element. For example, on a {@code <div>} with one empty {@code <p>}, this returns
2026     {@code <p></p>}, whereas {@link #outerHtml()} returns {@code <div><p></p></div>}.
2027
2028     @return the inner HTML of this element
2029     @see #html(Appendable)
2030     @see #outerHtml()
2031     */
2032    public String html() {
2033        StringBuilder sb = StringUtil.borrowBuilder();
2034        html(sb);
2035        String html = StringUtil.releaseBuilder(sb);
2036        return NodeUtils.outputSettings(this).prettyPrint() ? html.trim() : html;
2037    }
2038
2039    /**
2040     Append the inner HTML of this element to the supplied {@link Appendable}.
2041
2042     @param appendable the {@link Appendable} that will receive the HTML
2043     @return the supplied {@link Appendable}, for chaining
2044     @throws org.jsoup.SerializationException if the appendable throws an IOException
2045     @see #html()
2046     @see #outerHtml(Appendable)
2047     @see #outerHtml()
2048     */
2049    @Override
2050    public <T extends Appendable> T html(T appendable) {
2051        html(QuietAppendable.wrap(appendable));
2052        return appendable;
2053    }
2054
2055    /** Append the inner HTML of this element to the supplied {@link QuietAppendable}. */
2056    void html(QuietAppendable accum) {
2057        if (NodeUtils.outputSettings(this).syntax() == html && isHtmlVoid()) return;
2058        Node child = firstChild();
2059        if (child != null) {
2060            Printer printer = Printer.printerFor(child, accum);
2061            while (child != null) {
2062                printer.traverse(child);
2063                child = child.nextSibling();
2064            }
2065        }
2066    }
2067
2068    /**
2069     * Set this element's inner HTML. Clears the existing HTML first.
2070     * @param html HTML to parse and set into this element
2071     * @return this element
2072     * @see #append(String)
2073     */
2074    public Element html(String html) {
2075        empty();
2076        append(html);
2077        return this;
2078    }
2079
2080    @Override
2081    public Element clone() {
2082        return (Element) super.clone();
2083    }
2084
2085    @Override
2086    public Element shallowClone() {
2087        // simpler than implementing a clone version with no child copy
2088        String baseUri = baseUri();
2089        if (baseUri.isEmpty()) baseUri = null; // saves setting a blank internal attribute
2090        return new Element(tag, baseUri, attributes == null ? null : attributes.clone());
2091    }
2092
2093    @Override
2094    protected Element doClone(@Nullable Node parent) {
2095        Element clone = (Element) super.doClone(parent);
2096        clone.childNodes = new NodeList(childNodes.size());
2097        clone.childNodes.addAll(childNodes); // the children then get iterated and cloned in Node.clone
2098        if (attributes != null) {
2099            clone.attributes = attributes.clone();
2100            // clear any cached children
2101            clone.attributes.userData(childElsKey, null);
2102        }
2103
2104        return clone;
2105    }
2106
2107    // overrides of Node for call chaining
2108    @Override
2109    public Element clearAttributes() {
2110        if (attributes != null) {
2111            super.clearAttributes(); // keeps internal attributes via iterator
2112            if (attributes.size == 0)
2113                attributes = null; // only remove entirely if no internal attributes
2114        }
2115
2116        return this;
2117    }
2118
2119    @Override
2120    public Element removeAttr(String attributeKey) {
2121        return (Element) super.removeAttr(attributeKey);
2122    }
2123
2124    @Override
2125    public Element root() {
2126        return (Element) super.root(); // probably a document, but always at least an element
2127    }
2128
2129    @Override
2130    public Element traverse(NodeVisitor nodeVisitor) {
2131        return (Element) super.traverse(nodeVisitor);
2132    }
2133
2134    @Override
2135    public Element forEachNode(Consumer<? super Node> action) {
2136        return (Element) super.forEachNode(action);
2137    }
2138
2139    /**
2140     Perform the supplied action on this Element and each of its descendant Elements, during a depth-first traversal.
2141     Elements may be inspected, changed, added, replaced, or removed.
2142     @param action the function to perform on the element
2143     @see Node#forEachNode(Consumer)
2144     */
2145    @Override
2146    public void forEach(Consumer<? super Element> action) {
2147        stream().forEach(action);
2148    }
2149
2150    /**
2151     Returns an Iterator that iterates this Element and each of its descendant Elements, in document order.
2152     @return an Iterator
2153     */
2154    @Override
2155    public Iterator<Element> iterator() {
2156        return new NodeIterator<>(this, Element.class);
2157    }
2158
2159    @Override
2160    public Element filter(NodeFilter nodeFilter) {
2161        return  (Element) super.filter(nodeFilter);
2162    }
2163
2164    static final class NodeList extends ArrayList<Node> {
2165        /** Tracks if the children have valid sibling indices. We only need to reindex on siblingIndex() demand. */
2166        boolean validChildren = true;
2167
2168        public NodeList(int size) {
2169            super(size);
2170        }
2171
2172        /** The modCount is used to invalidate the cached element children. */
2173        int modCount() {
2174            return this.modCount;
2175        }
2176
2177        void incrementMod() {
2178            this.modCount++;
2179        }
2180    }
2181
2182    /**
2183     Repairs indexes from the insertion point on; preceding indexes must still be valid.
2184     */
2185    void reindexChildren(int start) {
2186        final int size = childNodes.size();
2187        for (int i = start; i < size; i++) {
2188            childNodes.get(i).setSiblingIndex(i);
2189        }
2190        childNodes.validChildren = true;
2191    }
2192
2193    void invalidateChildren() {
2194        childNodes.validChildren = false;
2195    }
2196
2197    boolean hasValidChildren() {
2198        return childNodes.validChildren;
2199    }
2200}