XMLマスターポイントレッスン ~ ベーシック編 ~
第8回 XSLTの基礎
インフォテリア認定教育センター 鈴木智也 SUZUKI, Tomoya
「前回までは、DTDやXML Schemaを利用したXML文書の定義方法について解説しました。
今回からは、3回にわたってXMLデータを変換する「XSLT(XSL Transformations)」について解説していきます。XSLTスタイルシートを使ってHTMLデータを出力したり、別の構造のXML文書へ変換したりする方法を紹介します。ベーシックV2試験のセクション5「XSLT/XPath」を攻略するための必須知識なので、しっかりと学習しておきましょう。
XMLデータの有効活用
今日では、同じ情報がさまざまな媒体で公開されています。例えば、通信販売であれば冊子やPC/携帯電話のWebサイトなどから商品情報を見ることができます。いずれの場合も見ることができる商品名や価格などの情報は同じですが、その表示方法は異なります。逆にカタログのWebサイトを見てみると、商品ごとにレイアウトなどのデザインは共通で、多数の商品情報が掲載されています。
そこで、商品情報のデータそのものとレイアウトなどのデザインを別々に管理していけば、修正や更新といった要求にも柔軟に対応できます。XMLを利用すればタグによる見出し付きでデータのみを扱うことができますので、あとはXMLで記述された商品情報に対してどのように表示させるかのレイアウト情報だけを指定すれば良いことになります(図1)。
XML形式のデータを変換するには
XMLはデータのみを記述できるため、「どのようにデータを読み取って表示するのか」はアプリケーション次第です。また、最近では保存されたデータをWebブラウザから参照するようなWebシステムの環境が増えていますので、XML形式で保存されているデータをHTML形式に変換してWebブラウザから確認できると非常に便利です。では、XML形式のデータをどのようにHTML形式に変換すれば良いのでしょうか。その方法として、大きく次の2つを考えることができます。
- [1] DOM/SAXなどを利用してプログラムからデータを読み取り、任意のHTML形式に出力する
- [2] XSLTを使ってスタイルシートに変換ルールを記述し、HTML形式に出力する
[1]では、読み取ったデータをプログラミングにより自由な形に加工できます。しかし、変換処理がプログラムで記述されているため、HTMLのデザインが変更になった場合には、プログラム自体を再開発する必要があります。一方、[2]では変換ルールはスタイルシートに記述されるため、デザインが変更されてもプログラム自体を変更する必要はありません。頻繁にデザインが変更されるような環境では、スタイルシートで変換内容が修正できることは非常に便利です。
XSLTとは
ここで、XSLTについて簡単に説明しておきます。XMLデータをHTML形式などに変換して表示するための仕様は、すでにW3Cで標準化されています。このうち、XMLの構造変換に関する部分が先行して1999年11月に「XSLT(XSL Transformations)」という仕様が勧告されました。XMLの書式変換に関する「XSL-FO(FormattingObject:書式情報)」の部分は、2001年10月に「XSL(ExtensibleStylesheetLanguage)」という仕様で勧告されています。
XSLTでは、変換ルールをXML形式で記述したXSLTスタイルシートを使います。これを「XSLTプロセッサ」と呼ばれるアプリケーションが読み取り、指定されたXML文書を変換します(図2)。変換結果は、XML形式やHTML形式、テキスト形式で出力できます。
また、XSLではXML形式で書式情報を記述します(通常は基となるXML文書をXSLTで変換して書式情報を追加します)。これを「XSLフォーマッタ」というアプリケーションに読み込ませることでレイアウトが統一された表示結果や印刷物を得ることもできます(図3)。
これらの技術を使うことによって、XML形式で記述された電子データを基に、Webブラウザで閲覧したりプリントアウトして紙媒体で見たり、ということも可能となります。
XSLTスタイルシートによるデータ変換
それでは、実際にXSLTスタイルシートを使ってXMLデータをHTMLデータに変換してみましょう。ここでは、ユーザー情報を表わすXML文書(LIST1)をXSLTスタイルシート(LIST2)で変換する例を見ていきます。実際にHTML形式に変換されたデータがLIST3です。LIST1の2行目で、指定されたXSLTスタイルシート(list2.xsl)が適用されています。
LIST1:ソースXML文書(list1.xml)
01 <?xml version="1.0" encoding="Shift_JIS"?>
02 <?xml-stylesheet type="text/xsl" href="list2.xsl"?>
03 <ユーザーリスト>
04 <ユーザー>
05 <名前>山田太郎</名前>
06 <アカウント>yamada</アカウント>
07 </ユーザー>
08 </ユーザーリスト>
(※行番号は解説の便宜上付けたもので、実際のコードには不要です。以下同)
LIST2:XSLTスタイルシート(list2.xsl)
01 <?xml version="1.0" encoding="Shift_JIS"?>
02 <xsl:stylesheet version="1.0"
03 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
04 <xsl:template match="/">
05 <html>
06 <body>
07 <h1>ようこそ</h1>
08 こんにちは<xsl:value-of select="ユーザーリスト/ユーザー/名前" />さん<br/>
09 </body>
10 </html>
11 </xsl:template>
12 </xsl:stylesheet>
LIST3:変換結果(list3.html)
<html>
<body>
<h1>ようこそ</h1>
こんにちは山田太郎さん<br>
</body>
</html>
なお、InternetExplorer 5.x以降では、XML文書を開くと変換結果を表示できます(図4)。
図4:IEで見た変換結果
図4を見ると、LIST1のXML文書中の名前要素の内容が抽出され、HTMLに反映されています。これは、XSLTスタイルシートのどの部分で指示されているのでしょうか。そこでLIST2を見てみると、HTMLのタグとXSLTの命令が混合して記述されていることが分かります。この中からXSLTの命令がどれなのかを見分けるために、次の名前空間を指定しています。
http://www.w3.org/1999/XSL/Transform
この記述は、XSLTの命令であることを表わしています。これをXSLTの命令すべてに指定していると冗長になってしまうので、接頭辞と関連付けて使用します。接頭辞を何にするかは任意ですが、一般的にXSLTでは「xsl」という接頭辞を使うことが多く、接頭辞と要素名は「:」(コロン)で区切られます。つまり、「xsl:~」と記述することで、変換のための命令と出力するデータを区別できるのです。XSLTスタイルシートはXML文書なので、ルート要素が必要です。XSLTスタイルシートのルート要素は「xsl:stylesheet要素」です(図5)。
書式変換のためのさまざまな命令は、xsl:stylesheet要素の子要素に記述します。特にxsl:stylesheet要素の直下に記述できる要素のことを「トップレベルエレメント」と言います(表)。
表:トップレベルエレメントとして記述できる要素
key
param
template
decimal-format
namespace-alias
preserve-space
variable
include<
output
strip-space
また、具体的な変換内容を「テンプレート(LIST2の5~10行目)」と呼び、テンプレートは「テンプレートルール」内に記述します。テンプレートルールを表わしているのが「xsl:template要素」です(LIST2の4~11行目)。
なお、HTML文書はXML文書ではないので、記述の中には属性を引用符で囲まなかったり、開始タグしか記述しなかったり、XML文書として整形式にはならないといったさまざま書き方があります。しかし、XSLTスタイルシートはXML文書なので、必ず整形式である必要があります。したがって、HTMLのbr要素などは空要素で表現します(LIST2の8行目)。
変換元のXMLを指定するための仕様「XPath」
XMLデータから書式を変換するためには、ただ単にXSLTスタイルシートをかませれば良い、というわけではありません。「AをBへ変換する」といった、どのように変換するのかを明確に指定する必要があります。つまり、元となるデータAを指定しなければならないのです。そこで、書式変換の元となるXML文書を指定するための仕様として、1999年11月にW3Cから「XPath(XMLPath Language)」が勧告されました。
XPathでは、XML文書の構成要素をノードとして扱います。例えば、LIST4のXML文書をXPathによるノードで表現すると図6のようになります。
LIST4:カタログXML文書(list4.xml)
01 <?xml version="1.0" encoding="Shift_JIS"?>
02 <カタログ>
03 <タイトル>XML連載記念グッズ</タイトル>
04 <商品商品コード="p001">
05 <品名>XMLストラップ</品名>
06 <単価>700</単価>
07 </商品>
08 </カタログ>
XPathでは、ルートノード「/」を頂点とするツリー構造で表現されますが、ここで注意しなければならないのは「ルートノードとルート要素は異なる」という点です。ルート要素は要素のツリー構造に対するルートです。XML文書では、ルート要素の外側にもコメントや処理命令を記述できますので、これらをまとめるルートノードが存在するのです。
ノードを指定するには、ルートノードから順に各階層のノードを/で区切って指定します。例えばLIST4の品名要素であれば、XPath式は「/カタログ/商品/品名」となります。また、XSLTでは、テンプレートルールに対して処理対象とするノードを指定します。これがxsl:template要素のmatch属性(LIST5の4行目)です。
LIST5:XSLTスタイルシート(list5.xsl)
01 <?xml version="1.0" encoding="Shift_JIS"?>
02 <xsl:stylesheet version="1.0"
03 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
04 <xsl:template match="/">
05 <html>
06 <body>
07 <h1><xsl:value-of select="カタログ/タイトル" /></h1>
08 今回の目玉商品はコチラ<br/>
09 <table border="1" width="200">
10 <tr><th>品名</th><th>価格</th></tr>
11 <xsl:apply-templates select="カタログ/商品"/>
12 </table>
13 </body>
14 </html>
15 </xsl:template>
16 <xsl:template match="商品">
17 <tr>
18 <td><xsl:value-of select="品名" /></td>
19 <td><xsl:value-of select="単価" /></td>
20 </tr>
21 </xsl:template>
22 </xsl:stylesheet>
したがって、LIST5の4~15行目では、ルートノードを処理対象とするテンプレートルールを表わしていることになります。このとき、テンプレートルールの処理対象となっているノードを「カレントノード」と言います。XPathには、ルートノードから記述する「絶対パス」(図7)とカレントノードを基点として記述する「相対パス」(図8)があります。 LIST4の品名要素に対してカレントノードがカタログ要素ノードであるならば、XPath式は「商品/品名」となります。
なお、属性を指定する場合には「@属性名」と指定します。LIST4の商品コード属性を表わすXPath式は「商品/@商品コード」となります(図9)。
データを抽出する「xsl:value-of」命令
xsl:value-of命令を使うと、変換元のXML文書からデータを抽出して、変換結果として出力できます。xsl:value-of命令では、抽出したいデータをselect属性にXPath式で指定します(図10)
LIST2の8行目では、指定された「ユーザーリスト/ユーザー/名前」のテキスト内容である「山田太郎」が抽出され、変換結果として出力されます。
変換ルールを記述する「xsl:template」要素
xsl:template要素内には、具体的な変換処理内容をテンプレートとして記述します。match属性にはソースXML文書のどの部分を変換するのかを指定します(図11)。
XSLTプロセッサは、最初にルートノードを処理するテンプレートルールを適用し、適用されたテンプレートルール内のテンプレートを上から順に実行していきます(図12)。 プログラムのサブルーチンのように、複数のテンプレートルールを作成することもできます。
ほかのテンプレートルールを適用する「xsl:apply-templates」命令
テンプレートルールからほかのテンプレートルールを適用するにはxsl:apply-templates命令を使い、select属性によって変換元XML文書のどの部分を適用させたいのかをXPath式で指定します(図13)。LIST5では商品要素のデータを表示するために別のテンプレートを適用しています。
相対パスの指定
各xsl:template要素のmatch属性に指定されたノードがカレントノードとなるので、相対パスで指定するときには注意が必要です。LIST5の4~15行目では/(ルートノード)がカレントノード、16~21行目では商品要素ノードがカレントノードとなります。
今月の確認問題
さて、ここまでXSLTの特徴や基本的なXSLTスタイルシートの書き方について解説してきました。ここで、今回解説した内容がしっかりと理解できているかどうか、確認問題で復習してみましょう。
問題1
XSLTの利用方法として、間違っているものを選択してください。
- XMLデータをWebブラウザで表示するためにHTML形式に変換する
- XMLデータを他のシステムに転送するために、データの一部を抽出した別のXMLデータを出力する
- XMLデータをXML未対応のシステムに転送するため、テキスト形式であるCSV形式として出力する
- XMLデータを効率よく転送するために、圧縮形式のzip形式に変換する
解説
XSLTでは、XML形式やHTML形式、テキスト形式で出力できます。XML形式として基のデータの一部をコピーすることもできます。テキスト形式で出力するときに「,」(カンマ)で区切ることにより、CSV形式で出力することも可能です。ただし、バイナリ形式のファイルは出力できません。よって、正解はDです。
問題2
XSLTスタイルシートの書き方として正しいものを選択してください。
-
<?xml version="1.0"
encoding="Shift_JIS"?>
<stylesheet version="1.0">
<template match="/">
<html>
<body>
<h1>ようこそ</h1>
こんにちは<value-of select="ユーザーリスト/ユーザー/名前" />さん<br/>
</body>
</html>
</template>
</stylesheet> -
<?xml version="1.0" encoding="Shift_JIS"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<html>
<body>
<h1>ようこそ</h1>
こんにちは<xsl:value-of select="ユーザーリスト/ユーザー/名前" />さん<br/>
</body>
</html>
</xsl:stylesheet> -
<?xml version="1.0" encoding="Shift_JIS"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h1>ようこそ</h1>
こんにちは<xsl:value-of select="ユーザーリスト/ユーザー/名前" />さん<br>
</body>
</html>
</xsl:template>
</xsl:stylesheet> -
<?xml version="1.0" encoding="Shift_JIS"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h1>ようこそ</h1>
こんにちは<xsl:value-of select="ユーザーリスト/ユーザー/名前" />さん<br/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
解説
XSLTスタイルシートでは、名前空間として「http://www.w3.org/1999/XSL/Transform」が宣言され、名前空間に属する要素によって記述されなければなりません。XSLTと同じ名前の要素であっても、名前空間が指定されていなければXSLTの命令とは認識されません。
テンプレートはxsl:template要素の子要素として記述しますが、xsl:stylesheet要素の直下に記述することはできません。また、XSLTスタイルシートはXML文書ですので整形式である必要があります。HTMLのタグは、空要素タグとしてと記述します。よって正解はDです。
問題3
次のXML文書をXSLTスタイルシートによって変換し、HTML文書のような結果を得たいとき、[1]にあてはまる正しいXPathの記述を選択してください。
[XML文書]
<?xml version="1.0" encoding="Shift_JIS"?>
<おやつ>
<昨日>
<果物>バナナ</果物>
</昨日>
<今日>
<果物>スイカ</果物>
</今日>
<明日>
<果物>メロン</果物>
</明日>
</おやつ>
[XSLスタイルシート]
<?xml version="1.0" encoding="Shift_JIS"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h1>おやつ</h1>
<xsl:apply-templates select="おやつ/明日"/>
</body>
</html>
</xsl:template>
<xsl:template match="明日">
おやつは<xsl:value-of select="
" />です<br/>
</xsl:template>
</xsl:stylesheet>
[HTML文書]
<html>
<body>
<h1>おやつ</h1>
おやつはメロンです<br>
</body>
</html>
- /おやつ/明日/果物
- おやつ/明日/果物
- 明日/果物
- 果物
解説
XPathでは、絶対パスは/から書き始め、/で始まらないパスは相対パスです。この問題では、明日要素ノードの下にある果物要素ノードを指定します。絶対パスで表現すると「/おやつ/明日/果物」となり、相対パスの場合はxsl:template要素のmatch属性に指定されたノードがカレントノードとなります。ここではカレントノードが明日要素ノードとなるので相対パスで表現すると「果物」となります。よって、正解はAとDです。
* * *
今回は、XSLTの特徴や基本的なXSLTスタイルシートの書き方について解説しました。特にXSLTスタイルシートのルート要素は「xsl:stylesheet要素」、xsl:stylesheet要素の直下にできる要素は「トップレベルエレメント」と呼ばれること、XPathの「絶対パス」と「相対パス」の違いはしっかりと押さえておきましょう。また、テンプレートルールにおけるカレントノードを正確に把握できるようにしましょう。
次回は、より詳しいXPathの記述方法やXSLTの便利な命令について解説します。
鈴木智也(すずきともや)
株式会社東芝OAコンサルタント教育ソリューション技術部に勤務。インストラクタとして、主にXMLやプログラミング言語の講座を担当。日ごろのストレスを、週末にテニスボールへぶつけています。ネットに引っ掛けたりアウトしたりして、余計ストレスが増えているような気もしますが……。
<掲載> P.158-163 DB Magazine 2006 September