グループをまとめるタグ その1

まず,index.xmlとindex.htmlの同じ部分を見比べてください.

<!-- index.xml -->
<contents>
  <content href="whatsnew/index.html" name="新着">
    2002.12.1
    <ul>
      <li><a href="saijiki/index.html">歳時記</a>に2002.11.24から2002.11.30までを追加.</li>
      <li><a href="biboroku/index.html">備忘録</a>のXML+XSLTに「wwwc用metaタグを作る」を追加.</li>
    </ul>
  </content>

  <content href="saijiki/index.html" name="歳時記">
    日々の出来事など.
  </content>

  <content href="ryokoki/index.html" name="旅行記">
    旅先での写真や駄文を.
  </content>

  <content href="hyoryuki/index.html" name="漂流記">
    システム開発への私見です.
  </content>

  <content href="biboroku/index.html" name="備忘録">
    教えてもらったことやできたことを忘れないうちに.
  </content>

  <content href="zatsuroku/index.html" name="雑録">
    その他雑多なものが色々.
  </content>

  <content href="links/index.html" name="リンク">
    友人・知合い,便利なソフトウェア,参考になるサイト等.
  </content>
</contents>

<!-- index.html -->
<dl class="contents">
  <dt><a href="whatsnew/index.html">新着</a></dt>
  <dd>
    2002.12.1
    <ul>
      <li><a href="saijiki/index.html">歳時記</a>に2002.11.24から2002.11.30までを追加.</li>
      <li><a href="biboroku/index.html">備忘録</a>のXML+XSLTに「wwwc用metaタグを作る」を追加.</li>
    </ul>
  </dd>

  <dt><a href="saijiki/index.html">歳時記</a></dt>
  <dd>日々の出来事など.</dd>

  <dt><a href="ryokoki/index.html">旅行記</a></dt>
  <dd>旅先での写真や駄文を.</dd>

  <dt><a href="hyoryuki/index.html">漂流記</a></dt>
  <dd>システム開発への私見です.</dd>

  <dt><a href="biboroku/index.html">備忘録</a></dt>
  <dd>教えてもらったことやできたことを忘れないうちに.</dd>

  <dt><a href="zatsuroku/index.html">雑録</a></dt>
  <dd>その他雑多なものが色々.</dd>

  <dt><a href="links/index.html">リンク</a></dt>
  <dd>友人・知合い,便利なソフトウェア,参考になるサイト等.</dd>
</dl>
  

XMLの<contents>とHTMLの<dl>,XMLの<content>とHTMLの<dt>,XMLのテキストノードとHTMLの<dd>がそれぞれ対応しているのがわかります.当初作成していたHTMLを元にXMLを作ったので,要素が対応づいているのは,当然といえば当然です.

ある日気がつきました.XMLの<contents>はHTMLの<dl>を作るためだけに存在しているタグです.いらないのではないかと.つまり,繰返している<content>の最初の要素の前に<dl>を,最後の要素の後に</dl>をXSLTでつけてやれば,グループを囲っている<contents>はいらなくなります.つまり,index.xmlからcontents要素をなくし,最初と最後のcontent要素で<dl></dl>を作るXSLTを作れば,事足りそうです.

<!-- index.xml -->
<content href="whatsnew/index.html" name="新着"> <!-- 一番最初のcontentの前に<dl> -->
  2002.12.1
  <ul>
    <li><a href="saijiki/index.html">歳時記</a>に2002.11.24から2002.11.30までを追加.</li>
    <li><a href="biboroku/index.html">備忘録</a>のXML+XSLTに「wwwc用metaタグを作る」を追加.</li>
  </ul>
</content>

<content href="saijiki/index.html" name="歳時記">
  日々の出来事など.
</content>

<content href="ryokoki/index.html" name="旅行記">
  旅先での写真や駄文を.
</content>

<content href="hyoryuki/index.html" name="漂流記">
  システム開発への私見です.
</content>

<content href="biboroku/index.html" name="備忘録">
  教えてもらったことやできたことを忘れないうちに.
</content>

<content href="zatsuroku/index.html" name="雑録">
  その他雑多なものが色々.
</content>

<content href="links/index.html" name="リンク"> <!-- 一番最後のcontentの後に</dl> -->
  友人・知合い,便利なソフトウェア,参考になるサイト等.
</content>
  

まずは簡単なサンプルで試してみることにしました.以下のsam.xmlから<dl></dl>で囲った結果を出すXSLTを作ることにします.

<!-- sam.xml -->
<?xml version="1.0" encoding="utf-8"?>
<root>
  <item>a</item>
  <item>b</item>
  <item>c</item>
</root>

<!-- 出力結果 -->
<?xml version="1.0" encoding="utf-8"?>
<dl>
  <dt>a</dt>
  <dt>b</dt>
  <dt>c</dt>
</dl>
  

最初に考えたのはこんなXSLTです.これはエラーになります.開始タグ<dl>に対応する終了タグが別のタグの中にあるため,整形式のXMLではないのです.

<!-- 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]">
    <dl> <!-- 整形式XMLとしては,このタグに対応する終了タグは -->
      <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>
    </dl> <!-- ここに終了タグを書くと整形式XMLではない -->
  </xsl:template>
</xsl:stylesheet>
  

<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">&lt;</xsl:text>
    <xsl:text>dl</xsl:text>
    <xsl:text disable-output-escaping="yes">&gt;</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">&lt;</xsl:text>
    <xsl:text>/dl</xsl:text>
    <xsl:text disable-output-escaping="yes">&gt;</xsl:text>
  </xsl:template>
</xsl:stylesheet>
  

実行結果です.うまくいきました.

$ xt sam.xml sam.xsl
<?xml version="1.0" encoding="utf-8"?>
<dl><dt>a</dt><dt>b</dt><dt>c</dt></dl>
  

ちなみに,sam.xslは<xsl:choose>を使って書くこともできます.

<!-- sam.xsl xsl:choose版 -->
<?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">
    <xsl:choose>
      <xsl:when test="position()=1">
        <xsl:text disable-output-escaping="yes">&lt;</xsl:text>
        <xsl:text>dl</xsl:text>
        <xsl:text disable-output-escaping="yes">&gt;</xsl:text>
        <dt><xsl:value-of select="self::node()"/></dt>
      </xsl:when>
      <xsl:when test="position()=last()">
        <dt><xsl:value-of select="self::node()"/></dt>
        <xsl:text disable-output-escaping="yes">&lt;</xsl:text>
        <xsl:text>/dl</xsl:text>
        <xsl:text disable-output-escaping="yes">&gt;</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <dt><xsl:value-of select="self::node()"/></dt>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>
  

この結果で,トップページを作っているXSLTにあるcontentのテンプレートも書換えます.

<!-- 修正前 -->
<xsl:template match="contents">
  <dl class="{name()}">
    <xsl:apply-templates/>
  </dl>
</xsl:template>

<xsl:template match="content">
  <dt><a href="{@href}"><xsl:value-of select="@name"/></a></dt>
  <dd>
    <xsl:apply-templates/>
  </dd>
</xsl:template>

<!-- 修正後 -->
<xsl:template match="content[position()=1]">
  <xsl:text disable-output-escaping="yes">&lt;</xsl:text>
  <xsl:text>dl class="contents"</xsl:text>
  <xsl:text disable-output-escaping="yes">&gt;</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">&lt;</xsl:text>
  <xsl:text>/dl</xsl:text>
  <xsl:text disable-output-escaping="yes">&gt;</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>