アップデート一覧に戻る
New releaseAug 9, 2026

xmloxide v0.5.0

libxml2の純粋なRust再実装

共有

xmloxide

CI crates.io docs.rs License: MIT MSRV

libxml2 の純Rust再実装 — オープンソース世界で事実上の標準XML/HTMLパースライブラリです。

libxml2は2025年12月に公式メンテナンス終了となり、既知のセキュリティ問題を抱えています。xmloxideは、メモリ安全かつ高性能で、同じ適合性テストスイートを通過する代替品を目指します。

特徴

  • メモリ安全 — アリーナベースのツリーで、公開APIにunsafeを一切含みません
  • 適合性 — W3C XML適合性テストスイートで100%の合格率(1727/1727の該当テスト)
  • エラーリカバリ — libxml2と同様に、不正なXMLでも解析して利用可能なツリーを生成
  • 複数のパースAPI — DOMツリー、SAX2ストリーミング、XmlReaderプル、プッシュ/インクリメンタル
  • HTMLパーサー — 自動クローズや空要素をサポートしたエラー耐性のあるHTML 4.01パーサー
  • WHATWG HTML5パーサー — 完全なHTML Living Standardトークナイザーとツリービルダー(8810/8810のhtml5lib-tests合格)
  • HTML5ストリーミング — DOMツリーを構築せずにトークナイザーをラップするSAXライクなコールバックAPI(html5::sax)
  • CSSセレクター — 親しみやすいCSS構文で要素をクエリ(css::select)。コンビネーター、疑似クラス、高速な#idルックアップ対応
  • XPath 1.0+ — 完全な式パーサーと評価器。XPath 1.0の全コア関数に加え、主要なXPath 2.0関数(matches()、replace()、tokenize()、upper-case()、lower-case()、abs()、min()、max()など)をサポート
  • 検証 — DTD、RelaxNG、XML Schema (XSD)、ISO Schematron (ISO/IEC 19757-3) による検証
  • Serde統合 — オプションのserdeフィーチャーで、Rust型とのXML (逆)シリアライズ
  • 非同期パース — オプションのasyncフィーチャーで、tokio::io::AsyncReadソースからのパース
  • Canonical XML — C14N 1.0およびExclusive C14Nシリアライズ
  • XInclude — ドキュメントインクルード処理
  • XMLカタログ — URI解決のためのOASIS XMLカタログ
  • xmllint CLI — XMLのパース、検証、クエリを行うコマンドラインツール
  • 可能な限りゼロコピー — 文字列インターンによる高速比較
  • グローバル状態なし — 各Documentは自己完結型でSend + Sync
  • C/C++ FFI — C/C++プロジェクトに埋め込むための完全なC APIとヘッダーファイル(include/xmloxide.h)
  • 最小限の依存関係 — encoding_rsのみ(ライブラリは他に依存関係なし。clapはCLIのみ)

クイックスタート

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");

シリアライズ

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クエリ

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ストリーミング

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パース

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"));

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");

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"));

フラグメントパース(innerHTMLの背後にあるアルゴリズム)もサポートしています:

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();

HTML5ストリーミング(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"]);

エラーリカバリ

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ツール

# パースしてプリティプリント
xmllint --format document.xml

# スキーマに対して検証
xmllint --schema schema.xsd document.xml
xmllint --relaxng schema.rng document.xml
xmllint --schematron schema.sch document.xml
xmllint --dtdvalid schema.dtd document.xml

# XPathクエリ
xmllint --xpath "//title" document.xml

# Canonical XML
xmllint --c14n document.xml

# HTMLパース
xmllint --html page.html

モジュール概要

モジュール説明
treeアリーナベースのDOMツリー(Document、NodeId、NodeKind)
parserエラーリカバリ機能付きXML 1.0再帰下降パーサー
parser::pushチャンク入力用のプッシュ/インクリメンタルパーサー
htmlエラー耐性のあるHTML 4.01パーサー
html5WHATWG HTML Living Standardパーサー(トークナイザー+ツリービルダー)
html5::saxHTML5用のストリーミングSAXライクAPI(DOMツリーは構築しない)
cssドキュメントツリーをクエリするCSSセレクターエンジン
saxSAX2ストリーミングイベント駆動パーサー
readerXmlReaderプルベースのパースAPI
serialXML、HTML、HTML5シリアライザー、およびCanonical XML (C14N)
xpathXPath 1.0+式パーサーと評価器
validation::dtdDTDパースと検証
validation::relaxngRelaxNGスキーマ検証
validation::xsdXML Schema (XSD) 検証
validation::schematronISO Schematronルールベース検証
serde_xmlSerde XML (逆)シリアライズ(オプションのserdeフィーチャー)
async_xmltokio::io::AsyncRead経由の非同期パース(オプションのasyncフィーチャー)
xincludeXInclude 1.0ドキュメントインクルード
catalogURI解決のためのOASIS XMLカタログ
encoding文字エンコーディング検出と変換
ffiC/C++ FFIバインディング(include/xmloxide.h)

パフォーマンス

パースのスループットはlibxml2と競合します — ほとんどのドキュメントで3-4%以内、SVGでは12%高速です。シリアライズはアリーナベースのツリー設計のおかげで1.5-2.4倍高速です。XPathはすべてのベンチマークで1.1-2.7倍高速です。

パース:

ドキュメントサイズxmloxidelibxml2結果
Atomフィード4.9 KB26.7 µs (176 MiB/s)25.5 µs (184 MiB/s)~4%低速
SVG描画6.3 KB58.5 µs (103 MiB/s)65.6 µs (92 MiB/s)12%高速
Maven POM11.5 KB76.9 µs (142 MiB/s)74.2 µs (148 MiB/s)~4%低速
XHTMLページ10.2 KB69.5 µs (139 MiB/s)61.5 µs (157 MiB/s)~13%低速
大(374 KB)374 KB2.15 ms (169 MiB/s)2.08 ms (175 MiB/s)~3%低速

シリアライズ:

ドキュメントサイズxmloxidelibxml2結果
Atomフィード4.9 KB11.3 µs17.5 µs1.5倍高速
Maven POM11.5 KB20.1 µs47.5 µs2.4倍高速
大(374 KB)374 KB614 µs1397 µs2.3倍高速

XPath:

式xmloxidelibxml2結果
単純パス (//entry/title)1.51 µs1.63 µs8%高速
属性述語 (//book[@id])5.91 µs15.99 µs2.7倍高速
count()関数1.09 µs1.67 µs1.5倍高速
string()関数1.32 µs1.77 µs1.3倍高速

カテゴリ