xsltとは、Extensible Stylesheet Language
の略で、データを木構造で格納したxml文書を処理する技術のことです。
雛形であるxslにxmlのデータを流し込むとアウトプットとしてhtmlが生成されるイメージ。
サンプルとして、以下のような階層構造を持ったxmlを用意します。
<?xml version="1.0" encoding="UTF-8"?>
<person>
<item class="employee" id="00001">
<name>一郎</name>
<age>20</age>
<phone type="private">111-111-111</phone>
<phone type="business">100-000-000</phone>
</item>
<item class="employee" id="00002">
<name>二郎</name>
<age>30</age>
<phone type="private">222-222-222</phone>
<phone type="business">200-000-000</phone>
</item>
<item class="director" id="00003">
<name>三郎</name>
<age>40</age>
<phone type="private">333-333-333</phone>
<phone type="business">300-000-000</phone>
<phone type="secret">999-999-999</phone>
</item>
</person>
以下の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="html" indent="yes" encoding="UTF-8"/>
<!-- ルート階層-->
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<!-- /person階層 -->
<xsl:template match="person">
<xsl:apply-templates />
</xsl:template>
<!-- /person/item階層-->
<xsl:template match="item">
<xsl:apply-templates select="name"/>
<xsl:apply-templates select="age"/>
<xsl:apply-templates select="phone[@type='private']"/>
</xsl:template>
<!-- /person/item/name階層 -->
<xsl:template match="name">
<p>名前:<xsl:value-of select="."/></p>
</xsl:template>
<!-- /person/item/age階層 -->
<xsl:template match="age">
<p>年齢:<xsl:value-of select="."/></p>
</xsl:template>
<!-- /person/item/phone@private階層 -->
<xsl:template match="phone[@type='private']">
<p>電話番号(私用):<xsl:value-of select="."/></p>
<!-- 1階層上を参照 -->
<p>電話番号(仕事):<xsl:value-of select="../phone[@type='business']"/></p>
<p>1階層上の年齢:<xsl:value-of select="../age"/></p>
</xsl:template>
</xsl:stylesheet>
すると結果は以下のようになります。
<html>
<body>
<p>名前:一郎</p>
<p>年齢:20</p>
<p>電話番号(私用):111-111-111</p>
<p>電話番号(仕事):100-000-000</p>
<p>一回層上の年齢:20</p>
<p>名前:二郎</p>
<p>年齢:30</p>
<p>電話番号(私用):222-222-222</p>
<p>電話番号(仕事):200-000-000</p>
<p>一回層上の年齢:30</p>
<p>名前:三郎</p>
<p>年齢:40</p>
<p>電話番号(私用):333-333-333</p>
<p>電話番号(仕事):300-000-000</p>
<p>一回層上の年齢:40</p>
</body>
</html>
select
属性<xsl:value-of select="."/></p>
もしくはcurrent()
を使用して以下のとおり。
<xsl:value-of select="current()"/>
<xsl:apply-templates select="name"/>
もしくは./
を付けて以下のとおり。
<xsl:apply-templates select="./name"/>
/
から書き始めると絶対パスと解釈されます。
※ただし、以下の記述は最初に見つかったnameの値が取得されます。
<xsl:value-of select="/person/item/name"/>
現在位置の1階層上を指すには以下のように記述します。
<xsl:value-of select="../age"/>
xsl:template
要素name属性またはmatch属性を指定する必要があります。
name属性を指定した場合は、属性値を使って、xsl:call-template要素
を用いることで呼び出すことができます。
match属性を指定した場合は、xsl:apply-templates
要素を用いることで呼び出すことができます。
<!-- name属性の場合 -->
<xsl:template name="aaa">
<p>test</p>
</xsl:template>
<!-- match属性の場合 -->
<xsl:template match="bbb">
<p>test</p>
</xsl:template>
xsl:call-template
要素xsl:call-template
要素は名前付きテンプレートを呼び出すことができます。
名前付きテンプレートとは以下のようにname属性で定義されたテンプレートのことです。
<xsl:template name="itiran">
<h1>社員一覧</h1>
</xsl:template>
上記のテンプレートを呼び出す際は以下のように記述します。
<xsl:call-template name="itiran" />
そのため、<xsl:template match="/abc/def">
のようにmatch
属性で定義されたテンプレートを呼び出すことはできません。
match属性で定義されたテンプレートを呼び出すにはxsl:apply-templates
要素を使用します。
xsl:apply-templates
要素xsl:apply-templates
要素は、select
属性で指定したパターンとマッチするテンプレートを呼び出します。
また、パターンにマッチするすべてのノードに対してテンプレートが適用されます。
つまり、xml側にノードが存在しない場合は、テンプレートは呼び出されません。
サンプルの階層構造からitem
要素がclass="employee"
のノードの値を取得したい場合、テンプレートは以下のように定義します。
<xsl:template match="/person/item[@class='employee']">
<p><xsl:value-of select="./@id"/>,<xsl:value-of select="./name"/>,<xsl:value-of select="./age"/>,<xsl:value-of select="./phone[@type='private']"/></p>
</xsl:template>
上記のテンプレートを呼び出すには、xsl:apply-templates
要素を使って以下のように記述します。
<div><xsl:apply-templates select="/person/item[@class='employee']"/></div>
xsl:value-of
要素xsl:value-of
要素は、select
属性に指定したパターンとマッチする値を取得します。
次郎さんの名前を取得したい場合は以下のように記述します。
<xsl:value-of select="/person/item[@id='00002']/name"/>
また三郎さんの仕事用の電話番号を取得したい場合は以下のように記述します。
<xsl:value-of select="/person/item[@id='00003']/phone[@type='business']"/>
なお、すべてのnameを取得しようとして<xsl:value-of select="/person/item/name"/>
を実行しても、これはうまく動きません。最初にヒットした「一郎」のみが取得できます。
すべてのnameを取得するには後述するxsl:for-each
要素を使用します。
xsl:for-each
要素xsl:for-each
要素は、select
属性の値にマッチするすべてのノードに対して繰り返し処理を行います。
item要素から全てのnameの値を取得するには以下のように記述します。
<xsl:for-each select="/person/item">
<xsl:value-of select="./name"/>
</xsl:for-each>
xsl:if
要素xsl:if
要素は、条件によって処理を分岐する要素です。
test
属性には式を指定します。式の評価がtrue
の場合のみ、xsl:if
要素の中身が実行されます。false
の場合は何も実行されません。
item要素のclassの属性の値が「employee」なら「従業員」、「director」なら「部長」を表示するには以下のように記述します。
<!-- item要素の数だけループ -->
<xsl:for-each select="/person/item">
<p><xsl:value-of select="./name"/></p>
<xsl:if test="@class='employee'">
<p>従業員</p>
</xsl:if>
<xsl:if test="@class='director'">
<p>部長</p>
</xsl:if>
</xsl:for-each>
変数を宣言するには2通りの方法があります。
xsl:param
要素以下のように記述します。属性typeの値を変数「type」に格納するという意味です。
<xsl:param name="type" select="@type"/>
任意の値を持たせるには以下のように記述します。appleという文字列を変数「str」に格納するという意味です。
<xsl:param name="str" >apple</xsl:param>
数値を指定する場合は、以下の記述方法でも設定できます。
<xsl:param name="size" select="16"/>
xsl:variable
要素以下のように記述します。属性typeの値を変数「type」に格納するという意味です。
<xsl:variable name="type" select="@type"/>
任意の値を持たせるには以下のように記述します。lemonという文字列を変数「str」に格納するという意味です。
<xsl:variable name="str" >lemon</xsl:variable>
数値を指定する場合は、以下の記述方法でも設定できます。
<xsl:variable name="size" select="16"/>
java側で変数に初期値をセットしてxslファイルに渡すには、 transformer.setParameter();
を使用します。
Java側のサンプルは以下のとおり。
public static void main(String[] args) {
try {
// XSLTファイルの指定
StreamSource template = new StreamSource("sampleXSLT.xsl");
// XMLファイルの指定
StreamSource xml = new StreamSource("sampleXML.xml");
// 出力ファイルの指定
StreamResult result = new StreamResult(new FileOutputStream("result.xml"));
// XSLTプロセッサのファクトリの生成
TransformerFactory tFactory = TransformerFactory.newInstance();
// XSLTプロセッサの生成
Transformer transformer = tFactory.newTransformer(template);
// 変数の初期化
transformer.setParameter("fruits", "apple");
// 実行
transformer.transform(xml, result);
} catch (Exception e) {
e.printStackTrace();
}
}
xsl側のサンプルは以下のとおり。xsl:variable
要素だと値を受け取れないようなので、xsl:param
要素で変数宣言します。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" encoding="UTF-8"/>
<xsl:param name="fruits" select="100"/>
<!-- ルート階層-->
<xsl:template match="/">
<html>
<body>
<xsl:value-of select="$fruits"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
結果は以下のとおりです。
<html>
<body>apple</body>
</html>
xsl:choose
要素とxsl:when
要素とxsl:otherwise
要素xsl:choose
要素とxsl:when
要素とxsl:otherwise
要素はセットで使用します。
いわゆるcase文に相当します。なおxsl:otherwise
要素は省略可能です。
<!-- item要素の数だけループ -->
<xsl:for-each select="/person/item">
<p><xsl:value-of select="./name"/></p>
<!-- phone要素の数だけループ -->
<xsl:for-each select="./phone">
<!-- phone要素のtype属性の値を変数「type」に格納 -->
<xsl:variable name="type" select="@type"/>
<!-- 条件分岐処理 -->
<xsl:choose>
<xsl:when test="$type='private'">プライベート用</xsl:when>
<xsl:when test="$type='business'">仕事用</xsl:when>
<xsl:otherwise>秘密の電話番号 </xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:for-each>
例えば、xml内にphone要素がいくつあるのかをカウントして表示するには以下のように記述します。
phoneの先頭に//
を付与して//phone
と指定します。
<xsl:variable name="n" select="count(//phone)"/>
<xsl:value-of select="$n"/>
同じ要素が何回登場するか。つまり同名の兄弟要素がいくつあるかをカウントしてくれる。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" encoding="UTF-8"/>
<!-- ルート階層-->
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<!-- /person階層 -->
<xsl:template match="person">
<xsl:apply-templates />
</xsl:template>
<!-- /person/item階層-->
<xsl:template match="item">
<xsl:apply-templates select="phone"/>
</xsl:template>
<!-- /person/item/name階層 -->
<xsl:template match="phone">
<p>電話番号:<xsl:value-of select="current()"/></p>
<p>Position:<xsl:value-of select="position()"/></p>
</xsl:template>
</xsl:stylesheet>
実行結果は以下のとおり。パターンにマッチしてテンプレートが実行されるたびに1からの採番になる。
<html>
<body>
<p>電話番号:111-111-111</p>
<p>Position:1</p>
<p>電話番号:100-000-000</p>
<p>Position:2</p>
<p>電話番号:222-222-222</p>
<p>Position:1</p>
<p>電話番号:200-000-000</p>
<p>Position:2</p>
<p>電話番号:333-333-333</p>
<p>Position:1</p>
<p>電話番号:300-000-000</p>
<p>Position:2</p>
<p>電話番号:999-999-999</p>
<p>Position:3</p>
</body>
</html>
xsl:element
要素要素を生成します。
<xsl:element name="html">
<xsl:element name="body">
<xsl:element name="div">test</xsl:element>
</xsl:element>
</xsl:element>
上記を実行すると、以下のように生成されます。
<html>
<body>
<div>test</div>
</body>
</html>
xsl:attribute
要素要素に属性を付与します。
<xsl:variable name="str" >lemon</xsl:variable>
<xsl:element name="html">
<xsl:element name="body">
<xsl:element name="div">
<xsl:attribute name="class">
<xsl:value-of select="$str"/>
</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
上記を実行すると、以下のように生成されます。
<html>
<body>
<div class="lemon"></div>
</body>
</html>
以上で記事の解説はお終い!
もっとJavaやSpringを勉強したい方にはUdemyがオススメ!同僚に差をつけよう!