Skip to main content

css_to_xpath/
lib.rs

1#![doc = include_str!("../README.md")]
2#![forbid(unsafe_code)]
3#![warn(missing_docs)]
4
5mod parser;
6mod translate;
7
8pub use parser::MAX_NESTING_DEPTH;
9pub use translate::{
10    Error, MAX_NTH_OF_BYTES, MAX_NTH_OF_DEPTH, Mode, ParseErrorKind, ParseModeError, Translator,
11};
12
13/// A `prefix` that searches the context node and its whole subtree:
14/// `"a"` becomes `descendant-or-self::a`.
15pub const DESCENDANT_OR_SELF: &str = "descendant-or-self::";
16
17/// A `prefix` that searches the whole document, wherever the expression
18/// is evaluated from: `"a"` becomes `//a`.
19pub const WHOLE_DOCUMENT: &str = "//";
20
21/// Translate a CSS selector to an XPath 1.0 expression.
22///
23/// # Arguments
24///
25/// * `css` — A CSS selector string.
26/// * `prefix` — An XPath path prefix prepended verbatim to each
27///   selector-group branch, so it must end in something a node test can
28///   follow: an axis ([`DESCENDANT_OR_SELF`]) or a step separator
29///   ([`WHOLE_DOCUMENT`]). Pass `""` for a bare relative expression.
30///   Nothing validates it — `"/html/body "` yields `/html/body div`,
31///   which XPath reads as a division, not a path. A selector group
32///   anchored on `:scope` ignores `prefix` and anchors on `self::`
33///   instead.
34/// * `mode` — The translator flavour: [`Mode::Generic`], [`Mode::Html`], or
35///   [`Mode::Xhtml`].
36///
37/// # Errors
38///
39/// Returns an [`Error`] when the selector is syntactically invalid or uses
40/// an unsupported construct.
41pub fn css_to_xpath(css: &str, prefix: &str, mode: Mode) -> Result<String, Error> {
42    Translator::new(mode).css_to_xpath(css, prefix)
43}