Working with XML in Rust: Library Overview and Practical Examples
Rust is a modern systems programming language increasingly used for building high-load web services, command-line tools, and embedded systems. When working with data, the need to process XML documents often arises. Unlike Python, where the standard library xml.etree.ElementTree covers most tasks, the Rust ecosystem offers several specialized crates with different approaches. In this article, we will look at three of the most popular tools for working with XML in Rust: roxmltree, quick-xml, and serde-xml-rs.
1. roxmltree — Fast and Safe Read-Only Parser
roxmltree is a crate designed exclusively for reading XML. It does not support mutation or document creation, but it provides a very fast and reliable parser with full namespace support. The main advantage is working with borrowed data (zero-copy), which minimizes memory allocation.
// cargo add roxmltreeuse roxmltree::Document;
fn main() -> Result<(), roxmltree::Error> { let xml = r#" <root> <item id="1">First element</item> <item id="2">Second element</item> </root>"#;
let doc = Document::parse(xml)?;
// Get the root element let root = doc.root_element(); println!("Root element: {}", root.tag_name().name());
// Find all child <item> elements for item in root.children().filter(|n| n.has_tag_name("item")) { let id = item.attribute("id").unwrap_or("unknown"); let text = item.text().unwrap_or(""); println!("ID: {}, Text: {}", id, text); }
Ok(())}When to use: If you only need to read XML files (configurations, API responses, RSS feeds) and maximum performance is important. roxmltree is ideal for one-time parsing.
2. quick-xml — Universal Parser with Read and Write Support
quick-xml is the most popular crate for working with XML in Rust. It supports both parsing (event-driven and DOM-like) and serialization (writing) of XML. It works with streams (Reader) as well as entire strings. It supports attributes, CDATA, comments, and escape sequences.
// cargo add quick-xmluse quick_xml::Reader;use quick_xml::events::Event;
fn main() -> Result<(), quick_xml::Error> { let xml = r#"<library> <book genre="rust">Programming in Rust</book> <book genre="python">Python for Beginners</book></library>"#;
let mut reader = Reader::from_str(xml); reader.trim_text(true); let mut txt = String::new(); let mut current_genre = String::new();
loop { match reader.read_event_into(&mut txt) { Ok(Event::Start(ref e)) => { if e.name().as_ref() == b"book" { // Get the genre attribute if let Some(attr) = e.attributes().flatten().find(|a| a.key.as_ref() == b"genre") { current_genre = String::from_utf8_lossy(&attr.value).to_string(); } } } Ok(Event::Text(ref e)) => { let text = e.unescape()?; println!("Genre: {}, Title: {}", current_genre, text); } Ok(Event::Eof) => break, Err(e) => panic!("Error: {:?}", e), _ => {} } txt.clear(); } Ok(())}When to use: If you need flexibility — reading large files streamingly, creating new XML documents or