mode属性を使ってマッチする/しないを切替える
やりたいこと
前後の兄弟要素をdiv
で囲みたい.具体的には,以下の変換前のxmlのh1
とol
をdiv
で囲み,変換後のxmlにしたい.ちなみに,li
の中にあるnew
要素もspan class="new"
に変換する.
<!-- 変換前のxml -->
<?xml version="1.0" encoding="UTF-8"?>
<root>
<h1>見出し</h1>
<ol>
<li><new/>項目1</li>
<li>項目2</li>
<li>項目3</li>
</ol>
</root>
<!-- 変換後のxml -->
<?xml version="1.0" encoding="UTF-8"?>
<root>
<div> <!-- h1とolをdivで囲む -->
<h1>見出し</h1>
<ol>
<li><span class="new">new</span>項目1</li> <!-- newをspan class="new"に変換-->
<li>項目2</li>
<li>項目3</li>
</ol>
</div>
</root>
うまくいかない
最初に試したxslが以下の内容.following-sibling
軸を使ってh1
と直後のol
をdiv
の中で出力している.
<!-- 最初に試したxsl -->
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/root/h1">
<root>
<div> <!-- divで囲んで -->
<xsl:copy-of select="."/> <!-- h1と -->
<xsl:apply-templates select="following-sibling::ol"/> <!-- olを出力 -->
</div>
</root>
</xsl:template>
<xsl:template match="ol">
<ol>
<xsl:apply-templates/>
</ol>
</xsl:template>
<xsl:template match="li">
<li><xsl:apply-templates/></li>
</xsl:template>
<xsl:template match="new">
<span class="{name()}"><xsl:copy-of select="name()"/></span>
</xsl:template>
</xsl:stylesheet>
実行結果は以下の通り.h1
とol
をdiv
で囲むことはできたが,不要なol
も出力している.h1
の兄弟要素(following-sibling::ol
)として出力したol
とol
自身の2回である.h1
の兄弟要素のol
は出力して,ol
自身の出力はしないスタイルシートを作る必要がある.
<!-- 実行結果 -->
<?xml version="1.0" encoding="UTF-8"?>
<root>
<div> <!-- h1とolをdivで囲めた -->
<h1>見出し</h1>
<ol>
<li><span class="new">new</span>項目1</li>
<li>項目2</li>
<li>項目3</li>
</ol>
</div>
</root>
<ol> <!-- このolはいらない -->
<li><span class="new">new</span>項目1</li>
<li>項目2</li>
<li>項目3</li>
</ol>
mode属性で出力を制御
match
属性にfollowing-sibling::ol
は書けない.マッチするテンプレートを指定するためにmode
属性を使用する.つまり,以下のようにする.
ol
自身は出力のないテンプレートを適応following-sibling::ol
にはmode
を指定したテンプレートを適応
<!-- modeを指定したxsl -->
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/root/h1">
<root>
<div>
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::ol" mode="mode01"/> <!-- mode属性でマッチするテンプレートを指定 -->
</div>
</root>
</xsl:template>
<xsl:template match="ol" mode="mode01"> <!--following-sibling::olにマッチするテンプレート -->
<ol>
<xsl:apply-templates/>
</ol>
</xsl:template>
<xsl:template match="ol"/> <!-- ol自身にマッチするテンプレート.出力なし -->
<xsl:template match="li">
<li><xsl:apply-templates/></li>
</xsl:template>
<xsl:template match="new">
<span class="{name()}"><xsl:copy-of select="name()"/></span>
</xsl:template>
</xsl:stylesheet>
ちなみに
new
要素をspan class="new"
に変換する必要がなく,ol
以下の要素をそのまま出力すれば良い場合は,mode
属性なしでスタイルシートを作成できる.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/root/h1">
<root>
<div>
<xsl:copy-of select="."/>
<xsl:copy-of select="following-sibling::ol"/> <!-- そのまま出力 -->
</div>
</root>
</xsl:template>
<xsl:template match="ol"/> <!-- ol自身にマッチするテンプレート.出力なし -->
</xsl:stylesheet>
実行環境
- xalan-j 2.7.2
- openJDK 1.8.0_121
- FreeBSD 11.0