Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use this XPath 1.0 expression to match an element whose whitespace-separated class list contains the token notice:

//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')]

Replace notice with the class you need. The added spaces and normalize-space() make the test match a complete class token, so it finds notice in class="highlighted notice" but not inside noticeable. This pattern is documented in Parsel and Scrapy documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The reliable XPath class selector

HTML’s class attribute is normally a space-separated list, not a single value. Therefore, an exact attribute comparison is too narrow:

//div[@class='notice']

That expression misses <div class="notice highlighted">. A bare substring test is too broad:

//*[contains(@class, 'notice')]

It can also match noticeable. Use the token-boundary pattern instead:

//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')]

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

normalize-space(@class) collapses runs of whitespace and removes leading or trailing whitespace. Concatenating one space on each side turns the class list into a searchable, space-delimited string; searching for ' notice ' then requires boundaries on both sides. The XPath language specification is available in the XPath 1.0 Recommendation.

Choose the element scope

Search every element

Use //* when the class may occur on any element type:

//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')]

Restrict the tag name

Use a tag test when you know the element type:

//div[contains(concat(' ', normalize-space(@class), ' '), ' notice ')]

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

This avoids returning a matching span, section, or another element with the same class.

Search descendants of the current node

When an API has already selected a parent node, make the XPath relative with a leading dot:

.//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')]

Without the dot, // starts from the document root in common XPath contexts and can return matches outside the selected subtree. Parsel demonstrates this distinction when chaining CSS selection with relative XPath in its usage documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
XPath 2.0 Programmer's Reference
  • Used Book in Good Condition

Require two or more classes

Add one token predicate for every class that must be present:

//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ') and contains(concat(' ', normalize-space(@class), ' '), ' urgent ')]

This matches an element carrying both notice and urgent, regardless of their order or any additional classes. In HTML-aware selector APIs, the equivalent CSS selector is .notice.urgent; class membership is defined in terms of whitespace-separated tokens by Selectors Level 4.

Combine class matching with other predicates

Match text as well as class

For an element with the class and visible text containing “Warning,” combine predicates:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ') and contains(normalize-space(.), 'Warning')]

normalize-space(.) uses the element’s descendant text. If exact text is required, use an equality predicate instead, but remember that nested markup can make the element’s string value differ from the text you see visually.

Match an attribute

For a classed link whose href contains /alerts/:

//a[contains(concat(' ', normalize-space(@class), ' '), ' notice ') and contains(@href, '/alerts/')]

Select an ancestor or child

XPath is useful when the class condition is only one part of navigation. For example, to select a notice’s parent:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')]/..

To select a button inside each notice:

//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')]//button

These navigation features are a reason to keep XPath when a simple CSS class selector is not enough.

Get the first matching element correctly

Position predicates have an important scope difference:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • //li[1] selects every li that is first among its siblings under its parent.
  • (//li)[1] selects only the first li in the document-wide result.

The same rule applies to a class-filtered query. First match overall:

(//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')])[1]

First matching notice under each parent context:

//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')][1]

Parsel documents this parenthesizing distinction in its selector guide.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

XPath versus CSS for class lookup

If the task is only “find elements with this class” and your library supports CSS, .notice is shorter and easier to read. Two classes become .notice.urgent. Parsel recommends CSS for routine class lookup while showing XPath for subsequent extraction and navigation; Scrapy documents the same class-token pitfall and CSS alternative in its selector documentation.

Need Preferred expression Reason
One class, CSS supported .notice Concise token-aware class selection
One class, XPath required //*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')] Works with multiple classes and avoids substring matches
Two classes .notice.urgent or two XPath predicates Requires both tokens
Class plus text, parent, or positional logic XPath Supports predicates and document navigation in one expression
Already scoped to a node .//*[...] Keeps the search relative to that node

Browser automation APIs expose XPath as one locator strategy among others; Selenium’s locator documentation provides the relevant browser context at selenium.dev.

Use the expression in host code

Python with lxml

Pass the XPath as a normal Python string. The quotes surrounding the class token must survive unchanged:

from lxml import html
tree = html.fromstring('<div class="highlighted notice">Alert</div>')
nodes = tree.xpath("//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')]")
print(nodes[0].text)

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If the class name is supplied by a user or configuration, interpolate it only after applying the quoting rules of your XPath library; do not concatenate untrusted text into an expression without that library’s escaping mechanism.

Browser DevTools

In a browser console, XPath evaluation depends on the host API. The standard DOM method is:

document.evaluate("//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)

Use the returned snapshot’s snapshotItem(index) method to inspect matches. Browser rendering, JavaScript execution, and namespaces are host concerns; XPath only queries the document supplied to it.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Scrapy or Parsel

With a response selector, use:

response.xpath("//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')]")

After a CSS selection, keep the XPath relative:

response.css('article').xpath(".//*[contains(concat(' ', normalize-space(@class), ' '), ' notice ')]")

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Common failures and fixes

No results from @class='notice'

Cause: the element has additional classes, different whitespace, or a different class order.

Fix: use the padded normalize-space() token expression.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Unexpected results from contains(@class, 'notice')

Cause: substring matching also sees names such as noticeable.

Fix: include the surrounding spaces in both the normalized attribute and search token.

A relative query returns elements elsewhere

Cause: the expression starts with // instead of .// after a scoped selection.

Fix: add the leading dot for descendants of the current context node.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The “first” result is repeated

Cause: [1] was applied to each parent-level step.

Fix: wrap the complete result in parentheses before applying [1].

The selector works in one document but not another

Cause: class values, namespaces, parser behavior, or generated DOM content differ. XPath does not fetch or render a page.

Fix: inspect the actual parsed document, confirm the class attribute exists at query time, and account for namespaces when querying XML or namespaced HTML.

Or skip the browser setup

If you need a clean screenshot of a page while diagnosing or documenting class-based elements, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one GET request. Its cleanup steps accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo documentation for options such as full-page capture, CSS-selector element capture, device presets, custom JavaScript, waits, headers, cookies, blocking rules, caching, signed links, asynchronous jobs, webhooks, bulk capture, and PDF settings. The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Practical checklist

  • Use token-aware matching with concat, normalize-space, and padded spaces.
  • Choose //* for any tag or a specific tag such as //div when appropriate.
  • Use .// for descendants of the current context node.
  • Add one predicate per required class.
  • Parenthesize the full result before applying a document-wide positional predicate.
  • Prefer CSS for simple class-only selection when your API supports it; retain XPath for text, navigation, and compound predicates.
  • Verify the document and timing supplied by the host parser or browser.

Frequently Asked Questions

Does XPath have a dedicated class selector?

XPath has no CSS-style class shorthand. Match the class attribute as a whitespace-separated token with the padded `normalize-space()` expression.

Can this pattern match a class containing a space?

No. HTML class names are whitespace-separated tokens, so a value containing a space represents multiple classes. Match each token separately.

Why does my XPath return nothing after a CSS selection?

The XPath is probably document-rooted. Prefix the descendant expression with `.` so it is evaluated relative to the node selected by CSS.

When should I use CSS instead of XPath?

Use CSS for straightforward class membership when supported. Use XPath when you also need text predicates, ancestor/child navigation, or positional logic.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.