html.selector
import html.selector
htmllifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelledhtml.selector.*needsimport html.selector.
A small, deliberately bounded CSS selector engine: enough to find things in a parsed document, and no more.
Supported syntax
| Form | Example |
|---|---|
| type | div |
| universal | * |
| id | #main |
| class | .warning |
| attribute presence | [disabled] |
| attribute equality | [type="text"] |
| descendant | article p |
| child | ul > li |
| next sibling | h2 + p |
| subsequent sibling | h2 ~ p |
| first child | li:first-child |
| last child | li:last-child |
| nth child | li:nth-child(2n+1) |
| selector list | h1, h2, h3 |
Compound selectors combine freely: ul.menu > li[data-id]:first-child
is valid, as is any comma-separated list of those.
Deliberately not supported
Everything else, and the parser says so rather than quietly ignoring it.
:not(), :has(), :nth-of-type(), ::before, namespace prefixes,
and the substring attribute operators (^=, $=, *=, ~=, |=) all
raise a SelectorError. A selector that silently matches nothing is far
worse to debug than one that refuses to compile.
Case sensitivity
Type selectors and attribute names fold ASCII case, matching how HTML itself treats them. Ids, class names and attribute values are compared exactly, which is what standards-mode HTML does.
Functions
compile()
html.compile(source: string) -> Selector
Compiles source into a reusable Selector.
Compiled selectors are cached by source text, so calling this with the same string repeatedly costs a dictionary lookup rather than a parse. The cache holds at most 256 selectors and is dropped wholesale when it fills, so a program that builds selector strings dynamically cannot grow it without bound.
%> import html
%> var s = html.selector.compile('ul.menu > li:first-child')
%> s.matches(element)
true
Parameters
source(string)
Returns Selector
Raises SelectorError when source is empty, malformed, or uses
syntax outside the supported subset.
Classes
SelectorError
class html.SelectorError < Error
Raised when a selector cannot be parsed, or uses syntax this module deliberately does not support. The message names the offending part of the selector.
Constructor
html.SelectorError(message)
Parameters
message(string)
AttributeTest
class html.selector.AttributeTest
One name/=value test from a [...] block.
Fields
| Field | Type | Description |
|---|---|---|
name | The attribute name, lowercased. | |
value | The value the attribute must equal, or nil when the test is a bare presence check. |
Constructor
html.selector.AttributeTest(name: string, value: ?string)
Parameters
name(string)value(?string)
AttributeTest.matches()
html.selector.AttributeTest.matches(element) -> bool
True when element satisfies this test.
Parameters
element(any)
Returns bool
PseudoTest
class html.selector.PseudoTest
One :pseudo or :pseudo(...) test.
Fields
| Field | Type | Description |
|---|---|---|
name | The pseudo-class name, lowercased and without its colon. | |
step | The a of the an+b argument, for nth-child. | |
offset | The b of the an+b argument, for nth-child. |
Constructor
html.selector.PseudoTest(name: string, step: ?number, offset: ?number)
Parameters
name(string)step(?number)offset(?number)
PseudoTest.matches()
html.selector.PseudoTest.matches(element) -> bool
True when element satisfies this test.
Parameters
element(any)
Returns bool
CompoundSelector
class html.selector.CompoundSelector
A run of simple selectors with nothing between them, such as
div#main.active[data-x]:first-child. Every part has to match the same
element.
Fields
| Field | Type | Description |
|---|---|---|
tag_name | The type selector’s tag name in lowercase, or nil when the compound has none or uses *. | |
id | The id the element must carry, or nil. | |
classes | Class names the element must all carry. | |
attributes | AttributeTest instances the element must all satisfy. | |
pseudos | PseudoTest instances the element must all satisfy. |
Constructor
html.selector.CompoundSelector()
CompoundSelector.matches()
html.selector.CompoundSelector.matches(element) -> bool
True when element satisfies every part of this compound.
Parameters
element(any)
Returns bool
ComplexSelector
class html.selector.ComplexSelector
One selector from a comma-separated list: a chain of compounds joined by
combinators, such as ul > li + li.
Fields
| Field | Type | Description |
|---|---|---|
compounds | The compounds, leftmost first. | |
combinators | How each compound relates to the one before it. |
Constructor
html.selector.ComplexSelector()
ComplexSelector.matches()
html.selector.ComplexSelector.matches(element) -> bool
True when element matches this selector.
Matching runs right to left, which is what makes a selector like body div span
cheap: the rightmost compound rejects almost every element outright, and
only survivors pay for the walk up the tree.
Parameters
element(any)
Returns bool
Selector
class html.Selector
A compiled selector list: h1, h2 is one of these holding two
ComplexSelector instances.
Instances are immutable once compiled and safe to reuse, which is why
compile() caches them.
Fields
| Field | Type | Description |
|---|---|---|
source | The selector text this was compiled from, kept for error messages and for to_string(). | |
alternatives | The alternatives, in the order they were written. |
Constructor
html.Selector(source: string, alternatives: list)
Parameters
source(string)alternatives(list)
Selector.matches()
html.Selector.matches(element) -> bool
True when element matches any alternative in this selector.
Parameters
element(any)
Returns bool
Selector.to_string()
html.Selector.to_string() -> string
The selector text this was compiled from.
Returns string
2026, Richard Ore and The Zuri Contributors