Scala の XML パターンマッチング

Scala のパターンマッチング機能は非常に強力で、XML もパターンマッチング対象にする事ができる。という事で簡単に試してみた。

今回、試した環境は以下の通り。

XML パターン指定

XML のパターン指定は以下のように XML の要素と "{パターン}" という記述を使って行える。

  • <要素名>{パターン}

{パターン} の定義方法は以下のようなものがある。

  • {変数名} で 1つのノードを持つ要素にマッチ
  • {変数名 @ _*} で複数のノードを持つ要素にマッチし Array や ArrayBuffer でマッチ箇所を取得

なお、今のところ属性定義は使えないみたい。(<要素名 属性名="xxx"> のようなパターン指定はできない模様)

xml_match.scala ファイル
import scala.xml.Node

def check(node: Node): Unit = node match {
    case <data>{ d }</data> => println("1: '" + d + "'")
    case <data>{ d @ _* }</data> => println("2: " + d)
    case _ => println("3: no match")
}

check(<data>test1</data>)
check(<data>test2<abc /> <name><no>first</no></name></data>)
check(<data><a href="">http://</a></data>)
check(<data />)
check(<data></data>)
check(<data> </data>)
check(<data>
</data>)
check(<data name="test">123</data>)
check(<dataList>a</dataList>)
実行結果
>scala xml_match.scala
1: 'test1'
2: ArrayBuffer(test2, <abc></abc>,  , <name><no>first</no></name>)
1: '<a href="">http://</a>'
2: Array()
2: Array()
1: ' '
1: '
'
1: '123'
3: no match

上記の結果より、スペースや改行もマッチしており、 は { d @ _* } の方にマッチしている事がわかる。

Elem シングルトンオブジェクトを使ったパターン指定

XML の要素を使ってパターン指定する代わりに Elem シングルトンオブジェクトを使う方法も用意されている。

Elem の場合は以下のような記述を使う事になる。

  • Elem(接頭子, 要素名, 属性, スコープ, パターン)

"<要素名>{パターン}" という XML パターンを Elem で置き換えると以下のようになる

  • Elem(_, 要素名, _, _, パターン)

xml_match.scala ファイルの XML パターン部分を Elem を使って書き換えたのが以下。

xml_match2.scala ファイル
import scala.xml.{Node, Elem}

def check(node: Node): Unit = node match {
    case Elem(_, "data", _, _, d) => println("1: '" + d + "'")
    case Elem(_, "data", _, _, d @ _ *) => println("2: " + d)
    case _ => println("3: no match")
}

check(<data>test1</data>)
check(<data>test2<abc /> <name><no>first</no></name></data>)
check(<data><a href="">http://</a></data>)
check(<data />)
check(<data></data>)
check(<data> </data>)
check(<data>
</data>)
check(<data name="test">123</data>)
check(<dataList>a</dataList>)
実行結果
>scala xml_match2.scala
1: 'test1'
2: ArrayBuffer(test2, <abc></abc>,  , <name><no>first</no></name>)
1: '<a href="">http://</a>'
2: Array()
2: Array()
1: ' '
1: '
'
1: '123'
3: no match

実行結果は XML パターンを使った場合と同じになる。