Migration Guide
Migrating from Python lxml to oxml
Upgrade your XML processing pipelines from Python's C-dependent libxml2 wrapper to pure-Rust memory safety, zero-copy streaming, and true multi-threaded concurrency.
Why Migrate?
Python's lxml has powered XML processing for two decades by wrapping the C libraries libxml2 and libxslt. However, production engineering demands have evolved:
- Memory Safety & Zero Vulnerabilities:
libxml2has suffered numerous CVEs (buffer overflows, use-after-free, memory leaks).oxmlenforces#![forbid(unsafe_code)]with 100% pure, safe Rust. - True Multi-Threading:
lxmlis constrained by Python's Global Interpreter Lock (GIL).oxmlstructures (Document,XPath) implementSendandSync, allowing multi-threaded parsing across CPU cores with Rayon or Tokio. - Painless Cross-Compilation: No C compiler toolchains, system package dependencies (
libxml2-dev), or wheels mismatches across macOS, Linux (glibc/musl), and Windows. - Edge & WebAssembly:
oxmlcompiles directly to WebAssembly (oxml-wasm), enabling identical XML processing in browsers and Cloudflare Workers.
Concept & API Mapping
Python lxml.etree | Rust oxml Ecosystem | Key Advantage |
|---|---|---|
etree.fromstring(xml) | oxml::parse(xml) | Fast generational arena allocation |
etree.parse(file) | oxml::stream::Reader::from_reader(f) | Bounded 34 KB buffer memory footprint |
tree.xpath("//book/text()") | doc.select("//book/text()") | Complete W3C XPath 1.0 with $O(1)$ integer fast-path |
XPath(expr)(tree) | oxml::XPath::compile(expr)? | Precompiled expression reuse across threads |
etree.iterparse(...) | reader.next_borrowed() | Zero-copy &str borrowing directly from buffer |
etree.tostring(el) | oxml::format_xml(doc, ...) | Indentation, minification, and empty element style control |
etree.XMLSchema(xsd).validate(doc) | xmlschema::validate(&doc, &schema) | Pure-Rust XSD validator with 95.2% W3C conformance |
| Custom LLM agent scripts | oxml-mcp | 5 native MCP tools for Claude, Cursor, and AI agents |
Code Comparisons
1. Document Parsing & XPath Queries
In Python with lxml:
=
=
=
# ['Dune']
In Rust with oxml:
use ;
>
2. High-Performance Streaming
In Python, iterparse requires careful manual node clearing (elem.clear()) to avoid unbounded memory expansion:
# Required to free C memory
In Rust with oxml, memory is strictly bounded by design with zero-copy slice borrowing:
use ;
let mut reader = from_reader?;
while let Some = reader.next_borrowed?
3. XML Schema (XSD) Validation
In Python with lxml:
=
=
=
In Rust with xmlschema:
use ;
let schema = parse_schema?;
let doc = parse?;
let report = validate;
if report.is_valid else