Vendored ODNI public XML schemas, deduplicated and consolidated, split
into one crate per ODNI package. Designed to be consumed as
[build-dependencies] by Rust projects that codegen Rust types from
the ODNI XSDs (e.g. Marque).
The workspace ships 60 ODNI packages (~700 MB of schemas, schematron, XSL, and supporting docs) split across 60 per-package crates plus a metadata-only meta-crate (61 crates).
ism-data/ (workspace root)
Cargo.toml ← virtual workspace
README.md
SECURITY.md ← threat model + consumer hardening
provenance.toml ← upstream ODNI snapshot info + zip hashes
crates/
ism-data/ ← metadata-only meta crate
Cargo.toml
src/lib.rs ← PACKAGES list + namespace registry
ism-ismcat/ ← one crate per ODNI package
Cargo.toml
build.rs ← verifies its data/ slice at compile time
src/lib.rs ← package API
data/ ← ISMCAT files only
ISMCAT/...
_provenance/
manifest.txt ← SHA-256 of every file under data/
manifest.sha256 ← SHA-256 of manifest.txt itself
ism-ic-edh/
ism-base-tdf/
... (59 total per-package crates)
tools/ ← regen + reproduce scripts
.github/workflows/ ← integrity + reproduce CI
Per-package crate names are ism-{lowercased}:
| ODNI package | Crate name |
|---|---|
| ISMCAT | ism-ismcat |
| IC-Docbook | ism-ic-docbook |
| BASE-TDF | ism-base-tdf |
| RR-SM | ism-rr-sm |
| RevRecall | ism-revrecall |
Within each package, the directory shape is exactly what ODNI ships in
their *-Public-Standalone.zip, so all relative xs:import /
schemaLocation references resolve as the schemas' authors intended.
Add only the per-package crates your codegen needs as
[build-dependencies]. A small allowlist of crates is published to
crates.io (see tools/published.toml); everything
else is reachable only via git dependency. To detect at runtime which
packages are crates.io-reachable, use ism_data::is_published(pkg).
# crates.io (preferred when available)
[build-dependencies]
ism-data = "20230609.0.0"
ism-ismcat = "20230609.0.0"
ism-ic-edh = "20230609.0.0"
# OR, git tag (any package, including those not on crates.io)
[build-dependencies]
ism-data = { git = "https://github.com/marquetools/ism-data", tag = "v20230609.0.0" }
ism-ismcat = { git = "https://github.com/marquetools/ism-data", tag = "v20230609.0.0" }
ism-ic-edh = { git = "https://github.com/marquetools/ism-data", tag = "v20230609.0.0" }// build.rs
fn main() {
// Per-package crate API: get a path to a specific schema.
let xsd = ism_ismcat::package_root().join("Schema/ISMCAT/ISMCAT.xsd");
println!("cargo:rerun-if-changed={}", xsd.display());
// Meta crate: resolve a namespace to (package, relpath).
let (pkg, rel) = ism_data::resolve_namespace("urn:us:gov:ic:edh")
.expect("IC-EDH namespace is part of the ODNI set");
assert_eq!(pkg, "IC-EDH");
let edh_xsd = ism_ic_edh::package_root().join(rel);
// Pass to your codegen.
my_codegen::generate_rust(&xsd);
my_codegen::generate_rust(&edh_xsd);
}Every ism-{pkg} crate exposes:
pub const PACKAGE_NAME: &str; // e.g. "ISMCAT"
pub const MANIFEST_DIGEST: &str; // SHA-256 of data/_provenance/manifest.txt
pub const FILE_COUNT: usize; // count of files under data/
pub fn data_root() -> PathBuf; // -> .../crates/ism-ismcat/data
pub fn package_root() -> PathBuf; // -> .../crates/ism-ismcat/data/ISMCAT
pub fn resolve_namespace(uri: &str) -> Option<PathBuf>;
pub fn known_namespaces() -> impl Iterator<Item = (&'static str, &'static str)>;
pub fn verify_integrity() -> Result<usize, VerifyError>;
pub fn verify_file(rel: &str) -> Result<(), VerifyError>;env!("CARGO_MANIFEST_DIR") resolves at the consumer's build time to
the location where Cargo placed the per-package crate's source —
typically inside ~/.cargo/git/checkouts/ when consumed as a git
dependency. That's exactly where the data files live, so paths Just
Work.
ism-data (the meta crate) carries no schema files. It exposes:
pub const PACKAGES: &[&str]; // 59 ODNI package names
pub fn resolve_namespace(uri: &str) -> Option<(&'static str, &'static str)>;
pub fn package_for_namespace(uri: &str) -> Option<&'static str>;
pub fn relpath_for_namespace(uri: &str) -> Option<&'static str>;
pub fn known_namespaces() -> impl Iterator<Item = (&'static str, &'static str, &'static str)>;
pub fn crate_name_for(package: &str) -> Option<String>; // e.g. "ISMCAT" -> "ism-ismcat"Every per-package crate's build.rs re-hashes every file under its own
data/ against data/_provenance/manifest.txt at the consumer's
compile time and refuses to compile on mismatch. A single modified byte
under crates/ism-ismcat/data/ breaks any consumer's build of that
crate. See SECURITY.md for the full threat model.
For runtime checks, use verify_integrity() / verify_file(rel) on
the per-package crate, or MANIFEST_DIGEST for external attestation.
The workspace version (Cargo.toml's [workspace.package].version)
tracks the date stamp of the latest ISM package in the upstream ODNI
snapshot consolidated. All per-package crates inherit it via
version.workspace = true. Bump it whenever you re-vendor.
Three GitHub Actions workflows live under .github/workflows/:
- integrity.yml — runs on every PR and weekly. Re-derives every
per-crate manifest from
crates/*/data/, diffs against the committed manifests, runscargo test --workspace --all-features -- --ignored(which exercises the full-tree integrity check across every crate). Prevents drift between any crate'sdata/and itsmanifest.txt. - check-upstream.yml — weekly cron, plus manual trigger. Runs
tools/check_upstream.pyto HEAD-check known ODNI zip URLs and scrape the standards listing page; opens a tracking issue when changes are detected. Configure the URLs intools/upstream_baseline.jsononce before this workflow becomes useful. - reproduce-from-zips.yml — manual trigger. Given a URL to a
bundle of the upstream zips, downloads them, verifies against
provenance.toml, runs the per-package consolidation, and asserts every per-crate manifest matches the committed one. The strongest available proof that "what we vendored" came from "what ODNI published".
When ODNI publishes new package versions, see
.github/ISSUE_TEMPLATE/upstream-update.md for the full re-vendor
checklist. The high-level flow:
- Download the new
*-Public-Standalone.zipfiles. - Run the consolidation script (lives in the parent project at
_meta/consolidate.py) to produce a deduplicated tree. - Move the tree under
crates/ism-<pkg>/data/<PKG>/for every package. - Run
tools/rederive_manifest.py --writeto regenerate every per-cratemanifest.txt,manifest.sha256, andMANIFEST_DIGEST. - Bump
[workspace.package].versionin the workspaceCargo.toml. - Update workspace
provenance.tomlwith the new snapshot date and upstream zip hashes. - If new packages appear, scaffold them with
tools/split_into_crates.pyand add tocrates/ism-data/src/lib.rsPACKAGESconst. - Commit, tag, push.
235 namespaces have a canonical-path mapping baked into the meta crate. Iterate them all:
for (uri, pkg, rel) in ism_data::known_namespaces() {
println!("{} -> {} / {}", uri, pkg, rel);
}Namespaces from upstream standards (W3C XLink, GML, DocBook, etc.) that happen to appear in the bundled schemas are present in the table when ODNI redistributes them — those entries point at the ODNI-bundled copy. If you need authoritative upstream behavior, point your XML library at the appropriate upstream catalog separately.
- No runtime parsing or validation. This workspace is data + path
helpers only. Pair it with
quick-xml,xmlschema,roxmltree, or whatever XML library suits your codegen. - No XML catalog file. Cargo doesn't have a clean way to surface
static asset paths to non-Rust tools. If you need a catalog, it's
trivial to generate one from
ism_data::known_namespaces()at build time.
Compressed git clone of this repo runs around 50–80 MB; git's delta
compression collapses the redundant content very efficiently. The
working-tree size after clone is ~700 MB across all 59 crates. For a
workspace consumed only at build time, this is acceptable — and
consumers that publish individual crates to crates.io can ship
just the slices they need.
Schemas are U.S. Government public-domain works. Crate scaffolding
(Rust source, build scripts, CI, config) is dual-licensed under MIT-0
or Unlicense. See LICENSES/ and the LICENSE-* files.