StAX XML Parser には StAX2 Woodstox を使う (Java/Kotlin)

Java や Kotlin などの JDK 開発環境で、XML をパースする選択肢として StAX パーサーがあります。

# 要約

StAX Parser は XML ファイルを詳細に解析したいケースで便利です。

JDK 標準の　StAX Parser よりも、[StAX2 Woodstox](https://github.com/FasterXML/woodstox) を使用することをお勧めします。

# XML Parser の選択肢

JDK 標準(外部ライブラリ不要で使える)の XML Paresr は以下のものがあります。

| 種類 | 特徴 | class |
| --- | --- | ---|
| DOM (Document Object Model) | XML をツリー構造で処理する | org.w3c.dom.Document<br/>javax.xml.parsers.DocumentBuilder |
| XPath (XML Path Language) | XPath 文字列で XML 要素にアクセスする | org.w3c.dom.Document<br/>javax.xml.parsers.DocumentBuilder<br/>javax.xml.xpath.XPath |
| SAX (Simple API for XML Proccessing) | イベントベースで XML を解析する | javax.xml.parsers.SAXParser<br/>javax.xml.parsers.SAXParserFactory |
| StAX (Streaming API for XML) | イベントベースで XML を解析する | javax.xml.stream.XMLInputFactory<br/>javax.xml.stream.XMLStreamReader<br/>javax.xml.stream.XMLEventReader |

それぞれの簡単な実装については以下の記事がわかりやすいです。

https://www.bold.ne.jp/engineer-club/java-xml-read

StAX Parser の実装の解説は以下も参考になります。

http://www.ne.jp/asahi/hishidama/home/tech/java/xml/stax.html

# StAX Parser について

SAX Parser は XML のパース処理を開始したあとは org.xml.sax.helpers.DefaultHandler でイベントを待ち受ける Push 型のイベント駆動パーサーです。

それに対し、StAX Parser は XMLEventReader.hasNext() と XMLEventReader.next() で XML パース時のイベントを順番に取り出して処理をする Pull 型のイベント駆動パーサーです。

StAX Parser であれば、次のイベントを取ってくるタイミングを自由に制御できるため、SAX Parser よりも XML を細かく解析することができます。読み込み元の XML ファイルの先頭から末尾まで、すべてのデータを漏れなく処理したい場合に向いています。

## JDK に含まれる StAX Parser は SJSXP

StAX Parser は JDK 6 から使えるようになりました。JDK 6 以上であれば依存関係を追加せずに `javax.xml.stream` パッケージを利用できます。

JDK には StAX Parser として SJSXP (Sun Java Streaming XML Parser) `com.sun.xml.stream` がバンドルされています。　

StAX Parser は以下のように XMLEventReader を取得して解析を開始します。

```kotlin
val factory = XMLInputFactory.newInstance()
val reader = factory.createXMLEventReader(inputStream)
```

このとき、StAX Parser の実装は自動的に選択されます。ビルド時に StAX Parser ライブラリを一つも含めなければ、SJSXP が使用されます。

SJSXP は StAX を最低限実装しているだけで、パース時のオプションなども最低限であり、期待したいベントを取ってくれないことも多いです。

StAX で XML をパースするのであれば SJSXP よりも、次の **Stax2 Woodstox ライブラリを使用することをお勧めします。**

## Stax2 Woodstox Parser

SJSXP 以外の StAX 実装もあります。

[FasterXML](http://fasterxml.com/) により、StAX の拡張として Stax2 API が定義され、その実装として Aalto と Woodstox があります。

https://github.com/FasterXML/stax2-api

https://github.com/FasterXML/aalto-xml

https://github.com/FasterXML/woodstox

Woodstox は StAX の機能を実装し、SJSXP よりも詳細な動作オプションが指定可能であり柔軟です。FasterXML によりしっかりメンテナンスもされているようです。

StAX 仕様準拠の property はこちらに解説があります。

https://cowtowncoder.medium.com/configuring-woodstox-xml-parser-basic-stax-properties-39bdf88c18ec

StAX2 および Woodstox がサポートする property はこちらに解説があります。

https://cowtowncoder.medium.com/configuring-woodstox-xml-parser-stax2-properties-c80ef5a32ef1

https://medium.com/@cowtowncoder/configuring-woodstox-xml-parser-woodstox-specific-properties-1ce5030a5173

## Stax2 Woodstox をプロジェクトに追加する

Gradle かつ Kotlin なプロジェクトの設定例です。依存関係を追加するだけで使えます。

ライブラリの依存解決リポジトリに `mavenCentral()` が定義されていることを確認してください。

`settings.gradle.kts`

```kotlin
//...
dependencyResolutionManagement {
    repositories {
        //...
        mavenCentral()
    }
}
//...
```

依存関係を追加します。

`build.gradle.kts`

```kotlin
//...
dependencies {
    //...
    implementation("com.fasterxml.woodstox:woodstox-core:6.2.8")
    //...
}
//...
```

XMLInputFactory から XMLEventReader を生成します。

Woodstox ライブラリの依存関係を追加していれば SJSXP ではなく Woodstox Parser のインスタンスが生成されます。

```kotlin
val factory = XMLInputFactory.newInstance()　as XMLInputFactory2 // WstxInputFactory が生成される
val reader = factory.createXMLEventReader(inputStream) as WstxEventReader // WstxEventReader が生成される

// reader を使って StAX 解析すると、Woodstox 実装でパースされる
```