データベース入門 資料 7
XSLT スタイルシートの基本構造と反復処理

今野 英明

平成26年6月2日


?


1 XSLT スタイルシートの基本構造

XSLT スタイルシートは,XML 文書をどのような形に変換するかを,XSLT で記したものである 1。 なお,以下では XSLT スタイルシートを,単にスタイルシートと呼ぶことがある。

次の例は,前回の資料で紹介した, 変換対象となる XML 文書から, XML 宣言やタグ等を除いた文字データ部分をすべて出力するスタイルシートである。

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="UTF-8" />
  <xsl:template match="/">
    <xsl:value-of select="/" />
  </xsl:template>
</xsl:stylesheet>

XSLT スタイルシート自体も整形式の XML 文書なので,スタイルシートにも XML の用語(XML 宣言や要素,属性等)や規則が当てはまることは紹介済みである。 それに加え,XSLT には独自の規則や役割を持つ要素があるので,上記のスタイルシートを元にこれらを説明する。


1.1 XSLT における相対ロケーションパスの基点

XSLT における相対ロケーションパスの基点は,カレントノード (current node) と呼ばれる, 現在処理中のノードであり,これを .(ドット)で表す。

XSLT スタイルシートでは,ロケーションパスをテンプレート内で使うが, その際の (初期の) カレントノードは xsl:template 要素の match 属性によって決まる。 例えば,<xsl:template match="/"> で始まるテンプレート内の初期カレントノードはルートノードである。 従って, このテンプレートでは / と . は等価であり, <xsl:value-of select="/" /><xsl:value-of select="." /> の出力は同じである。

テンプレート内にカレントノードを変更する XSLT の要素があれば, その中ではカレントノードに応じて相対ロケーションパスの基点が変わる 3

2 XSLT の反復構造

本章では,前回資料の XML 文書例 (以下,単に「XML 文書例」と呼ぶ。)
<?xml version="1.0" ?> 
<ref>
 <book isbn="1111">
  <title>Title1</title>
  <author>Author1</author>
 </book>
 <book>
  <title>Title2</title>
  <author>Author2</author>
 </book>
 <web>
  <title>Title3</title>
 </web>
</ref>
から
Title1 Title2
のような出力を得るための XSLT テンプレートの書き方を紹介する。 このような出力はノードセット /reb/book に''反復処理''を施すことで得られる。


2.1 xsl:for-each 要素による反復

XSLT スタイルシートのテンプレート内に xsl:for-each 要素を置くことで, テンプレート内で反復処理を指定することができる。 xsl:for-each 要素を使うには,相対ロケーションパスとカレントノードの考え方が必要である。

次に示すのは xsl:for-each を使ったスタイルシートの例である。

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="UTF-8" />
  <xsl:template match="/">
    <xsl:for-each select="/ref/book">
      <xsl:value-of select="title" />
      <xsl:value-of select="author" />
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>
これを XML 文書例に適用すると,次の出力が得られる4
Title1Author1Title2Author2
以下では,上記のスタイルシートのうち, xsl:for-each の動作に関わる部分について説明する。

3 データの並べ換えと空白文字の出力

第 2.1節の XSLT スタイルシートにおいて, xsl:for-each 要素を
<xsl:for-each select="/ref/book">
  <xsl:sort order="descending"/>
  <xsl:value-of select="title" />
  <xsl:text> </xsl:text>
  <xsl:value-of select="author" />
  <xsl:text>
</xsl:text>
</xsl:for-each>
に変更して,XML 文書例を処理すると,出力は次のとおりとなる。
Title2 Author2
Title1 Author1
この出力を得るために行っているテンプレート内の処理について,以下に記す。


3.1 xsl:sort 要素による並べ換え

xsl:for-each 要素は,特に指定しなければ, XML 文書に現れた順にカレントノードを変更して反復処理を行うが, xsl:for-each の内容の始めに xsl:sort 要素を置くことで, 処理の順序を変更できる。

例えば,先の <xsl:sort order="descending"/> は, 出力される文字列値が辞書の逆順(降順)になるように, xsl:for-each が処理するノードの順序を並べ換えるものである。

xsl:order 要素の動作を指定する属性は幾つかあり, order 属性は並べ換えの順を指定するものである。 属性値には ascending (昇順)か descending (降順)を指定する (order 属性を略すと昇順になる)。

他の属性としては,並べ換えに使うキーを指定する select 属性があり, <xsl:sort select="author" order="descending"/> とすれば,author ノードの文字列値が降順になるように, 処理順序の並べ換えが行われる。


3.2 xsl:text 要素を使った空白文字の出力

第 2.1 節の実行結果において, 空白や改行無しに Title1 や Author1 などが続いて出力されたのは, テンプレート内で, 空白文字(ブランクや改行)からなる文字データをタグの外に書いても, それらが出力されないためである。

テンプレートに記述した空白や改行を出力したければ, xsl:text 要素が使える。 例えば,内容が空白文字である xsl:text 要素

<xsl:text> </xsl:text>
<xsl:text>
</xsl:text>
をテンプレート内に書けば,空白や改行を出力できる。


4 練習問題

  1. 2.1 節の XSLT スタイルシートにおける xsl:value-of 要素の select 属性値 title と author を,各々 /ref/book/title と /ref/book/author に変更して, XML 文書例 (/pub/db_a/xml/data_model.xml) を xsltproc コマンドで処理してみなさい。 その出力が得られる理由を考えなさい。

  2. 参考文献の XML データ (/pub/db_a/xml/ref.xml) から, title 要素の内容のみを全て出力するための XSLT テンプレートを作成し, xsltproc コマンドで処理しなさい。 xsl:for-each 要素を使うこと。 xsl:text 要素を使って,適切な改行を出力すること。 xsl:sort 要素の使い方も確認してみなさい。

  3. 「資料 5. XMLの基礎」の 4. 練習問題の 4. で作成した郵便番号の XML 文書から,元の設問にあるような郵便番号の一覧を作るための XSLT テンプレートを作成しなさい。 ただし,各列の標題である「市名 町名 郵便番号」の出力は省いてよい。



... で記したものである1
Web ページ作成に用いられる CSS (Cascading Style Sheets) とは異なる
... 形式2
text 形式は変換結果からタグを除去 (テキストノードの内容のみ出力) し, 文字データのエスケープ (変換) を行わないで出力する形式。 text の他には xml と html がある。
... その中ではカレントノードに応じて相対ロケーションパスの基点が変わる3
xsl:for-each 要素がこれに該当する。
... 文書例に適用すると,次の出力が得られる4
xsltproc /pub/db_a/xml/for_each.xsl /pub/db_a/xml/data_model.xml