まとめ

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,2401.8秒1.1秒1.6倍
34 若菜上46,2304.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がない環境でもビルドが動作する