以前Scalaの標準のXMLサポートでは"\\"でXpathの"//"を表し"\"で"/"を表すというXPathライクな表記が出来ることを紹介しました.でもScalaですからこれらは、実はみんなメソッドです.Scales XMLの場合はどうなのでしょうか?以前の http://blogs.yahoo.co.jp/tnakita/14719186.html とほぼ同じことは次のように書けます.
package scalestest
import scales.utils._
import ScalesUtils._
import scales.xml._
import ScalesXml._
import scales.xml.Functions._
import java.io._
import scalaz._
import Scalaz._
object dsltest {
def main(args: Array[String]): Unit = {
val root=top(doc)
val titles = (root \* "cd").filter(cd => string(cd.\* ("year")) == "1987") \* "title"
val title = titles.head
println("The title='" + string(title) + "'")
}
}
このプログラムは http://blogs.yahoo.co.jp/tnakita/14649736.html のXMLに対して動かすと、
The title='Abbey Road'
と表示してくれます.
これだけと"\"が"\*"に代わったくらいに見えます.あとScales XMLの提供するstringという関数を使うとテキストノードまでたどらなくても文字列値を得ることができるのが便利なところです.
例えば上記のコードに続けて、
val artist = title.\^.\*("artist")
println("The artist='" + string(artist) + "'")
と書けば、
The artist='The Beatles'
と表示してくれます."\^"でXPathの"parent::"を実装してくれています.つまり一回親に戻ってその子のartist要素を辿れています.
更に
val nextCdTitle = title.\^.following_sibling_::.*(2).\*("title")
println("The next(2) cd title='" + string(nextCdTitle) + "'")
val nextCdArtist = nextCdTitle.\^.\*("artist")
println("The next(2) cd artist='" + string(nextCdArtist) + "'")
と書けば、
The next(2) cd title='Thriller'
The next(2) cd artist='Michael Jackson'
と表示してくれます.つまり"following_sibling_::.*(2)"でXPathの"following-sibling::*[2]"を表現しています.ちょっと記述にクセがありますけれど、スゴイ進歩です.
これらの一覧は、XPathクラスの定義を見ればわかります.
でもこのクラス定義はちょっと古いようです.GitHubから落としたコードを見たほうがわかりやすでしょう.例えば、scalesXml\core\src\main\scala\scales\xml\xpath\Axe.scalaには、
preceding_sibling_::
following_sibling_::
descendant_::
following_::
preceding_::
ancestor_::
ancestor_or_self_::
descendant_or_self_::
が定義されています.XPathを意識してなかなか頑張っています.
しかし、実際にプログラムを書いてみた正直な感想ですが「なんでXPathなら簡単に記述できることを、苦労してややこしい記法で書かなければならないのかなぁ?」というところです.
Scales XMLの良いところはまだまだ他にもあります.追って紹介したいと思います.