Skip to content
James Conway edited this page Nov 4, 2026 · 2 revisions

Short answers to what people ask first about Parsec, each pointing at the page with the long one.

All 24 questions

Can I use Parsec today?

Yes, from git; it isn't released. Add parsec-html = { git = "https://github.com/parsec-html/parsec" } to your dependencies and use parsec. The API can still change before 0.1.0, so pin a commit if that matters to you. Getting started has the details.

When is the first release?

When milestones M1 to M4 are done and the benchmarks show Parsec ahead of Lexbor on every page in the corpus (#32). There's no date. Roadmap has what's in each milestone.

Is it a fork of Lexbor, or html5ever?

Neither. It's its own parser, written in Rust from the HTML Standard. It's developed inside Netweir as crates/netweir-html and synced here; Contributing explains how.

Is it faster than Lexbor?

Not measured parser against parser yet; that's #2. The one published number is end-to-end from Python, Netweir against selectolax, and it includes the queries and Python itself. Benchmarks has it with its caveats.

How correct is it?

It passes all 7,045 html5lib tokenizer runs it can be given and all 3,898 runs of the WPT tree-construction cases that don't need JavaScript. Conformance says exactly what's counted and skipped.

Does it run JavaScript?

No. The scripting flag only changes how <noscript> is parsed, as a browser with JavaScript on or off would parse it. See Parsing.

Which scripting value should I use?

false, usually. Then <noscript> fallbacks become ordinary elements your selectors can find. Use true if you want the tree a JavaScript-enabled browser builds.

Can I parse bytes, or pages in other encodings?

Not yet. Parsec takes a &str, so decode first. Encoding sniffing is #5, and the encodings themselves are #25.

Why did my page parse in quirks mode?

Either it has no doctype, or it has an old one, or it starts with a byte order mark before the doctype. A browser drops the BOM while decoding; Parsec sees it as text, so strip a leading \u{FEFF} yourself. Parsing shows how.

Why doesn't .Foo match class="foo"?

Class names and ids compare exactly, as in a browser, except in quirks-mode documents. A page with no doctype is in quirks mode, so there .foo would match. See Selectors.

Why doesn't [href] find SVG's xlink:href?

Because xlink:href is in the XLink namespace and [href] means no namespace, as in a browser. Use [*|href].

Why can't my selector see what's inside a <template>?

The HTML Standard keeps template contents out of the tree, and Parsec follows it. Run the selector on doc.template_contents(id), or call doc.adopt_template_contents() once to move all contents into the tree, as lxml and Beautiful Soup show them. See The document tree.

Why is :lang() (or :valid, or ::before) an error?

Parsec refuses selectors it doesn't match yet, rather than parse them and silently match nothing. Each missing pseudo-class has an issue; pseudo-elements select parts of elements, not elements, so select can't return them. Selectors has the list.

How do I read one attribute?

let doc = parsec::parse("<a href=/x>x</a>", false);
let a = parsec::css::SelectorList::parse("a").unwrap().select(&doc, doc.root())[0];
let href = doc.attrs(a).find(|&(_, name, _)| name == "href").map(|(_, _, v)| v);
assert_eq!(href, Some("/x"));

There's no single-call getter yet.

How do I set innerHTML?

There's no setter. Parse the markup with parse_fragment in the element's context and copy the nodes in; Moving from Lexbor has a helper that does it.

What happens to a node I remove?

It's unlinked from the tree but stays in the document, with its subtree, until the document is dropped. Its id stays valid and you can insert it again. See Editing.

Can I share a Document between threads?

Yes. It's Send and Sync today, so you can read it from many threads and move it between them; edits need &mut. That isn't a promise yet: #11 makes it one. See Thread safety and memory safety.

How do I protect a crawler from hostile pages?

Use parse_with with a budget, and check sizes before you parse. Limits and hostile input explains what the budget covers and where Parsec is and isn't linear.

Can I get line and column numbers?

Not yet. Parse errors with positions are #7, and positions on nodes and attributes are #8.

Can I stream a page in as it downloads?

Not yet; the whole input has to be in memory. Chunked input is #6.

Is there XPath?

Not yet: #31, which brings Netweir's XPath 1.0 engine over. There's no XML parser either; Ns::Xml is for trees you build yourself.

Can I use it from C, Python or JavaScript?

Not yet. The C API is #20, Python #23, WebAssembly #24.

Why does it need a CLA if it's Apache-2.0?

Because the parser is shared with Netweir, which is AGPL-3.0 and also sold under a commercial licence, so contributions here may go there too. You keep your copyright. Contributing has the details.

Where do I ask something that isn't here?

Discussions. Bugs go to Issues, and security problems to the private form in SECURITY.md.

See also

Clone this wiki locally