【XSL】繰り返し処理と条件分岐のフロー制御タグ


XSLのフロー制御系のタグについて




 

■test.xml

以下のXMLファイルを相手にすることを考えます。

<?xml version="1.0" encoding="Shift_JIS"?>  
<?xml-stylesheet type="text/xsl" href="test.xsl"?>  
<test>  
 <numbers>  
   <val flag="0">100.00</val>  
   <val flag="0">1</val>  
   <val flag="0">-1</val>  
   <val flag="1">1.2</val>  
   <val flag="0">-2.3</val>  
   <val flag="0">12.3</val>  
   <val flag="0">-23.4</val>  
   <val flag="0">1.45</val>  
   <val flag="0">-4.78</val>  
   <val flag="0">3.14159265358979</val>  
 </numbers>  
</test>  

 





■xsl:for-each

複数の同一タグを相手に繰り返し処理を記述できるタグです。

test.xmlでは「/test/numbers/」配下の「val」が繰り返しされているので、これをfor-eachで処理してみます。
基本的な記述は以下の通り

<?xml version="1.0" encoding="Shift_JIS"?>  
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">   

<xsl:output method=“html” encoding=“Shift_JIS”/>

<xsl:template match="/">

<html>

<head>
<title>
test
</title>
</head>

<body>
<h1>test</h1>
<xsl:for-each select="/test/numbers/val">

  ...(略;ここにループ処理をかく)...  
    
<span class="c-red bold">&lt;/xsl:for-each&gt;</span>  

</body>

</html>

</xsl:template>
</xsl:stylesheet>


ループの中では/test/numbers/valタグの位置にいる認識で処理がまわせます。
すなわち「.」で現在処理中のvalタグ値が、「./@[属性名]」で処理中のタグの当該属性値がとれます。

    <xsl:for-each select="/test/numbers/val">  
  <span class="c-green"></span>  
  <span class="c-red bold">&lt;xsl:variable name="val" select="."/&gt;</span>  
    
  <span class="c-green"></span>  
  <span class="c-red bold">&lt;xsl:variable name="val" select="./@flag"/&gt;</span>  
    
  <span class="c-green"></span>  
  <span class="c-red bold">val = &lt;xsl:value-of select="$val"/&gt; , flag = &lt;xsl:value-of select="$flag"/&gt;&amp;lt:br/&gt;</span>  
    
&lt;/xsl:for-each&gt;  


結果は以下の通り。

val = 100.00 , flag=0  

val = 1 , flag=0

val = -1 , flag=0

val = 1.2 , flag=1

val = -2.3 , flag=0

val = 12.3 , flag=0

val = -23.4 , flag=0

val = 1.45 , flag=0

val = -4.78 , flag=0

val = 3.14159265358979 , flag=0


前回記事の(4)複数タグの値取得を一発で指示する方法と似てますが、プログラムチックに記述できるこっちのほうが個人的には馴染みありますね。。
まあ、やりやすいほうを選べばいいでしょう。




■xsl:if、xsl:choose(when,otherwise)

上と同じXMLを使って今度は条件分岐させてみます。

    ...(略)...  
&lt;xsl:for-each select="/test/numbers/val"&gt;  
    
  <span class="c-green"></span>  
  &lt;xsl:variable name="val" select="."/&gt;  
    
  <span class="c-green"></span>  
  &lt;xsl:variable name="val" select="./@flag"/&gt;  
    
  <span class="c-green"></span>  
  <span class="c-red bold">&lt;xsl:if test="$flag = '1'"&gt;  
    val(-1) = &lt;xsl:value-of select="number($val) * -1"/&gt;  ,  
  &lt;/xsl:if&gt;</span>  
    
  val = &lt;xsl:value-of select="$val"/&gt; , flag = &lt;xsl:value-of select="$flag"/&gt;&amp;lt:br/&gt;  
    
&lt;/xsl:for-each&gt;  
  
...(略)...  


上のxsl:ifでは変数「flag」の値が1のデータのときのみ、「val(-1)=変数valの値×-1」という内容を出力するように指示しています。
test=""と書いてダブクォ内に判定式を書く使い方になっています。
なんでtest?ってのは、Linuxのtestコマンドに依存しているんでしょうねえ。
ちなみに、$flag = '1'だと変数代入してるみたいに見えます(==とかにしたくなるw)がこれで判定式になっています。

結果は以下の通り。
赤太字のタグに関してだけflag=1なので、val(-1)が追加出力されているのがわかります。

val = 100.00 , flag=0  

val = 1 , flag=0

val = -1 , flag=0

val(-1) = -1.2 , val = 1.2 , flag=1

val = -2.3 , flag=0

val = 12.3 , flag=0

val = -23.4 , flag=0

val = 1.45 , flag=0

val = -4.78 , flag=0

val = 3.14159265358979 , flag=0

val(-1) = -288.93 , val = 288.93 , flag=1


ただ、xsl:ifにはelseが存在しないため、if-elseを実装する場合にはxsl:choose、xsl:when、xsl:otherwiseが必要です。

    ...(略)...  
&lt;xsl:for-each select="/test/numbers/val"&gt;  
    
  <span class="c-green"></span>  
  &lt;xsl:variable name="val" select="."/&gt;  
    
  <span class="c-green"></span>  
  &lt;xsl:variable name="val" select="./@flag"/&gt;  
    
  <span class="c-green"></span>  
  &lt;xsl:if test="$flag = '1'"&gt;  
    val(-1) = &lt;xsl:value-of select="number($val) * -1"/&gt;  ,  
  &lt;/xsl:if&gt;  
    
  val = &lt;xsl:value-of select="$val"/&gt; , flag = &lt;xsl:value-of select="$flag"/&gt;&amp;lt:br/&gt;  
  <span class="c-red bold">&lt;xsl:choose&gt;  
    &lt;xsl:when test="$flag = '0' and $val &amp;lt; 0"&gt;  
      this value is flag = '0' and less than 0.  
    &lt;/xsl:when&gt;  
    &lt;xsl:when test="$flag = '1' and $val &amp;gt; 100"&gt;  
      this value is flag  = '1' and greater than 100.  
    &lt;/xsl:when&gt;  
    &lt;xsl:otherwise&gt;  
      this value is otherwise  
    &lt;/xsl:otherwise&gt;  
  &lt;/xsl:choose&gt;</span>  
  &lt;hr/&gt;  
    
&lt;/xsl:for-each&gt;  
  
...(略)...  


複数判定が必要なブロック全体をまずxsl:chooseで覆い、対象条件にひっかかる分だけxsl:whenを書いて、最後にelseに当たる処理をxsl:otherwiseで記述します。

ちなみに複数条件にhitした場合は最初にhitしたタグで処理され、次のほうのタグでは処理されません。
例えば

      <xsl:choose>  
        <xsl:when test="$flag = '0' and $val &lt; 0">  
          this value is flag = '0' and less than 0.  
        </xsl:when>  
        <xsl:when test="$flag = '0' and $val &lt; -2">  
          this value is flag  = '0' and less than -2.  
        </xsl:when>  
        <xsl:otherwise>  
          this value is otherwise  
        </xsl:otherwise>  
      </xsl:choose>  


とすると、val=-2.3等のタグは、一番目の<xsl:when test="$flag = '0' and $val &lt; 0">と二番目の <xsl:when test="$flag = '0' and $val < -2"&gt;の両方にhitしますが、一番目のほうで処理されて二番目のほうは無視されます。
(javaのif-elseifと同じですね)