Class Selector

java.lang.Object
org.jsoup.select.Selector

public class Selector extends Object
Find elements and nodes using CSS selectors.

Using selectors

Use selectors to find elements by tag, class, attribute, text, or their position in the document. Pass a query to Element.select(String) to get matching elements, or Element.selectFirst(String) to get the first match.

Elements links = doc.select("a[href]");
Elements images = doc.select("article img");
Element heading = doc.selectFirst("article > h1");

Combine selectors to narrow your search: a.download[href$=.zip] finds links with the download class whose URLs end in .zip. Try queries in the Try jsoup online playground. To retrieve nodes such as text and comments, use Element.selectNodes(String).

jsoup 1.24.1 introduces an opt-in Web query mode with changes to matching behavior; see Query compatibility changes and the selector migration guide.

Selector syntax

A selector combines simple selectors, such as .header[title], with combinators, such as >, to describe relationships between elements. The universal selector * is implicit: .header and *.header are equivalent.

See element and attribute selectors, combinators, logical selectors, structural selectors, text, regex, and index selectors, and node selectors.

Element and attribute selectors

PatternMatchesExample
*any element*
tagelements with the given tag namediv
*|Eelements of type E in any namespace (including non-namespaced)*|name finds <dc:name> and <name> elements
ns|Eelements of type E in the namespace nsdc|name finds <dc:name> elements
ns|*all elements in the namespace nsdc|* finds <dc:p> and <dc:img> elements
#idelements with attribute ID of "id"div#wrap, #logo
.classelements with a class name of "class"div.left, .result
[attr]elements with an attribute named "attr" (with any value)a[href], [title]
[^attrPrefix]elements with an attribute name starting with "attrPrefix". Use to find elements with HTML5 datasets[^data-], div[^data-]
[attr=val]elements with an attribute named "attr", and value equal to "val"img[width="500"], a[rel=nofollow]
[attr!=val]elements whose attribute value differs from "val", including elements without the attributea[rel!=nofollow]
[attr^=valPrefix]elements with an attribute named "attr", and value starting with "valPrefix"a[href^="http:"]
[attr$=valSuffix]elements with an attribute named "attr", and value ending with "valSuffix"img[src$=".png"]
[attr*=valContaining]elements with an attribute named "attr", and value containing "valContaining"a[href*="/search/"]
[attr~=regex]elements with an attribute value matching the regular expression; see the upcoming change to token matchingimg[src~=(?i)\.(png|jpe?g)]
[attr|=val]matches an exact value or that value followed by a hyphen[lang|=en] matches "en" and "en-US"
[attr=val i], [attr=val s]i ignores ASCII case in the attribute value; s requires exact case. Neither changes attribute-name matching. Also applies to substring and hyphen operators; see case matching[data-sku="AbC123" i], [type="TEXT" s]
:matchesAttr(attr, regex)elements with an attribute value containing a regex matchimg:matchesAttr(src, (?i)\.(png|jpe?g))
[*]elements with any attributep[*] finds p elements that have at least one attribute; p:not([*]) finds those with no attributes

Combinators

PatternMatchesExample
E Fan F element descended from an E elementdiv a, .logo h1
E > Fan F direct child of Eol > li
E + Fan F element immediately preceded by sibling Eli + li, div.head + div
E ~ Fan F element preceded by sibling Eh1 ~ p
E, F, Gall matching elements E, F, or Ga[href], div, h3

Logical selectors

PatternMatchesExample
:has(selector)elements that contain at least one element matching the selectordiv:has(p) finds divs that contain p elements.
div:has(> a) selects div elements that have at least one direct child a element.
section:has(h1, h2) finds section elements that contain a h1 or a h2 element
:is(selector list)elements that match any of the selectors in the selector list:is(h1, h2, h3, h4, h5, h6) finds any heading element.
:is(section, article) > :is(h1, h2) finds a h1 or h2 that is a direct child of a section or an article
:not(selector)elements that do not match the selector. See also Elements.not(String)div:not(.logo) finds all divs that do not have the "logo" class.

div:not(:has(div)) finds divs that do not contain divs.

Structural selectors

PatternMatchesExample
:scopeThe element you query from, or the document element (usually html) when querying a Document:scope > p finds direct child paragraphs
:rootThe tree's root element: the document element, or the topmost element of a detached tree:root
:nth-child(an+b)elements at child positions an+b, for any integer n starting at zero. Positions start at 1 and count element siblings. Use odd for 2n+1, or even for 2ntr:nth-child(2n+1) finds odd rows; li:nth-child(5) finds the fifth list item; :nth-child(10n-1) finds positions 9, 19, 29, etc.
:nth-last-child(an+b)like :nth-child(), counting from the last siblingtr:nth-last-child(-n+2) finds the last two rows
:nth-of-type(an+b)like :nth-child(), counting only siblings of the same typeimg:nth-of-type(2n+1)
:nth-last-of-type(an+b)like :nth-of-type(), counting from the last siblingimg:nth-last-of-type(2n+1)
:first-childelements that are the first child of some other element.div > p:first-child
:last-childelements that are the last child of some other element.ol > li:last-child
:first-of-typeelements that are the first sibling of its type in the list of children of its parent elementdl dt:first-of-type
:last-of-typeelements that are the last sibling of its type in the list of children of its parent elementtr > td:last-of-type
:only-childelements with a parent and no element siblingsp:only-child
:only-of-typeelements with a parent and no siblings of the same typep:only-of-type
:emptyelements that contain no child elements or nodes, with the exception of blank text nodes, comments, XML declarations, and doctype declarations. In other words, it matches elements that are effectively empty of meaningful content.li:not(:empty)

Text, regex, and index selectors

These jsoup extensions match text or zero-based sibling indexes.

PatternMatchesExample
:lt(n)elements whose sibling index is less than ntd:lt(3) finds the first 3 cells of each row
:gt(n)elements whose sibling index is greater than ntd:gt(1) finds cells after skipping the first two
:eq(n)elements whose sibling index is equal to ntd:eq(0) finds the first cell of each row
:contains(text)elements that contain the specified text. The search is case insensitive. The text may appear in the found element, or any of its descendants. The text is whitespace normalized.

To find content that includes parentheses, escape those with a \.

p:contains(jsoup) finds p elements containing the text "jsoup".

p:contains(hello \(there\)) finds p elements containing the text "Hello (There)"

:containsOwn(text)elements that directly contain the specified text. The search is case insensitive. The text must appear in the found element, not any of its descendants.p:containsOwn(jsoup) finds p elements with own text "jsoup".
:containsData(data)elements that contain the specified data. The contents of script and style elements, and comment nodes (etc) are considered data nodes, not text nodes. The search is case insensitive. The data may appear in the found element, or any of its descendants.script:containsData(jsoup) finds script elements containing the data "jsoup".
:containsWholeText(text)elements containing the exact text, including case, spaces, and newlines, in themselves or their descendants. A br contributes a newline. Escape parentheses with a backslashp:containsWholeText(Hello) finds paragraphs containing "Hello", but not "hello"
:containsWholeOwnText(text)like :containsWholeText(), but matches only the element's own textp:containsWholeOwnText(Hello) finds paragraphs containing "Hello" in their own text, excluding child elements' text
:matches(regex)elements containing whitespace normalized text that matches the specified regular expression. The text may appear in the found element, or any of its descendants.td:matches(\d+) finds table cells containing digits. div:matches((?i)login) finds divs containing the text, case insensitively.
:matchesOwn(regex)like :matches(), but matches only the element's own whitespace-normalized texttd:matchesOwn(\d+)
:matchesWholeText(regex)elements containing non-normalized whole text that matches the specified regular expression. The text may appear in the found element, or any of its descendants.td:matchesWholeText(\s{2,}) finds table cells containing a run of at least two whitespace characters.
:matchesWholeOwnText(regex)elements whose own non-normalized whole text matches the specified regular expression. The text must appear in the found element, not any of its descendants.td:matchesWholeOwnText(\n\d+) finds table cells directly containing digits following a newline.

Node selectors

These jsoup extensions select text, comments, and other nodes directly. Combine a node type with a content filter, such as ::text:contains(foo), and use combinators to restrict where it appears:

Nodes<TextNode> text = doc.selectNodes("p ::text:contains(foo)", TextNode.class);

This returns individual text nodes containing "foo" inside paragraphs. To find paragraphs containing that text, use the regular element selector p:contains(foo).

Use Element.selectNodes(String) to retrieve nodes, or the typed overload to collect a specific node type. With Element.select(String), use node selectors inside :has() when their presence or content determines which elements you want. For example, this finds divs with a direct child comment containing "TODO":

Elements annotated = doc.select("div:has(> ::comment:contains(TODO))");
PatternMatchesExample
::nodeAny Node, including elements and leaf nodessection > ::node finds all direct child nodes of sections, including elements, text, and comments
::leafnodeNon-element nodes, such as text, comments, data, and processing instructions. An empty element is still an element, not a leaf nodearticle ::leafnode:not(:blank) finds non-element nodes with nonblank values inside articles
::textText nodes, including CDATA sectionsp ::text:contains(foo) finds individual text nodes containing "foo" inside paragraphs
::commentComments; content filters search the comment data, without the enclosing markup::comment:contains(TODO) finds comments containing "TODO"
::dataData nodes, such as the contents of HTML script and style elements, which are stored as data rather than text nodesscript > ::data:contains(analytics) finds script data containing "analytics"
::cdataCDATA sections; content filters search the section's text, without the CDATA delimiters::cdata:contains(config) finds CDATA sections containing "config"
::piProcessing instructions; content filters search the instruction's data::pi:contains(country-options) finds instructions with "country-options" in their data
::pi(target)Processing instructions with the specified case-sensitive target::pi(xml-stylesheet) finds instructions such as <?xml-stylesheet href="style.xsl"?>
::pi[...]Processing instructions whose data matches an attribute selector. The instruction data is parsed into attributes for comparison::pi(marker)[name=country-options] finds instructions such as <?marker name="country-options"?>

Append :contains(text), :matches(regex), or :blank to any of these node selectors to test its value. For text, comments, data, and CDATA, this is the node's content; for processing instructions, its data; for elements, their own text, excluding child elements' text. Node values retain whitespace; :contains() normalizes whitespace in the search text and ignores case. :matches() searches the value using a regular expression, and :blank tests for an empty or whitespace-only value.

For example, ::comment:matches(\d+) finds comments containing digits, and ::text:not(:blank) finds text nodes with nonblank content. These filters can be combined with :not() and with each other.

Matching rules

In the default legacy mode, Element.select(String) searches the element it is called on and its descendants. For example, given <div id="outer"><div id="inner"></div></div>, outer.select("div") returns both divs, while outer.select(":scope > div") returns only the inner div. See Query compatibility changes for Web mode's matching rules.

Element.is(String) checks whether the element itself matches the query. Element.closest(String) finds the nearest matching element: itself or an ancestor.

Ancestor matching stops at the element you query from. For example, panel.select("body p") does not match paragraphs when the body is outside the panel.

Tag and attribute names ignore ASCII case. Class names and literal attribute values ignore Unicode case; IDs match exactly. Structural selectors such as :nth-of-type() group siblings by their normalized tag names.

Use i on an attribute selector to ignore ASCII case in its value, or s for exact case; see case matching for examples. These flags do not affect attribute names or the default regex interpretation of ~=; use regex inline flags such as (?i) there.

Text selectors keep the matching rules described in their entries above. Regex selectors use Java's Pattern syntax and flags.

Escaping and regular expressions

The examples in the tables are CSS queries. When writing a query in a Java string literal, double each backslash.

Escape CSS special characters with a backslash. To match <p id="i.d">, the CSS query is #i\.d; in Java, write document.select("#i\\.d"). You can also use escapeCssIdentifier(String) to escape a tag, ID, or class name.

Regex arguments are passed to the regex parser without CSS unescaping. For example, the CSS query img:matchesAttr(src, (?i)\.(png|jpe?g)) is written in Java as document.select("img:matchesAttr(src, (?i)\\.(png|jpe?g))"). Whitespace immediately after the argument comma is skipped; use \x20 for a leading literal space.

Regex arguments use balanced parentheses. Escape literal parentheses that would unbalance the argument, including inside character classes: :matchesAttr(x, ^[^\)]+$) is written in Java as document.select(":matchesAttr(x, ^[^\\)]+$)"). Surrounding quotes are part of the regex, not an argument wrapper.

When searching for literal text through a regex selector, use Pattern.quote(String) to quote it: String query = "div:matches(" + Pattern.quote(text) + ")";.

Query compatibility changes

jsoup 1.24.1 introduces Web query behavior that follows CSS and Web DOM standards more closely. Set the jsoup.queryMode system property before running queries to choose:

  • legacy: use the query behavior of earlier jsoup releases.
  • web: use the updated CSS and Web DOM matching rules described below.
  • check: return legacy results while comparing supported queries against Web mode and reporting differences. See Checking query compatibility.

The default is legacy in 1.24.1 and changes to web in 1.25.1, when legacy and check remain available. In 1.26.1, Web behavior is the only option and the property is removed. See the selector migration guide for compatibility testing and query updates.

What changes in Web mode

Query behaviorLegacy modeWeb mode
Query resultsInclude the starting element if it matches.Include only its descendants.
Selector relationshipsAncestor matching stops at the element you query from.Can match ancestors and siblings outside its subtree; results stay inside the element you query from.
Tag and attribute namesIgnore ASCII case.HTML names ignore ASCII case. Names in XML and foreign content (such as SVG and MathML) match exactly, as do attribute names on processing instructions.
Classes and IDsClasses ignore Unicode case; IDs match exactly.Match exactly, except class and ID selectors in quirks documents ignore ASCII case.
Literal attribute values without a flagIgnore Unicode case.Match exactly, except HTML attributes with case-insensitive values, such as type, rel, and lang, ignore ASCII case.
~=Matches an attribute value using a regex.Matches a complete whitespace-separated token. Supports i and s flags.
:nth-of-type() and related selectorsCompares normalized tag names.Compares namespace and exact local name.

These rules apply to select, selectFirst, their stream and node variants, and the convenience finders on Element: getElementsBy*, text finders, getElementById, and getAllElements. Element.hasClass(String) uses the selected mode's class case rules. getElementById continues to match IDs exactly, including in quirks documents. Text and regex selectors retain their value-matching rules.

Checking query compatibility

Check mode helps you find queries that may behave differently when switching to Web mode. Enable it before running your queries:

System.setProperty("jsoup.queryMode", "check");

Each supported query runs in both modes and returns the legacy result. If the results differ, or the query fails in Web mode, jsoup writes a diagnostic to stderr identifying the query and up to two caller locations. Comparisons check which elements are returned and their order, not just the number of matches.

jsoup query compat: select("div"): legacy=2, web=1; results differ; at example.ProductParser.items(ProductParser.java:42)

(Checks cover common string-query methods such as select() and selectFirst(); streams, node queries, supplied evaluators, and convenience finders run without checks.)

Use check mode when running tests or assessing compatibility; running queries twice adds overhead. After reviewing and updating affected queries, switch to web.

Query results and scope

:scope refers to the element the query is called on, or the document element when querying a Document. In Web mode, adding :scope does not include that element in query results. Element.is(String) and Element.closest(String) still test the supplied element; their :scope refers to that element. Elements.not(String) tests each supplied element directly.

To include the starting element when it matches, filter Element.stream() with Evaluator.asPredicate(Element).

In Web mode, inside :has(), a leading combinator starts from each element being tested, but :scope still refers to the element the query is called on. For example, outer.select("div:has(> p)") finds divs with a direct child paragraph; outer.select("div:has(:scope > p)") finds none, because a paragraph inside a descendant div cannot also be a direct child of outer.

Attribute regular expressions

Use :matchesAttr(attr, regex) for attribute regexes in either mode, as shown in the syntax table. See Escaping and regular expressions for Java string examples and escaping rules.

Case matching and attribute values

In Web mode, the document's parser selects HTML rules (the default) or XML rules with Parser.xmlParser(). The comparison table distinguishes attribute names from values. The i and s flags affect values only: [data-sku="AbC123" i] ignores ASCII case, while [type="TEXT" s] requires exact case. Both flags work in every query mode from 1.24.1.

For case-insensitive class matching in Web mode, use [class~="card" i] instead of .card. See the comparison table for default class and ID case rules.

Unquoted attribute values are supported in both modes, including numbers, URLs, and text with spaces. In Web mode, a final separate i or s is a case flag. Quote literal values ending in either token, such as [data-x="two words i"].

See Also:
  • Method Details

    • select

      public static Elements select(String query, Element root)
      Find Elements matching the CSS query.
      Parameters:
      query - CSS selector
      root - root element to descend into
      Returns:
      matching elements, empty if none
      Throws:
      Selector.SelectorParseException - (unchecked) on an invalid CSS query.
    • select

      public static Elements select(Evaluator evaluator, Element root)
      Find Elements matching the Evaluator.
      Parameters:
      evaluator - CSS Evaluator
      root - root (context) element to start from
      Returns:
      matching elements, empty if none
    • selectStream

      public static Stream<Element> selectStream(String query, Element root)
      Finds a Stream of elements matching the CSS query.
      Parameters:
      query - CSS selector
      root - root element to descend into
      Returns:
      a Stream of matching elements, empty if none
      Throws:
      Selector.SelectorParseException - (unchecked) on an invalid CSS query.
      Since:
      1.19.1
    • selectStream

      public static Stream<Element> selectStream(Evaluator evaluator, Element root)
      Finds a Stream of elements matching the evaluator.
      Parameters:
      evaluator - CSS selector
      root - root element to descend into
      Returns:
      matching elements, empty if none
      Since:
      1.19.1
    • select

      public static Elements select(String query, Iterable<Element> roots)
      Find elements matching the query, across multiple roots. Elements will be deduplicated (in the case of overlapping hierarchies).
      Parameters:
      query - CSS selector
      roots - root elements to descend into
      Returns:
      matching elements, empty if none
    • selectFirst

      public static @Nullable Element selectFirst(String cssQuery, Element root)
      Find the first Element that matches the query.
      Parameters:
      cssQuery - CSS selector
      root - root element to descend into
      Returns:
      the matching element, or null if none.
    • selectFirst

      public static @Nullable Element selectFirst(String cssQuery, Iterable<Element> roots)
      Find the first element matching the query, across multiple roots.
      Parameters:
      cssQuery - CSS selector
      roots - root elements to descend into
      Returns:
      the first matching element, or null if none
      Since:
      1.19.1
    • escapeCssIdentifier

      public static String escapeCssIdentifier(String in)
      Given a CSS identifier (such as a tag, ID, or class), escape any CSS special characters that would otherwise not be valid in a selector.
      Since:
      1.20.1
      See Also:
    • unescapeCssIdentifier

      public static String unescapeCssIdentifier(String in)
      Consume a CSS identifier (ID or class) off the queue.

      Note: For backwards compatibility this method supports improperly formatted CSS identifiers, e.g. 1 instead of \31.

      Returns:
      The unescaped identifier.
      Throws:
      IllegalArgumentException - if an invalid escape sequence was found.
      Since:
      1.20.1
      See Also:
    • evaluatorOf

      public static Evaluator evaluatorOf(String css)
      Parse a CSS query into an Evaluator. If you are evaluating the same query repeatedly, it may be more efficient to parse it once and reuse the Evaluator. The evaluator captures the current value of jsoup.queryMode; later property changes do not alter it.
      Parameters:
      css - CSS query
      Returns:
      Evaluator
      Throws:
      Selector.SelectorParseException - if the CSS query is invalid
      Since:
      1.21.1
      See Also: