revised: Nov./16th/2003
XSLT (XSL Transformations)は、XML文書の木構造を別の構造へ変換するための仕様です。XSLT自身が、XMLベースのマークアップ言語であり、入力XML文書をソース・ツリー(source tree)と呼び、結果のXML文書を結果ツリー(result tree)と呼びます。
XSLTは、そもそもXML文書のスタイルを記述するための仕様であるXSL (Extensible Stylesheet Languag)の一部として策定されていましたが、勧告まで纏め上げるのに手間取ったため、1999年11月にXSLTのみ先行して勧告されました。XSLも2001年10月に勧告にいたっています。
XSLは、XSLT部分とXSL-FO (Formatting Object)という部分の二つの部分を含んでいます。XSL-FOは、XML文書の表示体裁を指定するものです。HTML以来使われているスタイルシートであるCSS (Cascading Style Sheet)は、文書の表示体裁を指定するものであり、この部分はFOが担うことになります。一方、機械処理を前提とするXMLデータでは、特定の要素を抜き出したり、表形式にしたり、別の文書型に変換したりといった構造変換の仕組みが必要とされました。これを担うのがXSLTです。
XML文書を処理するに当たり、DOM/SAXなどのAPIを使えば、自由に処理することが可能ですが、構造に対するマッチングの判定や入出力などなどは、長大なif-else if構造やswitch構造の中に、println()やStringBuffer.append()を繰り返し記述するような、退屈で込み入ったコードが必要となります。このようなときに、XSLTプロセッサを使えば、要素の木構造変換を簡単に行うことが可能となります。
XSLTは、XMLベースのマークアップ言語として定義されています。しかし、DTDやXML Schemaによるスキーマ定義は与えられておらず、仕様書のなかで要素のシンタックスと意味が定義されています。XML文書のボキャブラリとしては、名前空間URIに "http://www.w3.org/1999/XSL/Transform" が与えられています。
参考情報として、XSLT 1.0仕様書には、DTDによる文書型定義が挙げられており、現在策定中でワーキング・ドラフト段階にあるのXSLT 2.0には、XML Schemaによるスキーマが挙げられています。名前空間URIは、XSLT 2.0でも "http://www.w3.org/1999/XSL/Transform" のままであり、バージョンはstylesheet要素のversion属性の値で示すことになります。
論より証拠で、最初に簡単なXSLTのサンプルを見てみましょう。リスト2は、リスト1のXML文書 (XPathDemo.xml) をソースツリーとして、結果ツリーである"result.xml" を生成するためのXSLT文書です。
リスト1. XML文書のサンプル(XPathDemo.xml)
<?xml version="1.0" encoding="UTF-8"?>
<address>
<item sex="male" custid="E21099">
<name>菅井 学</name>
<access kind="email"></access>
<access kind="url">http://www.nextindex.net/java/</access>
<image file="msugai.png" />
</item>
<item sex="male" custid="E27989">
<name>鈴木 竜広</name>
<access kind="email">tsuzuki@hoge.foo.bar</access>
<image file="tsuzuki.png" />
</item>
<item sex="female" custid="E29435">
<name>栃原 宏枝</name>
<access kind="tel">090-xxxx-xxxx</access>
<image file="tochi.png" />
</item>
</address>
リスト2. XSLT文書(XSLTDemo.xsl)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- 結果ツリーの出力方法 -->
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<!-- テンプレート1 -->
<xsl:template match="/">
<namelist>
<male>男性:<xsl:apply-templates select="/address/item[@sex='male']"/></male>
<female>女性:<xsl:apply-templates select="/address/item[@sex='female']"/></female>
</namelist>
</xsl:template>
<!-- テンプレート2 -->
<xsl:template match="/address/item[@sex='male']">
<cust><xsl:value-of select="./name"/>, <xsl:value-of select="./@custid"/></cust>
</xsl:template>
<!-- テンプレート3 -->
<xsl:template match="/address/item[@sex='female']">
<cust><xsl:value-of select="./name"/>, <xsl:value-of select="./@custid"/></cust>
</xsl:template>
</xsl:stylesheet>
XSLTの説明は後回しにして、Javaのコードも紹介しましょう。XSLTとXML文書を読み込んで、結果ツリーを出力するJavaのソースコードはリスト3のようになります。
リスト3. XSLTプロセッサを利用するコード(XSLTDemo.java)
import java.io.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
class XSLTDemo {
public static void main(String[] args) {
try {
// XSLTのストリーム・ソース
StreamSource xsltSrc = new StreamSource(args[0]);
// ソース・ツリーのストリーム・ソース
StreamSource source = new StreamSource(args[1]);
// 結果ツリーのストリーム・リザルト
StreamResult result = new StreamResult(new FileOutputStream("result.xml"));
// XSLTプロセッサのファクトリの生成
TransformerFactory tFactory = TransformerFactory.newInstance();
// XSLTプロセッサの生成
Transformer transformer = tFactory.newTransformer(xsltSrc);
// 変換と結果ツリーの出力
transformer.transform(source, result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
リスト3はJAXPで用意されているAPIにより記述しています。JAXPでは、XSLTを処理するために、ストリーム、DOM、SAXの三つの入出力APIを用意していますが、ストリームは最も原始的なものです。いずれの場合も、XSLTプロセッサの実装を抽象化するクラス javax.xml.transform.Transformer を、ファクトリー・クラス javax.xml.transform.TransformerFactory で生成します。Transformer オブジェクトは、特定のXSLT文書に関連付けられて、ファクトリー・メソッド newFactory() により生成されるので、XSLT文書を変更しないのであれば、複数のXML文書の変換に対して、Transformer オブジェクトの生成は一回で済みます。
ソースツリーであるリスト1 (XPathDemo.xml)、XSLT文書であるリスト2 (XSLTDemo.xsl)、及びJavaアプリケーションのソースリスト3 (XSLTDemo.java)を同じディレクトリに置いて実行した結果が、次に挙げるリスト4です。結果ツリーは "result.xml"(リスト5)に出力されます。
リスト4. XSLTDemo.javaの実行結果
>javac XSLTDemo.java >java XSLTDemo XSLTDemo.xsl XPathDemo.xml >
リスト5. ソースXPathDemo.xmlにXSLT文書XSLTDemo.xslを適用した結果ツリー(result.xml)
<?xml version="1.0" encoding="UTF-8"?> <namelist> <male>男性:<cust>菅井 学, E21099</cust> <cust>鈴木 竜広, E27989</cust> </male> <female>女性:<cust>栃原 宏枝, E29435</cust> </female> </namelist>