
New releaseAug 9, 2026
xmloxide v0.5.0
Uma reimplementação pura em Rust do libxml2
xmloxide
Uma reimplementação pura em Rust do libxml2 — a biblioteca de análise XML/HTML padrão de facto no mundo open-source.
O libxml2 tornou-se oficialmente não mantido em dezembro de 2025, com problemas de segurança conhecidos. O xmloxide visa ser um substituto seguro em termos de memória e de alto desempenho que passa nos mesmos conjuntos de testes de conformidade.
Funcionalidades
- Seguro em termos de memória — árvore baseada em arena com zero
unsafena API pública - Conforme — taxa de aprovação de 100% no W3C XML Conformance Test Suite (1727/1727 testes aplicáveis)
- Recuperação de erros — analisa XML malformado e ainda produz uma árvore utilizável, tal como o libxml2
- Múltiplas APIs de análise — árvore DOM, streaming SAX2, pull XmlReader, push/incremental
- Analisador HTML — análise HTML 4.01 tolerante a erros com fecho automático e elementos vazios
- Analisador HTML5 WHATWG — tokenizer e construtor de árvore completos do HTML Living Standard (8810/8810 testes html5lib-tests aprovados)
- Streaming HTML5 — API de callback semelhante a SAX para HTML5 (
html5::sax) que encapsula o tokenizer sem construir uma árvore DOM - Seletores CSS — consulta elementos com sintaxe CSS familiar (
css::select) incluindo combinadores, pseudo-classes e pesquisa rápida por#id - XPath 1.0+ — analisador de expressões e avaliador completos com todas as funções principais XPath 1.0, mais funções chave do XPath 2.0 (
matches(),replace(),tokenize(),upper-case(),lower-case(),abs(),min(),max()e mais) - Validação — validação DTD, RelaxNG, XML Schema (XSD) e ISO Schematron (ISO/IEC 19757-3)
- Integração Serde — funcionalidade opcional
serdepara (de)serialização XML de/para tipos Rust - Análise assíncrona — funcionalidade opcional
asyncpara análise a partir de fontestokio::io::AsyncRead - XML Canónico — serialização C14N 1.0 e C14N Exclusiva
- XInclude — processamento de inclusão de documentos
- Catálogos XML — Catálogos XML OASIS para resolução de URI
- CLI
xmllint— ferramenta de linha de comando para analisar, validar e consultar XML - Zero-copy sempre que possível — interning de strings para comparações rápidas
- Sem estado global — cada
Documenté autónomo eSend + Sync - FFI C/C++ — API C completa com ficheiro de cabeçalho (
include/xmloxide.h) para incorporação em projetos C/C++ - Dependências mínimas — apenas
encoding_rs(a biblioteca não tem outras dependências;clapé apenas para CLI)
Início Rápido
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");
Serialização
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>");
Consultas XPath
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);
Streaming SAX2
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!("Elemento: {name}");
}
}
parse_sax("<root><child/></root>", &ParseOptions::default(), &mut MyHandler).unwrap();
Análise HTML
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"));
Seletores CSS
use xmloxide::css::select;
use xmloxide::Document;
let doc = Document::parse_str(r#"<div><p class="intro">Hello</p><p>World</p></div>"#).unwrap();
let root = doc.root_element().unwrap();
let intros = select(&doc, root, "p.intro").unwrap();
assert_eq!(intros.len(), 1);
assert_eq!(doc.text_content(intros[0]), "Hello");
Análise HTML5 (WHATWG)
use xmloxide::html5::parse_html5;
let doc = parse_html5("<p>Hello <b>world</b>").unwrap();
let root = doc.root_element().unwrap();
assert_eq!(doc.node_name(root), Some("html"));
A análise de fragmentos (o algoritmo por detrás do innerHTML) também é suportada:
use xmloxide::html5::{parse_html5_with_options, Html5ParseOptions};
let opts = Html5ParseOptions {
scripting: false,
fragment_context: Some("body".to_string()),
};
let doc = parse_html5_with_options("<p>fragment</p>", &opts).unwrap();
Streaming HTML5 (semelhante a SAX)
use xmloxide::html5::sax::{Html5SaxHandler, parse_html5_sax};
struct LinkExtractor { hrefs: Vec<String> }
impl Html5SaxHandler for LinkExtractor {
fn start_element(&mut self, name: &str, attrs: &[(String, String)], _sc: bool) {
if name == "a" {
if let Some((_, href)) = attrs.iter().find(|(n, _)| n == "href") {
self.hrefs.push(href.clone());
}
}
}
}
let mut handler = LinkExtractor { hrefs: Vec::new() };
parse_html5_sax(r#"<a href="https://github.com/jonwiggins/xmloxide/blob/main/page">Link</a>"#, &mut handler);
assert_eq!(handler.hrefs, vec!["/page"]);
Recuperação de Erros
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);
}
Ferramenta CLI
# Analisar e imprimir formatado
xmllint --format document.xml
# Validar contra um esquema
xmllint --schema schema.xsd document.xml
xmllint --relaxng schema.rng document.xml
xmllint --schematron schema.sch document.xml
xmllint --dtdvalid schema.dtd document.xml
# Consulta XPath
xmllint --xpath "//title" document.xml
# XML Canónico
xmllint --c14n document.xml
# Analisar HTML
xmllint --html page.html