Using XML Queries and Transformations

Control of Flow

Like most programming languages, XSLT includes a few keywords to let you control the flow of the processing. These include the if/then construct, while loops and some extras. Like anything in XSLT, these features are implemented as XML elements.

if

The if element does one of the most common things in programming – checking a condition and executing an action if the condition is met. A simple example is:

<xsl:template match="AUTHOR">
  <xsl:if test="@name">
       <I><xsl:value-of select="@name"/></I>
  </xsl:if>
</xsl:template>

The if element has a test attribute. If the XPath expression in it returns false (an empty node list), the content of the element is not executed. In the example, the XPath query @name returns true if an attribute with name name exists. The if element cannot be combined with an else element (as is common in many languages). If you need an else, you have to use the choose/when/otherwise construct. Several if elements can be used nested.

choose/when/otherwise

For more complex choices the choose, when and otherwise elements can be used. The elements when and otherwise can only be used within a choose element. The processor will check every when element from the top down. A when element works exactly like an if element. The first time the test attribute returns true, the content of that when element is executed. After this, the processor jumps past the choose element without further checking. If none of the when elements can be executed, the otherwise element will be executed (if there is one).

<xsl:template match="AUTHOR">
  <xsl:choose>
    <xsl:when test="@name = 'Duynstee'">
      <B><xsl:value-of select="@name"/></B>
    </xsl:when>
    <xsl:when test="@name">
      <I><xsl:value-of select="@name"/></I>
    </xsl:when>
       <xsl:otherwise>
      No name available
    </xsl:otherwise>
  <xsl:choose>
</xsl:template>

In this example, the name attribute of the AUTHOR element we are processing is first checked for being 'Duynstee'. If it is, the value of the attribute is generated in the output as content of a B element and the processor jumps past the xsl:choose element in the stylesheet. If it is not, the next check is performed. If this is the case, the value of the name attribute is generated as content of an I element. If the second check fails too, then (and only then) will the processor execute the content of the xsl:otherwise element, which means generating the string 'No name available'.

for-each

For looping through a set of nodes, XSLT specifies the for-each element. The for-each element has a select attribute holding an XPath expression. The content of the for-each element is executed for each result from this query. Inside the loop, the context is moved to the current result set element.

<xsl:template match="PUBLISHER"><xsl:for-each select="child::BOOK">
  <xsl:value-of select="attribute::title"/>
  <xsl:for-each select="child::AUTHOR">
     <xsl:value-of select="attribute::name"/>
  </ xsl:for-each>
  <xsl:text>&#13;</xsl:text>
<!—Insert a new line after each book -->
</ xsl:for-each>
</xsl:template>

In this example, for-each elements are nested. Because the context moves with the for-each loop, the select attribute of the inner loop is evaluated in the context of the results of the outer loop. This is of course what you would expect.

Note that there is not much difference between an apply-templates element with an appropriate template and a for-each loop. Basically, a for-each loop is an in-line template. However, a for-each loop is generally more easy to read, but separating the content over several templates makes reuse of the inner template easier.

sort

Whenever XSLT iterates along a set of nodes, it can be useful to set the order of iteration. By default this is always document order, but the destination format may expect another order (or you are transforming data to HTML and you need to display it in a set order).

Sorting can be used on the elements apply-templates and for-each. The sort element is inserted as a child element of the apply-templates or for-each element. Consider this example:

<xsl:template match="FAMILY">
  <xsl:apply-templates select="PERSON">
    <xsl:sort select="@lastname"/>
    <xsl:sort select="@firstname"/>
  </xsl:apply-templates>
</xsl:template>

The select attribute holds an XPath expression. This expression is evaluated for each of the nodes in the set. The result of this expression determines the position in the sorted set.

By inserting multiple sort elements, the result set can be sorted primarily on the first criterion, and secondarily on the second one. In this case, the apply-templates element selects a set of all PERSON elements. These are sorted first on their lastname attribute, then on their firstname attribute. Only after the sorting does the XSLT processor start searching for the appropriate matching templates.

A number of extra optional attributes can be used with the sort element. The most important ones are:

  • order, for specifying 'ascending' or 'descending' sort order.
  • data-type, for sorting numerically or alphabetically. The default is alphabetically, causing 10 to be smaller than 9. Available values for data-type are 'text' and 'number'. Other values can also be used, but the meaning is not specified by the XSLT specification.
  • case-order, for specifying lower-first or upper-first. When case-order is lower-first, A sorts after a. There is no functionality for case insensitivity.

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Brevity is the soul of wit” - Shakespeare