Skip to content

Rust API

The complete rustdoc for the crate is published alongside this site.

Open the Rust API reference

The shape of it

src/lib.rs re-exports everything that is public API. If a name is not re-exported there, it is not part of the compatibility promise.

Start at For
SchemaSetBuilder Reading documents into a schema set
Compilation What compiling produced: the components and every diagnostic
Schemas The compiled model, and every query over it
ElementRef Following a schema without touching an id
DocumentValidator Checking a document, and the typed PSVI
ValueValidator Checking one lexical form against a simple type
Diagnostics What went wrong, with codes and spans
Value A typed XSD value

Modules worth knowing

Module
model The component types and Schemas itself
refs The navigable view: ElementRef, TypeRef, ChildRef
content Content models, matching, UPA
instance Streaming validation and the PSVI
decode A validated document as a typed tree, every qualified name kept
values Typed values and facet checking
atomic The 14 datatypes implemented from the specification
datatypes The 50 built-ins and their derivation graph
diagnostics Codes, severities, spans
names Interned qualified names
regex XSD patterns, transpiled

Configuration — Version, Conformance, Resolver, FileResolver — lives at the crate root rather than in a module named after the phase that consumes it.

Two ways to reach a component

Components are held in arenas and addressed by Copy ids — TypeId, ElementId, ParticleId and the rest. A component graph is cyclic (a type can contain an element of that type), so Rust references would mean Rc<RefCell<…>> everywhere; ids keep the model Send + Sync, cheap to copy, and cheap to compare.

Ids are not what you want to ask questions with, though, so there is a view over them. An ElementRef is a borrow of the schema plus an id — two words, Copy, no allocation and no reference counting — and following one reads the way the schema reads:

use xsdkit::Schemas;

fn describe(schemas: &Schemas) -> Option<()> {
    let report = schemas.element(Some("urn:example"), "report")?;
    for child in report.children() {
        println!("{}: {}", child.local_name(), child.type_of().display_name());
    }
    Some(())
}

The arena underneath is never more than a method call away. Index is implemented for every id, name lookups have _id forms that hand ids back, and Schemas::get turns an id into a reference:

use xsdkit::{ElementId, Schemas};

fn by_id(schemas: &Schemas, element: ElementId) {
    let decl = &schemas[element];             // the raw component
    let ty = &schemas[decl.type_id];
    let same = schemas.get(element);          // …or a reference to it
    assert_eq!(same.name(), decl.name);
}

An id from one Schemas used against another is a programming error, not a runtime check — treat them as belonging to the set they came from. References carry their schema, so comparing two of them accounts for it.

Cargo features

Feature
serde Serialize/Deserialize for Schemas, so a large schema set is compiled once and loaded thereafter
python Builds the PyO3 extension module; not for library use

Doc comments are the reference

The crate is documented inline and the docs build runs with RUSTDOCFLAGS="-D warnings" in CI, so a broken intra-doc link fails the build rather than rotting quietly. The Rust snippets on this site are compiled too, by scripts/check-doc-snippets.py, for the same reason.

cargo doc --open