グループをまとめるタグ その2
グループをまとめるタグ その1で記述したXSLTには大きな欠点が一つありました.それは,「グループ内の要素が一つだと,グループをまとめるタグを作成できない」というものです.つまり,以下のsam.xmlにsam.xslを適応すると,item[potision()=last()]
のテンプレートだけを適応します.
<!-- sam.xml --> <?xml version="1.0" encoding="utf-8"?> <root> <item>a</item> </root> <!-- sam.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"/> <xsl:template match="/root"> <xsl:apply-templates select="item"/> </xsl:template> <xsl:template match="item[position()=1]"> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> <xsl:template match="item"> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> <xsl:template match="item[position()=last()]"> <dt><xsl:value-of select="self::node()"/></dt> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>/dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> </xsl:template> </xsl:stylesheet> <!-- 実行結果 --> $ xt sam.xml sam.xsl <?xml version="1.0" encoding="utf-8"?> <dt>a</dt></dl>
要素が一つしかないということは,position()=1 and position=last()
ということなので,sam.xslに修正を加えました.
<!-- sam.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"/> <xsl:template match="/root"> <xsl:apply-templates select="item"/> </xsl:template> <xsl:template match="item[position()=1 and position()=last()]"> <!-- itemが一つしかない場合 --> <dl> <dt><xsl:value-of select="self::node()"/></dt> </dl> </xsl:template> <xsl:template match="item[position()=1]"> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> <xsl:template match="item"> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> <xsl:template match="item[position()=last()]"> <dt><xsl:value-of select="self::node()"/></dt> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>/dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> </xsl:template> </xsl:stylesheet>
しかし,実行結果は同じでした.
<!-- 実行結果 -->
$ xt sam.xml sam.xsl
<?xml version="1.0" encoding="utf-8"?>
<dt>a</dt></dl>
何気なく順番を入替えてみました.
<!-- sam.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"/> <xsl:template match="/root"> <xsl:apply-templates select="item"/> </xsl:template> <xsl:template match="item[position()=1]"> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> <xsl:template match="item"> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> <xsl:template match="item[position()=last()]"> <dt><xsl:value-of select="self::node()"/></dt> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>/dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> </xsl:template> <xsl:template match="item[position()=1 and position()=last()]"> <!-- itemが一つしかない場合を一番下に --> <dl> <dt><xsl:value-of select="self::node()"/></dt> </dl> </xsl:template> </xsl:stylesheet> <!-- 実行結果 --> $ xt sam.xml sam.xsl <?xml version="1.0" encoding="utf-8"?> <dl><dt>a</dt></dl>
思っていたとおりの結果が出ました.もう少し試してみます.
<!-- sam.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"/> <xsl:template match="/root"> <xsl:apply-templates select="item"/> </xsl:template> <xsl:template match="item"> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> <xsl:template match="item[position()=last()]"> <dt><xsl:value-of select="self::node()"/></dt> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>/dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> </xsl:template> <xsl:template match="item[position()=1 and position()=last()]"> <dl> <dt><xsl:value-of select="self::node()"/></dt> </dl> </xsl:template> <xsl:template match="item[position()=1]"> <!-- 最初のitemに合致するテンプレートを一番下に --> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> </xsl:stylesheet> <!-- 実行結果 --> $ xt sam.xml sam.xsl <?xml version="1.0" encoding="utf-8"?> <dl><dt>a</dt> <!-- sam.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"/> <xsl:template match="/root"> <xsl:apply-templates select="item"/> </xsl:template> <xsl:template match="item[position()=last()]"> <dt><xsl:value-of select="self::node()"/></dt> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>/dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> </xsl:template> <xsl:template match="item[position()=1 and position()=last()]"> <dl> <dt><xsl:value-of select="self::node()"/></dt> </dl> </xsl:template> <xsl:template match="item[position()=1]"> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> <xsl:template match="item"> <!-- 最初と最後以外のitemに合致するテンプレートを一番下に --> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> </xsl:stylesheet> <!-- 実行結果 --> $ xt sam.xml sam.xsl <?xml version="1.0" encoding="utf-8"?> <dl><dt>a</dt>
一つしかないitem要素は
- item[position()=1]
- item[position()=last()]
- item[position()=1 and position()=last()]
の三つのテンプレートに合致し,XSLTの優先順序(最後に定義したテンプレートを優先)従い,一番最後にあるテンプレートが有効になっていたようです.item[position()=1 and position()=last()]
を持つテンプレートを最後に書けば思ったとおりのことができます.しかし,忘れそうなので,priority
属性で優先順位を指定することとしました.
<!-- sam.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"/> <xsl:template match="/root"> <xsl:apply-templates select="item"/> </xsl:template> <xsl:template match="item[position()=1 and position()=last()]" priority="1"> <!-- itemが一つしかない場合はこのテンプレートを優先する --> <dl> <dt><xsl:value-of select="self::node()"/></dt> </dl> </xsl:template> <xsl:template match="item[position()=1]"> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> <xsl:template match="item"> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> <xsl:template match="item[position()=last()]"> <dt><xsl:value-of select="self::node()"/></dt> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>/dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> </xsl:template> </xsl:stylesheet> <!-- 実行結果 --> $ xt sam.xml sam.xsl <?xml version="1.0" encoding="utf-8"?> <dl><dt>a</dt></dl>
priorityを使わず,以下のやり方でも同様の結果となります.
<!-- sam.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"/> <xsl:template match="/root"> <xsl:apply-templates select="item"/> </xsl:template> <xsl:template match="item[position()=1 and position()=last()]"> <!-- itemが一つしかない場合はこのテンプレート --> <dl> <dt><xsl:value-of select="self::node()"/></dt> </dl> </xsl:template> <xsl:template match="item[position()=1 and position()!=last()]"> <!-- itemが複数ある場合の先頭はこのテンプレート --> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> <xsl:template match="item"> <dt><xsl:value-of select="self::node()"/></dt> </xsl:template> <xsl:template match="item[position()!=1 and position()=last()]"> <!-- itemが複数ある場合の最後はこのテンプレート --> <dt><xsl:value-of select="self::node()"/></dt> <xsl:text disable-output-escaping="yes"><</xsl:text> <xsl:text>/dl</xsl:text> <xsl:text disable-output-escaping="yes">></xsl:text> </xsl:template> </xsl:stylesheet> <!-- 実行結果 --> $ xt sam.xml sam.xsl <?xml version="1.0" encoding="utf-8"?> <dl><dt>a</dt></dl>
トップページを作るXSLTのcontent部分も再修正です.
<!-- 修正後 -->
<xsl:template match="content[position()=1 and position()=last()]" priority="1">
<dl class="contents">
<xsl:call-template name="content"/>
</dl>
</xsl:template>
<xsl:template match="content[position()=1]">
<xsl:text disable-output-escaping="yes"><</xsl:text>
<xsl:text>dl class="contents"</xsl:text>
<xsl:text disable-output-escaping="yes">></xsl:text>
<xsl:call-template name="content"/>
</xsl:template>
<xsl:template match="content">
<xsl:call-template name="content"/>
</xsl:template>
<xsl:template match="content[position()=last()]">
<xsl:call-template name="content"/>
<xsl:text disable-output-escaping="yes"><</xsl:text>
<xsl:text>/dl</xsl:text>
<xsl:text disable-output-escaping="yes">></xsl:text>
</xsl:template>
<xsl:template name="content">
<dt><a href="{@href}"><xsl:value-of select="@name"/></a></dt>
<dd>
<xsl:apply-templates/>
</dd>
</xsl:template>