The xsl:choose, xsl:when, and xsl:otherwise Elements

The <xsl:choose>, <xsl:when>, and <xsl: otherwise > Elements

The <xsl:choose> element is something like the Java switch statement, which enables you to compare a test value against several possible matches.

The <xsl:choose> element has no attributes. It contains one or more <xsl:when> elements, and, optionally , one <xsl:otherwise> element, which must come last if you use it.

Heres how it works; you enclose <xsl:when> elements, each of which has a true/false test, in an <xsl:choose> element. The template body in the first <xsl:when> element whose test evaluates as true is used, and all the others are not. The last element inside the <xsl:choose> element may be an <xsl:otherwise> element, and the template body inside this element is used if none of the tests in the preceeding <xsl:when> elements evaluate to true:

 <xsl:choose>      <xsl:when test="expression1">          <!--  template-body 1  -->      </xsl:when>      <xsl:when test="expression2>          <!--  template-body 2  -->      </xsl:when>      <xsl:when test="expression3">          <!--  template-body 3  -->      </xsl:when>      <xsl:otherwise>          <!--  template-body 4  -->      </xsl:otherwise>  </xsl:choose> 

In the preceding section, it took three <xsl:if> elements to perform this transformation properly:

 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:output method="xml/>  <xsl:template match="PLANETS">  <DOCUMENT>      <TITLE>          The Planets      </TITLE>      <PLANETS>          The first three planets are: <xsl:apply-templates select="PLANET"/>      </PLANETS>  </DOCUMENT>  </xsl:template>  <xsl:template match="PLANET">      <xsl:if test="NAME[not(text())]">          <xsl:message terminate="yes">              Each planet must have a name!          </xsl:message>      </xsl:if>      <xsl:value-of select="NAME"/>      <xsl:if test="position()!=last()">, </xsl:if>      <xsl:if test="position()=last()-1">and </xsl:if>      <xsl:if test="position()=last()">.</xsl:if>  </xsl:template>  </xsl:stylesheet> 

Now Ill do the same thing with a single <xsl:choose> element:

 <?xml version="1.0"?>  <xsl:stylesheet version="1.0" xmlns::xsl="http://www.w3.org/1999/XSL/Transform">  <xml:output method="xml"/>  <xsl:output method="xml"/>  <xsl:template match="PLANETS">  <DOCUMENT>      <TITLE>          The Planets      </TITLE>      <PLANETS>          The first three planets are: <xsl:apply-templates select="PLANET"/>      </PLANETS>  </DOCUMENT>  </xsl:template>  <xsl:template match="PLANET">      <xsl:if test="NAME[not(text())]">          <xsl:message terminate="yes">              Each planet must have a name!          </xsl:message>      </xsl:if>      <xsl:value-of select="NAME"/>      <xsl:choose>          .          .          .      </xsl:choose>  </xsl:template>  </xsl:stylesheet> 

Well need to test where we are in the document by enclosing several <xsl:when> elements. This element has only one attribute:

  • test (mandatory). Set to a Boolean (true/false) condition that you want tested .

The <xsl:when> element contains a template body.

You set the test attribute of <xsl:when> to a true/false expression that specifies whether the enclosed template body is used or ignored. For example, heres how I add <xsl:when> elements with the appropriate punctuation for any of the planets that are not the last one:

 <?xml version="1.0"?>  <xsl:stylesheet version="1.0" xmlns::xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:output method="xml"/>  <xsl:template match="PLANETS">  <DOCUMENT>      <TITLE>          The Planets      </TITLE>      <PLANETS>          The first three planets are: <xsl:apply-templates select="PLANET"/>      </PLANETS>  </DOCUMENT>  </xsl:template>  <xsl:template match="PLANET">      <xsl:if test="NAME[not(text())]">          <xsl:message terminate="yes">              Each planet must have a name!          </xsl:message>      </xsl:if>      <xsl:value-of select="NAME"/>      <xsl:choose>          <xsl:when test="position()!=last()">, </xsl:when>          <xsl:when test="position()=last()-1">and </xsl:when>          .          .          .      </xsl:choose>  </xsl:template>  </xsl:stylesheet> 

These two <xsl:when> elements match all <PLANET> elements except the last one, so an <xsl:otherwise> element can be used for the last <PLANET> element. The template body in this element is used if no <xsl:when> element in the <xsl:choose> element had a test that evaluated as true.

The <xsl:otherwise> element has no attributes, and contains a template body. Heres how I put it to work in this example:

Listing 5.4 Using <xsl:choose>
 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:output method="xml"/>  <xsl:template match="PLANETS">  <DOCUMENT>      <TITLE>          The Planets      </TITLE>      <PLANETS>          The first three planets are: <xsl:apply-templates select="PLANET"/>      </PLANETS>  </DOCUMENT>  </xsl:template>  <xsl:template match="PLANET">      <xsl:if test="NAME[not(text())]">          <xsl:message terminate="yes">              Each planet must have a name!          </xsl:message>      </xsl:if>      <xsl:value-of select="NAME"/>      <xsl:choose>          <xsl:when test="position()!=last()">, </xsl:when>          <xsl:when test="position()=last()-1">and </xsl:when>          <xsl:otherwise>.</xsl:otherwise>      </xsl:choose>  </xsl:template>  </xsl:stylesheet> 

And thats it; this code produces the same result as when we used <xsl:if> to check the position of the <PLANET> elements:

 <?xml version="1.0" encoding="UTF-8"?>  <DOCUMENT>      <TITLE>          The Planets      </TITLE>      <PLANETS>          The first three planets are: Mercury, Venus, and Earth.      </PLANETS>  </DOCUMENT> 

Heres another XML-to-XML example. In this case, I convert planets.xml to a new XML document, preserving only the name of each planet, and adding a description:

 <?xml version="1.0" encoding="UTF-8"?>  <DOCUMENT>      <TITLE>          The Planets      </TITLE>      <PLANETS>          <PLANET>              <NAME>Mercury</NAME>              <DESCRIPTION>Hottest</DESCRIPTION>          </PLANET>          <PLANET>              <NAME>Venus</NAME>              <DESCRIPTION>Hot</DESCRIPTION>          </PLANET>          <PLANET>              <NAME>Earth</NAME>              <DESCRIPTION>OK</DESCRIPTION>          </PLANET>      </PLANETS>  </DOCUMENT> 

I can implement this transformation by checking the value of each <NAME> element, which is its enclosed text (note that string matches like this are case-sensitive in XSLT):

Listing 5.5 Second <xsl:choose> Example
 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:output method="xml"/>  <xsl:template match="PLANETS">  <DOCUMENT>      <TITLE>          The Planets      </TITLE>      <PLANETS>          <xsl:apply-templates select="PLANET"/>      </PLANETS>  </DOCUMENT>  </xsl:template>  <xsl:template match="PLANET">      <xsl:if test="NAME[not(text())]">          <xsl:message terminate="yes">              Each planet must have a name!          </xsl:message>      </xsl:if>      <PLANET>          <NAME>              <xsl:value-of select="NAME"/>          </NAME>          <DESCRIPTION>              <xsl:choose>                  <xsl:when test="NAME='Mercury'">Hottest</xsl:when>                  <xsl:when test="NAME='Venus'">Hot</xsl:when>                  <xsl:when test="NAME='Earth'">OK</xsl:when>              </xsl:choose>          </DESCRIPTION>      </PLANET>  </xsl:template>  </xsl:stylesheet> 

Thats all it takes.

Now, suppose that I want to add COLOR attributes to each <PLANET> element:

 <?xml version="1.0"?>  <?xml-stylesheet type="text/xml" href="planets.xsl"?>  <PLANETS>    <PLANET COLOR="RED">      <NAME>Mercury</NAME>      <MASS UNITS="(Earth = 1)">.0553</MASS>      <DAY UNITS="days">58.65</DAY>      <RADIUS UNITS="miles">1516</RADIUS>      <DENSITY UNITS="(Earth = 1)">.983</DENSITY>      <DISTANCE UNITS="million miles">43.4</DISTANCE><!--At perihelion-->    </PLANET>    <PLANET COLOR="WHITE">      <NAME>Venus</NAME>      <MASS UNITS="(Earth = 1)">.815</MASS>      <DAY UNITS="days">116.75</DAY>      <RADIUS UNITS="miles">3716</RADIUS>      <DENSITY UNITS="(Earth = 1)">.943</DENSITY>      <DISTANCE UNITS="million miles">66.8</DISTANCE><!--At perihelion-->    </PLANET>    <PLANET COLOR="BLUE">      <NAME>Earth</NAME>      <MASS UNITS="(Earth = 1)">1</MASS>      <DAY UNITS="days">1</DAY>      <RADIUS UNITS="miles">2107</RADIUS>      <DENSITY UNITS="(Earth = 1)">1</DENSITY>      <DISTANCE UNITS="million miles">128.4</DISTANCE><!--At perihelion-->    </PLANET>  </PLANETS> 

We could display the names of the various planets, formatted in different ways, by using HTML <B> , <I> , and <U> tags, depending on the value of the COLOR attribute, with an <xsl:choose> element, as follows :

Listing 5.6 Formatting Using <xsl:choose>
 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:template match="PLANETS">      <HTML>          <HEAD>              <TITLE>                  Planets              </TITLE>          </HEAD>          <BODY>              <xsl:apply-templates select="PLANET"/>          </BODY>      </HTML>  </xsl:template>  <xsl:template match="PLANET">      <xsl:choose>          <xsl:when test="@COLOR = "RED'">              <B>                  <xsl:value-of select="NAME"/>              </B>          </xsl:when>          <xsl:when test="@COLOR = 'WHITE'">              <I>                  <xsl:value-of select="NAME"/>              </I>          </xsl:when>          <xsl:when test="@COLOR = 'BLUE'">              <U>                  <xsl:value-of select="NAME"/>              </U>          </xsl:when>          <xsl:otherwise>               <PRE>                   <xsl:value-of select="."/>               </PRE>          </xsl:otherwise>      </xsl:choose>  </xsl:template>  </xsl:stylesheet> 

Here is the result document:

 <HTML>      <HEAD>          <TITLE>              Planets          </TITLE>      </HEAD>      <BODY>          <B>Mercury</B>          <I>Venus</I>          <U>Earth</U>      </BODY>  </HTML> 

Youve seen that you can use <xsl:if> to test single conditions and <xsl:choose> to test multiple conditions, and these elements mirror whats available in most programming languages. In addition to conditional statements such as these, most programming languages also include looping statements, and XSLT contains something similar: the <xsl:for-each> element.



Inside XSLT
Inside Xslt
ISBN: B0031W8M4K
EAN: N/A
Year: 2005
Pages: 196

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net