schematron 0.3.1

Schematron: pure Rust implementation of ISO/IEC 19757-3 rule-based XML validation, with its own XML parser, XPath 1.0 engine, XPath 2.0 subset, schema linting, and SVRL reporting. By SixArm.com.
Documentation
# Errors

One error type, `schematron::Error`, built with `thiserror`. Every variant
names *what* failed and *where*, because a schema error that says only
"invalid XPath" costs the user more time than the crate saved them.

```rust
#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("I/O error for {path}: {source}")]
    Io { path: String, source: std::io::Error },

    #[error("XML parse error at line {line}, column {column}: {message}")]
    XmlParse { line: usize, column: usize, message: String },

    #[error("schema error in <{element}>{}: {message}", OptionalAt(.location))]
    Schema { element: String, location: Option<String>, message: String },

    #[error("XPath syntax error in {context}: {message}\n  expression: {expression}\n  {caret}")]
    XPathSyntax { context: String, expression: String, position: usize, message: String, caret: String },

    #[error("XPath evaluation error in {context}: {message}")]
    XPathEval { context: String, message: String },

    #[error("unknown phase {phase:?}; the schema defines: {available}")]
    UnknownPhase { phase: String, available: String },

    #[error("unsupported query binding {binding:?}; this crate implements XPath 1.0 (xslt, xpath)")]
    UnsupportedQueryBinding { binding: String },

    #[error("include cycle: {chain}")]
    IncludeCycle { chain: String },

    #[error("include depth limit of {limit} exceeded at {href}")]
    IncludeDepth { limit: usize, href: String },

    #[error("cannot resolve {href}: {message}")]
    Resolve { href: String, message: String },
}
```

## Error message quality

An XPath syntax error prints a caret under the offending character:

```
XPath syntax error in rule[@context='invoice']/assert[1]/@test: expected ')'
  expression: count(line[@qty > 0) > 0
                                 ^
```

The `context` string is a human-readable path to the schema construct, built
during compilation: `pattern[@id='lines']/rule[@context='line']/assert[2]/@test`.

`Error` is `#[non_exhaustive]`, so variants can be added without a breaking
change; match with a `_` arm.

## What is an error versus a finding

A **finding** is a failed assertion: the document broke a rule. It goes in the
`Report`, not in `Result::Err`.

An **error** is the crate being unable to do its job: the schema is malformed,
the document is not well-formed, an expression does not compile, a variable is
unbound. It goes in `Result::Err`.

A false assertion is never an error, and an error is never silently converted
into a false assertion. Doing the latter would let a broken schema report a
clean bill of health.