Six-point-three seconds became forty milliseconds, and a graphics format with no Pure-Rust home before now has one.
Today we released OxiXML 0.1.1 — a hardening release that finishes the query/transform tier against its W3C suites, adds a typed SVG document model, and makes arbitrary-precision xs:integer/xs:decimal the workspace default.
No C, no C++, no Fortran — still the same zero-external-crates-by-default Pure-Rust workspace introduced at 0.1.0. 0.1.1 breaks compatibility with 0.1.0 deliberately and ships no compatibility shims: 0.1.0 is superseded and is being yanked from crates.io, so 0.1.1 is the version to depend on. It compiles to a single static binary, targets WASM, and runs everywhere.
Why OxiXML 0.1.1 is a game changer
At 0.1.0, four things were true that don’t hold anymore:
- No Pure-Rust SVG document model existed anywhere in the workspace — every COOLJAPAN project that needed to emit SVG hand-rolled its own unescaped
format!("<svg …")string. - The XSLT run-time rebound every global variable, by value, into a fresh binding chain for every expression evaluated and every pattern matched — a stylesheet that read a large document into a global recopied it on every single use.
fn:xml-to-jsonsilently took the first element child of a two-element document instead of raising the error the specification requires.- An unbounded RSA public exponent let a crafted key turn one signature-verify or key-transport call into seconds of CPU time.
0.1.1 ends all of that:
- A typed SVG 1.1/2.0 document model (
oxixml-svg) — parse/build/lint over anoxixml-domtree, exact Bézier/arc geometry, a CSS cascade, an 88-element/216-attribute vocabulary check, and anoxixml-cli svgsubcommand. - Global variables now cost nothing per expression. Measured on one binary: 2,000 stylesheet-function calls over a large global, 6.337s → 40.7ms — roughly 156× faster, from one shared, immutable binding chain instead of a per-evaluation copy.
- Arbitrary-precision
xs:integer/xs:decimalby default — unbounded arithmetic, casts in both directions, large ranges, and exact map-key semantics;fn:unsignedLongnow reachesu64::MAX. - The query/transform tier locked to its W3C suites: XPath 21,731/21,731 (100%), XQuery 29,744/29,744 (100%), XSLT 98.9% (7,340/7,420 adjudicated, four byte-identical runs), XSD 1.0 99.9% / XSD 1.1 99.9% — every failing case named, classed, and evidenced in an in-repo expected-failure ledger, checked in both directions.
- RSA exponent denial-of-service closed —
oxixml-dsig/oxixml-enccap public exponents at 256 bits before anymodpowruns.
Technical Deep Dive: four fronts
- SVG, built on the existing tree.
oxixml-svgadds no new tree type —SvgDocument/SvgElementsit overoxixml-dom, so the same namespace-aware, serialization-safe core that parses arbitrary XML also parses SVG. A geometry engine computes bounding boxes, arc length, and point-at-length per SVG Appendix F math; a CSS cascade covers a documented selector subset; the linter carries 18 diagnostic codes. - Numbers without a ceiling. New
BigInteger/BigDecimalatomics inoxixml-infosetthread through casts, largetoranges, and map-key /distinct-values/index-of/ sort semantics — fixed-width in-range values stay byte-identical, so this is pure added capability, not a performance regression. - Correctness the conformance suites forced. A cooperative deadline (
EvaluationLimits::declare_deadline,Parameters::with_deadline) stops a runaway expression or stylesheet with the spec’s ownXPDY0130code, checked between evaluation steps rather than on a hard-kill timer.fn:transformlets a stylesheet invoke another XSLT processor.xsl:apply-imports/xsl:next-matchnow search the correct import-precedence window, so an overridden rule can’t re-match itself. - Security hardening in
oxixml-dsig/oxixml-enc. DSA and ECDSA (P-256/P-384) sign+verify with RFC 6979 deterministic nonces, RSASSA-PSS sign+verify, RFC 5280 X.509 certification-path validation via a publicPathValidator, and ECDH-ES/DH-ES key agreement via ConcatKDF — alongside the RSA exponent cap above.
Getting Started
Add the new SVG crate:
cargo add oxixml-svg
use oxixml_svg::{Length, LengthUnit, Linter, Rect, SvgBuilder, SvgDocument};
fn main() {
// Parse a document and read a typed presentation attribute.
let doc = SvgDocument::parse_str(
r#"<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100">
<rect x="10" y="20" width="50" height="30"/>
</svg>"#,
)
.expect("well-formed SVG");
assert_eq!(doc.width(), Some(Ok(Length::new(200.0, LengthUnit::None))));
// Compute the rect's bounding box through the geometry engine: turn it
// into its equivalent path, then measure that path.
let rect = doc.svg_element().children().next().expect("the rect element");
let ctx = oxixml_svg::values::length::LengthContext::default();
let path = oxixml_svg::tree::shapes::equivalent_path(rect, &ctx)
.expect("rect is a recognized shape")
.expect("its geometry attributes are all valid");
let bbox =
oxixml_svg::geometry::path_ops::bounding_box(&path).expect("a non-empty rect has a bbox");
assert_eq!(bbox, Rect::new(10.0, 20.0, 50.0, 30.0).expect("a valid rect"));
// Lint the document: nothing here is unknown, deprecated, or dangling.
let diagnostics = Linter::new().lint(doc.document());
assert!(diagnostics.is_empty());
}
Or pull it in through the facade instead of the standalone crate:
[dependencies]
oxixml = { version = "0.1.1", features = ["svg"] }
What’s New in 0.1.1
Breaking
oxixml-hdt:BitmapTriples::writereturnsResult; a newHdtError::NonDenseSubjectIdsvariant replaces silent renumbering of a gapped-subject structure.oxixml-dsig:KeyInfoItem::DsaKeyValue/EcKeyValuebecame struct variants carrying real key material (DsaKeyValue { p, q, g, y },EcKeyValue { named_curve, public_key }).oxixml-regex:Regex::xpathnow reads character classes against XSD 1.0 specifically — the version this processor reports.Regex::xpath_versioned(pattern, flags, version)is the new escape hatch for an XSD 1.1 host.- A round of F&O/XPath behavior corrections:
fn:xml-to-jsonerror handling, XML-whitespace-only list tokenization (not Unicode whitespace),fn:idrefno longer tokenizing its argument, a correctedKindTest::is_subtype_ofsubtype judgement, and exact (non-promoting) map-key comparison.
Added
- New crate
oxixml-svg(above), arbitrary-precisionxs:integer/xs:decimal, the cooperative deadline mechanism,fn:transform,json/adaptiveXSLT output methods, and the DSA/ECDSA/RSASSA-PSS/X.509/ECDH-ES additions tooxixml-dsig/oxixml-enc.
Fixed
- The 156× global-variable binding-chain rewrite (above).
- XSLT base-URI rules on copies,
fn:snapshotof a parented attribute/namespace node for XPath and XQuery callers (not just throughoxixml-xslt), and a version-selector-inheritance defect in the XML Schema Test Suite harness that had been silently grading XSD 1.1 syntax under 1.0.
Full itemized detail is in the CHANGELOG.
Tips
- Update
oxixml-dsigKeyInfoItemmatches.DsaKeyValue/EcKeyValueare struct variants now, not unit variants — anywhere you pattern-match them needs the field list. - Bound a runaway query or transform with a real deadline, not a watchdog thread.
EvaluationLimits::declare_deadline(Instant::now() + Duration::from_secs(30))for XPath/XQuery,Parameters::new().with_deadline(Instant::now() + Duration::from_secs(5))for XSLT — both raiseXPDY0130between evaluation steps, so an evaluation with no deadline never even reads the clock. - Implementing XSD 1.1 and calling
Regex::xpathdirectly? Switch toRegex::xpath_versioned. The unversioned call now unconditionally reads XSD 1.0 character classes. oxixml-svg’s geometry engine answers bounding-box/length questions without rasterizing. If you only need “what space does this path occupy,”geometry::path_ops::bounding_boxis cheaper than round-tripping through a renderer.- Re-check any code that relied on numeric map-key promotion. Two integers that round to the same
xs:doubleare now distinct map keys under exact-value comparison;eq/compare/fn:distinct-valueskeep their existing promotion semantics unchanged. oxixml-cli svgadds SVG-aware lint, statistics, and pretty/minified re-serialization — runoxixml svg --helpfor the full flag reference.
This is the foundation
OxiXML depends on nothing else in the ecosystem, so any project can adopt it without a dependency cycle. OxiRS, OxiGeo, OxiMedia, Legalis-RS, and every COOLJAPAN project migrating off quick-xml or an Oxigraph crate sit on top of it tier by tier — and now so does anything that needs to emit or read SVG without hand-rolling its own escaping.
Repository: https://github.com/cool-japan/oxixml
Star the repo if you want SVG, unbounded-precision numbers, and a query/transform tier held to a byte-identical, four-run conformance ledger — in Rust, with no JVM or C library underneath.
The era of hand-rolled SVG strings and silently-recopied global variables is over. Pure Rust XML and RDF — complete, conformant, and sovereign — is here.
— KitaSan at COOLJAPAN OÜ August 6, 2026