1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//! A pure Rust XPath 1.0 engine.
//!
//! Schematron's `xslt` and `xpath` query language bindings are XPath 1.0, so
//! validating a schema means evaluating XPath. This module implements the
//! language in full — all thirteen axes, all twenty-seven core functions, and
//! XPath 1.0's conversion and comparison semantics — with no external XPath
//! crate and no XSLT processor.
//!
//! The pipeline is: source text, then [`lexer`](self) tokens, then [`parse`]
//! into an [`Expr`], then [`evaluate`] against an [`EvalContext`].
//! Expressions are parsed once when a schema is compiled and evaluated many
//! times, which is where the performance comes from.
//!
//! See `spec/xpath.md` for the grammar and the semantics.
//!
//! # Examples
//!
//! ```
//! use schematron::xml::Document;
//! use schematron::xpath::{evaluate, parse, EvalContext, Namespaces, Variables};
//!
//! let doc = Document::from_str("<order><line qty='2'/><line qty='0'/></order>")?;
//! let expr = parse("count(line[@qty > 0])")?;
//!
//! let variables = Variables::new();
//! let namespaces = Namespaces::new();
//! let context = EvalContext::new(&doc, doc.document_element().unwrap(), &variables, &namespaces);
//!
//! assert_eq!(evaluate(&expr, &context)?.to_number(&doc), 1.0);
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! # Surprises worth knowing
//!
//! - An unprefixed name matches **no namespace**. There is no default
//! namespace in XPath 1.0, so a schema for a namespaced vocabulary must
//! declare a prefix and use it everywhere.
//! - `a != b` is not `not(a = b)` when node-sets are involved: both can be
//! true at once, because each is existential over the node-set.
//! - Every relational comparison converts to number, so `'x' > 0` is false
//! rather than an error — the string becomes NaN.
//!
//! # Reaching other documents
//!
//! `document(uri)` returns the root nodes of external documents, so a
//! node-set can span documents. Because node handles are indices into one
//! arena, a loaded document is merged into that arena beside the instance,
//! keeping its own root — so `/` and `id()` still mean "this document" from
//! inside it.
//!
//! Loading is driven by the validator, which supplies a [`Documents`]
//! registry. Evaluating an expression directly through this module has no
//! registry, and `document()` is then an error rather than an empty node-set:
//! silently returning nothing would turn a broken lookup into a passing
//! assertion. See `spec/xpath.md`.
pub use ;
pub use ;
pub use XPathVersion;
pub use ;
pub use ;
pub use ;
pub use ;