C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

Rust で XML パーサー使いたいならどの crate を使うと嬉しいかもしれないか、のメモ

状況

crates.io には執筆時点では複数の XML お取り扱いらしい crate が存在しています:

などなど。他にもいくつも登録されています。

1つの性能指標: quick-xml vs. sxd-document vs. xml5ever vs. xml-rs

quick-xml, sxd-document, xml5ever, xml-rs の4つについて性能指標を計測する crate があるようです:

note: RazrFalcon/choose-your-xml-rs では RazrFalcon/roxmltree#alternatives を事実上の移行先として案内していますが、残念ながら RazrFalcon/roxmltree は git clone からとりあえず cargo bench したところ大量のエラーでビルドできず面倒くさい気配がしたのでベンチマークとしては触れない事にしました。( roxmltree 本体の cargo build は問題ないのだけど )

リポジトリーは既に archived ですが動作は可能でした。とりあえず clone してそのまま試してみると:

cargo bench # xml-rs-0.7 quick-xml-0.10 xml5ever-0.11 sxd-document-0.2
running 11 tests
test quick_xml_large     ... bench:   1,922,040 ns/iter (+/- 53,752)
test quick_xml_medium    ... bench:     519,440 ns/iter (+/- 20,166)
test quick_xml_small     ... bench:       8,187 ns/iter (+/- 262)
test sxd_document_medium ... bench:   2,767,680 ns/iter (+/- 295,128)
test sxd_document_small  ... bench:      46,143 ns/iter (+/- 6,440)
test xml5ever_large      ... bench:   9,244,405 ns/iter (+/- 629,496)
test xml5ever_medium     ... bench:   7,367,160 ns/iter (+/- 1,179,293)
test xml5ever_small      ... bench:      53,068 ns/iter (+/- 11,841)
test xmlrs_large         ... bench:  25,043,130 ns/iter (+/- 1,684,648)
test xmlrs_medium        ... bench:  11,846,650 ns/iter (+/- 2,163,808)
test xmlrs_small         ... bench:      87,464 ns/iter (+/- 16,859)

↑は依存が最新版に設定されていないので:

f:id:USAGI-WRP:20200803145309p:plain

依存する XML crate 群を最新版に再定義し、 quick-xml と xml5ever のバージョンアップに伴う仕様変更に対応するパッチを充てて:

cargo bench # xml-rs-0.8.3 quick-xml-0.18.1 xml5ever-0.16.1 sxd-document-0.3.2
running 11 tests
test quick_xml_large     ... bench:   1,959,025 ns/iter (+/- 109,147)
test quick_xml_medium    ... bench:     510,790 ns/iter (+/- 87,736)
test quick_xml_small     ... bench:       7,367 ns/iter (+/- 154)
test sxd_document_medium ... bench:   2,809,025 ns/iter (+/- 323,460)
test sxd_document_small  ... bench:      44,845 ns/iter (+/- 1,459)
test xml5ever_large      ... bench:   8,118,040 ns/iter (+/- 569,471)
test xml5ever_medium     ... bench:   6,755,910 ns/iter (+/- 168,634)
test xml5ever_small      ... bench:      47,349 ns/iter (+/- 2,106)
test xmlrs_large         ... bench:  24,848,280 ns/iter (+/- 1,742,538)
test xmlrs_medium        ... bench:  12,093,030 ns/iter (+/- 978,933)
test xmlrs_small         ... bench:      92,197 ns/iter (+/- 6,255)

巨大なXMLを扱う、パース速度が大事、そのような場合はこれらの選択肢から選べば quick-xml がとても優秀っぽい事がわかります。

minidom ≈ quick-xml vs. roxmltree ≈ xmlparser

xmlparser は↑のベンチマークの Author の RazrFalcon が書いた crate です。↑のベンチマークで"事実上の移行先"としてリンクされていた roxmltreexmlparser をラップした高レベルパーサーという位置づけのようです。ここでちょっとした XML パーサー crate 群の整理:

high low
roxmltree xmlparser
sdx-document (独自の実装詳細)
xmltree xml-rs
minidom quick-xml

↑こんな高レベルのパーサーと低レベルパーサーの関係になっていたようです。その上で、巨大な XML を大量を扱いたい場合にはやはり速度は大事なので、 quick-xml vs. xmlparser あるいは minidom vs. roxmltree を中心に比較すると、

  • パース速度:
    • 高レベルのパース: roxmltree(xmlparser) が minidom(quick-xml) より 1.59 倍くらい高速
    • 低レベルのパース: quick-xml が xmlparser より 1.35 倍くらい高速
  • 列挙速度:
    • 任意要素の文字列マッチング: xmltree が roxmltree より 1.07 倍くらい高速、 minidom より 1.79 倍くらい高速
    • 特定名要素の検索: romxltree が xmltree より 4.58 倍くらい高速、 minidom より 5.86 倍くらい高速

らしい。また、 roxmltree について RazrFalcon によると:

  • xmlparser が quick-xml より遅い部分はより厳密なパースによるもの
  • roxmltree は設計上は panic を起こさないし内部で unsafe も使わない
  • roxmltree では XPath/XQuery, 変更や書き出し、仕様上完璧なXMLのサポートをする気は無いよ

と README に明記されています。

とりあえずの結論

  1. 高速な低レベルパーサーが必要な場合: quick-xml または次点で xmlparser
  2. 高速で安全安定っぽい高レベルサーバーが必要な場合: roxmltree
  3. もし特定の機能サポート都合で roxmltree ≈ xmlparser を使い難い場合:
    • 高レベル向け: xmltree, minidom, sdx-document, または別の何かを探すか作るか
    • 低レベル向け: quick-xml, xml-rs, または別の何かを探すか作るか

実際に使ってみてより詳細な気づきがあればその時にまたメモを追加しようと思います。

参考