revised: Nov./16th/2003
ソース・ツリーであるリスト1と、結果ツリーであるリスト5を見比べながら、XSLT文書であるリスト2の中身を見ていきましょう。
XSLT文書はXMLベースのマークアップ言語として定義されているので、XML宣言で始まる整形式のXML文書である必要があります。
XSLT文書のルート要素はstylesheet要素であり、その属性には表1に挙げるものを指定する。
| 属性 | 値 |
|---|---|
version | 現時点では1.0のみ(必須) |
exclude-result-prefixes | 結果ツリーに含めない名前空間 |
xmlns:接頭辞 | 名前空間URI |
xmlns | デフォルト名前空間URI |
表1の属性で、必ず指定するのが、version属性と、XSLT自身の名前空間URIを指定するxmlns属性です。リスト2で挙げたXSLT文書では、version="1.0" と、XSLT自身の名前空間である "http://www.w3.org/1999/XSL/Transform" を接頭辞 xsl で定義してあります。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
例えば、ソース・ツリーで名前空間 "http://www.hoge.foo.demo/ScehmaDemo" を使っている場合は、XSLT文書でもこの名前空間URIを指定しておく必要があります。この名前空間をデフォルト名前空間にして、結果ツリーにはこの名前空間を含めたくないという場合は、次のように指定します。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.hoge.foo.demo/ScehmaDemo"
exclude-result-prefixes="#default">
接頭辞にpreを指定する場合は、名前空間URIの指定に xmlns:pre を使い、exclude-result-prefixes属性の値にpreを指定します。
stylesheet要素の直接の子要素に、リスト2では、出力方法を指定するoutput要素と、変換規則を記述するtemplate要素を記述しました。他にも、リスト6に挙げる要素が記述可能です。これらの要素は、XSLT仕様書ではトップ・レベル要素と呼ばれています。本稿では、全てのトップ・レベル要素を紹介することはできません。詳細は、W3CのXSLT 1.0仕様書を参照してください。
リスト6. XSLT文書のトップレベル要素
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- 外部XSLT文書のインポート
本スタイルシートの規則よりも優先する -->
<xsl:import href="..."/>
<!-- 外部XSLT文書のインクルード
本スタイルシートの規則の方が優先する -->
<xsl:include href="..."/>
<!-- スペース区切りの要素名を指定して、
当該要素のテキスト・ノードから空白を除去する -->
<xsl:strip-space elements="..."/>
<!-- デフォルトでは全ての要素名が指定されており、
当該要素の空白をそのまま維持する -->
<xsl:preserve-space elements="..."/>
<!-- method属性に"xml" | "html" | "text"を指定して、
対応する出力形式を指定する -->
<xsl:output method="..."/>
<!-- 関数key()で利用する、ノードを参照するキーとその値を定義する -->
<xsl:key name="..." match="..." use="..."/>
<!-- 関数format-number()で利用する、数値を文字列かするパターンを定義する -->
<xsl:decimal-format name="..."/>
<!-- 名前空間URIが別の名前空間URIに関する別名であることを宣言する -->
<xsl:namespace-alias stylesheet-prefix="..." result-prefix="..."/>
<!-- 名前つき属性集合を定義する -->
<xsl:attribute-set name="...">
...
</xsl:attribute-set>
<!-- 変数名とその値を定義する -->
<xsl:variable name="...">...</xsl:variable>
<!-- 変数名とそのデフォルト値を定義する -->
<xsl:param name="...">...</xsl:param>
<!-- パターンにマッチするノードの変換規則を記述する -->
<xsl:template match="...">
...
</xsl:template>
<!-- 名前つき変換規則を定義する -->
<xsl:template name="...">
...
</xsl:template>
</xsl:stylesheet>
XSLT文書で最も重要なものは、変換規則を記述するtemplate要素です。ここで、xsl:template要素について、詳しく紹介しましょう。
xsl:template要素は、内容に結果ツリーを記述します。match属性とname属性の何れかが必須の属性であり、name属性が指定されている場合は、属性値を使って、xsl:call-template要素から明示的に参照可能となります。一方、match属性が指定されている場合は、属性値のXPathにマッチしたノードを、結果ツリーに変換する規則として機能します。
リスト2のXSLT文書では、三つのテンプレートが定義されています。最初のものは、match属性値にルート・ノードが指定されており、文書全体を内容のツリー構造に変換するテンプレートです。リスト2では、結果ツリーのルート要素がnamelist要素であり、その子要素にmale要素とfemale要素を記述しました。何れの要素の場合も、内容にはxsl:apply-templates要素が現れています。
xsl:apply-templatesは、select属性を持ち、値に対応するノード集合に対応するテンプレートが当該箇所に挿入される。
male要素の子要素であるxsl:apply-templates要素の場合は、select="/address/item[@sex='male']" が指定されており、マッチする全てのノードに対して、再帰的にテンプレート2が適用され、その結果が挿入されることになります。同様に、female要素の子要素には、テンプレート3の結果が挿入されます。
テンプレート2は、ソースツリーのsex属性の値がmaleであるitem要素にマッチするテンプレートです。内容はcust要素で、その内容にはxsl:value-of要素が指定されています。xsl:value-of要素はselect属性を持ち、マッチするパターンに対応するテキストを結果ツリーのテキスト・ノードに挿入します。すなわち、select属性に要素ノードの集合が指定されれば、その子孫のテキストノードであり、属性ノードが指定されれば、その値が結果ツリーのテキスト・ノードに挿入されることになります。
xsl:template要素の子要素として、xsl:value-of要素を紹介したが、他にも多くの要素が定義されています。それら全てを説明する余裕はありませんが、一部の要素については本稿でも紹介します。最初に紹介するのは、繰り返し構造を記述するxsl:for-each要素です。
xsl:for-each要素は、select属性の値にマッチするノードが存在する限り、内容を繰り返します。リスト7は、リスト1を、XHTML 1.1文書のテーブルに変換するものです。
リスト7. xsl:value-ofの例(XSLTDemo2.xsl)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml">
<!-- 結果ツリーの出力方法 -->
<xsl:output method="xml" encoding="UTF-8" indent="yes"
doctype-public="-//W3C//DTD XHTML 1.1//EN"
doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" />
<!-- テンプレート -->
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" >
<head>
<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8" />
<title>顧客リスト</title>
</head>
<body>
<table border="1">
<!-- 繰り返し -->
<xsl:for-each select="address/item">
<tr>
<th><xsl:apply-templates select="name"/></th>
<!-- 繰り返し -->
<xsl:for-each select="access">
<td><xsl:apply-templates/></td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
リスト7では、xsl:output要素に、XHTML 1.1の文書型の、公開識別子とシステム識別子を指定しいます。この情報に基づいて、DTD宣言が結果ツリーに挿入されます。
尚、XHTMLもXML文書であるので、HTML 4向けのoutput method="html"は指定していません。また、文字符号化方法にはUTF-8を明示的に指定し、結果ツリーの出力でインデントをとるように指定しました。このスタイルシートを指定してリスト3を実行すると、結果ツリーはリスト8のようになります。実際は改行されるのみでインデントはとられませんが、見やすくするために適宜スペースを挿入してあります。
リスト8. リスト7による結果ツリー
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<title>顧客リスト</title>
</head>
<body>
<table border="1">
<tr>
<th>菅井 学</th>
<td></td>
<td>http://www.nextindex.net/java/</td>
</tr><tr>
<th>鈴木 竜広</th>
<td>tsuzuki@hoge.foo.bar</td>
</tr><tr>
<th>栃原 宏枝</th>
<td>090-xxxx-xxxx</td>
</tr>
</table>
</body>
</html>
xsl:if要素とxsl:choose要素XSTLには、条件によって処理を変更する要素も用意されています。IF-THEN型の場合はxsl:if要素を用い、スイッチ型の条件分岐はxsl:choose要素を用いることになります。
xsl:if要素は、test属性に指定された式を評価して、真であれば内容のテンプレートを実行し、偽であればなにもしません。リスト9は、リスト7に性別のカラムを追加したものです。sex属性の値が"male"であれば「男性」、"female"でれば「女性」と出力します。
xsl:choose要素は、子要素にxsl:when要素を持ち、そのtest属性の値を評価して、実行するテンプレートを選択します。全てのxsl:when要素のtest属性値が真でなければ、xsl:otherwise要素の内容が実行されます。xsl:when要素が真でなく、xsl:otherwise要素が存在しない場合は、なにもしません。リスト9では、xsl:variable要素を用いて変数$kindを定義して、その値に応じて対応する文字列を付加しています。
XSLTで定義されている要素には、他にもいろいろありますが、最後にソート要素を紹介します。xsl:sort要素は、xsl:apply-templates要素又はxsl:for-each要素の子供として定義され、複数記述することで、一時ソートキー、二次ソートキーとして働きます。属性には、表8に挙げるもものが定義されています。
| 属性 | 概要 |
|---|---|
select | ソートキー |
lang | 言語 |
data-type |
|
order |
|
case-order |
|
リスト9では、name要素の文字コードの降順にソートしています。
リスト9. 条件分岐とソートの例(XSLTDemo3.xsl)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml">
<!-- 結果ツリーの出力方法 -->
<xsl:output method="xml" encoding="UTF-8" indent="yes"
doctype-public="-//W3C//DTD XHTML 1.1//EN"
doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" />
<!-- テンプレート -->
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" >
<head>
<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8" />
<title>顧客リスト</title>
</head>
<body>
<table border="1">
<!-- 繰り返し -->
<xsl:for-each select="address/item">
<!-- ソート指定 -->
<xsl:sort select="./name" order="descending"/>
<tr>
<th><xsl:apply-templates select="name"/></th>
<!-- 条件分岐 -->
<xsl:if test="@sex='male'">
<td>男性</td>
</xsl:if>
<xsl:if test="@sex='female'">
<td>女性</td>
</xsl:if>
<!-- 繰り返し -->
<xsl:for-each select="access">
<td>
<!-- 変数定義 -->
<xsl:variable name="kind" select="@kind"/>
<!-- 条件分岐 -->
<xsl:choose>
<xsl:when test="$kind='email'">email: </xsl:when>
<xsl:when test="$kind='tel'">tel: </xsl:when>
<xsl:otherwise>others: </xsl:otherwise>
</xsl:choose>
<xsl:apply-templates/>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
リスト9 の XSLT 文書で、リスト1 の XML 文書を処理すると、リスト10のようになります。使ったアプリケーションはリスト3のものです。
リスト10. XSLTDemo3.xslの処理結果
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<title>顧客リスト</title>
</head>
<body>
<table border="1">
<tr>
<th>鈴木 竜広</th>
<td>男性</td>
<td>email: tsuzuki@hoge.foo.bar</td>
</tr>
<tr>
<th>栃原 宏枝</th>
<td>女性</td>
<td>tel: 090-xxxx-xxxx</td>
</tr>
<tr>
<th>菅井 学</th>
<td>男性</td>
<td>email: </td>
<td>others: http://www.nextindex.net/java/</td>
</tr>
</table>
</body>
</html>
XSLT 1.0では、以上で挙げた要素や属性のほかにも、多くのものが定義されています。より詳細な定義は、W3CのXSLT 1.0仕様書を参照ください。