特定の条件で属性をつける

はじめに

ある特定の条件の場合だけ要素に属性をつけたいとする.例として

xsltの中のcolor変数に値がある場合はbody要素のcolor属性に変数の値をつける

と言う場合を考えてみよう.xsltプロセッサはSaxonを使用する.下記の例の中にある${saxon_home}はSaxonをインストールしたディレクトリのことだ.colorにblueを設定して

$ java -cp "${saxon_home}/saxon8.jar;." net.sf.saxon.Transform -novw foo.xml foo.xsl color=blue

とした場合には

<?xml version="1.0" encoding="UTF-8"?>
<body color="blue">  <!-- color属性に引数で指定したblueを設定 -->
  ここに本文
</body>

colorに何も値を設定せずに

$ java -cp "${saxon_home}/saxon8.jar;." net.sf.saxon.Transform -novw foo.xml foo.xsl

とした場合には

<?xml version="1.0" encoding="UTF-8"?>
<body>
  ここに本文
</body>

となるようにしたい.xmlはこんな内容にしておこう.

<!-- foo.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<root>
  <foo/>
</root>

単純にbody要素を書き分けると整形式ではなくなる

xsltを考えよう.まず思いついたのはこんなものだが,これは整形式のxmlではないのでエラーとなり動かない.<xsl:choose>で場合分けしている<body>の閉じタグの位置がずれているためだ.

<!-- foo.xsl -->
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:param name="color"/>

  <xsl:template match="/root">
    <xsl:choose>
      <xsl:when test="$color">
        <body color="{$color}"> <!-- bodyの閉じタグが同じレベルにないのでエラー -->
      </xsl:when>
      <xsl:otherwise>
        <body> <!-- bodyの閉じタグが同じレベルにないのでエラー -->
      </xsl:otherwise>
    </xsl:choose>
    ここに本文
    </body>
  </xsl:template>
</xsl:stylesheet>

body要素と本文を二重に書く

<body>要素と本文を二重に書くとエラーはでなくなる.しかし,これは面倒だ.

<!-- foo.xsl -->
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:param name="color"/>

  <xsl:template match="/root">
    <xsl:choose>
      <xsl:when test="$color">
        <body color="{$color}"> <!-- color属性がある場合 -->
          ここに本文
        </body>
      </xsl:when>
      <xsl:otherwise>
        <body> <!-- color属性がない場合 -->
          ここに本文
        </body>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

文字列として扱ってみる

<body>を文字列として組み立てるやり方もある.あまり格好は良くない.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:param name="color"/>

  <xsl:template match="/root">
    <xsl:text disable-output-escaping="yes">&lt;body</xsl:text>
    <xsl:if test="$color">
      <xsl:value-of select="concat(' color=&quot;',$color,'&quot;')"/>
    </xsl:if>
    <xsl:text disable-output-escaping="yes">&gt;</xsl:text>
    ここに本文
    <xsl:text disable-output-escaping="yes">&lt;/body&gt;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

<xsl:attribute>を使う

<xsl:attribute>を使うともうちょっとスマートにできた.

<!-- foo.xsl -->
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:param name="color"/>

  <xsl:template match="/root">
    <body>
      <xsl:if test="$color">
        <xsl:attribute name="color">
          <xsl:value-of select="$color"/>
        </xsl:attribute>
      </xsl:if>
      ここに本文
    </body>
  </xsl:template>
</xsl:stylesheet>