Architecture & Trade-offs
Comparing oxml to Rust XML Peers
An honest, technical assessment of architectural trade-offs across quick-xml, roxmltree, xot, xee, and libxml2. When to choose oxml, and when to pick an alternative.
Ecosystem Capability Matrix
Every XML library makes deliberate trade-offs between memory footprint, mutation capability, streaming throughput, and query ergonomics. The table below compares the primary Rust XML libraries as of October 2026.
| Capability | oxml | quick-xml | roxmltree | xot | xee |
|---|---|---|---|---|---|
| Primary Model | Mutable Arena DOM | Pull Parser (Streaming) | Read-Only Slice Tree | Mutable Arena Tree | Read-Only Tree |
| Memory Safety | #![forbid(unsafe_code)] | Safe Rust | Safe Rust | Safe Rust | Safe Rust |
| DOM Mutation | O(1) Generational | None (Event Stream) | None (Read-Only) | Arena Mutation | None (Read-Only) |
| XPath Support | W3C XPath 1.0 | None | None (Cursor only) | None (Cursor only) | W3C XPath 3.1 |
| XML Schema (XSD) | Partial (95.2% W3C) | None | None | None | None |
| WebAssembly | Native (<220 KB) | Supported (Reader) | Supported (Read-Only) | Supported (Tree) | Supported (Engine) |
| AI Agent (MCP) | Native (oxml-mcp) | None | None | None | None |
| Core Dependencies | 0 (Parser core) | 0 (Minimal) | 0 (Minimal) | Minimal | Minimal |
Head-to-Head Deep Dive
1. oxml vs quick-xml
quick-xml strengths: With over 379 million downloads, quick-xml is the performance standard for raw streaming pull-parsing in Rust. Because it does not build an in-memory document tree, it achieves streaming throughputs between 1.2 GB/s and 1.5 GB/s with near-zero heap allocations. If you are processing 50 GB log files, financial transaction streams, or running batch ETL where elements are processed and discarded immediately, quick-xml is the best choice.
Where oxml wins: quick-xml does not provide a DOM, XPath evaluation, or schema validation. If your application needs to locate nodes via XPath expressions (such as //soap:Body//m:GetStockPrice), mutate node attributes, re-order children, or serialize formatted XML, quick-xml requires you to implement your own tree data structures. oxml provides a high-level, generational arena DOM with full XPath 1.0 evaluation out of the box.
2. oxml vs roxmltree
roxmltree strengths: roxmltree (>66M downloads) is an exceptionally mature, read-only XML tree representation. By intentionally forbidding mutation and node insertion, it stores the document as a contiguous array of node descriptors referencing the original input string. Memory consumption is predictably low (typically 1.5x to 2x the raw document size), and document parsing is fast and memory-efficient.
Where oxml wins: roxmltree is strictly read-only. You cannot add children, update text, rename tags, or delete elements. Furthermore, roxmltree does not include an XPath engine; queries must be performed manually using Rust iterator methods (e.g. node.children().filter(...)). oxml combines mutable arena operations with standard XPath 1.0 queries and XSD validation.
3. oxml vs xot
xot strengths: xot is a mutable XML tree library that treats XML namespaces, prefixes, and comments as first-class citizens. Like oxml, it uses an arena allocation pattern to avoid pointer indirection and reference counting cycles.
Where oxml wins: oxml ships as an integrated ecosystem: a pure-Rust XPath 1.0 engine, partial W3C XML Schema validation (xmlschema), WebAssembly bindings, a developer CLI tool, and an MCP server for AI agents, all versioned together without dependency mismatches.
4. oxml vs xee
xee strengths: xee (developed by Paligo) is the premier pure-Rust implementation of W3C XPath 3.1 and partial XSLT 3.0. If you require XPath 2.0 or 3.1 capabilities—including regular expression functions (fn:matches), sequence operations, dynamic maps, arrays, or XSLT transformation templates—xee is the library to choose.
Where oxml wins: oxml targets W3C XPath 1.0 and pairs it with mutable DOM manipulation, partial XSD validation, and cross-platform runtimes (WASM, CLI, MCP). If you do not require XPath 3.1 constructs, oxml provides a unified, zero-unsafe package.
5. oxml vs lxml & libxml2
libxml2 / lxml context: libxml2 is the venerable C library underlying Python's lxml, R's xml2, and PHP's XML extensions. In 2025, libxml2 experienced a maintainer transition that highlighted long-standing security challenges inherent in large legacy C codebases (buffer overflows, integer overflows, memory exhaustion, and use-after-free bugs).
Where lxml wins: Decades of maturity, full XSLT 1.0 support, Schematron, RelaxNG, and complete Python ecosystem integration.
Where oxml wins: Complete memory safety enforced by #![forbid(unsafe_code)] at compile time. Pure Rust ensures that untrusted XML inputs cannot trigger undefined behavior, memory corruption, or remote code execution. oxml compiles cleanly to WebAssembly without Emscripten C runtime shims and provides a native Model Context Protocol (MCP) server for modern AI agent integrations.
When Not to Use oxml — Honestly
We believe engineering honesty builds long-term trust. We explicitly recommend choosing alternative tools under the following conditions:
- Multi-Gigabyte Streaming Pipelines: If your input files exceed available RAM or you only need to extract values sequentially without building a DOM, use
quick-xml. - Strict Read-Only Document Crawling: If you only need to inspect small-to-medium documents without modifying them or running XPath queries, use
roxmltreefor minimal memory consumption. - XPath 3.1 and XSLT Transformations: If you require XPath 3.1 functions, sequence comprehension, or XSLT stylesheets, use
xeeorSaxon. - Exhaustive XSD 1.1 with Complex Redefines: If you depend on edge-case XSD 1.1 features or complex schema redefinitions, use
libxml2orSaxonuntilxmlschemaachieves 100% W3C coverage.