xmlschema 0.0.3

XML Schema (XSD) validation for Rust, with zero unsafe code
Documentation

[!NOTE] The rewrite has landed. Schema parsing, structural validation, simple types with restriction facets, and xs:pattern all work; see Status for exactly what is and is not supported.

0.0.1 on crates.io is the old crate, which exposed no public API at all. Do not use it.

Contents

Getting started

  • Status — what works today, honestly
  • Install — once there is something to install

Reference

Practical


Status

State
Schema parsing ✅ elements, sequence, choice, cardinality, attributes
Simple types ✅ nine built-ins, nine restriction facets
xs:pattern ✅ own engine, XSD dialect
Diagnostics ✅ every violation, each with a path
Tests ✅ 27
xs:all
xs:import / include
Identity constraints
Complex-type derivation

An unsupported construct is skipped rather than rejected: the surrounding rules still apply, so a schema using xs:all validates everything else correctly instead of failing wholesale.

Install

[dependencies]
xmlschema = { git = "https://github.com/sebastienrousseau/xmlschema" }
oxml = { git = "https://github.com/sebastienrousseau/oxml" }

Published releases follow once the suite cuts its first version together.

Quick Start

use xmlschema::{parse_schema, validate};

let xsd = r#"
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="book">
      <xs:complexType>
        <xs:sequence>
          <xs:element name="title" type="xs:string"/>
        </xs:sequence>
        <xs:attribute name="lang" type="xs:string" use="required"/>
      </xs:complexType>
    </xs:element>
  </xs:schema>
"#;

let schema = parse_schema(xsd)?;
let doc = oxml::parse("<book lang='en'><title>Dune</title></book>")?;

assert!(validate(&doc, &schema).is_valid());
# Ok::<(), Box<dyn std::error::Error>>(())

Every violation is reported, each with a path:

/invoice/issued — `22/08/2026` is not a valid date (YYYY-MM-DD)
/invoice/line[1]/@currency — `pounds` does not match the pattern `[A-Z]{3}`
/invoice/line[1]/amount — -5 must be greater than 0
/invoice/line[2] — missing required attribute `currency`
/invoice/line[2]/amount — `not a number` is not a valid decimal

Why this crate exists

Rust has no pure-Rust XSD validator. The options today are:

  • libxml — bindings to libxml2. Complete and battle-tested, but it is C: it needs a build toolchain, contains unsafe, does not work in WebAssembly, and inherits libxml2's CVE stream.
  • Nothing else. There is no maintained pure-Rust implementation.

For a project already committed to safe Rust — no C toolchain, WASM targets, an auditable dependency tree — that is not a choice so much as an absence.

xmlschema exists to close it, with the same constraints as the rest of the suite: #![forbid(unsafe_code)], no FFI, no C.

The oxml ecosystem

Every member ships the same version number, so there is never a compatibility table to consult.

Crate What it is Status
oxml Core — parser, tree, XPath 1.0 Available
oxml-cli Command-line querying and formatting Planned
oxml-lsp Language server Planned
oxml-mcp Model Context Protocol server Planned
oxml-wasm WebAssembly bindings Planned
xmlschema XSD validation Being rewritten

This crate keeps its published name rather than being folded into oxml. The name means XSD validation specifically, and repurposing it into a general toolkit would have handed existing users something entirely different under a name they already depend on.

Ecosystem comparison

Crate XSD validation Pure Rust WASM Last release
xmlschema planned 2023 (unusable)
libxml ✗ (C-FFI) active
quick-xml active
roxmltree active
xot 2025

Planned capabilities

In order:

  1. Schema parsing — read an .xsd into a usable model, built on oxml's tree.
  2. Structural validation — elements, attributes, cardinality, sequence/choice/all.
  3. Simple type validation — the built-in datatypes, restrictions, patterns, enumerations.
  4. Complex types — extension, restriction, mixed content.
  5. Diagnostics — every violation reported with an element path and a reason, so a caller can fix all of them in one pass rather than probing one failure at a time.

Import mechanisms (xs:import, xs:include, xs:redefine) come after the core is correct, because they multiply the surface without adding validation power.

Development

git clone https://github.com/sebastienrousseau/xmlschema
cd xmlschema
cargo test

Security

XSD validation is normally applied to untrusted documents, which makes the parser's threat model part of this crate's threat model. It inherits oxml's posture:

  • No entity expansion. Only the five predefined entities and numeric character references are resolved, so XXE and billion-laughs are foreclosed by construction rather than by a flag.
  • No unsafe. #![forbid(unsafe_code)], enforced at compile time.

Report vulnerabilities privately — see SECURITY.md.

Documentation

Acknowledgements

  • libxml2 — the reference implementation, and the yardstick for behaviour.
  • W3C — for the XML Schema specification.
  • python-xmlschema — proof that a readable, standalone XSD implementation is achievable.

License

Licensed under either of

at your option.