XPath contains() and not(contains()) are two of the most commonly used string-matching functions that help locate nodes based on partial text values.

I’m sharing a best-case example of how the contains() function will work. In this article, we’ll explore everything about these functions—how they work, when to use them, and a variety of real-world examples for XML, HTML scraping, and automation use cases.

🔍What Is contains() in XPath?

Syntax:

				
					contains(America, Am)
				
			

Returns:

True:  if the substring is found.
False: if it is not.

✅Basic Examples:

1. Select all elements where the class attribute contains the word active:

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

2. Find all <div> elements whose text contains Login:

				
					//div[contains(text(), 'Login')]
				
			

3. Locate a <span> whose id contains the substring user:

				
					//span[contains(@id, 'user')]
				
			

❌ What Is not(contains()) in XPath?

As the name suggests, not(contains()) is used to find nodes that do not contain a specific substring.

Syntax:

				
					not(contains(America, Am))

				
			

✅ Basic Examples:

1. Find all elements that do not have disabled in their class:

				
					//*[not(contains(@class, 'disabled'))]

				
			

2. Get <a> tags that don’t contain the word logout in their href:

				
					//a[not(contains(@href, 'logout'))]

				
			

3. Get all <option> elements that don’t contain the word Select:

				
					//option[not(contains(text(), 'Select'))]
				
			

🧠Advanced XPath contains() and not(contains()) Use Cases

Let’s dive deeper into some more advanced scenarios you might face while working with XML, HTML, or scraping tools like Selenium, Scrapy, or Puppeteer.

📘 1. Multiple Conditions with contains()

				
					//div[contains(@class, 'btn') and contains(@class, 'primary')]

				
			

This selects all <div> elements that have both btn and primary in their class.

📘 2. contains() with Partial Match in Element Text

				
					//*[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'submit')]

				
			

This case-insensitive match finds any element where the text contains “submit”, ignoring case.

📘 3. Combine contains() and starts-with()

				
					//input[contains(@name, 'email') and starts-with(@type, 'text')]

				
			

Finds text input fields related to email addresses.

📘 4. Filtering Child Elements with not(contains())

				
					//ul/li[not(contains(text(), 'Deprecated'))]

				
			

Gets all list items that are not marked as “Deprecated”.

📘 5. Extracting Dynamic Buttons from Forms

Input:

				
					<button class="btn btn-primary">Submit Form</button>
<button class="btn btn-secondary">Cancel</button>

				
			

Use:

				
					//button[contains(text(), 'Submit')]

				
			

🧩 Pro Tips

1. Be cautious with spaces:

				
					//div[contains(@class, 'btn primary')]

				
			

This won’t match if classes are separated. Instead, break into multiple conditions:

				
					//div[contains(@class, 'btn') and contains(@class, 'primary')]

				
			

2. Use normalize-space() with text(): To avoid hidden whitespaces:

				
					//h2[contains(normalize-space(text()), 'Welcome')]