Xmloxide: A Rust Reimplementation of libxml2 Created with AI Agent Assistance

What is Xmloxide?
Xmloxide is a pure Rust reimplementation of libxml2, the widely used C library for parsing, creating, and manipulating XML and HTML documents. The project was created after libxml2 became officially unmaintained in December 2025 with known security issues. The developer used Claude Code to reproduce the library by having the AI agent work against existing test suites until they passed.
Key Features and Capabilities
- Memory-safe — arena-based tree with zero unsafe in the public API
- Conformant — 100% pass rate on the W3C XML Conformance Test Suite (1727/1727 applicable tests)
- Error recovery — parse malformed XML and still produce a usable tree, just like libxml2
- Multiple parsing APIs — DOM tree, SAX2 streaming, XmlReader pull, push/incremental
- HTML parser — error-tolerant HTML 4.01 parsing with auto-closing and void elements
- XPath 1.0 — full expression parser and evaluator with all core functions
- Validation — DTD, RelaxNG, and XML Schema (XSD) validation
- Canonical XML — C14N 1.0 and Exclusive C14N serialization
- XInclude — document inclusion processing
- XML Catalogs — OASIS XML Catalogs for URI resolution
- xmllint CLI — command-line tool for parsing, validating, and querying XML
- Zero-copy where possible — string interning for fast comparisons
- No global state — each Document is self-contained and Send + Sync
- C/C++ FFI — full C API with header file (include/xmloxide.h) for embedding in C/C++ projects
- Minimal dependencies — only encoding_rs (library has zero other deps; clap is CLI-only)
Performance and Compatibility
Performance is similar to libxml2 on most parsing operations and better on serialization. The library passes the compatibility suite as well as the W3C XML Conformance Test Suite.
Code Examples
Basic parsing:
use xmloxide::Document;
let doc = Document::parse_str("<root><child>Hello</child></root>").unwrap();
let root = doc.root_element().unwrap();
assert_eq!(doc.node_name(root), Some("root"));
assert_eq!(doc.text_content(root), "Hello");
Serialization:
use xmloxide::Document;
use xmloxide::serial::serialize;
let doc = Document::parse_str("<root><child>Hello</child></root>").unwrap();
let xml = serialize(&doc);
assert_eq!(xml, "<root><child>Hello</child></root>");
XPath queries:
use xmloxide::Document;
use xmloxide::xpath::{evaluate, XPathValue};
let doc = Document::parse_str("<library><book><title>Rust</title></book></library>").unwrap();
let root = doc.root_element().unwrap();
let result = evaluate(&doc, root, "count(book)").unwrap();
assert_eq!(result.to_number(), 1.0);
SAX2 streaming:
use xmloxide::sax::{parse_sax, SaxHandler, DefaultHandler};
use xmloxide::parser::ParseOptions;
struct MyHandler;
impl SaxHandler for MyHandler {
fn start_element(&mut self, name: &str, _: Option<&str>, _: Option<&str>, _: &[(String, String, Option<String>, Option<String>)]) {
println!("Element: {name}");
}
}
parse_sax("<root><child/></root>", &ParseOptions::default(), &mut MyHandler).unwrap();
HTML parsing:
use xmloxide::html::parse_html;
let doc = parse_html("<p>Hello <br> World").unwrap();
let root = doc.root_element().unwrap();
assert_eq!(doc.node_name(root), Some("html"));
Error recovery:
use xmloxide::parser::{parse_str_with_options, ParseOptions};
let opts = ParseOptions::default().recover(true);
let doc = parse_str_with_options("<root><unclosed>", &opts).unwrap();
for diag in &doc.diagnostics {
eprintln!("{}", diag);
}
CLI Usage
The xmllint CLI tool provides:
# Parse and pretty-print
xmllint --format document.xml
Validate against a schema
xmllint --schema schema.xsd document.xml
xmllint --relaxng schema.rng document.xml
xmllint --dtdvalid
AI Agent Development Context
The developer experimented with having Claude Code reproduce Redis and SQLite before targeting libxml2. The approach involved tasking the AI agent to work on projects until existing test suites passed. This demonstrates how coding agents can quickly iterate given a test suite, potentially addressing legacy code maintenance problems.
📖 Read the full source: HN AI Agents
👀 See Also

Building a Local Open-Source AI Workspace with Rust and Tauri
Explore a fully local, open-source AI workspace built using Rust, Tauri, and sqlite-vec, without a Python backend.

2026 Hermes Agent Alternatives Roundup: Self-Hosted Options from OpenClaw to memU Bot
A developer who has been running Hermes since launch tested every self-hosted and managed alternative after the ClawHub security mess. Key findings: OpenClaw (370k stars) but 9 CVEs in 4 days and ~20% malicious packages; TrustClaw rebuilt with OAuth/sandboxing; nanobot at ~4K lines Python with MCP; memU Bot with unique structured memory. Managed options include Perplexity Computer (19 models, $200/mo), Claude Cowork (opens real Mac apps), and KimiClaw (40GB RAG, locked to K2.5, Chinese data law). Full roundup at source.

Nia-docs tool creates local filesystem from documentation URLs for Claude AI
The nia-docs tool lets you run npx nia-docs with a documentation URL to create a local filesystem of the docs, which Claude AI can then access directly without additional configuration.

Adeu v1.4: Open-Source MCP for Track Changes in DOCX
Adeu v1.4 surgically injects native OOXML redlines into DOCX files, preserving formatting, numbering, and layouts. Adds footnotes/endnotes inline editing, defined term linting, cross-reference maps, and multi-level list round-tripping.