Using XSL Conditional Statements and Recursions

XSLT allows different approaches to recursion. With the use of xsl:template (match) and xsl:for-each, developers can perform recursive task.

XSL allows two elements for conditional processing, xsl:if and xsl:choose. With xsl:if a sequence constructor is evaluated only if the specified condition in a test attribute returns true. However with xsl:choose instruction supports selection of one choice when there are several possibilities.

xsl:template (match)

The xsl:template match uses the pattern defined in the match attribute to identify which nodes apply the rule defined in the template. If more than one template rule meets the match criteria, they are first considered in order of import precedence. The templates that have the highest import precedence are applied to the resultant document. If there is still more than one template rule that meets the match criteria and shares the same import precedence, they are next considered in order of priority. The priority is either given by the value of the priority attribute, or is a default priority that depends on the match pattern.

<xsl:template
name="name"
match="pattern"
priority=number>
<!-- Content:(<xsl:param>*,template) -->
</xsl:template>

Example

<!-- XSL Template with match -->
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet SYSTEM "http://commons.omniupdate.com/dtd/standard.dtd">
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ou="http://omniupdate.com/XSL/Variables">
     <!--  Main Template -->
     <xsl:template match="/">
          <!-- Template Content -->
     </xsl:template>
</xsl:stylesheet>

Attribute: name (optional): Specifies a name for the template. If this attribute is omitted, there must be a match attribute.

Attribute: match (optional): Contains the match pattern for the template. If this attribute is omitted, there must be a name attribute.

Attribute: priority (optional): A positive or negative integer or decimal number that denotes the priority of the template.

Once a match pattern is successful, the rules defined in the template are applied to every node satisfying the match pattern.

Example

<!-- Source XSL FILE --> 
<root>
     <faculty>
          <first_name>John</first_name>
          <last_name>Doe</last_name>
          <department>Computer Science</department>
          <phone>123-234-1234</phone>
     </faculty>
     <faculty>
          <first_name>Peter</first_name>
          <last_name>Parker</last_name>
          <designation>Economics</designation>
          <phone>234-123-7890</phone>
     </faculty>
     <faculty>
          <first_name>Mary</first_name>
          <last_name>Jane</last_name>
          <designation></designation>
          <phone></phone>
     </faculty>
</root>

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet SYSTEM     "http://commons.omniupdate.com/dtd/standard.dtd">
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ou="http://omniupdate.com/XSL/Variables">
     <!--  Main Template -->
     <xsl:template match="/">
          <!-- Template Content -->
     </xsl:template>
</xsl:stylesheet>
 
<!-- Recursive XSL Template -->
<!DOCTYPE xsl:stylesheet SYSTEM "http://commons.omniupdate.com/dtd/standard.dtd" >
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" encoding="UTF-8" omit-xml-declaration="yes" /> 
     <xsl:template match="/">
     <html>
          <head>
               <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
               <title>Faculty Table</title>
          </head>
          <body>
               <table>
                     <thead>
                          <tr>
                               <td>First Name</td>
                               <td>Last Name</td>
                               <td>Department</td>
                               <td>Phone Number</td>
                          </tr>
                     </thead>
                     <tbody>
                          <xsl:apply-templates select="/root"/>
                     </tbody>
               </table>
          </body>
     </html>
     </xsl:template>
 
     <xsl:template match="faculty">
          <tr>
               <xsl:apply-templates />
          </tr>
     </xsl:template>
                                               
     <xsl:template match="first_name">
          <td><xsl:value-of select="." /></td>
     </xsl:template>
 
     <xsl:template match="last_name">
          <td><xsl:value-of select="." /></td>
     </xsl:template>
 
     <xsl:template match="department">
          <td><xsl:value-of select="." /></td>
     </xsl:template>
 
     <xsl:template match="phone">
          <td><xsl:value-of select="." /></td>
     </xsl:template>
                           
</xsl:stylesheet>

xsl:for-each

Recursion can also be accomplished using xsl:for-each. It allows developers to evaluate the sequence constructor within the xsl:for-each once for each item in that sequence. Using the same XML file as source, here is an example of xsl:for-each:

Example

<!DOCTYPE xsl:stylesheet SYSTEM "http://commons.omniupdate.com/dtd/standard.dtd" >
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" encoding="UTF-8" omit-xml-declaration="yes" /> 
     <xsl:template match="/">
     <html>
          <head>
               <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
               <title>Faculty Table</title>
          </head>
          <body>
               <table>
                     <thead>
                          <tr>
                               <td>First Name</td>
                               <td>Last Name</td>
                               <td>Department</td>
                               <td>Phone Number</td>
                          </tr>
                     </thead>
                     <tbody>
                         
                          <xsl:for-each select="/root/faculty">
                               <tr>
                     <td><xsl:value-of select="./first_name"/></td>
                     <td><xsl:value-of select="./last_name"/></td>
                     <td><xsl:value-of select="./department"/></td>
                     <td><xsl:value-of select="./phone"/></td>
                               </tr>
                          </xsl:for-each>
                         
                     </tbody>
               </table>
          </body>
     </html>
     </xsl:template>                      
</xsl:stylesheet>

xsl:if

xsl:if is used for conditional processing. It takes a mandatory testattribute, with a Boolean expression.

<xsl:if
test="expression">
     <!-- Content: sequence-constructor -->
</xsl:if> 

Example

<!-- Test if it is raining -->
<xsl:variable name="raining" select="'yes'"/>
<xsl:if test="$raining='yes'"
>
     Yes
</xsl:if>

Output

Yes

Attribute: test (mandatory): The Boolean condition to be tested.

xsl:when

xsl:when is always used as a child element of xsl:choose. It defines a condition to be tested and, if the condition is true, the action to be performed.

<xsl:choose>
<xsl:when
test="expression">
          <!-- Content: sequence-constructor -->
</xsl:when>
<xsl:choose>

Example

<!-- Test if it is raining -->
<xsl:variable name="raining" select="'yes'"/>
     <xsl:choose>
          <xsl:when test="$raining='yes'">
               Yes
          </xsl:when>
          <xsl:when test="$raining='maybe'">
               May be
          </xsl:when>
</xsl:choose>

Output

Yes

Attribute: test(mandatory): The Boolean condition to be tested.

xsl:otherwise

xsl:otherwise is always used as a child element of xsl:choose. It defines the action to be performed when none of the xsl:when conditions are satisfied.

<xsl:choose>
<xsl:when
test="expression">
          <!-- Content: sequence-constructor -->
</xsl:when>
<xsl:otherwise>
     <!-- Content: sequence-constructor -->
</xsl:otherwise>
<xsl:choose>

Example

<!-- Test if it is raining -->
<xsl:variable name="raining" select="'yes'"/>
     <xsl:choose>
          <xsl:when test="$raining='yes'">
               Yes
          </xsl:when>
          <xsl:when test="$raining='maybe'">
               May be
          </xsl:when>
          <xsl:when test="$raining='no'">
               No
          </xsl:when>
          <xsl:otherwise>
               Don&apos;t know
          </xsl:otherwise>    
</xsl:choose>

Output

Yes

Attribute: test(mandatory): The Boolean condition to be tested.