まとめ
TEI XML → HTML変換において、npx xslt3(Saxon-JS)からJava Saxon-HEへ切り替えたところ、ビルド時間が1分48秒から23秒に短縮された(約5倍の高速化)。
背景
校異源氏物語テキストDBは、源氏物語のデジタルエディションで、54巻分のTEI XMLファイルを持つ。ビルドスクリプト(Python)が各XMLをHTMLに変換するため、npx xslt3を54回呼び出していた。
python3 scripts/prebuild.py xsl # 全54巻のXSLT処理
この処理がビルドパイプライン全体で最も時間のかかるステップだった。
ベンチマーク
ファイルごとの比較
| 巻 | 文字数 | npx xslt3 (JS) | saxon (Java) | 高速化率 |
|---|---|---|---|---|
| 01 桐壺 | 11,240 | 1.8秒 | 1.1秒 | 1.6倍 |
| 34 若菜上 | 46,230 | 4.9秒 | 0.4秒 | 12倍 |
ファイルが大きいほど改善幅が大きい。JVM起動コスト(約1秒)を差し引くと、実際の変換処理は桁違いに速い。
合計(全54巻)
npx xslt3 (Saxon-JS): 1分48秒
saxon (Saxon-HE): 23秒
移行手順
ローカル環境(macOS)
brew install saxon
ビルドスクリプト
SAXON_JAR環境変数 → saxonコマンド → npx xslt3の順にフォールバックするヘルパーを追加した。
def xslt_cmd(xsl, src, dst):
"""Return XSLT command, preferring Saxon-HE over npx xslt3."""
saxon_jar = os.environ.get('SAXON_JAR')
if saxon_jar:
return ['java', '-jar', saxon_jar, f'-xsl:{xsl}', f'-s:{src}', f'-o:{dst}']
if shutil.which('saxon'):
return ['saxon', f'-xsl:{xsl}', f'-s:{src}', f'-o:{dst}']
return ['npx', 'xslt3', f'-xsl:{xsl}', f'-s:{src}', f'-o:{dst}']
GitHub Actions
Node.js + xslt3をJava + Saxon-HE jarに置き換えた。
- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
- name: Download Saxon-HE
run: |
curl -sL -o /tmp/saxon-he.jar \
https://repo1.maven.org/maven2/net/sf/saxon/Saxon-HE/12.5/Saxon-HE-12.5.jar
- name: Run prebuild
env:
SAXON_JAR: /tmp/saxon-he.jar
run: python3 scripts/prebuild.py tei xsl waka stats
出力の差異
HTMLの内容は同等で、フォーマット(空白、<!DOCTYPE html> vs <!DOCTYPE HTML>)のみ異なる。ブラウザ上での表示に影響はない。
所感
- Saxon-JS(JavaScript)は手軽だが、大きいファイルでは処理速度が大幅に低下する
- Java Saxon-HEはフリー(MPL 2.0)で、
brew install saxonで簡単にインストールできる - フォールバック方式により、Saxonがない環境でもビルドが動作する