やりたいこと
xlsxファイルをパースします。
今回はApache Tikaを用いてパースを行います。
パースする内容
今回は以下のような内容のファイルをパースしていきます。
補足として、今回の記事を書くにあたって確認用に利用したファイルはGoogle Docsのスプレッドシートで生成したものなので、純正/サードパーティ性のソフトから生成した場合もちゃんと動くのか確認できていません。
また、実際のファイルではフォントをバラバラに変更したりしていましたがパース結果に影響は有りませんでした。
シート1 | ||
---|---|---|
hoge | ふが | ピヨ |
fizz | バッズ | fizzBuzz |
やりかた
ライブラリを導入してparseすればできます。
今回はxml
系(含xlsx)ファイルのみに対応してパースする方法と、Tikaにファイル種別を検出してもらって自動でパースする方法との2通りを試します。
Apache Tika Parsersを導入する
Mavenから導入します。
検証には1.21
を使いました。
xml
系データのみをパースする方法
OOXMLParser
を用いてパースすることでできます。
パースした結果はContentHandler
(今回はBodyContentHandler
)に格納されます。
BodyContentHandler
からの情報取得はtoString
以外の方法を見つけられませんでした。
サンプルコードは以下の通りです。
src/main/resources
に入っているxml系ファイルをパースします。
注意点として、xml系でない(=OOXMLParser
がパースできない)ファイルを入れると落ちます。
実行結果はTikaにファイル種別を検出してもらって自動でパースする方法と同じなので割愛します。
import org.apache.tika.parser.ParseContext
import org.apache.tika.parser.microsoft.ooxml.OOXMLParser
import org.apache.tika.sax.BodyContentHandler
import org.apache.tika.metadata.Metadata as TikaMetadata
import java.io.File
import java.io.FileInputStream
fun main() {
val parser = OOXMLParser() // XML系データ用のパーサー
val metaData = TikaMetadata()
val context = ParseContext()
val handler = BodyContentHandler() // パース結果が格納されるハンドラ
File(System.getProperty("user.dir") + "/src/main/resources").listFiles().forEach {
parser.parse(FileInputStream(it), handler, metaData, context)
println(handler.toString())
}
}
Tikaにファイル種別を検出してもらって自動でパースする方法
先ほどのサンプルコードからパーサーをAutoDetectParser
に差し替えることで実現できます。
import org.apache.tika.parser.AutoDetectParser
import org.apache.tika.parser.ParseContext
import org.apache.tika.sax.BodyContentHandler
import org.apache.tika.metadata.Metadata as TikaMetadata
import java.io.File
import java.io.FileInputStream
fun main() {
val parser = AutoDetectParser() // ファイル種別まで自動検出するパーサー
val metaData = TikaMetadata()
val context = ParseContext()
val handler = BodyContentHandler() // パース結果が格納されるハンドラ
File(System.getProperty("user.dir") + "/src/main/resources").listFiles().forEach {
println("-------------")
println(it.name)
parser.parse(FileInputStream(it), handler, metaData, context)
println(handler.toString())
println("-------------")
}
}
実行結果
スプレッドシートで落とせるzip以外のファイル形式を全て回してみました。
-------------
xls_for_test.xlsx
シート1
hoge ふが ピヨ
fizz バッズ fizzBuzz
-------------
-------------
xls_for_test - シート1.csv
シート1
hoge ふが ピヨ
fizz バッズ fizzBuzz
hoge,ふが,ピヨ
fizz,バッズ,fizzBuzz
-------------
-------------
xls_for_test.ods
シート1
hoge ふが ピヨ
fizz バッズ fizzBuzz
hoge,ふが,ピヨ
fizz,バッズ,fizzBuzz
hoge
ふが
ピヨ
fizz
バッズ
fizzBuzz
???
Page
??? (???)
00/00/0000, 00:00:00
Page /
-------------
-------------
xls_for_test - シート1.pdf
シート1
hoge ふが ピヨ
fizz バッズ fizzBuzz
hoge,ふが,ピヨ
fizz,バッズ,fizzBuzz
hoge
ふが
ピヨ
fizz
バッズ
fizzBuzz
???
Page
??? (???)
00/00/0000, 00:00:00
Page /
hoge ふが ピヨ
fizz バッズ fizzBuzz
-------------
-------------
xls_for_test - シート1.tsv
シート1
hoge ふが ピヨ
fizz バッズ fizzBuzz
hoge,ふが,ピヨ
fizz,バッズ,fizzBuzz
hoge
ふが
ピヨ
fizz
バッズ
fizzBuzz
???
Page
??? (???)
00/00/0000, 00:00:00
Page /
hoge ふが ピヨ
fizz バッズ fizzBuzz
hoge ふが ピヨ
fizz バッズ fizzBuzz
-------------
感想
とりあえずxlsxに限らず様々な形式のファイルがパースできてよかったです。
ただ、パースした結果の出力はBodyContentHandler
の形式だと辛いので、より目的に合致するものが無いか探していきます。