Overview
Builds XPath expressions by appending attribute conditions with support for regular expressions, boolean attributes, XPath sub-expressions, and class-based filtering.
Description
XPathBuilder takes an initial XPath expression (either a String or XPath::Expression) and provides add_attribute_conditions to append predicate filters. For :class attributes, it generates contains_word predicates for positive classes and negated contains_word for classes prefixed with !, with double-bang (!!) escaping. Regexp values are handled by the regexp_to_xpath_conditions method, which uses RegexpDisassembler to extract alternated substrings and builds contains predicates, applying uppercase transformation for case-insensitive regexps. Boolean values produce XPath.attr(name) for true and !XPath.attr(name) for false/nil. XPath::Expression values are used directly as sub-predicates via XPath.attr(name)[value]. String values produce equality checks. When the base expression is itself an XPath::Expression, conditions are appended via the [] predicate operator; otherwise, string expressions are wrapped in parentheses with the predicate appended.
Usage
Use XPathBuilder internally when defining XPath-based selectors in Capybara to translate high-level attribute filters into valid XPath predicate expressions. It is the XPath counterpart to CSSBuilder and is used by Capybara's selector infrastructure.
Code Reference
Source Location
Signature
class Capybara::Selector::XPathBuilder
def initialize(expression)
attr_reader :expression
def add_attribute_conditions(**conditions)
end
Import
require 'capybara/selector/builders/xpath_builder'
I/O Contract
XPathBuilder#initialize
| Parameter |
Type |
Description
|
expression |
String, XPath::Expression, or nil |
The initial XPath expression; nil defaults to an empty string
|
| Returns |
Type |
Description
|
| Instance |
XPathBuilder |
A new builder initialized with the given XPath expression
|
XPathBuilder#add_attribute_conditions
| Parameter |
Type |
Description
|
**conditions |
Hash{Symbol => String, Regexp, Boolean, XPath::Expression, nil} |
Attribute name-value pairs to append as XPath predicates
|
| Returns |
Type |
Description
|
| expression |
String or XPath::Expression |
The updated XPath expression with all predicate conditions appended
|
Special attribute handling:
| Attribute |
Value Type |
Generated XPath Predicate
|
:class |
String |
contains_word('classname') (positive) or not(contains_word('classname')) (negated with ! prefix)
|
:class |
Regexp |
Delegates to attribute_conditions(class: regexp)
|
:class |
XPath::Expression |
Delegates to attribute_conditions(class: expr)
|
| any |
XPath::Expression |
@attr[value] -- sub-expression used as predicate directly
|
| any |
Regexp |
contains('substring') predicates joined with AND/OR from regexp disassembly
|
| any |
true |
@attr -- attribute presence check
|
| any |
false or nil |
not(@attr) -- attribute absence check
|
| any |
String |
@attr = 'value' -- equality check
|
Usage Examples
Basic attribute conditions
builder = Capybara::Selector::XPathBuilder.new('.//div')
builder.add_attribute_conditions(id: 'main', disabled: true)
builder.expression
# => "(.//div)[@id = 'main'][@disabled]"
Class conditions with negation
builder = Capybara::Selector::XPathBuilder.new('.//span')
builder.add_attribute_conditions(class: ['active', '!hidden'])
builder.expression
# => "(.//span)[contains_word(@class, 'active') and not(contains_word(@class, 'hidden'))]"
Regexp attribute matching
builder = Capybara::Selector::XPathBuilder.new('.//input')
builder.add_attribute_conditions(name: /user.*name/i)
builder.expression
# => XPath expression with: contains(uppercase(@name), 'USER') and contains(uppercase(@name), 'NAME')
XPath::Expression as base
base_xpath = XPath.descendant(:div)
builder = Capybara::Selector::XPathBuilder.new(base_xpath)
builder.add_attribute_conditions(role: 'button')
builder.expression
# => XPath::Expression with [@role = 'button'] predicate appended via [] operator
Boolean attribute absence
builder = Capybara::Selector::XPathBuilder.new('.//input')
builder.add_attribute_conditions(disabled: false, readonly: nil)
builder.expression
# => "(.//input)[not(@disabled) and not(@readonly)]"
Related Pages