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