倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

MarkupBuilder でスタイルシートを書いてみた

XSLT スタイルシートは(特にロジックなどを)書くのが結構大変。 以前から RELAX NG Compact Syntax のような簡略記法がないかなぁと思っていましたが、Groovy の Builder を使うとこの目的が達せられるかと思いチョット試してみました。

変換対象の XML データ


まずは変換対象の XML データ。 簡単のため、名前空間は使用しないことにしましょう:

<?xml version="1.0"?>
<Groovy-Projects>
  <Groovy latest-version="1.7.2">
    <url>http://groovy.codehaus.org/</url>
    <description>An agile dynamic language for the Java Platform</description>
  </Groovy>

  <Gant latest-version="1.9.2">
    <url>http://gant.codehaus.org/</url>
    <description>A Groovy-based build system that uses Ant tasks, but no XML.</description>
  </Gant>

  <GMaven latest-version="1.2">
    <url>http://docs.codehaus.org/display/GMAVEN/Home</url>
    <description>GMaven provides integration of Groovy into Maven.</description>
  </GMaven>

  <Griffon latest-version="0.3.1">
    <url>http://griffon.codehaus.org/</url>
    <description>A Grails-like Rich Internet Framework</description>
  </Griffon>

  <Grails latest-version="1.3.1">
    <url>http://grails.org/</url>
    <description>a Groovy-based web framework inspired by Ruby on Rails</description>
  </Grails>
</Groovy-Projects>

Groovy の Builder を用いたスタイルシート


では肝心のスタイルシートを見ていきましょう。

まずは準備としての Builder のインスタンスを取得します。 ここでは結果のスタイルシートXML を内容とする文字列として取得するために StringWriter のインスタンスを作成してそれを MarkupBuilder に渡します。

def writer = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(writer)

さて、次がスタイルシートを構築する Builder を使ったコードです:

builder.'xsl:stylesheet'(
        version:'1.0',
        xmlns:'http://www.w3.org/TR/xhtml1/strict',
        'xmlns:xsl':'http://www.w3.org/1999/XSL/Transform'){

    'xsl:template'(match:'/'){
        html{
            head{
                title('Hello, Groovy world !')
            }
            body{
                table(border:'1'){
                    tr{
                        th('Project Name')
                        th('Latest Version')
                        th('Description')
                    }
                    'xsl:apply-templates'(select:'*')
                }
            }
        }
    }

    'xsl:template'(match:'/Groovy-Projects/*'){
        tr{
            th{
                a{
                    'xsl:attribute'(name:'href'){
                        'xsl:value-of'(select:'url')
                    }
                    'xsl:value-of'(select:'local-name()')
                }
            }
            td{'xsl:value-of'(select:'@latest-version')}
            td{'xsl:value-of'(select:'description')}
        }
    }
}
  • XML 形式で書くのに比べれば、書くのも読むのも楽だと思いませんか?
  • チョット面倒なのは、名前空間接頭辞を使用するには名前にコロン (:) が必要なため、XSLT のタグを全てシングルクォート (') で囲む必要があるところでしょうか。 XSLT名前空間をデフォルト名前空間にしても(接頭辞を使わないようにしても)、HTML タグの方に名前空間を使わないといけなくなるので、あまり簡単にはなりません。 そもそも、XSLT のタグにはハイフン (-) を含むものがいくつもあるので、結局はシングルクォートで囲む必要はありますが。
  • if, choose などのロジックを書くときに簡潔さの有難味がもっとありそう。
  • Groovy の Builder は混合内容モデル*1を使えませんが、xsl:text 要素を使えば問題ないでしょう。

スタイルシートが取得できれば、あとは javax.xml.transform パッケージ内のクラスを用いて XSL 変換を実行します(細かいコードは省略):

def reader = new StringReader(writer.toString())
def stylesheet = new StreamSource(reader)

def trans = TransformerFactory.newInstance().newTransformer(stylesheet)
// Transformer を用いた変換処理
  • 「StreamSource」は javax.xml.transform.StreamSource
  • 「TransformerFactory」は javax.xml.transform.TransformerFactory

変換結果の HTML ファイル


上記の変換を施すと、結果として以下の HTML が得られます(見やすさのため、適当に整形しています):

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/TR/xhtml1/strict">

<head>
  <title>Hello, Groovy world !</title>
</head>

<body>
  <table border="1">
    <tr>
      <th>Project Name</th><th>Latest Version</th><th>Description</th>
    </tr>

    <tr>
      <th><a href="http://groovy.codehaus.org/">Groovy</a></th><td>1.7.2</td>
      <td>An agile dynamic language for the Java Platform</td>
    </tr>

    <tr>
      <th><a href="http://gant.codehaus.org/">Gant</a></th><td>1.9.2</td>
      <td>A Groovy-based build system that uses Ant tasks, but no XML.</td>
    </tr>

    <tr>
      <th><a href="http://docs.codehaus.org/display/GMAVEN/Home">GMaven</a></th>
      <td>1.2</td><td>GMaven provides integration of Groovy into Maven.</td>
    </tr>

    <tr>
      <th><a href="http://griffon.codehaus.org/">Griffon</a></th><td>0.3.1</td>
      <td>A Grails-like Rich Internet Framework</td>
    </tr>

    <tr>
      <th><a href="http://grails.org/">Grails</a></th><td>1.3.1</td>
      <td>a Groovy-based web framework inspired by Ruby on Rails</td>
    </tr>
  </table>
</body>
</html>

ブラウザで表示するとこんな感じ:















Project NameLatest VersionDescription
Groovy1.7.2An agile dynamic language for the Java Platform
Gant1.9.2A Groovy-based build system that uses Ant tasks, but no XML.
GMaven1.2GMaven provides integration of Groovy into Maven.
Griffon0.3.1A Grails-like Rich Internet Framework
Grails1.3.1a Groovy-based web framework inspired by Ruby on Rails

どうでしょう?
Groovyイン・アクション

Groovyイン・アクション


XSLT: Mastering XML Transformations

XSLT: Mastering XML Transformations

*1:ある要素下に子テキストと子要素が混在しているもの。 正式には何て言うんですっけ?